diff --git a/packages/angular/cli/src/command-builder/utilities/json-schema.ts b/packages/angular/cli/src/command-builder/utilities/json-schema.ts index 0a4215be8eed..78218465cf02 100644 --- a/packages/angular/cli/src/command-builder/utilities/json-schema.ts +++ b/packages/angular/cli/src/command-builder/utilities/json-schema.ts @@ -390,10 +390,10 @@ export async function parseJsonSchemaToOptions( // Sort by positional and name. return options.sort((a, b) => { - if (a.positional) { - return b.positional ? a.positional - b.positional : a.name.localeCompare(b.name); - } else if (b.positional) { - return -1; + if (a.positional !== undefined) { + return b.positional !== undefined ? a.positional - b.positional : -1; + } else if (b.positional !== undefined) { + return 1; } return a.name.localeCompare(b.name); diff --git a/packages/angular/cli/src/command-builder/utilities/json-schema_spec.ts b/packages/angular/cli/src/command-builder/utilities/json-schema_spec.ts index 496a2094b62c..117b325f26b1 100644 --- a/packages/angular/cli/src/command-builder/utilities/json-schema_spec.ts +++ b/packages/angular/cli/src/command-builder/utilities/json-schema_spec.ts @@ -346,4 +346,47 @@ describe('parseJsonSchemaToOptions', () => { ); }); }); + + describe('with positional arguments not in alphabetical order', () => { + it('sorts positional arguments by their index', async () => { + const jsonSchema = { + '$id': 'FakeSchema', + 'title': 'Fake Schema', + 'type': 'object', + 'required': ['preset'], + 'properties': { + 'preset': { + 'type': 'string', + 'enum': ['form', 'table'], + 'description': 'preset.', + '$default': { + '$source': 'argv', + 'index': 0, + }, + 'x-prompt': 'Which preset?', + }, + 'name': { + 'type': 'string', + 'description': 'name.', + '$default': { + '$source': 'argv', + 'index': 1, + }, + }, + 'path': { + 'type': 'string', + 'description': 'path.', + }, + }, + }; + const registry = new schema.CoreSchemaRegistry(); + const options = await parseJsonSchemaToOptions(registry, jsonSchema, /* interactive= */ true); + + expect(options).toEqual([ + jasmine.objectContaining({ name: 'preset', positional: 0, required: false }), + jasmine.objectContaining({ name: 'name', positional: 1, required: false }), + jasmine.objectContaining({ name: 'path', positional: undefined, required: false }), + ]); + }); + }); }); diff --git a/tests/e2e/tests/generate/help-output.ts b/tests/e2e/tests/generate/help-output.ts index 86fc3b988b38..bd5c71a7d9d1 100644 --- a/tests/e2e/tests/generate/help-output.ts +++ b/tests/e2e/tests/generate/help-output.ts @@ -32,14 +32,14 @@ export default function () { "$id": "FakeSchema", "title": "Fake Schema", "type": "object", - "required": ["a"], + "required": ["b"], "properties": { "b": { "type": "string", "description": "b.", "$default": { "$source": "argv", - "index": 1 + "index": 0 } }, "a": { @@ -47,7 +47,7 @@ export default function () { "description": "a.", "$default": { "$source": "argv", - "index": 0 + "index": 1 } }, "optC": { @@ -76,7 +76,7 @@ export default function () { ) .then(() => ng('generate', 'fake-schematics:fake', '--help')) .then(({ stdout }) => { - assert.match(stdout, /ng generate fake-schematics:fake \[b\]/); + assert.match(stdout, /ng generate fake-schematics:fake \[a\]/); assert.match(stdout, /opt-a[\s\S]*opt-b[\s\S]*opt-c/); }) // set up default collection. @@ -89,7 +89,7 @@ export default function () { .then(() => ng('generate', 'fake', '--help')) // verify same output .then(({ stdout }) => { - assert.match(stdout, /ng generate fake \[b\]/); + assert.match(stdout, /ng generate fake \[a\]/); assert.match(stdout, /opt-a[\s\S]*opt-b[\s\S]*opt-c/); })