Skip to content

Commit 4b3e661

Browse files
authored
Merge pull request #12336 from Microsoft/ownJsonParsing
Use parser to parse tsconfig json instead of using Json.parse
2 parents 537695c + 09f0b34 commit 4b3e661

File tree

83 files changed

+2232
-1035
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+2232
-1035
lines changed

src/compiler/checker.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,12 @@ namespace ts {
2727
return symbol.id;
2828
}
2929

30+
export function isInstantiatedModule(node: ModuleDeclaration, preserveConstEnums: boolean) {
31+
const moduleState = getModuleInstanceState(node);
32+
return moduleState === ModuleInstanceState.Instantiated ||
33+
(preserveConstEnums && moduleState === ModuleInstanceState.ConstEnumOnly);
34+
}
35+
3036
export function createTypeChecker(host: TypeCheckerHost, produceDiagnostics: boolean): TypeChecker {
3137
// Cancellation that controls whether or not we can cancel in the middle of type checking.
3238
// In general cancelling is *not* safe for the type checker. We might be in the middle of

src/compiler/commandLineParser.ts

Lines changed: 624 additions & 156 deletions
Large diffs are not rendered by default.

src/compiler/core.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2139,6 +2139,8 @@ namespace ts {
21392139
return ScriptKind.TS;
21402140
case Extension.Tsx:
21412141
return ScriptKind.TSX;
2142+
case ".json":
2143+
return ScriptKind.JSON;
21422144
default:
21432145
return ScriptKind.Unknown;
21442146
}

src/compiler/diagnosticMessages.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
{
1+
{
22
"Unterminated string literal.": {
33
"category": "Error",
44
"code": 1002
@@ -899,6 +899,14 @@
899899
"category": "Error",
900900
"code": 1326
901901
},
902+
"String literal with double quotes expected.": {
903+
"category": "Error",
904+
"code": 1327
905+
},
906+
"Property value can only be string literal, numeric literal, 'true', 'false', 'null', object literal or array literal.": {
907+
"category": "Error",
908+
"code": 1328
909+
},
902910

903911
"Duplicate identifier '{0}'.": {
904912
"category": "Error",

src/compiler/emitter.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,70 @@ namespace ts {
88
const delimiters = createDelimiterMap();
99
const brackets = createBracketsMap();
1010

11+
/*@internal*/
12+
/**
13+
* Iterates over the source files that are expected to have an emit output.
14+
*
15+
* @param host An EmitHost.
16+
* @param action The action to execute.
17+
* @param sourceFilesOrTargetSourceFile
18+
* If an array, the full list of source files to emit.
19+
* Else, calls `getSourceFilesToEmit` with the (optional) target source file to determine the list of source files to emit.
20+
*/
21+
export function forEachEmittedFile(
22+
host: EmitHost, action: (emitFileNames: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle, emitOnlyDtsFiles: boolean) => void,
23+
sourceFilesOrTargetSourceFile?: SourceFile[] | SourceFile,
24+
emitOnlyDtsFiles?: boolean) {
25+
26+
const sourceFiles = isArray(sourceFilesOrTargetSourceFile) ? sourceFilesOrTargetSourceFile : getSourceFilesToEmit(host, sourceFilesOrTargetSourceFile);
27+
const options = host.getCompilerOptions();
28+
if (options.outFile || options.out) {
29+
if (sourceFiles.length) {
30+
const jsFilePath = options.outFile || options.out;
31+
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
32+
const declarationFilePath = options.declaration ? removeFileExtension(jsFilePath) + Extension.Dts : "";
33+
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, createBundle(sourceFiles), emitOnlyDtsFiles);
34+
}
35+
}
36+
else {
37+
for (const sourceFile of sourceFiles) {
38+
const jsFilePath = getOwnEmitOutputFilePath(sourceFile, host, getOutputExtension(sourceFile, options));
39+
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
40+
const declarationFilePath = !isSourceFileJavaScript(sourceFile) && (emitOnlyDtsFiles || options.declaration) ? getDeclarationEmitOutputFilePath(sourceFile, host) : undefined;
41+
action({ jsFilePath, sourceMapFilePath, declarationFilePath }, sourceFile, emitOnlyDtsFiles);
42+
}
43+
}
44+
}
45+
46+
function getSourceMapFilePath(jsFilePath: string, options: CompilerOptions) {
47+
return options.sourceMap ? jsFilePath + ".map" : undefined;
48+
}
49+
50+
// JavaScript files are always LanguageVariant.JSX, as JSX syntax is allowed in .js files also.
51+
// So for JavaScript files, '.jsx' is only emitted if the input was '.jsx', and JsxEmit.Preserve.
52+
// For TypeScript, the only time to emit with a '.jsx' extension, is on JSX input, and JsxEmit.Preserve
53+
function getOutputExtension(sourceFile: SourceFile, options: CompilerOptions): Extension {
54+
if (options.jsx === JsxEmit.Preserve) {
55+
if (isSourceFileJavaScript(sourceFile)) {
56+
if (fileExtensionIs(sourceFile.fileName, Extension.Jsx)) {
57+
return Extension.Jsx;
58+
}
59+
}
60+
else if (sourceFile.languageVariant === LanguageVariant.JSX) {
61+
// TypeScript source file preserving JSX syntax
62+
return Extension.Jsx;
63+
}
64+
}
65+
return Extension.Js;
66+
}
67+
68+
function getOriginalSourceFileOrBundle(sourceFileOrBundle: SourceFile | Bundle) {
69+
if (sourceFileOrBundle.kind === SyntaxKind.Bundle) {
70+
return updateBundle(sourceFileOrBundle, sameMap(sourceFileOrBundle.sourceFiles, getOriginalSourceFile));
71+
}
72+
return getOriginalSourceFile(sourceFileOrBundle);
73+
}
74+
1175
/*@internal*/
1276
// targetSourceFile is when users only want one file in entire project to be emitted. This is used in compileOnSave feature
1377
export function emitFiles(resolver: EmitResolver, host: EmitHost, targetSourceFile: SourceFile, emitOnlyDtsFiles?: boolean, transformers?: TransformerFactory<SourceFile>[]): EmitResult {

src/compiler/factory.ts

Lines changed: 0 additions & 191 deletions
Original file line numberDiff line numberDiff line change
@@ -2287,14 +2287,6 @@ namespace ts {
22872287
return range;
22882288
}
22892289

2290-
/**
2291-
* Gets flags that control emit behavior of a node.
2292-
*/
2293-
export function getEmitFlags(node: Node): EmitFlags | undefined {
2294-
const emitNode = node.emitNode;
2295-
return emitNode && emitNode.flags;
2296-
}
2297-
22982290
/**
22992291
* Sets flags that control emit behavior of a node.
23002292
*/
@@ -3809,16 +3801,6 @@ namespace ts {
38093801
return node;
38103802
}
38113803

3812-
export function skipPartiallyEmittedExpressions(node: Expression): Expression;
3813-
export function skipPartiallyEmittedExpressions(node: Node): Node;
3814-
export function skipPartiallyEmittedExpressions(node: Node) {
3815-
while (node.kind === SyntaxKind.PartiallyEmittedExpression) {
3816-
node = (<PartiallyEmittedExpression>node).expression;
3817-
}
3818-
3819-
return node;
3820-
}
3821-
38223804
function updateOuterExpression(outerExpression: OuterExpression, expression: Expression) {
38233805
switch (outerExpression.kind) {
38243806
case SyntaxKind.ParenthesizedExpression: return updateParen(outerExpression, expression);
@@ -4239,177 +4221,4 @@ namespace ts {
42394221
Debug.assertNode(node, isExpression);
42404222
return <Expression>node;
42414223
}
4242-
4243-
export interface ExternalModuleInfo {
4244-
externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[]; // imports of other external modules
4245-
externalHelpersImportDeclaration: ImportDeclaration | undefined; // import of external helpers
4246-
exportSpecifiers: Map<ExportSpecifier[]>; // export specifiers by name
4247-
exportedBindings: Identifier[][]; // exported names of local declarations
4248-
exportedNames: Identifier[]; // all exported names local to module
4249-
exportEquals: ExportAssignment | undefined; // an export= declaration if one was present
4250-
hasExportStarsToExportValues: boolean; // whether this module contains export*
4251-
}
4252-
4253-
export function collectExternalModuleInfo(sourceFile: SourceFile, resolver: EmitResolver, compilerOptions: CompilerOptions): ExternalModuleInfo {
4254-
const externalImports: (ImportDeclaration | ImportEqualsDeclaration | ExportDeclaration)[] = [];
4255-
const exportSpecifiers = createMultiMap<ExportSpecifier>();
4256-
const exportedBindings: Identifier[][] = [];
4257-
const uniqueExports = createMap<boolean>();
4258-
let exportedNames: Identifier[];
4259-
let hasExportDefault = false;
4260-
let exportEquals: ExportAssignment = undefined;
4261-
let hasExportStarsToExportValues = false;
4262-
4263-
for (const node of sourceFile.statements) {
4264-
switch (node.kind) {
4265-
case SyntaxKind.ImportDeclaration:
4266-
// import "mod"
4267-
// import x from "mod"
4268-
// import * as x from "mod"
4269-
// import { x, y } from "mod"
4270-
externalImports.push(<ImportDeclaration>node);
4271-
break;
4272-
4273-
case SyntaxKind.ImportEqualsDeclaration:
4274-
if ((<ImportEqualsDeclaration>node).moduleReference.kind === SyntaxKind.ExternalModuleReference) {
4275-
// import x = require("mod")
4276-
externalImports.push(<ImportEqualsDeclaration>node);
4277-
}
4278-
4279-
break;
4280-
4281-
case SyntaxKind.ExportDeclaration:
4282-
if ((<ExportDeclaration>node).moduleSpecifier) {
4283-
if (!(<ExportDeclaration>node).exportClause) {
4284-
// export * from "mod"
4285-
externalImports.push(<ExportDeclaration>node);
4286-
hasExportStarsToExportValues = true;
4287-
}
4288-
else {
4289-
// export { x, y } from "mod"
4290-
externalImports.push(<ExportDeclaration>node);
4291-
}
4292-
}
4293-
else {
4294-
// export { x, y }
4295-
for (const specifier of (<ExportDeclaration>node).exportClause.elements) {
4296-
if (!uniqueExports.get(specifier.name.text)) {
4297-
const name = specifier.propertyName || specifier.name;
4298-
exportSpecifiers.add(name.text, specifier);
4299-
4300-
const decl = resolver.getReferencedImportDeclaration(name)
4301-
|| resolver.getReferencedValueDeclaration(name);
4302-
4303-
if (decl) {
4304-
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(decl), specifier.name);
4305-
}
4306-
4307-
uniqueExports.set(specifier.name.text, true);
4308-
exportedNames = append(exportedNames, specifier.name);
4309-
}
4310-
}
4311-
}
4312-
break;
4313-
4314-
case SyntaxKind.ExportAssignment:
4315-
if ((<ExportAssignment>node).isExportEquals && !exportEquals) {
4316-
// export = x
4317-
exportEquals = <ExportAssignment>node;
4318-
}
4319-
break;
4320-
4321-
case SyntaxKind.VariableStatement:
4322-
if (hasModifier(node, ModifierFlags.Export)) {
4323-
for (const decl of (<VariableStatement>node).declarationList.declarations) {
4324-
exportedNames = collectExportedVariableInfo(decl, uniqueExports, exportedNames);
4325-
}
4326-
}
4327-
break;
4328-
4329-
case SyntaxKind.FunctionDeclaration:
4330-
if (hasModifier(node, ModifierFlags.Export)) {
4331-
if (hasModifier(node, ModifierFlags.Default)) {
4332-
// export default function() { }
4333-
if (!hasExportDefault) {
4334-
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), getDeclarationName(<FunctionDeclaration>node));
4335-
hasExportDefault = true;
4336-
}
4337-
}
4338-
else {
4339-
// export function x() { }
4340-
const name = (<FunctionDeclaration>node).name;
4341-
if (!uniqueExports.get(name.text)) {
4342-
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
4343-
uniqueExports.set(name.text, true);
4344-
exportedNames = append(exportedNames, name);
4345-
}
4346-
}
4347-
}
4348-
break;
4349-
4350-
case SyntaxKind.ClassDeclaration:
4351-
if (hasModifier(node, ModifierFlags.Export)) {
4352-
if (hasModifier(node, ModifierFlags.Default)) {
4353-
// export default class { }
4354-
if (!hasExportDefault) {
4355-
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), getDeclarationName(<ClassDeclaration>node));
4356-
hasExportDefault = true;
4357-
}
4358-
}
4359-
else {
4360-
// export class x { }
4361-
const name = (<ClassDeclaration>node).name;
4362-
if (!uniqueExports.get(name.text)) {
4363-
multiMapSparseArrayAdd(exportedBindings, getOriginalNodeId(node), name);
4364-
uniqueExports.set(name.text, true);
4365-
exportedNames = append(exportedNames, name);
4366-
}
4367-
}
4368-
}
4369-
break;
4370-
}
4371-
}
4372-
4373-
const externalHelpersModuleName = getOrCreateExternalHelpersModuleNameIfNeeded(sourceFile, compilerOptions, hasExportStarsToExportValues);
4374-
const externalHelpersImportDeclaration = externalHelpersModuleName && createImportDeclaration(
4375-
/*decorators*/ undefined,
4376-
/*modifiers*/ undefined,
4377-
createImportClause(/*name*/ undefined, createNamespaceImport(externalHelpersModuleName)),
4378-
createLiteral(externalHelpersModuleNameText));
4379-
4380-
if (externalHelpersImportDeclaration) {
4381-
externalImports.unshift(externalHelpersImportDeclaration);
4382-
}
4383-
4384-
return { externalImports, exportSpecifiers, exportEquals, hasExportStarsToExportValues, exportedBindings, exportedNames, externalHelpersImportDeclaration };
4385-
}
4386-
4387-
function collectExportedVariableInfo(decl: VariableDeclaration | BindingElement, uniqueExports: Map<boolean>, exportedNames: Identifier[]) {
4388-
if (isBindingPattern(decl.name)) {
4389-
for (const element of decl.name.elements) {
4390-
if (!isOmittedExpression(element)) {
4391-
exportedNames = collectExportedVariableInfo(element, uniqueExports, exportedNames);
4392-
}
4393-
}
4394-
}
4395-
else if (!isGeneratedIdentifier(decl.name)) {
4396-
if (!uniqueExports.get(decl.name.text)) {
4397-
uniqueExports.set(decl.name.text, true);
4398-
exportedNames = append(exportedNames, decl.name);
4399-
}
4400-
}
4401-
return exportedNames;
4402-
}
4403-
4404-
/** Use a sparse array as a multi-map. */
4405-
function multiMapSparseArrayAdd<V>(map: V[][], key: number, value: V): V[] {
4406-
let values = map[key];
4407-
if (values) {
4408-
values.push(value);
4409-
}
4410-
else {
4411-
map[key] = values = [value];
4412-
}
4413-
return values;
4414-
}
44154224
}

src/compiler/parser.ts

Lines changed: 36 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
/// <reference path="utilities.ts"/>
22
/// <reference path="scanner.ts"/>
3-
/// <reference path="factory.ts"/>
43

54
namespace ts {
65
let NodeConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
@@ -466,6 +465,15 @@ namespace ts {
466465
return Parser.parseIsolatedEntityName(text, languageVersion);
467466
}
468467

468+
/**
469+
* Parse json text into SyntaxTree and return node and parse errors if any
470+
* @param fileName
471+
* @param sourceText
472+
*/
473+
export function parseJsonText(fileName: string, sourceText: string): JsonSourceFile {
474+
return Parser.parseJsonText(fileName, sourceText);
475+
}
476+
469477
// See also `isExternalOrCommonJsModule` in utilities.ts
470478
export function isExternalModule(file: SourceFile): boolean {
471479
return file.externalModuleIndicator !== undefined;
@@ -632,9 +640,34 @@ namespace ts {
632640
return isInvalid ? entityName : undefined;
633641
}
634642

643+
export function parseJsonText(fileName: string, sourceText: string): JsonSourceFile {
644+
initializeState(sourceText, ScriptTarget.ES2015, /*syntaxCursor*/ undefined, ScriptKind.JSON);
645+
// Set source file so that errors will be reported with this file name
646+
sourceFile = createSourceFile(fileName, ScriptTarget.ES2015, ScriptKind.JSON);
647+
const result = <JsonSourceFile>sourceFile;
648+
649+
// Prime the scanner.
650+
nextToken();
651+
if (token() === SyntaxKind.EndOfFileToken) {
652+
sourceFile.endOfFileToken = <EndOfFileToken>parseTokenNode();
653+
}
654+
else if (token() === SyntaxKind.OpenBraceToken ||
655+
lookAhead(() => token() === SyntaxKind.StringLiteral)) {
656+
result.jsonObject = parseObjectLiteralExpression();
657+
sourceFile.endOfFileToken = parseExpectedToken(SyntaxKind.EndOfFileToken, /*reportAtCurrentPosition*/ false, Diagnostics.Unexpected_token);
658+
}
659+
else {
660+
parseExpected(SyntaxKind.OpenBraceToken);
661+
}
662+
663+
sourceFile.parseDiagnostics = parseDiagnostics;
664+
clearState();
665+
return result;
666+
}
667+
635668
function getLanguageVariant(scriptKind: ScriptKind) {
636669
// .tsx and .jsx files are treated as jsx language variant.
637-
return scriptKind === ScriptKind.TSX || scriptKind === ScriptKind.JSX || scriptKind === ScriptKind.JS ? LanguageVariant.JSX : LanguageVariant.Standard;
670+
return scriptKind === ScriptKind.TSX || scriptKind === ScriptKind.JSX || scriptKind === ScriptKind.JS || scriptKind === ScriptKind.JSON ? LanguageVariant.JSX : LanguageVariant.Standard;
638671
}
639672

640673
function initializeState(_sourceText: string, languageVersion: ScriptTarget, _syntaxCursor: IncrementalParser.SyntaxCursor, scriptKind: ScriptKind) {
@@ -652,7 +685,7 @@ namespace ts {
652685
identifierCount = 0;
653686
nodeCount = 0;
654687

655-
contextFlags = scriptKind === ScriptKind.JS || scriptKind === ScriptKind.JSX ? NodeFlags.JavaScriptFile : NodeFlags.None;
688+
contextFlags = scriptKind === ScriptKind.JS || scriptKind === ScriptKind.JSX || scriptKind === ScriptKind.JSON ? NodeFlags.JavaScriptFile : NodeFlags.None;
656689
parseErrorBeforeNextFinishedNode = false;
657690

658691
// Initialize and prime the scanner before parsing the source elements.

0 commit comments

Comments
 (0)