/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as Formatter from 'vs/base/common/jsonFormatter'; import * as assert from 'assert'; suite('JSON - formatter', () => { function format(content: string, expected: string, insertSpaces = true) { let range: Formatter.Range | undefined = undefined; const rangeStart = content.indexOf('|'); const rangeEnd = content.lastIndexOf('|'); if (rangeStart !== -1 && rangeEnd !== -1) { content = content.substring(0, rangeStart) + content.substring(rangeStart + 1, rangeEnd) + content.substring(rangeEnd + 1); range = { offset: rangeStart, length: rangeEnd - rangeStart }; } const edits = Formatter.format(content, range, { tabSize: 2, insertSpaces: insertSpaces, eol: '\n' }); let lastEditOffset = content.length; for (let i = edits.length - 1; i >= 0; i--) { let edit = edits[i]; assert(edit.offset >= 0 && edit.length >= 0 && edit.offset + edit.length <= content.length); assert(typeof edit.content === 'string'); assert(lastEditOffset >= edit.offset + edit.length); // make sure all edits are ordered lastEditOffset = edit.offset; content = content.substring(0, edit.offset) + edit.content + content.substring(edit.offset + edit.length); } assert.equal(content, expected); } test('object - single property', () => { const content = [ '{"x" : 1}' ].join('\n'); const expected = [ '{', ' "x": 1', '}' ].join('\n'); format(content, expected); }); test('object - multiple properties', () => { const content = [ '{"x" : 1, "y" : "foo", "z" : true}' ].join('\n'); const expected = [ '{', ' "x": 1,', ' "y": "foo",', ' "z": true', '}' ].join('\n'); format(content, expected); }); test('object - no properties ', () => { const content = [ '{"x" : { }, "y" : {}}' ].join('\n'); const expected = [ '{', ' "x": {},', ' "y": {}', '}' ].join('\n'); format(content, expected); }); test('object - nesting', () => { const content = [ '{"x" : { "y" : { "z" : { }}, "a": true}}' ].join('\n'); const expected = [ '{', ' "x": {', ' "y": {', ' "z": {}', ' },', ' "a": true', ' }', '}' ].join('\n'); format(content, expected); }); test('array - single items', () => { const content = [ '["[]"]' ].join('\n'); const expected = [ '[', ' "[]"', ']' ].join('\n'); format(content, expected); }); test('array - multiple items', () => { const content = [ '[true,null,1.2]' ].join('\n'); const expected = [ '[', ' true,', ' null,', ' 1.2', ']' ].join('\n'); format(content, expected); }); test('array - no items', () => { const content = [ '[ ]' ].join('\n'); const expected = [ '[]' ].join('\n'); format(content, expected); }); test('array - nesting', () => { const content = [ '[ [], [ [ {} ], "a" ] ]' ].join('\n'); const expected = [ '[', ' [],', ' [', ' [', ' {}', ' ],', ' "a"', ' ]', ']', ].join('\n'); format(content, expected); }); test('syntax errors', () => { const content = [ '[ null 1.2 ]' ].join('\n'); const expected = [ '[', ' null 1.2', ']', ].join('\n'); format(content, expected); }); test('empty lines', () => { const content = [ '{', '"a": true,', '', '"b": true', '}', ].join('\n'); const expected = [ '{', '\t"a": true,', '\t"b": true', '}', ].join('\n'); format(content, expected, false); }); test('single line comment', () => { const content = [ '[ ', '//comment', '"foo", "bar"', '] ' ].join('\n'); const expected = [ '[', ' //comment', ' "foo",', ' "bar"', ']', ].join('\n'); format(content, expected); }); test('block line comment', () => { const content = [ '[{', ' /*comment*/ ', '"foo" : true', '}] ' ].join('\n'); const expected = [ '[', ' {', ' /*comment*/', ' "foo": true', ' }', ']', ].join('\n'); format(content, expected); }); test('single line comment on same line', () => { const content = [ ' { ', ' "a": {}// comment ', ' } ' ].join('\n'); const expected = [ '{', ' "a": {} // comment ', '}', ].join('\n'); format(content, expected); }); test('single line comment on same line 2', () => { const content = [ '{ //comment', '}' ].join('\n'); const expected = [ '{ //comment', '}' ].join('\n'); format(content, expected); }); test('block comment on same line', () => { const content = [ '{ "a": {}, /*comment*/ ', ' /*comment*/ "b": {}, ', ' "c": {/*comment*/} } ', ].join('\n'); const expected = [ '{', ' "a": {}, /*comment*/', ' /*comment*/ "b": {},', ' "c": { /*comment*/}', '}', ].join('\n'); format(content, expected); }); test('block comment on same line advanced', () => { const content = [ ' { "d": [', ' null', ' ] /*comment*/', ' ,"e": /*comment*/ [null] }', ].join('\n'); const expected = [ '{', ' "d": [', ' null', ' ] /*comment*/,', ' "e": /*comment*/ [', ' null', ' ]', '}', ].join('\n'); format(content, expected); }); test('multiple block comments on same line', () => { const content = [ '{ "a": {} /*comment*/, /*comment*/ ', ' /*comment*/ "b": {} /*comment*/ } ' ].join('\n'); const expected = [ '{', ' "a": {} /*comment*/, /*comment*/', ' /*comment*/ "b": {} /*comment*/', '}', ].join('\n'); format(content, expected); }); test('multiple mixed comments on same line', () => { const content = [ '[ /*comment*/ /*comment*/ // comment ', ']' ].join('\n'); const expected = [ '[ /*comment*/ /*comment*/ // comment ', ']' ].join('\n'); format(content, expected); }); test('range', () => { const content = [ '{ "a": {},', '|"b": [null, null]|', '} ' ].join('\n'); const expected = [ '{ "a": {},', '"b": [', ' null,', ' null', ']', '} ', ].join('\n'); format(content, expected); }); test('range with existing indent', () => { const content = [ '{ "a": {},', ' |"b": [null],', '"c": {}', '}|' ].join('\n'); const expected = [ '{ "a": {},', ' "b": [', ' null', ' ],', ' "c": {}', '}', ].join('\n'); format(content, expected); }); test('range with existing indent - tabs', () => { const content = [ '{ "a": {},', '| "b": [null], ', '"c": {}', '} | ' ].join('\n'); const expected = [ '{ "a": {},', '\t"b": [', '\t\tnull', '\t],', '\t"c": {}', '}', ].join('\n'); format(content, expected, false); }); test('block comment none-line breaking symbols', () => { const content = [ '{ "a": [ 1', '/* comment */', ', 2', '/* comment */', ']', '/* comment */', ',', ' "b": true', '/* comment */', '}' ].join('\n'); const expected = [ '{', ' "a": [', ' 1', ' /* comment */', ' ,', ' 2', ' /* comment */', ' ]', ' /* comment */', ' ,', ' "b": true', ' /* comment */', '}', ].join('\n'); format(content, expected); }); test('line comment after none-line breaking symbols', () => { const content = [ '{ "a":', '// comment', 'null,', ' "b"', '// comment', ': null', '// comment', '}' ].join('\n'); const expected = [ '{', ' "a":', ' // comment', ' null,', ' "b"', ' // comment', ' : null', ' // comment', '}', ].join('\n'); format(content, expected); }); });