diff --git a/packages/schematics/angular/utility/json-utils.ts b/packages/schematics/angular/utility/json-utils.ts index 8684785aef8d..cf1754a9a44d 100644 --- a/packages/schematics/angular/utility/json-utils.ts +++ b/packages/schematics/angular/utility/json-utils.ts @@ -143,7 +143,6 @@ export function removePropertyInAstObject( recorder.remove(start.offset, end.offset - start.offset); if (!nextProp) { - recorder.insertRight(start.offset, '\n'); } } @@ -155,21 +154,39 @@ export function appendValueInAstArray( value: JsonValue, indent = 4, ) { - const indentStr = _buildIndent(indent); + let indentStr = _buildIndent(indent); let index = node.start.offset + 1; + // tslint:disable-next-line: no-any + let newNodes: any[] | undefined; + if (node.elements.length > 0) { // Insert comma. - const last = node.elements[node.elements.length - 1]; - recorder.insertRight(last.end.offset, ','); - index = indent ? last.end.offset + 1 : last.end.offset; + const { end } = node.elements[node.elements.length - 1]; + const isClosingOnSameLine = node.end.offset - end.offset === 1; + + if (isClosingOnSameLine && indent) { + // Reformat the entire array + recorder.remove(node.start.offset, node.end.offset - node.start.offset); + newNodes = [ + ...node.elements.map(({ value }) => value), + value, + ]; + index = node.start.offset; + // In case we are generating the entire node we need to reduce the spacing as + // otherwise we'd end up having incorrect double spacing + indent = indent - 2; + indentStr = _buildIndent(indent); + } else { + recorder.insertRight(end.offset, ','); + index = end.offset; + } } recorder.insertRight( index, - (node.elements.length === 0 && indent ? '\n' : '') - + ' '.repeat(indent) - + _stringifyContent(value, indentStr) - + indentStr.slice(0, -indent), + (newNodes ? '' : indentStr) + + _stringifyContent(newNodes || value, indentStr) + + (node.elements.length === 0 && indent ? indentStr.substr(0, -indent) + '\n' : ''), ); } diff --git a/packages/schematics/angular/utility/json-utils_spec.ts b/packages/schematics/angular/utility/json-utils_spec.ts index becda85f3f1c..400e4e1dd320 100644 --- a/packages/schematics/angular/utility/json-utils_spec.ts +++ b/packages/schematics/angular/utility/json-utils_spec.ts @@ -15,6 +15,7 @@ import { removePropertyInAstObject, } from './json-utils'; +// tslint:disable-next-line: no-big-function describe('json-utils', () => { const a = 'a'; const b = 'b'; @@ -199,6 +200,35 @@ describe('json-utils', () => { expect(JSON.parse(got)).toEqual(want); } }); - }); + it('should insert multiple props with different indentations in Object literal', () => { + const cases: Array<[string[], string, {}, number]> = [ + // initial | value | want | indent + [[], z, [z], 0], + [[z], m, [z, m], 0], + [[m, z], a, [m, z, a], 0], + [[a, m, z], b, [a, m, z, b], 0], + // todo: investigate how to do this this of addition with the correct formatting + // [[], z, [z], 2], + [[z], m, [z, m], 2], + [[m, z], a, [m, z, a], 2], + [[a, m, z], b, [a, m, z, b], 2], + // todo: investigate how to do this this of addition with the correct formatting + // [[], z, [z], 4], + [[z], m, [z, m], 4], + [[m, z], a, [m, z, a], 4], + [[a, m, z], b, [a, m, z, b], 4], + ]; + for (const c of cases) { + const [initial, value, want, indent] = c; + const got = runTest((rec: UpdateRecorder, ast: JsonAstObject) => { + expect(ast.properties[0].value.kind).toBe('array'); + appendValueInAstArray(rec, ast.properties[0].value as unknown as JsonAstArray, value, indent * 2); + }, { data: initial }, indent); + const wantData = { data: want }; + expect(got).toBe(JSON.stringify(wantData, null, indent)); + expect(JSON.parse(got)).toEqual(wantData); + } + }); + }); });