Merge branch 'master' into nested-excess-property-checking-for-discriminated-unions

This commit is contained in:
Nathan Shively-Sanders
2018-01-25 15:32:53 -08:00
280 changed files with 6303 additions and 2539 deletions
+530 -460
View File
File diff suppressed because it is too large Load Diff
+384
View File
@@ -0,0 +1,384 @@
/// <reference path="program.ts" />
namespace ts {
export interface EmitOutput {
outputFiles: OutputFile[];
emitSkipped: boolean;
}
export interface OutputFile {
name: string;
writeByteOrderMark: boolean;
text: string;
}
}
/*@internal*/
namespace ts {
export function getFileEmitOutput(program: Program, sourceFile: SourceFile, emitOnlyDtsFiles: boolean,
cancellationToken?: CancellationToken, customTransformers?: CustomTransformers): EmitOutput {
const outputFiles: OutputFile[] = [];
const emitResult = program.emit(sourceFile, writeFile, cancellationToken, emitOnlyDtsFiles, customTransformers);
return { outputFiles, emitSkipped: emitResult.emitSkipped };
function writeFile(fileName: string, text: string, writeByteOrderMark: boolean) {
outputFiles.push({ name: fileName, writeByteOrderMark, text });
}
}
export interface BuilderState {
/**
* Information of the file eg. its version, signature etc
*/
fileInfos: Map<BuilderState.FileInfo>;
/**
* Contains the map of ReferencedSet=Referenced files of the file if module emit is enabled
* Otherwise undefined
* Thus non undefined value indicates, module emit
*/
readonly referencedMap: ReadonlyMap<BuilderState.ReferencedSet> | undefined;
/**
* Map of files that have already called update signature.
* That means hence forth these files are assumed to have
* no change in their signature for this version of the program
*/
hasCalledUpdateShapeSignature: Map<true>;
/**
* Cache of all files excluding default library file for the current program
*/
allFilesExcludingDefaultLibraryFile: ReadonlyArray<SourceFile> | undefined;
/**
* Cache of all the file names
*/
allFileNames: ReadonlyArray<string> | undefined;
}
}
/*@internal*/
namespace ts.BuilderState {
/**
* Information about the source file: Its version and optional signature from last emit
*/
export interface FileInfo {
readonly version: string;
signature: string | undefined;
}
/**
* Referenced files with values for the keys as referenced file's path to be true
*/
export type ReferencedSet = ReadonlyMap<true>;
/**
* Compute the hash to store the shape of the file
*/
export type ComputeHash = (data: string) => string;
/**
* Gets the referenced files for a file from the program with values for the keys as referenced file's path to be true
*/
function getReferencedFiles(program: Program, sourceFile: SourceFile, getCanonicalFileName: GetCanonicalFileName): Map<true> | undefined {
let referencedFiles: Map<true> | undefined;
// We need to use a set here since the code can contain the same import twice,
// but that will only be one dependency.
// To avoid invernal conversion, the key of the referencedFiles map must be of type Path
if (sourceFile.imports && sourceFile.imports.length > 0) {
const checker: TypeChecker = program.getTypeChecker();
for (const importName of sourceFile.imports) {
const symbol = checker.getSymbolAtLocation(importName);
if (symbol && symbol.declarations && symbol.declarations[0]) {
const declarationSourceFile = getSourceFileOfNode(symbol.declarations[0]);
if (declarationSourceFile) {
addReferencedFile(declarationSourceFile.path);
}
}
}
}
const sourceFileDirectory = getDirectoryPath(sourceFile.path);
// Handle triple slash references
if (sourceFile.referencedFiles && sourceFile.referencedFiles.length > 0) {
for (const referencedFile of sourceFile.referencedFiles) {
const referencedPath = toPath(referencedFile.fileName, sourceFileDirectory, getCanonicalFileName);
addReferencedFile(referencedPath);
}
}
// Handle type reference directives
if (sourceFile.resolvedTypeReferenceDirectiveNames) {
sourceFile.resolvedTypeReferenceDirectiveNames.forEach((resolvedTypeReferenceDirective) => {
if (!resolvedTypeReferenceDirective) {
return;
}
const fileName = resolvedTypeReferenceDirective.resolvedFileName;
const typeFilePath = toPath(fileName, sourceFileDirectory, getCanonicalFileName);
addReferencedFile(typeFilePath);
});
}
return referencedFiles;
function addReferencedFile(referencedPath: Path) {
if (!referencedFiles) {
referencedFiles = createMap<true>();
}
referencedFiles.set(referencedPath, true);
}
}
/**
* Returns true if oldState is reusable, that is the emitKind = module/non module has not changed
*/
export function canReuseOldState(newReferencedMap: ReadonlyMap<ReferencedSet>, oldState: Readonly<BuilderState> | undefined) {
return oldState && !oldState.referencedMap === !newReferencedMap;
}
/**
* Creates the state of file references and signature for the new program from oldState if it is safe
*/
export function create(newProgram: Program, getCanonicalFileName: GetCanonicalFileName, oldState?: Readonly<BuilderState>): BuilderState {
const fileInfos = createMap<FileInfo>();
const referencedMap = newProgram.getCompilerOptions().module !== ModuleKind.None ? createMap<ReferencedSet>() : undefined;
const hasCalledUpdateShapeSignature = createMap<true>();
const useOldState = canReuseOldState(referencedMap, oldState);
// Create the reference map, and set the file infos
for (const sourceFile of newProgram.getSourceFiles()) {
const version = sourceFile.version;
const oldInfo = useOldState && oldState.fileInfos.get(sourceFile.path);
if (referencedMap) {
const newReferences = getReferencedFiles(newProgram, sourceFile, getCanonicalFileName);
if (newReferences) {
referencedMap.set(sourceFile.path, newReferences);
}
}
fileInfos.set(sourceFile.path, { version, signature: oldInfo && oldInfo.signature });
}
return {
fileInfos,
referencedMap,
hasCalledUpdateShapeSignature,
allFilesExcludingDefaultLibraryFile: undefined,
allFileNames: undefined
};
}
/**
* Gets the files affected by the path from the program
*/
export function getFilesAffectedBy(state: BuilderState, programOfThisState: Program, path: Path, cancellationToken: CancellationToken | undefined, computeHash: ComputeHash, cacheToUpdateSignature?: Map<string>): ReadonlyArray<SourceFile> {
// Since the operation could be cancelled, the signatures are always stored in the cache
// They will be commited once it is safe to use them
// eg when calling this api from tsserver, if there is no cancellation of the operation
// In the other cases the affected files signatures are commited only after the iteration through the result is complete
const signatureCache = cacheToUpdateSignature || createMap();
const sourceFile = programOfThisState.getSourceFileByPath(path);
if (!sourceFile) {
return emptyArray;
}
if (!updateShapeSignature(state, programOfThisState, sourceFile, signatureCache, cancellationToken, computeHash)) {
return [sourceFile];
}
const result = (state.referencedMap ? getFilesAffectedByUpdatedShapeWhenModuleEmit : getFilesAffectedByUpdatedShapeWhenNonModuleEmit)(state, programOfThisState, sourceFile, signatureCache, cancellationToken, computeHash);
if (!cacheToUpdateSignature) {
// Commit all the signatures in the signature cache
updateSignaturesFromCache(state, signatureCache);
}
return result;
}
/**
* Updates the signatures from the cache into state's fileinfo signatures
* This should be called whenever it is safe to commit the state of the builder
*/
export function updateSignaturesFromCache(state: BuilderState, signatureCache: Map<string>) {
signatureCache.forEach((signature, path) => {
state.fileInfos.get(path).signature = signature;
state.hasCalledUpdateShapeSignature.set(path, true);
});
}
/**
* Returns if the shape of the signature has changed since last emit
*/
function updateShapeSignature(state: Readonly<BuilderState>, programOfThisState: Program, sourceFile: SourceFile, cacheToUpdateSignature: Map<string>, cancellationToken: CancellationToken | undefined, computeHash: ComputeHash) {
Debug.assert(!!sourceFile);
// If we have cached the result for this file, that means hence forth we should assume file shape is uptodate
if (state.hasCalledUpdateShapeSignature.has(sourceFile.path) || cacheToUpdateSignature.has(sourceFile.path)) {
return false;
}
const info = state.fileInfos.get(sourceFile.path);
Debug.assert(!!info);
const prevSignature = info.signature;
let latestSignature: string;
if (sourceFile.isDeclarationFile) {
latestSignature = sourceFile.version;
}
else {
const emitOutput = getFileEmitOutput(programOfThisState, sourceFile, /*emitOnlyDtsFiles*/ true, cancellationToken);
if (emitOutput.outputFiles && emitOutput.outputFiles.length > 0) {
latestSignature = computeHash(emitOutput.outputFiles[0].text);
}
else {
latestSignature = prevSignature;
}
}
cacheToUpdateSignature.set(sourceFile.path, latestSignature);
return !prevSignature || latestSignature !== prevSignature;
}
/**
* Get all the dependencies of the sourceFile
*/
export function getAllDependencies(state: BuilderState, programOfThisState: Program, sourceFile: SourceFile): ReadonlyArray<string> {
const compilerOptions = programOfThisState.getCompilerOptions();
// With --out or --outFile all outputs go into single file, all files depend on each other
if (compilerOptions.outFile || compilerOptions.out) {
return getAllFileNames(state, programOfThisState);
}
// If this is non module emit, or its a global file, it depends on all the source files
if (!state.referencedMap || (!isExternalModule(sourceFile) && !containsOnlyAmbientModules(sourceFile))) {
return getAllFileNames(state, programOfThisState);
}
// Get the references, traversing deep from the referenceMap
const seenMap = createMap<true>();
const queue = [sourceFile.path];
while (queue.length) {
const path = queue.pop();
if (!seenMap.has(path)) {
seenMap.set(path, true);
const references = state.referencedMap.get(path);
if (references) {
const iterator = references.keys();
for (let { value, done } = iterator.next(); !done; { value, done } = iterator.next()) {
queue.push(value as Path);
}
}
}
}
return arrayFrom(mapDefinedIterator(seenMap.keys(), path => {
const file = programOfThisState.getSourceFileByPath(path as Path);
return file ? file.fileName : path;
}));
}
/**
* Gets the names of all files from the program
*/
function getAllFileNames(state: BuilderState, programOfThisState: Program): ReadonlyArray<string> {
if (!state.allFileNames) {
const sourceFiles = programOfThisState.getSourceFiles();
state.allFileNames = sourceFiles === emptyArray ? emptyArray : sourceFiles.map(file => file.fileName);
}
return state.allFileNames;
}
/**
* Gets the files referenced by the the file path
*/
function getReferencedByPaths(state: Readonly<BuilderState>, referencedFilePath: Path) {
return arrayFrom(mapDefinedIterator(state.referencedMap.entries(), ([filePath, referencesInFile]) =>
referencesInFile.has(referencedFilePath) ? filePath as Path : undefined
));
}
/**
* For script files that contains only ambient external modules, although they are not actually external module files,
* they can only be consumed via importing elements from them. Regular script files cannot consume them. Therefore,
* there are no point to rebuild all script files if these special files have changed. However, if any statement
* in the file is not ambient external module, we treat it as a regular script file.
*/
function containsOnlyAmbientModules(sourceFile: SourceFile) {
for (const statement of sourceFile.statements) {
if (!isModuleWithStringLiteralName(statement)) {
return false;
}
}
return true;
}
/**
* Gets all files of the program excluding the default library file
*/
function getAllFilesExcludingDefaultLibraryFile(state: BuilderState, programOfThisState: Program, firstSourceFile: SourceFile): ReadonlyArray<SourceFile> {
// Use cached result
if (state.allFilesExcludingDefaultLibraryFile) {
return state.allFilesExcludingDefaultLibraryFile;
}
let result: SourceFile[];
addSourceFile(firstSourceFile);
for (const sourceFile of programOfThisState.getSourceFiles()) {
if (sourceFile !== firstSourceFile) {
addSourceFile(sourceFile);
}
}
state.allFilesExcludingDefaultLibraryFile = result || emptyArray;
return state.allFilesExcludingDefaultLibraryFile;
function addSourceFile(sourceFile: SourceFile) {
if (!programOfThisState.isSourceFileDefaultLibrary(sourceFile)) {
(result || (result = [])).push(sourceFile);
}
}
}
/**
* When program emits non modular code, gets the files affected by the sourceFile whose shape has changed
*/
function getFilesAffectedByUpdatedShapeWhenNonModuleEmit(state: BuilderState, programOfThisState: Program, sourceFileWithUpdatedShape: SourceFile) {
const compilerOptions = programOfThisState.getCompilerOptions();
// If `--out` or `--outFile` is specified, any new emit will result in re-emitting the entire project,
// so returning the file itself is good enough.
if (compilerOptions && (compilerOptions.out || compilerOptions.outFile)) {
return [sourceFileWithUpdatedShape];
}
return getAllFilesExcludingDefaultLibraryFile(state, programOfThisState, sourceFileWithUpdatedShape);
}
/**
* When program emits modular code, gets the files affected by the sourceFile whose shape has changed
*/
function getFilesAffectedByUpdatedShapeWhenModuleEmit(state: BuilderState, programOfThisState: Program, sourceFileWithUpdatedShape: SourceFile, cacheToUpdateSignature: Map<string>, cancellationToken: CancellationToken | undefined, computeHash: ComputeHash | undefined) {
if (!isExternalModule(sourceFileWithUpdatedShape) && !containsOnlyAmbientModules(sourceFileWithUpdatedShape)) {
return getAllFilesExcludingDefaultLibraryFile(state, programOfThisState, sourceFileWithUpdatedShape);
}
const compilerOptions = programOfThisState.getCompilerOptions();
if (compilerOptions && (compilerOptions.isolatedModules || compilerOptions.out || compilerOptions.outFile)) {
return [sourceFileWithUpdatedShape];
}
// Now we need to if each file in the referencedBy list has a shape change as well.
// Because if so, its own referencedBy files need to be saved as well to make the
// emitting result consistent with files on disk.
const seenFileNamesMap = createMap<SourceFile>();
// Start with the paths this file was referenced by
seenFileNamesMap.set(sourceFileWithUpdatedShape.path, sourceFileWithUpdatedShape);
const queue = getReferencedByPaths(state, sourceFileWithUpdatedShape.path);
while (queue.length > 0) {
const currentPath = queue.pop();
if (!seenFileNamesMap.has(currentPath)) {
const currentSourceFile = programOfThisState.getSourceFileByPath(currentPath);
seenFileNamesMap.set(currentPath, currentSourceFile);
if (currentSourceFile && updateShapeSignature(state, programOfThisState, currentSourceFile, cacheToUpdateSignature, cancellationToken, computeHash)) {
queue.push(...getReferencedByPaths(state, currentPath));
}
}
}
// Return array of values that needs emit
// Return array of values that needs emit
return arrayFrom(mapDefinedIterator(seenFileNamesMap.values(), value => value));
}
}
+44 -41
View File
@@ -749,10 +749,12 @@ namespace ts {
return _jsxNamespace;
}
function getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken) {
function getEmitResolver(sourceFile: SourceFile, cancellationToken: CancellationToken, ignoreDiagnostics?: boolean) {
// Ensure we have all the type information in place for this file so that all the
// emitter questions of this resolver will return the right information.
getDiagnostics(sourceFile, cancellationToken);
if (!ignoreDiagnostics) {
getDiagnostics(sourceFile, cancellationToken);
}
return emitResolver;
}
@@ -2422,12 +2424,15 @@ namespace ts {
const visitedSymbolTables: SymbolTable[] = [];
return forEachSymbolTableInScope(enclosingDeclaration, getAccessibleSymbolChainFromSymbolTable);
function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable): Symbol[] | undefined {
/**
* @param {ignoreQualification} boolean Set when a symbol is being looked for through the exports of another symbol (meaning we have a route to qualify it already)
*/
function getAccessibleSymbolChainFromSymbolTable(symbols: SymbolTable, ignoreQualification?: boolean): Symbol[] | undefined {
if (!pushIfUnique(visitedSymbolTables, symbols)) {
return undefined;
}
const result = trySymbolTable(symbols);
const result = trySymbolTable(symbols, ignoreQualification);
visitedSymbolTables.pop();
return result;
}
@@ -2439,22 +2444,22 @@ namespace ts {
!!getAccessibleSymbolChain(symbolFromSymbolTable.parent, enclosingDeclaration, getQualifiedLeftMeaning(meaning), useOnlyExternalAliasing);
}
function isAccessible(symbolFromSymbolTable: Symbol, resolvedAliasSymbol?: Symbol) {
function isAccessible(symbolFromSymbolTable: Symbol, resolvedAliasSymbol?: Symbol, ignoreQualification?: boolean) {
return symbol === (resolvedAliasSymbol || symbolFromSymbolTable) &&
// if the symbolFromSymbolTable is not external module (it could be if it was determined as ambient external module and would be in globals table)
// and if symbolFromSymbolTable or alias resolution matches the symbol,
// check the symbol can be qualified, it is only then this symbol is accessible
!some(symbolFromSymbolTable.declarations, hasExternalModuleSymbol) &&
canQualifySymbol(symbolFromSymbolTable, meaning);
(ignoreQualification || canQualifySymbol(symbolFromSymbolTable, meaning));
}
function isUMDExportSymbol(symbol: Symbol) {
return symbol && symbol.declarations && symbol.declarations[0] && isNamespaceExportDeclaration(symbol.declarations[0]);
}
function trySymbolTable(symbols: SymbolTable) {
function trySymbolTable(symbols: SymbolTable, ignoreQualification: boolean | undefined) {
// If symbol is directly available by its name in the symbol table
if (isAccessible(symbols.get(symbol.escapedName))) {
if (isAccessible(symbols.get(symbol.escapedName), /*resolvedAliasSymbol*/ undefined, ignoreQualification)) {
return [symbol];
}
@@ -2467,14 +2472,14 @@ namespace ts {
&& (!useOnlyExternalAliasing || some(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration))) {
const resolvedImportedSymbol = resolveAlias(symbolFromSymbolTable);
if (isAccessible(symbolFromSymbolTable, resolvedImportedSymbol)) {
if (isAccessible(symbolFromSymbolTable, resolvedImportedSymbol, ignoreQualification)) {
return [symbolFromSymbolTable];
}
// Look in the exported members, if we can find accessibleSymbolChain, symbol is accessible using this chain
// but only if the symbolFromSymbolTable can be qualified
const candidateTable = getExportsOfSymbol(resolvedImportedSymbol);
const accessibleSymbolsFromExports = candidateTable && getAccessibleSymbolChainFromSymbolTable(candidateTable);
const accessibleSymbolsFromExports = candidateTable && getAccessibleSymbolChainFromSymbolTable(candidateTable, /*ignoreQualification*/ true);
if (accessibleSymbolsFromExports && canQualifySymbol(symbolFromSymbolTable, getQualifiedLeftMeaning(meaning))) {
return [symbolFromSymbolTable].concat(accessibleSymbolsFromExports);
}
@@ -3949,7 +3954,8 @@ namespace ts {
if (strictNullChecks && declaration.flags & NodeFlags.Ambient && isParameterDeclaration(declaration)) {
parentType = getNonNullableType(parentType);
}
const declaredType = getTypeOfPropertyOfType(parentType, text);
const propType = getTypeOfPropertyOfType(parentType, text);
const declaredType = propType && getApparentTypeForLocation(propType, declaration.name);
type = declaredType && getFlowTypeOfReference(declaration, declaredType) ||
isNumericLiteralName(text) && getIndexTypeOfType(parentType, IndexKind.Number) ||
getIndexTypeOfType(parentType, IndexKind.String);
@@ -5992,7 +5998,9 @@ namespace ts {
for (const memberType of types) {
for (const { escapedName } of getAugmentedPropertiesOfType(memberType)) {
if (!props.has(escapedName)) {
props.set(escapedName, createUnionOrIntersectionProperty(unionType as UnionType, escapedName));
const prop = createUnionOrIntersectionProperty(unionType as UnionType, escapedName);
// May be undefined if the property is private
if (prop) props.set(escapedName, prop);
}
}
}
@@ -6174,7 +6182,7 @@ namespace ts {
t;
}
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: __String): Symbol {
function createUnionOrIntersectionProperty(containingType: UnionOrIntersectionType, name: __String): Symbol | undefined {
let props: Symbol[];
const isUnion = containingType.flags & TypeFlags.Union;
const excludeModifiers = isUnion ? ModifierFlags.NonPublicAccessibilityModifier : 0;
@@ -6562,7 +6570,7 @@ namespace ts {
// b) It references `arguments` somewhere
const lastParam = lastOrUndefined(declaration.parameters);
const lastParamTags = lastParam && getJSDocParameterTags(lastParam);
const lastParamVariadicType = lastParamTags && firstDefined(lastParamTags, p =>
const lastParamVariadicType = firstDefined(lastParamTags, p =>
p.typeExpression && isJSDocVariadicType(p.typeExpression.type) ? p.typeExpression.type : undefined);
if (!lastParamVariadicType && !containsArgumentsReference(declaration)) {
return false;
@@ -9635,7 +9643,7 @@ namespace ts {
}
else if (target.flags & TypeFlags.IndexedAccess) {
// A type S is related to a type T[K] if S is related to A[K], where K is string-like and
// A is the apparent type of T.
// A is the constraint of T.
const constraint = getConstraintOfIndexedAccess(<IndexedAccessType>target);
if (constraint) {
if (result = isRelatedTo(source, constraint, reportErrors)) {
@@ -9671,7 +9679,7 @@ namespace ts {
}
else if (source.flags & TypeFlags.IndexedAccess) {
// A type S[K] is related to a type T if A[K] is related to T, where K is string-like and
// A is the apparent type of S.
// A is the constraint of S.
const constraint = getConstraintOfIndexedAccess(<IndexedAccessType>source);
if (constraint) {
if (result = isRelatedTo(constraint, target, reportErrors)) {
@@ -9679,10 +9687,11 @@ namespace ts {
return result;
}
}
else if (target.flags & TypeFlags.IndexedAccess && (<IndexedAccessType>source).indexType === (<IndexedAccessType>target).indexType) {
// if we have indexed access types with identical index types, see if relationship holds for
// the two object types.
else if (target.flags & TypeFlags.IndexedAccess) {
if (result = isRelatedTo((<IndexedAccessType>source).objectType, (<IndexedAccessType>target).objectType, reportErrors)) {
result &= isRelatedTo((<IndexedAccessType>source).indexType, (<IndexedAccessType>target).indexType, reportErrors);
}
if (result) {
errorInfo = saveErrorInfo;
return result;
}
@@ -10963,7 +10972,7 @@ namespace ts {
return type === typeParameter || type.flags & TypeFlags.UnionOrIntersection && forEach((<UnionOrIntersectionType>type).types, t => isTypeParameterAtTopLevel(t, typeParameter));
}
/** Create an object with properties named in the string literal type. Every property has type `{}` */
/** Create an object with properties named in the string literal type. Every property has type `any` */
function createEmptyObjectTypeFromStringLiteral(type: Type) {
const members = createSymbolTable();
forEachType(type, t => {
@@ -10972,7 +10981,7 @@ namespace ts {
}
const name = escapeLeadingUnderscores((t as StringLiteralType).value);
const literalProp = createSymbol(SymbolFlags.Property, name);
literalProp.type = emptyObjectType;
literalProp.type = anyType;
if (t.symbol) {
literalProp.declarations = t.symbol.declarations;
literalProp.valueDeclaration = t.symbol.valueDeclaration;
@@ -11027,7 +11036,9 @@ namespace ts {
const templateType = getTemplateTypeFromMappedType(target);
const inference = createInferenceInfo(typeParameter);
inferTypes([inference], sourceType, templateType);
return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) : emptyObjectType;
return inference.candidates ? getUnionType(inference.candidates, UnionReduction.Subtype) :
inference.contraCandidates ? getCommonSubtype(inference.contraCandidates) :
emptyObjectType;
}
function getUnmatchedProperty(source: Type, target: Type, requireOptionalProperties: boolean) {
@@ -11763,16 +11774,6 @@ namespace ts {
}
function getTypeWithFacts(type: Type, include: TypeFacts) {
if (type.flags & TypeFlags.IndexedAccess) {
// TODO (weswig): This is a substitute for a lazy negated type to remove the types indicated by the TypeFacts from the (potential) union the IndexedAccess refers to
// - See discussion in https://github.com/Microsoft/TypeScript/pull/19275 for details, and test `strictNullNotNullIndexTypeShouldWork` for current behavior
const baseConstraint = getBaseConstraintOfType(type) || emptyObjectType;
const result = filterType(baseConstraint, t => (getTypeFacts(t) & include) !== 0);
if (result !== baseConstraint) {
return result;
}
return type;
}
return filterType(type, t => (getTypeFacts(t) & include) !== 0);
}
@@ -12886,19 +12887,20 @@ namespace ts {
const parent = node.parent;
return parent.kind === SyntaxKind.PropertyAccessExpression ||
parent.kind === SyntaxKind.CallExpression && (<CallExpression>parent).expression === node ||
parent.kind === SyntaxKind.ElementAccessExpression && (<ElementAccessExpression>parent).expression === node;
parent.kind === SyntaxKind.ElementAccessExpression && (<ElementAccessExpression>parent).expression === node ||
parent.kind === SyntaxKind.NonNullExpression ||
parent.kind === SyntaxKind.BindingElement && (<BindingElement>parent).name === node && !!(<BindingElement>parent).initializer;
}
function typeHasNullableConstraint(type: Type) {
return type.flags & TypeFlags.TypeVariable && maybeTypeOfKind(getBaseConstraintOfType(type) || emptyObjectType, TypeFlags.Nullable);
}
function getDeclaredOrApparentType(symbol: Symbol, node: Node) {
function getApparentTypeForLocation(type: Type, node: Node) {
// When a node is the left hand expression of a property access, element access, or call expression,
// and the type of the node includes type variables with constraints that are nullable, we fetch the
// apparent type of the node *before* performing control flow analysis such that narrowings apply to
// the constraint type.
const type = getTypeOfSymbol(symbol);
if (isApparentTypePosition(node) && forEachType(type, typeHasNullableConstraint)) {
return mapType(getWidenedType(type), getApparentType);
}
@@ -12988,7 +12990,7 @@ namespace ts {
checkCollisionWithCapturedNewTargetVariable(node, node);
checkNestedBlockScopedBinding(node, symbol);
const type = getDeclaredOrApparentType(localOrExportSymbol, node);
const type = getApparentTypeForLocation(getTypeOfSymbol(localOrExportSymbol), node);
const assignmentKind = getAssignmentTargetKind(node);
if (assignmentKind) {
@@ -13047,7 +13049,7 @@ namespace ts {
node.parent.kind === SyntaxKind.NonNullExpression ||
declaration.kind === SyntaxKind.VariableDeclaration && (<VariableDeclaration>declaration).exclamationToken ||
declaration.flags & NodeFlags.Ambient;
const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, getRootDeclaration(declaration) as VariableLikeDeclaration) : type) :
const initialType = assumeInitialized ? (isParameter ? removeOptionalityFromDeclaredType(type, declaration as VariableLikeDeclaration) : type) :
type === autoType || type === autoArrayType ? undefinedType :
getOptionalType(type);
const flowType = getFlowTypeOfReference(node, type, initialType, flowContainer, !assumeInitialized);
@@ -15309,7 +15311,7 @@ namespace ts {
// If the targetAttributesType is an emptyObjectType, indicating that there is no property named 'props' on this instance type.
// but there exists a sourceAttributesType, we need to explicitly give an error as normal assignability check allow excess properties and will pass.
if (targetAttributesType === emptyObjectType && (isTypeAny(sourceAttributesType) || (<ResolvedType>sourceAttributesType).properties.length > 0)) {
if (targetAttributesType === emptyObjectType && (isTypeAny(sourceAttributesType) || getPropertiesOfType(<ResolvedType>sourceAttributesType).length > 0)) {
error(openingLikeElement, Diagnostics.JSX_element_class_does_not_support_attributes_because_it_does_not_have_a_0_property, unescapeLeadingUnderscores(getJsxElementPropertiesName()));
}
else {
@@ -15554,7 +15556,7 @@ namespace ts {
return unknownType;
}
}
propType = getDeclaredOrApparentType(prop, node);
propType = getApparentTypeForLocation(getTypeOfSymbol(prop), node);
}
// Only compute control flow type if this is a property access expression that isn't an
// assignment target, and the referenced property was declared as a variable, property,
@@ -16716,7 +16718,7 @@ namespace ts {
const isDecorator = node.kind === SyntaxKind.Decorator;
const isJsxOpeningOrSelfClosingElement = isJsxOpeningLikeElement(node);
let typeArguments: ReadonlyArray<TypeNode>;
let typeArguments: NodeArray<TypeNode>;
if (!isTaggedTemplate && !isDecorator && !isJsxOpeningOrSelfClosingElement) {
typeArguments = (<CallExpression>node).typeArguments;
@@ -16845,7 +16847,7 @@ namespace ts {
max = Math.max(max, length(sig.typeParameters));
}
const paramCount = min < max ? min + "-" + max : min;
diagnostics.add(createDiagnosticForNode(node, Diagnostics.Expected_0_type_arguments_but_got_1, paramCount, typeArguments.length));
diagnostics.add(createDiagnosticForNodeArray(getSourceFileOfNode(node), typeArguments, Diagnostics.Expected_0_type_arguments_but_got_1, paramCount, typeArguments.length));
}
else if (args) {
let min = Number.POSITIVE_INFINITY;
@@ -21029,6 +21031,7 @@ namespace ts {
}
break;
case SyntaxKind.IndexSignature:
case SyntaxKind.SemicolonClassElement:
// Can't be private
break;
default:
+17 -221
View File
@@ -4,7 +4,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 = "2.7";
export const versionMajorMinor = "2.8";
/** The version of the TypeScript compiler release */
export const version = `${versionMajorMinor}.0`;
}
@@ -16,6 +16,10 @@ namespace ts {
// Update: We also consider a path like `C:\foo.ts` "relative" because we do not search for it in `node_modules` or treat it as an ambient module.
return pathIsRelative(moduleName) || isRootedDiskPath(moduleName);
}
export function sortAndDeduplicateDiagnostics(diagnostics: ReadonlyArray<Diagnostic>): Diagnostic[] {
return sortAndDeduplicate(diagnostics, compareDiagnostics);
}
}
/* @internal */
@@ -183,6 +187,10 @@ namespace ts {
/** Like `forEach`, but suitable for use with numbers and strings (which may be falsy). */
export function firstDefined<T, U>(array: ReadonlyArray<T> | undefined, callback: (element: T, index: number) => U | undefined): U | undefined {
if (array === undefined) {
return undefined;
}
for (let i = 0; i < array.length; i++) {
const result = callback(array[i], i);
if (result !== undefined) {
@@ -336,6 +344,10 @@ namespace ts {
return false;
}
export function arraysEqual<T>(a: ReadonlyArray<T>, b: ReadonlyArray<T>, equalityComparer: EqualityComparer<T> = equateValues): boolean {
return a.length === b.length && a.every((x, i) => equalityComparer(x, b[i]));
}
export function indexOfAnyCharCode(text: string, charCodes: ReadonlyArray<number>, start?: number): number {
for (let i = start || 0; i < text.length; i++) {
if (contains(charCodes, text.charCodeAt(i))) {
@@ -1457,6 +1469,9 @@ namespace ts {
/** Returns its argument. */
export function identity<T>(x: T) { return x; }
/** Returns lower case string */
export function toLowerCase(x: string) { return x.toLowerCase(); }
/** Throws an error because a function is not implemented. */
export function notImplemented(): never {
throw new Error("Not implemented");
@@ -1890,10 +1905,6 @@ namespace ts {
return text1 ? Comparison.GreaterThan : Comparison.LessThan;
}
export function sortAndDeduplicateDiagnostics(diagnostics: ReadonlyArray<Diagnostic>): Diagnostic[] {
return sortAndDeduplicate(diagnostics, compareDiagnostics);
}
export function normalizeSlashes(path: string): string {
return path.replace(/\\/g, "/");
}
@@ -2927,9 +2938,7 @@ namespace ts {
export type GetCanonicalFileName = (fileName: string) => string;
export function createGetCanonicalFileName(useCaseSensitiveFileNames: boolean): GetCanonicalFileName {
return useCaseSensitiveFileNames
? ((fileName) => fileName)
: ((fileName) => fileName.toLowerCase());
return useCaseSensitiveFileNames ? identity : toLowerCase;
}
/**
@@ -3054,223 +3063,10 @@ namespace ts {
export function assertTypeIsNever(_: never): void { } // tslint:disable-line no-empty
export interface FileAndDirectoryExistence {
fileExists: boolean;
directoryExists: boolean;
}
export interface CachedDirectoryStructureHost extends DirectoryStructureHost {
/** Returns the queried result for the file exists and directory exists if at all it was done */
addOrDeleteFileOrDirectory(fileOrDirectory: string, fileOrDirectoryPath: Path): FileAndDirectoryExistence | undefined;
addOrDeleteFile(fileName: string, filePath: Path, eventKind: FileWatcherEventKind): void;
clearCache(): void;
}
interface MutableFileSystemEntries {
readonly files: string[];
readonly directories: string[];
}
export const emptyFileSystemEntries: FileSystemEntries = {
files: emptyArray,
directories: emptyArray
};
export function createCachedDirectoryStructureHost(host: DirectoryStructureHost): CachedDirectoryStructureHost {
const cachedReadDirectoryResult = createMap<MutableFileSystemEntries>();
const getCurrentDirectory = memoize(() => host.getCurrentDirectory());
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames);
return {
useCaseSensitiveFileNames: host.useCaseSensitiveFileNames,
newLine: host.newLine,
readFile: (path, encoding) => host.readFile(path, encoding),
write: s => host.write(s),
writeFile,
fileExists,
directoryExists,
createDirectory,
getCurrentDirectory,
getDirectories,
readDirectory,
addOrDeleteFileOrDirectory,
addOrDeleteFile,
clearCache,
exit: code => host.exit(code)
};
function toPath(fileName: string) {
return ts.toPath(fileName, getCurrentDirectory(), getCanonicalFileName);
}
function getCachedFileSystemEntries(rootDirPath: Path): MutableFileSystemEntries | undefined {
return cachedReadDirectoryResult.get(rootDirPath);
}
function getCachedFileSystemEntriesForBaseDir(path: Path): MutableFileSystemEntries | undefined {
return getCachedFileSystemEntries(getDirectoryPath(path));
}
function getBaseNameOfFileName(fileName: string) {
return getBaseFileName(normalizePath(fileName));
}
function createCachedFileSystemEntries(rootDir: string, rootDirPath: Path) {
const resultFromHost: MutableFileSystemEntries = {
files: map(host.readDirectory(rootDir, /*extensions*/ undefined, /*exclude*/ undefined, /*include*/["*.*"]), getBaseNameOfFileName) || [],
directories: host.getDirectories(rootDir) || []
};
cachedReadDirectoryResult.set(rootDirPath, resultFromHost);
return resultFromHost;
}
/**
* If the readDirectory result was already cached, it returns that
* Otherwise gets result from host and caches it.
* The host request is done under try catch block to avoid caching incorrect result
*/
function tryReadDirectory(rootDir: string, rootDirPath: Path): MutableFileSystemEntries | undefined {
const cachedResult = getCachedFileSystemEntries(rootDirPath);
if (cachedResult) {
return cachedResult;
}
try {
return createCachedFileSystemEntries(rootDir, rootDirPath);
}
catch (_e) {
// If there is exception to read directories, dont cache the result and direct the calls to host
Debug.assert(!cachedReadDirectoryResult.has(rootDirPath));
return undefined;
}
}
function fileNameEqual(name1: string, name2: string) {
return getCanonicalFileName(name1) === getCanonicalFileName(name2);
}
function hasEntry(entries: ReadonlyArray<string>, name: string) {
return some(entries, file => fileNameEqual(file, name));
}
function updateFileSystemEntry(entries: string[], baseName: string, isValid: boolean) {
if (hasEntry(entries, baseName)) {
if (!isValid) {
return filterMutate(entries, entry => !fileNameEqual(entry, baseName));
}
}
else if (isValid) {
return entries.push(baseName);
}
}
function writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void {
const path = toPath(fileName);
const result = getCachedFileSystemEntriesForBaseDir(path);
if (result) {
updateFilesOfFileSystemEntry(result, getBaseNameOfFileName(fileName), /*fileExists*/ true);
}
return host.writeFile(fileName, data, writeByteOrderMark);
}
function fileExists(fileName: string): boolean {
const path = toPath(fileName);
const result = getCachedFileSystemEntriesForBaseDir(path);
return result && hasEntry(result.files, getBaseNameOfFileName(fileName)) ||
host.fileExists(fileName);
}
function directoryExists(dirPath: string): boolean {
const path = toPath(dirPath);
return cachedReadDirectoryResult.has(path) || host.directoryExists(dirPath);
}
function createDirectory(dirPath: string) {
const path = toPath(dirPath);
const result = getCachedFileSystemEntriesForBaseDir(path);
const baseFileName = getBaseNameOfFileName(dirPath);
if (result) {
updateFileSystemEntry(result.directories, baseFileName, /*isValid*/ true);
}
host.createDirectory(dirPath);
}
function getDirectories(rootDir: string): string[] {
const rootDirPath = toPath(rootDir);
const result = tryReadDirectory(rootDir, rootDirPath);
if (result) {
return result.directories.slice();
}
return host.getDirectories(rootDir);
}
function readDirectory(rootDir: string, extensions?: ReadonlyArray<string>, excludes?: ReadonlyArray<string>, includes?: ReadonlyArray<string>, depth?: number): string[] {
const rootDirPath = toPath(rootDir);
const result = tryReadDirectory(rootDir, rootDirPath);
if (result) {
return matchFiles(rootDir, extensions, excludes, includes, host.useCaseSensitiveFileNames, getCurrentDirectory(), depth, getFileSystemEntries);
}
return host.readDirectory(rootDir, extensions, excludes, includes, depth);
function getFileSystemEntries(dir: string) {
const path = toPath(dir);
if (path === rootDirPath) {
return result;
}
return tryReadDirectory(dir, path) || emptyFileSystemEntries;
}
}
function addOrDeleteFileOrDirectory(fileOrDirectory: string, fileOrDirectoryPath: Path) {
const existingResult = getCachedFileSystemEntries(fileOrDirectoryPath);
if (existingResult) {
// Just clear the cache for now
// For now just clear the cache, since this could mean that multiple level entries might need to be re-evaluated
clearCache();
}
else {
// This was earlier a file (hence not in cached directory contents)
// or we never cached the directory containing it
const parentResult = getCachedFileSystemEntriesForBaseDir(fileOrDirectoryPath);
if (parentResult) {
const baseName = getBaseNameOfFileName(fileOrDirectory);
if (parentResult) {
const fsQueryResult: FileAndDirectoryExistence = {
fileExists: host.fileExists(fileOrDirectoryPath),
directoryExists: host.directoryExists(fileOrDirectoryPath)
};
if (fsQueryResult.directoryExists || hasEntry(parentResult.directories, baseName)) {
// Folder added or removed, clear the cache instead of updating the folder and its structure
clearCache();
}
else {
// No need to update the directory structure, just files
updateFilesOfFileSystemEntry(parentResult, baseName, fsQueryResult.fileExists);
}
return fsQueryResult;
}
}
}
}
function addOrDeleteFile(fileName: string, filePath: Path, eventKind: FileWatcherEventKind) {
if (eventKind === FileWatcherEventKind.Changed) {
return;
}
const parentResult = getCachedFileSystemEntriesForBaseDir(filePath);
if (parentResult) {
updateFilesOfFileSystemEntry(parentResult, getBaseNameOfFileName(fileName), eventKind === FileWatcherEventKind.Created);
}
}
function updateFilesOfFileSystemEntry(parentResult: MutableFileSystemEntries, baseName: string, fileExists: boolean) {
updateFileSystemEntry(parentResult.files, baseName, fileExists);
}
function clearCache() {
cachedReadDirectoryResult.clear();
}
}
export function singleElementArray<T>(t: T | undefined): T[] | undefined {
return t === undefined ? undefined : [t];
+1 -1
View File
@@ -2000,7 +2000,7 @@ namespace ts {
export function writeDeclarationFile(declarationFilePath: string, sourceFileOrBundle: SourceFile | Bundle, host: EmitHost, resolver: EmitResolver, emitterDiagnostics: DiagnosticCollection, emitOnlyDtsFiles: boolean) {
const emitDeclarationResult = emitDeclarations(host, resolver, emitterDiagnostics, declarationFilePath, sourceFileOrBundle, emitOnlyDtsFiles);
const emitSkipped = emitDeclarationResult.reportedDeclarationError || host.isEmitBlocked(declarationFilePath) || host.getCompilerOptions().noEmit;
if (!emitSkipped) {
if (!emitSkipped || emitOnlyDtsFiles) {
const sourceFiles = sourceFileOrBundle.kind === SyntaxKind.Bundle ? sourceFileOrBundle.sourceFiles : [sourceFileOrBundle];
const declarationOutput = emitDeclarationResult.referencesOutput
+ getDeclarationOutput(emitDeclarationResult.synchronousDeclarationOutput, emitDeclarationResult.moduleElementDeclarationEmitInfo);
-4
View File
@@ -3897,10 +3897,6 @@
"category": "Message",
"code": 95002
},
"Extract symbol": {
"category": "Message",
"code": 95003
},
"Extract to {0} in {1}": {
"category": "Message",
"code": 95004
+27 -26
View File
@@ -1,7 +1,6 @@
/// <reference path="sys.ts" />
/// <reference path="emitter.ts" />
/// <reference path="core.ts" />
/// <reference path="builder.ts" />
namespace ts {
const ignoreDiagnosticCommentRegEx = /(^\s*$)|(^\s*\/\/\/?\s*(@ts-ignore)?)/;
@@ -1141,32 +1140,34 @@ namespace ts {
function emitWorker(program: Program, sourceFile: SourceFile, writeFileCallback: WriteFileCallback, cancellationToken: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult {
let declarationDiagnostics: ReadonlyArray<Diagnostic> = [];
if (options.noEmit) {
return { diagnostics: declarationDiagnostics, sourceMaps: undefined, emittedFiles: undefined, emitSkipped: true };
}
// If the noEmitOnError flag is set, then check if we have any errors so far. If so,
// immediately bail out. Note that we pass 'undefined' for 'sourceFile' so that we
// get any preEmit diagnostics, not just the ones
if (options.noEmitOnError) {
const diagnostics = [
...program.getOptionsDiagnostics(cancellationToken),
...program.getSyntacticDiagnostics(sourceFile, cancellationToken),
...program.getGlobalDiagnostics(cancellationToken),
...program.getSemanticDiagnostics(sourceFile, cancellationToken)
];
if (diagnostics.length === 0 && program.getCompilerOptions().declaration) {
declarationDiagnostics = program.getDeclarationDiagnostics(/*sourceFile*/ undefined, cancellationToken);
if (!emitOnlyDtsFiles) {
if (options.noEmit) {
return { diagnostics: declarationDiagnostics, sourceMaps: undefined, emittedFiles: undefined, emitSkipped: true };
}
if (diagnostics.length > 0 || declarationDiagnostics.length > 0) {
return {
diagnostics: concatenate(diagnostics, declarationDiagnostics),
sourceMaps: undefined,
emittedFiles: undefined,
emitSkipped: true
};
// If the noEmitOnError flag is set, then check if we have any errors so far. If so,
// immediately bail out. Note that we pass 'undefined' for 'sourceFile' so that we
// get any preEmit diagnostics, not just the ones
if (options.noEmitOnError) {
const diagnostics = [
...program.getOptionsDiagnostics(cancellationToken),
...program.getSyntacticDiagnostics(sourceFile, cancellationToken),
...program.getGlobalDiagnostics(cancellationToken),
...program.getSemanticDiagnostics(sourceFile, cancellationToken)
];
if (diagnostics.length === 0 && program.getCompilerOptions().declaration) {
declarationDiagnostics = program.getDeclarationDiagnostics(/*sourceFile*/ undefined, cancellationToken);
}
if (diagnostics.length > 0 || declarationDiagnostics.length > 0) {
return {
diagnostics: concatenate(diagnostics, declarationDiagnostics),
sourceMaps: undefined,
emittedFiles: undefined,
emitSkipped: true
};
}
}
}
@@ -1178,7 +1179,7 @@ namespace ts {
// This is because in the -out scenario all files need to be emitted, and therefore all
// files need to be type checked. And the way to specify that all files need to be type
// checked is to not pass the file to getEmitResolver.
const emitResolver = getDiagnosticsProducingTypeChecker().getEmitResolver((options.outFile || options.out) ? undefined : sourceFile);
const emitResolver = getDiagnosticsProducingTypeChecker().getEmitResolver((options.outFile || options.out) ? undefined : sourceFile, cancellationToken, emitOnlyDtsFiles);
performance.mark("beforeEmit");
+17 -17
View File
@@ -9,12 +9,12 @@ namespace ts {
startRecordingFilesWithChangedResolutions(): void;
finishRecordingFilesWithChangedResolutions(): Path[];
resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, logChanges: boolean): ResolvedModuleFull[];
resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined): ResolvedModuleFull[];
resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
invalidateResolutionOfFile(filePath: Path): void;
removeResolutionsOfFile(filePath: Path): void;
createHasInvalidatedResolution(): HasInvalidatedResolution;
createHasInvalidatedResolution(forceAllFilesAsInvalidated?: boolean): HasInvalidatedResolution;
startCachingPerDirectoryResolution(): void;
finishCachingPerDirectoryResolution(): void;
@@ -47,7 +47,7 @@ namespace ts {
onInvalidatedResolution(): void;
watchTypeRootsDirectory(directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags): FileWatcher;
onChangedAutomaticTypeDirectiveNames(): void;
getCachedDirectoryStructureHost?(): CachedDirectoryStructureHost;
getCachedDirectoryStructureHost(): CachedDirectoryStructureHost | undefined;
projectName?: string;
getGlobalCache?(): string | undefined;
writeLog(s: string): void;
@@ -73,7 +73,7 @@ namespace ts {
type GetResolutionWithResolvedFileName<T extends ResolutionWithFailedLookupLocations = ResolutionWithFailedLookupLocations, R extends ResolutionWithResolvedFileName = ResolutionWithResolvedFileName> =
(resolution: T) => R;
export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootDirForResolution: string): ResolutionCache {
export function createResolutionCache(resolutionHost: ResolutionCacheHost, rootDirForResolution: string, logChangesWhenResolvingModule: boolean): ResolutionCache {
let filesWithChangedSetOfUnresolvedImports: Path[] | undefined;
let filesWithInvalidatedResolutions: Map<true> | undefined;
let allFilesHaveInvalidatedResolution = false;
@@ -88,6 +88,7 @@ namespace ts {
const perDirectoryResolvedTypeReferenceDirectives = createMap<Map<ResolvedTypeReferenceDirectiveWithFailedLookupLocations>>();
const getCurrentDirectory = memoize(() => resolutionHost.getCurrentDirectory());
const cachedDirectoryStructureHost = resolutionHost.getCachedDirectoryStructureHost();
/**
* These are the extensions that failed lookup files will have by default,
@@ -159,8 +160,8 @@ namespace ts {
return collected;
}
function createHasInvalidatedResolution(): HasInvalidatedResolution {
if (allFilesHaveInvalidatedResolution) {
function createHasInvalidatedResolution(forceAllFilesAsInvalidated?: boolean): HasInvalidatedResolution {
if (allFilesHaveInvalidatedResolution || forceAllFilesAsInvalidated) {
// Any file asked would have invalidated resolution
filesWithInvalidatedResolutions = undefined;
return returnTrue;
@@ -307,12 +308,12 @@ namespace ts {
);
}
function resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined, logChanges: boolean): ResolvedModuleFull[] {
function resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames: string[] | undefined): ResolvedModuleFull[] {
return resolveNamesWithLocalCache(
moduleNames, containingFile,
resolvedModuleNames, perDirectoryResolvedModuleNames,
resolveModuleName, getResolvedModule,
reusedNames, logChanges
reusedNames, logChangesWhenResolvingModule
);
}
@@ -468,14 +469,9 @@ namespace ts {
function createDirectoryWatcher(directory: string, dirPath: Path) {
return resolutionHost.watchDirectoryOfFailedLookupLocation(directory, fileOrDirectory => {
const fileOrDirectoryPath = resolutionHost.toPath(fileOrDirectory);
if (resolutionHost.getCachedDirectoryStructureHost) {
if (cachedDirectoryStructureHost) {
// Since the file existance changed, update the sourceFiles cache
resolutionHost.getCachedDirectoryStructureHost().addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath);
}
// Ignore emits from the program
if (isEmittedFileOfProgram(resolutionHost.getCurrentProgram(), fileOrDirectory)) {
return;
cachedDirectoryStructureHost.addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath);
}
// If the files are added to project root or node_modules directory, always run through the invalidation process
@@ -581,6 +577,10 @@ namespace ts {
if (!isPathWithDefaultFailedLookupExtension(fileOrDirectoryPath) && !customFailedLookupPaths.has(fileOrDirectoryPath)) {
return false;
}
// Ignore emits from the program
if (isEmittedFileOfProgram(resolutionHost.getCurrentProgram(), fileOrDirectoryPath)) {
return false;
}
// Resolution need to be invalidated if failed lookup location is same as the file or directory getting created
isChangedFailedLookupLocation = location => resolutionHost.toPath(location) === fileOrDirectoryPath;
}
@@ -602,9 +602,9 @@ namespace ts {
// Create new watch and recursive info
return resolutionHost.watchTypeRootsDirectory(typeRoot, fileOrDirectory => {
const fileOrDirectoryPath = resolutionHost.toPath(fileOrDirectory);
if (resolutionHost.getCachedDirectoryStructureHost) {
if (cachedDirectoryStructureHost) {
// Since the file existance changed, update the sourceFiles cache
resolutionHost.getCachedDirectoryStructureHost().addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath);
cachedDirectoryStructureHost.addOrDeleteFileOrDirectory(fileOrDirectory, fileOrDirectoryPath);
}
// For now just recompile
+4 -1
View File
@@ -335,7 +335,10 @@ namespace ts {
/* @internal */
export function computePositionOfLineAndCharacter(lineStarts: ReadonlyArray<number>, line: number, character: number, debugText?: string): number {
Debug.assert(line >= 0 && line < lineStarts.length);
if (line < 0 || line >= lineStarts.length) {
Debug.fail(`Bad line number. Line: ${line}, lineStarts.length: ${lineStarts.length} , line map is correct? ${debugText !== undefined ? arraysEqual(lineStarts, computeLineStarts(debugText)) : "unknown"}`);
}
const res = lineStarts[line] + character;
if (line < lineStarts.length - 1) {
Debug.assert(res < lineStarts[line + 1]);
+10 -16
View File
@@ -30,27 +30,14 @@ namespace ts {
mtime?: Date;
}
/**
* Partial interface of the System thats needed to support the caching of directory structure
*/
export interface DirectoryStructureHost {
export interface System {
args: string[];
newLine: string;
useCaseSensitiveFileNames: boolean;
write(s: string): void;
readFile(path: string, encoding?: string): string | undefined;
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
fileExists(path: string): boolean;
directoryExists(path: string): boolean;
createDirectory(path: string): void;
getCurrentDirectory(): string;
getDirectories(path: string): string[];
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
exit(exitCode?: number): void;
}
export interface System extends DirectoryStructureHost {
args: string[];
getFileSize?(path: string): number;
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
/**
* @pollingInterval - this parameter is used in polling-based watchers and ignored in watchers that
* use native OS file watching
@@ -58,7 +45,13 @@ namespace ts {
watchFile?(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
resolvePath(path: string): string;
fileExists(path: string): boolean;
directoryExists(path: string): boolean;
createDirectory(path: string): void;
getExecutingFilePath(): string;
getCurrentDirectory(): string;
getDirectories(path: string): string[];
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
getModifiedTime?(path: string): Date;
/**
* This should be cryptographically secure.
@@ -66,6 +59,7 @@ namespace ts {
*/
createHash?(data: string): string;
getMemoryUsage?(): number;
exit(exitCode?: number): void;
realpath?(path: string): string;
/*@internal*/ getEnvironmentVariable(name: string): string;
/*@internal*/ tryEnableSourceMapsForHost?(): void;
+1 -1
View File
@@ -148,7 +148,7 @@ namespace ts {
}
function visitLabeledStatement(node: LabeledStatement) {
if (enclosingFunctionFlags & FunctionFlags.Async && enclosingFunctionFlags & FunctionFlags.Generator) {
if (enclosingFunctionFlags & FunctionFlags.Async) {
const statement = unwrapInnermostStatementOfLabel(node);
if (statement.kind === SyntaxKind.ForOfStatement && (<ForOfStatement>statement).awaitModifier) {
return visitForOfStatement(<ForOfStatement>statement, node);
+33 -36
View File
@@ -21,10 +21,10 @@ namespace ts {
return <string>diagnostic.messageText;
}
let reportDiagnostic = createDiagnosticReporter(sys, reportDiagnosticSimply);
let reportDiagnostic = createDiagnosticReporter(sys);
function udpateReportDiagnostic(options: CompilerOptions) {
if (options.pretty) {
reportDiagnostic = createDiagnosticReporter(sys, reportDiagnosticWithColorAndContext);
reportDiagnostic = createDiagnosticReporter(sys, /*pretty*/ true);
}
}
@@ -55,7 +55,7 @@ namespace ts {
// If there are any errors due to command line parsing and/or
// setting up localization, report them and quit.
if (commandLine.errors.length > 0) {
reportDiagnostics(commandLine.errors, reportDiagnostic);
commandLine.errors.forEach(reportDiagnostic);
return sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
}
@@ -110,12 +110,11 @@ namespace ts {
const commandLineOptions = commandLine.options;
if (configFileName) {
const reportWatchDiagnostic = createWatchDiagnosticReporter();
const configParseResult = parseConfigFile(configFileName, commandLineOptions, sys, reportDiagnostic, reportWatchDiagnostic);
const configParseResult = parseConfigFileWithSystem(configFileName, commandLineOptions, sys, reportDiagnostic);
udpateReportDiagnostic(configParseResult.options);
if (isWatchSet(configParseResult.options)) {
reportWatchModeWithoutSysSupport();
createWatchModeWithConfigFile(configParseResult, commandLineOptions, createWatchingSystemHost(reportWatchDiagnostic));
createWatchOfConfigFile(configParseResult, commandLineOptions);
}
else {
performCompilation(configParseResult.fileNames, configParseResult.options);
@@ -125,7 +124,7 @@ namespace ts {
udpateReportDiagnostic(commandLineOptions);
if (isWatchSet(commandLineOptions)) {
reportWatchModeWithoutSysSupport();
createWatchModeWithoutConfigFile(commandLine.fileNames, commandLineOptions, createWatchingSystemHost());
createWatchOfFilesAndCompilerOptions(commandLine.fileNames, commandLineOptions);
}
else {
performCompilation(commandLine.fileNames, commandLineOptions);
@@ -145,44 +144,42 @@ namespace ts {
enableStatistics(compilerOptions);
const program = createProgram(rootFileNames, compilerOptions, compilerHost);
const exitStatus = compileProgram(program);
const exitStatus = emitFilesAndReportErrors(program, reportDiagnostic, s => sys.write(s + sys.newLine));
reportStatistics(program);
return sys.exit(exitStatus);
}
function createWatchingSystemHost(reportWatchDiagnostic?: DiagnosticReporter) {
const watchingHost = ts.createWatchingSystemHost(/*pretty*/ undefined, sys, parseConfigFile, reportDiagnostic, reportWatchDiagnostic);
watchingHost.beforeCompile = enableStatistics;
const afterCompile = watchingHost.afterCompile;
watchingHost.afterCompile = (host, program, builder) => {
afterCompile(host, program, builder);
reportStatistics(program);
function updateWatchCompilationHost(watchCompilerHost: WatchCompilerHost<EmitAndSemanticDiagnosticsBuilderProgram>) {
const compileUsingBuilder = watchCompilerHost.createProgram;
watchCompilerHost.createProgram = (rootNames, options, host, oldProgram) => {
enableStatistics(options);
return compileUsingBuilder(rootNames, options, host, oldProgram);
};
const emitFilesUsingBuilder = watchCompilerHost.afterProgramCreate;
watchCompilerHost.afterProgramCreate = builderProgram => {
emitFilesUsingBuilder(builderProgram);
reportStatistics(builderProgram.getProgram());
};
return watchingHost;
}
function compileProgram(program: Program): ExitStatus {
let diagnostics: Diagnostic[];
function createWatchStatusReporter(options: CompilerOptions) {
return ts.createWatchStatusReporter(sys, !!options.pretty);
}
// First get and report any syntactic errors.
diagnostics = program.getSyntacticDiagnostics().slice();
function createWatchOfConfigFile(configParseResult: ParsedCommandLine, optionsToExtend: CompilerOptions) {
const watchCompilerHost = ts.createWatchCompilerHostOfConfigFile(configParseResult.options.configFilePath, optionsToExtend, sys, /*createProgram*/ undefined, reportDiagnostic, createWatchStatusReporter(configParseResult.options));
updateWatchCompilationHost(watchCompilerHost);
watchCompilerHost.rootFiles = configParseResult.fileNames;
watchCompilerHost.options = configParseResult.options;
watchCompilerHost.configFileSpecs = configParseResult.configFileSpecs;
watchCompilerHost.configFileWildCardDirectories = configParseResult.wildcardDirectories;
createWatchProgram(watchCompilerHost);
}
// If we didn't have any syntactic errors, then also try getting the global and
// semantic errors.
if (diagnostics.length === 0) {
diagnostics = program.getOptionsDiagnostics().concat(program.getGlobalDiagnostics());
if (diagnostics.length === 0) {
diagnostics = program.getSemanticDiagnostics().slice();
}
}
// Emit and report any errors we ran into.
const { emittedFiles, emitSkipped, diagnostics: emitDiagnostics } = program.emit();
addRange(diagnostics, emitDiagnostics);
return handleEmitOutputAndReportErrors(sys, program, emittedFiles, emitSkipped, diagnostics, reportDiagnostic);
function createWatchOfFilesAndCompilerOptions(rootFiles: string[], options: CompilerOptions) {
const watchCompilerHost = ts.createWatchCompilerHostOfFilesAndCompilerOptions(rootFiles, options, sys, /*createProgram*/ undefined, reportDiagnostic, createWatchStatusReporter(options));
updateWatchCompilationHost(watchCompilerHost);
createWatchProgram(watchCompilerHost);
}
function enableStatistics(compilerOptions: CompilerOptions) {
+1
View File
@@ -38,6 +38,7 @@
"emitter.ts",
"watchUtilities.ts",
"program.ts",
"builderState.ts",
"builder.ts",
"resolutionCache.ts",
"watch.ts",
+2 -1
View File
@@ -2892,7 +2892,7 @@ namespace ts {
// Should not be called directly. Should only be accessed through the Program instance.
/* @internal */ getDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): Diagnostic[];
/* @internal */ getGlobalDiagnostics(): Diagnostic[];
/* @internal */ getEmitResolver(sourceFile?: SourceFile, cancellationToken?: CancellationToken): EmitResolver;
/* @internal */ getEmitResolver(sourceFile?: SourceFile, cancellationToken?: CancellationToken, ignoreDiagnostics?: boolean): EmitResolver;
/* @internal */ getNodeCount(): number;
/* @internal */ getIdentifierCount(): number;
@@ -4471,6 +4471,7 @@ namespace ts {
/* @internal */ onReleaseOldSourceFile?(oldSourceFile: SourceFile, oldOptions: CompilerOptions): void;
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
createHash?(data: string): string;
}
/* @internal */
+8 -3
View File
@@ -599,6 +599,11 @@ namespace ts {
return createDiagnosticForNodeInSourceFile(sourceFile, node, message, arg0, arg1, arg2, arg3);
}
export function createDiagnosticForNodeArray(sourceFile: SourceFile, nodes: NodeArray<Node>, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic {
const start = skipTrivia(sourceFile.text, nodes.pos);
return createFileDiagnostic(sourceFile, start, nodes.end - start, message, arg0, arg1, arg2, arg3);
}
export function createDiagnosticForNodeInSourceFile(sourceFile: SourceFile, node: Node, message: DiagnosticMessage, arg0?: string | number, arg1?: string | number, arg2?: string | number, arg3?: string | number): Diagnostic {
const span = getErrorSpanForNode(sourceFile, node);
return createFileDiagnostic(sourceFile, span.start, span.length, message, arg0, arg1, arg2, arg3);
@@ -3380,14 +3385,14 @@ namespace ts {
const carriageReturnLineFeed = "\r\n";
const lineFeed = "\n";
export function getNewLineCharacter(options: CompilerOptions | PrinterOptions, system?: { newLine: string }): string {
export function getNewLineCharacter(options: CompilerOptions | PrinterOptions, getNewLine?: () => string): string {
switch (options.newLine) {
case NewLineKind.CarriageReturnLineFeed:
return carriageReturnLineFeed;
case NewLineKind.LineFeed:
return lineFeed;
}
return system ? system.newLine : sys ? sys.newLine : carriageReturnLineFeed;
return getNewLine ? getNewLine() : sys ? sys.newLine : carriageReturnLineFeed;
}
/**
@@ -4704,7 +4709,7 @@ namespace ts {
}
export function isTypeOfExpression(node: Node): node is TypeOfExpression {
return node.kind === SyntaxKind.AwaitExpression;
return node.kind === SyntaxKind.TypeOfExpression;
}
export function isVoidExpression(node: Node): node is VoidExpression {
+523 -263
View File
File diff suppressed because it is too large Load Diff
+260 -11
View File
@@ -2,6 +2,247 @@
/* @internal */
namespace ts {
/**
* Partial interface of the System thats needed to support the caching of directory structure
*/
export interface DirectoryStructureHost {
fileExists(path: string): boolean;
readFile(path: string, encoding?: string): string | undefined;
directoryExists?(path: string): boolean;
getDirectories?(path: string): string[];
readDirectory?(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
createDirectory?(path: string): void;
writeFile?(path: string, data: string, writeByteOrderMark?: boolean): void;
}
interface FileAndDirectoryExistence {
fileExists: boolean;
directoryExists: boolean;
}
export interface CachedDirectoryStructureHost extends DirectoryStructureHost {
useCaseSensitiveFileNames: boolean;
getDirectories(path: string): string[];
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
/** Returns the queried result for the file exists and directory exists if at all it was done */
addOrDeleteFileOrDirectory(fileOrDirectory: string, fileOrDirectoryPath: Path): FileAndDirectoryExistence | undefined;
addOrDeleteFile(fileName: string, filePath: Path, eventKind: FileWatcherEventKind): void;
clearCache(): void;
}
interface MutableFileSystemEntries {
readonly files: string[];
readonly directories: string[];
}
export function createCachedDirectoryStructureHost(host: DirectoryStructureHost, currentDirectory: string, useCaseSensitiveFileNames: boolean): CachedDirectoryStructureHost | undefined {
if (!host.getDirectories || !host.readDirectory) {
return undefined;
}
const cachedReadDirectoryResult = createMap<MutableFileSystemEntries>();
const getCanonicalFileName = createGetCanonicalFileName(useCaseSensitiveFileNames);
return {
useCaseSensitiveFileNames,
fileExists,
readFile: (path, encoding) => host.readFile(path, encoding),
directoryExists: host.directoryExists && directoryExists,
getDirectories,
readDirectory,
createDirectory: host.createDirectory && createDirectory,
writeFile: host.writeFile && writeFile,
addOrDeleteFileOrDirectory,
addOrDeleteFile,
clearCache
};
function toPath(fileName: string) {
return ts.toPath(fileName, currentDirectory, getCanonicalFileName);
}
function getCachedFileSystemEntries(rootDirPath: Path): MutableFileSystemEntries | undefined {
return cachedReadDirectoryResult.get(rootDirPath);
}
function getCachedFileSystemEntriesForBaseDir(path: Path): MutableFileSystemEntries | undefined {
return getCachedFileSystemEntries(getDirectoryPath(path));
}
function getBaseNameOfFileName(fileName: string) {
return getBaseFileName(normalizePath(fileName));
}
function createCachedFileSystemEntries(rootDir: string, rootDirPath: Path) {
const resultFromHost: MutableFileSystemEntries = {
files: map(host.readDirectory(rootDir, /*extensions*/ undefined, /*exclude*/ undefined, /*include*/["*.*"]), getBaseNameOfFileName) || [],
directories: host.getDirectories(rootDir) || []
};
cachedReadDirectoryResult.set(rootDirPath, resultFromHost);
return resultFromHost;
}
/**
* If the readDirectory result was already cached, it returns that
* Otherwise gets result from host and caches it.
* The host request is done under try catch block to avoid caching incorrect result
*/
function tryReadDirectory(rootDir: string, rootDirPath: Path): MutableFileSystemEntries | undefined {
const cachedResult = getCachedFileSystemEntries(rootDirPath);
if (cachedResult) {
return cachedResult;
}
try {
return createCachedFileSystemEntries(rootDir, rootDirPath);
}
catch (_e) {
// If there is exception to read directories, dont cache the result and direct the calls to host
Debug.assert(!cachedReadDirectoryResult.has(rootDirPath));
return undefined;
}
}
function fileNameEqual(name1: string, name2: string) {
return getCanonicalFileName(name1) === getCanonicalFileName(name2);
}
function hasEntry(entries: ReadonlyArray<string>, name: string) {
return some(entries, file => fileNameEqual(file, name));
}
function updateFileSystemEntry(entries: string[], baseName: string, isValid: boolean) {
if (hasEntry(entries, baseName)) {
if (!isValid) {
return filterMutate(entries, entry => !fileNameEqual(entry, baseName));
}
}
else if (isValid) {
return entries.push(baseName);
}
}
function writeFile(fileName: string, data: string, writeByteOrderMark?: boolean): void {
const path = toPath(fileName);
const result = getCachedFileSystemEntriesForBaseDir(path);
if (result) {
updateFilesOfFileSystemEntry(result, getBaseNameOfFileName(fileName), /*fileExists*/ true);
}
return host.writeFile(fileName, data, writeByteOrderMark);
}
function fileExists(fileName: string): boolean {
const path = toPath(fileName);
const result = getCachedFileSystemEntriesForBaseDir(path);
return result && hasEntry(result.files, getBaseNameOfFileName(fileName)) ||
host.fileExists(fileName);
}
function directoryExists(dirPath: string): boolean {
const path = toPath(dirPath);
return cachedReadDirectoryResult.has(path) || host.directoryExists(dirPath);
}
function createDirectory(dirPath: string) {
const path = toPath(dirPath);
const result = getCachedFileSystemEntriesForBaseDir(path);
const baseFileName = getBaseNameOfFileName(dirPath);
if (result) {
updateFileSystemEntry(result.directories, baseFileName, /*isValid*/ true);
}
host.createDirectory(dirPath);
}
function getDirectories(rootDir: string): string[] {
const rootDirPath = toPath(rootDir);
const result = tryReadDirectory(rootDir, rootDirPath);
if (result) {
return result.directories.slice();
}
return host.getDirectories(rootDir);
}
function readDirectory(rootDir: string, extensions?: ReadonlyArray<string>, excludes?: ReadonlyArray<string>, includes?: ReadonlyArray<string>, depth?: number): string[] {
const rootDirPath = toPath(rootDir);
const result = tryReadDirectory(rootDir, rootDirPath);
if (result) {
return matchFiles(rootDir, extensions, excludes, includes, useCaseSensitiveFileNames, currentDirectory, depth, getFileSystemEntries);
}
return host.readDirectory(rootDir, extensions, excludes, includes, depth);
function getFileSystemEntries(dir: string) {
const path = toPath(dir);
if (path === rootDirPath) {
return result;
}
return tryReadDirectory(dir, path) || emptyFileSystemEntries;
}
}
function addOrDeleteFileOrDirectory(fileOrDirectory: string, fileOrDirectoryPath: Path) {
const existingResult = getCachedFileSystemEntries(fileOrDirectoryPath);
if (existingResult) {
// Just clear the cache for now
// For now just clear the cache, since this could mean that multiple level entries might need to be re-evaluated
clearCache();
return undefined;
}
const parentResult = getCachedFileSystemEntriesForBaseDir(fileOrDirectoryPath);
if (!parentResult) {
return undefined;
}
// This was earlier a file (hence not in cached directory contents)
// or we never cached the directory containing it
if (!host.directoryExists) {
// Since host doesnt support directory exists, clear the cache as otherwise it might not be same
clearCache();
return undefined;
}
const baseName = getBaseNameOfFileName(fileOrDirectory);
const fsQueryResult: FileAndDirectoryExistence = {
fileExists: host.fileExists(fileOrDirectoryPath),
directoryExists: host.directoryExists(fileOrDirectoryPath)
};
if (fsQueryResult.directoryExists || hasEntry(parentResult.directories, baseName)) {
// Folder added or removed, clear the cache instead of updating the folder and its structure
clearCache();
}
else {
// No need to update the directory structure, just files
updateFilesOfFileSystemEntry(parentResult, baseName, fsQueryResult.fileExists);
}
return fsQueryResult;
}
function addOrDeleteFile(fileName: string, filePath: Path, eventKind: FileWatcherEventKind) {
if (eventKind === FileWatcherEventKind.Changed) {
return;
}
const parentResult = getCachedFileSystemEntriesForBaseDir(filePath);
if (parentResult) {
updateFilesOfFileSystemEntry(parentResult, getBaseNameOfFileName(fileName), eventKind === FileWatcherEventKind.Created);
}
}
function updateFilesOfFileSystemEntry(parentResult: MutableFileSystemEntries, baseName: string, fileExists: boolean) {
updateFileSystemEntry(parentResult.files, baseName, fileExists);
}
function clearCache() {
cachedReadDirectoryResult.clear();
}
}
export enum ConfigFileProgramReloadLevel {
None,
/** Update the file name list from the disk */
@@ -90,53 +331,61 @@ namespace ts {
return program.isEmittedFile(file);
}
export function addFileWatcher(host: System, file: string, cb: FileWatcherCallback): FileWatcher {
export interface WatchFileHost {
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
}
export function addFileWatcher(host: WatchFileHost, file: string, cb: FileWatcherCallback): FileWatcher {
return host.watchFile(file, cb);
}
export function addFileWatcherWithLogging(host: System, file: string, cb: FileWatcherCallback, log: (s: string) => void): FileWatcher {
export function addFileWatcherWithLogging(host: WatchFileHost, file: string, cb: FileWatcherCallback, log: (s: string) => void): FileWatcher {
const watcherCaption = `FileWatcher:: `;
return createWatcherWithLogging(addFileWatcher, watcherCaption, log, /*logOnlyTrigger*/ false, host, file, cb);
}
export function addFileWatcherWithOnlyTriggerLogging(host: System, file: string, cb: FileWatcherCallback, log: (s: string) => void): FileWatcher {
export function addFileWatcherWithOnlyTriggerLogging(host: WatchFileHost, file: string, cb: FileWatcherCallback, log: (s: string) => void): FileWatcher {
const watcherCaption = `FileWatcher:: `;
return createWatcherWithLogging(addFileWatcher, watcherCaption, log, /*logOnlyTrigger*/ true, host, file, cb);
}
export type FilePathWatcherCallback = (fileName: string, eventKind: FileWatcherEventKind, filePath: Path) => void;
export function addFilePathWatcher(host: System, file: string, cb: FilePathWatcherCallback, path: Path): FileWatcher {
export function addFilePathWatcher(host: WatchFileHost, file: string, cb: FilePathWatcherCallback, path: Path): FileWatcher {
return host.watchFile(file, (fileName, eventKind) => cb(fileName, eventKind, path));
}
export function addFilePathWatcherWithLogging(host: System, file: string, cb: FilePathWatcherCallback, path: Path, log: (s: string) => void): FileWatcher {
export function addFilePathWatcherWithLogging(host: WatchFileHost, file: string, cb: FilePathWatcherCallback, path: Path, log: (s: string) => void): FileWatcher {
const watcherCaption = `FileWatcher:: `;
return createWatcherWithLogging(addFileWatcher, watcherCaption, log, /*logOnlyTrigger*/ false, host, file, cb, path);
}
export function addFilePathWatcherWithOnlyTriggerLogging(host: System, file: string, cb: FilePathWatcherCallback, path: Path, log: (s: string) => void): FileWatcher {
export function addFilePathWatcherWithOnlyTriggerLogging(host: WatchFileHost, file: string, cb: FilePathWatcherCallback, path: Path, log: (s: string) => void): FileWatcher {
const watcherCaption = `FileWatcher:: `;
return createWatcherWithLogging(addFileWatcher, watcherCaption, log, /*logOnlyTrigger*/ true, host, file, cb, path);
}
export function addDirectoryWatcher(host: System, directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags): FileWatcher {
export interface WatchDirectoryHost {
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
}
export function addDirectoryWatcher(host: WatchDirectoryHost, directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags): FileWatcher {
const recursive = (flags & WatchDirectoryFlags.Recursive) !== 0;
return host.watchDirectory(directory, cb, recursive);
}
export function addDirectoryWatcherWithLogging(host: System, directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags, log: (s: string) => void): FileWatcher {
export function addDirectoryWatcherWithLogging(host: WatchDirectoryHost, directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags, log: (s: string) => void): FileWatcher {
const watcherCaption = `DirectoryWatcher ${(flags & WatchDirectoryFlags.Recursive) !== 0 ? "recursive" : ""}:: `;
return createWatcherWithLogging(addDirectoryWatcher, watcherCaption, log, /*logOnlyTrigger*/ false, host, directory, cb, flags);
}
export function addDirectoryWatcherWithOnlyTriggerLogging(host: System, directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags, log: (s: string) => void): FileWatcher {
export function addDirectoryWatcherWithOnlyTriggerLogging(host: WatchDirectoryHost, directory: string, cb: DirectoryWatcherCallback, flags: WatchDirectoryFlags, log: (s: string) => void): FileWatcher {
const watcherCaption = `DirectoryWatcher ${(flags & WatchDirectoryFlags.Recursive) !== 0 ? "recursive" : ""}:: `;
return createWatcherWithLogging(addDirectoryWatcher, watcherCaption, log, /*logOnlyTrigger*/ true, host, directory, cb, flags);
}
type WatchCallback<T, U> = (fileName: string, cbOptional1?: T, optional?: U) => void;
type AddWatch<T, U> = (host: System, file: string, cb: WatchCallback<T, U>, optional?: U) => FileWatcher;
function createWatcherWithLogging<T, U>(addWatch: AddWatch<T, U>, watcherCaption: string, log: (s: string) => void, logOnlyTrigger: boolean, host: System, file: string, cb: WatchCallback<T, U>, optional?: U): FileWatcher {
type AddWatch<H, T, U> = (host: H, file: string, cb: WatchCallback<T, U>, optional?: U) => FileWatcher;
function createWatcherWithLogging<H, T, U>(addWatch: AddWatch<H, T, U>, watcherCaption: string, log: (s: string) => void, logOnlyTrigger: boolean, host: H, file: string, cb: WatchCallback<T, U>, optional?: U): FileWatcher {
const info = `PathInfo: ${file}`;
if (!logOnlyTrigger) {
log(`${watcherCaption}Added: ${info}`);
+2 -2
View File
@@ -131,13 +131,13 @@ function removeExpectedErrors(errors: string, cwd: string): string {
function isUnexpectedError(cwd: string) {
return (error: string[]) => {
ts.Debug.assertGreaterThanOrEqual(error.length, 1);
const match = error[0].match(/(.+\.ts)\((\d+),\d+\): error TS/);
const match = error[0].match(/(.+\.tsx?)\((\d+),\d+\): error TS/);
if (!match) {
return true;
}
const [, errorFile, lineNumberString] = match;
const lines = fs.readFileSync(path.join(cwd, errorFile), { encoding: "utf8" }).split("\n");
const lineNumber = parseInt(lineNumberString);
const lineNumber = parseInt(lineNumberString) - 1;
ts.Debug.assertGreaterThanOrEqual(lineNumber, 0);
ts.Debug.assertLessThan(lineNumber, lines.length);
const previousLine = lineNumber - 1 > 0 ? lines[lineNumber - 1] : "";
+44 -46
View File
@@ -23,7 +23,7 @@ namespace FourSlash {
ts.disableIncrementalParsing = false;
// Represents a parsed source file with metadata
export interface FourSlashFile {
interface FourSlashFile {
// The contents of the file (with markers, etc stripped out)
content: string;
fileName: string;
@@ -34,7 +34,7 @@ namespace FourSlash {
}
// Represents a set of parsed source files and options
export interface FourSlashData {
interface FourSlashData {
// Global options (name/value pairs)
globalOptions: Harness.TestCaseParser.CompilerSettings;
@@ -59,7 +59,7 @@ namespace FourSlash {
export interface Marker {
fileName: string;
position: number;
data?: any;
data?: {};
}
export interface Range {
@@ -89,21 +89,6 @@ namespace FourSlash {
end: number;
}
export import IndentStyle = ts.IndentStyle;
const entityMap = ts.createMapFromTemplate({
"&": "&amp;",
"\"": "&quot;",
"'": "&#39;",
"/": "&#47;",
"<": "&lt;",
">": "&gt;"
});
export function escapeXmlAttributeValue(s: string) {
return s.replace(/[&<>"'\/]/g, ch => entityMap.get(ch));
}
// Name of testcase metadata including ts.CompilerOptions properties that will be used by globalOptions
// To add additional option, add property into the testOptMetadataNames, refer the property in either globalMetadataNames or fileMetadataNames
// Add cases into convertGlobalOptionsToCompilationsSettings function for the compiler to acknowledge such option from meta data
@@ -1079,7 +1064,7 @@ namespace FourSlash {
for (const reference of expectedReferences) {
const { fileName, start, end } = reference;
if (reference.marker && reference.marker.data) {
const { isWriteAccess, isDefinition } = reference.marker.data;
const { isWriteAccess, isDefinition } = reference.marker.data as { isWriteAccess?: boolean, isDefinition?: boolean };
this.verifyReferencesWorker(actualReferences, fileName, start, end, isWriteAccess, isDefinition);
}
else {
@@ -1102,25 +1087,35 @@ namespace FourSlash {
}
public verifyReferenceGroups(startRanges: Range | Range[], parts: FourSlashInterface.ReferenceGroup[]): void {
const fullExpected = ts.map(parts, ({ definition, ranges }) => ({ definition, ranges: ranges.map(rangeToReferenceEntry) }));
interface ReferenceGroupJson {
definition: string | { text: string, range: ts.TextSpan };
references: ts.ReferenceEntry[];
}
const fullExpected = ts.map<FourSlashInterface.ReferenceGroup, ReferenceGroupJson>(parts, ({ definition, ranges }) => ({
definition: typeof definition === "string" ? definition : { ...definition, range: textSpanFromRange(definition.range) },
references: ranges.map<ts.ReferenceEntry>(r => {
const { isWriteAccess = false, isDefinition = false, isInString } = (r.marker && r.marker.data || {}) as { isWriteAccess?: boolean, isDefinition?: boolean, isInString?: true };
return {
isWriteAccess,
isDefinition,
fileName: r.fileName,
textSpan: textSpanFromRange(r),
...(isInString ? { isInString: true } : undefined),
};
}),
}));
for (const startRange of toArray(startRanges)) {
this.goToRangeStart(startRange);
const fullActual = ts.map(this.findReferencesAtCaret(), ({ definition, references }) => ({
definition: definition.displayParts.map(d => d.text).join(""),
ranges: references
}));
const fullActual = ts.map<ts.ReferencedSymbol, ReferenceGroupJson>(this.findReferencesAtCaret(), ({ definition, references }, i) => {
const text = definition.displayParts.map(d => d.text).join("");
return {
definition: typeof fullExpected[i].definition === "string" ? text : { text, range: definition.textSpan },
references,
};
});
this.assertObjectsEqual(fullActual, fullExpected);
}
function rangeToReferenceEntry(r: Range): ts.ReferenceEntry {
const { isWriteAccess, isDefinition, isInString } = (r.marker && r.marker.data) || { isWriteAccess: false, isDefinition: false, isInString: undefined };
const result: ts.ReferenceEntry = { fileName: r.fileName, textSpan: { start: r.start, length: r.end - r.start }, isWriteAccess: !!isWriteAccess, isDefinition: !!isDefinition };
if (isInString !== undefined) {
result.isInString = isInString;
}
return result;
}
}
public verifyNoReferences(markerNameOrRange?: string | Range) {
@@ -1139,7 +1134,7 @@ namespace FourSlash {
}
}
public verifySingleReferenceGroup(definition: string, ranges?: Range[]) {
public verifySingleReferenceGroup(definition: FourSlashInterface.ReferenceGroupDefinition, ranges?: Range[]) {
ranges = ranges || this.getRanges();
this.verifyReferenceGroups(ranges, [{ definition, ranges }]);
}
@@ -1305,8 +1300,13 @@ Actual: ${stringify(fullActual)}`);
}
public verifyRangesAreRenameLocations(options?: Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: Range[] }) {
const ranges = ts.isArray(options) ? options : options && options.ranges || this.getRanges();
this.verifyRenameLocations(ranges, { ranges, ...options });
if (ts.isArray(options)) {
this.verifyRenameLocations(options, options);
}
else {
const ranges = options && options.ranges || this.getRanges();
this.verifyRenameLocations(ranges, { ranges, ...options });
}
}
public verifyRenameLocations(startRanges: Range | Range[], options: Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges: Range[] }) {
@@ -2568,18 +2568,14 @@ Actual: ${stringify(fullActual)}`);
const originalContent = scriptInfo.content;
for (const codeFix of codeFixes) {
this.applyEdits(codeFix.changes[0].fileName, codeFix.changes[0].textChanges, /*isFormattingEdit*/ false);
let text = this.rangeText(ranges[0]);
// TODO:GH#18445 (remove this line to see errors in many `importNameCodeFix` tests)
text = text.replace(/\r\n/g, "\n");
const text = this.rangeText(ranges[0]);
actualTextArray.push(text);
scriptInfo.updateContent(originalContent);
}
const sortedExpectedArray = expectedTextArray.sort();
const sortedActualArray = actualTextArray.sort();
if (sortedExpectedArray.length !== sortedActualArray.length) {
this.raiseError(`Expected ${sortedExpectedArray.length} import fixes, got ${sortedActualArray.length}`);
if (expectedTextArray.length !== actualTextArray.length) {
this.raiseError(`Expected ${expectedTextArray.length} import fixes, got ${actualTextArray.length}`);
}
ts.zipWith(sortedExpectedArray, sortedActualArray, (expected, actual, index) => {
ts.zipWith(expectedTextArray, actualTextArray, (expected, actual, index) => {
if (expected !== actual) {
this.raiseError(`Import fix at index ${index} doesn't match.\n${showTextDiff(expected, actual)}`);
}
@@ -4077,7 +4073,7 @@ namespace FourSlashInterface {
this.state.verifyNoReferences(markerNameOrRange);
}
public singleReferenceGroup(definition: string, ranges?: FourSlash.Range[]) {
public singleReferenceGroup(definition: ReferenceGroupDefinition, ranges?: FourSlash.Range[]) {
this.state.verifySingleReferenceGroup(definition, ranges);
}
@@ -4589,10 +4585,12 @@ namespace FourSlashInterface {
}
export interface ReferenceGroup {
definition: string;
definition: ReferenceGroupDefinition;
ranges: FourSlash.Range[];
}
export type ReferenceGroupDefinition = string | { text: string, range: FourSlash.Range };
export interface ApplyRefactorOptions {
refactorName: string;
actionName: string;
+81 -6
View File
@@ -41,22 +41,97 @@ namespace ts {
program = updateProgramFile(program, "/b.ts", "namespace B { export const x = 1; }");
assertChanges(["/b.js", "/a.js"]);
});
it("keeps the file in affected files if cancellation token throws during the operation", () => {
const files: NamedSourceText[] = [
{ name: "/a.ts", text: SourceText.New("", 'import { b } from "./b";', "") },
{ name: "/b.ts", text: SourceText.New("", ' import { c } from "./c";', "export const b = c;") },
{ name: "/c.ts", text: SourceText.New("", "", "export const c = 0;") },
{ name: "/d.ts", text: SourceText.New("", "", "export const dd = 0;") },
{ name: "/e.ts", text: SourceText.New("", "", "export const ee = 0;") },
];
let program = newProgram(files, ["/d.ts", "/e.ts", "/a.ts"], {});
const assertChanges = makeAssertChangesWithCancellationToken(() => program);
// No cancellation
assertChanges(["/d.js", "/e.js", "/c.js", "/b.js", "/a.js"]);
// cancel when emitting a.ts
program = updateProgramFile(program, "/a.ts", "export function foo() { }");
assertChanges(["/a.js"], 0);
// Change d.ts and verify previously pending a.ts is emitted as well
program = updateProgramFile(program, "/d.ts", "export function bar() { }");
assertChanges(["/a.js", "/d.js"]);
// Cancel when emitting b.js
program = updateProgramFile(program, "/b.ts", "export class b { foo() { c + 1; } }");
program = updateProgramFile(program, "/d.ts", "export function bar2() { }");
assertChanges(["/d.js", "/b.js", "/a.js"], 1);
// Change e.ts and verify previously b.js as well as a.js get emitted again since previous change was consumed completely but not d.ts
program = updateProgramFile(program, "/e.ts", "export function bar3() { }");
assertChanges(["/b.js", "/a.js", "/e.js"]);
// Cancel in the middle of affected files list after b.js emit
program = updateProgramFile(program, "/b.ts", "export class b { foo2() { c + 1; } }");
assertChanges(["/b.js", "/a.js"], 1);
// Change e.ts and verify previously b.js as well as a.js get emitted again since previous change was consumed completely but not d.ts
program = updateProgramFile(program, "/e.ts", "export function bar5() { }");
assertChanges(["/b.js", "/a.js", "/e.js"]);
});
});
function makeAssertChanges(getProgram: () => Program): (fileNames: ReadonlyArray<string>) => void {
const builder = createBuilder({
getCanonicalFileName: identity,
computeHash: identity
});
const host: BuilderProgramHost = { useCaseSensitiveFileNames: returnTrue };
let builderProgram: EmitAndSemanticDiagnosticsBuilderProgram | undefined;
return fileNames => {
const program = getProgram();
builder.updateProgram(program);
builderProgram = createEmitAndSemanticDiagnosticsBuilderProgram(program, host, builderProgram);
const outputFileNames: string[] = [];
builder.emitChangedFiles(program, fileName => outputFileNames.push(fileName));
// tslint:disable-next-line no-empty
while (builderProgram.emitNextAffectedFile(fileName => outputFileNames.push(fileName))) {
}
assert.deepEqual(outputFileNames, fileNames);
};
}
function makeAssertChangesWithCancellationToken(getProgram: () => Program): (fileNames: ReadonlyArray<string>, cancelAfterEmitLength?: number) => void {
const host: BuilderProgramHost = { useCaseSensitiveFileNames: returnTrue };
let builderProgram: EmitAndSemanticDiagnosticsBuilderProgram | undefined;
let cancel = false;
const cancellationToken: CancellationToken = {
isCancellationRequested: () => cancel,
throwIfCancellationRequested: () => {
if (cancel) {
throw new OperationCanceledException();
}
},
};
return (fileNames, cancelAfterEmitLength?: number) => {
cancel = false;
let operationWasCancelled = false;
const program = getProgram();
builderProgram = createEmitAndSemanticDiagnosticsBuilderProgram(program, host, builderProgram);
const outputFileNames: string[] = [];
try {
// tslint:disable-next-line no-empty
do {
assert.isFalse(cancel);
if (outputFileNames.length === cancelAfterEmitLength) {
cancel = true;
}
} while (builderProgram.emitNextAffectedFile(fileName => outputFileNames.push(fileName), cancellationToken));
}
catch (e) {
assert.isFalse(operationWasCancelled);
assert(e instanceof OperationCanceledException, e.toString());
operationWasCancelled = true;
}
assert.equal(cancel, operationWasCancelled);
assert.equal(operationWasCancelled, fileNames.length > cancelAfterEmitLength);
assert.deepEqual(outputFileNames, fileNames.slice(0, cancelAfterEmitLength));
};
}
function updateProgramFile(program: ProgramWithSourceTexts, fileName: string, fileContent: string): ProgramWithSourceTexts {
return updateProgram(program, program.getRootFileNames(), program.getCompilerOptions(), files => {
updateProgramText(files, fileName, fileContent);
@@ -273,6 +273,13 @@ let i: I = [#|{ a: 1 }|];
const myObj: { member(x: number, y: string): void } = {
member: [#|(x, y) => x + y|],
}
`);
testExtractConstant("extractConstant_CaseClauseExpression", `
switch (1) {
case [#|1|]:
break;
}
`);
});
+52
View File
@@ -365,6 +365,58 @@ switch (x) {
refactor.extractSymbol.Messages.cannotExtractRange.message
]);
testExtractRangeFailed("extractRangeFailed14",
`
switch(1) {
case [#|1:
break;|]
}
`,
[
refactor.extractSymbol.Messages.cannotExtractRange.message
]);
testExtractRangeFailed("extractRangeFailed15",
`
switch(1) {
case [#|1:
break|];
}
`,
[
refactor.extractSymbol.Messages.cannotExtractRange.message
]);
// Documentation only - it would be nice if the result were [$|1|]
testExtractRangeFailed("extractRangeFailed16",
`
switch(1) {
[#|case 1|]:
break;
}
`,
[
refactor.extractSymbol.Messages.cannotExtractRange.message
]);
// Documentation only - it would be nice if the result were [$|1|]
testExtractRangeFailed("extractRangeFailed17",
`
switch(1) {
[#|case 1:|]
break;
}
`,
[
refactor.extractSymbol.Messages.cannotExtractRange.message
]);
testExtractRangeFailed("extractRangeFailed18",
`[#|{ 1;|] }`,
[
refactor.extractSymbol.Messages.cannotExtractRange.message
]);
testExtractRangeFailed("extract-method-not-for-token-expression-statement", `[#|a|]`, [refactor.extractSymbol.Messages.cannotExtractIdentifier.message]);
});
}
@@ -121,7 +121,6 @@ namespace ts {
const sourceFile = program.getSourceFile(path);
const context: RefactorContext = {
cancellationToken: { throwIfCancellationRequested: noop, isCancellationRequested: returnFalse },
newLineCharacter,
program,
file: sourceFile,
startPosition: selectionRange.start,
@@ -185,7 +184,6 @@ namespace ts {
const sourceFile = program.getSourceFile(f.path);
const context: RefactorContext = {
cancellationToken: { throwIfCancellationRequested: noop, isCancellationRequested: returnFalse },
newLineCharacter,
program,
file: sourceFile,
startPosition: selectionRange.start,
+10 -22
View File
@@ -884,7 +884,6 @@ namespace ts {
});
});
import TestSystem = ts.TestFSWithWatch.TestServerHost;
type FileOrFolder = ts.TestFSWithWatch.FileOrFolder;
import createTestSystem = ts.TestFSWithWatch.createWatchedSystem;
import libFile = ts.TestFSWithWatch.libFile;
@@ -910,30 +909,21 @@ namespace ts {
return JSON.parse(JSON.stringify(filesOrOptions));
}
function createWatchingSystemHost(host: TestSystem) {
return ts.createWatchingSystemHost(/*pretty*/ undefined, host);
}
function verifyProgramWithoutConfigFile(watchingSystemHost: WatchingSystemHost, rootFiles: string[], options: CompilerOptions) {
const program = createWatchModeWithoutConfigFile(rootFiles, options, watchingSystemHost)();
function verifyProgramWithoutConfigFile(system: System, rootFiles: string[], options: CompilerOptions) {
const program = createWatchProgram(createWatchCompilerHostOfFilesAndCompilerOptions(rootFiles, options, system)).getCurrentProgram().getProgram();
verifyProgramIsUptoDate(program, duplicate(rootFiles), duplicate(options));
}
function getConfigParseResult(watchingSystemHost: WatchingSystemHost, configFileName: string) {
return parseConfigFile(configFileName, {}, watchingSystemHost.system, watchingSystemHost.reportDiagnostic, watchingSystemHost.reportWatchDiagnostic);
}
function verifyProgramWithConfigFile(watchingSystemHost: WatchingSystemHost, configFile: string) {
const result = getConfigParseResult(watchingSystemHost, configFile);
const program = createWatchModeWithConfigFile(result, {}, watchingSystemHost)();
const { fileNames, options } = getConfigParseResult(watchingSystemHost, configFile);
function verifyProgramWithConfigFile(system: System, configFileName: string) {
const program = createWatchProgram(createWatchCompilerHostOfConfigFile(configFileName, {}, system)).getCurrentProgram().getProgram();
const { fileNames, options } = parseConfigFileWithSystem(configFileName, {}, system, notImplemented);
verifyProgramIsUptoDate(program, fileNames, options);
}
function verifyProgram(files: FileOrFolder[], rootFiles: string[], options: CompilerOptions, configFile: string) {
const watchingSystemHost = createWatchingSystemHost(createTestSystem(files));
verifyProgramWithoutConfigFile(watchingSystemHost, rootFiles, options);
verifyProgramWithConfigFile(watchingSystemHost, configFile);
const system = createTestSystem(files);
verifyProgramWithoutConfigFile(system, rootFiles, options);
verifyProgramWithConfigFile(system, configFile);
}
it("has empty options", () => {
@@ -1044,11 +1034,9 @@ namespace ts {
};
const configFile: FileOrFolder = {
path: "/src/tsconfig.json",
content: JSON.stringify({ compilerOptions, include: ["packages/**/ *.ts"] })
content: JSON.stringify({ compilerOptions, include: ["packages/**/*.ts"] })
};
const watchingSystemHost = createWatchingSystemHost(createTestSystem([app, module1, module2, module3, libFile, configFile]));
verifyProgramWithConfigFile(watchingSystemHost, configFile.path);
verifyProgramWithConfigFile(createTestSystem([app, module1, module2, module3, libFile, configFile]), configFile.path);
});
});
}
+3
View File
@@ -4,6 +4,7 @@ const expect: typeof _chai.expect = _chai.expect;
namespace ts.server {
let lastWrittenToHost: string;
const noopFileWatcher: FileWatcher = { close: noop };
const mockHost: ServerHost = {
args: [],
newLine: "\n",
@@ -26,6 +27,8 @@ namespace ts.server {
setImmediate: () => 0,
clearImmediate: noop,
createHash: Harness.mockHash,
watchFile: () => noopFileWatcher,
watchDirectory: () => noopFileWatcher
};
class TestSession extends Session {
+60 -72
View File
@@ -22,24 +22,16 @@ namespace ts.tscWatch {
checkFileNames(`Program rootFileNames`, program.getRootFileNames(), expectedFiles);
}
function createWatchingSystemHost(system: WatchedSystem) {
return ts.createWatchingSystemHost(/*pretty*/ undefined, system);
function createWatchOfConfigFile(configFileName: string, host: WatchedSystem, maxNumberOfFilesToIterateForInvalidation?: number) {
const compilerHost = ts.createWatchCompilerHostOfConfigFile(configFileName, {}, host);
compilerHost.maxNumberOfFilesToIterateForInvalidation = maxNumberOfFilesToIterateForInvalidation;
const watch = createWatchProgram(compilerHost);
return () => watch.getCurrentProgram().getProgram();
}
function parseConfigFile(configFileName: string, watchingSystemHost: WatchingSystemHost) {
return ts.parseConfigFile(configFileName, {}, watchingSystemHost.system, watchingSystemHost.reportDiagnostic, watchingSystemHost.reportWatchDiagnostic);
}
function createWatchModeWithConfigFile(configFilePath: string, host: WatchedSystem, maxNumberOfFilesToIterateForInvalidation?: number) {
const watchingSystemHost = createWatchingSystemHost(host);
watchingSystemHost.maxNumberOfFilesToIterateForInvalidation = maxNumberOfFilesToIterateForInvalidation;
const configFileResult = parseConfigFile(configFilePath, watchingSystemHost);
return ts.createWatchModeWithConfigFile(configFileResult, {}, watchingSystemHost);
}
function createWatchModeWithoutConfigFile(fileNames: string[], host: WatchedSystem, options: CompilerOptions = {}) {
const watchingSystemHost = createWatchingSystemHost(host);
return ts.createWatchModeWithoutConfigFile(fileNames, options, watchingSystemHost);
function createWatchOfFilesAndCompilerOptions(rootFiles: string[], host: WatchedSystem, options: CompilerOptions = {}) {
const watch = createWatchProgram(createWatchCompilerHostOfFilesAndCompilerOptions(rootFiles, options, host));
return () => watch.getCurrentProgram().getProgram();
}
function getEmittedLineForMultiFileOutput(file: FileOrFolder, host: WatchedSystem) {
@@ -218,7 +210,7 @@ namespace ts.tscWatch {
content: `export let x: number`
};
const host = createWatchedSystem([appFile, moduleFile, libFile]);
const watch = createWatchModeWithoutConfigFile([appFile.path], host);
const watch = createWatchOfFilesAndCompilerOptions([appFile.path], host);
checkProgramActualFiles(watch(), [appFile.path, libFile.path, moduleFile.path]);
@@ -243,7 +235,7 @@ namespace ts.tscWatch {
const host = createWatchedSystem([f1, config], { useCaseSensitiveFileNames: false });
const upperCaseConfigFilePath = combinePaths(getDirectoryPath(config.path).toUpperCase(), getBaseFileName(config.path));
const watch = createWatchModeWithConfigFile(upperCaseConfigFilePath, host);
const watch = createWatchOfConfigFile(upperCaseConfigFilePath, host);
checkProgramActualFiles(watch(), [combinePaths(getDirectoryPath(upperCaseConfigFilePath), getBaseFileName(f1.path))]);
});
@@ -272,14 +264,10 @@ namespace ts.tscWatch {
};
const host = createWatchedSystem([configFile, libFile, file1, file2, file3]);
const watchingSystemHost = createWatchingSystemHost(host);
const configFileResult = parseConfigFile(configFile.path, watchingSystemHost);
assert.equal(configFileResult.errors.length, 0, `expect no errors in config file, got ${JSON.stringify(configFileResult.errors)}`);
const watch = createWatchProgram(createWatchCompilerHostOfConfigFile(configFile.path, {}, host, /*createProgram*/ undefined, notImplemented));
const watch = ts.createWatchModeWithConfigFile(configFileResult, {}, watchingSystemHost);
checkProgramActualFiles(watch(), [file1.path, libFile.path, file2.path]);
checkProgramRootFiles(watch(), [file1.path, file2.path]);
checkProgramActualFiles(watch.getCurrentProgram().getProgram(), [file1.path, libFile.path, file2.path]);
checkProgramRootFiles(watch.getCurrentProgram().getProgram(), [file1.path, file2.path]);
checkWatchedFiles(host, [configFile.path, file1.path, file2.path, libFile.path]);
const configDir = getDirectoryPath(configFile.path);
checkWatchedDirectories(host, [configDir, combinePaths(configDir, projectSystem.nodeModulesAtTypes)], /*recursive*/ true);
@@ -295,7 +283,7 @@ namespace ts.tscWatch {
content: `{}`
};
const host = createWatchedSystem([commonFile1, libFile, configFile]);
const watch = createWatchModeWithConfigFile(configFile.path, host);
const watch = createWatchOfConfigFile(configFile.path, host);
const configDir = getDirectoryPath(configFile.path);
checkWatchedDirectories(host, [configDir, combinePaths(configDir, projectSystem.nodeModulesAtTypes)], /*recursive*/ true);
@@ -319,7 +307,7 @@ namespace ts.tscWatch {
}`
};
const host = createWatchedSystem([commonFile1, commonFile2, configFile]);
const watch = createWatchModeWithConfigFile(configFile.path, host);
const watch = createWatchOfConfigFile(configFile.path, host);
const commonFile3 = "/a/b/commonFile3.ts";
checkProgramRootFiles(watch(), [commonFile1.path, commonFile3]);
@@ -332,7 +320,7 @@ namespace ts.tscWatch {
content: `{}`
};
const host = createWatchedSystem([commonFile1, commonFile2, configFile]);
const watch = createWatchModeWithConfigFile(configFile.path, host);
const watch = createWatchOfConfigFile(configFile.path, host);
checkProgramRootFiles(watch(), [commonFile1.path, commonFile2.path]);
// delete commonFile2
@@ -354,7 +342,7 @@ namespace ts.tscWatch {
let x = y`
};
const host = createWatchedSystem([file1, libFile]);
const watch = createWatchModeWithoutConfigFile([file1.path], host);
const watch = createWatchOfFilesAndCompilerOptions([file1.path], host);
checkProgramRootFiles(watch(), [file1.path]);
checkProgramActualFiles(watch(), [file1.path, libFile.path]);
@@ -380,7 +368,7 @@ namespace ts.tscWatch {
};
const files = [commonFile1, commonFile2, configFile];
const host = createWatchedSystem(files);
const watch = createWatchModeWithConfigFile(configFile.path, host);
const watch = createWatchOfConfigFile(configFile.path, host);
checkProgramRootFiles(watch(), [commonFile1.path, commonFile2.path]);
configFile.content = `{
@@ -407,7 +395,7 @@ namespace ts.tscWatch {
};
const host = createWatchedSystem([commonFile1, commonFile2, excludedFile1, configFile]);
const watch = createWatchModeWithConfigFile(configFile.path, host);
const watch = createWatchOfConfigFile(configFile.path, host);
checkProgramRootFiles(watch(), [commonFile1.path, commonFile2.path]);
});
@@ -435,7 +423,7 @@ namespace ts.tscWatch {
};
const files = [file1, nodeModuleFile, classicModuleFile, configFile];
const host = createWatchedSystem(files);
const watch = createWatchModeWithConfigFile(configFile.path, host);
const watch = createWatchOfConfigFile(configFile.path, host);
checkProgramRootFiles(watch(), [file1.path]);
checkProgramActualFiles(watch(), [file1.path, nodeModuleFile.path]);
@@ -463,7 +451,7 @@ namespace ts.tscWatch {
}`
};
const host = createWatchedSystem([commonFile1, commonFile2, libFile, configFile]);
const watch = createWatchModeWithConfigFile(configFile.path, host);
const watch = createWatchOfConfigFile(configFile.path, host);
checkProgramRootFiles(watch(), [commonFile1.path, commonFile2.path]);
});
@@ -481,7 +469,7 @@ namespace ts.tscWatch {
content: `export let y = 1;`
};
const host = createWatchedSystem([file1, file2, file3]);
const watch = createWatchModeWithoutConfigFile([file1.path], host);
const watch = createWatchOfFilesAndCompilerOptions([file1.path], host);
checkProgramRootFiles(watch(), [file1.path]);
checkProgramActualFiles(watch(), [file1.path, file2.path]);
@@ -510,7 +498,7 @@ namespace ts.tscWatch {
content: `export let y = 1;`
};
const host = createWatchedSystem([file1, file2, file3]);
const watch = createWatchModeWithoutConfigFile([file1.path], host);
const watch = createWatchOfFilesAndCompilerOptions([file1.path], host);
checkProgramActualFiles(watch(), [file1.path, file2.path, file3.path]);
host.reloadFS([file1, file3]);
@@ -533,7 +521,7 @@ namespace ts.tscWatch {
content: `export let y = 1;`
};
const host = createWatchedSystem([file1, file2, file3]);
const watch = createWatchModeWithoutConfigFile([file1.path, file3.path], host);
const watch = createWatchOfFilesAndCompilerOptions([file1.path, file3.path], host);
checkProgramActualFiles(watch(), [file1.path, file2.path, file3.path]);
host.reloadFS([file1, file3]);
@@ -561,7 +549,7 @@ namespace ts.tscWatch {
};
const host = createWatchedSystem([file1, file2, file3, configFile]);
const watch = createWatchModeWithConfigFile(configFile.path, host);
const watch = createWatchOfConfigFile(configFile.path, host);
checkProgramRootFiles(watch(), [file2.path, file3.path]);
checkProgramActualFiles(watch(), [file1.path, file2.path, file3.path]);
@@ -583,10 +571,10 @@ namespace ts.tscWatch {
content: "export let y = 1;"
};
const host = createWatchedSystem([file1, file2, file3]);
const watch = createWatchModeWithoutConfigFile([file2.path, file3.path], host);
const watch = createWatchOfFilesAndCompilerOptions([file2.path, file3.path], host);
checkProgramActualFiles(watch(), [file2.path, file3.path]);
const watch2 = createWatchModeWithoutConfigFile([file1.path], host);
const watch2 = createWatchOfFilesAndCompilerOptions([file1.path], host);
checkProgramActualFiles(watch2(), [file1.path, file2.path, file3.path]);
// Previous program shouldnt be updated
@@ -609,7 +597,7 @@ namespace ts.tscWatch {
};
const host = createWatchedSystem([file1, configFile]);
const watch = createWatchModeWithConfigFile(configFile.path, host);
const watch = createWatchOfConfigFile(configFile.path, host);
checkProgramActualFiles(watch(), [file1.path]);
host.reloadFS([file1, file2, configFile]);
@@ -634,7 +622,7 @@ namespace ts.tscWatch {
};
const host = createWatchedSystem([file1, file2, configFile]);
const watch = createWatchModeWithConfigFile(configFile.path, host);
const watch = createWatchOfConfigFile(configFile.path, host);
checkProgramActualFiles(watch(), [file1.path]);
@@ -664,7 +652,7 @@ namespace ts.tscWatch {
};
const host = createWatchedSystem([file1, file2, configFile]);
const watch = createWatchModeWithConfigFile(configFile.path, host);
const watch = createWatchOfConfigFile(configFile.path, host);
checkProgramActualFiles(watch(), [file1.path, file2.path]);
const modifiedConfigFile = {
@@ -692,7 +680,7 @@ namespace ts.tscWatch {
content: JSON.stringify({ compilerOptions: {} })
};
const host = createWatchedSystem([file1, file2, libFile, config]);
const watch = createWatchModeWithConfigFile(config.path, host);
const watch = createWatchOfConfigFile(config.path, host);
checkProgramActualFiles(watch(), [file1.path, file2.path, libFile.path]);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
@@ -716,7 +704,7 @@ namespace ts.tscWatch {
content: "{"
};
const host = createWatchedSystem([file1, corruptedConfig]);
const watch = createWatchModeWithConfigFile(corruptedConfig.path, host);
const watch = createWatchOfConfigFile(corruptedConfig.path, host);
checkProgramActualFiles(watch(), [file1.path]);
});
@@ -766,7 +754,7 @@ namespace ts.tscWatch {
})
};
const host = createWatchedSystem([libES5, libES2015Promise, app, config1], { executingFilePath: "/compiler/tsc.js" });
const watch = createWatchModeWithConfigFile(config1.path, host);
const watch = createWatchOfConfigFile(config1.path, host);
checkProgramActualFiles(watch(), [libES5.path, app.path]);
@@ -791,7 +779,7 @@ namespace ts.tscWatch {
})
};
const host = createWatchedSystem([f, config]);
const watch = createWatchModeWithConfigFile(config.path, host);
const watch = createWatchOfConfigFile(config.path, host);
checkProgramActualFiles(watch(), [f.path]);
});
@@ -805,7 +793,7 @@ namespace ts.tscWatch {
content: 'import * as T from "./moduleFile"; T.bar();'
};
const host = createWatchedSystem([moduleFile, file1, libFile]);
const watch = createWatchModeWithoutConfigFile([file1.path], host);
const watch = createWatchOfFilesAndCompilerOptions([file1.path], host);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
const moduleFileOldPath = moduleFile.path;
@@ -837,7 +825,7 @@ namespace ts.tscWatch {
content: `{}`
};
const host = createWatchedSystem([moduleFile, file1, configFile, libFile]);
const watch = createWatchModeWithConfigFile(configFile.path, host);
const watch = createWatchOfConfigFile(configFile.path, host);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
const moduleFileOldPath = moduleFile.path;
@@ -872,7 +860,7 @@ namespace ts.tscWatch {
path: "/a/c"
};
const host = createWatchedSystem([f1, config, node, cwd], { currentDirectory: cwd.path });
const watch = createWatchModeWithConfigFile(config.path, host);
const watch = createWatchOfConfigFile(config.path, host);
checkProgramActualFiles(watch(), [f1.path, node.path]);
});
@@ -887,7 +875,7 @@ namespace ts.tscWatch {
content: 'import * as T from "./moduleFile"; T.bar();'
};
const host = createWatchedSystem([file1, libFile]);
const watch = createWatchModeWithoutConfigFile([file1.path], host);
const watch = createWatchOfFilesAndCompilerOptions([file1.path], host);
checkOutputErrors(host, [
getDiagnosticModuleNotFoundOfFile(watch(), file1, "./moduleFile")
@@ -914,7 +902,7 @@ namespace ts.tscWatch {
};
const host = createWatchedSystem([file, configFile, libFile]);
const watch = createWatchModeWithConfigFile(configFile.path, host);
const watch = createWatchOfConfigFile(configFile.path, host);
checkOutputErrors(host, [
getUnknownCompilerOption(watch(), configFile, "foo"),
getUnknownCompilerOption(watch(), configFile, "allowJS")
@@ -934,7 +922,7 @@ namespace ts.tscWatch {
};
const host = createWatchedSystem([file, configFile, libFile]);
createWatchModeWithConfigFile(configFile.path, host);
createWatchOfConfigFile(configFile.path, host);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
});
@@ -951,7 +939,7 @@ namespace ts.tscWatch {
};
const host = createWatchedSystem([file, configFile, libFile]);
const watch = createWatchModeWithConfigFile(configFile.path, host);
const watch = createWatchOfConfigFile(configFile.path, host);
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
configFile.content = `{
@@ -987,7 +975,7 @@ namespace ts.tscWatch {
};
const host = createWatchedSystem([file1, configFile, libFile]);
const watch = createWatchModeWithConfigFile(configFile.path, host);
const watch = createWatchOfConfigFile(configFile.path, host);
checkProgramActualFiles(watch(), [libFile.path]);
});
@@ -1013,7 +1001,7 @@ namespace ts.tscWatch {
content: `export const x: number`
};
const host = createWatchedSystem([f, config, t1, t2], { currentDirectory: getDirectoryPath(f.path) });
const watch = createWatchModeWithConfigFile(config.path, host);
const watch = createWatchOfConfigFile(config.path, host);
checkProgramActualFiles(watch(), [t1.path, t2.path]);
});
@@ -1024,7 +1012,7 @@ namespace ts.tscWatch {
content: "let x = 1"
};
const host = createWatchedSystem([f, libFile]);
const watch = createWatchModeWithoutConfigFile([f.path], host, { allowNonTsExtensions: true });
const watch = createWatchOfFilesAndCompilerOptions([f.path], host, { allowNonTsExtensions: true });
checkProgramActualFiles(watch(), [f.path, libFile.path]);
});
@@ -1052,7 +1040,7 @@ namespace ts.tscWatch {
const files = [file, libFile, configFile];
const host = createWatchedSystem(files);
const watch = createWatchModeWithConfigFile(configFile.path, host);
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")
@@ -1089,7 +1077,7 @@ namespace ts.tscWatch {
})
};
const host = createWatchedSystem([file1, file2, libFile, tsconfig], { currentDirectory: proj });
const watch = createWatchModeWithConfigFile(tsconfig.path, host, /*maxNumberOfFilesToIterateForInvalidation*/1);
const watch = createWatchOfConfigFile(tsconfig.path, host, /*maxNumberOfFilesToIterateForInvalidation*/1);
checkProgramActualFiles(watch(), [file1.path, file2.path, libFile.path]);
assert.isTrue(host.fileExists("build/file1.js"));
@@ -1138,7 +1126,7 @@ namespace ts.tscWatch {
const files = [f1, f2, config, libFile];
host.reloadFS(files);
createWatchModeWithConfigFile(config.path, host);
createWatchOfConfigFile(config.path, host);
const allEmittedLines = getEmittedLines(files);
checkOutputContains(host, allEmittedLines);
@@ -1200,7 +1188,7 @@ namespace ts.tscWatch {
mapOfFilesWritten.set(p, count ? count + 1 : 1);
return originalWriteFile(p, content);
};
createWatchModeWithConfigFile(configFile.path, host);
createWatchOfConfigFile(configFile.path, host);
if (useOutFile) {
// Only out file
assert.equal(mapOfFilesWritten.size, 1);
@@ -1284,7 +1272,7 @@ namespace ts.tscWatch {
host.reloadFS(firstReloadFileList ? getFiles(firstReloadFileList) : files);
// Initial compile
createWatchModeWithConfigFile(configFile.path, host);
createWatchOfConfigFile(configFile.path, host);
if (firstCompilationEmitFiles) {
checkAffectedLines(host, getFiles(firstCompilationEmitFiles), allEmittedFiles);
}
@@ -1595,11 +1583,11 @@ namespace ts.tscWatch {
// Initial compile
if (configFile) {
createWatchModeWithConfigFile(configFile.path, host);
createWatchOfConfigFile(configFile.path, host);
}
else {
// First file as the root
createWatchModeWithoutConfigFile([files[0].path], host, { listEmittedFiles: true });
createWatchOfFilesAndCompilerOptions([files[0].path], host, { listEmittedFiles: true });
}
checkOutputContains(host, allEmittedFiles);
@@ -1719,7 +1707,7 @@ namespace ts.tscWatch {
const files = [root, imported, libFile];
const host = createWatchedSystem(files);
const watch = createWatchModeWithoutConfigFile([root.path], host, { module: ModuleKind.AMD });
const watch = createWatchOfFilesAndCompilerOptions([root.path], host, { module: ModuleKind.AMD });
const f1IsNotModule = getDiagnosticOfFileFromProgram(watch(), root.path, root.content.indexOf('"f1"'), '"f1"'.length, Diagnostics.File_0_is_not_a_module, imported.path);
const cannotFindFoo = getDiagnosticOfFileFromProgram(watch(), imported.path, imported.content.indexOf("foo"), "foo".length, Diagnostics.Cannot_find_name_0, "foo");
@@ -1820,7 +1808,7 @@ namespace ts.tscWatch {
return originalFileExists.call(host, fileName);
};
const watch = createWatchModeWithoutConfigFile([root.path], host, { module: ModuleKind.AMD });
const watch = createWatchOfFilesAndCompilerOptions([root.path], host, { module: ModuleKind.AMD });
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called");
checkOutputErrors(host, [
@@ -1862,7 +1850,7 @@ namespace ts.tscWatch {
return originalFileExists.call(host, fileName);
};
const watch = createWatchModeWithoutConfigFile([root.path], host, { module: ModuleKind.AMD });
const watch = createWatchOfFilesAndCompilerOptions([root.path], host, { module: ModuleKind.AMD });
assert.isTrue(fileExistsCalledForBar, "'fileExists' should be called");
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
@@ -1911,7 +1899,7 @@ declare module "fs" {
const filesWithNodeType = files.concat(packageJson, nodeType);
const host = createWatchedSystem(files, { currentDirectory: "/a/b" });
const watch = createWatchModeWithoutConfigFile([root.path], host, { });
const watch = createWatchOfFilesAndCompilerOptions([root.path], host, { });
checkOutputErrors(host, [
getDiagnosticModuleNotFoundOfFile(watch(), root, "fs")
@@ -1953,7 +1941,7 @@ declare module "fs" {
const files = [root, file, libFile];
const host = createWatchedSystem(files, { currentDirectory: "/a/b" });
const watch = createWatchModeWithoutConfigFile([root.path, file.path], host, {});
const watch = createWatchOfFilesAndCompilerOptions([root.path, file.path], host, {});
checkOutputErrors(host, [
getDiagnosticModuleNotFoundOfFile(watch(), root, "fs")
@@ -1995,7 +1983,7 @@ declare module "fs" {
const outDirFolder = "/a/b/projects/myProject/dist/";
const programFiles = [file1, file2, module1, libFile];
const host = createWatchedSystem(programFiles.concat(configFile), { currentDirectory: "/a/b/projects/myProject/" });
const watch = createWatchModeWithConfigFile(configFile.path, host);
const watch = createWatchOfConfigFile(configFile.path, host);
checkProgramActualFiles(watch(), programFiles.map(f => f.path));
checkOutputErrors(host, emptyArray, /*errorsPosition*/ ExpectedOutputErrorsPosition.AfterCompilationStarting);
const expectedFiles: ExpectedFile[] = [
@@ -2072,7 +2060,7 @@ declare module "fs" {
};
const files = [configFile, file1, file2, libFile];
const host = createWatchedSystem(files);
const watch = createWatchModeWithConfigFile(configFile.path, host);
const watch = createWatchOfConfigFile(configFile.path, host);
checkProgramActualFiles(watch(), mapDefined(files, f => f === configFile ? undefined : f.path));
file1.content = "var zz30 = 100;";
@@ -2094,7 +2082,7 @@ declare module "fs" {
};
const host = createWatchedSystem([file]);
createWatchModeWithoutConfigFile([file.path], host);
createWatchOfFilesAndCompilerOptions([file.path], host);
host.runQueuedTimeoutCallbacks();
host.checkScreenClears(1);
@@ -2106,7 +2094,7 @@ declare module "fs" {
content: ""
};
const host = createWatchedSystem([file]);
createWatchModeWithoutConfigFile([file.path], host);
createWatchOfFilesAndCompilerOptions([file.path], host);
const modifiedFile = {
...file,
@@ -2846,6 +2846,45 @@ namespace ts.projectSystem {
const options = project.getCompilerOptions();
assert.equal(options.outDir, "C:/a/b", "");
});
it("dynamic file without external project", () => {
const file: FileOrFolder = {
path: "^walkThroughSnippet:/Users/UserName/projects/someProject/out/someFile#1.js",
content: "var x = 10;"
};
const host = createServerHost([libFile], { useCaseSensitiveFileNames: true });
const projectService = createProjectService(host);
projectService.setCompilerOptionsForInferredProjects({
module: ModuleKind.CommonJS,
allowJs: true,
allowSyntheticDefaultImports: true,
allowNonTsExtensions: true
});
projectService.openClientFile(file.path, "var x = 10;");
projectService.checkNumberOfProjects({ inferredProjects: 1 });
const project = projectService.inferredProjects[0];
checkProjectRootFiles(project, [file.path]);
checkProjectActualFiles(project, [file.path, libFile.path]);
assert.strictEqual(projectService.getDefaultProjectForFile(server.toNormalizedPath(file.path), /*ensureProject*/ true), project);
const indexOfX = file.content.indexOf("x");
assert.deepEqual(project.getLanguageService(/*ensureSynchronized*/ true).getQuickInfoAtPosition(file.path, indexOfX), {
kind: ScriptElementKind.variableElement,
kindModifiers: "",
textSpan: { start: indexOfX, length: 1 },
displayParts: [
{ text: "var", kind: "keyword" },
{ text: " ", kind: "space" },
{ text: "x", kind: "localName" },
{ text: ":", kind: "punctuation" },
{ text: " ", kind: "space" },
{ text: "number", kind: "keyword" }
],
documentation: [],
tags: []
});
});
});
describe("tsserverProjectSystem Proper errors", () => {
+1 -1
View File
@@ -479,7 +479,7 @@ interface Array<T> {}`
private invokeFileWatcher(fileFullPath: string, eventKind: FileWatcherEventKind) {
const callbacks = this.watchedFiles.get(this.toPath(fileFullPath));
invokeWatcherCallbacks(callbacks, ({ cb, fileName }) => cb(fileName, eventKind));
invokeWatcherCallbacks(callbacks, ({ cb }) => cb(fileFullPath, eventKind));
}
private getRelativePathToDirectory(directoryFullPath: string, fileFullPath: string) {
@@ -14,7 +14,7 @@
<Cmt Name="LcxAdmin" />
<Cmt Name="Loc" />
<Cmt Name="Note" />
<Cmt Name="Rccx" />
<Cmt Name="RCCX" />
</OwnedComments>
<Settings Name="@vsLocTools@\current\default.lss" Type="LSS" />
<Item ItemId=";String Table" ItemType="0" PsrId="306" Leaf="false">
@@ -573,6 +573,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_a_property_name_2566" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have a property name.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[其余元素不能具有属性名。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_an_initializer_1186" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have an initializer.]]></Val>
@@ -3369,15 +3378,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_symbol_95003" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract symbol]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[提取符号]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_to_0_in_1_95004" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract to {0} in {1}]]></Val>
@@ -3564,6 +3564,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Found_package_json_at_0_Package_ID_is_1_6190" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Found 'package.json' at '{0}'. Package ID is '{1}'.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[在“{0}”找到了 "package.json"。包 ID 为“{1}”。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_1250" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'.]]></Val>
@@ -6594,11 +6603,11 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_Colon_6079" ItemType="0" PsrId="306" Leaf="true">
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_6079" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Specify library files to be included in the compilation: ]]></Val>
<Val><![CDATA[Specify library files to be included in the compilation.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[指定要在编译中包括的库文件: ]]></Val>
<Val><![CDATA[指定要在编译中包括的库文件。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -14,7 +14,7 @@
<Cmt Name="LcxAdmin" />
<Cmt Name="Loc" />
<Cmt Name="Note" />
<Cmt Name="Rccx" />
<Cmt Name="RCCX" />
</OwnedComments>
<Settings Name="@vsLocTools@\current\default.lss" Type="LSS" />
<Item ItemId=";String Table" ItemType="0" PsrId="306" Leaf="false">
@@ -573,6 +573,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_a_property_name_2566" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have a property name.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[REST 元素不得有屬性名稱。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_an_initializer_1186" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have an initializer.]]></Val>
@@ -888,6 +897,9 @@
<Item ItemId=";Add_async_modifier_to_containing_function_90029" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Add async modifier to containing function]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[將 async 修飾詞新增至包含的函式]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -3366,15 +3378,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_symbol_95003" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract symbol]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[解壓縮符號]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_to_0_in_1_95004" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract to {0} in {1}]]></Val>
@@ -3561,6 +3564,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Found_package_json_at_0_Package_ID_is_1_6190" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Found 'package.json' at '{0}'. Package ID is '{1}'.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[於 '{0}' 找到 'package.json'。套件識別碼為 '{1}'。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_1250" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'.]]></Val>
@@ -4620,6 +4632,9 @@
<Item ItemId=";Mapped_object_type_implicitly_has_an_any_template_type_7039" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Mapped object type implicitly has an 'any' template type.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[對應的物件類型隱含具有 'any' 範本類型。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -6588,11 +6603,11 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_Colon_6079" ItemType="0" PsrId="306" Leaf="true">
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_6079" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Specify library files to be included in the compilation: ]]></Val>
<Val><![CDATA[Specify library files to be included in the compilation.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[指定編譯內要包含的程式庫檔: ]]></Val>
<Val><![CDATA[請指定要併入編譯中的程式庫檔案。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -19,7 +19,7 @@
<Cmt Name="ManifestData" />
<Cmt Name="Mnemonic" />
<Cmt Name="Note" />
<Cmt Name="Rccx" />
<Cmt Name="RCCX" />
<Cmt Name="UIType" />
<Cmt Name="UTSData" />
<Cmt Name="UTSUI" />
@@ -582,6 +582,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_a_property_name_2566" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have a property name.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Element rest nemůže mít název vlastnosti.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_an_initializer_1186" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have an initializer.]]></Val>
@@ -897,6 +906,9 @@
<Item ItemId=";Add_async_modifier_to_containing_function_90029" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Add async modifier to containing function]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Přidat modifikátor async do obsahující funkce]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -3375,15 +3387,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_symbol_95003" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract symbol]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Extrahovat symbol]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_to_0_in_1_95004" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract to {0} in {1}]]></Val>
@@ -3570,6 +3573,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Found_package_json_at_0_Package_ID_is_1_6190" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Found 'package.json' at '{0}'. Package ID is '{1}'.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[V {0} se našel soubor package.json. ID balíčku je {1}.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_1250" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'.]]></Val>
@@ -4629,6 +4641,9 @@
<Item ItemId=";Mapped_object_type_implicitly_has_an_any_template_type_7039" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Mapped object type implicitly has an 'any' template type.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Typu mapovaného objektu má implicitně typ šablony any.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -6597,11 +6612,11 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_Colon_6079" ItemType="0" PsrId="306" Leaf="true">
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_6079" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Specify library files to be included in the compilation: ]]></Val>
<Val><![CDATA[Specify library files to be included in the compilation.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Zadejte soubory knihovny, které se mají zahrnout do kompilace: ]]></Val>
<Val><![CDATA[Zadejte soubory knihovny, které se mají zahrnout do kompilace.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -14,7 +14,7 @@
<Cmt Name="LcxAdmin" />
<Cmt Name="Loc" />
<Cmt Name="Note" />
<Cmt Name="Rccx" />
<Cmt Name="RCCX" />
</OwnedComments>
<Settings Name="@vsLocTools@\current\default.lss" Type="LSS" />
<Item ItemId=";String Table" ItemType="0" PsrId="306" Leaf="false">
@@ -573,6 +573,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_a_property_name_2566" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have a property name.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Ein rest-Element darf keinen Eigenschaftennamen aufweisen.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_an_initializer_1186" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have an initializer.]]></Val>
@@ -885,6 +894,9 @@
<Item ItemId=";Add_async_modifier_to_containing_function_90029" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Add async modifier to containing function]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Async-Modifizierer zur enthaltenden Funktion hinzufügen]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -3363,15 +3375,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_symbol_95003" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract symbol]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Symbol extrahieren]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_to_0_in_1_95004" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract to {0} in {1}]]></Val>
@@ -3558,6 +3561,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Found_package_json_at_0_Package_ID_is_1_6190" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Found 'package.json' at '{0}'. Package ID is '{1}'.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA["Package.json" unter "{0}" gefunden. Paket-ID: "{1}".]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_1250" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'.]]></Val>
@@ -4617,6 +4629,9 @@
<Item ItemId=";Mapped_object_type_implicitly_has_an_any_template_type_7039" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Mapped object type implicitly has an 'any' template type.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Der zugeordnete Objekttyp weist implizit einen any-Vorlagentyp auf.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -6579,11 +6594,11 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_Colon_6079" ItemType="0" PsrId="306" Leaf="true">
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_6079" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Specify library files to be included in the compilation: ]]></Val>
<Val><![CDATA[Specify library files to be included in the compilation.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Geben Sie Bibliotheksdateien an, die in die Kompilierung eingeschlossen werden sollen: ]]></Val>
<Val><![CDATA[Geben Sie Bibliotheksdateien an, die in die Kompilierung eingeschlossen werden sollen.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -19,7 +19,7 @@
<Cmt Name="ManifestData" />
<Cmt Name="Mnemonic" />
<Cmt Name="Note" />
<Cmt Name="Rccx" />
<Cmt Name="RCCX" />
<Cmt Name="UIType" />
<Cmt Name="UTSData" />
<Cmt Name="UTSUI" />
@@ -582,6 +582,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_a_property_name_2566" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have a property name.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Un elemento rest no puede tener un nombre de propiedad.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_an_initializer_1186" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have an initializer.]]></Val>
@@ -897,6 +906,9 @@
<Item ItemId=";Add_async_modifier_to_containing_function_90029" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Add async modifier to containing function]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Agregar el modificador async a la función contenedora]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -3375,15 +3387,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_symbol_95003" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract symbol]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Extraer el símbolo]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_to_0_in_1_95004" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract to {0} in {1}]]></Val>
@@ -3570,6 +3573,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Found_package_json_at_0_Package_ID_is_1_6190" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Found 'package.json' at '{0}'. Package ID is '{1}'.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Se encontró "package.json" en "{0}". El identificador de paquete es "{1}".]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_1250" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'.]]></Val>
@@ -4629,6 +4641,9 @@
<Item ItemId=";Mapped_object_type_implicitly_has_an_any_template_type_7039" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Mapped object type implicitly has an 'any' template type.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[El tipo de objeto asignado tiene implícitamente un tipo de plantilla "any".]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -6597,11 +6612,11 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_Colon_6079" ItemType="0" PsrId="306" Leaf="true">
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_6079" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Specify library files to be included in the compilation: ]]></Val>
<Val><![CDATA[Specify library files to be included in the compilation.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Especifique archivos de biblioteca para incluirlos en la compilación: ]]></Val>
<Val><![CDATA[Especifique los archivos de biblioteca que se van a incluir en la compilación.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -19,7 +19,7 @@
<Cmt Name="ManifestData" />
<Cmt Name="Mnemonic" />
<Cmt Name="Note" />
<Cmt Name="Rccx" />
<Cmt Name="RCCX" />
<Cmt Name="UIType" />
<Cmt Name="UTSData" />
<Cmt Name="UTSUI" />
@@ -582,6 +582,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_a_property_name_2566" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have a property name.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Un élément rest ne peut pas avoir de nom de propriété.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_an_initializer_1186" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have an initializer.]]></Val>
@@ -897,6 +906,9 @@
<Item ItemId=";Add_async_modifier_to_containing_function_90029" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Add async modifier to containing function]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Ajouter le modificateur async dans la fonction conteneur]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -3375,15 +3387,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_symbol_95003" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract symbol]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Extraire le symbole]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_to_0_in_1_95004" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract to {0} in {1}]]></Val>
@@ -3570,6 +3573,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Found_package_json_at_0_Package_ID_is_1_6190" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Found 'package.json' at '{0}'. Package ID is '{1}'.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA['package.json' trouvé sur '{0}'. L'ID de package est '{1}'.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_1250" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'.]]></Val>
@@ -4629,6 +4641,9 @@
<Item ItemId=";Mapped_object_type_implicitly_has_an_any_template_type_7039" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Mapped object type implicitly has an 'any' template type.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Le type d'objet mappé a implicitement un type de modèle 'any'.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -6597,11 +6612,11 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_Colon_6079" ItemType="0" PsrId="306" Leaf="true">
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_6079" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Specify library files to be included in the compilation: ]]></Val>
<Val><![CDATA[Specify library files to be included in the compilation.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Spécifiez les fichiers bibliothèques à inclure dans la compilation : ]]></Val>
<Val><![CDATA[Spécifiez les fichiers bibliothèques à inclure dans la compilation.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -14,7 +14,7 @@
<Cmt Name="LcxAdmin" />
<Cmt Name="Loc" />
<Cmt Name="Note" />
<Cmt Name="Rccx" />
<Cmt Name="RCCX" />
</OwnedComments>
<Settings Name="@vsLocTools@\current\default.lss" Type="LSS" />
<Item ItemId=";String Table" ItemType="0" PsrId="306" Leaf="false">
@@ -573,6 +573,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_a_property_name_2566" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have a property name.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Un elemento rest non può contenere un nome proprietà.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_an_initializer_1186" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have an initializer.]]></Val>
@@ -3369,15 +3378,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_symbol_95003" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract symbol]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Estrarre il simbolo]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_to_0_in_1_95004" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract to {0} in {1}]]></Val>
@@ -3564,6 +3564,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Found_package_json_at_0_Package_ID_is_1_6190" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Found 'package.json' at '{0}'. Package ID is '{1}'.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Il file 'package.json' è stato trovato in '{0}'. L'ID pacchetto è '{1}'.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_1250" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'.]]></Val>
@@ -6594,11 +6603,11 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_Colon_6079" ItemType="0" PsrId="306" Leaf="true">
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_6079" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Specify library files to be included in the compilation: ]]></Val>
<Val><![CDATA[Specify library files to be included in the compilation.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Specifica i file di libreria da includere nella compilazione: ]]></Val>
<Val><![CDATA[Specificare i file di libreria da includere nella compilazione.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -14,7 +14,7 @@
<Cmt Name="LcxAdmin" />
<Cmt Name="Loc" />
<Cmt Name="Note" />
<Cmt Name="Rccx" />
<Cmt Name="RCCX" />
</OwnedComments>
<Settings Name="@vsLocTools@\current\default.lss" Type="LSS" />
<Item ItemId=";String Table" ItemType="0" PsrId="306" Leaf="false">
@@ -573,6 +573,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_a_property_name_2566" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have a property name.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[rest 要素にプロパティ名を指定することはできません。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_an_initializer_1186" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have an initializer.]]></Val>
@@ -3369,15 +3378,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_symbol_95003" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract symbol]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[シンボルの抽出]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_to_0_in_1_95004" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract to {0} in {1}]]></Val>
@@ -3564,6 +3564,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Found_package_json_at_0_Package_ID_is_1_6190" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Found 'package.json' at '{0}'. Package ID is '{1}'.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA['{0}' で 'package.json' が見つかりました。パッケージ ID は、'{1}' です。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_1250" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'.]]></Val>
@@ -6594,11 +6603,11 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_Colon_6079" ItemType="0" PsrId="306" Leaf="true">
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_6079" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Specify library files to be included in the compilation: ]]></Val>
<Val><![CDATA[Specify library files to be included in the compilation.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[コンパイルに含めるライブラリ ファイルを指定します: ]]></Val>
<Val><![CDATA[コンパイルに含めるライブラリ ファイルを指定します。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -14,7 +14,7 @@
<Cmt Name="LcxAdmin" />
<Cmt Name="Loc" />
<Cmt Name="Note" />
<Cmt Name="Rccx" />
<Cmt Name="RCCX" />
</OwnedComments>
<Settings Name="@vsLocTools@\current\default.lss" Type="LSS" />
<Item ItemId=";String Table" ItemType="0" PsrId="306" Leaf="false">
@@ -573,6 +573,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_a_property_name_2566" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have a property name.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[rest 요소에는 속성 이름을 사용할 수 없습니다.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_an_initializer_1186" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have an initializer.]]></Val>
@@ -888,6 +897,9 @@
<Item ItemId=";Add_async_modifier_to_containing_function_90029" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Add async modifier to containing function]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[포함된 함수에 async 한정자 추가]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -3366,15 +3378,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_symbol_95003" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract symbol]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[기호 추출]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_to_0_in_1_95004" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract to {0} in {1}]]></Val>
@@ -3561,6 +3564,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Found_package_json_at_0_Package_ID_is_1_6190" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Found 'package.json' at '{0}'. Package ID is '{1}'.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA['{0}'에서 'package.json'을 찾았습니다. 패키지 ID는 '{1}'입니다.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_1250" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'.]]></Val>
@@ -4620,6 +4632,9 @@
<Item ItemId=";Mapped_object_type_implicitly_has_an_any_template_type_7039" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Mapped object type implicitly has an 'any' template type.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[매핑된 개체 형식에는 'any' 템플릿 형식이 암시적으로 포함됩니다.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -6588,11 +6603,11 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_Colon_6079" ItemType="0" PsrId="306" Leaf="true">
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_6079" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Specify library files to be included in the compilation: ]]></Val>
<Val><![CDATA[Specify library files to be included in the compilation.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[컴파일에 포함할 라이브러리 파일 지정: ]]></Val>
<Val><![CDATA[컴파일에 포함할 라이브러리 파일을 지정합니다.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -7,7 +7,7 @@
<Cmt Name="Dev" />
<Cmt Name="LcxAdmin" />
<Cmt Name="Loc" />
<Cmt Name="Rccx" />
<Cmt Name="RCCX" />
</OwnedComments>
<Settings Name="@vsLocTools@\current\default.lss" Type="LSS" />
<Item ItemId=";String Table" ItemType="0" PsrId="306" Leaf="false">
@@ -566,6 +566,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_a_property_name_2566" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have a property name.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Element rest nie może mieć nazwy właściwości.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_an_initializer_1186" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have an initializer.]]></Val>
@@ -878,6 +887,9 @@
<Item ItemId=";Add_async_modifier_to_containing_function_90029" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Add async modifier to containing function]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Dodaj modyfikator asynchroniczny do funkcji zawierającej]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -3356,15 +3368,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_symbol_95003" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract symbol]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Wyodrębnij symbol]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_to_0_in_1_95004" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract to {0} in {1}]]></Val>
@@ -3551,6 +3554,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Found_package_json_at_0_Package_ID_is_1_6190" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Found 'package.json' at '{0}'. Package ID is '{1}'.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Znaleziono plik „package.json” w lokalizacji „{0}”. Identyfikator pakietu to „{1}”.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_1250" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'.]]></Val>
@@ -4610,6 +4622,9 @@
<Item ItemId=";Mapped_object_type_implicitly_has_an_any_template_type_7039" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Mapped object type implicitly has an 'any' template type.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Zmapowany typ obiektu niejawnie ma typ szablonu „any”.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -6572,11 +6587,11 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_Colon_6079" ItemType="0" PsrId="306" Leaf="true">
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_6079" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Specify library files to be included in the compilation: ]]></Val>
<Val><![CDATA[Specify library files to be included in the compilation.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Określ pliki biblioteki do uwzględnienia w kompilacji: ]]></Val>
<Val><![CDATA[Określ pliki biblioteki do uwzględnienia w kompilacji.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -7,7 +7,7 @@
<Cmt Name="Dev" />
<Cmt Name="LcxAdmin" />
<Cmt Name="Loc" />
<Cmt Name="Rccx" />
<Cmt Name="RCCX" />
</OwnedComments>
<Settings Name="@vsLocTools@\current\default.lss" Type="LSS" />
<Item ItemId=";String Table" ItemType="0" PsrId="306" Leaf="false">
@@ -566,6 +566,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_a_property_name_2566" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have a property name.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Um elemento restante não pode ter um nome de propriedade.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_an_initializer_1186" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have an initializer.]]></Val>
@@ -3359,15 +3368,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_symbol_95003" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract symbol]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Extrair símbolo]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_to_0_in_1_95004" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract to {0} in {1}]]></Val>
@@ -3554,6 +3554,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Found_package_json_at_0_Package_ID_is_1_6190" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Found 'package.json' at '{0}'. Package ID is '{1}'.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA['package.json' encontrado em '{0}'. A ID do pacote é '{1}'.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_1250" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'.]]></Val>
@@ -6578,11 +6587,11 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_Colon_6079" ItemType="0" PsrId="306" Leaf="true">
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_6079" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Specify library files to be included in the compilation: ]]></Val>
<Val><![CDATA[Specify library files to be included in the compilation.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Especifique os arquivos de biblioteca a serem incluídos na compilação: ]]></Val>
<Val><![CDATA[Especifique os arquivos de biblioteca a serem incluídos na compilação.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -13,7 +13,7 @@
<Cmt Name="Dev" />
<Cmt Name="LcxAdmin" />
<Cmt Name="Note" />
<Cmt Name="Rccx" />
<Cmt Name="RCCX" />
</OwnedComments>
<Settings Name="@vsLocTools@\current\default.lss" Type="LSS" />
<Item ItemId=";String Table" ItemType="0" PsrId="306" Leaf="false">
@@ -572,6 +572,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_a_property_name_2566" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have a property name.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Элемент rest не может иметь имя свойства.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_an_initializer_1186" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have an initializer.]]></Val>
@@ -887,6 +896,9 @@
<Item ItemId=";Add_async_modifier_to_containing_function_90029" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Add async modifier to containing function]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Добавьте модификатор async в содержащую функцию]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -3365,15 +3377,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_symbol_95003" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract symbol]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Извлечь символ]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_to_0_in_1_95004" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract to {0} in {1}]]></Val>
@@ -3560,6 +3563,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Found_package_json_at_0_Package_ID_is_1_6190" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Found 'package.json' at '{0}'. Package ID is '{1}'.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Найден "package.json" в "{0}". Идентификатор пакета: "{1}".]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_1250" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'.]]></Val>
@@ -4619,6 +4631,9 @@
<Item ItemId=";Mapped_object_type_implicitly_has_an_any_template_type_7039" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Mapped object type implicitly has an 'any' template type.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Сопоставленный объект неявно имеет тип шаблона "любой".]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -6587,11 +6602,11 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_Colon_6079" ItemType="0" PsrId="306" Leaf="true">
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_6079" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Specify library files to be included in the compilation: ]]></Val>
<Val><![CDATA[Specify library files to be included in the compilation.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Укажите файлы библиотеки для включения в компиляцию: ]]></Val>
<Val><![CDATA[Укажите файлы библиотек для включения в компиляцию.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -7,7 +7,7 @@
<Cmt Name="Dev" />
<Cmt Name="LcxAdmin" />
<Cmt Name="Loc" />
<Cmt Name="Rccx" />
<Cmt Name="RCCX" />
</OwnedComments>
<Settings Name="@vsLocTools@\current\default.lss" Type="LSS" />
<Item ItemId=";String Table" ItemType="0" PsrId="306" Leaf="false">
@@ -566,6 +566,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_a_property_name_2566" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have a property name.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Rest öğesinin özellik adı olamaz.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_rest_element_cannot_have_an_initializer_1186" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A rest element cannot have an initializer.]]></Val>
@@ -881,6 +890,9 @@
<Item ItemId=";Add_async_modifier_to_containing_function_90029" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Add async modifier to containing function]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[İçeren işleve zaman uyumsuz değiştirici ekle]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -3359,15 +3371,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_symbol_95003" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract symbol]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Sembolü ayıkla]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Extract_to_0_in_1_95004" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Extract to {0} in {1}]]></Val>
@@ -3554,6 +3557,15 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Found_package_json_at_0_Package_ID_is_1_6190" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Found 'package.json' at '{0}'. Package ID is '{1}'.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA['{0}' konumunda 'package.json' bulundu. Paket kimliği '{1}'.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Function_declarations_are_not_allowed_inside_blocks_in_strict_mode_when_targeting_ES3_or_ES5_1250" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Function declarations are not allowed inside blocks in strict mode when targeting 'ES3' or 'ES5'.]]></Val>
@@ -4613,6 +4625,9 @@
<Item ItemId=";Mapped_object_type_implicitly_has_an_any_template_type_7039" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Mapped object type implicitly has an 'any' template type.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Eşleştirilmiş nesne türü örtük olarak 'any' şablon türüne sahip.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
</Item>
@@ -6581,11 +6596,11 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_Colon_6079" ItemType="0" PsrId="306" Leaf="true">
<Item ItemId=";Specify_library_files_to_be_included_in_the_compilation_6079" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Specify library files to be included in the compilation: ]]></Val>
<Val><![CDATA[Specify library files to be included in the compilation.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Derlemeye dahil edilecek kitaplık dosyalarını belirtin: ]]></Val>
<Val><![CDATA[Derlemeye dahil edilecek kitaplık dosyalarını belirtin.]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
+8 -8
View File
@@ -898,7 +898,7 @@ namespace ts.server {
const project = this.getOrCreateInferredProjectForProjectRootPathIfEnabled(info, projectRootPath) ||
this.getOrCreateSingleInferredProjectIfEnabled() ||
this.createInferredProject(getDirectoryPath(info.path));
this.createInferredProject(info.isDynamic ? this.currentDirectory : getDirectoryPath(info.path));
project.addRoot(info);
project.updateGraph();
@@ -1495,7 +1495,7 @@ namespace ts.server {
}
private createConfiguredProject(configFileName: NormalizedPath) {
const cachedDirectoryStructureHost = createCachedDirectoryStructureHost(this.host);
const cachedDirectoryStructureHost = createCachedDirectoryStructureHost(this.host, this.host.getCurrentDirectory(), this.host.useCaseSensitiveFileNames);
const { projectOptions, configFileErrors, configFileSpecs } = this.convertConfigFileContentToProjectOptions(configFileName, cachedDirectoryStructureHost);
this.logger.info(`Opened configuration file ${configFileName}`);
const languageServiceEnabled = !this.exceededTotalSizeLimitForNonTsFiles(configFileName, projectOptions.compilerOptions, projectOptions.files, fileNamePropertyReader);
@@ -1655,7 +1655,7 @@ namespace ts.server {
}
private getOrCreateInferredProjectForProjectRootPathIfEnabled(info: ScriptInfo, projectRootPath: NormalizedPath | undefined): InferredProject | undefined {
if (!this.useInferredProjectPerProjectRoot) {
if (info.isDynamic || !this.useInferredProjectPerProjectRoot) {
return undefined;
}
@@ -1800,19 +1800,19 @@ namespace ts.server {
return this.getOrCreateScriptInfoWorker(fileName, currentDirectory, /*openedByClient*/ true, fileContent, scriptKind, hasMixedContent);
}
getOrCreateScriptInfoForNormalizedPath(fileName: NormalizedPath, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: DirectoryStructureHost) {
getOrCreateScriptInfoForNormalizedPath(fileName: NormalizedPath, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: { fileExists(path: string): boolean; }) {
return this.getOrCreateScriptInfoWorker(fileName, this.currentDirectory, openedByClient, fileContent, scriptKind, hasMixedContent, hostToQueryFileExistsOn);
}
private getOrCreateScriptInfoWorker(fileName: NormalizedPath, currentDirectory: string, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: DirectoryStructureHost) {
private getOrCreateScriptInfoWorker(fileName: NormalizedPath, currentDirectory: string, openedByClient: boolean, fileContent?: string, scriptKind?: ScriptKind, hasMixedContent?: boolean, hostToQueryFileExistsOn?: { fileExists(path: string): boolean; }) {
Debug.assert(fileContent === undefined || openedByClient, "ScriptInfo needs to be opened by client to be able to set its user defined content");
const path = normalizedPathToPath(fileName, currentDirectory, this.toCanonicalFileName);
let info = this.getScriptInfoForPath(path);
if (!info) {
const isDynamic = isDynamicFileName(fileName);
Debug.assert(isRootedDiskPath(fileName) || isDynamic || openedByClient, "Script info with non-dynamic relative file name can only be open script info");
Debug.assert(!isRootedDiskPath(fileName) || this.currentDirectory === currentDirectory || !this.openFilesWithNonRootedDiskPath.has(this.toCanonicalFileName(fileName)), "Open script files with non rooted disk path opened with current directory context cannot have same canonical names");
Debug.assert(!isDynamic || this.currentDirectory === currentDirectory, "Dynamic files must always have current directory context since containing external project name will always match the script info name.");
Debug.assert(isRootedDiskPath(fileName) || isDynamic || openedByClient, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nScript info with non-dynamic relative file name can only be open script info`);
Debug.assert(!isRootedDiskPath(fileName) || this.currentDirectory === currentDirectory || !this.openFilesWithNonRootedDiskPath.has(this.toCanonicalFileName(fileName)), "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nOpen script files with non rooted disk path opened with current directory context cannot have same canonical names`);
Debug.assert(!isDynamic || this.currentDirectory === currentDirectory, "", () => `${JSON.stringify({ fileName, currentDirectory, hostCurrentDirectory: this.currentDirectory, openKeys: arrayFrom(this.openFilesWithNonRootedDiskPath.keys()) })}\nDynamic files must always have current directory context since containing external project name will always match the script info name.`);
// If the file is not opened by client and the file doesnot exist on the disk, return
if (!openedByClient && !isDynamic && !(hostToQueryFileExistsOn || this.host).fileExists(fileName)) {
return;
+22 -27
View File
@@ -3,7 +3,7 @@
/// <reference path="scriptInfo.ts"/>
/// <reference path="..\compiler\resolutionCache.ts"/>
/// <reference path="typingsCache.ts"/>
/// <reference path="..\compiler\builder.ts"/>
/// <reference path="..\compiler\builderState.ts"/>
namespace ts.server {
@@ -140,7 +140,7 @@ namespace ts.server {
/*@internal*/
resolutionCache: ResolutionCache;
private builder: Builder;
private builderState: BuilderState | undefined;
/**
* Set of files names that were updated since the last call to getChangesSinceVersion.
*/
@@ -202,6 +202,9 @@ namespace ts.server {
/*@internal*/
readonly currentDirectory: string;
/*@internal*/
public directoryStructureHost: DirectoryStructureHost;
/*@internal*/
constructor(
/*@internal*/readonly projectName: string,
@@ -212,8 +215,9 @@ namespace ts.server {
languageServiceEnabled: boolean,
private compilerOptions: CompilerOptions,
public compileOnSaveEnabled: boolean,
/*@internal*/public directoryStructureHost: DirectoryStructureHost,
directoryStructureHost: DirectoryStructureHost,
currentDirectory: string | undefined) {
this.directoryStructureHost = directoryStructureHost;
this.currentDirectory = this.projectService.getNormalizedAbsolutePath(currentDirectory || "");
this.cancellationToken = new ThrottledCancellationToken(this.projectService.cancellationToken, this.projectService.throttleWaitMilliseconds);
@@ -238,7 +242,7 @@ namespace ts.server {
}
// Use the current directory as resolution root only if the project created using current directory string
this.resolutionCache = createResolutionCache(this, currentDirectory && this.currentDirectory);
this.resolutionCache = createResolutionCache(this, currentDirectory && this.currentDirectory, /*logChangesWhenResolvingModule*/ true);
this.languageService = createLanguageService(this, this.documentRegistry);
if (!languageServiceEnabled) {
this.disableLanguageService();
@@ -267,7 +271,7 @@ namespace ts.server {
}
getNewLine() {
return this.directoryStructureHost.newLine;
return this.projectService.host.newLine;
}
getProjectVersion() {
@@ -335,7 +339,7 @@ namespace ts.server {
}
useCaseSensitiveFileNames() {
return this.directoryStructureHost.useCaseSensitiveFileNames;
return this.projectService.host.useCaseSensitiveFileNames;
}
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[] {
@@ -343,7 +347,7 @@ namespace ts.server {
}
readFile(fileName: string): string | undefined {
return this.directoryStructureHost.readFile(fileName);
return this.projectService.host.readFile(fileName);
}
fileExists(file: string): boolean {
@@ -354,7 +358,7 @@ namespace ts.server {
}
resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModuleFull[] {
return this.resolutionCache.resolveModuleNames(moduleNames, containingFile, reusedNames, /*logChanges*/ true);
return this.resolutionCache.resolveModuleNames(moduleNames, containingFile, reusedNames);
}
resolveTypeReferenceDirectives(typeDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[] {
@@ -369,6 +373,11 @@ namespace ts.server {
return this.directoryStructureHost.getDirectories(path);
}
/*@internal*/
getCachedDirectoryStructureHost(): CachedDirectoryStructureHost {
return undefined;
}
/*@internal*/
toPath(fileName: string) {
return toPath(fileName, this.currentDirectory, this.projectService.toCanonicalFileName);
@@ -443,15 +452,6 @@ namespace ts.server {
return this.languageService;
}
private ensureBuilder() {
if (!this.builder) {
this.builder = createBuilder({
getCanonicalFileName: this.projectService.toCanonicalFileName,
computeHash: data => this.projectService.host.createHash(data)
});
}
}
private shouldEmitFile(scriptInfo: ScriptInfo) {
return scriptInfo && !scriptInfo.isDynamicOrHasMixedContent();
}
@@ -461,8 +461,8 @@ namespace ts.server {
return [];
}
this.updateGraph();
this.ensureBuilder();
return mapDefined(this.builder.getFilesAffectedBy(this.program, scriptInfo.path),
this.builderState = BuilderState.create(this.program, this.projectService.toCanonicalFileName, this.builderState);
return mapDefined(BuilderState.getFilesAffectedBy(this.builderState, this.program, scriptInfo.path, this.cancellationToken, data => this.projectService.host.createHash(data)),
sourceFile => this.shouldEmitFile(this.projectService.getScriptInfoForPath(sourceFile.path)) ? sourceFile.fileName : undefined);
}
@@ -498,6 +498,7 @@ namespace ts.server {
}
this.languageService.cleanupSemanticCache();
this.languageServiceEnabled = false;
this.builderState = undefined;
this.resolutionCache.closeTypeRootsWatch();
this.projectService.onUpdateLanguageServiceStateForProject(this, /*languageServiceEnabled*/ false);
}
@@ -557,7 +558,7 @@ namespace ts.server {
this.rootFilesMap = undefined;
this.externalFiles = undefined;
this.program = undefined;
this.builder = undefined;
this.builderState = undefined;
this.resolutionCache.clear();
this.resolutionCache = undefined;
this.cachedUnresolvedImportsPerFile = undefined;
@@ -813,15 +814,9 @@ namespace ts.server {
if (this.setTypings(cachedTypings)) {
hasChanges = this.updateGraphWorker() || hasChanges;
}
if (this.builder) {
this.builder.updateProgram(this.program);
}
}
else {
this.lastCachedUnresolvedImportsList = undefined;
if (this.builder) {
this.builder.clear();
}
}
if (hasChanges) {
@@ -921,7 +916,7 @@ namespace ts.server {
missingFilePath,
(fileName, eventKind) => {
if (this.projectKind === ProjectKind.Configured) {
(this.directoryStructureHost as CachedDirectoryStructureHost).addOrDeleteFile(fileName, missingFilePath, eventKind);
this.getCachedDirectoryStructureHost().addOrDeleteFile(fileName, missingFilePath, eventKind);
}
if (eventKind === FileWatcherEventKind.Created && this.missingFilesMap.has(missingFilePath)) {
+2 -2
View File
@@ -196,7 +196,7 @@ namespace ts.server {
/*@internal*/
export function isDynamicFileName(fileName: NormalizedPath) {
return getBaseFileName(fileName)[0] === "^";
return fileName[0] === "^" || getBaseFileName(fileName)[0] === "^";
}
export class ScriptInfo {
@@ -345,7 +345,7 @@ namespace ts.server {
detachAllProjects() {
for (const p of this.containingProjects) {
if (p.projectKind === ProjectKind.Configured) {
(p.directoryStructureHost as CachedDirectoryStructureHost).addOrDeleteFile(this.fileName, this.path, FileWatcherEventKind.Deleted);
p.getCachedDirectoryStructureHost().addOrDeleteFile(this.fileName, this.path, FileWatcherEventKind.Deleted);
}
const isInfoRoot = p.isRoot(this);
// detach is unnecessary since we'll clean the list of containing projects anyways
+3 -1
View File
@@ -11,6 +11,8 @@ declare namespace ts.server {
type RequireResult = { module: {}, error: undefined } | { module: undefined, error: { stack?: string, message?: string } };
export interface ServerHost extends System {
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
clearTimeout(timeoutId: any): void;
setImmediate(callback: (...args: any[]) => void, ...args: any[]): any;
@@ -129,4 +131,4 @@ declare namespace ts.server {
createDirectory(path: string): void;
watchFile?(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
}
}
}
-1
View File
@@ -10,7 +10,6 @@ namespace ts {
export interface CodeFixContextBase extends textChanges.TextChangesContext {
sourceFile: SourceFile;
program: Program;
host: LanguageServiceHost;
cancellationToken: CancellationToken;
}
+29 -23
View File
@@ -1,23 +1,25 @@
/* @internal */
namespace ts.codefix {
const fixId = "disableJsDiagnostics";
const errorCodes = mapDefined(Object.keys(Diagnostics), key => {
const diag = (Diagnostics as MapLike<DiagnosticMessage>)[key];
const errorCodes = mapDefined(Object.keys(Diagnostics) as ReadonlyArray<keyof typeof Diagnostics>, key => {
const diag = Diagnostics[key];
return diag.category === DiagnosticCategory.Error ? diag.code : undefined;
});
registerCodeFix({
errorCodes,
getCodeActions(context) {
const { sourceFile, program, newLineCharacter, span } = context;
const { sourceFile, program, span } = context;
if (!isInJavaScriptFile(sourceFile) || !isCheckJsEnabledForFile(sourceFile, program.getCompilerOptions())) {
return undefined;
}
const newLineCharacter = getNewLineOrDefaultFromHost(context.host, context.formatContext.options);
return [{
description: getLocaleSpecificMessage(Diagnostics.Ignore_this_error_message),
changes: [createFileTextChanges(sourceFile.fileName, [getIgnoreCommentLocationForLocation(sourceFile, span.start, newLineCharacter)])],
changes: [createFileTextChanges(sourceFile.fileName, [getIgnoreCommentLocationForLocation(sourceFile, span.start, newLineCharacter).change])],
fixId,
},
{
@@ -33,17 +35,23 @@ namespace ts.codefix {
fixId: undefined,
}];
},
fixIds: [fixId], // No point applying as a group, doing it once will fix all errors
getAllCodeActions: context => codeFixAllWithTextChanges(context, errorCodes, (changes, err) => {
if (err.start !== undefined) {
changes.push(getIgnoreCommentLocationForLocation(err.file!, err.start, context.newLineCharacter));
}
}),
fixIds: [fixId],
getAllCodeActions: context => {
const seenLines = createMap<true>(); // Only need to add `// @ts-ignore` for a line once.
return codeFixAllWithTextChanges(context, errorCodes, (changes, err) => {
if (err.start !== undefined) {
const { lineNumber, change } = getIgnoreCommentLocationForLocation(err.file!, err.start, getNewLineOrDefaultFromHost(context.host, context.formatContext.options));
if (addToSeen(seenLines, lineNumber)) {
changes.push(change);
}
}
});
},
});
function getIgnoreCommentLocationForLocation(sourceFile: SourceFile, position: number, newLineCharacter: string): TextChange {
const { line } = getLineAndCharacterOfPosition(sourceFile, position);
const lineStartPosition = getStartPositionOfLine(line, sourceFile);
function getIgnoreCommentLocationForLocation(sourceFile: SourceFile, position: number, newLineCharacter: string): { lineNumber: number, change: TextChange } {
const { line: lineNumber } = getLineAndCharacterOfPosition(sourceFile, position);
const lineStartPosition = getStartPositionOfLine(lineNumber, sourceFile);
const startPosition = getFirstNonSpaceCharacterPosition(sourceFile.text, lineStartPosition);
// First try to see if we can put the '// @ts-ignore' on the previous line.
@@ -52,19 +60,17 @@ namespace ts.codefix {
// if so, we do not want to separate the node from its comment if we can.
if (!isInComment(sourceFile, startPosition) && !isInString(sourceFile, startPosition) && !isInTemplateString(sourceFile, startPosition)) {
const token = getTouchingToken(sourceFile, startPosition, /*includeJsDocComment*/ false);
const tokenLeadingCommnets = getLeadingCommentRangesOfNode(token, sourceFile);
if (!tokenLeadingCommnets || !tokenLeadingCommnets.length || tokenLeadingCommnets[0].pos >= startPosition) {
return {
span: { start: startPosition, length: 0 },
newText: `// @ts-ignore${newLineCharacter}`
};
const tokenLeadingComments = getLeadingCommentRangesOfNode(token, sourceFile);
if (!tokenLeadingComments || !tokenLeadingComments.length || tokenLeadingComments[0].pos >= startPosition) {
return { lineNumber, change: createTextChange(startPosition, 0, `// @ts-ignore${newLineCharacter}`) };
}
}
// If all fails, add an extra new line immediately before the error span.
return {
span: { start: position, length: 0 },
newText: `${position === startPosition ? "" : newLineCharacter}// @ts-ignore${newLineCharacter}`
};
return { lineNumber, change: createTextChange(position, 0, `${position === startPosition ? "" : newLineCharacter}// @ts-ignore${newLineCharacter}`) };
}
function createTextChange(start: number, length: number, newText: string): TextChange {
return { span: { start, length }, newText };
}
}
@@ -142,7 +142,7 @@ namespace ts.codefix {
return typeNode || createKeywordTypeNode(SyntaxKind.AnyKeyword);
}
function createAddPropertyDeclarationAction(context: textChanges.TextChangesContext, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, makeStatic: boolean, tokenName: string, typeNode: TypeNode): CodeFixAction {
function createAddPropertyDeclarationAction(context: CodeFixContext, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, makeStatic: boolean, tokenName: string, typeNode: TypeNode): CodeFixAction {
const description = formatStringFromArgs(getLocaleSpecificMessage(makeStatic ? Diagnostics.Declare_static_property_0 : Diagnostics.Declare_property_0), [tokenName]);
const changes = textChanges.ChangeTracker.with(context, t => addPropertyDeclaration(t, classDeclarationSourceFile, classDeclaration, tokenName, typeNode, makeStatic));
return { description, changes, fixId };
@@ -159,7 +159,7 @@ namespace ts.codefix {
changeTracker.insertNodeAtClassStart(classDeclarationSourceFile, classDeclaration, property);
}
function createAddIndexSignatureAction(context: textChanges.TextChangesContext, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, tokenName: string, typeNode: TypeNode): CodeFixAction {
function createAddIndexSignatureAction(context: CodeFixContext, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, tokenName: string, typeNode: TypeNode): CodeFixAction {
// Index signatures cannot have the static modifier.
const stringTypeNode = createKeywordTypeNode(SyntaxKind.StringKeyword);
const indexingParameter = createParameter(
@@ -181,7 +181,7 @@ namespace ts.codefix {
return { description: formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Add_index_signature_for_property_0), [tokenName]), changes, fixId: undefined };
}
function getActionForMethodDeclaration(context: textChanges.TextChangesContext, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, token: Identifier, callExpression: CallExpression, makeStatic: boolean, inJs: boolean): CodeFixAction | undefined {
function getActionForMethodDeclaration(context: CodeFixContext, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, token: Identifier, callExpression: CallExpression, makeStatic: boolean, inJs: boolean): CodeFixAction | undefined {
const description = formatStringFromArgs(getLocaleSpecificMessage(makeStatic ? Diagnostics.Declare_static_method_0 : Diagnostics.Declare_method_0), [token.text]);
const changes = textChanges.ChangeTracker.with(context, t => addMethodDeclaration(t, classDeclarationSourceFile, classDeclaration, token, callExpression, makeStatic, inJs));
return { description, changes, fixId };
+3 -8
View File
@@ -29,12 +29,8 @@ namespace ts.codefix {
symbolName: string;
}
interface SymbolAndTokenContext extends SymbolContext {
interface ImportCodeFixContext extends SymbolContext {
symbolToken: Identifier | undefined;
}
interface ImportCodeFixContext extends SymbolAndTokenContext {
host: LanguageServiceHost;
program: Program;
checker: TypeChecker;
compilerOptions: CompilerOptions;
@@ -173,7 +169,6 @@ namespace ts.codefix {
const symbolToken = cast(getTokenAtPosition(context.sourceFile, context.span.start, /*includeJsDocComment*/ false), isIdentifier);
return {
host: context.host,
newLineCharacter: context.newLineCharacter,
formatContext: context.formatContext,
sourceFile: context.sourceFile,
program,
@@ -395,7 +390,7 @@ namespace ts.codefix {
In this case we should prefer using the relative path "../a" instead of the baseUrl path "foo/a".
*/
const pathFromSourceToBaseUrl = getRelativePath(baseUrl, sourceDirectory, getCanonicalFileName);
const relativeFirst = getRelativePathNParents(pathFromSourceToBaseUrl) < getRelativePathNParents(relativePath);
const relativeFirst = getRelativePathNParents(relativePath) < getRelativePathNParents(pathFromSourceToBaseUrl);
return relativeFirst ? [relativePath, importRelativeToBaseUrl] : [importRelativeToBaseUrl, relativePath];
}));
// Only return results for the re-export with the shortest possible path (and also give the other path even if that's long.)
@@ -472,7 +467,7 @@ namespace ts.codefix {
addJsExtension: boolean,
): string | undefined {
const roots = getEffectiveTypeRoots(options, host);
return roots && firstDefined(roots, unNormalizedTypeRoot => {
return firstDefined(roots, unNormalizedTypeRoot => {
const typeRoot = toPath(unNormalizedTypeRoot, /*basePath*/ undefined, getCanonicalFileName);
if (startsWith(moduleFileName, typeRoot)) {
return removeExtensionAndIndexPostFix(moduleFileName.substring(typeRoot.length + 1), options, addJsExtension);
+107 -63
View File
@@ -20,6 +20,8 @@ namespace ts.Completions {
None,
ClassElementKeywords, // Keywords at class keyword
ConstructorParameterKeywords, // Keywords at constructor parameter
FunctionLikeBodyKeywords, // Keywords at function like body
TypeKeywords,
}
export function getCompletionsAtPosition(
@@ -76,7 +78,7 @@ namespace ts.Completions {
}
function completionInfoFromData(sourceFile: SourceFile, typeChecker: TypeChecker, compilerOptions: CompilerOptions, log: Log, completionData: CompletionData, includeInsertTextCompletions: boolean): CompletionInfo {
const { symbols, completionKind, isNewIdentifierLocation, location, propertyAccessToConvert, keywordFilters, symbolToOriginInfoMap, recommendedCompletion } = completionData;
const { symbols, completionKind, isNewIdentifierLocation, location, propertyAccessToConvert, keywordFilters, symbolToOriginInfoMap, recommendedCompletion, isJsxInitializer } = completionData;
if (sourceFile.languageVariant === LanguageVariant.JSX && location && location.parent && isJsxClosingElement(location.parent)) {
// In the TypeScript JSX element, if such element is not defined. When users query for completion at closing tag,
@@ -97,7 +99,7 @@ namespace ts.Completions {
const entries: CompletionEntry[] = [];
if (isSourceFileJavaScript(sourceFile)) {
const uniqueNames = getCompletionEntriesFromSymbols(symbols, entries, location, sourceFile, typeChecker, compilerOptions.target, log, completionKind, includeInsertTextCompletions, propertyAccessToConvert, recommendedCompletion, symbolToOriginInfoMap);
const uniqueNames = getCompletionEntriesFromSymbols(symbols, entries, location, sourceFile, typeChecker, compilerOptions.target, log, completionKind, includeInsertTextCompletions, propertyAccessToConvert, isJsxInitializer, recommendedCompletion, symbolToOriginInfoMap);
getJavaScriptCompletionEntries(sourceFile, location.pos, uniqueNames, compilerOptions.target, entries);
}
else {
@@ -105,7 +107,7 @@ namespace ts.Completions {
return undefined;
}
getCompletionEntriesFromSymbols(symbols, entries, location, sourceFile, typeChecker, compilerOptions.target, log, completionKind, includeInsertTextCompletions, propertyAccessToConvert, recommendedCompletion, symbolToOriginInfoMap);
getCompletionEntriesFromSymbols(symbols, entries, location, sourceFile, typeChecker, compilerOptions.target, log, completionKind, includeInsertTextCompletions, propertyAccessToConvert, isJsxInitializer, recommendedCompletion, symbolToOriginInfoMap);
}
// TODO add filter for keyword based on type/value/namespace and also location
@@ -165,6 +167,7 @@ namespace ts.Completions {
origin: SymbolOriginInfo | undefined,
recommendedCompletion: Symbol | undefined,
propertyAccessToConvert: PropertyAccessExpression | undefined,
isJsxInitializer: boolean,
includeInsertTextCompletions: boolean,
): CompletionEntry | undefined {
const info = getCompletionEntryDisplayNameForSymbol(symbol, target, origin, kind);
@@ -172,19 +175,27 @@ namespace ts.Completions {
return undefined;
}
const { name, needsConvertPropertyAccess } = info;
if (needsConvertPropertyAccess && !includeInsertTextCompletions) {
return undefined;
}
let insertText: string | undefined;
let replacementSpan: TextSpan | undefined;
if (kind === CompletionKind.Global && origin && origin.type === "this-type") {
insertText = needsConvertPropertyAccess ? `this["${name}"]` : `this.${name}`;
if (includeInsertTextCompletions) {
if (origin && origin.type === "this-type") {
insertText = needsConvertPropertyAccess ? `this["${name}"]` : `this.${name}`;
}
else if (needsConvertPropertyAccess) {
// TODO: GH#20619 Use configured quote style
insertText = `["${name}"]`;
replacementSpan = createTextSpanFromBounds(findChildOfKind(propertyAccessToConvert!, SyntaxKind.DotToken, sourceFile)!.getStart(sourceFile), propertyAccessToConvert!.name.end);
}
if (isJsxInitializer) {
if (insertText === undefined) insertText = name;
insertText = `{${insertText}}`;
}
}
else if (needsConvertPropertyAccess) {
// TODO: GH#20619 Use configured quote style
insertText = `["${name}"]`;
replacementSpan = createTextSpanFromBounds(findChildOfKind(propertyAccessToConvert!, SyntaxKind.DotToken, sourceFile)!.getStart(sourceFile), propertyAccessToConvert!.name.end);
if (insertText !== undefined && !includeInsertTextCompletions) {
return undefined;
}
// TODO(drosen): Right now we just permit *all* semantic meanings when calling
@@ -233,6 +244,7 @@ namespace ts.Completions {
kind: CompletionKind,
includeInsertTextCompletions?: boolean,
propertyAccessToConvert?: PropertyAccessExpression | undefined,
isJsxInitializer?: boolean,
recommendedCompletion?: Symbol,
symbolToOriginInfoMap?: SymbolOriginInfoMap,
): Map<true> {
@@ -244,7 +256,7 @@ namespace ts.Completions {
const uniques = createMap<true>();
for (const symbol of symbols) {
const origin = symbolToOriginInfoMap ? symbolToOriginInfoMap[getSymbolId(symbol)] : undefined;
const entry = createCompletionEntry(symbol, location, sourceFile, typeChecker, target, kind, origin, recommendedCompletion, propertyAccessToConvert, includeInsertTextCompletions);
const entry = createCompletionEntry(symbol, location, sourceFile, typeChecker, target, kind, origin, recommendedCompletion, propertyAccessToConvert, isJsxInitializer, includeInsertTextCompletions);
if (!entry) {
continue;
}
@@ -481,6 +493,7 @@ namespace ts.Completions {
location: Node;
symbolToOriginInfoMap: SymbolOriginInfoMap;
previousToken: Node;
readonly isJsxInitializer: boolean;
}
function getSymbolCompletionFromEntryId(
typeChecker: TypeChecker,
@@ -499,7 +512,7 @@ namespace ts.Completions {
return { type: "request", request: completionData };
}
const { symbols, location, completionKind, symbolToOriginInfoMap, previousToken } = completionData;
const { symbols, location, completionKind, symbolToOriginInfoMap, previousToken, isJsxInitializer } = completionData;
// Find the symbol with the matching entry name.
// We don't need to perform character checks here because we're only comparing the
@@ -508,7 +521,7 @@ namespace ts.Completions {
return firstDefined<Symbol, SymbolCompletion>(symbols, (symbol): SymbolCompletion => { // TODO: Shouldn't need return type annotation (GH#12632)
const origin = symbolToOriginInfoMap[getSymbolId(symbol)];
const info = getCompletionEntryDisplayNameForSymbol(symbol, compilerOptions.target, origin, completionKind);
return info && info.name === name && getSourceFromOrigin(origin) === source ? { type: "symbol" as "symbol", symbol, location, symbolToOriginInfoMap, previousToken } : undefined;
return info && info.name === name && getSourceFromOrigin(origin) === source ? { type: "symbol" as "symbol", symbol, location, symbolToOriginInfoMap, previousToken, isJsxInitializer } : undefined;
}) || { type: "none" };
}
@@ -564,7 +577,7 @@ namespace ts.Completions {
}
case "none": {
// Didn't find a symbol with this name. See if we can find a keyword instead.
if (some(getKeywordCompletions(KeywordCompletionFilters.None), c => c.name === name)) {
if (allKeywordsCompletions().some(c => c.name === name)) {
return {
name,
kind: ScriptElementKind.keyword,
@@ -627,7 +640,6 @@ namespace ts.Completions {
host,
program,
checker,
newLineCharacter: host.getNewLine(),
compilerOptions,
sourceFile,
formatContext,
@@ -677,11 +689,13 @@ namespace ts.Completions {
readonly symbolToOriginInfoMap: SymbolOriginInfoMap;
readonly recommendedCompletion: Symbol | undefined;
readonly previousToken: Node | undefined;
readonly isJsxInitializer: boolean;
}
type Request = { readonly kind: CompletionDataKind.JsDocTagName | CompletionDataKind.JsDocTag } | { readonly kind: CompletionDataKind.JsDocParameterName, tag: JSDocParameterTag };
const enum CompletionKind {
ObjectPropertyDeclaration,
/** Note that sometimes we access completions from global scope, but use "None" instead of this. See isGlobalCompletionScope. */
Global,
PropertyAccess,
MemberLike,
@@ -857,6 +871,7 @@ namespace ts.Completions {
let isRightOfDot = false;
let isRightOfOpenTag = false;
let isStartingCloseTag = false;
let isJsxInitializer = false;
let location = getTouchingPropertyName(sourceFile, position, insideJsDocTagTypeExpression); // TODO: GH#15853
if (contextToken) {
@@ -915,6 +930,10 @@ namespace ts.Completions {
location = contextToken;
}
break;
case SyntaxKind.JsxAttribute:
isJsxInitializer = previousToken.kind === SyntaxKind.EqualsToken;
break;
}
}
}
@@ -960,7 +979,7 @@ namespace ts.Completions {
log("getCompletionData: Semantic work: " + (timestamp() - semanticStart));
const recommendedCompletion = previousToken && getRecommendedCompletion(previousToken, typeChecker);
return { kind: CompletionDataKind.Data, symbols, completionKind, propertyAccessToConvert, isNewIdentifierLocation, location, keywordFilters, symbolToOriginInfoMap, recommendedCompletion, previousToken };
return { kind: CompletionDataKind.Data, symbols, completionKind, propertyAccessToConvert, isNewIdentifierLocation, location, keywordFilters, symbolToOriginInfoMap, recommendedCompletion, previousToken, isJsxInitializer };
type JSDocTagWithTypeExpression = JSDocParameterTag | JSDocPropertyTag | JSDocReturnTag | JSDocTypeTag | JSDocTypedefTag;
@@ -1061,6 +1080,10 @@ namespace ts.Completions {
return true;
}
if (tryGetFunctionLikeBodyCompletionContainer(contextToken)) {
keywordFilters = KeywordCompletionFilters.FunctionLikeBodyKeywords;
}
if (classLikeContainer = tryGetClassLikeCompletionContainer(contextToken)) {
// cursor inside class declaration
getGetClassLikeCompletionSymbols(classLikeContainer);
@@ -1159,6 +1182,9 @@ namespace ts.Completions {
}
function filterGlobalCompletion(symbols: Symbol[]): void {
const isTypeCompletion = insideJsDocTagTypeExpression || !isContextTokenValueLocation(contextToken) && (isPartOfTypeNode(location) || isContextTokenTypeLocation(contextToken));
if (isTypeCompletion) keywordFilters = KeywordCompletionFilters.TypeKeywords;
filterMutate(symbols, symbol => {
if (!isSourceFile(location)) {
// export = /**/ here we want to get all meanings, so any symbol is ok
@@ -1166,19 +1192,14 @@ namespace ts.Completions {
return true;
}
// This is an alias, follow what it aliases
if (symbol && symbol.flags & SymbolFlags.Alias) {
symbol = typeChecker.getAliasedSymbol(symbol);
}
symbol = skipAlias(symbol, typeChecker);
// import m = /**/ <-- It can only access namespace (if typing import = x. this would get member symbols and not namespace)
if (isInRightSideOfInternalImportEqualsDeclaration(location)) {
return !!(symbol.flags & SymbolFlags.Namespace);
}
if (insideJsDocTagTypeExpression ||
(!isContextTokenValueLocation(contextToken) &&
(isPartOfTypeNode(location) || isContextTokenTypeLocation(contextToken)))) {
if (isTypeCompletion) {
// Its a type, but you can reach it by namespace.type as well
return symbolCanBeReferencedAtTypeLocation(symbol);
}
@@ -1195,7 +1216,7 @@ namespace ts.Completions {
contextToken.parent.kind === SyntaxKind.TypeQuery;
}
function isContextTokenTypeLocation(contextToken: Node) {
function isContextTokenTypeLocation(contextToken: Node): boolean {
if (contextToken) {
const parentKind = contextToken.parent.kind;
switch (contextToken.kind) {
@@ -1213,6 +1234,7 @@ namespace ts.Completions {
return parentKind === SyntaxKind.AsExpression;
}
}
return false;
}
function symbolCanBeReferencedAtTypeLocation(symbol: Symbol): boolean {
@@ -1689,6 +1711,22 @@ namespace ts.Completions {
return undefined;
}
function tryGetFunctionLikeBodyCompletionContainer(contextToken: Node): FunctionLikeDeclaration {
if (contextToken) {
let prev: Node;
const container = findAncestor(contextToken.parent, (node: Node) => {
if (isClassLike(node)) {
return "quit";
}
if (isFunctionLikeDeclaration(node) && prev === node.body) {
return true;
}
prev = node;
});
return container && container as FunctionLikeDeclaration;
}
}
function tryGetContainingJsxElement(contextToken: Node): JsxOpeningLikeElement {
if (contextToken) {
const parent = contextToken.parent;
@@ -2092,13 +2130,13 @@ namespace ts.Completions {
const validIdentiferResult: CompletionEntryDisplayNameForSymbol = { name, needsConvertPropertyAccess: false };
if (isIdentifierText(name, target)) return validIdentiferResult;
switch (kind) {
case CompletionKind.None:
case CompletionKind.MemberLike:
return undefined;
case CompletionKind.ObjectPropertyDeclaration:
// TODO: GH#18169
return { name: JSON.stringify(name), needsConvertPropertyAccess: false };
case CompletionKind.PropertyAccess:
case CompletionKind.None:
case CompletionKind.Global:
// Don't add a completion for a name starting with a space. See https://github.com/Microsoft/TypeScript/pull/20547
return name.charCodeAt(0) === CharacterCodes.space ? undefined : { name, needsConvertPropertyAccess: true };
@@ -2110,49 +2148,38 @@ namespace ts.Completions {
}
// A cache of completion entries for keywords, these do not change between sessions
const _keywordCompletions: CompletionEntry[][] = [];
function getKeywordCompletions(keywordFilter: KeywordCompletionFilters): CompletionEntry[] {
const completions = _keywordCompletions[keywordFilter];
if (completions) {
return completions;
const _keywordCompletions: ReadonlyArray<CompletionEntry>[] = [];
const allKeywordsCompletions: () => ReadonlyArray<CompletionEntry> = ts.memoize(() => {
const res: CompletionEntry[] = [];
for (let i = SyntaxKind.FirstKeyword; i <= SyntaxKind.LastKeyword; i++) {
res.push({
name: tokenToString(i),
kind: ScriptElementKind.keyword,
kindModifiers: ScriptElementKindModifier.none,
sortText: "0"
});
}
return _keywordCompletions[keywordFilter] = generateKeywordCompletions(keywordFilter);
type FilterKeywordCompletions = (entryName: string) => boolean;
function generateKeywordCompletions(keywordFilter: KeywordCompletionFilters): CompletionEntry[] {
return res;
});
function getKeywordCompletions(keywordFilter: KeywordCompletionFilters): ReadonlyArray<CompletionEntry> {
return _keywordCompletions[keywordFilter] || (_keywordCompletions[keywordFilter] = allKeywordsCompletions().filter(entry => {
const kind = stringToToken(entry.name);
switch (keywordFilter) {
case KeywordCompletionFilters.None:
return getAllKeywordCompletions();
// "undefined" is a global variable, so don't need a keyword completion for it.
return kind !== SyntaxKind.UndefinedKeyword;
case KeywordCompletionFilters.ClassElementKeywords:
return getFilteredKeywordCompletions(isClassMemberCompletionKeywordText);
return isClassMemberCompletionKeyword(kind);
case KeywordCompletionFilters.ConstructorParameterKeywords:
return getFilteredKeywordCompletions(isConstructorParameterCompletionKeywordText);
return isConstructorParameterCompletionKeyword(kind);
case KeywordCompletionFilters.FunctionLikeBodyKeywords:
return isFunctionLikeBodyCompletionKeyword(kind);
case KeywordCompletionFilters.TypeKeywords:
return isTypeKeyword(kind);
default:
Debug.assertNever(keywordFilter);
return Debug.assertNever(keywordFilter);
}
}
function getAllKeywordCompletions() {
const allKeywordsCompletions: CompletionEntry[] = [];
for (let i = SyntaxKind.FirstKeyword; i <= SyntaxKind.LastKeyword; i++) {
// "undefined" is a global variable, so don't need a keyword completion for it.
if (i === SyntaxKind.UndefinedKeyword) continue;
allKeywordsCompletions.push({
name: tokenToString(i),
kind: ScriptElementKind.keyword,
kindModifiers: ScriptElementKindModifier.none,
sortText: "0"
});
}
return allKeywordsCompletions;
}
function getFilteredKeywordCompletions(filterFn: FilterKeywordCompletions) {
return filter(
getKeywordCompletions(KeywordCompletionFilters.None),
entry => filterFn(entry.name)
);
}
}));
}
function isClassMemberCompletionKeyword(kind: SyntaxKind) {
@@ -2189,6 +2216,23 @@ namespace ts.Completions {
return isConstructorParameterCompletionKeyword(stringToToken(text));
}
function isFunctionLikeBodyCompletionKeyword(kind: SyntaxKind) {
switch (kind) {
case SyntaxKind.PublicKeyword:
case SyntaxKind.PrivateKeyword:
case SyntaxKind.ProtectedKeyword:
case SyntaxKind.ReadonlyKeyword:
case SyntaxKind.ConstructorKeyword:
case SyntaxKind.StaticKeyword:
case SyntaxKind.AbstractKeyword:
case SyntaxKind.GetKeyword:
case SyntaxKind.SetKeyword:
case SyntaxKind.UndefinedKeyword:
return false;
}
return true;
}
function isEqualityOperatorKind(kind: ts.SyntaxKind): kind is EqualityOperator {
switch (kind) {
case ts.SyntaxKind.EqualsEqualsEqualsToken:
+8 -4
View File
@@ -44,7 +44,7 @@ namespace ts.FindAllReferences {
export function findReferencedSymbols(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, sourceFile: SourceFile, position: number): ReferencedSymbol[] | undefined {
const referencedSymbols = findAllReferencedSymbols(program, cancellationToken, sourceFiles, sourceFile, position);
const checker = program.getTypeChecker();
return !referencedSymbols || !referencedSymbols.length ? undefined : mapDefined(referencedSymbols, ({ definition, references }) =>
return !referencedSymbols || !referencedSymbols.length ? undefined : mapDefined<SymbolAndEntries, ReferencedSymbol>(referencedSymbols, ({ definition, references }) =>
// Only include referenced symbols that have a valid definition.
definition && { definition: definitionToReferencedSymbolDefinitionInfo(definition, checker), references: references.map(toReferenceEntry) });
}
@@ -356,7 +356,7 @@ namespace ts.FindAllReferences.Core {
/** Core find-all-references algorithm for a normal symbol. */
function getReferencedSymbolsForSymbol(symbol: Symbol, node: Node, sourceFiles: ReadonlyArray<SourceFile>, checker: TypeChecker, cancellationToken: CancellationToken, options: Options): SymbolAndEntries[] {
symbol = skipPastExportOrImportSpecifier(symbol, node, checker);
symbol = skipPastExportOrImportSpecifierOrUnion(symbol, node, checker);
// Compute the meaning from the location and the symbol it references
const searchMeaning = getIntersectingMeaningFromDeclarations(getMeaningFromLocation(node), symbol.declarations);
@@ -405,7 +405,7 @@ namespace ts.FindAllReferences.Core {
}
/** Handle a few special cases relating to export/import specifiers. */
function skipPastExportOrImportSpecifier(symbol: Symbol, node: Node, checker: TypeChecker): Symbol {
function skipPastExportOrImportSpecifierOrUnion(symbol: Symbol, node: Node, checker: TypeChecker): Symbol {
const { parent } = node;
if (isExportSpecifier(parent)) {
return getLocalSymbolForExportSpecifier(node as Identifier, symbol, parent, checker);
@@ -415,7 +415,11 @@ namespace ts.FindAllReferences.Core {
return checker.getImmediateAliasedSymbol(symbol);
}
return symbol;
// If the symbol is declared as part of a declaration like `{ type: "a" } | { type: "b" }`, use the property on the union type to get more references.
return firstDefined(symbol.declarations, decl =>
isTypeLiteralNode(decl.parent) && isUnionTypeNode(decl.parent.parent)
? checker.getPropertyOfType(checker.getTypeFromTypeNode(decl.parent.parent), symbol.name)
: undefined) || symbol;
}
/**
+3
View File
@@ -321,6 +321,9 @@ namespace ts.formatting {
rule("NoSpaceAfterCloseBracket", SyntaxKind.CloseBracketToken, anyToken, [isNonJsxSameLineTokenContext, isNotBeforeBlockInFunctionDeclarationContext], RuleAction.Delete),
rule("SpaceAfterSemicolon", SyntaxKind.SemicolonToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.Space),
// Remove extra space between for and await
rule("SpaceBetweenForAndAwaitKeyword", SyntaxKind.ForKeyword, SyntaxKind.AwaitKeyword, [isNonJsxSameLineTokenContext], RuleAction.Space),
// Add a space between statements. All keywords except (do,else,case) has open/close parens after them.
// So, we have a rule to add a space for [),Any], [do,Any], [else,Any], and [case,Any]
rule(
+18 -66
View File
@@ -127,30 +127,16 @@ namespace ts.GoToDefinition {
}
const symbol = typeChecker.getSymbolAtLocation(node);
if (!symbol) {
return undefined;
}
const type = typeChecker.getTypeOfSymbolAtLocation(symbol, node);
const type = symbol && typeChecker.getTypeOfSymbolAtLocation(symbol, node);
if (!type) {
return undefined;
}
if (type.flags & TypeFlags.Union && !(type.flags & TypeFlags.Enum)) {
const result: DefinitionInfo[] = [];
forEach((<UnionType>type).types, t => {
if (t.symbol) {
addRange(/*to*/ result, /*from*/ getDefinitionFromSymbol(typeChecker, t.symbol, node));
}
});
return result;
return flatMap((<UnionType>type).types, t => t.symbol && getDefinitionFromSymbol(typeChecker, t.symbol, node));
}
if (!type.symbol) {
return undefined;
}
return getDefinitionFromSymbol(typeChecker, type.symbol, node);
return type.symbol && getDefinitionFromSymbol(typeChecker, type.symbol, node);
}
export function getDefinitionAndBoundSpan(program: Program, sourceFile: SourceFile, position: number): DefinitionInfoAndBoundSpan {
@@ -199,66 +185,32 @@ namespace ts.GoToDefinition {
}
function getDefinitionFromSymbol(typeChecker: TypeChecker, symbol: Symbol, node: Node): DefinitionInfo[] {
const result: DefinitionInfo[] = [];
const declarations = symbol.getDeclarations();
const { symbolName, symbolKind, containerName } = getSymbolInfo(typeChecker, symbol, node);
return getConstructSignatureDefinition() || getCallSignatureDefinition() || map(symbol.declarations, declaration => createDefinitionInfo(declaration, symbolKind, symbolName, containerName));
if (!tryAddConstructSignature(symbol, node, symbolKind, symbolName, containerName, result) &&
!tryAddCallSignature(symbol, node, symbolKind, symbolName, containerName, result)) {
// Just add all the declarations.
forEach(declarations, declaration => {
result.push(createDefinitionInfo(declaration, symbolKind, symbolName, containerName));
});
}
return result;
function tryAddConstructSignature(symbol: Symbol, location: Node, symbolKind: ScriptElementKind, symbolName: string, containerName: string, result: DefinitionInfo[]) {
function getConstructSignatureDefinition(): DefinitionInfo[] | undefined {
// Applicable only if we are in a new expression, or we are on a constructor declaration
// and in either case the symbol has a construct signature definition, i.e. class
if (isNewExpressionTarget(location) || location.kind === SyntaxKind.ConstructorKeyword) {
if (symbol.flags & SymbolFlags.Class) {
// Find the first class-like declaration and try to get the construct signature.
for (const declaration of symbol.getDeclarations()) {
if (isClassLike(declaration)) {
return tryAddSignature(
declaration.members, /*selectConstructors*/ true, symbolKind, symbolName, containerName, result);
}
}
Debug.fail("Expected declaration to have at least one class-like declaration");
}
if (isNewExpressionTarget(node) || node.kind === SyntaxKind.ConstructorKeyword && symbol.flags & SymbolFlags.Class) {
const cls = find(symbol.declarations, isClassLike) || Debug.fail("Expected declaration to have at least one class-like declaration");
return getSignatureDefinition(cls.members, /*selectConstructors*/ true);
}
return false;
}
function tryAddCallSignature(symbol: Symbol, location: Node, symbolKind: ScriptElementKind, symbolName: string, containerName: string, result: DefinitionInfo[]) {
if (isCallExpressionTarget(location) || isNewExpressionTarget(location) || isNameOfFunctionDeclaration(location)) {
return tryAddSignature(symbol.declarations, /*selectConstructors*/ false, symbolKind, symbolName, containerName, result);
}
return false;
function getCallSignatureDefinition(): DefinitionInfo[] | undefined {
return isCallExpressionTarget(node) || isNewExpressionTarget(node) || isNameOfFunctionDeclaration(node)
? getSignatureDefinition(symbol.declarations, /*selectConstructors*/ false)
: undefined;
}
function tryAddSignature(signatureDeclarations: ReadonlyArray<Declaration> | undefined, selectConstructors: boolean, symbolKind: ScriptElementKind, symbolName: string, containerName: string, result: DefinitionInfo[]) {
function getSignatureDefinition(signatureDeclarations: ReadonlyArray<Declaration> | undefined, selectConstructors: boolean): DefinitionInfo[] | undefined {
if (!signatureDeclarations) {
return false;
return undefined;
}
const declarations: Declaration[] = [];
let definition: Declaration | undefined;
for (const d of signatureDeclarations) {
if (selectConstructors ? d.kind === SyntaxKind.Constructor : isSignatureDeclaration(d)) {
declarations.push(d);
if ((<FunctionLikeDeclaration>d).body) definition = d;
}
}
if (declarations.length) {
result.push(createDefinitionInfo(definition || lastOrUndefined(declarations), symbolKind, symbolName, containerName));
return true;
}
return false;
const declarations = signatureDeclarations.filter(selectConstructors ? isConstructorDeclaration : isSignatureDeclaration);
return declarations.length
? [createDefinitionInfo(find(declarations, d => !!(<FunctionLikeDeclaration>d).body) || last(declarations), symbolKind, symbolName, containerName)]
: undefined;
}
}
+22 -1
View File
@@ -510,11 +510,32 @@ namespace ts.FindAllReferences {
return undefined;
}
const sym = useLhsSymbol ? checker.getSymbolAtLocation((node.left as ts.PropertyAccessExpression).name) : symbol;
const sym = useLhsSymbol ? checker.getSymbolAtLocation(cast(node.left, isPropertyAccessExpression).name) : symbol;
// Better detection for GH#20803
if (sym && !(checker.getMergedSymbol(sym.parent).flags & SymbolFlags.Module)) {
Debug.fail(`Special property assignment kind does not have a module as its parent. Assignment is ${showSymbol(sym)}, parent is ${showSymbol(sym.parent)}`);
}
return sym && exportInfo(sym, kind);
}
}
function showSymbol(s: Symbol): string {
const decls = s.declarations.map(d => (ts as any).SyntaxKind[d.kind]).join(",");
const flags = showFlags(s.flags, (ts as any).SymbolFlags);
return `{ declarations: ${decls}, flags: ${flags} }`;
}
function showFlags(f: number, flags: any) {
const out = [];
for (let pow = 0; pow <= 30; pow++) {
const n = 1 << pow;
if (f & n) {
out.push(flags[n]);
}
}
return out.join("|");
}
function getImport(): ImportedSymbol | undefined {
const isImport = isNodeImport(node);
if (!isImport) return undefined;
+3 -9
View File
@@ -1,12 +1,6 @@
/* @internal */
namespace ts {
export interface Refactor {
/** An unique code associated with each refactor */
name: string;
/** Description of the refactor to display in the UI of the editor */
description: string;
/** Compute the associated code actions */
getEditsForAction(context: RefactorContext, actionName: string): RefactorEditInfo | undefined;
@@ -19,7 +13,6 @@ namespace ts {
startPosition: number;
endPosition?: number;
program: Program;
host: LanguageServiceHost;
cancellationToken?: CancellationToken;
}
@@ -28,8 +21,9 @@ namespace ts {
// e.g. nonSuggestableRefactors[refactorCode] -> the refactor you want
const refactors: Map<Refactor> = createMap<Refactor>();
export function registerRefactor(refactor: Refactor) {
refactors.set(refactor.name, refactor);
/** @param name An unique code associated with each refactor. Does not have to be human-readable. */
export function registerRefactor(name: string, refactor: Refactor) {
refactors.set(name, refactor);
}
export function getApplicableRefactors(context: RefactorContext): ApplicableRefactorInfo[] {
@@ -1,13 +1,10 @@
/* @internal */
namespace ts.refactor.annotateWithTypeFromJSDoc {
const refactorName = "Annotate with type from JSDoc";
const actionName = "annotate";
const description = Diagnostics.Annotate_with_type_from_JSDoc.message;
registerRefactor(refactorName, { getEditsForAction, getAvailableActions });
const annotateTypeFromJSDoc: Refactor = {
name: "Annotate with type from JSDoc",
description: Diagnostics.Annotate_with_type_from_JSDoc.message,
getEditsForAction,
getAvailableActions
};
type DeclarationWithType =
| FunctionLikeDeclaration
| VariableDeclaration
@@ -15,8 +12,6 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
| PropertySignature
| PropertyDeclaration;
registerRefactor(annotateTypeFromJSDoc);
function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined {
if (isInJavaScriptFile(context.file)) {
return undefined;
@@ -25,11 +20,11 @@ namespace ts.refactor.annotateWithTypeFromJSDoc {
const node = getTokenAtPosition(context.file, context.startPosition, /*includeJsDocComment*/ false);
if (hasUsableJSDoc(findAncestor(node, isDeclarationWithType))) {
return [{
name: annotateTypeFromJSDoc.name,
description: annotateTypeFromJSDoc.description,
name: refactorName,
description,
actions: [
{
description: annotateTypeFromJSDoc.description,
description,
name: actionName
}
]
@@ -1,16 +1,10 @@
/* @internal */
namespace ts.refactor.convertFunctionToES6Class {
const refactorName = "Convert to ES2015 class";
const actionName = "convert";
const convertFunctionToES6Class: Refactor = {
name: "Convert to ES2015 class",
description: Diagnostics.Convert_function_to_an_ES2015_class.message,
getEditsForAction,
getAvailableActions
};
registerRefactor(convertFunctionToES6Class);
const description = Diagnostics.Convert_function_to_an_ES2015_class.message;
registerRefactor(refactorName, { getEditsForAction, getAvailableActions });
function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined {
if (!isInJavaScriptFile(context.file)) {
@@ -29,11 +23,11 @@ namespace ts.refactor.convertFunctionToES6Class {
if ((symbol.flags & SymbolFlags.Function) && symbol.members && (symbol.members.size > 0)) {
return [
{
name: convertFunctionToES6Class.name,
description: convertFunctionToES6Class.description,
name: refactorName,
description,
actions: [
{
description: convertFunctionToES6Class.description,
description,
name: actionName
}
]
+5 -12
View File
@@ -1,15 +1,8 @@
/* @internal */
namespace ts.refactor {
const actionName = "Convert to ES6 module";
const convertToEs6Module: Refactor = {
name: actionName,
description: getLocaleSpecificMessage(Diagnostics.Convert_to_ES6_module),
getEditsForAction,
getAvailableActions,
};
registerRefactor(convertToEs6Module);
const description = getLocaleSpecificMessage(Diagnostics.Convert_to_ES6_module);
registerRefactor(actionName, { getEditsForAction, getAvailableActions });
function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined {
const { file, startPosition } = context;
@@ -20,11 +13,11 @@ namespace ts.refactor {
const node = getTokenAtPosition(file, startPosition, /*includeJsDocComment*/ false);
return !isAtTriggerLocation(file, node) ? undefined : [
{
name: convertToEs6Module.name,
description: convertToEs6Module.description,
name: actionName,
description,
actions: [
{
description: convertToEs6Module.description,
description,
name: actionName,
},
],
+21 -10
View File
@@ -3,14 +3,8 @@
/* @internal */
namespace ts.refactor.extractSymbol {
const extractSymbol: Refactor = {
name: "Extract Symbol",
description: getLocaleSpecificMessage(Diagnostics.Extract_symbol),
getAvailableActions,
getEditsForAction,
};
registerRefactor(extractSymbol);
const refactorName = "Extract Symbol";
registerRefactor(refactorName, { getAvailableActions, getEditsForAction });
/**
* Compute the associated code actions
@@ -77,7 +71,7 @@ namespace ts.refactor.extractSymbol {
if (functionActions.length) {
infos.push({
name: extractSymbol.name,
name: refactorName,
description: getLocaleSpecificMessage(Diagnostics.Extract_function),
actions: functionActions
});
@@ -85,7 +79,7 @@ namespace ts.refactor.extractSymbol {
if (constantActions.length) {
infos.push({
name: extractSymbol.name,
name: refactorName,
description: getLocaleSpecificMessage(Diagnostics.Extract_constant),
actions: constantActions
});
@@ -241,6 +235,16 @@ namespace ts.refactor.extractSymbol {
break;
}
}
if (!statements.length) {
// https://github.com/Microsoft/TypeScript/issues/20559
// Ranges like [|case 1: break;|] will fail to populate `statements` because
// they will never find `start` in `start.parent.statements`.
// Consider: We could support ranges like [|case 1:|] by refining them to just
// the expression.
return { errors: [createFileDiagnostic(sourceFile, span.start, length, Messages.cannotExtractRange)] };
}
return { targetRange: { range: statements, facts: rangeFacts, declarations } };
}
@@ -1327,6 +1331,13 @@ namespace ts.refactor.extractSymbol {
}
prevStatement = statement;
}
if (!prevStatement && isCaseClause(curr)) {
// We must have been in the expression of the case clause.
Debug.assert(isSwitchStatement(curr.parent.parent));
return curr.parent.parent;
}
// There must be at least one statement since we started in one.
Debug.assert(prevStatement !== undefined);
return prevStatement;
@@ -1,15 +1,9 @@
/* @internal */
namespace ts.refactor.installTypesForPackage {
const refactorName = "Install missing types package";
const actionName = "install";
const installTypesForPackage: Refactor = {
name: "Install missing types package",
description: "Install missing types package",
getEditsForAction,
getAvailableActions,
};
registerRefactor(installTypesForPackage);
const description = "Install missing types package";
registerRefactor(refactorName, { getEditsForAction, getAvailableActions });
function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined {
if (getStrictOptionValue(context.program.getCompilerOptions(), "noImplicitAny")) {
@@ -20,8 +14,8 @@ namespace ts.refactor.installTypesForPackage {
const action = getAction(context);
return action && [
{
name: installTypesForPackage.name,
description: installTypesForPackage.description,
name: refactorName,
description,
actions: [
{
description: action.description,
+5 -12
View File
@@ -1,15 +1,8 @@
/* @internal */
namespace ts.refactor.installTypesForPackage {
const actionName = "Convert to default import";
const useDefaultImport: Refactor = {
name: actionName,
description: getLocaleSpecificMessage(Diagnostics.Convert_to_default_import),
getEditsForAction,
getAvailableActions,
};
registerRefactor(useDefaultImport);
const description = getLocaleSpecificMessage(Diagnostics.Convert_to_default_import);
registerRefactor(actionName, { getEditsForAction, getAvailableActions });
function getAvailableActions(context: RefactorContext): ApplicableRefactorInfo[] | undefined {
const { file, startPosition, program } = context;
@@ -31,11 +24,11 @@ namespace ts.refactor.installTypesForPackage {
return [
{
name: useDefaultImport.name,
description: useDefaultImport.description,
name: actionName,
description,
actions: [
{
description: useDefaultImport.description,
description,
name: actionName,
},
],
+3 -6
View File
@@ -1255,7 +1255,7 @@ namespace ts {
getCancellationToken: () => cancellationToken,
getCanonicalFileName,
useCaseSensitiveFileNames: () => useCaseSensitivefileNames,
getNewLine: () => getNewLineCharacter(newSettings, { newLine: getNewLineOrDefaultFromHost(host) }),
getNewLine: () => getNewLineCharacter(newSettings, () => getNewLineOrDefaultFromHost(host)),
getDefaultLibFileName: (options) => host.getDefaultLibFileName(options),
writeFile: noop,
getCurrentDirectory: () => currentDirectory,
@@ -1887,12 +1887,11 @@ namespace ts {
synchronizeHostData();
const sourceFile = getValidSourceFile(fileName);
const span = createTextSpanFromBounds(start, end);
const newLineCharacter = getNewLineOrDefaultFromHost(host);
const formatContext = formatting.getFormatContext(formatOptions);
return flatMap(deduplicate(errorCodes, equateValues, compareValues), errorCode => {
cancellationToken.throwIfCancellationRequested();
return codefix.getFixes({ errorCode, sourceFile, span, program, newLineCharacter, host, cancellationToken, formatContext });
return codefix.getFixes({ errorCode, sourceFile, span, program, host, cancellationToken, formatContext });
});
}
@@ -1900,10 +1899,9 @@ namespace ts {
synchronizeHostData();
Debug.assert(scope.type === "file");
const sourceFile = getValidSourceFile(scope.fileName);
const newLineCharacter = getNewLineOrDefaultFromHost(host);
const formatContext = formatting.getFormatContext(formatOptions);
return codefix.getAllFixes({ fixId, sourceFile, program, newLineCharacter, host, cancellationToken, formatContext });
return codefix.getAllFixes({ fixId, sourceFile, program, host, cancellationToken, formatContext });
}
function applyCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
@@ -2134,7 +2132,6 @@ namespace ts {
startPosition,
endPosition,
program: getProgram(),
newLineCharacter: formatOptions ? formatOptions.newLineCharacter : host.getNewLine(),
host,
formatContext: formatting.getFormatContext(formatOptions),
cancellationToken,
+2 -2
View File
@@ -187,7 +187,7 @@ namespace ts.textChanges {
}
export interface TextChangesContext {
newLineCharacter: string;
host: LanguageServiceHost;
formatContext: ts.formatting.FormatContext;
}
@@ -199,7 +199,7 @@ namespace ts.textChanges {
private readonly nodesInsertedAtClassStarts = createMap<{ sourceFile: SourceFile, cls: ClassLikeDeclaration, members: ClassElement[] }>();
public static fromContext(context: TextChangesContext): ChangeTracker {
return new ChangeTracker(context.newLineCharacter === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed, context.formatContext);
return new ChangeTracker(getNewLineOrDefaultFromHost(context.host, context.formatContext.options) === "\n" ? NewLineKind.LineFeed : NewLineKind.CarriageReturnLineFeed, context.formatContext);
}
public static with(context: TextChangesContext, cb: (tracker: ChangeTracker) => void): FileTextChanges[] {
+6 -1
View File
@@ -1,4 +1,4 @@
{
{
"extends": "../tsconfig-base",
"compilerOptions": {
"removeComments": false,
@@ -37,6 +37,11 @@
"../compiler/declarationEmitter.ts",
"../compiler/emitter.ts",
"../compiler/program.ts",
"../compiler/builderState.ts",
"../compiler/builder.ts",
"../compiler/resolutionCache.ts",
"../compiler/watch.ts",
"../compiler/watchUtilities.ts",
"../compiler/commandLineParser.ts",
"../compiler/diagnosticInformationMap.generated.ts",
"types.ts",
+8 -2
View File
@@ -1070,12 +1070,16 @@ namespace ts {
export const typeKeywords: ReadonlyArray<SyntaxKind> = [
SyntaxKind.AnyKeyword,
SyntaxKind.BooleanKeyword,
SyntaxKind.KeyOfKeyword,
SyntaxKind.NeverKeyword,
SyntaxKind.NullKeyword,
SyntaxKind.NumberKeyword,
SyntaxKind.ObjectKeyword,
SyntaxKind.StringKeyword,
SyntaxKind.SymbolKeyword,
SyntaxKind.VoidKeyword,
SyntaxKind.UndefinedKeyword,
SyntaxKind.UniqueKeyword,
];
export function isTypeKeyword(kind: SyntaxKind): boolean {
@@ -1259,8 +1263,10 @@ namespace ts {
/**
* The default is CRLF.
*/
export function getNewLineOrDefaultFromHost(host: LanguageServiceHost | LanguageServiceShimHost) {
return host.getNewLine ? host.getNewLine() : carriageReturnLineFeed;
export function getNewLineOrDefaultFromHost(host: LanguageServiceHost | LanguageServiceShimHost, formatSettings?: FormatCodeSettings) {
return (formatSettings && formatSettings.newLineCharacter) ||
(host.getNewLine && host.getNewLine()) ||
carriageReturnLineFeed;
}
export function lineBreakPart() {