mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into add-codefix-cannot-find-name-in-for-loop
This commit is contained in:
+36
-28
@@ -274,6 +274,9 @@ namespace ts {
|
||||
if (isStringOrNumericLiteralLike(nameExpression)) {
|
||||
return escapeLeadingUnderscores(nameExpression.text);
|
||||
}
|
||||
if (isSignedNumericLiteral(nameExpression)) {
|
||||
return tokenToString(nameExpression.operator) + nameExpression.operand.text as __String;
|
||||
}
|
||||
|
||||
Debug.assert(isWellKnownSymbolSyntactically(nameExpression));
|
||||
return getPropertyNameForKnownSymbolName(idText((<PropertyAccessExpression>nameExpression).name));
|
||||
@@ -2515,7 +2518,7 @@ namespace ts {
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.fail(Debug.showSyntaxKind(thisContainer));
|
||||
Debug.failBadSyntaxKind(thisContainer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2581,7 +2584,7 @@ namespace ts {
|
||||
// Fix up parent pointers since we're going to use these nodes before we bind into them
|
||||
node.left.parent = node;
|
||||
node.right.parent = node;
|
||||
if (isIdentifier(lhs.expression) && container === file && isNameOfExportsOrModuleExportsAliasDeclaration(file, lhs.expression)) {
|
||||
if (isIdentifier(lhs.expression) && container === file && isExportsOrModuleExportsOrAlias(file, lhs.expression)) {
|
||||
// This can be an alias for the 'exports' or 'module.exports' names, e.g.
|
||||
// var util = module.exports;
|
||||
// util.property = function ...
|
||||
@@ -2975,21 +2978,27 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function isExportsOrModuleExportsOrAlias(sourceFile: SourceFile, node: Expression): boolean {
|
||||
return isExportsIdentifier(node) ||
|
||||
isModuleExportsPropertyAccessExpression(node) ||
|
||||
isIdentifier(node) && isNameOfExportsOrModuleExportsAliasDeclaration(sourceFile, node);
|
||||
}
|
||||
|
||||
function isNameOfExportsOrModuleExportsAliasDeclaration(sourceFile: SourceFile, node: Identifier): boolean {
|
||||
const symbol = lookupSymbolForNameWorker(sourceFile, node.escapedText);
|
||||
return !!symbol && !!symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) &&
|
||||
!!symbol.valueDeclaration.initializer && isExportsOrModuleExportsOrAliasOrAssignment(sourceFile, symbol.valueDeclaration.initializer);
|
||||
}
|
||||
|
||||
function isExportsOrModuleExportsOrAliasOrAssignment(sourceFile: SourceFile, node: Expression): boolean {
|
||||
return isExportsOrModuleExportsOrAlias(sourceFile, node) ||
|
||||
(isAssignmentExpression(node, /*excludeCompoundAssignment*/ true) && (
|
||||
isExportsOrModuleExportsOrAliasOrAssignment(sourceFile, node.left) || isExportsOrModuleExportsOrAliasOrAssignment(sourceFile, node.right)));
|
||||
let i = 0;
|
||||
const q = [node];
|
||||
while (q.length && i < 100) {
|
||||
i++;
|
||||
node = q.shift()!;
|
||||
if (isExportsIdentifier(node) || isModuleExportsPropertyAccessExpression(node)) {
|
||||
return true;
|
||||
}
|
||||
else if (isIdentifier(node)) {
|
||||
const symbol = lookupSymbolForNameWorker(sourceFile, node.escapedText);
|
||||
if (!!symbol && !!symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) && !!symbol.valueDeclaration.initializer) {
|
||||
const init = symbol.valueDeclaration.initializer;
|
||||
q.push(init);
|
||||
if (isAssignmentExpression(init, /*excludeCompoundAssignment*/ true)) {
|
||||
q.push(init.left);
|
||||
q.push(init.right);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function lookupSymbolForNameWorker(container: Node, name: __String): Symbol | undefined {
|
||||
@@ -3223,8 +3232,7 @@ namespace ts {
|
||||
// A ClassDeclaration is ES6 syntax.
|
||||
transformFlags = subtreeFlags | TransformFlags.AssertES2015;
|
||||
|
||||
// A class with a parameter property assignment, property initializer, computed property name, or decorator is
|
||||
// TypeScript syntax.
|
||||
// A class with a parameter property assignment or decorator is TypeScript syntax.
|
||||
// An exported declaration may be TypeScript syntax, but is handled by the visitor
|
||||
// for a namespace declaration.
|
||||
if ((subtreeFlags & TransformFlags.ContainsTypeScriptClassSyntax)
|
||||
@@ -3241,8 +3249,7 @@ namespace ts {
|
||||
// A ClassExpression is ES6 syntax.
|
||||
let transformFlags = subtreeFlags | TransformFlags.AssertES2015;
|
||||
|
||||
// A class with a parameter property assignment, property initializer, or decorator is
|
||||
// TypeScript syntax.
|
||||
// A class with a parameter property assignment or decorator is TypeScript syntax.
|
||||
if (subtreeFlags & TransformFlags.ContainsTypeScriptClassSyntax
|
||||
|| node.typeParameters) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
@@ -3332,7 +3339,6 @@ namespace ts {
|
||||
|| hasModifier(node, ModifierFlags.TypeScriptModifier)
|
||||
|| node.typeParameters
|
||||
|| node.type
|
||||
|| (node.name && isComputedPropertyName(node.name)) // While computed method names aren't typescript, the TS transform must visit them to emit property declarations correctly
|
||||
|| !node.body) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
@@ -3363,7 +3369,6 @@ namespace ts {
|
||||
if (node.decorators
|
||||
|| hasModifier(node, ModifierFlags.TypeScriptModifier)
|
||||
|| node.type
|
||||
|| (node.name && isComputedPropertyName(node.name)) // While computed accessor names aren't typescript, the TS transform must visit them to emit property declarations correctly
|
||||
|| !node.body) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
@@ -3378,12 +3383,15 @@ namespace ts {
|
||||
}
|
||||
|
||||
function computePropertyDeclaration(node: PropertyDeclaration, subtreeFlags: TransformFlags) {
|
||||
// A PropertyDeclaration is TypeScript syntax.
|
||||
let transformFlags = subtreeFlags | TransformFlags.AssertTypeScript;
|
||||
let transformFlags = subtreeFlags | TransformFlags.ContainsClassFields;
|
||||
|
||||
// If the PropertyDeclaration has an initializer or a computed name, we need to inform its ancestor
|
||||
// so that it handle the transformation.
|
||||
if (node.initializer || isComputedPropertyName(node.name)) {
|
||||
// Decorators, TypeScript-specific modifiers, and type annotations are TypeScript syntax.
|
||||
if (some(node.decorators) || hasModifier(node, ModifierFlags.TypeScriptModifier) || node.type) {
|
||||
transformFlags |= TransformFlags.AssertTypeScript;
|
||||
}
|
||||
|
||||
// Hoisted variables related to class properties should live within the TypeScript class wrapper.
|
||||
if (isComputedPropertyName(node.name) || (hasStaticModifier(node) && node.initializer)) {
|
||||
transformFlags |= TransformFlags.ContainsTypeScriptClassSyntax;
|
||||
}
|
||||
|
||||
|
||||
+139
-70
@@ -10,18 +10,13 @@ namespace ts {
|
||||
export interface ReusableDiagnosticRelatedInformation {
|
||||
category: DiagnosticCategory;
|
||||
code: number;
|
||||
file: Path | undefined;
|
||||
file: string | undefined;
|
||||
start: number | undefined;
|
||||
length: number | undefined;
|
||||
messageText: string | ReusableDiagnosticMessageChain;
|
||||
}
|
||||
|
||||
export interface ReusableDiagnosticMessageChain {
|
||||
messageText: string;
|
||||
category: DiagnosticCategory;
|
||||
code: number;
|
||||
next?: ReusableDiagnosticMessageChain;
|
||||
}
|
||||
export type ReusableDiagnosticMessageChain = DiagnosticMessageChain;
|
||||
|
||||
export interface ReusableBuilderProgramState extends ReusableBuilderState {
|
||||
/**
|
||||
@@ -227,7 +222,7 @@ namespace ts {
|
||||
// Unchanged file copy diagnostics
|
||||
const diagnostics = oldState!.semanticDiagnosticsPerFile!.get(sourceFilePath);
|
||||
if (diagnostics) {
|
||||
state.semanticDiagnosticsPerFile!.set(sourceFilePath, oldState!.hasReusableDiagnostic ? convertToDiagnostics(diagnostics as ReadonlyArray<ReusableDiagnostic>, newProgram) : diagnostics as ReadonlyArray<Diagnostic>);
|
||||
state.semanticDiagnosticsPerFile!.set(sourceFilePath, oldState!.hasReusableDiagnostic ? convertToDiagnostics(diagnostics as ReadonlyArray<ReusableDiagnostic>, newProgram, getCanonicalFileName) : diagnostics as ReadonlyArray<Diagnostic>);
|
||||
if (!state.semanticDiagnosticsFromOldState) {
|
||||
state.semanticDiagnosticsFromOldState = createMap<true>();
|
||||
}
|
||||
@@ -246,37 +241,32 @@ namespace ts {
|
||||
return state;
|
||||
}
|
||||
|
||||
function convertToDiagnostics(diagnostics: ReadonlyArray<ReusableDiagnostic>, newProgram: Program): ReadonlyArray<Diagnostic> {
|
||||
function convertToDiagnostics(diagnostics: ReadonlyArray<ReusableDiagnostic>, newProgram: Program, getCanonicalFileName: GetCanonicalFileName): ReadonlyArray<Diagnostic> {
|
||||
if (!diagnostics.length) return emptyArray;
|
||||
const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(getOutputPathForBuildInfo(newProgram.getCompilerOptions())!, newProgram.getCurrentDirectory()));
|
||||
return diagnostics.map(diagnostic => {
|
||||
const result: Diagnostic = convertToDiagnosticRelatedInformation(diagnostic, newProgram);
|
||||
const result: Diagnostic = convertToDiagnosticRelatedInformation(diagnostic, newProgram, toPath);
|
||||
result.reportsUnnecessary = diagnostic.reportsUnnecessary;
|
||||
result.source = diagnostic.source;
|
||||
const { relatedInformation } = diagnostic;
|
||||
result.relatedInformation = relatedInformation ?
|
||||
relatedInformation.length ?
|
||||
relatedInformation.map(r => convertToDiagnosticRelatedInformation(r, newProgram)) :
|
||||
relatedInformation.map(r => convertToDiagnosticRelatedInformation(r, newProgram, toPath)) :
|
||||
emptyArray :
|
||||
undefined;
|
||||
return result;
|
||||
});
|
||||
|
||||
function toPath(path: string) {
|
||||
return ts.toPath(path, buildInfoDirectory, getCanonicalFileName);
|
||||
}
|
||||
}
|
||||
|
||||
function convertToDiagnosticRelatedInformation(diagnostic: ReusableDiagnosticRelatedInformation, newProgram: Program): DiagnosticRelatedInformation {
|
||||
const { file, messageText } = diagnostic;
|
||||
function convertToDiagnosticRelatedInformation(diagnostic: ReusableDiagnosticRelatedInformation, newProgram: Program, toPath: (path: string) => Path): DiagnosticRelatedInformation {
|
||||
const { file } = diagnostic;
|
||||
return {
|
||||
...diagnostic,
|
||||
file: file && newProgram.getSourceFileByPath(file),
|
||||
messageText: messageText === undefined || isString(messageText) ?
|
||||
messageText :
|
||||
convertToDiagnosticMessageChain(messageText, newProgram)
|
||||
};
|
||||
}
|
||||
|
||||
function convertToDiagnosticMessageChain(diagnostic: ReusableDiagnosticMessageChain, newProgram: Program): DiagnosticMessageChain {
|
||||
return {
|
||||
...diagnostic,
|
||||
next: diagnostic.next && convertToDiagnosticMessageChain(diagnostic.next, newProgram)
|
||||
file: file ? newProgram.getSourceFileByPath(toPath(file)) : undefined
|
||||
};
|
||||
}
|
||||
|
||||
@@ -620,19 +610,23 @@ namespace ts {
|
||||
/**
|
||||
* Gets the program information to be emitted in buildInfo so that we can use it to create new program
|
||||
*/
|
||||
function getProgramBuildInfo(state: Readonly<ReusableBuilderProgramState>): ProgramBuildInfo | undefined {
|
||||
function getProgramBuildInfo(state: Readonly<ReusableBuilderProgramState>, getCanonicalFileName: GetCanonicalFileName): ProgramBuildInfo | undefined {
|
||||
if (state.compilerOptions.outFile || state.compilerOptions.out) return undefined;
|
||||
const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(getOutputPathForBuildInfo(state.compilerOptions)!, Debug.assertDefined(state.program).getCurrentDirectory()));
|
||||
const fileInfos: MapLike<BuilderState.FileInfo> = {};
|
||||
state.fileInfos.forEach((value, key) => {
|
||||
const signature = state.currentAffectedFilesSignatures && state.currentAffectedFilesSignatures.get(key);
|
||||
fileInfos[key] = signature === undefined ? value : { version: value.version, signature };
|
||||
fileInfos[relativeToBuildInfo(key)] = signature === undefined ? value : { version: value.version, signature };
|
||||
});
|
||||
|
||||
const result: ProgramBuildInfo = { fileInfos, options: state.compilerOptions };
|
||||
const result: ProgramBuildInfo = {
|
||||
fileInfos,
|
||||
options: convertToReusableCompilerOptions(state.compilerOptions, relativeToBuildInfo)
|
||||
};
|
||||
if (state.referencedMap) {
|
||||
const referencedMap: MapLike<string[]> = {};
|
||||
state.referencedMap.forEach((value, key) => {
|
||||
referencedMap[key] = arrayFrom(value.keys());
|
||||
referencedMap[relativeToBuildInfo(key)] = arrayFrom(value.keys(), relativeToBuildInfo);
|
||||
});
|
||||
result.referencedMap = referencedMap;
|
||||
}
|
||||
@@ -642,9 +636,9 @@ namespace ts {
|
||||
state.exportedModulesMap.forEach((value, key) => {
|
||||
const newValue = state.currentAffectedFilesExportedModulesMap && state.currentAffectedFilesExportedModulesMap.get(key);
|
||||
// Not in temporary cache, use existing value
|
||||
if (newValue === undefined) exportedModulesMap[key] = arrayFrom(value.keys());
|
||||
if (newValue === undefined) exportedModulesMap[relativeToBuildInfo(key)] = arrayFrom(value.keys(), relativeToBuildInfo);
|
||||
// Value in cache and has updated value map, use that
|
||||
else if (newValue) exportedModulesMap[key] = arrayFrom(newValue.keys());
|
||||
else if (newValue) exportedModulesMap[relativeToBuildInfo(key)] = arrayFrom(newValue.keys(), relativeToBuildInfo);
|
||||
});
|
||||
result.exportedModulesMap = exportedModulesMap;
|
||||
}
|
||||
@@ -655,50 +649,78 @@ namespace ts {
|
||||
state.semanticDiagnosticsPerFile.forEach((value, key) => semanticDiagnosticsPerFile.push(
|
||||
value.length ?
|
||||
[
|
||||
key,
|
||||
relativeToBuildInfo(key),
|
||||
state.hasReusableDiagnostic ?
|
||||
value as ReadonlyArray<ReusableDiagnostic> :
|
||||
convertToReusableDiagnostics(value as ReadonlyArray<Diagnostic>)
|
||||
convertToReusableDiagnostics(value as ReadonlyArray<Diagnostic>, relativeToBuildInfo)
|
||||
] :
|
||||
key
|
||||
relativeToBuildInfo(key)
|
||||
));
|
||||
result.semanticDiagnosticsPerFile = semanticDiagnosticsPerFile;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
function relativeToBuildInfo(path: string) {
|
||||
return ensurePathIsNonModuleName(getRelativePathFromDirectory(buildInfoDirectory, path, getCanonicalFileName));
|
||||
}
|
||||
}
|
||||
|
||||
function convertToReusableDiagnostics(diagnostics: ReadonlyArray<Diagnostic>): ReadonlyArray<ReusableDiagnostic> {
|
||||
function convertToReusableCompilerOptions(options: CompilerOptions, relativeToBuildInfo: (path: string) => string) {
|
||||
const result: CompilerOptions = {};
|
||||
const optionsNameMap = getOptionNameMap().optionNameMap;
|
||||
|
||||
for (const name in options) {
|
||||
if (hasProperty(options, name)) {
|
||||
result[name] = convertToReusableCompilerOptionValue(
|
||||
optionsNameMap.get(name.toLowerCase()),
|
||||
options[name] as CompilerOptionsValue,
|
||||
relativeToBuildInfo
|
||||
);
|
||||
}
|
||||
}
|
||||
if (result.configFilePath) {
|
||||
result.configFilePath = relativeToBuildInfo(result.configFilePath);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function convertToReusableCompilerOptionValue(option: CommandLineOption | undefined, value: CompilerOptionsValue, relativeToBuildInfo: (path: string) => string) {
|
||||
if (option) {
|
||||
if (option.type === "list") {
|
||||
const values = value as ReadonlyArray<string | number>;
|
||||
if (option.element.isFilePath && values.length) {
|
||||
return values.map(relativeToBuildInfo);
|
||||
}
|
||||
}
|
||||
else if (option.isFilePath) {
|
||||
return relativeToBuildInfo(value as string);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function convertToReusableDiagnostics(diagnostics: ReadonlyArray<Diagnostic>, relativeToBuildInfo: (path: string) => string): ReadonlyArray<ReusableDiagnostic> {
|
||||
Debug.assert(!!diagnostics.length);
|
||||
return diagnostics.map(diagnostic => {
|
||||
const result: ReusableDiagnostic = convertToReusableDiagnosticRelatedInformation(diagnostic);
|
||||
const result: ReusableDiagnostic = convertToReusableDiagnosticRelatedInformation(diagnostic, relativeToBuildInfo);
|
||||
result.reportsUnnecessary = diagnostic.reportsUnnecessary;
|
||||
result.source = diagnostic.source;
|
||||
const { relatedInformation } = diagnostic;
|
||||
result.relatedInformation = relatedInformation ?
|
||||
relatedInformation.length ?
|
||||
relatedInformation.map(r => convertToReusableDiagnosticRelatedInformation(r)) :
|
||||
relatedInformation.map(r => convertToReusableDiagnosticRelatedInformation(r, relativeToBuildInfo)) :
|
||||
emptyArray :
|
||||
undefined;
|
||||
return result;
|
||||
});
|
||||
}
|
||||
|
||||
function convertToReusableDiagnosticRelatedInformation(diagnostic: DiagnosticRelatedInformation): ReusableDiagnosticRelatedInformation {
|
||||
const { file, messageText } = diagnostic;
|
||||
function convertToReusableDiagnosticRelatedInformation(diagnostic: DiagnosticRelatedInformation, relativeToBuildInfo: (path: string) => string): ReusableDiagnosticRelatedInformation {
|
||||
const { file } = diagnostic;
|
||||
return {
|
||||
...diagnostic,
|
||||
file: file && file.path,
|
||||
messageText: messageText === undefined || isString(messageText) ?
|
||||
messageText :
|
||||
convertToReusableDiagnosticMessageChain(messageText)
|
||||
};
|
||||
}
|
||||
|
||||
function convertToReusableDiagnosticMessageChain(diagnostic: DiagnosticMessageChain): ReusableDiagnosticMessageChain {
|
||||
return {
|
||||
...diagnostic,
|
||||
next: diagnostic.next && convertToReusableDiagnosticMessageChain(diagnostic.next)
|
||||
file: file ? relativeToBuildInfo(file.path) : undefined
|
||||
};
|
||||
}
|
||||
|
||||
@@ -767,7 +789,7 @@ namespace ts {
|
||||
const computeHash = host.createHash || generateDjb2Hash;
|
||||
let state = createBuilderProgramState(newProgram, getCanonicalFileName, oldState);
|
||||
let backupState: BuilderProgramState | undefined;
|
||||
newProgram.getProgramBuildInfo = () => getProgramBuildInfo(state);
|
||||
newProgram.getProgramBuildInfo = () => getProgramBuildInfo(state, getCanonicalFileName);
|
||||
|
||||
// To ensure that we arent storing any references to old program or new program without state
|
||||
newProgram = undefined!; // TODO: GH#18217
|
||||
@@ -796,6 +818,7 @@ namespace ts {
|
||||
(result as SemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile = getSemanticDiagnosticsOfNextAffectedFile;
|
||||
}
|
||||
else if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) {
|
||||
(result as EmitAndSemanticDiagnosticsBuilderProgram).getSemanticDiagnosticsOfNextAffectedFile = getSemanticDiagnosticsOfNextAffectedFile;
|
||||
(result as EmitAndSemanticDiagnosticsBuilderProgram).emitNextAffectedFile = emitNextAffectedFile;
|
||||
}
|
||||
else {
|
||||
@@ -913,6 +936,11 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
// Add file to affected file pending emit to handle for later emit time
|
||||
if (kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) {
|
||||
addToAffectedFilesPendingEmit(state, [(affected as SourceFile).path]);
|
||||
}
|
||||
|
||||
// Get diagnostics for the affected file if its not ignored
|
||||
if (ignoreSourceFile && ignoreSourceFile(affected as SourceFile)) {
|
||||
// Get next affected file
|
||||
@@ -951,18 +979,8 @@ namespace ts {
|
||||
|
||||
// When semantic builder asks for diagnostics of the whole program,
|
||||
// ensure that all the affected files are handled
|
||||
let affected: SourceFile | Program | undefined;
|
||||
let affectedFilesPendingEmit: Path[] | undefined;
|
||||
while (affected = getNextAffectedFile(state, cancellationToken, computeHash)) {
|
||||
if (affected !== state.program && kind === BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram) {
|
||||
(affectedFilesPendingEmit || (affectedFilesPendingEmit = [])).push((affected as SourceFile).path);
|
||||
}
|
||||
doneWithAffectedFile(state, affected);
|
||||
}
|
||||
|
||||
// In case of emit builder, cache the files to be emitted
|
||||
if (affectedFilesPendingEmit) {
|
||||
addToAffectedFilesPendingEmit(state, affectedFilesPendingEmit);
|
||||
// tslint:disable-next-line no-empty
|
||||
while (getSemanticDiagnosticsOfNextAffectedFile(cancellationToken)) {
|
||||
}
|
||||
|
||||
let diagnostics: Diagnostic[] | undefined;
|
||||
@@ -984,26 +1002,35 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function getMapOfReferencedSet(mapLike: MapLike<ReadonlyArray<string>> | undefined): ReadonlyMap<BuilderState.ReferencedSet> | undefined {
|
||||
function getMapOfReferencedSet(mapLike: MapLike<ReadonlyArray<string>> | undefined, toPath: (path: string) => Path): ReadonlyMap<BuilderState.ReferencedSet> | undefined {
|
||||
if (!mapLike) return undefined;
|
||||
const map = createMap<BuilderState.ReferencedSet>();
|
||||
// Copies keys/values from template. Note that for..in will not throw if
|
||||
// template is undefined, and instead will just exit the loop.
|
||||
for (const key in mapLike) {
|
||||
if (hasProperty(mapLike, key)) {
|
||||
map.set(key, arrayToSet(mapLike[key]));
|
||||
map.set(toPath(key), arrayToSet(mapLike[key], toPath));
|
||||
}
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
export function createBuildProgramUsingProgramBuildInfo(program: ProgramBuildInfo): EmitAndSemanticDiagnosticsBuilderProgram & SemanticDiagnosticsBuilderProgram {
|
||||
const fileInfos = createMapFromTemplate(program.fileInfos);
|
||||
export function createBuildProgramUsingProgramBuildInfo(program: ProgramBuildInfo, buildInfoPath: string, host: ReadBuildProgramHost): EmitAndSemanticDiagnosticsBuilderProgram {
|
||||
const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(buildInfoPath, host.getCurrentDirectory()));
|
||||
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames());
|
||||
|
||||
const fileInfos = createMap<BuilderState.FileInfo>();
|
||||
for (const key in program.fileInfos) {
|
||||
if (hasProperty(program.fileInfos, key)) {
|
||||
fileInfos.set(toPath(key), program.fileInfos[key]);
|
||||
}
|
||||
}
|
||||
|
||||
const state: ReusableBuilderProgramState = {
|
||||
fileInfos,
|
||||
compilerOptions: program.options,
|
||||
referencedMap: getMapOfReferencedSet(program.referencedMap),
|
||||
exportedModulesMap: getMapOfReferencedSet(program.exportedModulesMap),
|
||||
compilerOptions: convertFromReusableCompilerOptions(program.options, toAbsolutePath),
|
||||
referencedMap: getMapOfReferencedSet(program.referencedMap, toPath),
|
||||
exportedModulesMap: getMapOfReferencedSet(program.exportedModulesMap, toPath),
|
||||
semanticDiagnosticsPerFile: program.semanticDiagnosticsPerFile && arrayToMap(program.semanticDiagnosticsPerFile, value => isString(value) ? value : value[0], value => isString(value) ? emptyArray : value[1]),
|
||||
hasReusableDiagnostic: true
|
||||
};
|
||||
@@ -1029,6 +1056,48 @@ namespace ts {
|
||||
emitNextAffectedFile: notImplemented,
|
||||
getSemanticDiagnosticsOfNextAffectedFile: notImplemented,
|
||||
};
|
||||
|
||||
function toPath(path: string) {
|
||||
return ts.toPath(path, buildInfoDirectory, getCanonicalFileName);
|
||||
}
|
||||
|
||||
function toAbsolutePath(path: string) {
|
||||
return getNormalizedAbsolutePath(path, buildInfoDirectory);
|
||||
}
|
||||
}
|
||||
|
||||
function convertFromReusableCompilerOptions(options: CompilerOptions, toAbsolutePath: (path: string) => string) {
|
||||
const result: CompilerOptions = {};
|
||||
const optionsNameMap = getOptionNameMap().optionNameMap;
|
||||
|
||||
for (const name in options) {
|
||||
if (hasProperty(options, name)) {
|
||||
result[name] = convertFromReusableCompilerOptionValue(
|
||||
optionsNameMap.get(name.toLowerCase()),
|
||||
options[name] as CompilerOptionsValue,
|
||||
toAbsolutePath
|
||||
);
|
||||
}
|
||||
}
|
||||
if (result.configFilePath) {
|
||||
result.configFilePath = toAbsolutePath(result.configFilePath);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
function convertFromReusableCompilerOptionValue(option: CommandLineOption | undefined, value: CompilerOptionsValue, toAbsolutePath: (path: string) => string) {
|
||||
if (option) {
|
||||
if (option.type === "list") {
|
||||
const values = value as ReadonlyArray<string | number>;
|
||||
if (option.element.isFilePath && values.length) {
|
||||
return values.map(toAbsolutePath);
|
||||
}
|
||||
}
|
||||
else if (option.isFilePath) {
|
||||
return toAbsolutePath(value as string);
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function createRedirectedBuilderProgram(state: { program: Program | undefined; compilerOptions: CompilerOptions; }, configFileParsingDiagnostics: ReadonlyArray<Diagnostic>): BuilderProgram {
|
||||
@@ -1181,7 +1250,7 @@ namespace ts {
|
||||
* The builder that can handle the changes in program and iterate through changed file to emit the files
|
||||
* The semantic diagnostics are cached per file and managed by clearing for the changed/affected files
|
||||
*/
|
||||
export interface EmitAndSemanticDiagnosticsBuilderProgram extends BuilderProgram {
|
||||
export interface EmitAndSemanticDiagnosticsBuilderProgram extends SemanticDiagnosticsBuilderProgram {
|
||||
/**
|
||||
* Emits the next affected file's emit result (EmitResult and sourceFiles emitted) or returns undefined if iteration is complete
|
||||
* The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host
|
||||
|
||||
+762
-369
File diff suppressed because it is too large
Load Diff
@@ -147,6 +147,12 @@ namespace ts {
|
||||
category: Diagnostics.Basic_Options,
|
||||
description: Diagnostics.Enable_incremental_compilation,
|
||||
},
|
||||
{
|
||||
name: "locale",
|
||||
type: "string",
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.The_locale_used_when_displaying_messages_to_the_user_e_g_en_us
|
||||
},
|
||||
];
|
||||
|
||||
/* @internal */
|
||||
@@ -239,6 +245,7 @@ namespace ts {
|
||||
esnext: ModuleKind.ESNext
|
||||
}),
|
||||
affectsModuleResolution: true,
|
||||
affectsEmit: true,
|
||||
paramType: Diagnostics.KIND,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Basic_Options,
|
||||
@@ -584,6 +591,7 @@ namespace ts {
|
||||
name: "esModuleInterop",
|
||||
type: "boolean",
|
||||
affectsSemanticDiagnostics: true,
|
||||
affectsEmit: true,
|
||||
showInSimplifiedHelpView: true,
|
||||
category: Diagnostics.Module_Resolution_Options,
|
||||
description: Diagnostics.Enables_emit_interoperability_between_CommonJS_and_ES_Modules_via_creation_of_namespace_objects_for_all_imports_Implies_allowSyntheticDefaultImports
|
||||
@@ -698,12 +706,6 @@ namespace ts {
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.Emit_a_UTF_8_Byte_Order_Mark_BOM_in_the_beginning_of_output_files
|
||||
},
|
||||
{
|
||||
name: "locale",
|
||||
type: "string",
|
||||
category: Diagnostics.Advanced_Options,
|
||||
description: Diagnostics.The_locale_used_when_displaying_messages_to_the_user_e_g_en_us
|
||||
},
|
||||
{
|
||||
name: "newLine",
|
||||
type: createMapFromTemplate({
|
||||
@@ -969,7 +971,8 @@ namespace ts {
|
||||
return typeAcquisition;
|
||||
}
|
||||
|
||||
function getOptionNameMap(): OptionNameMap {
|
||||
/* @internal */
|
||||
export function getOptionNameMap(): OptionNameMap {
|
||||
return optionNameMapCache || (optionNameMapCache = createOptionNameMap(optionDeclarations));
|
||||
}
|
||||
|
||||
@@ -1022,8 +1025,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface OptionsBase {
|
||||
interface OptionsBase {
|
||||
[option: string]: CompilerOptionsValue | undefined;
|
||||
}
|
||||
|
||||
@@ -1172,7 +1174,7 @@ namespace ts {
|
||||
export interface ParsedBuildCommand {
|
||||
buildOptions: BuildOptions;
|
||||
projects: string[];
|
||||
errors: ReadonlyArray<Diagnostic>;
|
||||
errors: Diagnostic[];
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
@@ -2361,7 +2363,7 @@ namespace ts {
|
||||
if (!host.fileExists(extendedConfigPath) && !endsWith(extendedConfigPath, Extension.Json)) {
|
||||
extendedConfigPath = `${extendedConfigPath}.json`;
|
||||
if (!host.fileExists(extendedConfigPath)) {
|
||||
errors.push(createDiagnostic(Diagnostics.File_0_does_not_exist, extendedConfig));
|
||||
errors.push(createDiagnostic(Diagnostics.File_0_not_found, extendedConfig));
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
@@ -2372,7 +2374,7 @@ namespace ts {
|
||||
if (resolved.resolvedModule) {
|
||||
return resolved.resolvedModule.resolvedFileName;
|
||||
}
|
||||
errors.push(createDiagnostic(Diagnostics.File_0_does_not_exist, extendedConfig));
|
||||
errors.push(createDiagnostic(Diagnostics.File_0_not_found, extendedConfig));
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
+1
-84
@@ -1,7 +1,7 @@
|
||||
namespace ts {
|
||||
// WARNING: The script `configureNightly.ts` uses a regexp to parse out these values.
|
||||
// If changing the text in this section, be sure to test `configureNightly` too.
|
||||
export const versionMajorMinor = "3.5";
|
||||
export const versionMajorMinor = "3.6";
|
||||
/** The version of the TypeScript compiler release */
|
||||
export const version = `${versionMajorMinor}.0-dev`;
|
||||
}
|
||||
@@ -1686,89 +1686,6 @@ namespace ts {
|
||||
export type AnyFunction = (...args: never[]) => void;
|
||||
export type AnyConstructor = new (...args: unknown[]) => unknown;
|
||||
|
||||
export namespace Debug {
|
||||
export let currentAssertionLevel = AssertionLevel.None;
|
||||
export let isDebugging = false;
|
||||
|
||||
export function shouldAssert(level: AssertionLevel): boolean {
|
||||
return currentAssertionLevel >= level;
|
||||
}
|
||||
|
||||
export function assert(expression: boolean, message?: string, verboseDebugInfo?: string | (() => string), stackCrawlMark?: AnyFunction): void {
|
||||
if (!expression) {
|
||||
if (verboseDebugInfo) {
|
||||
message += "\r\nVerbose Debug Information: " + (typeof verboseDebugInfo === "string" ? verboseDebugInfo : verboseDebugInfo());
|
||||
}
|
||||
fail(message ? "False expression: " + message : "False expression.", stackCrawlMark || assert);
|
||||
}
|
||||
}
|
||||
|
||||
export function assertEqual<T>(a: T, b: T, msg?: string, msg2?: string): void {
|
||||
if (a !== b) {
|
||||
const message = msg ? msg2 ? `${msg} ${msg2}` : msg : "";
|
||||
fail(`Expected ${a} === ${b}. ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function assertLessThan(a: number, b: number, msg?: string): void {
|
||||
if (a >= b) {
|
||||
fail(`Expected ${a} < ${b}. ${msg || ""}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function assertLessThanOrEqual(a: number, b: number): void {
|
||||
if (a > b) {
|
||||
fail(`Expected ${a} <= ${b}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function assertGreaterThanOrEqual(a: number, b: number): void {
|
||||
if (a < b) {
|
||||
fail(`Expected ${a} >= ${b}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function fail(message?: string, stackCrawlMark?: AnyFunction): never {
|
||||
debugger;
|
||||
const e = new Error(message ? `Debug Failure. ${message}` : "Debug Failure.");
|
||||
if ((<any>Error).captureStackTrace) {
|
||||
(<any>Error).captureStackTrace(e, stackCrawlMark || fail);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
export function assertDefined<T>(value: T | null | undefined, message?: string): T {
|
||||
if (value === undefined || value === null) return fail(message);
|
||||
return value;
|
||||
}
|
||||
|
||||
export function assertEachDefined<T, A extends ReadonlyArray<T>>(value: A, message?: string): A {
|
||||
for (const v of value) {
|
||||
assertDefined(v, message);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function assertNever(member: never, message = "Illegal value:", stackCrawlMark?: AnyFunction): never {
|
||||
const detail = typeof member === "object" && "kind" in member && "pos" in member ? "SyntaxKind: " + showSyntaxKind(member as Node) : JSON.stringify(member);
|
||||
return fail(`${message} ${detail}`, stackCrawlMark || assertNever);
|
||||
}
|
||||
|
||||
export function getFunctionName(func: AnyFunction) {
|
||||
if (typeof func !== "function") {
|
||||
return "";
|
||||
}
|
||||
else if (func.hasOwnProperty("name")) {
|
||||
return (<any>func).name;
|
||||
}
|
||||
else {
|
||||
const text = Function.prototype.toString.call(func);
|
||||
const match = /^function\s+([\w\$]+)\s*\(/.exec(text);
|
||||
return match ? match[1] : "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function equateValues<T>(a: T, b: T) {
|
||||
return a === b;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export namespace Debug {
|
||||
export let currentAssertionLevel = AssertionLevel.None;
|
||||
export let isDebugging = false;
|
||||
|
||||
export function shouldAssert(level: AssertionLevel): boolean {
|
||||
return currentAssertionLevel >= level;
|
||||
}
|
||||
|
||||
export function assert(expression: boolean, message?: string, verboseDebugInfo?: string | (() => string), stackCrawlMark?: AnyFunction): void {
|
||||
if (!expression) {
|
||||
if (verboseDebugInfo) {
|
||||
message += "\r\nVerbose Debug Information: " + (typeof verboseDebugInfo === "string" ? verboseDebugInfo : verboseDebugInfo());
|
||||
}
|
||||
fail(message ? "False expression: " + message : "False expression.", stackCrawlMark || assert);
|
||||
}
|
||||
}
|
||||
|
||||
export function assertEqual<T>(a: T, b: T, msg?: string, msg2?: string): void {
|
||||
if (a !== b) {
|
||||
const message = msg ? msg2 ? `${msg} ${msg2}` : msg : "";
|
||||
fail(`Expected ${a} === ${b}. ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function assertLessThan(a: number, b: number, msg?: string): void {
|
||||
if (a >= b) {
|
||||
fail(`Expected ${a} < ${b}. ${msg || ""}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function assertLessThanOrEqual(a: number, b: number): void {
|
||||
if (a > b) {
|
||||
fail(`Expected ${a} <= ${b}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function assertGreaterThanOrEqual(a: number, b: number): void {
|
||||
if (a < b) {
|
||||
fail(`Expected ${a} >= ${b}`);
|
||||
}
|
||||
}
|
||||
|
||||
export function fail(message?: string, stackCrawlMark?: AnyFunction): never {
|
||||
debugger;
|
||||
const e = new Error(message ? `Debug Failure. ${message}` : "Debug Failure.");
|
||||
if ((<any>Error).captureStackTrace) {
|
||||
(<any>Error).captureStackTrace(e, stackCrawlMark || fail);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
export function assertDefined<T>(value: T | null | undefined, message?: string): T {
|
||||
if (value === undefined || value === null) return fail(message);
|
||||
return value;
|
||||
}
|
||||
|
||||
export function assertEachDefined<T, A extends ReadonlyArray<T>>(value: A, message?: string): A {
|
||||
for (const v of value) {
|
||||
assertDefined(v, message);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
export function assertNever(member: never, message = "Illegal value:", stackCrawlMark?: AnyFunction): never {
|
||||
const detail = typeof member === "object" && "kind" in member && "pos" in member && formatSyntaxKind ? "SyntaxKind: " + formatSyntaxKind((member as Node).kind) : JSON.stringify(member);
|
||||
return fail(`${message} ${detail}`, stackCrawlMark || assertNever);
|
||||
}
|
||||
|
||||
export function getFunctionName(func: AnyFunction) {
|
||||
if (typeof func !== "function") {
|
||||
return "";
|
||||
}
|
||||
else if (func.hasOwnProperty("name")) {
|
||||
return (<any>func).name;
|
||||
}
|
||||
else {
|
||||
const text = Function.prototype.toString.call(func);
|
||||
const match = /^function\s+([\w\$]+)\s*\(/.exec(text);
|
||||
return match ? match[1] : "";
|
||||
}
|
||||
}
|
||||
|
||||
export function formatSymbol(symbol: Symbol): string {
|
||||
return `{ name: ${unescapeLeadingUnderscores(symbol.escapedName)}; flags: ${formatSymbolFlags(symbol.flags)}; declarations: ${map(symbol.declarations, node => formatSyntaxKind(node.kind))} }`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an enum value as a string for debugging and debug assertions.
|
||||
*/
|
||||
export function formatEnum(value = 0, enumObject: any, isFlags?: boolean) {
|
||||
const members = getEnumMembers(enumObject);
|
||||
if (value === 0) {
|
||||
return members.length > 0 && members[0][0] === 0 ? members[0][1] : "0";
|
||||
}
|
||||
if (isFlags) {
|
||||
let result = "";
|
||||
let remainingFlags = value;
|
||||
for (let i = members.length - 1; i >= 0 && remainingFlags !== 0; i--) {
|
||||
const [enumValue, enumName] = members[i];
|
||||
if (enumValue !== 0 && (remainingFlags & enumValue) === enumValue) {
|
||||
remainingFlags &= ~enumValue;
|
||||
result = `${enumName}${result ? "|" : ""}${result}`;
|
||||
}
|
||||
}
|
||||
if (remainingFlags === 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const [enumValue, enumName] of members) {
|
||||
if (enumValue === value) {
|
||||
return enumName;
|
||||
}
|
||||
}
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
function getEnumMembers(enumObject: any) {
|
||||
const result: [number, string][] = [];
|
||||
for (const name in enumObject) {
|
||||
const value = enumObject[name];
|
||||
if (typeof value === "number") {
|
||||
result.push([value, name]);
|
||||
}
|
||||
}
|
||||
|
||||
return stableSort<[number, string]>(result, (x, y) => compareValues(x[0], y[0]));
|
||||
}
|
||||
|
||||
export function formatSyntaxKind(kind: SyntaxKind | undefined): string {
|
||||
return formatEnum(kind, (<any>ts).SyntaxKind, /*isFlags*/ false);
|
||||
}
|
||||
|
||||
export function formatNodeFlags(flags: NodeFlags | undefined): string {
|
||||
return formatEnum(flags, (<any>ts).NodeFlags, /*isFlags*/ true);
|
||||
}
|
||||
|
||||
export function formatModifierFlags(flags: ModifierFlags | undefined): string {
|
||||
return formatEnum(flags, (<any>ts).ModifierFlags, /*isFlags*/ true);
|
||||
}
|
||||
|
||||
export function formatTransformFlags(flags: TransformFlags | undefined): string {
|
||||
return formatEnum(flags, (<any>ts).TransformFlags, /*isFlags*/ true);
|
||||
}
|
||||
|
||||
export function formatEmitFlags(flags: EmitFlags | undefined): string {
|
||||
return formatEnum(flags, (<any>ts).EmitFlags, /*isFlags*/ true);
|
||||
}
|
||||
|
||||
export function formatSymbolFlags(flags: SymbolFlags | undefined): string {
|
||||
return formatEnum(flags, (<any>ts).SymbolFlags, /*isFlags*/ true);
|
||||
}
|
||||
|
||||
export function formatTypeFlags(flags: TypeFlags | undefined): string {
|
||||
return formatEnum(flags, (<any>ts).TypeFlags, /*isFlags*/ true);
|
||||
}
|
||||
|
||||
export function formatObjectFlags(flags: ObjectFlags | undefined): string {
|
||||
return formatEnum(flags, (<any>ts).ObjectFlags, /*isFlags*/ true);
|
||||
}
|
||||
|
||||
export function failBadSyntaxKind(node: Node, message?: string): never {
|
||||
return fail(
|
||||
`${message || "Unexpected node."}\r\nNode ${formatSyntaxKind(node.kind)} was unexpected.`,
|
||||
failBadSyntaxKind);
|
||||
}
|
||||
|
||||
export const assertEachNode = shouldAssert(AssertionLevel.Normal)
|
||||
? (nodes: Node[], test: (node: Node) => boolean, message?: string): void => assert(
|
||||
test === undefined || every(nodes, test),
|
||||
message || "Unexpected node.",
|
||||
() => `Node array did not pass test '${getFunctionName(test)}'.`,
|
||||
assertEachNode)
|
||||
: noop;
|
||||
|
||||
export const assertNode = shouldAssert(AssertionLevel.Normal)
|
||||
? (node: Node | undefined, test: ((node: Node | undefined) => boolean) | undefined, message?: string): void => assert(
|
||||
test === undefined || test(node),
|
||||
message || "Unexpected node.",
|
||||
() => `Node ${formatSyntaxKind(node!.kind)} did not pass test '${getFunctionName(test!)}'.`,
|
||||
assertNode)
|
||||
: noop;
|
||||
|
||||
export const assertOptionalNode = shouldAssert(AssertionLevel.Normal)
|
||||
? (node: Node, test: (node: Node) => boolean, message?: string): void => assert(
|
||||
test === undefined || node === undefined || test(node),
|
||||
message || "Unexpected node.",
|
||||
() => `Node ${formatSyntaxKind(node.kind)} did not pass test '${getFunctionName(test)}'.`,
|
||||
assertOptionalNode)
|
||||
: noop;
|
||||
|
||||
export const assertOptionalToken = shouldAssert(AssertionLevel.Normal)
|
||||
? (node: Node, kind: SyntaxKind, message?: string): void => assert(
|
||||
kind === undefined || node === undefined || node.kind === kind,
|
||||
message || "Unexpected node.",
|
||||
() => `Node ${formatSyntaxKind(node.kind)} was not a '${formatSyntaxKind(kind)}' token.`,
|
||||
assertOptionalToken)
|
||||
: noop;
|
||||
|
||||
export const assertMissingNode = shouldAssert(AssertionLevel.Normal)
|
||||
? (node: Node, message?: string): void => assert(
|
||||
node === undefined,
|
||||
message || "Unexpected node.",
|
||||
() => `Node ${formatSyntaxKind(node.kind)} was unexpected'.`,
|
||||
assertMissingNode)
|
||||
: noop;
|
||||
|
||||
let isDebugInfoEnabled = false;
|
||||
|
||||
/**
|
||||
* Injects debug information into frequently used types.
|
||||
*/
|
||||
export function enableDebugInfo() {
|
||||
if (isDebugInfoEnabled) return;
|
||||
|
||||
// Add additional properties in debug mode to assist with debugging.
|
||||
Object.defineProperties(objectAllocator.getSymbolConstructor().prototype, {
|
||||
__debugFlags: { get(this: Symbol) { return formatSymbolFlags(this.flags); } }
|
||||
});
|
||||
|
||||
Object.defineProperties(objectAllocator.getTypeConstructor().prototype, {
|
||||
__debugFlags: { get(this: Type) { return formatTypeFlags(this.flags); } },
|
||||
__debugObjectFlags: { get(this: Type) { return this.flags & TypeFlags.Object ? formatObjectFlags((<ObjectType>this).objectFlags) : ""; } },
|
||||
__debugTypeToString: { value(this: Type) { return this.checker.typeToString(this); } },
|
||||
});
|
||||
|
||||
const nodeConstructors = [
|
||||
objectAllocator.getNodeConstructor(),
|
||||
objectAllocator.getIdentifierConstructor(),
|
||||
objectAllocator.getTokenConstructor(),
|
||||
objectAllocator.getSourceFileConstructor()
|
||||
];
|
||||
|
||||
for (const ctor of nodeConstructors) {
|
||||
if (!ctor.prototype.hasOwnProperty("__debugKind")) {
|
||||
Object.defineProperties(ctor.prototype, {
|
||||
__debugKind: { get(this: Node) { return formatSyntaxKind(this.kind); } },
|
||||
__debugNodeFlags: { get(this: Node) { return formatNodeFlags(this.flags); } },
|
||||
__debugModifierFlags: { get(this: Node) { return formatModifierFlags(getModifierFlagsNoCache(this)); } },
|
||||
__debugTransformFlags: { get(this: Node) { return formatTransformFlags(this.transformFlags); } },
|
||||
__debugIsParseTreeNode: { get(this: Node) { return isParseTreeNode(this); } },
|
||||
__debugEmitFlags: { get(this: Node) { return formatEmitFlags(getEmitFlags(this)); } },
|
||||
__debugGetText: {
|
||||
value(this: Node, includeTrivia?: boolean) {
|
||||
if (nodeIsSynthesized(this)) return "";
|
||||
const parseNode = getParseTreeNode(this);
|
||||
const sourceFile = parseNode && getSourceFileOfNode(parseNode);
|
||||
return sourceFile ? getSourceTextOfNodeFromSourceFile(sourceFile, parseNode, includeTrivia) : "";
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
isDebugInfoEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -655,7 +655,7 @@
|
||||
"category": "Error",
|
||||
"code": 1207
|
||||
},
|
||||
"Cannot compile namespaces when the '--isolatedModules' flag is provided.": {
|
||||
"All files must be modules when the '--isolatedModules' flag is provided.": {
|
||||
"category": "Error",
|
||||
"code": 1208
|
||||
},
|
||||
@@ -1236,7 +1236,7 @@
|
||||
"category": "Error",
|
||||
"code": 2348
|
||||
},
|
||||
"Cannot invoke an expression whose type lacks a call signature. Type '{0}' has no compatible call signatures.": {
|
||||
"This expression is not callable.": {
|
||||
"category": "Error",
|
||||
"code": 2349
|
||||
},
|
||||
@@ -1244,7 +1244,7 @@
|
||||
"category": "Error",
|
||||
"code": 2350
|
||||
},
|
||||
"Cannot use 'new' with an expression whose type lacks a call or construct signature.": {
|
||||
"This expression is not constructable.": {
|
||||
"category": "Error",
|
||||
"code": 2351
|
||||
},
|
||||
@@ -2621,6 +2621,38 @@
|
||||
"category": "Error",
|
||||
"code": 2754
|
||||
},
|
||||
"No constituent of type '{0}' is callable.": {
|
||||
"category": "Error",
|
||||
"code": 2755
|
||||
},
|
||||
"Not all constituents of type '{0}' are callable.": {
|
||||
"category": "Error",
|
||||
"code": 2756
|
||||
},
|
||||
"Type '{0}' has no call signatures.": {
|
||||
"category": "Error",
|
||||
"code": 2757
|
||||
},
|
||||
"Each member of the union type '{0}' has signatures, but none of those signatures are compatible with each other.": {
|
||||
"category": "Error",
|
||||
"code": 2758
|
||||
},
|
||||
"No constituent of type '{0}' is constructable.": {
|
||||
"category": "Error",
|
||||
"code": 2759
|
||||
},
|
||||
"Not all constituents of type '{0}' are constructable.": {
|
||||
"category": "Error",
|
||||
"code": 2760
|
||||
},
|
||||
"Type '{0}' has no construct signatures.": {
|
||||
"category": "Error",
|
||||
"code": 2761
|
||||
},
|
||||
"Each member of the union type '{0}' has construct signatures, but none of those signatures are compatible with each other.": {
|
||||
"category": "Error",
|
||||
"code": 2762
|
||||
},
|
||||
|
||||
"Import declaration '{0}' is using private name '{1}'.": {
|
||||
"category": "Error",
|
||||
@@ -2963,6 +2995,10 @@
|
||||
"category": "Error",
|
||||
"code": 4104
|
||||
},
|
||||
"Private or protected member '{0}' cannot be accessed on a type parameter.": {
|
||||
"category": "Error",
|
||||
"code": 4105
|
||||
},
|
||||
|
||||
"The current host does not support the '{0}' option.": {
|
||||
"category": "Error",
|
||||
@@ -3811,10 +3847,6 @@
|
||||
"category": "Error",
|
||||
"code": 6189
|
||||
},
|
||||
"Found 'package.json' at '{0}'. Package ID is '{1}'.": {
|
||||
"category": "Message",
|
||||
"code": 6190
|
||||
},
|
||||
"Whether to keep outdated console output in watch mode instead of clearing the screen.": {
|
||||
"category": "Message",
|
||||
"code": 6191
|
||||
@@ -3923,6 +3955,18 @@
|
||||
"category": "Message",
|
||||
"code": 6217
|
||||
},
|
||||
"======== Module name '{0}' was successfully resolved to '{1}' with Package ID '{2}'. ========": {
|
||||
"category": "Message",
|
||||
"code": 6218
|
||||
},
|
||||
"======== Type reference directive '{0}' was successfully resolved to '{1}' with Package ID '{2}', primary: {3}. ========": {
|
||||
"category": "Message",
|
||||
"code": 6219
|
||||
},
|
||||
"'package.json' had a falsy '{0}' field.": {
|
||||
"category": "Message",
|
||||
"code": 6220
|
||||
},
|
||||
|
||||
"Projects to reference": {
|
||||
"category": "Message",
|
||||
@@ -3948,7 +3992,7 @@
|
||||
"category": "Error",
|
||||
"code": 6306
|
||||
},
|
||||
"File '{0}' is not in project file list. Projects must list all files or use an 'include' pattern.": {
|
||||
"File '{0}' is not listed within the file list of project '{1}'. Projects must list all files or use an 'include' pattern.": {
|
||||
"category": "Error",
|
||||
"code": 6307
|
||||
},
|
||||
@@ -4284,6 +4328,14 @@
|
||||
"category": "Error",
|
||||
"code": 7052
|
||||
},
|
||||
"Element implicitly has an 'any' type because expression of type '{0}' can't be used to index type '{1}'.": {
|
||||
"category": "Error",
|
||||
"code": 7053
|
||||
},
|
||||
"No index signature with a parameter of type '{0}' was found on type '{1}'.": {
|
||||
"category": "Error",
|
||||
"code": 7054
|
||||
},
|
||||
"You cannot rename this element.": {
|
||||
"category": "Error",
|
||||
"code": 8000
|
||||
@@ -4974,14 +5026,18 @@
|
||||
"category": "Message",
|
||||
"code": 95079
|
||||
},
|
||||
"Add 'const' to unresolved variable": {
|
||||
"Infer 'this' type of '{0}' from usage": {
|
||||
"category": "Message",
|
||||
"code": 95080
|
||||
},
|
||||
"Add 'const' to all unresolved variables": {
|
||||
"Add 'const' to unresolved variable": {
|
||||
"category": "Message",
|
||||
"code": 95081
|
||||
},
|
||||
"Add 'const' to all unresolved variables": {
|
||||
"category": "Message",
|
||||
"code": 95082
|
||||
},
|
||||
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
|
||||
"category": "Error",
|
||||
"code": 18004
|
||||
@@ -4993,5 +5049,9 @@
|
||||
"Classes may not have a field named 'constructor'.": {
|
||||
"category": "Error",
|
||||
"code": 18006
|
||||
},
|
||||
"JSX expressions may not use the comma operator. Did you mean to write an array?": {
|
||||
"category": "Error",
|
||||
"code": 18007
|
||||
}
|
||||
}
|
||||
|
||||
+57
-17
@@ -249,14 +249,16 @@ namespace ts {
|
||||
};
|
||||
|
||||
function emitSourceFileOrBundle({ jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath }: EmitFileNames, sourceFileOrBundle: SourceFile | Bundle | undefined) {
|
||||
let buildInfoDirectory: string | undefined;
|
||||
if (buildInfoPath && sourceFileOrBundle && isBundle(sourceFileOrBundle)) {
|
||||
buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(buildInfoPath, host.getCurrentDirectory()));
|
||||
bundleBuildInfo = {
|
||||
commonSourceDirectory: host.getCommonSourceDirectory(),
|
||||
sourceFiles: sourceFileOrBundle.sourceFiles.map(file => file.fileName)
|
||||
commonSourceDirectory: relativeToBuildInfo(host.getCommonSourceDirectory()),
|
||||
sourceFiles: sourceFileOrBundle.sourceFiles.map(file => relativeToBuildInfo(getNormalizedAbsolutePath(file.fileName, host.getCurrentDirectory())))
|
||||
};
|
||||
}
|
||||
emitJsFileOrBundle(sourceFileOrBundle, jsFilePath, sourceMapFilePath);
|
||||
emitDeclarationFileOrBundle(sourceFileOrBundle, declarationFilePath, declarationMapPath);
|
||||
emitJsFileOrBundle(sourceFileOrBundle, jsFilePath, sourceMapFilePath, relativeToBuildInfo);
|
||||
emitDeclarationFileOrBundle(sourceFileOrBundle, declarationFilePath, declarationMapPath, relativeToBuildInfo);
|
||||
emitBuildInfo(bundleBuildInfo, buildInfoPath);
|
||||
|
||||
if (!emitSkipped && emittedFilesList) {
|
||||
@@ -278,13 +280,16 @@ namespace ts {
|
||||
emittedFilesList.push(declarationMapPath);
|
||||
}
|
||||
}
|
||||
|
||||
function relativeToBuildInfo(path: string) {
|
||||
return ensurePathIsNonModuleName(getRelativePathFromDirectory(buildInfoDirectory!, path, host.getCanonicalFileName));
|
||||
}
|
||||
}
|
||||
|
||||
function emitBuildInfo(bundle: BundleBuildInfo | undefined, buildInfoPath: string | undefined) {
|
||||
// Write build information if applicable
|
||||
if (!buildInfoPath || targetSourceFile || emitSkipped) return;
|
||||
const program = host.getProgramBuildInfo();
|
||||
if (!bundle && !program) return;
|
||||
if (host.isEmitBlocked(buildInfoPath) || compilerOptions.noEmit) {
|
||||
emitSkipped = true;
|
||||
return;
|
||||
@@ -292,7 +297,11 @@ namespace ts {
|
||||
writeFile(host, emitterDiagnostics, buildInfoPath, getBuildInfoText({ bundle, program, version }), /*writeByteOrderMark*/ false);
|
||||
}
|
||||
|
||||
function emitJsFileOrBundle(sourceFileOrBundle: SourceFile | Bundle | undefined, jsFilePath: string | undefined, sourceMapFilePath: string | undefined) {
|
||||
function emitJsFileOrBundle(
|
||||
sourceFileOrBundle: SourceFile | Bundle | undefined,
|
||||
jsFilePath: string | undefined,
|
||||
sourceMapFilePath: string | undefined,
|
||||
relativeToBuildInfo: (path: string) => string) {
|
||||
if (!sourceFileOrBundle || emitOnlyDtsFiles || !jsFilePath) {
|
||||
return;
|
||||
}
|
||||
@@ -315,7 +324,8 @@ namespace ts {
|
||||
inlineSourceMap: compilerOptions.inlineSourceMap,
|
||||
inlineSources: compilerOptions.inlineSources,
|
||||
extendedDiagnostics: compilerOptions.extendedDiagnostics,
|
||||
writeBundleFileInfo: !!bundleBuildInfo
|
||||
writeBundleFileInfo: !!bundleBuildInfo,
|
||||
relativeToBuildInfo
|
||||
};
|
||||
|
||||
// Create a printer to print the nodes
|
||||
@@ -336,7 +346,11 @@ namespace ts {
|
||||
if (bundleBuildInfo) bundleBuildInfo.js = printer.bundleFileInfo;
|
||||
}
|
||||
|
||||
function emitDeclarationFileOrBundle(sourceFileOrBundle: SourceFile | Bundle | undefined, declarationFilePath: string | undefined, declarationMapPath: string | undefined) {
|
||||
function emitDeclarationFileOrBundle(
|
||||
sourceFileOrBundle: SourceFile | Bundle | undefined,
|
||||
declarationFilePath: string | undefined,
|
||||
declarationMapPath: string | undefined,
|
||||
relativeToBuildInfo: (path: string) => string) {
|
||||
if (!sourceFileOrBundle || !(declarationFilePath && !isInJSFile(sourceFileOrBundle))) {
|
||||
return;
|
||||
}
|
||||
@@ -367,7 +381,8 @@ namespace ts {
|
||||
extendedDiagnostics: compilerOptions.extendedDiagnostics,
|
||||
onlyPrintJsDocStyle: true,
|
||||
writeBundleFileInfo: !!bundleBuildInfo,
|
||||
recordInternalSection: !!bundleBuildInfo
|
||||
recordInternalSection: !!bundleBuildInfo,
|
||||
relativeToBuildInfo
|
||||
};
|
||||
|
||||
const declarationPrinter = createPrinter(printerOptions, {
|
||||
@@ -614,10 +629,14 @@ namespace ts {
|
||||
getNewLine(): string;
|
||||
}
|
||||
|
||||
function createSourceFilesFromBundleBuildInfo(bundle: BundleBuildInfo): ReadonlyArray<SourceFile> {
|
||||
function createSourceFilesFromBundleBuildInfo(bundle: BundleBuildInfo, buildInfoDirectory: string, host: EmitUsingBuildInfoHost): ReadonlyArray<SourceFile> {
|
||||
const sourceFiles = bundle.sourceFiles.map(fileName => {
|
||||
const sourceFile = createNode(SyntaxKind.SourceFile, 0, 0) as SourceFile;
|
||||
sourceFile.fileName = fileName;
|
||||
sourceFile.fileName = getRelativePathFromDirectory(
|
||||
host.getCurrentDirectory(),
|
||||
getNormalizedAbsolutePath(fileName, buildInfoDirectory),
|
||||
!host.useCaseSensitiveFileNames()
|
||||
);
|
||||
sourceFile.text = "";
|
||||
sourceFile.statements = createNodeArray();
|
||||
return sourceFile;
|
||||
@@ -638,7 +657,12 @@ namespace ts {
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export function emitUsingBuildInfo(config: ParsedCommandLine, host: EmitUsingBuildInfoHost, getCommandLine: (ref: ProjectReference) => ParsedCommandLine | undefined): EmitUsingBuildInfoResult {
|
||||
export function emitUsingBuildInfo(
|
||||
config: ParsedCommandLine,
|
||||
host: EmitUsingBuildInfoHost,
|
||||
getCommandLine: (ref: ProjectReference) => ParsedCommandLine | undefined,
|
||||
customTransformers?: CustomTransformers
|
||||
): EmitUsingBuildInfoResult {
|
||||
const { buildInfoPath, jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath } = getOutputPathsForBundle(config.options, /*forceDtsPaths*/ false);
|
||||
const buildInfoText = host.readFile(Debug.assertDefined(buildInfoPath));
|
||||
if (!buildInfoText) return buildInfoPath!;
|
||||
@@ -656,6 +680,7 @@ namespace ts {
|
||||
|
||||
const buildInfo = getBuildInfo(buildInfoText);
|
||||
if (!buildInfo.bundle || !buildInfo.bundle.js || (declarationText && !buildInfo.bundle.dts)) return buildInfoPath!;
|
||||
const buildInfoDirectory = getDirectoryPath(getNormalizedAbsolutePath(buildInfoPath!, host.getCurrentDirectory()));
|
||||
const ownPrependInput = createInputFiles(
|
||||
jsFileText,
|
||||
declarationText!,
|
||||
@@ -671,11 +696,11 @@ namespace ts {
|
||||
);
|
||||
const outputFiles: OutputFile[] = [];
|
||||
const prependNodes = createPrependNodes(config.projectReferences, getCommandLine, f => host.readFile(f));
|
||||
const sourceFilesForJsEmit = createSourceFilesFromBundleBuildInfo(buildInfo.bundle);
|
||||
const sourceFilesForJsEmit = createSourceFilesFromBundleBuildInfo(buildInfo.bundle, buildInfoDirectory, host);
|
||||
const emitHost: EmitHost = {
|
||||
getPrependNodes: memoize(() => [...prependNodes, ownPrependInput]),
|
||||
getCanonicalFileName: host.getCanonicalFileName,
|
||||
getCommonSourceDirectory: () => buildInfo.bundle!.commonSourceDirectory,
|
||||
getCommonSourceDirectory: () => getNormalizedAbsolutePath(buildInfo.bundle!.commonSourceDirectory, buildInfoDirectory),
|
||||
getCompilerOptions: () => config.options,
|
||||
getCurrentDirectory: () => host.getCurrentDirectory(),
|
||||
getNewLine: () => host.getNewLine(),
|
||||
@@ -721,9 +746,15 @@ namespace ts {
|
||||
fileExists: f => host.fileExists(f),
|
||||
directoryExists: host.directoryExists && (f => host.directoryExists!(f)),
|
||||
useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
|
||||
getProgramBuildInfo: returnUndefined
|
||||
getProgramBuildInfo: returnUndefined,
|
||||
getSourceFileFromReference: returnUndefined,
|
||||
};
|
||||
emitFiles(notImplementedResolver, emitHost, /*targetSourceFile*/ undefined, getTransformers(config.options), /*emitOnlyDtsFiles*/ false);
|
||||
emitFiles(
|
||||
notImplementedResolver,
|
||||
emitHost,
|
||||
/*targetSourceFile*/ undefined,
|
||||
getTransformers(config.options, customTransformers)
|
||||
);
|
||||
return outputFiles;
|
||||
}
|
||||
|
||||
@@ -765,6 +796,7 @@ namespace ts {
|
||||
let write = writeBase;
|
||||
let isOwnFileEmit: boolean;
|
||||
const bundleFileInfo = printerOptions.writeBundleFileInfo ? { sections: [] } as BundleFileInfo : undefined;
|
||||
const relativeToBuildInfo = bundleFileInfo ? Debug.assertDefined(printerOptions.relativeToBuildInfo) : undefined;
|
||||
const recordInternalSection = printerOptions.recordInternalSection;
|
||||
let sourceFileTextPos = 0;
|
||||
let sourceFileTextKind: BundleFileTextLikeKind = BundleFileSectionKind.Text;
|
||||
@@ -933,7 +965,13 @@ namespace ts {
|
||||
if (prepend.oldFileOfCurrentEmit) bundleFileInfo.sections.push(...newSections);
|
||||
else {
|
||||
newSections.forEach(section => Debug.assert(isBundleFileTextLike(section)));
|
||||
bundleFileInfo.sections.push({ pos, end: writer.getTextPos(), kind: BundleFileSectionKind.Prepend, data: (prepend as UnparsedSource).fileName, texts: newSections as BundleFileTextLike[] });
|
||||
bundleFileInfo.sections.push({
|
||||
pos,
|
||||
end: writer.getTextPos(),
|
||||
kind: BundleFileSectionKind.Prepend,
|
||||
data: relativeToBuildInfo!((prepend as UnparsedSource).fileName),
|
||||
texts: newSections as BundleFileTextLike[]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4527,6 +4565,8 @@ namespace ts {
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
return generateNameForMethodOrAccessor(<MethodDeclaration | AccessorDeclaration>node);
|
||||
case SyntaxKind.ComputedPropertyName:
|
||||
return makeTempVariableName(TempFlags.Auto, /*reserveInNestedScopes*/ true);
|
||||
default:
|
||||
return makeTempVariableName(TempFlags.Auto);
|
||||
}
|
||||
|
||||
+60
-9
@@ -1544,8 +1544,8 @@ namespace ts {
|
||||
export function createIf(expression: Expression, thenStatement: Statement, elseStatement?: Statement) {
|
||||
const node = <IfStatement>createSynthesizedNode(SyntaxKind.IfStatement);
|
||||
node.expression = expression;
|
||||
node.thenStatement = thenStatement;
|
||||
node.elseStatement = elseStatement;
|
||||
node.thenStatement = asEmbeddedStatement(thenStatement);
|
||||
node.elseStatement = asEmbeddedStatement(elseStatement);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -1559,7 +1559,7 @@ namespace ts {
|
||||
|
||||
export function createDo(statement: Statement, expression: Expression) {
|
||||
const node = <DoStatement>createSynthesizedNode(SyntaxKind.DoStatement);
|
||||
node.statement = statement;
|
||||
node.statement = asEmbeddedStatement(statement);
|
||||
node.expression = expression;
|
||||
return node;
|
||||
}
|
||||
@@ -1574,7 +1574,7 @@ namespace ts {
|
||||
export function createWhile(expression: Expression, statement: Statement) {
|
||||
const node = <WhileStatement>createSynthesizedNode(SyntaxKind.WhileStatement);
|
||||
node.expression = expression;
|
||||
node.statement = statement;
|
||||
node.statement = asEmbeddedStatement(statement);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -1590,7 +1590,7 @@ namespace ts {
|
||||
node.initializer = initializer;
|
||||
node.condition = condition;
|
||||
node.incrementor = incrementor;
|
||||
node.statement = statement;
|
||||
node.statement = asEmbeddedStatement(statement);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -1607,7 +1607,7 @@ namespace ts {
|
||||
const node = <ForInStatement>createSynthesizedNode(SyntaxKind.ForInStatement);
|
||||
node.initializer = initializer;
|
||||
node.expression = expression;
|
||||
node.statement = statement;
|
||||
node.statement = asEmbeddedStatement(statement);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -1624,7 +1624,7 @@ namespace ts {
|
||||
node.awaitModifier = awaitModifier;
|
||||
node.initializer = initializer;
|
||||
node.expression = expression;
|
||||
node.statement = statement;
|
||||
node.statement = asEmbeddedStatement(statement);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -1676,7 +1676,7 @@ namespace ts {
|
||||
export function createWith(expression: Expression, statement: Statement) {
|
||||
const node = <WithStatement>createSynthesizedNode(SyntaxKind.WithStatement);
|
||||
node.expression = expression;
|
||||
node.statement = statement;
|
||||
node.statement = asEmbeddedStatement(statement);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -1704,7 +1704,7 @@ namespace ts {
|
||||
export function createLabel(label: string | Identifier, statement: Statement) {
|
||||
const node = <LabeledStatement>createSynthesizedNode(SyntaxKind.LabeledStatement);
|
||||
node.label = asName(label);
|
||||
node.statement = statement;
|
||||
node.statement = asEmbeddedStatement(statement);
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -2204,6 +2204,13 @@ namespace ts {
|
||||
return tag;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function createJSDocThisTag(typeExpression?: JSDocTypeExpression): JSDocThisTag {
|
||||
const tag = createJSDocTag<JSDocThisTag>(SyntaxKind.JSDocThisTag, "this");
|
||||
tag.typeExpression = typeExpression;
|
||||
return tag;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function createJSDocParamTag(name: EntityName, isBracketed: boolean, typeExpression?: JSDocTypeExpression, comment?: string): JSDocParameterTag {
|
||||
const tag = createJSDocTag<JSDocParameterTag>(SyntaxKind.JSDocParameterTag, "param");
|
||||
@@ -2657,6 +2664,7 @@ namespace ts {
|
||||
valuesHelper,
|
||||
readHelper,
|
||||
spreadHelper,
|
||||
spreadArraysHelper,
|
||||
restHelper,
|
||||
decorateHelper,
|
||||
metadataHelper,
|
||||
@@ -3072,6 +3080,12 @@ namespace ts {
|
||||
return typeof value === "number" ? createToken(value) : value;
|
||||
}
|
||||
|
||||
function asEmbeddedStatement<T extends Node>(statement: T): T | EmptyStatement;
|
||||
function asEmbeddedStatement<T extends Node>(statement: T | undefined): T | EmptyStatement | undefined;
|
||||
function asEmbeddedStatement<T extends Node>(statement: T | undefined): T | EmptyStatement | undefined {
|
||||
return statement && isNotEmittedStatement(statement) ? setTextRange(setOriginalNode(createEmptyStatement(), statement), statement) : statement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears any EmitNode entries from parse-tree nodes.
|
||||
* @param sourceFile A source file.
|
||||
@@ -3118,6 +3132,18 @@ namespace ts {
|
||||
return node.emitNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets `EmitFlags.NoComments` on a node and removes any leading and trailing synthetic comments.
|
||||
* @internal
|
||||
*/
|
||||
export function removeAllComments<T extends Node>(node: T): T {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
emitNode.flags |= EmitFlags.NoComments;
|
||||
emitNode.leadingComments = undefined;
|
||||
emitNode.trailingComments = undefined;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function setTextRange<T extends TextRange>(range: T, location: TextRange | undefined): T {
|
||||
if (location) {
|
||||
range.pos = location.pos;
|
||||
@@ -3693,6 +3719,31 @@ namespace ts {
|
||||
);
|
||||
}
|
||||
|
||||
export const spreadArraysHelper: UnscopedEmitHelper = {
|
||||
name: "typescript:spreadArrays",
|
||||
scoped: false,
|
||||
text: `
|
||||
var __spreadArrays = (this && this.__spreadArrays) || function () {
|
||||
for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;
|
||||
for (var r = Array(s), k = 0, i = 0; i < il; i++)
|
||||
for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)
|
||||
r[k] = a[j];
|
||||
return r;
|
||||
};`
|
||||
};
|
||||
|
||||
export function createSpreadArraysHelper(context: TransformationContext, argumentList: ReadonlyArray<Expression>, location?: TextRange) {
|
||||
context.requestEmitHelper(spreadArraysHelper);
|
||||
return setTextRange(
|
||||
createCall(
|
||||
getHelperName("__spreadArrays"),
|
||||
/*typeArguments*/ undefined,
|
||||
argumentList
|
||||
),
|
||||
location
|
||||
);
|
||||
}
|
||||
|
||||
// Utilities
|
||||
|
||||
export function createForOfBindingStatement(node: ForInitializer, boundValue: Expression): Statement {
|
||||
|
||||
@@ -16,12 +16,23 @@ namespace ts {
|
||||
push(value: T): void;
|
||||
}
|
||||
|
||||
function withPackageId(packageId: PackageId | undefined, r: PathAndExtension | undefined): Resolved | undefined {
|
||||
function withPackageId(packageInfo: PackageJsonInfo | undefined, r: PathAndExtension | undefined): Resolved | undefined {
|
||||
let packageId: PackageId | undefined;
|
||||
if (r && packageInfo) {
|
||||
const packageJsonContent = packageInfo.packageJsonContent as PackageJson;
|
||||
if (typeof packageJsonContent.name === "string" && typeof packageJsonContent.version === "string") {
|
||||
packageId = {
|
||||
name: packageJsonContent.name,
|
||||
subModuleName: r.path.slice(packageInfo.packageDirectory.length + directorySeparator.length),
|
||||
version: packageJsonContent.version
|
||||
};
|
||||
}
|
||||
}
|
||||
return r && { path: r.path, extension: r.ext, packageId };
|
||||
}
|
||||
|
||||
function noPackageId(r: PathAndExtension | undefined): Resolved | undefined {
|
||||
return withPackageId(/*packageId*/ undefined, r);
|
||||
return withPackageId(/*packageInfo*/ undefined, r);
|
||||
}
|
||||
|
||||
function removeIgnoredPackageId(r: Resolved | undefined): PathAndExtension | undefined {
|
||||
@@ -130,7 +141,15 @@ namespace ts {
|
||||
|
||||
function readPackageJsonPathField<K extends "typings" | "types" | "main" | "tsconfig">(jsonContent: PackageJson, fieldName: K, baseDirectory: string, state: ModuleResolutionState): PackageJson[K] | undefined {
|
||||
const fileName = readPackageJsonField(jsonContent, fieldName, "string", state);
|
||||
if (fileName === undefined) return;
|
||||
if (fileName === undefined) {
|
||||
return;
|
||||
}
|
||||
if (!fileName) {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.package_json_had_a_falsy_0_field, fieldName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
const path = normalizePath(combinePaths(baseDirectory, fileName));
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, fileName, path);
|
||||
@@ -307,7 +326,12 @@ namespace ts {
|
||||
const { fileName, packageId } = resolved;
|
||||
const resolvedFileName = options.preserveSymlinks ? fileName : realPath(fileName, host, traceEnabled);
|
||||
if (traceEnabled) {
|
||||
trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, resolvedFileName, primary);
|
||||
if (packageId) {
|
||||
trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_with_Package_ID_2_primary_Colon_3, typeReferenceDirectiveName, resolvedFileName, packageIdToString(packageId), primary);
|
||||
}
|
||||
else {
|
||||
trace(host, Diagnostics.Type_reference_directive_0_was_successfully_resolved_to_1_primary_Colon_2, typeReferenceDirectiveName, resolvedFileName, primary);
|
||||
}
|
||||
}
|
||||
resolvedTypeReferenceDirective = { primary, resolvedFileName, packageId, isExternalLibraryImport: pathContainsNodeModules(fileName) };
|
||||
}
|
||||
@@ -663,7 +687,12 @@ namespace ts {
|
||||
|
||||
if (traceEnabled) {
|
||||
if (result.resolvedModule) {
|
||||
trace(host, Diagnostics.Module_name_0_was_successfully_resolved_to_1, moduleName, result.resolvedModule.resolvedFileName);
|
||||
if (result.resolvedModule.packageId) {
|
||||
trace(host, Diagnostics.Module_name_0_was_successfully_resolved_to_1_with_Package_ID_2, moduleName, result.resolvedModule.resolvedFileName, packageIdToString(result.resolvedModule.packageId));
|
||||
}
|
||||
else {
|
||||
trace(host, Diagnostics.Module_name_0_was_successfully_resolved_to_1, moduleName, result.resolvedModule.resolvedFileName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
trace(host, Diagnostics.Module_name_0_was_not_resolved, moduleName);
|
||||
@@ -968,10 +997,9 @@ namespace ts {
|
||||
}
|
||||
const resolvedFromFile = loadModuleFromFile(extensions, candidate, onlyRecordFailures, state);
|
||||
if (resolvedFromFile) {
|
||||
const nm = considerPackageJson ? parseNodeModuleFromPath(resolvedFromFile) : undefined;
|
||||
const packageInfo = nm && getPackageJsonInfo(nm.packageDirectory, nm.subModuleName, /*onlyRecordFailures*/ false, state);
|
||||
const packageId = packageInfo && packageInfo.packageId;
|
||||
return withPackageId(packageId, resolvedFromFile);
|
||||
const packageDirectory = considerPackageJson ? parseNodeModuleFromPath(resolvedFromFile) : undefined;
|
||||
const packageInfo = packageDirectory ? getPackageJsonInfo(packageDirectory, /*onlyRecordFailures*/ false, state) : undefined;
|
||||
return withPackageId(packageInfo, resolvedFromFile);
|
||||
}
|
||||
}
|
||||
if (!onlyRecordFailures) {
|
||||
@@ -998,13 +1026,12 @@ namespace ts {
|
||||
* (Not neeeded for `loadModuleFromNodeModules` as that looks up the `package.json` as part of resolution.)
|
||||
*
|
||||
* packageDirectory is the directory of the package itself.
|
||||
* subModuleName is the path within the package.
|
||||
* For `blah/node_modules/foo/index.d.ts` this is { packageDirectory: "foo", subModuleName: "index.d.ts" }. (Part before "/node_modules/" is ignored.)
|
||||
* For `/node_modules/foo/bar.d.ts` this is { packageDirectory: "foo", subModuleName": "bar/index.d.ts" }.
|
||||
* For `/node_modules/@types/foo/bar/index.d.ts` this is { packageDirectory: "@types/foo", subModuleName: "bar/index.d.ts" }.
|
||||
* For `/node_modules/foo/bar/index.d.ts` this is { packageDirectory: "foo", subModuleName": "bar/index.d.ts" }.
|
||||
* For `blah/node_modules/foo/index.d.ts` this is packageDirectory: "foo"
|
||||
* For `/node_modules/foo/bar.d.ts` this is packageDirectory: "foo"
|
||||
* For `/node_modules/@types/foo/bar/index.d.ts` this is packageDirectory: "@types/foo"
|
||||
* For `/node_modules/foo/bar/index.d.ts` this is packageDirectory: "foo"
|
||||
*/
|
||||
function parseNodeModuleFromPath(resolved: PathAndExtension): { packageDirectory: string, subModuleName: string } | undefined {
|
||||
function parseNodeModuleFromPath(resolved: PathAndExtension): string | undefined {
|
||||
const path = normalizePath(resolved.path);
|
||||
const idx = path.lastIndexOf(nodeModulesPathPart);
|
||||
if (idx === -1) {
|
||||
@@ -1016,9 +1043,7 @@ namespace ts {
|
||||
if (path.charCodeAt(indexAfterNodeModules) === CharacterCodes.at) {
|
||||
indexAfterPackageName = moveToNextDirectorySeparatorIfAvailable(path, indexAfterPackageName);
|
||||
}
|
||||
const packageDirectory = path.slice(0, indexAfterPackageName);
|
||||
const subModuleName = removeExtension(path.slice(indexAfterPackageName + 1), resolved.ext) + Extension.Dts;
|
||||
return { packageDirectory, subModuleName };
|
||||
return path.slice(0, indexAfterPackageName);
|
||||
}
|
||||
|
||||
function moveToNextDirectorySeparatorIfAvailable(path: string, prevSeparatorIndex: number): number {
|
||||
@@ -1026,19 +1051,6 @@ namespace ts {
|
||||
return nextSeparatorIndex === -1 ? prevSeparatorIndex : nextSeparatorIndex;
|
||||
}
|
||||
|
||||
function addExtensionAndIndex(path: string): string {
|
||||
if (path === "") {
|
||||
return "index.d.ts";
|
||||
}
|
||||
if (endsWith(path, ".d.ts")) {
|
||||
return path;
|
||||
}
|
||||
if (path === "index" || endsWith(path, "/index")) {
|
||||
return path + ".d.ts";
|
||||
}
|
||||
return path + "/index.d.ts";
|
||||
}
|
||||
|
||||
function loadModuleFromFileNoPackageId(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
|
||||
return noPackageId(loadModuleFromFile(extensions, candidate, onlyRecordFailures, state));
|
||||
}
|
||||
@@ -1119,61 +1131,29 @@ namespace ts {
|
||||
}
|
||||
|
||||
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true) {
|
||||
const packageInfo = considerPackageJson ? getPackageJsonInfo(candidate, "", onlyRecordFailures, state) : undefined;
|
||||
const packageId = packageInfo && packageInfo.packageId;
|
||||
const packageInfo = considerPackageJson ? getPackageJsonInfo(candidate, onlyRecordFailures, state) : undefined;
|
||||
const packageJsonContent = packageInfo && packageInfo.packageJsonContent;
|
||||
const versionPaths = packageInfo && packageInfo.versionPaths;
|
||||
return withPackageId(packageId, loadNodeModuleFromDirectoryWorker(extensions, candidate, onlyRecordFailures, state, packageJsonContent, versionPaths));
|
||||
return withPackageId(packageInfo, loadNodeModuleFromDirectoryWorker(extensions, candidate, onlyRecordFailures, state, packageJsonContent, versionPaths));
|
||||
}
|
||||
|
||||
interface PackageJsonInfo {
|
||||
packageJsonContent: PackageJsonPathFields | undefined;
|
||||
packageId: PackageId | undefined;
|
||||
packageDirectory: string;
|
||||
packageJsonContent: PackageJsonPathFields;
|
||||
versionPaths: VersionPaths | undefined;
|
||||
}
|
||||
|
||||
function getPackageJsonInfo(packageDirectory: string, subModuleName: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PackageJsonInfo | undefined {
|
||||
function getPackageJsonInfo(packageDirectory: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PackageJsonInfo | undefined {
|
||||
const { host, traceEnabled } = state;
|
||||
const directoryExists = !onlyRecordFailures && directoryProbablyExists(packageDirectory, host);
|
||||
const packageJsonPath = combinePaths(packageDirectory, "package.json");
|
||||
if (directoryExists && host.fileExists(packageJsonPath)) {
|
||||
const packageJsonContent = readJson(packageJsonPath, host) as PackageJson;
|
||||
if (subModuleName === "") { // looking up the root - need to handle types/typings/main redirects for subModuleName
|
||||
const path = readPackageJsonTypesFields(packageJsonContent, packageDirectory, state);
|
||||
if (typeof path === "string") {
|
||||
subModuleName = addExtensionAndIndex(path.substring(packageDirectory.length + 1));
|
||||
}
|
||||
else {
|
||||
const jsPath = readPackageJsonMainField(packageJsonContent, packageDirectory, state);
|
||||
if (typeof jsPath === "string" && jsPath.length > packageDirectory.length) {
|
||||
const potentialSubModule = jsPath.substring(packageDirectory.length + 1);
|
||||
subModuleName = (forEach(supportedJSExtensions, extension =>
|
||||
tryRemoveExtension(potentialSubModule, extension)) || potentialSubModule) + Extension.Dts;
|
||||
}
|
||||
else {
|
||||
subModuleName = "index.d.ts";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!endsWith(subModuleName, Extension.Dts)) {
|
||||
subModuleName = addExtensionAndIndex(subModuleName);
|
||||
}
|
||||
|
||||
const versionPaths = readPackageJsonTypesVersionPaths(packageJsonContent, state);
|
||||
const packageId: PackageId | undefined = typeof packageJsonContent.name === "string" && typeof packageJsonContent.version === "string"
|
||||
? { name: packageJsonContent.name, subModuleName, version: packageJsonContent.version }
|
||||
: undefined;
|
||||
if (traceEnabled) {
|
||||
if (packageId) {
|
||||
trace(host, Diagnostics.Found_package_json_at_0_Package_ID_is_1, packageJsonPath, packageIdToString(packageId));
|
||||
}
|
||||
else {
|
||||
trace(host, Diagnostics.Found_package_json_at_0, packageJsonPath);
|
||||
}
|
||||
trace(host, Diagnostics.Found_package_json_at_0, packageJsonPath);
|
||||
}
|
||||
|
||||
return { packageJsonContent, packageId, versionPaths };
|
||||
const versionPaths = readPackageJsonTypesVersionPaths(packageJsonContent, state);
|
||||
return { packageDirectory, packageJsonContent, versionPaths };
|
||||
}
|
||||
else {
|
||||
if (directoryExists && traceEnabled) {
|
||||
@@ -1328,27 +1308,36 @@ namespace ts {
|
||||
const candidate = normalizePath(combinePaths(nodeModulesDirectory, moduleName));
|
||||
|
||||
// First look for a nested package.json, as in `node_modules/foo/bar/package.json`.
|
||||
let packageJsonContent: PackageJsonPathFields | undefined;
|
||||
let packageId: PackageId | undefined;
|
||||
let versionPaths: VersionPaths | undefined;
|
||||
|
||||
const packageInfo = getPackageJsonInfo(candidate, "", !nodeModulesDirectoryExists, state);
|
||||
let packageInfo = getPackageJsonInfo(candidate, !nodeModulesDirectoryExists, state);
|
||||
if (packageInfo) {
|
||||
({ packageJsonContent, packageId, versionPaths } = packageInfo);
|
||||
const fromFile = loadModuleFromFile(extensions, candidate, !nodeModulesDirectoryExists, state);
|
||||
if (fromFile) {
|
||||
return noPackageId(fromFile);
|
||||
}
|
||||
|
||||
const fromDirectory = loadNodeModuleFromDirectoryWorker(extensions, candidate, !nodeModulesDirectoryExists, state, packageJsonContent, versionPaths);
|
||||
return withPackageId(packageId, fromDirectory);
|
||||
const fromDirectory = loadNodeModuleFromDirectoryWorker(
|
||||
extensions,
|
||||
candidate,
|
||||
!nodeModulesDirectoryExists,
|
||||
state,
|
||||
packageInfo.packageJsonContent,
|
||||
packageInfo.versionPaths
|
||||
);
|
||||
return withPackageId(packageInfo, fromDirectory);
|
||||
}
|
||||
|
||||
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => {
|
||||
const pathAndExtension =
|
||||
loadModuleFromFile(extensions, candidate, onlyRecordFailures, state) ||
|
||||
loadNodeModuleFromDirectoryWorker(extensions, candidate, onlyRecordFailures, state, packageJsonContent, versionPaths);
|
||||
return withPackageId(packageId, pathAndExtension);
|
||||
loadNodeModuleFromDirectoryWorker(
|
||||
extensions,
|
||||
candidate,
|
||||
onlyRecordFailures,
|
||||
state,
|
||||
packageInfo && packageInfo.packageJsonContent,
|
||||
packageInfo && packageInfo.versionPaths
|
||||
);
|
||||
return withPackageId(packageInfo, pathAndExtension);
|
||||
};
|
||||
|
||||
const { packageName, rest } = parsePackageName(moduleName);
|
||||
@@ -1356,14 +1345,13 @@ namespace ts {
|
||||
const packageDirectory = combinePaths(nodeModulesDirectory, packageName);
|
||||
|
||||
// Don't use a "types" or "main" from here because we're not loading the root, but a subdirectory -- just here for the packageId and path mappings.
|
||||
const packageInfo = getPackageJsonInfo(packageDirectory, rest, !nodeModulesDirectoryExists, state);
|
||||
if (packageInfo) ({ packageId, versionPaths } = packageInfo);
|
||||
if (versionPaths) {
|
||||
packageInfo = getPackageJsonInfo(packageDirectory, !nodeModulesDirectoryExists, state);
|
||||
if (packageInfo && packageInfo.versionPaths) {
|
||||
if (state.traceEnabled) {
|
||||
trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, versionPaths.version, version, rest);
|
||||
trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, packageInfo.versionPaths.version, version, rest);
|
||||
}
|
||||
const packageDirectoryExists = nodeModulesDirectoryExists && directoryProbablyExists(packageDirectory, state.host);
|
||||
const fromPaths = tryLoadModuleUsingPaths(extensions, rest, packageDirectory, versionPaths.paths, loader, !packageDirectoryExists, state);
|
||||
const fromPaths = tryLoadModuleUsingPaths(extensions, rest, packageDirectory, packageInfo.versionPaths.paths, loader, !packageDirectoryExists, state);
|
||||
if (fromPaths) {
|
||||
return fromPaths.value;
|
||||
}
|
||||
@@ -1499,8 +1487,8 @@ namespace ts {
|
||||
}
|
||||
|
||||
/**
|
||||
* LSHost may load a module from a global cache of typings.
|
||||
* This is the minumum code needed to expose that functionality; the rest is in LSHost.
|
||||
* A host may load a module from a global cache of typings.
|
||||
* This is the minumum code needed to expose that functionality; the rest is in the host.
|
||||
*/
|
||||
/* @internal */
|
||||
export function loadModuleFromGlobalCache(moduleName: string, projectName: string | undefined, compilerOptions: CompilerOptions, host: ModuleResolutionHost, globalCache: string): ResolvedModuleWithFailedLookupLocations {
|
||||
|
||||
@@ -175,9 +175,9 @@ namespace ts.moduleSpecifiers {
|
||||
|
||||
function discoverProbableSymlinks(files: ReadonlyArray<SourceFile>, getCanonicalFileName: GetCanonicalFileName, cwd: string): ReadonlyMap<string> {
|
||||
const result = createMap<string>();
|
||||
const symlinks = mapDefined(files, sf =>
|
||||
sf.resolvedModules && firstDefinedIterator(sf.resolvedModules.values(), res =>
|
||||
res && res.originalPath && res.resolvedFileName !== res.originalPath ? [res.resolvedFileName, res.originalPath] : undefined));
|
||||
const symlinks = flatten<readonly [string, string]>(mapDefined(files, sf =>
|
||||
sf.resolvedModules && compact(arrayFrom(mapIterator(sf.resolvedModules.values(), res =>
|
||||
res && res.originalPath && res.resolvedFileName !== res.originalPath ? [res.resolvedFileName, res.originalPath] as const : undefined)))));
|
||||
for (const [resolvedPath, originalPath] of symlinks) {
|
||||
const [commonResolved, commonOriginal] = guessDirectorySymlink(resolvedPath, originalPath, cwd, getCanonicalFileName);
|
||||
result.set(commonOriginal, commonResolved);
|
||||
|
||||
+26
-5
@@ -4430,14 +4430,18 @@ namespace ts {
|
||||
|
||||
if (token() !== SyntaxKind.CloseBraceToken) {
|
||||
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
|
||||
node.expression = parseAssignmentExpressionOrHigher();
|
||||
// Only an AssignmentExpression is valid here per the JSX spec,
|
||||
// but we can unambiguously parse a comma sequence and provide
|
||||
// a better error message in grammar checking.
|
||||
node.expression = parseExpression();
|
||||
}
|
||||
if (inExpressionContext) {
|
||||
parseExpected(SyntaxKind.CloseBraceToken);
|
||||
}
|
||||
else {
|
||||
parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*shouldAdvance*/ false);
|
||||
scanJsxText();
|
||||
if (parseExpected(SyntaxKind.CloseBraceToken, /*message*/ undefined, /*shouldAdvance*/ false)) {
|
||||
scanJsxText();
|
||||
}
|
||||
}
|
||||
|
||||
return finishNode(node);
|
||||
@@ -6427,6 +6431,7 @@ namespace ts {
|
||||
BeginningOfLine,
|
||||
SawAsterisk,
|
||||
SavingComments,
|
||||
SavingBackticks, // NOTE: Only used when parsing tag comments
|
||||
}
|
||||
|
||||
const enum PropertyLikeParse {
|
||||
@@ -6687,18 +6692,23 @@ namespace ts {
|
||||
case SyntaxKind.NewLineTrivia:
|
||||
if (state >= JSDocState.SawAsterisk) {
|
||||
state = JSDocState.BeginningOfLine;
|
||||
// don't use pushComment here because we want to keep the margin unchanged
|
||||
comments.push(scanner.getTokenText());
|
||||
}
|
||||
indent = 0;
|
||||
break;
|
||||
case SyntaxKind.AtToken:
|
||||
if (state === JSDocState.SavingBackticks) {
|
||||
comments.push(scanner.getTokenText());
|
||||
break;
|
||||
}
|
||||
scanner.setTextPos(scanner.getTextPos() - 1);
|
||||
// falls through
|
||||
case SyntaxKind.EndOfFileToken:
|
||||
// Done
|
||||
break loop;
|
||||
case SyntaxKind.WhitespaceTrivia:
|
||||
if (state === JSDocState.SavingComments) {
|
||||
if (state === JSDocState.SavingComments || state === JSDocState.SavingBackticks) {
|
||||
pushComment(scanner.getTokenText());
|
||||
}
|
||||
else {
|
||||
@@ -6720,6 +6730,15 @@ namespace ts {
|
||||
}
|
||||
pushComment(scanner.getTokenText());
|
||||
break;
|
||||
case SyntaxKind.BacktickToken:
|
||||
if (state === JSDocState.SavingBackticks) {
|
||||
state = JSDocState.SavingComments;
|
||||
}
|
||||
else {
|
||||
state = JSDocState.SavingBackticks;
|
||||
}
|
||||
pushComment(scanner.getTokenText());
|
||||
break;
|
||||
case SyntaxKind.AsteriskToken:
|
||||
if (state === JSDocState.BeginningOfLine) {
|
||||
// leading asterisks start recording on the *next* (non-whitespace) token
|
||||
@@ -6730,7 +6749,9 @@ namespace ts {
|
||||
// record the * as a comment
|
||||
// falls through
|
||||
default:
|
||||
state = JSDocState.SavingComments; // leading identifiers start recording as well
|
||||
if (state !== JSDocState.SavingBackticks) {
|
||||
state = JSDocState.SavingComments; // leading identifiers start recording as well
|
||||
}
|
||||
pushComment(scanner.getTokenText());
|
||||
break;
|
||||
}
|
||||
|
||||
+11
-7
@@ -1395,7 +1395,7 @@ namespace ts {
|
||||
const filePath = newSourceFile.path;
|
||||
addFileToFilesByName(newSourceFile, filePath, newSourceFile.resolvedPath);
|
||||
// Set the file as found during node modules search if it was found that way in old progra,
|
||||
if (oldProgram.isSourceFileFromExternalLibrary(oldProgram.getSourceFileByPath(filePath)!)) {
|
||||
if (oldProgram.isSourceFileFromExternalLibrary(oldProgram.getSourceFileByPath(newSourceFile.resolvedPath)!)) {
|
||||
sourceFilesFoundSearchingNodeModules.set(filePath, true);
|
||||
}
|
||||
}
|
||||
@@ -1442,7 +1442,8 @@ namespace ts {
|
||||
},
|
||||
...(host.directoryExists ? { directoryExists: f => host.directoryExists!(f) } : {}),
|
||||
useCaseSensitiveFileNames: () => host.useCaseSensitiveFileNames(),
|
||||
getProgramBuildInfo: () => program.getProgramBuildInfo && program.getProgramBuildInfo()
|
||||
getProgramBuildInfo: () => program.getProgramBuildInfo && program.getProgramBuildInfo(),
|
||||
getSourceFileFromReference: (file, ref) => program.getSourceFileFromReference(file, ref),
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2127,7 +2128,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/** This should have similar behavior to 'processSourceFile' without diagnostics or mutation. */
|
||||
function getSourceFileFromReference(referencingFile: SourceFile, ref: FileReference): SourceFile | undefined {
|
||||
function getSourceFileFromReference(referencingFile: SourceFile | UnparsedSource, ref: FileReference): SourceFile | undefined {
|
||||
return getSourceFileFromReferenceWorker(resolveTripleslashReference(ref.fileName, referencingFile.fileName), fileName => filesByName.get(toPath(fileName)) || undefined);
|
||||
}
|
||||
|
||||
@@ -2232,7 +2233,10 @@ namespace ts {
|
||||
if (isRedirect) {
|
||||
inputName = getProjectReferenceRedirect(fileName) || fileName;
|
||||
}
|
||||
if (getNormalizedAbsolutePath(checkedName, currentDirectory) !== getNormalizedAbsolutePath(inputName, currentDirectory)) {
|
||||
// Check if it differs only in drive letters its ok to ignore that error:
|
||||
const checkedAbsolutePath = getNormalizedAbsolutePathWithoutRoot(checkedName, currentDirectory);
|
||||
const inputAbsolutePath = getNormalizedAbsolutePathWithoutRoot(inputName, currentDirectory);
|
||||
if (checkedAbsolutePath !== inputAbsolutePath) {
|
||||
reportFileNamesDifferOnlyInCasingError(inputName, checkedName, refFile, refPos, refEnd);
|
||||
}
|
||||
}
|
||||
@@ -2770,7 +2774,7 @@ namespace ts {
|
||||
// Ignore file that is not emitted
|
||||
if (!sourceFileMayBeEmitted(file, options, isSourceFileFromExternalLibrary, getResolvedProjectReferenceToRedirect)) continue;
|
||||
if (rootPaths.indexOf(file.path) === -1) {
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_in_project_file_list_Projects_must_list_all_files_or_use_an_include_pattern, file.fileName));
|
||||
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_listed_within_the_file_list_of_project_1_Projects_must_list_all_files_or_use_an_include_pattern, file.fileName, options.configFilePath || ""));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2855,10 +2859,10 @@ namespace ts {
|
||||
createDiagnosticForOptionName(Diagnostics.Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES2015_or_higher, "isolatedModules", "target");
|
||||
}
|
||||
|
||||
const firstNonExternalModuleSourceFile = find(files, f => !isExternalModule(f) && !f.isDeclarationFile && f.scriptKind !== ScriptKind.JSON);
|
||||
const firstNonExternalModuleSourceFile = find(files, f => !isExternalModule(f) && !isSourceFileJS(f) && !f.isDeclarationFile && f.scriptKind !== ScriptKind.JSON);
|
||||
if (firstNonExternalModuleSourceFile) {
|
||||
const span = getErrorSpanForNode(firstNonExternalModuleSourceFile, firstNonExternalModuleSourceFile);
|
||||
programDiagnostics.add(createFileDiagnostic(firstNonExternalModuleSourceFile, span.start, span.length, Diagnostics.Cannot_compile_namespaces_when_the_isolatedModules_flag_is_provided));
|
||||
programDiagnostics.add(createFileDiagnostic(firstNonExternalModuleSourceFile, span.start, span.length, Diagnostics.All_files_must_be_modules_when_the_isolatedModules_flag_is_provided));
|
||||
}
|
||||
}
|
||||
else if (firstNonAmbientExternalModuleSourceFile && languageVersion < ScriptTarget.ES2015 && options.module === ModuleKind.None) {
|
||||
|
||||
@@ -51,9 +51,11 @@ namespace ts {
|
||||
getCachedDirectoryStructureHost(): CachedDirectoryStructureHost | undefined;
|
||||
projectName?: string;
|
||||
getGlobalCache?(): string | undefined;
|
||||
globalCacheResolutionModuleName?(externalModuleName: string): string;
|
||||
writeLog(s: string): void;
|
||||
maxNumberOfFilesToIterateForInvalidation?: number;
|
||||
getCurrentProgram(): Program | undefined;
|
||||
fileIsOpen(filePath: Path): boolean;
|
||||
}
|
||||
|
||||
interface DirectoryWatchesOfFailedLookup {
|
||||
@@ -75,6 +77,41 @@ namespace ts {
|
||||
return some(ignoredPaths, searchPath => stringContains(path, searchPath));
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter out paths like
|
||||
* "/", "/user", "/user/username", "/user/username/folderAtRoot",
|
||||
* "c:/", "c:/users", "c:/users/username", "c:/users/username/folderAtRoot", "c:/folderAtRoot"
|
||||
* @param dirPath
|
||||
*/
|
||||
export function canWatchDirectory(dirPath: Path) {
|
||||
const rootLength = getRootLength(dirPath);
|
||||
if (dirPath.length === rootLength) {
|
||||
// Ignore "/", "c:/"
|
||||
return false;
|
||||
}
|
||||
|
||||
const nextDirectorySeparator = dirPath.indexOf(directorySeparator, rootLength);
|
||||
if (nextDirectorySeparator === -1) {
|
||||
// ignore "/user", "c:/users" or "c:/folderAtRoot"
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dirPath.charCodeAt(0) !== CharacterCodes.slash &&
|
||||
dirPath.substr(rootLength, nextDirectorySeparator).search(/users/i) === -1) {
|
||||
// Paths like c:/folderAtRoot/subFolder are allowed
|
||||
return true;
|
||||
}
|
||||
|
||||
for (let searchIndex = nextDirectorySeparator + 1, searchLevels = 2; searchLevels > 0; searchLevels--) {
|
||||
searchIndex = dirPath.indexOf(directorySeparator, searchIndex) + 1;
|
||||
if (searchIndex === 0) {
|
||||
// Folder isnt at expected minimun levels
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
export const maxNumberOfFilesToIterateForInvalidation = 256;
|
||||
|
||||
type GetResolutionWithResolvedFileName<T extends ResolutionWithFailedLookupLocations = ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName = ResolutionWithResolvedFileName> =
|
||||
@@ -234,7 +271,12 @@ namespace ts {
|
||||
if (globalCache !== undefined && !isExternalModuleNameRelative(moduleName) && !(primaryResult.resolvedModule && extensionIsTS(primaryResult.resolvedModule.extension))) {
|
||||
// create different collection of failed lookup locations for second pass
|
||||
// if it will fail and we've already found something during the first pass - we don't want to pollute its results
|
||||
const { resolvedModule, failedLookupLocations } = loadModuleFromGlobalCache(moduleName, resolutionHost.projectName, compilerOptions, host, globalCache);
|
||||
const { resolvedModule, failedLookupLocations } = loadModuleFromGlobalCache(
|
||||
Debug.assertDefined(resolutionHost.globalCacheResolutionModuleName)(moduleName),
|
||||
resolutionHost.projectName,
|
||||
compilerOptions,
|
||||
host,
|
||||
globalCache);
|
||||
if (resolvedModule) {
|
||||
return { resolvedModule, failedLookupLocations: addRange(primaryResult.failedLookupLocations as string[], failedLookupLocations) };
|
||||
}
|
||||
@@ -372,41 +414,6 @@ namespace ts {
|
||||
return endsWith(dirPath, "/node_modules/@types");
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter out paths like
|
||||
* "/", "/user", "/user/username", "/user/username/folderAtRoot",
|
||||
* "c:/", "c:/users", "c:/users/username", "c:/users/username/folderAtRoot", "c:/folderAtRoot"
|
||||
* @param dirPath
|
||||
*/
|
||||
function canWatchDirectory(dirPath: Path) {
|
||||
const rootLength = getRootLength(dirPath);
|
||||
if (dirPath.length === rootLength) {
|
||||
// Ignore "/", "c:/"
|
||||
return false;
|
||||
}
|
||||
|
||||
const nextDirectorySeparator = dirPath.indexOf(directorySeparator, rootLength);
|
||||
if (nextDirectorySeparator === -1) {
|
||||
// ignore "/user", "c:/users" or "c:/folderAtRoot"
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dirPath.charCodeAt(0) !== CharacterCodes.slash &&
|
||||
dirPath.substr(rootLength, nextDirectorySeparator).search(/users/i) === -1) {
|
||||
// Paths like c:/folderAtRoot/subFolder are allowed
|
||||
return true;
|
||||
}
|
||||
|
||||
for (let searchIndex = nextDirectorySeparator + 1, searchLevels = 2; searchLevels > 0; searchLevels--) {
|
||||
searchIndex = dirPath.indexOf(directorySeparator, searchIndex) + 1;
|
||||
if (searchIndex === 0) {
|
||||
// Folder isnt at expected minimun levels
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function getDirectoryToWatchFailedLookupLocation(failedLookupLocation: string, failedLookupLocationPath: Path): DirectoryOfFailedLookupWatch | undefined {
|
||||
if (isInDirectoryPath(rootPath, failedLookupLocationPath)) {
|
||||
// Ensure failed look up is normalized path
|
||||
@@ -698,6 +705,11 @@ namespace ts {
|
||||
// If something to do with folder/file starting with "." in node_modules folder, skip it
|
||||
if (isPathIgnored(fileOrDirectoryPath)) return false;
|
||||
|
||||
// prevent saving an open file from over-eagerly triggering invalidation
|
||||
if (resolutionHost.fileIsOpen(fileOrDirectoryPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Some file or directory in the watching directory is created
|
||||
// Return early if it does not have any of the watching extension or not the custom failed lookup path
|
||||
const dirOfFileOrDirectory = getDirectoryPath(fileOrDirectoryPath);
|
||||
|
||||
+1
-1
@@ -330,7 +330,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
/*@internal*/
|
||||
export const ignoredPaths = ["/node_modules/.", "/.git"];
|
||||
export const ignoredPaths = ["/node_modules/.", "/.git", "/.#"];
|
||||
|
||||
/*@internal*/
|
||||
export interface RecursiveDirectoryWatcherHost {
|
||||
|
||||
@@ -44,6 +44,7 @@ namespace ts {
|
||||
addRange(transformers, customTransformers && map(customTransformers.before, wrapScriptTransformerFactory));
|
||||
|
||||
transformers.push(transformTypeScript);
|
||||
transformers.push(transformClassFields);
|
||||
|
||||
if (jsx === JsxEmit.React) {
|
||||
transformers.push(transformJsx);
|
||||
|
||||
@@ -0,0 +1,511 @@
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
const enum ClassPropertySubstitutionFlags {
|
||||
/**
|
||||
* Enables substitutions for class expressions with static fields
|
||||
* which have initializers that reference the class name.
|
||||
*/
|
||||
ClassAliases = 1 << 0,
|
||||
}
|
||||
/**
|
||||
* Transforms ECMAScript Class Syntax.
|
||||
* TypeScript parameter property syntax is transformed in the TypeScript transformer.
|
||||
* For now, this transforms public field declarations using TypeScript class semantics
|
||||
* (where the declarations get elided and initializers are transformed as assignments in the constructor).
|
||||
* Eventually, this transform will change to the ECMAScript semantics (with Object.defineProperty).
|
||||
*/
|
||||
export function transformClassFields(context: TransformationContext) {
|
||||
const {
|
||||
hoistVariableDeclaration,
|
||||
endLexicalEnvironment,
|
||||
resumeLexicalEnvironment
|
||||
} = context;
|
||||
const resolver = context.getEmitResolver();
|
||||
|
||||
const previousOnSubstituteNode = context.onSubstituteNode;
|
||||
context.onSubstituteNode = onSubstituteNode;
|
||||
|
||||
let enabledSubstitutions: ClassPropertySubstitutionFlags;
|
||||
|
||||
let classAliases: Identifier[];
|
||||
|
||||
/**
|
||||
* Tracks what computed name expressions originating from elided names must be inlined
|
||||
* at the next execution site, in document order
|
||||
*/
|
||||
let pendingExpressions: Expression[] | undefined;
|
||||
|
||||
/**
|
||||
* Tracks what computed name expression statements and static property initializers must be
|
||||
* emitted at the next execution site, in document order (for decorated classes).
|
||||
*/
|
||||
let pendingStatements: Statement[] | undefined;
|
||||
|
||||
return chainBundle(transformSourceFile);
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
if (node.isDeclarationFile) {
|
||||
return node;
|
||||
}
|
||||
const visited = visitEachChild(node, visitor, context);
|
||||
addEmitHelpers(visited, context.readEmitHelpers());
|
||||
return visited;
|
||||
}
|
||||
|
||||
function visitor(node: Node): VisitResult<Node> {
|
||||
if (!(node.transformFlags & TransformFlags.ContainsClassFields)) return node;
|
||||
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ClassExpression:
|
||||
return visitClassExpression(node as ClassExpression);
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
return visitClassDeclaration(node as ClassDeclaration);
|
||||
case SyntaxKind.VariableStatement:
|
||||
return visitVariableStatement(node as VariableStatement);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the members of a class that has fields.
|
||||
*
|
||||
* @param node The node to visit.
|
||||
*/
|
||||
function classElementVisitor(node: Node): VisitResult<Node> {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
// Constructors for classes using class fields are transformed in
|
||||
// `visitClassDeclaration` or `visitClassExpression`.
|
||||
return undefined;
|
||||
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
// Visit the name of the member (if it's a computed property name).
|
||||
return visitEachChild(node, classElementVisitor, context);
|
||||
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
return visitPropertyDeclaration(node as PropertyDeclaration);
|
||||
|
||||
case SyntaxKind.ComputedPropertyName:
|
||||
return visitComputedPropertyName(node as ComputedPropertyName);
|
||||
|
||||
case SyntaxKind.SemicolonClassElement:
|
||||
return node;
|
||||
|
||||
default:
|
||||
return visitor(node);
|
||||
}
|
||||
}
|
||||
|
||||
function visitVariableStatement(node: VariableStatement) {
|
||||
const savedPendingStatements = pendingStatements;
|
||||
pendingStatements = [];
|
||||
|
||||
const visitedNode = visitEachChild(node, visitor, context);
|
||||
const statement = some(pendingStatements) ?
|
||||
[visitedNode, ...pendingStatements] :
|
||||
visitedNode;
|
||||
|
||||
pendingStatements = savedPendingStatements;
|
||||
return statement;
|
||||
}
|
||||
|
||||
function visitComputedPropertyName(name: ComputedPropertyName) {
|
||||
let node = visitEachChild(name, visitor, context);
|
||||
if (some(pendingExpressions)) {
|
||||
const expressions = pendingExpressions;
|
||||
expressions.push(name.expression);
|
||||
pendingExpressions = [];
|
||||
node = updateComputedPropertyName(
|
||||
node,
|
||||
inlineExpressions(expressions)
|
||||
);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
function visitPropertyDeclaration(node: PropertyDeclaration) {
|
||||
Debug.assert(!some(node.decorators));
|
||||
// Create a temporary variable to store a computed property name (if necessary).
|
||||
// If it's not inlineable, then we emit an expression after the class which assigns
|
||||
// the property name to the temporary variable.
|
||||
const expr = getPropertyNameExpressionIfNeeded(node.name, !!node.initializer);
|
||||
if (expr && !isSimpleInlineableExpression(expr)) {
|
||||
(pendingExpressions || (pendingExpressions = [])).push(expr);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function visitClassDeclaration(node: ClassDeclaration) {
|
||||
if (!forEach(node.members, isPropertyDeclaration)) {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
const savedPendingExpressions = pendingExpressions;
|
||||
pendingExpressions = undefined!;
|
||||
|
||||
const extendsClauseElement = getEffectiveBaseTypeNode(node);
|
||||
const isDerivedClass = !!(extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword);
|
||||
|
||||
const statements: Statement[] = [
|
||||
updateClassDeclaration(
|
||||
node,
|
||||
/*decorators*/ undefined,
|
||||
node.modifiers,
|
||||
node.name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.heritageClauses, visitor, isHeritageClause),
|
||||
transformClassMembers(node, isDerivedClass)
|
||||
)
|
||||
];
|
||||
|
||||
// Write any pending expressions from elided or moved computed property names
|
||||
if (some(pendingExpressions)) {
|
||||
statements.push(createExpressionStatement(inlineExpressions(pendingExpressions)));
|
||||
}
|
||||
|
||||
pendingExpressions = savedPendingExpressions;
|
||||
|
||||
// Emit static property assignment. Because classDeclaration is lexically evaluated,
|
||||
// it is safe to emit static property assignment after classDeclaration
|
||||
// From ES6 specification:
|
||||
// HasLexicalDeclaration (N) : Determines if the argument identifier has a binding in this environment record that was created using
|
||||
// a lexical declaration such as a LexicalDeclaration or a ClassDeclaration.
|
||||
const staticProperties = getInitializedProperties(node, /*isStatic*/ true);
|
||||
if (some(staticProperties)) {
|
||||
addInitializedPropertyStatements(statements, staticProperties, getInternalName(node));
|
||||
}
|
||||
|
||||
return statements;
|
||||
}
|
||||
|
||||
function visitClassExpression(node: ClassExpression): Expression {
|
||||
if (!forEach(node.members, isPropertyDeclaration)) {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
const savedPendingExpressions = pendingExpressions;
|
||||
pendingExpressions = undefined;
|
||||
|
||||
// If this class expression is a transformation of a decorated class declaration,
|
||||
// then we want to output the pendingExpressions as statements, not as inlined
|
||||
// expressions with the class statement.
|
||||
//
|
||||
// In this case, we use pendingStatements to produce the same output as the
|
||||
// class declaration transformation. The VariableStatement visitor will insert
|
||||
// these statements after the class expression variable statement.
|
||||
const isDecoratedClassDeclaration = isClassDeclaration(getOriginalNode(node));
|
||||
|
||||
const staticProperties = getInitializedProperties(node, /*isStatic*/ true);
|
||||
const extendsClauseElement = getEffectiveBaseTypeNode(node);
|
||||
const isDerivedClass = !!(extendsClauseElement && skipOuterExpressions(extendsClauseElement.expression).kind !== SyntaxKind.NullKeyword);
|
||||
|
||||
const classExpression = updateClassExpression(
|
||||
node,
|
||||
node.modifiers,
|
||||
node.name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.heritageClauses, visitor, isHeritageClause),
|
||||
transformClassMembers(node, isDerivedClass)
|
||||
);
|
||||
|
||||
if (some(staticProperties) || some(pendingExpressions)) {
|
||||
if (isDecoratedClassDeclaration) {
|
||||
Debug.assertDefined(pendingStatements, "Decorated classes transformed by TypeScript are expected to be within a variable declaration.");
|
||||
|
||||
// Write any pending expressions from elided or moved computed property names
|
||||
if (pendingStatements && pendingExpressions && some(pendingExpressions)) {
|
||||
pendingStatements.push(createExpressionStatement(inlineExpressions(pendingExpressions)));
|
||||
}
|
||||
pendingExpressions = savedPendingExpressions;
|
||||
|
||||
if (pendingStatements && some(staticProperties)) {
|
||||
addInitializedPropertyStatements(pendingStatements, staticProperties, getInternalName(node));
|
||||
}
|
||||
return classExpression;
|
||||
}
|
||||
else {
|
||||
const expressions: Expression[] = [];
|
||||
const isClassWithConstructorReference = resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference;
|
||||
const temp = createTempVariable(hoistVariableDeclaration, !!isClassWithConstructorReference);
|
||||
if (isClassWithConstructorReference) {
|
||||
// record an alias as the class name is not in scope for statics.
|
||||
enableSubstitutionForClassAliases();
|
||||
const alias = getSynthesizedClone(temp);
|
||||
alias.autoGenerateFlags &= ~GeneratedIdentifierFlags.ReservedInNestedScopes;
|
||||
classAliases[getOriginalNodeId(node)] = alias;
|
||||
}
|
||||
|
||||
// To preserve the behavior of the old emitter, we explicitly indent
|
||||
// the body of a class with static initializers.
|
||||
setEmitFlags(classExpression, EmitFlags.Indented | getEmitFlags(classExpression));
|
||||
expressions.push(startOnNewLine(createAssignment(temp, classExpression)));
|
||||
// Add any pending expressions leftover from elided or relocated computed property names
|
||||
addRange(expressions, map(pendingExpressions, startOnNewLine));
|
||||
addRange(expressions, generateInitializedPropertyExpressions(staticProperties, temp));
|
||||
expressions.push(startOnNewLine(temp));
|
||||
|
||||
pendingExpressions = savedPendingExpressions;
|
||||
return inlineExpressions(expressions);
|
||||
}
|
||||
}
|
||||
|
||||
pendingExpressions = savedPendingExpressions;
|
||||
return classExpression;
|
||||
}
|
||||
|
||||
function transformClassMembers(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) {
|
||||
const members: ClassElement[] = [];
|
||||
const constructor = transformConstructor(node, isDerivedClass);
|
||||
if (constructor) {
|
||||
members.push(constructor);
|
||||
}
|
||||
addRange(members, visitNodes(node.members, classElementVisitor, isClassElement));
|
||||
return setTextRange(createNodeArray(members), /*location*/ node.members);
|
||||
}
|
||||
|
||||
function transformConstructor(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) {
|
||||
const constructor = visitNode(getFirstConstructorWithBody(node), visitor, isConstructorDeclaration);
|
||||
const containsPropertyInitializer = forEach(node.members, isInitializedProperty);
|
||||
if (!containsPropertyInitializer) {
|
||||
return constructor;
|
||||
}
|
||||
const parameters = visitParameterList(constructor ? constructor.parameters : undefined, visitor, context);
|
||||
const body = transformConstructorBody(node, constructor, isDerivedClass);
|
||||
if (!body) {
|
||||
return undefined;
|
||||
}
|
||||
return startOnNewLine(
|
||||
setOriginalNode(
|
||||
setTextRange(
|
||||
createConstructor(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
parameters,
|
||||
body
|
||||
),
|
||||
constructor || node
|
||||
),
|
||||
constructor
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function transformConstructorBody(node: ClassDeclaration | ClassExpression, constructor: ConstructorDeclaration | undefined, isDerivedClass: boolean) {
|
||||
const properties = getInitializedProperties(node, /*isStatic*/ false);
|
||||
|
||||
// Only generate synthetic constructor when there are property initializers to move.
|
||||
if (!constructor && !some(properties)) {
|
||||
return visitFunctionBody(/*node*/ undefined, visitor, context);
|
||||
}
|
||||
|
||||
resumeLexicalEnvironment();
|
||||
|
||||
let indexOfFirstStatement = 0;
|
||||
let statements: Statement[] = [];
|
||||
|
||||
if (!constructor && isDerivedClass) {
|
||||
// Add a synthetic `super` call:
|
||||
//
|
||||
// super(...arguments);
|
||||
//
|
||||
statements.push(
|
||||
createExpressionStatement(
|
||||
createCall(
|
||||
createSuper(),
|
||||
/*typeArguments*/ undefined,
|
||||
[createSpread(createIdentifier("arguments"))]
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (constructor) {
|
||||
indexOfFirstStatement = addPrologueDirectivesAndInitialSuperCall(constructor, statements, visitor);
|
||||
}
|
||||
|
||||
// Add the property initializers. Transforms this:
|
||||
//
|
||||
// public x = 1;
|
||||
//
|
||||
// Into this:
|
||||
//
|
||||
// constructor() {
|
||||
// this.x = 1;
|
||||
// }
|
||||
//
|
||||
if (constructor && constructor.body) {
|
||||
let parameterPropertyDeclarationCount = 0;
|
||||
for (let i = indexOfFirstStatement; i < constructor.body.statements.length; i++) {
|
||||
if (isParameterPropertyDeclaration(getOriginalNode(constructor.body.statements[i]))) {
|
||||
parameterPropertyDeclarationCount++;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (parameterPropertyDeclarationCount > 0) {
|
||||
addRange(statements, visitNodes(constructor.body.statements, visitor, isStatement, indexOfFirstStatement, parameterPropertyDeclarationCount));
|
||||
indexOfFirstStatement += parameterPropertyDeclarationCount;
|
||||
}
|
||||
}
|
||||
addInitializedPropertyStatements(statements, properties, createThis());
|
||||
|
||||
// Add existing statements, skipping the initial super call.
|
||||
if (constructor) {
|
||||
addRange(statements, visitNodes(constructor.body!.statements, visitor, isStatement, indexOfFirstStatement));
|
||||
}
|
||||
|
||||
statements = mergeLexicalEnvironment(statements, endLexicalEnvironment());
|
||||
|
||||
return setTextRange(
|
||||
createBlock(
|
||||
setTextRange(
|
||||
createNodeArray(statements),
|
||||
/*location*/ constructor ? constructor.body!.statements : node.members
|
||||
),
|
||||
/*multiLine*/ true
|
||||
),
|
||||
/*location*/ constructor ? constructor.body : undefined
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates assignment statements for property initializers.
|
||||
*
|
||||
* @param properties An array of property declarations to transform.
|
||||
* @param receiver The receiver on which each property should be assigned.
|
||||
*/
|
||||
function addInitializedPropertyStatements(statements: Statement[], properties: ReadonlyArray<PropertyDeclaration>, receiver: LeftHandSideExpression) {
|
||||
for (const property of properties) {
|
||||
const statement = createExpressionStatement(transformInitializedProperty(property, receiver));
|
||||
setSourceMapRange(statement, moveRangePastModifiers(property));
|
||||
setCommentRange(statement, property);
|
||||
setOriginalNode(statement, property);
|
||||
statements.push(statement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates assignment expressions for property initializers.
|
||||
*
|
||||
* @param properties An array of property declarations to transform.
|
||||
* @param receiver The receiver on which each property should be assigned.
|
||||
*/
|
||||
function generateInitializedPropertyExpressions(properties: ReadonlyArray<PropertyDeclaration>, receiver: LeftHandSideExpression) {
|
||||
const expressions: Expression[] = [];
|
||||
for (const property of properties) {
|
||||
const expression = transformInitializedProperty(property, receiver);
|
||||
startOnNewLine(expression);
|
||||
setSourceMapRange(expression, moveRangePastModifiers(property));
|
||||
setCommentRange(expression, property);
|
||||
setOriginalNode(expression, property);
|
||||
expressions.push(expression);
|
||||
}
|
||||
|
||||
return expressions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a property initializer into an assignment statement.
|
||||
*
|
||||
* @param property The property declaration.
|
||||
* @param receiver The object receiving the property assignment.
|
||||
*/
|
||||
function transformInitializedProperty(property: PropertyDeclaration, receiver: LeftHandSideExpression) {
|
||||
// We generate a name here in order to reuse the value cached by the relocated computed name expression (which uses the same generated name)
|
||||
const propertyName = isComputedPropertyName(property.name) && !isSimpleInlineableExpression(property.name.expression)
|
||||
? updateComputedPropertyName(property.name, getGeneratedNameForNode(property.name))
|
||||
: property.name;
|
||||
const initializer = visitNode(property.initializer!, visitor, isExpression);
|
||||
const memberAccess = createMemberAccessForPropertyName(receiver, propertyName, /*location*/ propertyName);
|
||||
|
||||
return createAssignment(memberAccess, initializer);
|
||||
}
|
||||
|
||||
function enableSubstitutionForClassAliases() {
|
||||
if ((enabledSubstitutions & ClassPropertySubstitutionFlags.ClassAliases) === 0) {
|
||||
enabledSubstitutions |= ClassPropertySubstitutionFlags.ClassAliases;
|
||||
|
||||
// We need to enable substitutions for identifiers. This allows us to
|
||||
// substitute class names inside of a class declaration.
|
||||
context.enableSubstitution(SyntaxKind.Identifier);
|
||||
|
||||
// Keep track of class aliases.
|
||||
classAliases = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks node substitutions.
|
||||
*
|
||||
* @param hint The context for the emitter.
|
||||
* @param node The node to substitute.
|
||||
*/
|
||||
function onSubstituteNode(hint: EmitHint, node: Node) {
|
||||
node = previousOnSubstituteNode(hint, node);
|
||||
if (hint === EmitHint.Expression) {
|
||||
return substituteExpression(node as Expression);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
function substituteExpression(node: Expression) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Identifier:
|
||||
return substituteExpressionIdentifier(node as Identifier);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
function substituteExpressionIdentifier(node: Identifier): Expression {
|
||||
return trySubstituteClassAlias(node) || node;
|
||||
}
|
||||
|
||||
function trySubstituteClassAlias(node: Identifier): Expression | undefined {
|
||||
if (enabledSubstitutions & ClassPropertySubstitutionFlags.ClassAliases) {
|
||||
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ConstructorReferenceInClass) {
|
||||
// Due to the emit for class decorators, any reference to the class from inside of the class body
|
||||
// must instead be rewritten to point to a temporary variable to avoid issues with the double-bind
|
||||
// behavior of class names in ES6.
|
||||
// Also, when emitting statics for class expressions, we must substitute a class alias for
|
||||
// constructor references in static property initializers.
|
||||
const declaration = resolver.getReferencedValueDeclaration(node);
|
||||
if (declaration) {
|
||||
const classAlias = classAliases[declaration.id!]; // TODO: GH#18217
|
||||
if (classAlias) {
|
||||
const clone = getSynthesizedClone(classAlias);
|
||||
setSourceMapRange(clone, node);
|
||||
setCommentRange(clone, node);
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If the name is a computed property, this function transforms it, then either returns an expression which caches the
|
||||
* value of the result or the expression itself if the value is either unused or safe to inline into multiple locations
|
||||
* @param shouldHoist Does the expression need to be reused? (ie, for an initializer or a decorator)
|
||||
*/
|
||||
function getPropertyNameExpressionIfNeeded(name: PropertyName, shouldHoist: boolean): Expression | undefined {
|
||||
if (isComputedPropertyName(name)) {
|
||||
const expression = visitNode(name.expression, visitor, isExpression);
|
||||
const innerExpression = skipPartiallyEmittedExpressions(expression);
|
||||
const inlinable = isSimpleInlineableExpression(innerExpression);
|
||||
const alreadyTransformed = isAssignmentExpression(innerExpression) && isGeneratedIdentifier(innerExpression.left);
|
||||
if (!alreadyTransformed && !inlinable && shouldHoist) {
|
||||
const generatedName = getGeneratedNameForNode(name);
|
||||
hoistVariableDeclaration(generatedName);
|
||||
return createAssignment(generatedName, expression);
|
||||
}
|
||||
return (inlinable || isIdentifier(innerExpression)) ? undefined : expression;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -190,6 +190,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function createEmptyExports() {
|
||||
return createExportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createNamedExports([]), /*moduleSpecifier*/ undefined);
|
||||
}
|
||||
|
||||
function transformRoot(node: Bundle): Bundle;
|
||||
function transformRoot(node: SourceFile): SourceFile;
|
||||
function transformRoot(node: SourceFile | Bundle): SourceFile | Bundle;
|
||||
@@ -277,7 +281,7 @@ namespace ts {
|
||||
refs.forEach(referenceVisitor);
|
||||
const emittedImports = filter(combinedStatements, isAnyImportSyntax);
|
||||
if (isExternalModule(node) && (!resultHasExternalModuleIndicator || (needsScopeFixMarker && !resultHasScopeMarker))) {
|
||||
combinedStatements = setTextRange(createNodeArray([...combinedStatements, createExportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createNamedExports([]), /*moduleSpecifier*/ undefined)]), combinedStatements);
|
||||
combinedStatements = setTextRange(createNodeArray([...combinedStatements, createEmptyExports()]), combinedStatements);
|
||||
}
|
||||
const updated = updateSourceFileNode(node, combinedStatements, /*isDeclarationFile*/ true, references, getFileReferencesForUsedTypeReferences(), node.hasNoDefaultLib, getLibReferences());
|
||||
updated.exportedModulesFromDeclarationEmit = exportedModulesFromDeclarationEmit;
|
||||
@@ -348,7 +352,7 @@ namespace ts {
|
||||
function collectReferences(sourceFile: SourceFile | UnparsedSource, ret: Map<SourceFile>) {
|
||||
if (noResolve || (!isUnparsedSource(sourceFile) && isSourceFileJS(sourceFile))) return ret;
|
||||
forEach(sourceFile.referencedFiles, f => {
|
||||
const elem = tryResolveScriptReference(host, sourceFile, f);
|
||||
const elem = host.getSourceFileFromReference(sourceFile, f);
|
||||
if (elem) {
|
||||
ret.set("" + getOriginalNodeId(elem), elem);
|
||||
}
|
||||
@@ -670,7 +674,7 @@ namespace ts {
|
||||
}
|
||||
const priorNeedsDeclare = needsDeclare;
|
||||
needsDeclare = i.parent && isSourceFile(i.parent) && !(isExternalModule(i.parent) && isBundledEmit);
|
||||
const result = transformTopLevelDeclaration(i, /*privateDeclaration*/ true);
|
||||
const result = transformTopLevelDeclaration(i);
|
||||
needsDeclare = priorNeedsDeclare;
|
||||
lateStatementReplacementMap.set("" + getOriginalNodeId(i), result);
|
||||
}
|
||||
@@ -685,12 +689,12 @@ namespace ts {
|
||||
if (lateStatementReplacementMap.has(key)) {
|
||||
const result = lateStatementReplacementMap.get(key);
|
||||
lateStatementReplacementMap.delete(key);
|
||||
if (result && isSourceFile(statement.parent)) {
|
||||
if (result) {
|
||||
if (isArray(result) ? some(result, needsScopeMarker) : needsScopeMarker(result)) {
|
||||
// Top-level declarations in .d.ts files are always considered exported even without a modifier unless there's an export assignment or specifier
|
||||
needsScopeFixMarker = true;
|
||||
}
|
||||
if (isArray(result) ? some(result, isExternalModuleIndicator) : isExternalModuleIndicator(result)) {
|
||||
if (isSourceFile(statement.parent) && (isArray(result) ? some(result, isExternalModuleIndicator) : isExternalModuleIndicator(result))) {
|
||||
resultHasExternalModuleIndicator = true;
|
||||
}
|
||||
}
|
||||
@@ -939,8 +943,8 @@ namespace ts {
|
||||
case SyntaxKind.ExportDeclaration: {
|
||||
if (isSourceFile(input.parent)) {
|
||||
resultHasExternalModuleIndicator = true;
|
||||
resultHasScopeMarker = true;
|
||||
}
|
||||
resultHasScopeMarker = true;
|
||||
// Always visible if the parent node isn't dropped for being not visible
|
||||
// Rewrite external module names if necessary
|
||||
return updateExportDeclaration(input, /*decorators*/ undefined, input.modifiers, input.exportClause, rewriteModuleSpecifier(input, input.moduleSpecifier));
|
||||
@@ -949,8 +953,8 @@ namespace ts {
|
||||
// Always visible if the parent node isn't dropped for being not visible
|
||||
if (isSourceFile(input.parent)) {
|
||||
resultHasExternalModuleIndicator = true;
|
||||
resultHasScopeMarker = true;
|
||||
}
|
||||
resultHasScopeMarker = true;
|
||||
if (input.expression.kind === SyntaxKind.Identifier) {
|
||||
return input;
|
||||
}
|
||||
@@ -973,7 +977,19 @@ namespace ts {
|
||||
return input;
|
||||
}
|
||||
|
||||
function transformTopLevelDeclaration(input: LateVisibilityPaintedStatement, isPrivate?: boolean) {
|
||||
function stripExportModifiers(statement: Statement): Statement {
|
||||
if (isImportEqualsDeclaration(statement) || hasModifier(statement, ModifierFlags.Default)) {
|
||||
// `export import` statements should remain as-is, as imports are _not_ implicitly exported in an ambient namespace
|
||||
// Likewise, `export default` classes and the like and just be `default`, so we preserve their `export` modifiers, too
|
||||
return statement;
|
||||
}
|
||||
const clone = getMutableClone(statement);
|
||||
const modifiers = createModifiersFromModifierFlags(getModifierFlags(statement) & (ModifierFlags.All ^ ModifierFlags.Export));
|
||||
clone.modifiers = modifiers.length ? createNodeArray(modifiers) : undefined;
|
||||
return clone;
|
||||
}
|
||||
|
||||
function transformTopLevelDeclaration(input: LateVisibilityPaintedStatement) {
|
||||
if (shouldStripInternal(input)) return;
|
||||
switch (input.kind) {
|
||||
case SyntaxKind.ImportEqualsDeclaration: {
|
||||
@@ -1006,7 +1022,7 @@ namespace ts {
|
||||
return cleanup(updateTypeAliasDeclaration(
|
||||
input,
|
||||
/*decorators*/ undefined,
|
||||
ensureModifiers(input, isPrivate),
|
||||
ensureModifiers(input),
|
||||
input.name,
|
||||
visitNodes(input.typeParameters, visitDeclarationSubtree, isTypeParameterDeclaration),
|
||||
visitNode(input.type, visitDeclarationSubtree, isTypeNode)
|
||||
@@ -1015,7 +1031,7 @@ namespace ts {
|
||||
return cleanup(updateInterfaceDeclaration(
|
||||
input,
|
||||
/*decorators*/ undefined,
|
||||
ensureModifiers(input, isPrivate),
|
||||
ensureModifiers(input),
|
||||
input.name,
|
||||
ensureTypeParams(input, input.typeParameters),
|
||||
transformHeritageClauses(input.heritageClauses),
|
||||
@@ -1027,7 +1043,7 @@ namespace ts {
|
||||
const clean = cleanup(updateFunctionDeclaration(
|
||||
input,
|
||||
/*decorators*/ undefined,
|
||||
ensureModifiers(input, isPrivate),
|
||||
ensureModifiers(input),
|
||||
/*asteriskToken*/ undefined,
|
||||
input.name,
|
||||
ensureTypeParams(input, input.typeParameters),
|
||||
@@ -1036,19 +1052,25 @@ namespace ts {
|
||||
/*body*/ undefined
|
||||
));
|
||||
if (clean && resolver.isExpandoFunctionDeclaration(input)) {
|
||||
const declarations = mapDefined(resolver.getPropertiesOfContainerFunction(input), p => {
|
||||
const props = resolver.getPropertiesOfContainerFunction(input);
|
||||
const fakespace = createModuleDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, clean.name || createIdentifier("_default"), createModuleBlock([]), NodeFlags.Namespace);
|
||||
fakespace.flags ^= NodeFlags.Synthesized; // unset synthesized so it is usable as an enclosing declaration
|
||||
fakespace.parent = enclosingDeclaration as SourceFile | NamespaceDeclaration;
|
||||
fakespace.locals = createSymbolTable(props);
|
||||
fakespace.symbol = props[0].parent!;
|
||||
const declarations = mapDefined(props, p => {
|
||||
if (!isPropertyAccessExpression(p.valueDeclaration)) {
|
||||
return undefined;
|
||||
}
|
||||
getSymbolAccessibilityDiagnostic = createGetSymbolAccessibilityDiagnosticForNode(p.valueDeclaration);
|
||||
const type = resolver.createTypeOfDeclaration(p.valueDeclaration, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker);
|
||||
const type = resolver.createTypeOfDeclaration(p.valueDeclaration, fakespace, declarationEmitNodeBuilderFlags, symbolTracker);
|
||||
getSymbolAccessibilityDiagnostic = oldDiag;
|
||||
const varDecl = createVariableDeclaration(unescapeLeadingUnderscores(p.escapedName), type, /*initializer*/ undefined);
|
||||
return createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([varDecl]));
|
||||
});
|
||||
const namespaceDecl = createModuleDeclaration(/*decorators*/ undefined, ensureModifiers(input, isPrivate), input.name!, createModuleBlock(declarations), NodeFlags.Namespace);
|
||||
const namespaceDecl = createModuleDeclaration(/*decorators*/ undefined, ensureModifiers(input), input.name!, createModuleBlock(declarations), NodeFlags.Namespace);
|
||||
|
||||
if (!hasModifier(clean, ModifierFlags.ExportDefault)) {
|
||||
if (!hasModifier(clean, ModifierFlags.Default)) {
|
||||
return [clean, namespaceDecl];
|
||||
}
|
||||
|
||||
@@ -1080,7 +1102,9 @@ namespace ts {
|
||||
namespaceDecl.name
|
||||
);
|
||||
|
||||
resultHasExternalModuleIndicator = true;
|
||||
if (isSourceFile(input.parent)) {
|
||||
resultHasExternalModuleIndicator = true;
|
||||
}
|
||||
resultHasScopeMarker = true;
|
||||
|
||||
return [cleanDeclaration, namespaceDeclaration, exportDefaultDeclaration];
|
||||
@@ -1093,10 +1117,32 @@ namespace ts {
|
||||
needsDeclare = false;
|
||||
const inner = input.body;
|
||||
if (inner && inner.kind === SyntaxKind.ModuleBlock) {
|
||||
const oldNeedsScopeFix = needsScopeFixMarker;
|
||||
const oldHasScopeFix = resultHasScopeMarker;
|
||||
resultHasScopeMarker = false;
|
||||
needsScopeFixMarker = false;
|
||||
const statements = visitNodes(inner.statements, visitDeclarationStatements);
|
||||
const body = updateModuleBlock(inner, transformAndReplaceLatePaintedStatements(statements));
|
||||
let lateStatements = transformAndReplaceLatePaintedStatements(statements);
|
||||
if (input.flags & NodeFlags.Ambient) {
|
||||
needsScopeFixMarker = false; // If it was `declare`'d everything is implicitly exported already, ignore late printed "privates"
|
||||
}
|
||||
// With the final list of statements, there are 3 possibilities:
|
||||
// 1. There's an export assignment or export declaration in the namespace - do nothing
|
||||
// 2. Everything is exported and there are no export assignments or export declarations - strip all export modifiers
|
||||
// 3. Some things are exported, some are not, and there's no marker - add an empty marker
|
||||
if (!isGlobalScopeAugmentation(input) && !hasScopeMarker(lateStatements) && !resultHasScopeMarker) {
|
||||
if (needsScopeFixMarker) {
|
||||
lateStatements = createNodeArray([...lateStatements, createEmptyExports()]);
|
||||
}
|
||||
else {
|
||||
lateStatements = visitNodes(lateStatements, stripExportModifiers);
|
||||
}
|
||||
}
|
||||
const body = updateModuleBlock(inner, lateStatements);
|
||||
needsDeclare = previousNeedsDeclare;
|
||||
const mods = ensureModifiers(input, isPrivate);
|
||||
needsScopeFixMarker = oldNeedsScopeFix;
|
||||
resultHasScopeMarker = oldHasScopeFix;
|
||||
const mods = ensureModifiers(input);
|
||||
return cleanup(updateModuleDeclaration(
|
||||
input,
|
||||
/*decorators*/ undefined,
|
||||
@@ -1107,7 +1153,7 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
needsDeclare = previousNeedsDeclare;
|
||||
const mods = ensureModifiers(input, isPrivate);
|
||||
const mods = ensureModifiers(input);
|
||||
needsDeclare = false;
|
||||
visitNode(inner, visitDeclarationStatements);
|
||||
// eagerly transform nested namespaces (the nesting doesn't need any elision or painting done)
|
||||
@@ -1124,7 +1170,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
case SyntaxKind.ClassDeclaration: {
|
||||
const modifiers = createNodeArray(ensureModifiers(input, isPrivate));
|
||||
const modifiers = createNodeArray(ensureModifiers(input));
|
||||
const typeParameters = ensureTypeParams(input, input.typeParameters);
|
||||
const ctor = getFirstConstructorWithBody(input);
|
||||
let parameterProperties: ReadonlyArray<PropertyDeclaration> | undefined;
|
||||
@@ -1218,10 +1264,10 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
case SyntaxKind.VariableStatement: {
|
||||
return cleanup(transformVariableStatement(input, isPrivate));
|
||||
return cleanup(transformVariableStatement(input));
|
||||
}
|
||||
case SyntaxKind.EnumDeclaration: {
|
||||
return cleanup(updateEnumDeclaration(input, /*decorators*/ undefined, createNodeArray(ensureModifiers(input, isPrivate)), input.name, createNodeArray(mapDefined(input.members, m => {
|
||||
return cleanup(updateEnumDeclaration(input, /*decorators*/ undefined, createNodeArray(ensureModifiers(input)), input.name, createNodeArray(mapDefined(input.members, m => {
|
||||
if (shouldStripInternal(m)) return;
|
||||
// Rewrite enum values to their constants, if available
|
||||
const constValue = resolver.getConstantValue(m);
|
||||
@@ -1249,11 +1295,11 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function transformVariableStatement(input: VariableStatement, privateDeclaration?: boolean) {
|
||||
function transformVariableStatement(input: VariableStatement) {
|
||||
if (!forEach(input.declarationList.declarations, getBindingNameVisible)) return;
|
||||
const nodes = visitNodes(input.declarationList.declarations, visitDeclarationSubtree);
|
||||
if (!length(nodes)) return;
|
||||
return updateVariableStatement(input, createNodeArray(ensureModifiers(input, privateDeclaration)), updateVariableDeclarationList(input.declarationList, nodes));
|
||||
return updateVariableStatement(input, createNodeArray(ensureModifiers(input)), updateVariableDeclarationList(input.declarationList, nodes));
|
||||
}
|
||||
|
||||
function recreateBindingPattern(d: BindingPattern): VariableDeclaration[] {
|
||||
@@ -1300,28 +1346,25 @@ namespace ts {
|
||||
return isExportAssignment(node) || isExportDeclaration(node);
|
||||
}
|
||||
|
||||
function hasScopeMarker(node: Node) {
|
||||
if (isModuleBlock(node)) {
|
||||
return some(node.statements, isScopeMarker);
|
||||
}
|
||||
return false;
|
||||
function hasScopeMarker(statements: ReadonlyArray<Statement>) {
|
||||
return some(statements, isScopeMarker);
|
||||
}
|
||||
|
||||
function ensureModifiers(node: Node, privateDeclaration?: boolean): ReadonlyArray<Modifier> | undefined {
|
||||
function ensureModifiers(node: Node): ReadonlyArray<Modifier> | undefined {
|
||||
const currentFlags = getModifierFlags(node);
|
||||
const newFlags = ensureModifierFlags(node, privateDeclaration);
|
||||
const newFlags = ensureModifierFlags(node);
|
||||
if (currentFlags === newFlags) {
|
||||
return node.modifiers;
|
||||
}
|
||||
return createModifiersFromModifierFlags(newFlags);
|
||||
}
|
||||
|
||||
function ensureModifierFlags(node: Node, privateDeclaration?: boolean): ModifierFlags {
|
||||
function ensureModifierFlags(node: Node): ModifierFlags {
|
||||
let mask = ModifierFlags.All ^ (ModifierFlags.Public | ModifierFlags.Async); // No async modifiers in declaration files
|
||||
let additions = (needsDeclare && !isAlwaysType(node)) ? ModifierFlags.Ambient : ModifierFlags.None;
|
||||
const parentIsFile = node.parent.kind === SyntaxKind.SourceFile;
|
||||
if (!parentIsFile || (isBundledEmit && parentIsFile && isExternalModule(node.parent as SourceFile))) {
|
||||
mask ^= ((privateDeclaration || (isBundledEmit && parentIsFile) || hasScopeMarker(node.parent) ? 0 : ModifierFlags.Export) | ModifierFlags.Ambient);
|
||||
mask ^= ModifierFlags.Ambient;
|
||||
additions = ModifierFlags.None;
|
||||
}
|
||||
return maskModifierFlags(node, mask, additions);
|
||||
|
||||
@@ -145,7 +145,7 @@ namespace ts {
|
||||
loopOutParameters: LoopOutParameter[];
|
||||
}
|
||||
|
||||
type LoopConverter = (node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convertedLoopBodyStatements: Statement[] | undefined) => Statement;
|
||||
type LoopConverter = (node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convertedLoopBodyStatements: Statement[] | undefined, ancestorFacts: HierarchyFacts) => Statement;
|
||||
|
||||
// Facts we track as we traverse the tree
|
||||
const enum HierarchyFacts {
|
||||
@@ -163,11 +163,12 @@ namespace ts {
|
||||
ExportedVariableStatement = 1 << 5, // Enclosed in an exported variable statement in the current scope
|
||||
TopLevel = 1 << 6, // Enclosing block-scoped container is a top-level container
|
||||
Block = 1 << 7, // Enclosing block-scoped container is a Block
|
||||
IterationStatement = 1 << 8, // Enclosed in an IterationStatement
|
||||
IterationStatement = 1 << 8, // Immediately enclosed in an IterationStatement
|
||||
IterationStatementBlock = 1 << 9, // Enclosing Block is enclosed in an IterationStatement
|
||||
ForStatement = 1 << 10, // Enclosing block-scoped container is a ForStatement
|
||||
ForInOrForOfStatement = 1 << 11, // Enclosing block-scoped container is a ForInStatement or ForOfStatement
|
||||
ConstructorWithCapturedSuper = 1 << 12, // Enclosed in a constructor that captures 'this' for use with 'super'
|
||||
IterationContainer = 1 << 10, // Enclosed in an outer IterationStatement
|
||||
ForStatement = 1 << 11, // Enclosing block-scoped container is a ForStatement
|
||||
ForInOrForOfStatement = 1 << 12, // Enclosing block-scoped container is a ForInStatement or ForOfStatement
|
||||
ConstructorWithCapturedSuper = 1 << 13, // Enclosed in a constructor that captures 'this' for use with 'super'
|
||||
// NOTE: do not add more ancestor flags without also updating AncestorFactsMask below.
|
||||
// NOTE: when adding a new ancestor flag, be sure to update the subtree flags below.
|
||||
|
||||
@@ -184,11 +185,11 @@ namespace ts {
|
||||
|
||||
// A source file is a top-level block scope.
|
||||
SourceFileIncludes = TopLevel,
|
||||
SourceFileExcludes = BlockScopeExcludes & ~TopLevel,
|
||||
SourceFileExcludes = BlockScopeExcludes & ~TopLevel | IterationContainer,
|
||||
|
||||
// Functions, methods, and accessors are both new lexical scopes and new block scopes.
|
||||
FunctionIncludes = Function | TopLevel,
|
||||
FunctionExcludes = BlockScopeExcludes & ~TopLevel | ArrowFunction | AsyncFunctionBody | CapturesThis | NonStaticClassElement | ConstructorWithCapturedSuper,
|
||||
FunctionExcludes = BlockScopeExcludes & ~TopLevel | ArrowFunction | AsyncFunctionBody | CapturesThis | NonStaticClassElement | ConstructorWithCapturedSuper | IterationContainer,
|
||||
|
||||
AsyncFunctionBodyIncludes = FunctionIncludes | AsyncFunctionBody,
|
||||
AsyncFunctionBodyExcludes = FunctionExcludes & ~NonStaticClassElement,
|
||||
@@ -205,16 +206,16 @@ namespace ts {
|
||||
// 'do' and 'while' statements are not block scopes. We track that the subtree is contained
|
||||
// within an IterationStatement to indicate whether the embedded statement is an
|
||||
// IterationStatementBlock.
|
||||
DoOrWhileStatementIncludes = IterationStatement,
|
||||
DoOrWhileStatementIncludes = IterationStatement | IterationContainer,
|
||||
DoOrWhileStatementExcludes = None,
|
||||
|
||||
// 'for' statements are new block scopes and have special handling for 'let' declarations.
|
||||
ForStatementIncludes = IterationStatement | ForStatement,
|
||||
ForStatementIncludes = IterationStatement | ForStatement | IterationContainer,
|
||||
ForStatementExcludes = BlockScopeExcludes & ~ForStatement,
|
||||
|
||||
// 'for-in' and 'for-of' statements are new block scopes and have special handling for
|
||||
// 'let' declarations.
|
||||
ForInOrForOfStatementIncludes = IterationStatement | ForInOrForOfStatement,
|
||||
ForInOrForOfStatementIncludes = IterationStatement | ForInOrForOfStatement | IterationContainer,
|
||||
ForInOrForOfStatementExcludes = BlockScopeExcludes & ~ForInOrForOfStatement,
|
||||
|
||||
// Blocks (other than function bodies) are new block scopes.
|
||||
@@ -228,8 +229,8 @@ namespace ts {
|
||||
// Subtree facts
|
||||
//
|
||||
|
||||
NewTarget = 1 << 13, // Contains a 'new.target' meta-property
|
||||
CapturedLexicalThis = 1 << 14, // Contains a lexical `this` reference captured by an arrow function.
|
||||
NewTarget = 1 << 14, // Contains a 'new.target' meta-property
|
||||
CapturedLexicalThis = 1 << 15, // Contains a lexical `this` reference captured by an arrow function.
|
||||
|
||||
//
|
||||
// Subtree masks
|
||||
@@ -1566,7 +1567,7 @@ namespace ts {
|
||||
break;
|
||||
|
||||
default:
|
||||
Debug.failBadSyntaxKind(node);
|
||||
Debug.failBadSyntaxKind(member, currentSourceFile && currentSourceFile.fileName);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -2227,7 +2228,7 @@ namespace ts {
|
||||
|
||||
function visitIterationStatementWithFacts(excludeFacts: HierarchyFacts, includeFacts: HierarchyFacts, node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convert?: LoopConverter) {
|
||||
const ancestorFacts = enterSubtree(excludeFacts, includeFacts);
|
||||
const updated = convertIterationStatementBodyIfNecessary(node, outermostLabeledStatement, convert);
|
||||
const updated = convertIterationStatementBodyIfNecessary(node, outermostLabeledStatement, ancestorFacts, convert);
|
||||
exitSubtree(ancestorFacts, HierarchyFacts.None, HierarchyFacts.None);
|
||||
return updated;
|
||||
}
|
||||
@@ -2434,7 +2435,7 @@ namespace ts {
|
||||
return restoreEnclosingLabel(forStatement, outermostLabeledStatement, convertedLoopState && resetLabel);
|
||||
}
|
||||
|
||||
function convertForOfStatementForIterable(node: ForOfStatement, outermostLabeledStatement: LabeledStatement, convertedLoopBodyStatements: Statement[]): Statement {
|
||||
function convertForOfStatementForIterable(node: ForOfStatement, outermostLabeledStatement: LabeledStatement, convertedLoopBodyStatements: Statement[], ancestorFacts: HierarchyFacts): Statement {
|
||||
const expression = visitNode(node.expression, visitor, isExpression);
|
||||
const iterator = isIdentifier(expression) ? getGeneratedNameForNode(expression) : createTempVariable(/*recordTempVariable*/ undefined);
|
||||
const result = isIdentifier(expression) ? getGeneratedNameForNode(iterator) : createTempVariable(/*recordTempVariable*/ undefined);
|
||||
@@ -2447,13 +2448,18 @@ namespace ts {
|
||||
hoistVariableDeclaration(errorRecord);
|
||||
hoistVariableDeclaration(returnMethod);
|
||||
|
||||
// if we are enclosed in an outer loop ensure we reset 'errorRecord' per each iteration
|
||||
const initializer = ancestorFacts & HierarchyFacts.IterationContainer
|
||||
? inlineExpressions([createAssignment(errorRecord, createVoidZero()), values])
|
||||
: values;
|
||||
|
||||
const forStatement = setEmitFlags(
|
||||
setTextRange(
|
||||
createFor(
|
||||
/*initializer*/ setEmitFlags(
|
||||
setTextRange(
|
||||
createVariableDeclarationList([
|
||||
setTextRange(createVariableDeclaration(iterator, /*type*/ undefined, values), node.expression),
|
||||
setTextRange(createVariableDeclaration(iterator, /*type*/ undefined, initializer), node.expression),
|
||||
createVariableDeclaration(result, /*type*/ undefined, next)
|
||||
]),
|
||||
node.expression
|
||||
@@ -2665,7 +2671,7 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
function convertIterationStatementBodyIfNecessary(node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convert?: LoopConverter): VisitResult<Statement> {
|
||||
function convertIterationStatementBodyIfNecessary(node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, ancestorFacts: HierarchyFacts, convert?: LoopConverter): VisitResult<Statement> {
|
||||
if (!shouldConvertIterationStatement(node)) {
|
||||
let saveAllowedNonLabeledJumps: Jump | undefined;
|
||||
if (convertedLoopState) {
|
||||
@@ -2676,7 +2682,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
const result = convert
|
||||
? convert(node, outermostLabeledStatement, /*convertedLoopBodyStatements*/ undefined)
|
||||
? convert(node, outermostLabeledStatement, /*convertedLoopBodyStatements*/ undefined, ancestorFacts)
|
||||
: restoreEnclosingLabel(visitEachChild(node, visitor, context), outermostLabeledStatement, convertedLoopState && resetLabel);
|
||||
|
||||
if (convertedLoopState) {
|
||||
@@ -2708,7 +2714,7 @@ namespace ts {
|
||||
let loop: Statement;
|
||||
if (bodyFunction) {
|
||||
if (convert) {
|
||||
loop = convert(node, outermostLabeledStatement, bodyFunction.part);
|
||||
loop = convert(node, outermostLabeledStatement, bodyFunction.part, ancestorFacts);
|
||||
}
|
||||
else {
|
||||
const clone = convertIterationStatementCore(node, initializerFunction, createBlock(bodyFunction.part, /*multiLine*/ true));
|
||||
@@ -3813,8 +3819,11 @@ namespace ts {
|
||||
// [source]
|
||||
// [a, ...b, c]
|
||||
//
|
||||
// [output (downlevelIteration)]
|
||||
// __spread([a], b, [c])
|
||||
//
|
||||
// [output]
|
||||
// [a].concat(b, [c])
|
||||
// __spreadArrays([a], b, [c])
|
||||
|
||||
// Map spans of spread expressions into their expressions and spans of other
|
||||
// expressions into an array literal.
|
||||
@@ -3828,10 +3837,7 @@ namespace ts {
|
||||
if (compilerOptions.downlevelIteration) {
|
||||
if (segments.length === 1) {
|
||||
const firstSegment = segments[0];
|
||||
if (isCallExpression(firstSegment)
|
||||
&& isIdentifier(firstSegment.expression)
|
||||
&& (getEmitFlags(firstSegment.expression) & EmitFlags.HelperName)
|
||||
&& firstSegment.expression.escapedText === "___spread") {
|
||||
if (isCallToHelper(firstSegment, "___spread" as __String)) {
|
||||
return segments[0];
|
||||
}
|
||||
}
|
||||
@@ -3840,17 +3846,33 @@ namespace ts {
|
||||
}
|
||||
else {
|
||||
if (segments.length === 1) {
|
||||
const firstElement = elements[0];
|
||||
return needsUniqueCopy && isSpreadElement(firstElement) && firstElement.expression.kind !== SyntaxKind.ArrayLiteralExpression
|
||||
? createArraySlice(segments[0])
|
||||
: segments[0];
|
||||
const firstSegment = segments[0];
|
||||
if (!needsUniqueCopy
|
||||
|| isPackedArrayLiteral(firstSegment)
|
||||
|| isCallToHelper(firstSegment, "___spreadArrays" as __String)) {
|
||||
return segments[0];
|
||||
}
|
||||
}
|
||||
|
||||
// Rewrite using the pattern <segment0>.concat(<segment1>, <segment2>, ...)
|
||||
return createArrayConcat(segments.shift()!, segments);
|
||||
return createSpreadArraysHelper(context, segments);
|
||||
}
|
||||
}
|
||||
|
||||
function isPackedElement(node: Expression) {
|
||||
return !isOmittedExpression(node);
|
||||
}
|
||||
|
||||
function isPackedArrayLiteral(node: Expression) {
|
||||
return isArrayLiteralExpression(node) && every(node.elements, isPackedElement);
|
||||
}
|
||||
|
||||
function isCallToHelper(firstSegment: Expression, helperName: __String) {
|
||||
return isCallExpression(firstSegment)
|
||||
&& isIdentifier(firstSegment.expression)
|
||||
&& (getEmitFlags(firstSegment.expression) & EmitFlags.HelperName)
|
||||
&& firstSegment.expression.escapedText === helperName;
|
||||
}
|
||||
|
||||
function partitionSpread(node: Expression) {
|
||||
return isSpreadElement(node)
|
||||
? visitSpanOfSpreads
|
||||
|
||||
@@ -77,6 +77,8 @@ namespace ts {
|
||||
return visitObjectLiteralExpression(node as ObjectLiteralExpression);
|
||||
case SyntaxKind.BinaryExpression:
|
||||
return visitBinaryExpression(node as BinaryExpression, noDestructuringValue);
|
||||
case SyntaxKind.CatchClause:
|
||||
return visitCatchClause(node as CatchClause);
|
||||
case SyntaxKind.VariableDeclaration:
|
||||
return visitVariableDeclaration(node as VariableDeclaration);
|
||||
case SyntaxKind.ForOfStatement:
|
||||
@@ -272,6 +274,28 @@ namespace ts {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitCatchClause(node: CatchClause) {
|
||||
if (node.variableDeclaration &&
|
||||
isBindingPattern(node.variableDeclaration.name) &&
|
||||
node.variableDeclaration.name.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
|
||||
const name = getGeneratedNameForNode(node.variableDeclaration.name);
|
||||
const updatedDecl = updateVariableDeclaration(node.variableDeclaration, node.variableDeclaration.name, /*type*/ undefined, name);
|
||||
const visitedBindings = flattenDestructuringBinding(updatedDecl, visitor, context, FlattenLevel.ObjectRest);
|
||||
let block = visitNode(node.block, visitor, isBlock);
|
||||
if (some(visitedBindings)) {
|
||||
block = updateBlock(block, [
|
||||
createVariableStatement(/*modifiers*/ undefined, visitedBindings),
|
||||
...block.statements,
|
||||
]);
|
||||
}
|
||||
return updateCatchClause(
|
||||
node,
|
||||
updateVariableDeclaration(node.variableDeclaration, name, /*type*/ undefined, /*initializer*/ undefined),
|
||||
block);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits a VariableDeclaration node with a binding pattern.
|
||||
*
|
||||
|
||||
+146
-446
@@ -64,6 +64,7 @@ namespace ts {
|
||||
let currentLexicalScope: SourceFile | Block | ModuleBlock | CaseBlock;
|
||||
let currentNameScope: ClassDeclaration | undefined;
|
||||
let currentScopeFirstDeclarationsOfName: UnderscoreEscapedMap<Node> | undefined;
|
||||
let currentClassHasParameterProperties: boolean | undefined;
|
||||
|
||||
/**
|
||||
* Keeps track of whether expression substitution has been enabled for specific edge cases.
|
||||
@@ -83,12 +84,6 @@ namespace ts {
|
||||
*/
|
||||
let applicableSubstitutions: TypeScriptSubstitutionFlags;
|
||||
|
||||
/**
|
||||
* Tracks what computed name expressions originating from elided names must be inlined
|
||||
* at the next execution site, in document order
|
||||
*/
|
||||
let pendingExpressions: Expression[] | undefined;
|
||||
|
||||
return transformSourceFileOrBundle;
|
||||
|
||||
function transformSourceFileOrBundle(node: SourceFile | Bundle) {
|
||||
@@ -136,6 +131,7 @@ namespace ts {
|
||||
const savedCurrentScope = currentLexicalScope;
|
||||
const savedCurrentNameScope = currentNameScope;
|
||||
const savedCurrentScopeFirstDeclarationsOfName = currentScopeFirstDeclarationsOfName;
|
||||
const savedCurrentClassHasParameterProperties = currentClassHasParameterProperties;
|
||||
|
||||
// Handle state changes before visiting a node.
|
||||
onBeforeVisitNode(node);
|
||||
@@ -149,6 +145,7 @@ namespace ts {
|
||||
|
||||
currentLexicalScope = savedCurrentScope;
|
||||
currentNameScope = savedCurrentNameScope;
|
||||
currentClassHasParameterProperties = savedCurrentClassHasParameterProperties;
|
||||
return visited;
|
||||
}
|
||||
|
||||
@@ -315,12 +312,12 @@ namespace ts {
|
||||
function classElementVisitorWorker(node: Node): VisitResult<Node> {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
// TypeScript constructors are transformed in `visitClassDeclaration`.
|
||||
// We elide them here as `visitorWorker` checks transform flags, which could
|
||||
// erronously include an ES6 constructor without TypeScript syntax.
|
||||
return undefined;
|
||||
return visitConstructor(node as ConstructorDeclaration);
|
||||
|
||||
case SyntaxKind.PropertyDeclaration:
|
||||
// Property declarations are not TypeScript syntax, but they must be visited
|
||||
// for the decorator transformation.
|
||||
return visitPropertyDeclaration(node as PropertyDeclaration);
|
||||
case SyntaxKind.IndexSignature:
|
||||
case SyntaxKind.GetAccessor:
|
||||
case SyntaxKind.SetAccessor:
|
||||
@@ -437,7 +434,6 @@ namespace ts {
|
||||
// - decorators
|
||||
// - optional `implements` heritage clause
|
||||
// - parameter property assignments in the constructor
|
||||
// - property declarations
|
||||
// - index signatures
|
||||
// - method overload signatures
|
||||
return visitClassDeclaration(<ClassDeclaration>node);
|
||||
@@ -449,7 +445,6 @@ namespace ts {
|
||||
// - decorators
|
||||
// - optional `implements` heritage clause
|
||||
// - parameter property assignments in the constructor
|
||||
// - property declarations
|
||||
// - index signatures
|
||||
// - method overload signatures
|
||||
return visitClassExpression(<ClassExpression>node);
|
||||
@@ -612,9 +607,6 @@ namespace ts {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
const savedPendingExpressions = pendingExpressions;
|
||||
pendingExpressions = undefined;
|
||||
|
||||
const staticProperties = getInitializedProperties(node, /*isStatic*/ true);
|
||||
const facts = getClassFacts(node, staticProperties);
|
||||
|
||||
@@ -624,25 +616,11 @@ namespace ts {
|
||||
|
||||
const name = node.name || (facts & ClassFacts.NeedsName ? getGeneratedNameForNode(node) : undefined);
|
||||
const classStatement = facts & ClassFacts.HasConstructorDecorators
|
||||
? createClassDeclarationHeadWithDecorators(node, name, facts)
|
||||
? createClassDeclarationHeadWithDecorators(node, name)
|
||||
: createClassDeclarationHeadWithoutDecorators(node, name, facts);
|
||||
|
||||
let statements: Statement[] = [classStatement];
|
||||
|
||||
// Write any pending expressions from elided or moved computed property names
|
||||
if (some(pendingExpressions)) {
|
||||
statements.push(createExpressionStatement(inlineExpressions(pendingExpressions!)));
|
||||
}
|
||||
pendingExpressions = savedPendingExpressions;
|
||||
|
||||
// Emit static property assignment. Because classDeclaration is lexically evaluated,
|
||||
// it is safe to emit static property assignment after classDeclaration
|
||||
// From ES6 specification:
|
||||
// HasLexicalDeclaration (N) : Determines if the argument identifier has a binding in this environment record that was created using
|
||||
// a lexical declaration such as a LexicalDeclaration or a ClassDeclaration.
|
||||
if (facts & ClassFacts.HasStaticInitializedProperties) {
|
||||
addInitializedPropertyStatements(statements, staticProperties, facts & ClassFacts.UseImmediatelyInvokedFunctionExpression ? getInternalName(node) : getLocalName(node));
|
||||
}
|
||||
|
||||
// Write any decorators of the node.
|
||||
addClassElementDecorationStatements(statements, node, /*isStatic*/ false);
|
||||
@@ -745,7 +723,7 @@ namespace ts {
|
||||
name,
|
||||
/*typeParameters*/ undefined,
|
||||
visitNodes(node.heritageClauses, visitor, isHeritageClause),
|
||||
transformClassMembers(node, (facts & ClassFacts.IsDerivedClass) !== 0)
|
||||
transformClassMembers(node)
|
||||
);
|
||||
|
||||
// To better align with the old emitter, we should not emit a trailing source map
|
||||
@@ -755,6 +733,7 @@ namespace ts {
|
||||
emitFlags |= EmitFlags.NoTrailingSourceMap;
|
||||
}
|
||||
|
||||
aggregateTransformFlags(classDeclaration);
|
||||
setTextRange(classDeclaration, node);
|
||||
setOriginalNode(classDeclaration, node);
|
||||
setEmitFlags(classDeclaration, emitFlags);
|
||||
@@ -765,7 +744,7 @@ namespace ts {
|
||||
* Transforms a decorated class declaration and appends the resulting statements. If
|
||||
* the class requires an alias to avoid issues with double-binding, the alias is returned.
|
||||
*/
|
||||
function createClassDeclarationHeadWithDecorators(node: ClassDeclaration, name: Identifier | undefined, facts: ClassFacts) {
|
||||
function createClassDeclarationHeadWithDecorators(node: ClassDeclaration, name: Identifier | undefined) {
|
||||
// When we emit an ES6 class that has a class decorator, we must tailor the
|
||||
// emit to certain specific cases.
|
||||
//
|
||||
@@ -860,8 +839,9 @@ namespace ts {
|
||||
// ${members}
|
||||
// }
|
||||
const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause);
|
||||
const members = transformClassMembers(node, (facts & ClassFacts.IsDerivedClass) !== 0);
|
||||
const members = transformClassMembers(node);
|
||||
const classExpression = createClassExpression(/*modifiers*/ undefined, name, /*typeParameters*/ undefined, heritageClauses, members);
|
||||
aggregateTransformFlags(classExpression);
|
||||
setOriginalNode(classExpression, node);
|
||||
setTextRange(classExpression, location);
|
||||
|
||||
@@ -888,49 +868,18 @@ namespace ts {
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
const savedPendingExpressions = pendingExpressions;
|
||||
pendingExpressions = undefined;
|
||||
|
||||
const staticProperties = getInitializedProperties(node, /*isStatic*/ true);
|
||||
const heritageClauses = visitNodes(node.heritageClauses, visitor, isHeritageClause);
|
||||
const members = transformClassMembers(node, some(heritageClauses, c => c.token === SyntaxKind.ExtendsKeyword));
|
||||
|
||||
const classExpression = createClassExpression(
|
||||
/*modifiers*/ undefined,
|
||||
node.name,
|
||||
/*typeParameters*/ undefined,
|
||||
heritageClauses,
|
||||
members
|
||||
visitNodes(node.heritageClauses, visitor, isHeritageClause),
|
||||
transformClassMembers(node)
|
||||
);
|
||||
|
||||
aggregateTransformFlags(classExpression);
|
||||
setOriginalNode(classExpression, node);
|
||||
setTextRange(classExpression, node);
|
||||
|
||||
if (some(staticProperties) || some(pendingExpressions)) {
|
||||
const expressions: Expression[] = [];
|
||||
const isClassWithConstructorReference = resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference;
|
||||
const temp = createTempVariable(hoistVariableDeclaration, !!isClassWithConstructorReference);
|
||||
if (isClassWithConstructorReference) {
|
||||
// record an alias as the class name is not in scope for statics.
|
||||
enableSubstitutionForClassAliases();
|
||||
const alias = getSynthesizedClone(temp);
|
||||
alias.autoGenerateFlags &= ~GeneratedIdentifierFlags.ReservedInNestedScopes;
|
||||
classAliases[getOriginalNodeId(node)] = alias;
|
||||
}
|
||||
|
||||
// To preserve the behavior of the old emitter, we explicitly indent
|
||||
// the body of a class with static initializers.
|
||||
setEmitFlags(classExpression, EmitFlags.Indented | getEmitFlags(classExpression));
|
||||
expressions.push(startOnNewLine(createAssignment(temp, classExpression)));
|
||||
// Add any pending expressions leftover from elided or relocated computed property names
|
||||
addRange(expressions, map(pendingExpressions, startOnNewLine));
|
||||
pendingExpressions = savedPendingExpressions;
|
||||
addRange(expressions, generateInitializedPropertyExpressions(staticProperties, temp));
|
||||
expressions.push(startOnNewLine(temp));
|
||||
return inlineExpressions(expressions);
|
||||
}
|
||||
|
||||
pendingExpressions = savedPendingExpressions;
|
||||
return classExpression;
|
||||
}
|
||||
|
||||
@@ -938,344 +887,31 @@ namespace ts {
|
||||
* Transforms the members of a class.
|
||||
*
|
||||
* @param node The current class.
|
||||
* @param isDerivedClass A value indicating whether the class has an extends clause that does not extend 'null'.
|
||||
*/
|
||||
function transformClassMembers(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) {
|
||||
function transformClassMembers(node: ClassDeclaration | ClassExpression) {
|
||||
const members: ClassElement[] = [];
|
||||
const constructor = transformConstructor(node, isDerivedClass);
|
||||
if (constructor) {
|
||||
members.push(constructor);
|
||||
const constructor = getFirstConstructorWithBody(node);
|
||||
const parametersWithPropertyAssignments = constructor &&
|
||||
filter(constructor.parameters, isParameterPropertyDeclaration);
|
||||
|
||||
if (parametersWithPropertyAssignments) {
|
||||
for (const parameter of parametersWithPropertyAssignments) {
|
||||
if (isIdentifier(parameter.name)) {
|
||||
members.push(aggregateTransformFlags(createProperty(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
parameter.name,
|
||||
/*questionOrExclamationToken*/ undefined,
|
||||
/*type*/ undefined,
|
||||
/*initializer*/ undefined)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
addRange(members, visitNodes(node.members, classElementVisitor, isClassElement));
|
||||
return setTextRange(createNodeArray(members), /*location*/ node.members);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms (or creates) a constructor for a class.
|
||||
*
|
||||
* @param node The current class.
|
||||
* @param isDerivedClass A value indicating whether the class has an extends clause that does not extend 'null'.
|
||||
*/
|
||||
function transformConstructor(node: ClassDeclaration | ClassExpression, isDerivedClass: boolean) {
|
||||
// Check if we have property assignment inside class declaration.
|
||||
// If there is a property assignment, we need to emit constructor whether users define it or not
|
||||
// If there is no property assignment, we can omit constructor if users do not define it
|
||||
const constructor = getFirstConstructorWithBody(node);
|
||||
const hasInstancePropertyWithInitializer = forEach(node.members, isInstanceInitializedProperty);
|
||||
const hasParameterPropertyAssignments = constructor &&
|
||||
constructor.transformFlags & TransformFlags.ContainsTypeScriptClassSyntax &&
|
||||
forEach(constructor.parameters, isParameterWithPropertyAssignment);
|
||||
|
||||
// If the class does not contain nodes that require a synthesized constructor,
|
||||
// accept the current constructor if it exists.
|
||||
if (!hasInstancePropertyWithInitializer && !hasParameterPropertyAssignments) {
|
||||
return visitEachChild(constructor, visitor, context);
|
||||
}
|
||||
|
||||
const parameters = transformConstructorParameters(constructor);
|
||||
const body = transformConstructorBody(node, constructor, isDerivedClass);
|
||||
|
||||
// constructor(${parameters}) {
|
||||
// ${body}
|
||||
// }
|
||||
return startOnNewLine(
|
||||
setOriginalNode(
|
||||
setTextRange(
|
||||
createConstructor(
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
parameters,
|
||||
body
|
||||
),
|
||||
constructor || node
|
||||
),
|
||||
constructor
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms (or creates) the parameters for the constructor of a class with
|
||||
* parameter property assignments or instance property initializers.
|
||||
*
|
||||
* @param constructor The constructor declaration.
|
||||
*/
|
||||
function transformConstructorParameters(constructor: ConstructorDeclaration | undefined) {
|
||||
// The ES2015 spec specifies in 14.5.14. Runtime Semantics: ClassDefinitionEvaluation:
|
||||
// If constructor is empty, then
|
||||
// If ClassHeritag_eopt is present and protoParent is not null, then
|
||||
// Let constructor be the result of parsing the source text
|
||||
// constructor(...args) { super (...args);}
|
||||
// using the syntactic grammar with the goal symbol MethodDefinition[~Yield].
|
||||
// Else,
|
||||
// Let constructor be the result of parsing the source text
|
||||
// constructor( ){ }
|
||||
// using the syntactic grammar with the goal symbol MethodDefinition[~Yield].
|
||||
//
|
||||
// While we could emit the '...args' rest parameter, certain later tools in the pipeline might
|
||||
// downlevel the '...args' portion less efficiently by naively copying the contents of 'arguments' to an array.
|
||||
// Instead, we'll avoid using a rest parameter and spread into the super call as
|
||||
// 'super(...arguments)' instead of 'super(...args)', as you can see in "transformConstructorBody".
|
||||
return visitParameterList(constructor && constructor.parameters, visitor, context)
|
||||
|| <ParameterDeclaration[]>[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms (or creates) a constructor body for a class with parameter property
|
||||
* assignments or instance property initializers.
|
||||
*
|
||||
* @param node The current class.
|
||||
* @param constructor The current class constructor.
|
||||
* @param isDerivedClass A value indicating whether the class has an extends clause that does not extend 'null'.
|
||||
*/
|
||||
function transformConstructorBody(node: ClassExpression | ClassDeclaration, constructor: ConstructorDeclaration | undefined, isDerivedClass: boolean) {
|
||||
let statements: Statement[] = [];
|
||||
let indexOfFirstStatement = 0;
|
||||
|
||||
resumeLexicalEnvironment();
|
||||
|
||||
if (constructor) {
|
||||
indexOfFirstStatement = addPrologueDirectivesAndInitialSuperCall(constructor, statements);
|
||||
|
||||
// Add parameters with property assignments. Transforms this:
|
||||
//
|
||||
// constructor (public x, public y) {
|
||||
// }
|
||||
//
|
||||
// Into this:
|
||||
//
|
||||
// constructor (x, y) {
|
||||
// this.x = x;
|
||||
// this.y = y;
|
||||
// }
|
||||
//
|
||||
const propertyAssignments = getParametersWithPropertyAssignments(constructor);
|
||||
addRange(statements, map(propertyAssignments, transformParameterWithPropertyAssignment));
|
||||
}
|
||||
else if (isDerivedClass) {
|
||||
// Add a synthetic `super` call:
|
||||
//
|
||||
// super(...arguments);
|
||||
//
|
||||
statements.push(
|
||||
createExpressionStatement(
|
||||
createCall(
|
||||
createSuper(),
|
||||
/*typeArguments*/ undefined,
|
||||
[createSpread(createIdentifier("arguments"))]
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Add the property initializers. Transforms this:
|
||||
//
|
||||
// public x = 1;
|
||||
//
|
||||
// Into this:
|
||||
//
|
||||
// constructor() {
|
||||
// this.x = 1;
|
||||
// }
|
||||
//
|
||||
const properties = getInitializedProperties(node, /*isStatic*/ false);
|
||||
addInitializedPropertyStatements(statements, properties, createThis());
|
||||
|
||||
if (constructor) {
|
||||
// The class already had a constructor, so we should add the existing statements, skipping the initial super call.
|
||||
addRange(statements, visitNodes(constructor.body!.statements, visitor, isStatement, indexOfFirstStatement));
|
||||
}
|
||||
|
||||
// End the lexical environment.
|
||||
statements = mergeLexicalEnvironment(statements, endLexicalEnvironment());
|
||||
return setTextRange(
|
||||
createBlock(
|
||||
setTextRange(
|
||||
createNodeArray(statements),
|
||||
/*location*/ constructor ? constructor.body!.statements : node.members
|
||||
),
|
||||
/*multiLine*/ true
|
||||
),
|
||||
/*location*/ constructor ? constructor.body : undefined
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds super call and preceding prologue directives into the list of statements.
|
||||
*
|
||||
* @param ctor The constructor node.
|
||||
* @returns index of the statement that follows super call
|
||||
*/
|
||||
function addPrologueDirectivesAndInitialSuperCall(ctor: ConstructorDeclaration, result: Statement[]): number {
|
||||
if (ctor.body) {
|
||||
const statements = ctor.body.statements;
|
||||
// add prologue directives to the list (if any)
|
||||
const index = addPrologue(result, statements, /*ensureUseStrict*/ false, visitor);
|
||||
if (index === statements.length) {
|
||||
// list contains nothing but prologue directives (or empty) - exit
|
||||
return index;
|
||||
}
|
||||
|
||||
const statement = statements[index];
|
||||
if (statement.kind === SyntaxKind.ExpressionStatement && isSuperCall((<ExpressionStatement>statement).expression)) {
|
||||
result.push(visitNode(statement, visitor, isStatement));
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all parameters of a constructor that should be transformed into property assignments.
|
||||
*
|
||||
* @param node The constructor node.
|
||||
*/
|
||||
function getParametersWithPropertyAssignments(node: ConstructorDeclaration): ReadonlyArray<ParameterDeclaration> {
|
||||
return filter(node.parameters, isParameterWithPropertyAssignment);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether a parameter should be transformed into a property assignment.
|
||||
*
|
||||
* @param parameter The parameter node.
|
||||
*/
|
||||
function isParameterWithPropertyAssignment(parameter: ParameterDeclaration) {
|
||||
return hasModifier(parameter, ModifierFlags.ParameterPropertyModifier)
|
||||
&& isIdentifier(parameter.name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a parameter into a property assignment statement.
|
||||
*
|
||||
* @param node The parameter declaration.
|
||||
*/
|
||||
function transformParameterWithPropertyAssignment(node: ParameterDeclaration) {
|
||||
Debug.assert(isIdentifier(node.name));
|
||||
const name = node.name as Identifier;
|
||||
const propertyName = getMutableClone(name);
|
||||
setEmitFlags(propertyName, EmitFlags.NoComments | EmitFlags.NoSourceMap);
|
||||
|
||||
const localName = getMutableClone(name);
|
||||
setEmitFlags(localName, EmitFlags.NoComments);
|
||||
|
||||
return startOnNewLine(
|
||||
setEmitFlags(
|
||||
setTextRange(
|
||||
createExpressionStatement(
|
||||
createAssignment(
|
||||
setTextRange(
|
||||
createPropertyAccess(
|
||||
createThis(),
|
||||
propertyName
|
||||
),
|
||||
node.name
|
||||
),
|
||||
localName
|
||||
)
|
||||
),
|
||||
moveRangePos(node, -1)
|
||||
),
|
||||
EmitFlags.NoComments
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all property declarations with initializers on either the static or instance side of a class.
|
||||
*
|
||||
* @param node The class node.
|
||||
* @param isStatic A value indicating whether to get properties from the static or instance side of the class.
|
||||
*/
|
||||
function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): ReadonlyArray<PropertyDeclaration> {
|
||||
return filter(node.members, isStatic ? isStaticInitializedProperty : isInstanceInitializedProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether a class element is a static property declaration with an initializer.
|
||||
*
|
||||
* @param member The class element node.
|
||||
*/
|
||||
function isStaticInitializedProperty(member: ClassElement): member is PropertyDeclaration {
|
||||
return isInitializedProperty(member, /*isStatic*/ true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether a class element is an instance property declaration with an initializer.
|
||||
*
|
||||
* @param member The class element node.
|
||||
*/
|
||||
function isInstanceInitializedProperty(member: ClassElement): member is PropertyDeclaration {
|
||||
return isInitializedProperty(member, /*isStatic*/ false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether a class element is either a static or an instance property declaration with an initializer.
|
||||
*
|
||||
* @param member The class element node.
|
||||
* @param isStatic A value indicating whether the member should be a static or instance member.
|
||||
*/
|
||||
function isInitializedProperty(member: ClassElement, isStatic: boolean) {
|
||||
return member.kind === SyntaxKind.PropertyDeclaration
|
||||
&& isStatic === hasModifier(member, ModifierFlags.Static)
|
||||
&& (<PropertyDeclaration>member).initializer !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates assignment statements for property initializers.
|
||||
*
|
||||
* @param properties An array of property declarations to transform.
|
||||
* @param receiver The receiver on which each property should be assigned.
|
||||
*/
|
||||
function addInitializedPropertyStatements(statements: Statement[], properties: ReadonlyArray<PropertyDeclaration>, receiver: LeftHandSideExpression) {
|
||||
for (const property of properties) {
|
||||
const statement = createExpressionStatement(transformInitializedProperty(property, receiver));
|
||||
setSourceMapRange(statement, moveRangePastModifiers(property));
|
||||
setCommentRange(statement, property);
|
||||
setOriginalNode(statement, property);
|
||||
statements.push(statement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates assignment expressions for property initializers.
|
||||
*
|
||||
* @param properties An array of property declarations to transform.
|
||||
* @param receiver The receiver on which each property should be assigned.
|
||||
*/
|
||||
function generateInitializedPropertyExpressions(properties: ReadonlyArray<PropertyDeclaration>, receiver: LeftHandSideExpression) {
|
||||
const expressions: Expression[] = [];
|
||||
for (const property of properties) {
|
||||
const expression = transformInitializedProperty(property, receiver);
|
||||
startOnNewLine(expression);
|
||||
setSourceMapRange(expression, moveRangePastModifiers(property));
|
||||
setCommentRange(expression, property);
|
||||
setOriginalNode(expression, property);
|
||||
expressions.push(expression);
|
||||
}
|
||||
|
||||
return expressions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a property initializer into an assignment statement.
|
||||
*
|
||||
* @param property The property declaration.
|
||||
* @param receiver The object receiving the property assignment.
|
||||
*/
|
||||
function transformInitializedProperty(property: PropertyDeclaration, receiver: LeftHandSideExpression) {
|
||||
// We generate a name here in order to reuse the value cached by the relocated computed name expression (which uses the same generated name)
|
||||
const propertyName = isComputedPropertyName(property.name) && !isSimpleInlineableExpression(property.name.expression)
|
||||
? updateComputedPropertyName(property.name, getGeneratedNameForNode(property.name))
|
||||
: property.name;
|
||||
const initializer = visitNode(property.initializer!, visitor, isExpression);
|
||||
const memberAccess = createMemberAccessForPropertyName(receiver, propertyName, /*location*/ propertyName);
|
||||
|
||||
return createAssignment(memberAccess, initializer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets either the static or instance members of a class that are decorated, or have
|
||||
@@ -2144,16 +1780,6 @@ namespace ts {
|
||||
: createIdentifier("BigInt");
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple inlinable expression is an expression which can be copied into multiple locations
|
||||
* without risk of repeating any sideeffects and whose value could not possibly change between
|
||||
* any such locations
|
||||
*/
|
||||
function isSimpleInlineableExpression(expression: Expression) {
|
||||
return !isIdentifier(expression) && isSimpleCopiableExpression(expression) ||
|
||||
isWellKnownSymbolSyntactically(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an expression that represents a property name. For a computed property, a
|
||||
* name is generated for the node.
|
||||
@@ -2175,26 +1801,6 @@ namespace ts {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the name is a computed property, this function transforms it, then either returns an expression which caches the
|
||||
* value of the result or the expression itself if the value is either unused or safe to inline into multiple locations
|
||||
* @param shouldHoist Does the expression need to be reused? (ie, for an initializer or a decorator)
|
||||
* @param omitSimple Should expressions with no observable side-effects be elided? (ie, the expression is not hoisted for a decorator or initializer and is a literal)
|
||||
*/
|
||||
function getPropertyNameExpressionIfNeeded(name: PropertyName, shouldHoist: boolean, omitSimple: boolean): Expression | undefined {
|
||||
if (isComputedPropertyName(name)) {
|
||||
const expression = visitNode(name.expression, visitor, isExpression);
|
||||
const innerExpression = skipPartiallyEmittedExpressions(expression);
|
||||
const inlinable = isSimpleInlineableExpression(innerExpression);
|
||||
if (!inlinable && shouldHoist) {
|
||||
const generatedName = getGeneratedNameForNode(name);
|
||||
hoistVariableDeclaration(generatedName);
|
||||
return createAssignment(generatedName, expression);
|
||||
}
|
||||
return (omitSimple && (inlinable || isIdentifier(innerExpression))) ? undefined : expression;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Visits the property name of a class element, for use when emitting property
|
||||
* initializers. For a computed property on a node with decorators, a temporary
|
||||
@@ -2204,18 +1810,20 @@ namespace ts {
|
||||
*/
|
||||
function visitPropertyNameOfClassElement(member: ClassElement): PropertyName {
|
||||
const name = member.name!;
|
||||
let expr = getPropertyNameExpressionIfNeeded(name, some(member.decorators), /*omitSimple*/ false);
|
||||
if (expr) { // expr only exists if `name` is a computed property name
|
||||
// Inline any pending expressions from previous elided or relocated computed property name expressions in order to preserve execution order
|
||||
if (some(pendingExpressions)) {
|
||||
expr = inlineExpressions([...pendingExpressions, expr]);
|
||||
pendingExpressions.length = 0;
|
||||
// Computed property names need to be transformed into a hoisted variable when they are used more than once.
|
||||
// The names are used more than once when:
|
||||
// - the property is non-static and its initializer is moved to the constructor (when there are parameter property assignments).
|
||||
// - the property has a decorator.
|
||||
if (isComputedPropertyName(name) && ((!hasStaticModifier(member) && currentClassHasParameterProperties) || some(member.decorators))) {
|
||||
const expression = visitNode(name.expression, visitor, isExpression);
|
||||
const innerExpression = skipPartiallyEmittedExpressions(expression);
|
||||
if (!isSimpleInlineableExpression(innerExpression)) {
|
||||
const generatedName = getGeneratedNameForNode(name);
|
||||
hoistVariableDeclaration(generatedName);
|
||||
return updateComputedPropertyName(name, createAssignment(generatedName, expression));
|
||||
}
|
||||
return updateComputedPropertyName(name as ComputedPropertyName, expr);
|
||||
}
|
||||
else {
|
||||
return name;
|
||||
}
|
||||
return visitNode(name, visitor, isPropertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -2257,16 +1865,27 @@ namespace ts {
|
||||
*
|
||||
* @param node The declaration node.
|
||||
*/
|
||||
function shouldEmitFunctionLikeDeclaration(node: FunctionLikeDeclaration) {
|
||||
function shouldEmitFunctionLikeDeclaration<T extends FunctionLikeDeclaration>(node: T): node is T & { body: NonNullable<T["body"]> } {
|
||||
return !nodeIsMissing(node.body);
|
||||
}
|
||||
|
||||
function visitPropertyDeclaration(node: PropertyDeclaration): undefined {
|
||||
const expr = getPropertyNameExpressionIfNeeded(node.name, some(node.decorators) || !!node.initializer, /*omitSimple*/ true);
|
||||
if (expr && !isSimpleInlineableExpression(expr)) {
|
||||
(pendingExpressions || (pendingExpressions = [])).push(expr);
|
||||
function visitPropertyDeclaration(node: PropertyDeclaration) {
|
||||
const updated = updateProperty(
|
||||
node,
|
||||
/*decorators*/ undefined,
|
||||
visitNodes(node.modifiers, visitor, isModifier),
|
||||
visitPropertyNameOfClassElement(node),
|
||||
/*questionOrExclamationToken*/ undefined,
|
||||
/*type*/ undefined,
|
||||
visitNode(node.initializer, visitor)
|
||||
);
|
||||
if (updated !== node) {
|
||||
// While we emit the source map for the node after skipping decorators and modifiers,
|
||||
// we need to emit the comments for the original range.
|
||||
setCommentRange(updated, node);
|
||||
setSourceMapRange(updated, moveRangePastDecorators(node));
|
||||
}
|
||||
return undefined;
|
||||
return updated;
|
||||
}
|
||||
|
||||
function visitConstructor(node: ConstructorDeclaration) {
|
||||
@@ -2276,10 +1895,90 @@ namespace ts {
|
||||
|
||||
return updateConstructor(
|
||||
node,
|
||||
visitNodes(node.decorators, visitor, isDecorator),
|
||||
visitNodes(node.modifiers, visitor, isModifier),
|
||||
/*decorators*/ undefined,
|
||||
/*modifiers*/ undefined,
|
||||
visitParameterList(node.parameters, visitor, context),
|
||||
visitFunctionBody(node.body, visitor, context)
|
||||
transformConstructorBody(node.body, node)
|
||||
);
|
||||
}
|
||||
|
||||
function transformConstructorBody(body: Block, constructor: ConstructorDeclaration) {
|
||||
const parametersWithPropertyAssignments = constructor &&
|
||||
filter(constructor.parameters, isParameterPropertyDeclaration);
|
||||
if (!some(parametersWithPropertyAssignments)) {
|
||||
return visitFunctionBody(body, visitor, context);
|
||||
}
|
||||
|
||||
let statements: Statement[] = [];
|
||||
let indexOfFirstStatement = 0;
|
||||
|
||||
resumeLexicalEnvironment();
|
||||
|
||||
indexOfFirstStatement = addPrologueDirectivesAndInitialSuperCall(constructor, statements, visitor);
|
||||
|
||||
// Add parameters with property assignments. Transforms this:
|
||||
//
|
||||
// constructor (public x, public y) {
|
||||
// }
|
||||
//
|
||||
// Into this:
|
||||
//
|
||||
// constructor (x, y) {
|
||||
// this.x = x;
|
||||
// this.y = y;
|
||||
// }
|
||||
//
|
||||
addRange(statements, map(parametersWithPropertyAssignments, transformParameterWithPropertyAssignment));
|
||||
|
||||
// Add the existing statements, skipping the initial super call.
|
||||
addRange(statements, visitNodes(body.statements, visitor, isStatement, indexOfFirstStatement));
|
||||
|
||||
// End the lexical environment.
|
||||
statements = mergeLexicalEnvironment(statements, endLexicalEnvironment());
|
||||
const block = createBlock(setTextRange(createNodeArray(statements), body.statements), /*multiLine*/ true);
|
||||
setTextRange(block, /*location*/ body);
|
||||
setOriginalNode(block, body);
|
||||
return block;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms a parameter into a property assignment statement.
|
||||
*
|
||||
* @param node The parameter declaration.
|
||||
*/
|
||||
function transformParameterWithPropertyAssignment(node: ParameterPropertyDeclaration) {
|
||||
const name = node.name;
|
||||
if (!isIdentifier(name)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const propertyName = getMutableClone(name);
|
||||
setEmitFlags(propertyName, EmitFlags.NoComments | EmitFlags.NoSourceMap);
|
||||
|
||||
const localName = getMutableClone(name);
|
||||
setEmitFlags(localName, EmitFlags.NoComments);
|
||||
|
||||
return startOnNewLine(
|
||||
removeAllComments(
|
||||
setTextRange(
|
||||
setOriginalNode(
|
||||
createExpressionStatement(
|
||||
createAssignment(
|
||||
setTextRange(
|
||||
createPropertyAccess(
|
||||
createThis(),
|
||||
propertyName
|
||||
),
|
||||
node.name
|
||||
),
|
||||
localName
|
||||
)
|
||||
),
|
||||
node
|
||||
),
|
||||
moveRangePos(node, -1)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2418,6 +2117,7 @@ namespace ts {
|
||||
if (parameterIsThisKeyword(node)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const updated = updateParameter(
|
||||
node,
|
||||
/*decorators*/ undefined,
|
||||
|
||||
@@ -240,6 +240,47 @@ namespace ts {
|
||||
isIdentifier(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple inlinable expression is an expression which can be copied into multiple locations
|
||||
* without risk of repeating any sideeffects and whose value could not possibly change between
|
||||
* any such locations
|
||||
*/
|
||||
export function isSimpleInlineableExpression(expression: Expression) {
|
||||
return !isIdentifier(expression) && isSimpleCopiableExpression(expression) ||
|
||||
isWellKnownSymbolSyntactically(expression);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds super call and preceding prologue directives into the list of statements.
|
||||
*
|
||||
* @param ctor The constructor node.
|
||||
* @param result The list of statements.
|
||||
* @param visitor The visitor to apply to each node added to the result array.
|
||||
* @returns index of the statement that follows super call
|
||||
*/
|
||||
export function addPrologueDirectivesAndInitialSuperCall(ctor: ConstructorDeclaration, result: Statement[], visitor: Visitor): number {
|
||||
if (ctor.body) {
|
||||
const statements = ctor.body.statements;
|
||||
// add prologue directives to the list (if any)
|
||||
const index = addPrologue(result, statements, /*ensureUseStrict*/ false, visitor);
|
||||
if (index === statements.length) {
|
||||
// list contains nothing but prologue directives (or empty) - exit
|
||||
return index;
|
||||
}
|
||||
|
||||
const statement = statements[index];
|
||||
if (statement.kind === SyntaxKind.ExpressionStatement && isSuperCall((<ExpressionStatement>statement).expression)) {
|
||||
result.push(visitNode(statement, visitor, isStatement));
|
||||
return index + 1;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param input Template string input strings
|
||||
* @param args Names which need to be made file-level unique
|
||||
@@ -255,4 +296,43 @@ namespace ts {
|
||||
return result;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all property declarations with initializers on either the static or instance side of a class.
|
||||
*
|
||||
* @param node The class node.
|
||||
* @param isStatic A value indicating whether to get properties from the static or instance side of the class.
|
||||
*/
|
||||
export function getInitializedProperties(node: ClassExpression | ClassDeclaration, isStatic: boolean): ReadonlyArray<PropertyDeclaration> {
|
||||
return filter(node.members, isStatic ? isStaticInitializedProperty : isInstanceInitializedProperty);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether a class element is a static property declaration with an initializer.
|
||||
*
|
||||
* @param member The class element node.
|
||||
*/
|
||||
export function isStaticInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } {
|
||||
return isInitializedProperty(member) && hasStaticModifier(member);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether a class element is an instance property declaration with an initializer.
|
||||
*
|
||||
* @param member The class element node.
|
||||
*/
|
||||
export function isInstanceInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } {
|
||||
return isInitializedProperty(member) && !hasStaticModifier(member);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a value indicating whether a class element is either a static or an instance property declaration with an initializer.
|
||||
*
|
||||
* @param member The class element node.
|
||||
* @param isStatic A value indicating whether the member should be a static or instance member.
|
||||
*/
|
||||
export function isInitializedProperty(member: ClassElement): member is PropertyDeclaration & { initializer: Expression; } {
|
||||
return member.kind === SyntaxKind.PropertyDeclaration
|
||||
&& (<PropertyDeclaration>member).initializer !== undefined;
|
||||
}
|
||||
}
|
||||
+1727
-1232
File diff suppressed because it is too large
Load Diff
@@ -8,6 +8,7 @@
|
||||
|
||||
"files": [
|
||||
"core.ts",
|
||||
"debug.ts",
|
||||
"performance.ts",
|
||||
"semver.ts",
|
||||
|
||||
@@ -29,6 +30,7 @@
|
||||
"transformers/utilities.ts",
|
||||
"transformers/destructuring.ts",
|
||||
"transformers/ts.ts",
|
||||
"transformers/classFields.ts",
|
||||
"transformers/es2017.ts",
|
||||
"transformers/es2018.ts",
|
||||
"transformers/es2019.ts",
|
||||
|
||||
+45
-24
@@ -2546,6 +2546,8 @@ namespace ts {
|
||||
Shared = 1 << 10, // Referenced as antecedent more than once
|
||||
PreFinally = 1 << 11, // Injected edge that links pre-finally label and pre-try flow
|
||||
AfterFinally = 1 << 12, // Injected edge that links post-finally flow with the rest of the graph
|
||||
/** @internal */
|
||||
Cached = 1 << 13, // Indicates that at least one cross-call cache entry exists for this node, even if not a loop participant
|
||||
Label = BranchLabel | LoopLabel,
|
||||
Condition = TrueCondition | FalseCondition
|
||||
}
|
||||
@@ -2973,7 +2975,7 @@ namespace ts {
|
||||
// For testing purposes only.
|
||||
/* @internal */ structureIsReused?: StructureIsReused;
|
||||
|
||||
/* @internal */ getSourceFileFromReference(referencingFile: SourceFile, ref: FileReference): SourceFile | undefined;
|
||||
/* @internal */ getSourceFileFromReference(referencingFile: SourceFile | UnparsedSource, ref: FileReference): SourceFile | undefined;
|
||||
/* @internal */ getLibFileFromReference(ref: FileReference): SourceFile | undefined;
|
||||
|
||||
/** Given a source file, get the name of the package it was imported from. */
|
||||
@@ -3066,6 +3068,9 @@ namespace ts {
|
||||
|
||||
// Diagnostics were produced and outputs were generated in spite of them.
|
||||
DiagnosticsPresent_OutputsGenerated = 2,
|
||||
|
||||
// When build skipped because passed in project is invalid
|
||||
InvalidProject_OutputsSkipped = 3,
|
||||
}
|
||||
|
||||
export interface EmitResult {
|
||||
@@ -3152,6 +3157,7 @@ namespace ts {
|
||||
*/
|
||||
getExportSymbolOfSymbol(symbol: Symbol): Symbol;
|
||||
getPropertySymbolOfDestructuringAssignment(location: Identifier): Symbol | undefined;
|
||||
getTypeOfAssignmentPattern(pattern: AssignmentPattern): Type;
|
||||
getTypeAtLocation(node: Node): Type;
|
||||
getTypeFromTypeNode(node: TypeNode): Type;
|
||||
|
||||
@@ -3749,6 +3755,8 @@ namespace ts {
|
||||
extendedContainers?: Symbol[]; // Containers (other than the parent) which this symbol is aliased in
|
||||
extendedContainersByFile?: Map<Symbol[]>; // Containers (other than the parent) which this symbol is aliased in
|
||||
variances?: VarianceFlags[]; // Alias symbol type argument variance cache
|
||||
deferralConstituents?: Type[]; // Calculated list of constituents for a deferred type
|
||||
deferralParent?: Type; // Source union/intersection of a deferred type
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -3775,6 +3783,7 @@ namespace ts {
|
||||
ReverseMapped = 1 << 13, // Property of reverse-inferred homomorphic mapped type
|
||||
OptionalParameter = 1 << 14, // Optional parameter
|
||||
RestParameter = 1 << 15, // Rest parameter
|
||||
DeferredType = 1 << 16, // Calculation of the type of this symbol is deferred due to processing costs, should be fetched with `getTypeOfSymbolWithDeferredType`
|
||||
Synthetic = SyntheticProperty | SyntheticMethod,
|
||||
Discriminant = HasNonUniformType | HasLiteralType,
|
||||
Partial = ReadPartial | WritePartial
|
||||
@@ -3964,6 +3973,8 @@ namespace ts {
|
||||
StructuredOrInstantiable = StructuredType | Instantiable,
|
||||
/* @internal */
|
||||
ObjectFlagsType = Nullable | Never | Object | Union | Intersection,
|
||||
/* @internal */
|
||||
Simplifiable = IndexedAccess | Conditional,
|
||||
// 'Narrowable' types are types where narrowing actually narrows.
|
||||
// This *should* be every type other than null, undefined, void, and never
|
||||
Narrowable = Any | Unknown | StructuredOrInstantiable | StringLike | NumberLike | BigIntLike | BooleanLike | ESSymbol | UniqueESSymbol | NonPrimitive,
|
||||
@@ -3972,7 +3983,7 @@ namespace ts {
|
||||
NotPrimitiveUnion = Any | Unknown | Enum | Void | Never | StructuredOrInstantiable,
|
||||
// The following flags are aggregated during union and intersection type construction
|
||||
/* @internal */
|
||||
IncludesMask = Any | Unknown | Primitive | Never | Object | Union,
|
||||
IncludesMask = Any | Unknown | Primitive | Never | Object | Union | NonPrimitive,
|
||||
// The following flags are used for different purposes during union and intersection type construction
|
||||
/* @internal */
|
||||
IncludesStructuredOrInstantiable = TypeParameter,
|
||||
@@ -4005,6 +4016,8 @@ namespace ts {
|
||||
restrictiveInstantiation?: Type; // Instantiation with type parameters mapped to unconstrained form
|
||||
/* @internal */
|
||||
immediateBaseConstraint?: Type; // Immediate base constraint cache
|
||||
/* @internal */
|
||||
widened?: Type; // Cached widened form of the type
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -4076,19 +4089,20 @@ namespace ts {
|
||||
MarkerType = 1 << 13, // Marker type used for variance probing
|
||||
JSLiteral = 1 << 14, // Object type declared in JS - disables errors on read/write of nonexisting members
|
||||
FreshLiteral = 1 << 15, // Fresh object literal
|
||||
ArrayLiteral = 1 << 16, // Originates in an array literal
|
||||
/* @internal */
|
||||
PrimitiveUnion = 1 << 16, // Union of only primitive types
|
||||
PrimitiveUnion = 1 << 17, // Union of only primitive types
|
||||
/* @internal */
|
||||
ContainsWideningType = 1 << 17, // Type is or contains undefined or null widening type
|
||||
ContainsWideningType = 1 << 18, // Type is or contains undefined or null widening type
|
||||
/* @internal */
|
||||
ContainsObjectLiteral = 1 << 18, // Type is or contains object literal type
|
||||
ContainsObjectOrArrayLiteral = 1 << 19, // Type is or contains object literal type
|
||||
/* @internal */
|
||||
NonInferrableType = 1 << 19, // Type is or contains anyFunctionType or silentNeverType
|
||||
NonInferrableType = 1 << 20, // Type is or contains anyFunctionType or silentNeverType
|
||||
ClassOrInterface = Class | Interface,
|
||||
/* @internal */
|
||||
RequiresWidening = ContainsWideningType | ContainsObjectLiteral,
|
||||
RequiresWidening = ContainsWideningType | ContainsObjectOrArrayLiteral,
|
||||
/* @internal */
|
||||
PropagatingFlags = ContainsWideningType | ContainsObjectLiteral | NonInferrableType
|
||||
PropagatingFlags = ContainsWideningType | ContainsObjectOrArrayLiteral | NonInferrableType
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -4141,6 +4155,8 @@ namespace ts {
|
||||
export interface TypeReference extends ObjectType {
|
||||
target: GenericType; // Type reference target
|
||||
typeArguments?: ReadonlyArray<Type>; // Type reference type arguments (undefined if none)
|
||||
/* @internal */
|
||||
literalType?: TypeReference; // Clone of type with ObjectFlags.ArrayLiteral set
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -4336,8 +4352,8 @@ namespace ts {
|
||||
root: ConditionalRoot;
|
||||
checkType: Type;
|
||||
extendsType: Type;
|
||||
trueType: Type;
|
||||
falseType: Type;
|
||||
resolvedTrueType: Type;
|
||||
resolvedFalseType: Type;
|
||||
/* @internal */
|
||||
resolvedInferredTrueType?: Type; // The `trueType` instantiated with the `combinedMapper`, if present
|
||||
/* @internal */
|
||||
@@ -4422,15 +4438,16 @@ namespace ts {
|
||||
export type TypeMapper = (t: TypeParameter) => Type;
|
||||
|
||||
export const enum InferencePriority {
|
||||
NakedTypeVariable = 1 << 0, // Naked type variable in union or intersection type
|
||||
HomomorphicMappedType = 1 << 1, // Reverse inference for homomorphic mapped type
|
||||
MappedTypeConstraint = 1 << 2, // Reverse inference for mapped type
|
||||
ReturnType = 1 << 3, // Inference made from return type of generic function
|
||||
LiteralKeyof = 1 << 4, // Inference made from a string literal to a keyof T
|
||||
NoConstraints = 1 << 5, // Don't infer from constraints of instantiable types
|
||||
AlwaysStrict = 1 << 6, // Always use strict rules for contravariant inferences
|
||||
NakedTypeVariable = 1 << 0, // Naked type variable in union or intersection type
|
||||
HomomorphicMappedType = 1 << 1, // Reverse inference for homomorphic mapped type
|
||||
PartialHomomorphicMappedType = 1 << 2, // Partial reverse inference for homomorphic mapped type
|
||||
MappedTypeConstraint = 1 << 3, // Reverse inference for mapped type
|
||||
ReturnType = 1 << 4, // Inference made from return type of generic function
|
||||
LiteralKeyof = 1 << 5, // Inference made from a string literal to a keyof T
|
||||
NoConstraints = 1 << 6, // Don't infer from constraints of instantiable types
|
||||
AlwaysStrict = 1 << 7, // Always use strict rules for contravariant inferences
|
||||
|
||||
PriorityImpliesCombination = ReturnType | MappedTypeConstraint | LiteralKeyof, // These priorities imply that the resulting type should be a combination of all candidates
|
||||
PriorityImpliesCombination = ReturnType | MappedTypeConstraint | LiteralKeyof, // These priorities imply that the resulting type should be a combination of all candidates
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -5183,6 +5200,7 @@ namespace ts {
|
||||
ContainsYield = 1 << 17,
|
||||
ContainsHoistedDeclarationOrCompletion = 1 << 18,
|
||||
ContainsDynamicImport = 1 << 19,
|
||||
ContainsClassFields = 1 << 20,
|
||||
|
||||
// Please leave this as 1 << 29.
|
||||
// It is the maximum bit we can set before we outgrow the size of a v8 small integer (SMI) on an x86 system.
|
||||
@@ -5325,12 +5343,13 @@ namespace ts {
|
||||
Values = 1 << 8, // __values (used by ES2015 for..of and yield* transformations)
|
||||
Read = 1 << 9, // __read (used by ES2015 iterator destructuring transformation)
|
||||
Spread = 1 << 10, // __spread (used by ES2015 array spread and argument list spread transformations)
|
||||
Await = 1 << 11, // __await (used by ES2017 async generator transformation)
|
||||
AsyncGenerator = 1 << 12, // __asyncGenerator (used by ES2017 async generator transformation)
|
||||
AsyncDelegator = 1 << 13, // __asyncDelegator (used by ES2017 async generator yield* transformation)
|
||||
AsyncValues = 1 << 14, // __asyncValues (used by ES2017 for..await..of transformation)
|
||||
ExportStar = 1 << 15, // __exportStar (used by CommonJS/AMD/UMD module transformation)
|
||||
MakeTemplateObject = 1 << 16, // __makeTemplateObject (used for constructing template string array objects)
|
||||
SpreadArrays = 1 << 11, // __spreadArrays (used by ES2015 array spread and argument list spread transformations)
|
||||
Await = 1 << 12, // __await (used by ES2017 async generator transformation)
|
||||
AsyncGenerator = 1 << 13, // __asyncGenerator (used by ES2017 async generator transformation)
|
||||
AsyncDelegator = 1 << 14, // __asyncDelegator (used by ES2017 async generator yield* transformation)
|
||||
AsyncValues = 1 << 15, // __asyncValues (used by ES2017 for..await..of transformation)
|
||||
ExportStar = 1 << 16, // __exportStar (used by CommonJS/AMD/UMD module transformation)
|
||||
MakeTemplateObject = 1 << 17, // __makeTemplateObject (used for constructing template string array objects)
|
||||
FirstEmitHelper = Extends,
|
||||
LastEmitHelper = MakeTemplateObject,
|
||||
|
||||
@@ -5380,6 +5399,7 @@ namespace ts {
|
||||
|
||||
writeFile: WriteFileCallback;
|
||||
getProgramBuildInfo(): ProgramBuildInfo | undefined;
|
||||
getSourceFileFromReference: Program["getSourceFileFromReference"];
|
||||
}
|
||||
|
||||
export interface TransformationContext {
|
||||
@@ -5710,6 +5730,7 @@ namespace ts {
|
||||
/*@internal*/ writeBundleFileInfo?: boolean;
|
||||
/*@internal*/ recordInternalSection?: boolean;
|
||||
/*@internal*/ stripInternal?: boolean;
|
||||
/*@internal*/ relativeToBuildInfo?: (path: string) => string;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
|
||||
+27
-109
@@ -2073,7 +2073,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function importFromModuleSpecifier(node: StringLiteralLike): AnyValidImportOrReExport {
|
||||
return tryGetImportFromModuleSpecifier(node) || Debug.fail(Debug.showSyntaxKind(node.parent));
|
||||
return tryGetImportFromModuleSpecifier(node) || Debug.failBadSyntaxKind(node.parent);
|
||||
}
|
||||
|
||||
export function tryGetImportFromModuleSpecifier(node: StringLiteralLike): AnyValidImportOrReExport | undefined {
|
||||
@@ -2201,13 +2201,13 @@ namespace ts {
|
||||
let result: (JSDoc | JSDocTag)[] | undefined;
|
||||
// Pull parameter comments from declaring function as well
|
||||
if (isVariableLike(hostNode) && hasInitializer(hostNode) && hasJSDocNodes(hostNode.initializer!)) {
|
||||
result = addRange(result, (hostNode.initializer as HasJSDoc).jsDoc!);
|
||||
result = append(result, last((hostNode.initializer as HasJSDoc).jsDoc!));
|
||||
}
|
||||
|
||||
let node: Node | undefined = hostNode;
|
||||
while (node && node.parent) {
|
||||
if (hasJSDocNodes(node)) {
|
||||
result = addRange(result, node.jsDoc!);
|
||||
result = append(result, last(node.jsDoc!));
|
||||
}
|
||||
|
||||
if (node.kind === SyntaxKind.Parameter) {
|
||||
@@ -2611,13 +2611,6 @@ namespace ts {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function tryResolveScriptReference(host: ScriptReferenceHost, sourceFile: SourceFile | UnparsedSource, reference: FileReference) {
|
||||
if (!host.getCompilerOptions().noResolve) {
|
||||
const referenceFileName = isRootedDiskPath(reference.fileName) ? reference.fileName : combinePaths(getDirectoryPath(sourceFile.fileName), reference.fileName);
|
||||
return host.getSourceFile(referenceFileName);
|
||||
}
|
||||
}
|
||||
|
||||
export function getAncestor(node: Node | undefined, kind: SyntaxKind): Node | undefined {
|
||||
while (node) {
|
||||
if (node.kind === kind) {
|
||||
@@ -2712,11 +2705,19 @@ namespace ts {
|
||||
return isStringLiteralLike(node) || isNumericLiteral(node);
|
||||
}
|
||||
|
||||
export function isSignedNumericLiteral(node: Node): node is PrefixUnaryExpression & { operand: NumericLiteral } {
|
||||
return isPrefixUnaryExpression(node) && (node.operator === SyntaxKind.PlusToken || node.operator === SyntaxKind.MinusToken) && isNumericLiteral(node.operand);
|
||||
}
|
||||
|
||||
/**
|
||||
* A declaration has a dynamic name if both of the following are true:
|
||||
* 1. The declaration has a computed property name
|
||||
* 2. The computed name is *not* expressed as Symbol.<name>, where name
|
||||
* is a property of the Symbol constructor that denotes a built in
|
||||
* A declaration has a dynamic name if all of the following are true:
|
||||
* 1. The declaration has a computed property name.
|
||||
* 2. The computed name is *not* expressed as a StringLiteral.
|
||||
* 3. The computed name is *not* expressed as a NumericLiteral.
|
||||
* 4. The computed name is *not* expressed as a PlusToken or MinusToken
|
||||
* immediately followed by a NumericLiteral.
|
||||
* 5. The computed name is *not* expressed as `Symbol.<name>`, where `<name>`
|
||||
* is a property of the Symbol constructor that denotes a built-in
|
||||
* Symbol.
|
||||
*/
|
||||
export function hasDynamicName(declaration: Declaration): declaration is DynamicNamedDeclaration {
|
||||
@@ -2727,6 +2728,7 @@ namespace ts {
|
||||
export function isDynamicName(name: DeclarationName): boolean {
|
||||
return name.kind === SyntaxKind.ComputedPropertyName &&
|
||||
!isStringOrNumericLiteralLike(name.expression) &&
|
||||
!isSignedNumericLiteral(name.expression) &&
|
||||
!isWellKnownSymbolSyntactically(name.expression);
|
||||
}
|
||||
|
||||
@@ -4186,78 +4188,6 @@ namespace ts {
|
||||
return getNewLine ? getNewLine() : sys ? sys.newLine : carriageReturnLineFeed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats an enum value as a string for debugging and debug assertions.
|
||||
*/
|
||||
function formatEnum(value = 0, enumObject: any, isFlags?: boolean) {
|
||||
const members = getEnumMembers(enumObject);
|
||||
if (value === 0) {
|
||||
return members.length > 0 && members[0][0] === 0 ? members[0][1] : "0";
|
||||
}
|
||||
if (isFlags) {
|
||||
let result = "";
|
||||
let remainingFlags = value;
|
||||
for (let i = members.length - 1; i >= 0 && remainingFlags !== 0; i--) {
|
||||
const [enumValue, enumName] = members[i];
|
||||
if (enumValue !== 0 && (remainingFlags & enumValue) === enumValue) {
|
||||
remainingFlags &= ~enumValue;
|
||||
result = `${enumName}${result ? ", " : ""}${result}`;
|
||||
}
|
||||
}
|
||||
if (remainingFlags === 0) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const [enumValue, enumName] of members) {
|
||||
if (enumValue === value) {
|
||||
return enumName;
|
||||
}
|
||||
}
|
||||
}
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
function getEnumMembers(enumObject: any) {
|
||||
const result: [number, string][] = [];
|
||||
for (const name in enumObject) {
|
||||
const value = enumObject[name];
|
||||
if (typeof value === "number") {
|
||||
result.push([value, name]);
|
||||
}
|
||||
}
|
||||
|
||||
return stableSort<[number, string]>(result, (x, y) => compareValues(x[0], y[0]));
|
||||
}
|
||||
|
||||
export function formatSyntaxKind(kind: SyntaxKind | undefined): string {
|
||||
return formatEnum(kind, (<any>ts).SyntaxKind, /*isFlags*/ false);
|
||||
}
|
||||
|
||||
export function formatModifierFlags(flags: ModifierFlags | undefined): string {
|
||||
return formatEnum(flags, (<any>ts).ModifierFlags, /*isFlags*/ true);
|
||||
}
|
||||
|
||||
export function formatTransformFlags(flags: TransformFlags | undefined): string {
|
||||
return formatEnum(flags, (<any>ts).TransformFlags, /*isFlags*/ true);
|
||||
}
|
||||
|
||||
export function formatEmitFlags(flags: EmitFlags | undefined): string {
|
||||
return formatEnum(flags, (<any>ts).EmitFlags, /*isFlags*/ true);
|
||||
}
|
||||
|
||||
export function formatSymbolFlags(flags: SymbolFlags | undefined): string {
|
||||
return formatEnum(flags, (<any>ts).SymbolFlags, /*isFlags*/ true);
|
||||
}
|
||||
|
||||
export function formatTypeFlags(flags: TypeFlags | undefined): string {
|
||||
return formatEnum(flags, (<any>ts).TypeFlags, /*isFlags*/ true);
|
||||
}
|
||||
|
||||
export function formatObjectFlags(flags: ObjectFlags | undefined): string {
|
||||
return formatEnum(flags, (<any>ts).ObjectFlags, /*isFlags*/ true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new TextRange from the provided pos and end.
|
||||
*
|
||||
@@ -5259,6 +5189,9 @@ namespace ts {
|
||||
return node.parent.left.name;
|
||||
}
|
||||
}
|
||||
else if (isVariableDeclaration(node.parent) && isIdentifier(node.parent.name)) {
|
||||
return node.parent.name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7646,6 +7579,14 @@ namespace ts {
|
||||
return root + pathComponents.slice(1).join(directorySeparator);
|
||||
}
|
||||
|
||||
export function getNormalizedAbsolutePathWithoutRoot(fileName: string, currentDirectory: string | undefined) {
|
||||
return getPathWithoutRoot(getNormalizedPathComponents(fileName, currentDirectory));
|
||||
}
|
||||
|
||||
function getPathWithoutRoot(pathComponents: ReadonlyArray<string>) {
|
||||
if (pathComponents.length === 0) return "";
|
||||
return pathComponents.slice(1).join(directorySeparator);
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
@@ -8420,29 +8361,6 @@ namespace ts {
|
||||
return pathext ? path.slice(0, path.length - pathext.length) + (startsWith(ext, ".") ? ext : "." + ext) : path;
|
||||
}
|
||||
|
||||
export namespace Debug {
|
||||
export function showSymbol(symbol: Symbol): string {
|
||||
const symbolFlags = (ts as any).SymbolFlags;
|
||||
return `{ flags: ${symbolFlags ? showFlags(symbol.flags, symbolFlags) : symbol.flags}; declarations: ${map(symbol.declarations, showSyntaxKind)} }`;
|
||||
}
|
||||
|
||||
function showFlags(flags: number, flagsEnum: { [flag: number]: string }): string {
|
||||
const out: string[] = [];
|
||||
for (let pow = 0; pow <= 30; pow++) {
|
||||
const n = 1 << pow;
|
||||
if (flags & n) {
|
||||
out.push(flagsEnum[n]);
|
||||
}
|
||||
}
|
||||
return out.join("|");
|
||||
}
|
||||
|
||||
export function showSyntaxKind(node: Node): string {
|
||||
const syntaxKind = (ts as any).SyntaxKind;
|
||||
return syntaxKind ? syntaxKind[node.kind] : node.kind.toString();
|
||||
}
|
||||
}
|
||||
|
||||
export function tryParsePattern(pattern: string): Pattern | undefined {
|
||||
// This should be verified outside of here and a proper error thrown.
|
||||
Debug.assert(hasZeroOrOneAsteriskCharacter(pattern));
|
||||
|
||||
@@ -1558,100 +1558,4 @@ namespace ts {
|
||||
function aggregateTransformFlagsForChildNodes(transformFlags: TransformFlags, nodes: NodeArray<Node>): TransformFlags {
|
||||
return transformFlags | aggregateTransformFlagsForNodeArray(nodes);
|
||||
}
|
||||
|
||||
export namespace Debug {
|
||||
let isDebugInfoEnabled = false;
|
||||
|
||||
export function failBadSyntaxKind(node: Node, message?: string): never {
|
||||
return fail(
|
||||
`${message || "Unexpected node."}\r\nNode ${formatSyntaxKind(node.kind)} was unexpected.`,
|
||||
failBadSyntaxKind);
|
||||
}
|
||||
|
||||
export const assertEachNode = shouldAssert(AssertionLevel.Normal)
|
||||
? (nodes: Node[], test: (node: Node) => boolean, message?: string): void => assert(
|
||||
test === undefined || every(nodes, test),
|
||||
message || "Unexpected node.",
|
||||
() => `Node array did not pass test '${getFunctionName(test)}'.`,
|
||||
assertEachNode)
|
||||
: noop;
|
||||
|
||||
export const assertNode = shouldAssert(AssertionLevel.Normal)
|
||||
? (node: Node | undefined, test: ((node: Node | undefined) => boolean) | undefined, message?: string): void => assert(
|
||||
test === undefined || test(node),
|
||||
message || "Unexpected node.",
|
||||
() => `Node ${formatSyntaxKind(node!.kind)} did not pass test '${getFunctionName(test!)}'.`,
|
||||
assertNode)
|
||||
: noop;
|
||||
|
||||
export const assertOptionalNode = shouldAssert(AssertionLevel.Normal)
|
||||
? (node: Node, test: (node: Node) => boolean, message?: string): void => assert(
|
||||
test === undefined || node === undefined || test(node),
|
||||
message || "Unexpected node.",
|
||||
() => `Node ${formatSyntaxKind(node.kind)} did not pass test '${getFunctionName(test)}'.`,
|
||||
assertOptionalNode)
|
||||
: noop;
|
||||
|
||||
export const assertOptionalToken = shouldAssert(AssertionLevel.Normal)
|
||||
? (node: Node, kind: SyntaxKind, message?: string): void => assert(
|
||||
kind === undefined || node === undefined || node.kind === kind,
|
||||
message || "Unexpected node.",
|
||||
() => `Node ${formatSyntaxKind(node.kind)} was not a '${formatSyntaxKind(kind)}' token.`,
|
||||
assertOptionalToken)
|
||||
: noop;
|
||||
|
||||
export const assertMissingNode = shouldAssert(AssertionLevel.Normal)
|
||||
? (node: Node, message?: string): void => assert(
|
||||
node === undefined,
|
||||
message || "Unexpected node.",
|
||||
() => `Node ${formatSyntaxKind(node.kind)} was unexpected'.`,
|
||||
assertMissingNode)
|
||||
: noop;
|
||||
|
||||
/**
|
||||
* Injects debug information into frequently used types.
|
||||
*/
|
||||
export function enableDebugInfo() {
|
||||
if (isDebugInfoEnabled) return;
|
||||
|
||||
// Add additional properties in debug mode to assist with debugging.
|
||||
Object.defineProperties(objectAllocator.getSymbolConstructor().prototype, {
|
||||
__debugFlags: { get(this: Symbol) { return formatSymbolFlags(this.flags); } }
|
||||
});
|
||||
|
||||
Object.defineProperties(objectAllocator.getTypeConstructor().prototype, {
|
||||
__debugFlags: { get(this: Type) { return formatTypeFlags(this.flags); } },
|
||||
__debugObjectFlags: { get(this: Type) { return this.flags & TypeFlags.Object ? formatObjectFlags((<ObjectType>this).objectFlags) : ""; } },
|
||||
__debugTypeToString: { value(this: Type) { return this.checker.typeToString(this); } },
|
||||
});
|
||||
|
||||
const nodeConstructors = [
|
||||
objectAllocator.getNodeConstructor(),
|
||||
objectAllocator.getIdentifierConstructor(),
|
||||
objectAllocator.getTokenConstructor(),
|
||||
objectAllocator.getSourceFileConstructor()
|
||||
];
|
||||
|
||||
for (const ctor of nodeConstructors) {
|
||||
if (!ctor.prototype.hasOwnProperty("__debugKind")) {
|
||||
Object.defineProperties(ctor.prototype, {
|
||||
__debugKind: { get(this: Node) { return formatSyntaxKind(this.kind); } },
|
||||
__debugModifierFlags: { get(this: Node) { return formatModifierFlags(getModifierFlagsNoCache(this)); } },
|
||||
__debugTransformFlags: { get(this: Node) { return formatTransformFlags(this.transformFlags); } },
|
||||
__debugEmitFlags: { get(this: Node) { return formatEmitFlags(getEmitFlags(this)); } },
|
||||
__debugGetText: {
|
||||
value(this: Node, includeTrivia?: boolean) {
|
||||
if (nodeIsSynthesized(this)) return "";
|
||||
const parseNode = getParseTreeNode(this);
|
||||
const sourceFile = parseNode && getSourceFileOfNode(parseNode);
|
||||
return sourceFile ? getSourceTextOfNodeFromSourceFile(sourceFile, parseNode, includeTrivia) : "";
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
isDebugInfoEnabled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+96
-55
@@ -88,8 +88,6 @@ namespace ts {
|
||||
return result;
|
||||
}
|
||||
|
||||
export type ReportEmitErrorSummary = (errorCount: number) => void;
|
||||
|
||||
export function getErrorCountForSummary(diagnostics: ReadonlyArray<Diagnostic>) {
|
||||
return countWhere(diagnostics, diagnostic => diagnostic.category === DiagnosticCategory.Error);
|
||||
}
|
||||
@@ -113,12 +111,12 @@ namespace ts {
|
||||
getCurrentDirectory(): string;
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
getSourceFiles(): ReadonlyArray<SourceFile>;
|
||||
getSyntacticDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
getOptionsDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
getGlobalDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
getSemanticDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getOptionsDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getGlobalDiagnostics(cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): ReadonlyArray<Diagnostic>;
|
||||
getConfigFileParsingDiagnostics(): ReadonlyArray<Diagnostic>;
|
||||
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback): EmitResult;
|
||||
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult;
|
||||
}
|
||||
|
||||
export function listFiles(program: ProgramToEmitFilesAndReportErrors, writeFileName: (s: string) => void) {
|
||||
@@ -132,25 +130,35 @@ namespace ts {
|
||||
/**
|
||||
* Helper that emit files, report diagnostics and lists emitted and/or source files depending on compiler options
|
||||
*/
|
||||
export function emitFilesAndReportErrors(program: ProgramToEmitFilesAndReportErrors, reportDiagnostic: DiagnosticReporter, writeFileName?: (s: string) => void, reportSummary?: ReportEmitErrorSummary, writeFile?: WriteFileCallback) {
|
||||
export function emitFilesAndReportErrors(
|
||||
program: ProgramToEmitFilesAndReportErrors,
|
||||
reportDiagnostic: DiagnosticReporter,
|
||||
writeFileName?: (s: string) => void,
|
||||
reportSummary?: ReportEmitErrorSummary,
|
||||
writeFile?: WriteFileCallback,
|
||||
cancellationToken?: CancellationToken,
|
||||
emitOnlyDtsFiles?: boolean,
|
||||
customTransformers?: CustomTransformers
|
||||
) {
|
||||
// First get and report any syntactic errors.
|
||||
const diagnostics = program.getConfigFileParsingDiagnostics().slice();
|
||||
const configFileParsingDiagnosticsLength = diagnostics.length;
|
||||
addRange(diagnostics, program.getSyntacticDiagnostics());
|
||||
addRange(diagnostics, program.getSyntacticDiagnostics(/*sourceFile*/ undefined, cancellationToken));
|
||||
|
||||
// If we didn't have any syntactic errors, then also try getting the global and
|
||||
// semantic errors.
|
||||
if (diagnostics.length === configFileParsingDiagnosticsLength) {
|
||||
addRange(diagnostics, program.getOptionsDiagnostics());
|
||||
addRange(diagnostics, program.getGlobalDiagnostics());
|
||||
addRange(diagnostics, program.getOptionsDiagnostics(cancellationToken));
|
||||
addRange(diagnostics, program.getGlobalDiagnostics(cancellationToken));
|
||||
|
||||
if (diagnostics.length === configFileParsingDiagnosticsLength) {
|
||||
addRange(diagnostics, program.getSemanticDiagnostics());
|
||||
addRange(diagnostics, program.getSemanticDiagnostics(/*sourceFile*/ undefined, cancellationToken));
|
||||
}
|
||||
}
|
||||
|
||||
// Emit and report any errors we ran into.
|
||||
const { emittedFiles, emitSkipped, diagnostics: emitDiagnostics } = program.emit(/*targetSourceFile*/ undefined, writeFile);
|
||||
const emitResult = program.emit(/*targetSourceFile*/ undefined, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers);
|
||||
const { emittedFiles, diagnostics: emitDiagnostics } = emitResult;
|
||||
addRange(diagnostics, emitDiagnostics);
|
||||
|
||||
sortAndDeduplicateDiagnostics(diagnostics).forEach(reportDiagnostic);
|
||||
@@ -167,7 +175,34 @@ namespace ts {
|
||||
reportSummary(getErrorCountForSummary(diagnostics));
|
||||
}
|
||||
|
||||
if (emitSkipped && diagnostics.length > 0) {
|
||||
return {
|
||||
emitResult,
|
||||
diagnostics,
|
||||
};
|
||||
}
|
||||
|
||||
export function emitFilesAndReportErrorsAndGetExitStatus(
|
||||
program: ProgramToEmitFilesAndReportErrors,
|
||||
reportDiagnostic: DiagnosticReporter,
|
||||
writeFileName?: (s: string) => void,
|
||||
reportSummary?: ReportEmitErrorSummary,
|
||||
writeFile?: WriteFileCallback,
|
||||
cancellationToken?: CancellationToken,
|
||||
emitOnlyDtsFiles?: boolean,
|
||||
customTransformers?: CustomTransformers
|
||||
) {
|
||||
const { emitResult, diagnostics } = emitFilesAndReportErrors(
|
||||
program,
|
||||
reportDiagnostic,
|
||||
writeFileName,
|
||||
reportSummary,
|
||||
writeFile,
|
||||
cancellationToken,
|
||||
emitOnlyDtsFiles,
|
||||
customTransformers
|
||||
);
|
||||
|
||||
if (emitResult.emitSkipped && diagnostics.length > 0) {
|
||||
// If the emitter didn't emit anything, then pass that value along.
|
||||
return ExitStatus.DiagnosticsPresent_OutputsSkipped;
|
||||
}
|
||||
@@ -179,7 +214,7 @@ namespace ts {
|
||||
return ExitStatus.Success;
|
||||
}
|
||||
|
||||
const noopFileWatcher: FileWatcher = { close: noop };
|
||||
export const noopFileWatcher: FileWatcher = { close: noop };
|
||||
|
||||
export function createWatchHost(system = sys, reportWatchStatus?: WatchStatusReporter): WatchHost {
|
||||
const onWatchStatusChange = reportWatchStatus || createWatchStatusReporter(system);
|
||||
@@ -375,43 +410,6 @@ namespace ts {
|
||||
return host;
|
||||
}
|
||||
|
||||
export function readBuilderProgram(compilerOptions: CompilerOptions, readFile: (path: string) => string | undefined) {
|
||||
if (compilerOptions.out || compilerOptions.outFile) return undefined;
|
||||
const buildInfoPath = getOutputPathForBuildInfo(compilerOptions);
|
||||
if (!buildInfoPath) return undefined;
|
||||
const content = readFile(buildInfoPath);
|
||||
if (!content) return undefined;
|
||||
const buildInfo = getBuildInfo(content);
|
||||
if (buildInfo.version !== version) return undefined;
|
||||
if (!buildInfo.program) return undefined;
|
||||
return createBuildProgramUsingProgramBuildInfo(buildInfo.program);
|
||||
}
|
||||
|
||||
export function createIncrementalCompilerHost(options: CompilerOptions, system = sys): CompilerHost {
|
||||
const host = createCompilerHostWorker(options, /*setParentNodes*/ undefined, system);
|
||||
host.createHash = maybeBind(system, system.createHash);
|
||||
setGetSourceFileAsHashVersioned(host, system);
|
||||
changeCompilerHostLikeToUseCache(host, fileName => toPath(fileName, host.getCurrentDirectory(), host.getCanonicalFileName));
|
||||
return host;
|
||||
}
|
||||
|
||||
interface IncrementalProgramOptions<T extends BuilderProgram> {
|
||||
rootNames: ReadonlyArray<string>;
|
||||
options: CompilerOptions;
|
||||
configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>;
|
||||
projectReferences?: ReadonlyArray<ProjectReference>;
|
||||
host?: CompilerHost;
|
||||
createProgram?: CreateProgram<T>;
|
||||
}
|
||||
function createIncrementalProgram<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>({
|
||||
rootNames, options, configFileParsingDiagnostics, projectReferences, host, createProgram
|
||||
}: IncrementalProgramOptions<T>): T {
|
||||
host = host || createIncrementalCompilerHost(options);
|
||||
createProgram = createProgram || createEmitAndSemanticDiagnosticsBuilderProgram as any as CreateProgram<T>;
|
||||
const oldProgram = readBuilderProgram(options, path => host!.readFile(path)) as any as T;
|
||||
return createProgram(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences);
|
||||
}
|
||||
|
||||
export interface IncrementalCompilationOptions {
|
||||
rootNames: ReadonlyArray<string>;
|
||||
options: CompilerOptions;
|
||||
@@ -427,7 +425,7 @@ namespace ts {
|
||||
const system = input.system || sys;
|
||||
const host = input.host || (input.host = createIncrementalCompilerHost(input.options, system));
|
||||
const builderProgram = createIncrementalProgram(input);
|
||||
const exitStatus = emitFilesAndReportErrors(
|
||||
const exitStatus = emitFilesAndReportErrorsAndGetExitStatus(
|
||||
builderProgram,
|
||||
input.reportDiagnostic || createDiagnosticReporter(system),
|
||||
s => host.trace && host.trace(s),
|
||||
@@ -439,6 +437,49 @@ namespace ts {
|
||||
}
|
||||
|
||||
namespace ts {
|
||||
export interface ReadBuildProgramHost {
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
getCurrentDirectory(): string;
|
||||
readFile(fileName: string): string | undefined;
|
||||
}
|
||||
export function readBuilderProgram(compilerOptions: CompilerOptions, host: ReadBuildProgramHost) {
|
||||
if (compilerOptions.out || compilerOptions.outFile) return undefined;
|
||||
const buildInfoPath = getOutputPathForBuildInfo(compilerOptions);
|
||||
if (!buildInfoPath) return undefined;
|
||||
const content = host.readFile(buildInfoPath);
|
||||
if (!content) return undefined;
|
||||
const buildInfo = getBuildInfo(content);
|
||||
if (buildInfo.version !== version) return undefined;
|
||||
if (!buildInfo.program) return undefined;
|
||||
return createBuildProgramUsingProgramBuildInfo(buildInfo.program, buildInfoPath, host);
|
||||
}
|
||||
|
||||
export function createIncrementalCompilerHost(options: CompilerOptions, system = sys): CompilerHost {
|
||||
const host = createCompilerHostWorker(options, /*setParentNodes*/ undefined, system);
|
||||
host.createHash = maybeBind(system, system.createHash);
|
||||
setGetSourceFileAsHashVersioned(host, system);
|
||||
changeCompilerHostLikeToUseCache(host, fileName => toPath(fileName, host.getCurrentDirectory(), host.getCanonicalFileName));
|
||||
return host;
|
||||
}
|
||||
|
||||
export interface IncrementalProgramOptions<T extends BuilderProgram> {
|
||||
rootNames: ReadonlyArray<string>;
|
||||
options: CompilerOptions;
|
||||
configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>;
|
||||
projectReferences?: ReadonlyArray<ProjectReference>;
|
||||
host?: CompilerHost;
|
||||
createProgram?: CreateProgram<T>;
|
||||
}
|
||||
|
||||
export function createIncrementalProgram<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>({
|
||||
rootNames, options, configFileParsingDiagnostics, projectReferences, host, createProgram
|
||||
}: IncrementalProgramOptions<T>): T {
|
||||
host = host || createIncrementalCompilerHost(options);
|
||||
createProgram = createProgram || createEmitAndSemanticDiagnosticsBuilderProgram as any as CreateProgram<T>;
|
||||
const oldProgram = readBuilderProgram(options, host) as any as T;
|
||||
return createProgram(rootNames, options, host, oldProgram, configFileParsingDiagnostics, projectReferences);
|
||||
}
|
||||
|
||||
export type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void;
|
||||
/** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */
|
||||
export type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference> | undefined) => T;
|
||||
@@ -567,7 +608,6 @@ namespace ts {
|
||||
/*@internal*/
|
||||
getCurrentProgram(): T;
|
||||
/** Closes the watch */
|
||||
/*@internal*/
|
||||
close(): void;
|
||||
}
|
||||
|
||||
@@ -691,6 +731,7 @@ namespace ts {
|
||||
hasChangedAutomaticTypeDirectiveNames = true;
|
||||
scheduleProgramUpdate();
|
||||
};
|
||||
compilerHost.fileIsOpen = returnFalse;
|
||||
compilerHost.maxNumberOfFilesToIterateForInvalidation = host.maxNumberOfFilesToIterateForInvalidation;
|
||||
compilerHost.getCurrentProgram = getCurrentProgram;
|
||||
compilerHost.writeLog = writeLog;
|
||||
@@ -710,7 +751,7 @@ namespace ts {
|
||||
((typeDirectiveNames, containingFile, redirectedReference) => resolutionCache.resolveTypeReferenceDirectives(typeDirectiveNames, containingFile, redirectedReference));
|
||||
const userProvidedResolution = !!host.resolveModuleNames || !!host.resolveTypeReferenceDirectives;
|
||||
|
||||
builderProgram = readBuilderProgram(compilerOptions, path => compilerHost.readFile(path)) as any as T;
|
||||
builderProgram = readBuilderProgram(compilerOptions, compilerHost) as any as T;
|
||||
synchronizeProgram();
|
||||
|
||||
// Update the wild card directory watch
|
||||
|
||||
Reference in New Issue
Block a user