Skip to content

Commit

Permalink
Merge pull request #5450 from sarod/allow-comments-tsconfig
Browse files Browse the repository at this point in the history
Allow comments in tsconfig.json
  • Loading branch information
mhegazy committed Nov 2, 2015
2 parents f503169 + 638e4b7 commit 3e63144
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 2 deletions.
3 changes: 2 additions & 1 deletion Jakefile.js
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,8 @@ var harnessSources = harnessCoreSources.concat([
"transpile.ts",
"reuseProgramStructure.ts",
"cachingInServerLSHost.ts",
"moduleResolution.ts"
"moduleResolution.ts",
"tsconfigParsing.ts"
].map(function (f) {
return path.join(unittestsDirectory, f);
})).concat([
Expand Down
30 changes: 29 additions & 1 deletion src/compiler/commandLineParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -405,13 +405,41 @@ namespace ts {
*/
export function parseConfigFileTextToJson(fileName: string, jsonText: string): { config?: any; error?: Diagnostic } {
try {
return { config: /\S/.test(jsonText) ? JSON.parse(jsonText) : {} };
let jsonTextWithoutComments = removeComments(jsonText);
return { config: /\S/.test(jsonTextWithoutComments) ? JSON.parse(jsonTextWithoutComments) : {} };
}
catch (e) {
return { error: createCompilerDiagnostic(Diagnostics.Failed_to_parse_file_0_Colon_1, fileName, e.message) };
}
}


/**
* Remove the comments from a json like text.
* Comments can be single line comments (starting with # or //) or multiline comments using / * * /
*
* This method replace comment content by whitespace rather than completely remove them to keep positions in json parsing error reporting accurate.
*/
function removeComments(jsonText: string): string {
let output = "";
let scanner = createScanner(ScriptTarget.ES5, /* skipTrivia */ false, LanguageVariant.Standard, jsonText);
let token: SyntaxKind;
while ((token = scanner.scan()) !== SyntaxKind.EndOfFileToken) {
switch (token) {
case SyntaxKind.SingleLineCommentTrivia:
case SyntaxKind.MultiLineCommentTrivia:
// replace comments with whitespace to preserve original character positions
output += scanner.getTokenText().replace(/\S/g, " ");
break;
default:
output += scanner.getTokenText();
break;
}
}
return output;
}


/**
* Parse the contents of a config file (tsconfig.json).
* @param json The contents of the config file to parse
Expand Down
86 changes: 86 additions & 0 deletions tests/cases/unittests/tsconfigParsing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/// <reference path="..\..\..\src\harness\harness.ts" />
/// <reference path="..\..\..\src\compiler\commandLineParser.ts" />

namespace ts {
describe('parseConfigFileTextToJson', () => {
function assertParseResult(jsonText: string, expectedConfigObject: { config?: any; error?: Diagnostic }) {
let parsed = ts.parseConfigFileTextToJson("/apath/tsconfig.json", jsonText);
assert.equal(JSON.stringify(parsed), JSON.stringify(expectedConfigObject));
}

function assertParseError(jsonText: string) {
let parsed = ts.parseConfigFileTextToJson("/apath/tsconfig.json", jsonText);
assert.isTrue(undefined === parsed.config);
assert.isTrue(undefined !== parsed.error);
}

it("returns empty config for file with only whitespaces", () => {
assertParseResult("", { config : {} });
assertParseResult(" ", { config : {} });
});

it("returns empty config for file with comments only", () => {
assertParseResult("// Comment", { config: {} });
assertParseResult("/* Comment*/", { config: {} });
});

it("returns empty config when config is empty object", () => {
assertParseResult("{}", { config: {} });
});

it("returns config object without comments", () => {
assertParseResult(
`{ // Excluded files
"exclude": [
// Exclude d.ts
"file.d.ts"
]
}`, { config: { exclude: ["file.d.ts"] } });

assertParseResult(
`{
/* Excluded
Files
*/
"exclude": [
/* multiline comments can be in the middle of a line */"file.d.ts"
]
}`, { config: { exclude: ["file.d.ts"] } });
});

it("keeps string content untouched", () => {
assertParseResult(
`{
"exclude": [
"xx//file.d.ts"
]
}`, { config: { exclude: ["xx//file.d.ts"] } });
assertParseResult(
`{
"exclude": [
"xx/*file.d.ts*/"
]
}`, { config: { exclude: ["xx/*file.d.ts*/"] } });
});

it("handles escaped characters in strings correctly", () => {
assertParseResult(
`{
"exclude": [
"xx\\"//files"
]
}`, { config: { exclude: ["xx\"//files"] } });

assertParseResult(
`{
"exclude": [
"xx\\\\" // end of line comment
]
}`, { config: { exclude: ["xx\\"] } });
});

it("returns object with error when json is invalid", () => {
assertParseError("invalid");
});
});
}

0 comments on commit 3e63144

Please sign in to comment.