Merge branch 'master' into mh/33603-error-message-for-missing-member

This commit is contained in:
Michael Henderson
2019-09-26 17:30:25 -05:00
306 changed files with 17589 additions and 476 deletions
+69 -8
View File
@@ -13,11 +13,26 @@ namespace ts {
referenced: boolean;
}
export function getModuleInstanceState(node: ModuleDeclaration): ModuleInstanceState {
return node.body ? getModuleInstanceStateWorker(node.body) : ModuleInstanceState.Instantiated;
export function getModuleInstanceState(node: ModuleDeclaration, visited?: Map<ModuleInstanceState | undefined>): ModuleInstanceState {
if (node.body && !node.body.parent) {
// getModuleInstanceStateForAliasTarget needs to walk up the parent chain, so parent pointers must be set on this tree already
setParentPointers(node, node.body);
}
return node.body ? getModuleInstanceStateCached(node.body, visited) : ModuleInstanceState.Instantiated;
}
function getModuleInstanceStateWorker(node: Node): ModuleInstanceState {
function getModuleInstanceStateCached(node: Node, visited = createMap<ModuleInstanceState | undefined>()) {
const nodeId = "" + getNodeId(node);
if (visited.has(nodeId)) {
return visited.get(nodeId) || ModuleInstanceState.NonInstantiated;
}
visited.set(nodeId, undefined);
const result = getModuleInstanceStateWorker(node, visited);
visited.set(nodeId, result);
return result;
}
function getModuleInstanceStateWorker(node: Node, visited: Map<ModuleInstanceState | undefined>): ModuleInstanceState {
// A module is uninstantiated if it contains only
switch (node.kind) {
// 1. interface declarations, type alias declarations
@@ -37,11 +52,27 @@ namespace ts {
return ModuleInstanceState.NonInstantiated;
}
break;
// 4. other uninstantiated module declarations.
// 4. Export alias declarations pointing at only uninstantiated modules or things uninstantiated modules contain
case SyntaxKind.ExportDeclaration:
if (!(node as ExportDeclaration).moduleSpecifier && !!(node as ExportDeclaration).exportClause) {
let state = ModuleInstanceState.NonInstantiated;
for (const specifier of (node as ExportDeclaration).exportClause!.elements) {
const specifierState = getModuleInstanceStateForAliasTarget(specifier, visited);
if (specifierState > state) {
state = specifierState;
}
if (state === ModuleInstanceState.Instantiated) {
return state;
}
}
return state;
}
break;
// 5. other uninstantiated module declarations.
case SyntaxKind.ModuleBlock: {
let state = ModuleInstanceState.NonInstantiated;
forEachChild(node, n => {
const childState = getModuleInstanceStateWorker(n);
const childState = getModuleInstanceStateCached(n, visited);
switch (childState) {
case ModuleInstanceState.NonInstantiated:
// child is non-instantiated - continue searching
@@ -61,7 +92,7 @@ namespace ts {
return state;
}
case SyntaxKind.ModuleDeclaration:
return getModuleInstanceState(node as ModuleDeclaration);
return getModuleInstanceState(node as ModuleDeclaration, visited);
case SyntaxKind.Identifier:
// Only jsdoc typedef definition can exist in jsdoc namespace, and it should
// be considered the same as type alias
@@ -72,6 +103,36 @@ namespace ts {
return ModuleInstanceState.Instantiated;
}
function getModuleInstanceStateForAliasTarget(specifier: ExportSpecifier, visited: Map<ModuleInstanceState | undefined>) {
const name = specifier.propertyName || specifier.name;
let p: Node | undefined = specifier.parent;
while (p) {
if (isBlock(p) || isModuleBlock(p) || isSourceFile(p)) {
const statements = p.statements;
let found: ModuleInstanceState | undefined;
for (const statement of statements) {
if (nodeHasName(statement, name)) {
if (!statement.parent) {
setParentPointers(p, statement);
}
const state = getModuleInstanceStateCached(statement, visited);
if (found === undefined || state > found) {
found = state;
}
if (found === ModuleInstanceState.Instantiated) {
return found;
}
}
}
if (found !== undefined) {
return found;
}
}
p = p.parent;
}
return ModuleInstanceState.Instantiated; // Couldn't locate, assume could refer to a value
}
const enum ContainerFlags {
// The current node is not a container, and no container manipulation should happen before
// recursing into it.
@@ -2561,7 +2622,7 @@ namespace ts {
// Declare a 'member' if the container is an ES5 class or ES6 constructor
constructorSymbol.members = constructorSymbol.members || createSymbolTable();
// It's acceptable for multiple 'this' assignments of the same identifier to occur
declareSymbol(constructorSymbol.members, constructorSymbol, node, SymbolFlags.Property, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property);
declareSymbol(constructorSymbol.members, constructorSymbol, node, SymbolFlags.Property | SymbolFlags.Assignment, SymbolFlags.PropertyExcludes & ~SymbolFlags.Property);
addDeclarationToSymbol(constructorSymbol, constructorSymbol.valueDeclaration, SymbolFlags.Class);
}
break;
@@ -2575,7 +2636,7 @@ namespace ts {
// Bind this property to the containing class
const containingClass = thisContainer.parent;
const symbolTable = hasModifier(thisContainer, ModifierFlags.Static) ? containingClass.symbol.exports! : containingClass.symbol.members!;
declareSymbol(symbolTable, containingClass.symbol, node, SymbolFlags.Property, SymbolFlags.None, /*isReplaceableByMethod*/ true);
declareSymbol(symbolTable, containingClass.symbol, node, SymbolFlags.Property | SymbolFlags.Assignment, SymbolFlags.None, /*isReplaceableByMethod*/ true);
break;
case SyntaxKind.SourceFile:
// this.property = assignment in a source file -- declare symbol in exports for a module, in locals for a script
+1423 -63
View File
File diff suppressed because it is too large Load Diff
+8
View File
@@ -1552,6 +1552,14 @@ namespace ts {
return fn ? fn.bind(obj) : undefined;
}
export function mapMap<T, U>(map: Map<T>, f: (t: T, key: string) => [string, U]): Map<U>;
export function mapMap<T, U>(map: UnderscoreEscapedMap<T>, f: (t: T, key: __String) => [string, U]): Map<U>;
export function mapMap<T, U>(map: Map<T> | UnderscoreEscapedMap<T>, f: ((t: T, key: string) => [string, U]) | ((t: T, key: __String) => [string, U])): Map<U> {
const result = createMap<U>();
map.forEach((t: T, key: string & __String) => result.set(...(f(t, key))));
return result;
}
export interface MultiMap<T> extends Map<T[]> {
/**
* Adds the value to an array of values associated with the key, and returns the array.
+8
View File
@@ -4587,6 +4587,14 @@
"category": "Error",
"code": 9004
},
"Declaration emit for this file requires using private name '{0}'. An explicit type annotation may unblock declaration emit.": {
"category": "Error",
"code": 9005
},
"Declaration emit for this file requires using private name '{0}' from module '{1}'. An explicit type annotation may unblock declaration emit.": {
"category": "Error",
"code": 9006
},
"JSX attributes must only be assigned a non-empty 'expression'.": {
"category": "Error",
"code": 17000
+8 -10
View File
@@ -96,9 +96,7 @@ namespace ts {
comparePaths(sourceFile.fileName, ownOutputFilePath, host.getCurrentDirectory(), !host.useCaseSensitiveFileNames()) === Comparison.EqualTo;
const jsFilePath = options.emitDeclarationOnly || isJsonEmittedToSameLocation ? undefined : ownOutputFilePath;
const sourceMapFilePath = !jsFilePath || isJsonSourceFile(sourceFile) ? undefined : getSourceMapFilePath(jsFilePath, options);
// For legacy reasons (ie, we have baselines capturing the behavior), js files don't report a .d.ts output path - this would only matter if `declaration` and `allowJs` were both on, which is currently an error
const isJs = isSourceFileJS(sourceFile);
const declarationFilePath = ((forceDtsPaths || getEmitDeclarations(options)) && !isJs) ? getDeclarationEmitOutputFilePath(sourceFile.fileName, host) : undefined;
const declarationFilePath = (forceDtsPaths || getEmitDeclarations(options)) ? getDeclarationEmitOutputFilePath(sourceFile.fileName, host) : undefined;
const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined;
return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, buildInfoPath: undefined };
}
@@ -146,7 +144,7 @@ namespace ts {
/* @internal */
export function getOutputDeclarationFileName(inputFileName: string, configFile: ParsedCommandLine, ignoreCase: boolean) {
Debug.assert(!fileExtensionIs(inputFileName, Extension.Dts) && hasTSFileExtension(inputFileName));
Debug.assert(!fileExtensionIs(inputFileName, Extension.Dts));
return changeExtension(
getOutputPathWithoutChangingExt(inputFileName, configFile, ignoreCase, configFile.options.declarationDir || configFile.options.outDir),
Extension.Dts
@@ -199,7 +197,7 @@ namespace ts {
if (js && configFile.options.sourceMap) {
addOutput(`${js}.map`);
}
if (getEmitDeclarations(configFile.options) && hasTSFileExtension(inputFileName)) {
if (getEmitDeclarations(configFile.options)) {
const dts = getOutputDeclarationFileName(inputFileName, configFile, ignoreCase);
addOutput(dts);
if (configFile.options.declarationMap) {
@@ -248,7 +246,7 @@ namespace ts {
const jsFilePath = getOutputJSFileName(inputFileName, configFile, ignoreCase);
if (jsFilePath) return jsFilePath;
if (fileExtensionIs(inputFileName, Extension.Json)) continue;
if (getEmitDeclarations(configFile.options) && hasTSFileExtension(inputFileName)) {
if (getEmitDeclarations(configFile.options)) {
return getOutputDeclarationFileName(inputFileName, configFile, ignoreCase);
}
}
@@ -395,17 +393,16 @@ namespace ts {
declarationFilePath: string | undefined,
declarationMapPath: string | undefined,
relativeToBuildInfo: (path: string) => string) {
if (!sourceFileOrBundle || !(declarationFilePath && !isInJSFile(sourceFileOrBundle))) {
if (!sourceFileOrBundle || !declarationFilePath) {
return;
}
const sourceFiles = isSourceFile(sourceFileOrBundle) ? [sourceFileOrBundle] : sourceFileOrBundle.sourceFiles;
// Setup and perform the transformation to retrieve declarations from the input files
const nonJsFiles = filter(sourceFiles, isSourceFileNotJS);
const inputListOrBundle = (compilerOptions.outFile || compilerOptions.out) ? [createBundle(nonJsFiles, !isSourceFile(sourceFileOrBundle) ? sourceFileOrBundle.prepends : undefined)] : nonJsFiles;
const inputListOrBundle = (compilerOptions.outFile || compilerOptions.out) ? [createBundle(sourceFiles, !isSourceFile(sourceFileOrBundle) ? sourceFileOrBundle.prepends : undefined)] : sourceFiles;
if (emitOnlyDtsFiles && !getEmitDeclarations(compilerOptions)) {
// Checker wont collect the linked aliases since thats only done when declaration is enabled.
// Do that here when emitting only dts files
nonJsFiles.forEach(collectLinkedAliases);
sourceFiles.forEach(collectLinkedAliases);
}
const declarationTransform = transformNodes(resolver, host, compilerOptions, inputListOrBundle, declarationTransformers, /*allowDtsFiles*/ false);
if (length(declarationTransform.diagnostics)) {
@@ -659,6 +656,7 @@ namespace ts {
getAllAccessorDeclarations: notImplemented,
getSymbolOfExternalModuleSpecifier: notImplemented,
isBindingCapturedByNode: notImplemented,
getDeclarationStatementsForSourceFile: notImplemented,
};
/*@internal*/
+5
View File
@@ -2259,6 +2259,11 @@ namespace ts {
: node;
}
/* @internal */
export function createEmptyExports() {
return createExportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createNamedExports([]), /*moduleSpecifier*/ undefined);
}
export function createNamedExports(elements: readonly ExportSpecifier[]) {
const node = <NamedExports>createSynthesizedNode(SyntaxKind.NamedExports);
node.elements = createNodeArray(elements);
+4 -11
View File
@@ -856,7 +856,7 @@ namespace ts {
}
else if (getEmitModuleKind(parsedRef.commandLine.options) === ModuleKind.None) {
for (const fileName of parsedRef.commandLine.fileNames) {
if (!fileExtensionIs(fileName, Extension.Dts) && hasTSFileExtension(fileName)) {
if (!fileExtensionIs(fileName, Extension.Dts)) {
processSourceFile(getOutputDeclarationFileName(fileName, parsedRef.commandLine, !host.useCaseSensitiveFileNames()), /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
}
}
@@ -2448,8 +2448,8 @@ namespace ts {
}
function getProjectReferenceRedirectProject(fileName: string) {
// Ignore dts or any of the non ts files
if (!resolvedProjectReferences || !resolvedProjectReferences.length || fileExtensionIs(fileName, Extension.Dts) || !fileExtensionIsOneOf(fileName, supportedTSExtensions)) {
// Ignore dts
if (!resolvedProjectReferences || !resolvedProjectReferences.length || fileExtensionIs(fileName, Extension.Dts)) {
return undefined;
}
@@ -2510,7 +2510,7 @@ namespace ts {
}
else {
forEach(resolvedRef.commandLine.fileNames, fileName => {
if (!fileExtensionIs(fileName, Extension.Dts) && hasTSFileExtension(fileName)) {
if (!fileExtensionIs(fileName, Extension.Dts)) {
const outputDts = getOutputDeclarationFileName(fileName, resolvedRef.commandLine, host.useCaseSensitiveFileNames());
mapFromToProjectReferenceRedirectSource!.set(toPath(outputDts), fileName);
}
@@ -3077,10 +3077,6 @@ namespace ts {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_when_option_target_is_ES3, "useDefineForClassFields");
}
if (!options.noEmit && options.allowJs && getEmitDeclarations(options)) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", getEmitDeclarationOptionName(options));
}
if (options.checkJs && !options.allowJs) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "checkJs", "allowJs"));
}
@@ -3425,9 +3421,6 @@ namespace ts {
return resolveConfigFileProjectName(passedInRef.path);
}
function getEmitDeclarationOptionName(options: CompilerOptions) {
return options.declaration ? "declaration" : "composite";
}
/* @internal */
/**
* Returns a DiagnosticMessage if we won't include a resolved module due to its extension.
+30 -26
View File
@@ -1,11 +1,8 @@
/*@internal*/
namespace ts {
export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, file: SourceFile | undefined): DiagnosticWithLocation[] | undefined {
if (file && isSourceFileJS(file)) {
return []; // No declaration diagnostics for js for now
}
const compilerOptions = host.getCompilerOptions();
const result = transformNodes(resolver, host, compilerOptions, file ? [file] : filter(host.getSourceFiles(), isSourceFileNotJS), [transformDeclarations], /*allowDtsFiles*/ false);
const result = transformNodes(resolver, host, compilerOptions, file ? [file] : host.getSourceFiles(), [transformDeclarations], /*allowDtsFiles*/ false);
return result.diagnostics;
}
@@ -190,15 +187,24 @@ namespace ts {
}
}
function createEmptyExports() {
return createExportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createNamedExports([]), /*moduleSpecifier*/ undefined);
function transformDeclarationsForJS(sourceFile: SourceFile, bundled?: boolean) {
const oldDiag = getSymbolAccessibilityDiagnostic;
getSymbolAccessibilityDiagnostic = (s) => ({
diagnosticMessage: s.errorModuleName
? Diagnostics.Declaration_emit_for_this_file_requires_using_private_name_0_from_module_1_An_explicit_type_annotation_may_unblock_declaration_emit
: Diagnostics.Declaration_emit_for_this_file_requires_using_private_name_0_An_explicit_type_annotation_may_unblock_declaration_emit,
errorNode: s.errorNode || sourceFile
});
const result = resolver.getDeclarationStatementsForSourceFile(sourceFile, declarationEmitNodeBuilderFlags, symbolTracker, bundled);
getSymbolAccessibilityDiagnostic = oldDiag;
return result;
}
function transformRoot(node: Bundle): Bundle;
function transformRoot(node: SourceFile): SourceFile;
function transformRoot(node: SourceFile | Bundle): SourceFile | Bundle;
function transformRoot(node: SourceFile | Bundle) {
if (node.kind === SyntaxKind.SourceFile && (node.isDeclarationFile || isSourceFileJS(node))) {
if (node.kind === SyntaxKind.SourceFile && node.isDeclarationFile) {
return node;
}
@@ -209,7 +215,7 @@ namespace ts {
let hasNoDefaultLib = false;
const bundle = createBundle(map(node.sourceFiles,
sourceFile => {
if (sourceFile.isDeclarationFile || isSourceFileJS(sourceFile)) return undefined!; // Omit declaration files from bundle results, too // TODO: GH#18217
if (sourceFile.isDeclarationFile) return undefined!; // Omit declaration files from bundle results, too // TODO: GH#18217
hasNoDefaultLib = hasNoDefaultLib || sourceFile.hasNoDefaultLib;
currentSourceFile = sourceFile;
enclosingDeclaration = sourceFile;
@@ -221,10 +227,10 @@ namespace ts {
resultHasScopeMarker = false;
collectReferences(sourceFile, refs);
collectLibs(sourceFile, libs);
if (isExternalModule(sourceFile)) {
if (isExternalOrCommonJsModule(sourceFile) || isJsonSourceFile(sourceFile)) {
resultHasExternalModuleIndicator = false; // unused in external module bundle emit (all external modules are within module blocks, therefore are known to be modules)
needsDeclare = false;
const statements = visitNodes(sourceFile.statements, visitDeclarationStatements);
const statements = isSourceFileJS(sourceFile) ? createNodeArray(transformDeclarationsForJS(sourceFile, /*bundled*/ true)) : visitNodes(sourceFile.statements, visitDeclarationStatements);
const newFile = updateSourceFileNode(sourceFile, [createModuleDeclaration(
[],
[createModifier(SyntaxKind.DeclareKeyword)],
@@ -234,7 +240,7 @@ namespace ts {
return newFile;
}
needsDeclare = true;
const updated = visitNodes(sourceFile.statements, visitDeclarationStatements);
const updated = isSourceFileJS(sourceFile) ? createNodeArray(transformDeclarationsForJS(sourceFile)) : visitNodes(sourceFile.statements, visitDeclarationStatements);
return updateSourceFileNode(sourceFile, transformAndReplaceLatePaintedStatements(updated), /*isDeclarationFile*/ true, /*referencedFiles*/ [], /*typeReferences*/ [], /*hasNoDefaultLib*/ false, /*libReferences*/ []);
}
), mapDefined(node.prepends, prepend => {
@@ -276,12 +282,19 @@ namespace ts {
const references: FileReference[] = [];
const outputFilePath = getDirectoryPath(normalizeSlashes(getOutputPathsFor(node, host, /*forceDtsPaths*/ true).declarationFilePath!));
const referenceVisitor = mapReferencesIntoArray(references, outputFilePath);
const statements = visitNodes(node.statements, visitDeclarationStatements);
let combinedStatements = setTextRange(createNodeArray(transformAndReplaceLatePaintedStatements(statements)), node.statements);
refs.forEach(referenceVisitor);
emittedImports = filter(combinedStatements, isAnyImportSyntax);
if (isExternalModule(node) && (!resultHasExternalModuleIndicator || (needsScopeFixMarker && !resultHasScopeMarker))) {
combinedStatements = setTextRange(createNodeArray([...combinedStatements, createEmptyExports()]), combinedStatements);
let combinedStatements: NodeArray<Statement>;
if (isSourceFileJS(currentSourceFile)) {
combinedStatements = createNodeArray(transformDeclarationsForJS(node));
emittedImports = filter(combinedStatements, isAnyImportSyntax);
}
else {
const statements = visitNodes(node.statements, visitDeclarationStatements);
combinedStatements = setTextRange(createNodeArray(transformAndReplaceLatePaintedStatements(statements)), node.statements);
refs.forEach(referenceVisitor);
emittedImports = filter(combinedStatements, isAnyImportSyntax);
if (isExternalModule(node) && (!resultHasExternalModuleIndicator || (needsScopeFixMarker && !resultHasScopeMarker))) {
combinedStatements = setTextRange(createNodeArray([...combinedStatements, createEmptyExports()]), combinedStatements);
}
}
const updated = updateSourceFileNode(node, combinedStatements, /*isDeclarationFile*/ true, references, getFileReferencesForUsedTypeReferences(), node.hasNoDefaultLib, getLibReferences());
updated.exportedModulesFromDeclarationEmit = exportedModulesFromDeclarationEmit;
@@ -755,15 +768,6 @@ namespace ts {
}
}
function isExternalModuleIndicator(result: LateVisibilityPaintedStatement | ExportAssignment) {
// Exported top-level member indicates moduleness
return isAnyImportOrReExport(result) || isExportAssignment(result) || hasModifier(result, ModifierFlags.Export);
}
function needsScopeMarker(result: LateVisibilityPaintedStatement | ExportAssignment) {
return !isAnyImportOrReExport(result) && !isExportAssignment(result) && !hasModifier(result, ModifierFlags.Export) && !isAmbientModule(result);
}
function visitDeclarationSubtree(input: Node): VisitResult<Node> {
if (shouldStripInternal(input)) return;
if (isDeclaration(input)) {
+9 -1
View File
@@ -3734,6 +3734,7 @@ namespace ts {
getAllAccessorDeclarations(declaration: AccessorDeclaration): AllAccessorDeclarations;
getSymbolOfExternalModuleSpecifier(node: StringLiteralLike): Symbol | undefined;
isBindingCapturedByNode(node: Node, decl: VariableDeclaration | BindingElement): boolean;
getDeclarationStatementsForSourceFile(node: SourceFile, flags: NodeBuilderFlags, tracker: SymbolTracker, bundled?: boolean): Statement[] | undefined;
}
export const enum SymbolFlags {
@@ -3814,6 +3815,12 @@ namespace ts {
ClassMember = Method | Accessor | Property,
/* @internal */
ExportSupportsDefaultModifier = Class | Function | Interface,
/* @internal */
ExportDoesNotSupportDefaultModifier = ~ExportSupportsDefaultModifier,
/* @internal */
// The set of things we consider semantically classifiable. Used to speed up the LS during
// classification.
@@ -3877,6 +3884,7 @@ namespace ts {
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
cjsExportMerged?: Symbol; // Version of the symbol with all non export= exports merged with the export= target
}
/* @internal */
@@ -6024,7 +6032,7 @@ namespace ts {
// Called when the symbol writer encounters a symbol to write. Currently only used by the
// declaration emitter to help determine if it should patch up the final declaration file
// with import statements it previously saw (but chose not to emit).
trackSymbol?(symbol: Symbol, enclosingDeclaration?: Node, meaning?: SymbolFlags): void;
trackSymbol?(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags): void;
reportInaccessibleThisError?(): void;
reportPrivateInBaseOfClassExpression?(propertyName: string): void;
reportInaccessibleUniqueSymbolError?(): void;
+68 -7
View File
@@ -2606,6 +2606,8 @@ namespace ts {
// export = <EntityNameExpression>
// export default <EntityNameExpression>
// module.exports = <EntityNameExpression>
// {<Identifier>}
// {name: <EntityNameExpression>}
export function isAliasSymbolDeclaration(node: Node): boolean {
return node.kind === SyntaxKind.ImportEqualsDeclaration ||
node.kind === SyntaxKind.NamespaceExportDeclaration ||
@@ -2614,12 +2616,28 @@ namespace ts {
node.kind === SyntaxKind.ImportSpecifier ||
node.kind === SyntaxKind.ExportSpecifier ||
node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(<ExportAssignment>node) ||
isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports && exportAssignmentIsAlias(node);
isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports && exportAssignmentIsAlias(node) ||
isPropertyAccessExpression(node) && isBinaryExpression(node.parent) && node.parent.left === node && node.parent.operatorToken.kind === SyntaxKind.EqualsToken && isAliasableExpression(node.parent.right) ||
node.kind === SyntaxKind.ShorthandPropertyAssignment ||
node.kind === SyntaxKind.PropertyAssignment && isAliasableExpression((node as PropertyAssignment).initializer);
}
function isAliasableExpression(e: Expression) {
return isEntityNameExpression(e) || isClassExpression(e);
}
export function exportAssignmentIsAlias(node: ExportAssignment | BinaryExpression): boolean {
const e = isExportAssignment(node) ? node.expression : node.right;
return isEntityNameExpression(e) || isClassExpression(e);
const e = getExportAssignmentExpression(node);
return isAliasableExpression(e);
}
export function getExportAssignmentExpression(node: ExportAssignment | BinaryExpression): Expression {
return isExportAssignment(node) ? node.expression : node.right;
}
export function getPropertyAssignmentAliasLikeExpression(node: PropertyAssignment | ShorthandPropertyAssignment | PropertyAccessExpression): Expression {
return node.kind === SyntaxKind.ShorthandPropertyAssignment ? node.name : node.kind === SyntaxKind.PropertyAssignment ? node.initializer :
(node.parent as BinaryExpression).right;
}
export function getEffectiveBaseTypeNode(node: ClassLikeDeclaration | InterfaceDeclaration) {
@@ -2699,6 +2717,11 @@ namespace ts {
return token !== undefined && isNonContextualKeyword(token);
}
export function isStringAKeyword(name: string) {
const token = stringToToken(name);
return token !== undefined && isKeyword(token);
}
export function isIdentifierANonContextualKeyword({ originalKeywordKind }: Identifier): boolean {
return !!originalKeywordKind && !isContextualKeyword(originalKeywordKind);
}
@@ -3450,11 +3473,17 @@ namespace ts {
};
}
export function getResolvedExternalModuleName(host: EmitHost, file: SourceFile, referenceFile?: SourceFile): string {
export interface ResolveModuleNameResolutionHost {
getCanonicalFileName(p: string): string;
getCommonSourceDirectory(): string;
getCurrentDirectory(): string;
}
export function getResolvedExternalModuleName(host: ResolveModuleNameResolutionHost, file: SourceFile, referenceFile?: SourceFile): string {
return file.moduleName || getExternalModuleNameFromPath(host, file.fileName, referenceFile && referenceFile.fileName);
}
export function getExternalModuleNameFromDeclaration(host: EmitHost, resolver: EmitResolver, declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode): string | undefined {
export function getExternalModuleNameFromDeclaration(host: ResolveModuleNameResolutionHost, resolver: EmitResolver, declaration: ImportEqualsDeclaration | ImportDeclaration | ExportDeclaration | ModuleDeclaration | ImportTypeNode): string | undefined {
const file = resolver.getExternalModuleFileFromDeclaration(declaration);
if (!file || file.isDeclarationFile) {
return undefined;
@@ -3465,7 +3494,7 @@ namespace ts {
/**
* Resolves a local path to a path which is absolute to the base of the emit
*/
export function getExternalModuleNameFromPath(host: EmitHost, fileName: string, referencePath?: string): string {
export function getExternalModuleNameFromPath(host: ResolveModuleNameResolutionHost, fileName: string, referencePath?: string): string {
const getCanonicalFileName = (f: string) => host.getCanonicalFileName(f);
const dir = toPath(referencePath ? getDirectoryPath(referencePath) : host.getCommonSourceDirectory(), host.getCurrentDirectory(), getCanonicalFileName);
const filePath = getNormalizedAbsolutePath(fileName, host.getCurrentDirectory());
@@ -5224,6 +5253,17 @@ namespace ts {
return name && isIdentifier(name) ? name : undefined;
}
/** @internal */
export function nodeHasName(statement: Node, name: Identifier) {
if (isNamedDeclaration(statement) && isIdentifier(statement.name) && idText(statement.name as Identifier) === idText(name)) {
return true;
}
if (isVariableStatement(statement) && some(statement.declarationList.declarations, d => nodeHasName(d, name))) {
return true;
}
return false;
}
export function getNameOfJSDocTypedef(declaration: JSDocTypedefTag): Identifier | undefined {
return declaration.name || nameForNamelessJSDocTypedef(declaration);
}
@@ -6145,7 +6185,7 @@ namespace ts {
return node.kind === SyntaxKind.JSDocTypeExpression;
}
export function isJSDocAllType(node: JSDocAllType): node is JSDocAllType {
export function isJSDocAllType(node: Node): node is JSDocAllType {
return node.kind === SyntaxKind.JSDocAllType;
}
@@ -6762,6 +6802,27 @@ namespace ts {
return false;
}
/* @internal */
export function isScopeMarker(node: Node) {
return isExportAssignment(node) || isExportDeclaration(node);
}
/* @internal */
export function hasScopeMarker(statements: readonly Statement[]) {
return some(statements, isScopeMarker);
}
/* @internal */
export function needsScopeMarker(result: Statement) {
return !isAnyImportOrReExport(result) && !isExportAssignment(result) && !hasModifier(result, ModifierFlags.Export) && !isAmbientModule(result);
}
/* @internal */
export function isExternalModuleIndicator(result: Statement) {
// Exported top-level member indicates moduleness
return isAnyImportOrReExport(result) || isExportAssignment(result) || hasModifier(result, ModifierFlags.Export);
}
/* @internal */
export function isForInOrOfStatement(node: Node): node is ForInOrOfStatement {
return node.kind === SyntaxKind.ForInStatement || node.kind === SyntaxKind.ForOfStatement;
+13 -8
View File
@@ -219,14 +219,19 @@ namespace compiler {
return vpath.changeExtension(path, ext);
}
public getNumberOfJsFiles() {
let count = this.js.size;
this.js.forEach(document => {
if (ts.fileExtensionIs(document.file, ts.Extension.Json)) {
count--;
}
});
return count;
public getNumberOfJsFiles(includeJson: boolean) {
if (includeJson) {
return this.js.size;
}
else {
let count = this.js.size;
this.js.forEach(document => {
if (ts.fileExtensionIs(document.file, ts.Extension.Json)) {
count--;
}
});
return count;
}
}
}
+3 -3
View File
@@ -888,7 +888,7 @@ namespace Harness {
throw new Error("Only declaration files should be generated when emitDeclarationOnly:true");
}
}
else if (result.dts.size !== result.getNumberOfJsFiles()) {
else if (result.dts.size !== result.getNumberOfJsFiles(/*includeJson*/ true)) {
throw new Error("There were no errors and declFiles generated did not match number of js files generated");
}
}
@@ -907,7 +907,7 @@ namespace Harness {
if (vpath.isDeclaration(file.unitName) || vpath.isJson(file.unitName)) {
dtsFiles.push(file);
}
else if (vpath.isTypeScript(file.unitName)) {
else if (vpath.isTypeScript(file.unitName) || (vpath.isJavaScript(file.unitName) && options.allowJs)) {
const declFile = findResultCodeFile(file.unitName);
if (declFile && !findUnit(declFile.file, declInputFiles) && !findUnit(declFile.file, declOtherFiles)) {
dtsFiles.push({ unitName: declFile.file, content: utils.removeByteOrderMark(declFile.text) });
@@ -1269,7 +1269,7 @@ namespace Harness {
return;
}
else if (options.sourceMap || declMaps) {
if (result.maps.size !== (result.getNumberOfJsFiles() * (declMaps && options.sourceMap ? 2 : 1))) {
if (result.maps.size !== ((options.sourceMap ? result.getNumberOfJsFiles(/*includeJson*/ false) : 0) + (declMaps ? result.getNumberOfJsFiles(/*includeJson*/ true) : 0))) {
throw new Error("Number of sourcemap files should be same as js files.");
}
+1 -2
View File
@@ -1971,8 +1971,7 @@ namespace ts {
const notAccessible = () => { typeIsAccessible = false; };
const res = checker.typeToTypeNode(type, enclosingScope, /*flags*/ undefined, {
trackSymbol: (symbol, declaration, meaning) => {
// TODO: GH#18217
typeIsAccessible = typeIsAccessible && checker.isSymbolAccessible(symbol, declaration, meaning!, /*shouldComputeAliasToMarkVisible*/ false).accessibility === SymbolAccessibility.Accessible;
typeIsAccessible = typeIsAccessible && checker.isSymbolAccessible(symbol, declaration, meaning, /*shouldComputeAliasToMarkVisible*/ false).accessibility === SymbolAccessibility.Accessible;
},
reportInaccessibleThisError: notAccessible,
reportPrivateInBaseOfClassExpression: notAccessible,
+1
View File
@@ -99,6 +99,7 @@
"unittests/tsbuild/emptyFiles.ts",
"unittests/tsbuild/graphOrdering.ts",
"unittests/tsbuild/inferredTypeFromTransitiveModule.ts",
"unittests/tsbuild/javascriptProjectEmit.ts",
"unittests/tsbuild/lateBoundSymbol.ts",
"unittests/tsbuild/missingExtendedFile.ts",
"unittests/tsbuild/moduleSpecifiers.ts",
@@ -0,0 +1,286 @@
namespace ts {
describe("unittests:: tsbuild:: javascriptProjectEmit:: loads js-based projects and emits them correctly", () => {
verifyTsc({
scenario: "javascriptProjectEmit",
subScenario: `loads js-based projects and emits them correctly`,
fs: () => loadProjectFromFiles({
"/src/common/nominal.js": utils.dedent`
/**
* @template T, Name
* @typedef {T & {[Symbol.species]: Name}} Nominal
*/
module.exports = {};
`,
"/src/common/tsconfig.json": utils.dedent`
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"composite": true
},
"include": ["nominal.js"]
}`,
"/src/sub-project/index.js": utils.dedent`
import { Nominal } from '../common/nominal';
/**
* @typedef {Nominal<string, 'MyNominal'>} MyNominal
*/
`,
"/src/sub-project/tsconfig.json": utils.dedent`
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"composite": true
},
"references": [
{ "path": "../common" }
],
"include": ["./index.js"]
}`,
"/src/sub-project-2/index.js": utils.dedent`
import { MyNominal } from '../sub-project/index';
const variable = {
key: /** @type {MyNominal} */('value'),
};
/**
* @return {keyof typeof variable}
*/
export function getVar() {
return 'key';
}
`,
"/src/sub-project-2/tsconfig.json": utils.dedent`
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"composite": true
},
"references": [
{ "path": "../sub-project" }
],
"include": ["./index.js"]
}`,
"/src/tsconfig.json": utils.dedent`
{
"compilerOptions": {
"composite": true
},
"references": [
{ "path": "./sub-project" },
{ "path": "./sub-project-2" }
],
"include": []
}`,
"/src/tsconfig.base.json": utils.dedent`
{
"compilerOptions": {
"skipLibCheck": true,
"rootDir": "./",
"outDir": "../lib",
"allowJs": true,
"checkJs": true,
"declaration": true
}
}`,
}, symbolLibContent),
commandLineArgs: ["-b", "/src"]
});
});
describe("unittests:: tsbuild:: javascriptProjectEmit:: loads outfile js projects and concatenates them correctly", () => {
let projFs: vfs.FileSystem;
before(() => {
projFs = loadProjectFromFiles({
"/src/common/nominal.js": utils.dedent`
/**
* @template T, Name
* @typedef {T & {[Symbol.species]: Name}} Nominal
*/
`,
"/src/common/tsconfig.json": utils.dedent`
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"composite": true,
"outFile": "common.js"
},
"include": ["nominal.js"]
}`,
"/src/sub-project/index.js": utils.dedent`
/**
* @typedef {Nominal<string, 'MyNominal'>} MyNominal
*/
const c = /** @type {*} */(null);
`,
"/src/sub-project/tsconfig.json": utils.dedent`
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"composite": true,
"outFile": "sub-project.js"
},
"references": [
{ "path": "../common", "prepend": true }
],
"include": ["./index.js"]
}`,
"/src/sub-project-2/index.js": utils.dedent`
const variable = {
key: /** @type {MyNominal} */('value'),
};
/**
* @return {keyof typeof variable}
*/
function getVar() {
return 'key';
}
`,
"/src/sub-project-2/tsconfig.json": utils.dedent`
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"composite": true,
"outFile": "sub-project-2.js"
},
"references": [
{ "path": "../sub-project", "prepend": true }
],
"include": ["./index.js"]
}`,
"/src/tsconfig.json": utils.dedent`
{
"compilerOptions": {
"composite": true,
"outFile": "src.js"
},
"references": [
{ "path": "./sub-project", "prepend": true },
{ "path": "./sub-project-2", "prepend": true }
],
"include": []
}`,
"/src/tsconfig.base.json": utils.dedent`
{
"compilerOptions": {
"skipLibCheck": true,
"rootDir": "./",
"allowJs": true,
"checkJs": true,
"declaration": true
}
}`,
}, symbolLibContent);
});
after(() => {
projFs = undefined!;
});
verifyTsc({
scenario: "javascriptProjectEmit",
subScenario: `loads outfile js projects and concatenates them correctly`,
fs: () => projFs,
commandLineArgs: ["-b", "/src"]
});
verifyTscIncrementalEdits({
scenario: "javascriptProjectEmit",
subScenario: `modifies outfile js projects and concatenates them correctly`,
fs: () => projFs,
commandLineArgs: ["-b", "/src"],
incrementalScenarios: [{
buildKind: BuildKind.IncrementalDtsUnchanged,
modifyFs: fs => replaceText(fs, "/src/sub-project/index.js", "null", "undefined")
}]
});
});
describe("unittests:: tsbuild:: javascriptProjectEmit:: loads js-based projects with non-moved json files and emits them correctly", () => {
verifyTsc({
scenario: "javascriptProjectEmit",
subScenario: `loads js-based projects with non-moved json files and emits them correctly`,
fs: () => loadProjectFromFiles({
"/src/common/obj.json": utils.dedent`
{
"val": 42
}`,
"/src/common/index.ts": utils.dedent`
import x = require("./obj.json");
export = x;
`,
"/src/common/tsconfig.json": utils.dedent`
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"outDir": null
"composite": true
},
"include": ["index.ts", "obj.json"]
}`,
"/src/sub-project/index.js": utils.dedent`
import mod from '../common';
export const m = mod;
`,
"/src/sub-project/tsconfig.json": utils.dedent`
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"composite": true
},
"references": [
{ "path": "../common" }
],
"include": ["./index.js"]
}`,
"/src/sub-project-2/index.js": utils.dedent`
import { m } from '../sub-project/index';
const variable = {
key: m,
};
export function getVar() {
return variable;
}
`,
"/src/sub-project-2/tsconfig.json": utils.dedent`
{
"extends": "../tsconfig.base.json",
"compilerOptions": {
"composite": true
},
"references": [
{ "path": "../sub-project" }
],
"include": ["./index.js"]
}`,
"/src/tsconfig.json": utils.dedent`
{
"compilerOptions": {
"composite": true
},
"references": [
{ "path": "./sub-project" },
{ "path": "./sub-project-2" }
],
"include": []
}`,
"/src/tsconfig.base.json": utils.dedent`
{
"compilerOptions": {
"skipLibCheck": true,
"rootDir": "./",
"outDir": "../out",
"allowJs": true,
"checkJs": true,
"resolveJsonModule": true,
"esModuleInterop": true,
"declaration": true
}
}`,
}, symbolLibContent),
commandLineArgs: ["-b", "/src"]
});
});
}
@@ -52,7 +52,12 @@ namespace ts {
export default hello.hello`);
const allExpectedOutputs = ["/src/dist/src/index.js", "/src/dist/src/index.d.ts", "/src/dist/src/index.json"];
verifyProjectWithResolveJsonModuleWithFs(fs, "/src/tsconfig_withIncludeOfJson.json", allExpectedOutputs);
verifyProjectWithResolveJsonModuleWithFs(
fs,
"/src/tsconfig_withIncludeOfJson.json",
allExpectedOutputs,
errorDiagnostic([Diagnostics.Cannot_write_file_0_because_it_would_be_overwritten_by_multiple_input_files, "/src/dist/src/index.d.ts"])
);
});
it("with resolveJsonModule and files containing json file", () => {
@@ -885,8 +885,8 @@ namespace ts.tscWatch {
// More comment`;
const configFileContentAfterComment = `
"compilerOptions": {
"allowJs": true,
"declaration": true
"inlineSourceMap": true,
"mapRoot": "./"
}
}`;
const configFileContentWithComment = configFileContentBeforeComment + configFileContentComment + configFileContentAfterComment;
@@ -900,8 +900,9 @@ namespace ts.tscWatch {
const host = createWatchedSystem(files);
const watch = createWatchOfConfigFile(configFile.path, host);
const errors = () => [
getDiagnosticOfFile(watch().getCompilerOptions().configFile!, configFile.content.indexOf('"allowJs"'), '"allowJs"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration"),
getDiagnosticOfFile(watch().getCompilerOptions().configFile!, configFile.content.indexOf('"declaration"'), '"declaration"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration")
getDiagnosticOfFile(watch().getCompilerOptions().configFile!, configFile.content.indexOf('"inlineSourceMap"'), '"inlineSourceMap"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "mapRoot", "inlineSourceMap"),
getDiagnosticOfFile(watch().getCompilerOptions().configFile!, configFile.content.indexOf('"mapRoot"'), '"mapRoot"'.length, Diagnostics.Option_0_cannot_be_specified_with_option_1, "mapRoot", "inlineSourceMap"),
getDiagnosticOfFile(watch().getCompilerOptions().configFile!, configFile.content.indexOf('"mapRoot"'), '"mapRoot"'.length, Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "mapRoot", "sourceMap", "declarationMap")
];
const intialErrors = errors();
checkOutputErrorsInitial(host, intialErrors);
@@ -849,8 +849,8 @@ declare module '@custom/plugin' {
// comment`;
const configFileContentAfterComment = `
"compilerOptions": {
"allowJs": true,
"declaration": true
"inlineSourceMap": true,
"mapRoot": "./"
}
}`;
const configFileContentWithComment = configFileContentBeforeComment + configFileContentComment + configFileContentAfterComment;
@@ -874,7 +874,7 @@ declare module '@custom/plugin' {
seq: 2,
arguments: { file: configFile.path, projectFileName: projectName, includeLinePosition: true }
}).response as readonly server.protocol.DiagnosticWithLinePosition[];
assert.isTrue(diags.length === 2);
assert.isTrue(diags.length === 3);
configFile.content = configFileContentWithoutCommentLine;
host.reloadFS([file, configFile]);
@@ -885,10 +885,11 @@ declare module '@custom/plugin' {
seq: 2,
arguments: { file: configFile.path, projectFileName: projectName, includeLinePosition: true }
}).response as readonly server.protocol.DiagnosticWithLinePosition[];
assert.isTrue(diagsAfterEdit.length === 2);
assert.isTrue(diagsAfterEdit.length === 3);
verifyDiagnostic(diags[0], diagsAfterEdit[0]);
verifyDiagnostic(diags[1], diagsAfterEdit[1]);
verifyDiagnostic(diags[2], diagsAfterEdit[2]);
function verifyDiagnostic(beforeEditDiag: server.protocol.DiagnosticWithLinePosition, afterEditDiag: server.protocol.DiagnosticWithLinePosition) {
assert.equal(beforeEditDiag.message, afterEditDiag.message);