Merge branch 'transforms' into transforms-generators

This commit is contained in:
Ron Buckton
2016-07-18 15:43:28 -07:00
1010 changed files with 47343 additions and 17707 deletions
+101 -48
View File
@@ -572,6 +572,9 @@ namespace ts {
case SyntaxKind.CaseBlock:
bindCaseBlock(<CaseBlock>node);
break;
case SyntaxKind.CaseClause:
bindCaseClause(<CaseClause>node);
break;
case SyntaxKind.LabeledStatement:
bindLabeledStatement(<LabeledStatement>node);
break;
@@ -599,12 +602,6 @@ namespace ts {
}
}
function isNarrowableReference(expr: Expression): boolean {
return expr.kind === SyntaxKind.Identifier ||
expr.kind === SyntaxKind.ThisKeyword ||
expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((<PropertyAccessExpression>expr).expression);
}
function isNarrowingExpression(expr: Expression): boolean {
switch (expr.kind) {
case SyntaxKind.Identifier:
@@ -612,7 +609,7 @@ namespace ts {
case SyntaxKind.PropertyAccessExpression:
return isNarrowableReference(expr);
case SyntaxKind.CallExpression:
return true;
return hasNarrowableArgument(<CallExpression>expr);
case SyntaxKind.ParenthesizedExpression:
return isNarrowingExpression((<ParenthesizedExpression>expr).expression);
case SyntaxKind.BinaryExpression:
@@ -623,6 +620,39 @@ namespace ts {
return false;
}
function isNarrowableReference(expr: Expression): boolean {
return expr.kind === SyntaxKind.Identifier ||
expr.kind === SyntaxKind.ThisKeyword ||
expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((<PropertyAccessExpression>expr).expression);
}
function hasNarrowableArgument(expr: CallExpression) {
if (expr.arguments) {
for (const argument of expr.arguments) {
if (isNarrowableReference(argument)) {
return true;
}
}
}
if (expr.expression.kind === SyntaxKind.PropertyAccessExpression &&
isNarrowableReference((<PropertyAccessExpression>expr.expression).expression)) {
return true;
}
return false;
}
function isNarrowingNullCheckOperands(expr1: Expression, expr2: Expression) {
return (expr1.kind === SyntaxKind.NullKeyword || expr1.kind === SyntaxKind.Identifier && (<Identifier>expr1).text === "undefined") && isNarrowableOperand(expr2);
}
function isNarrowingTypeofOperands(expr1: Expression, expr2: Expression) {
return expr1.kind === SyntaxKind.TypeOfExpression && isNarrowableOperand((<TypeOfExpression>expr1).expression) && expr2.kind === SyntaxKind.StringLiteral;
}
function isNarrowingDiscriminant(expr: Expression) {
return expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((<PropertyAccessExpression>expr).expression);
}
function isNarrowingBinaryExpression(expr: BinaryExpression) {
switch (expr.operatorToken.kind) {
case SyntaxKind.EqualsToken:
@@ -631,34 +661,35 @@ namespace ts {
case SyntaxKind.ExclamationEqualsToken:
case SyntaxKind.EqualsEqualsEqualsToken:
case SyntaxKind.ExclamationEqualsEqualsToken:
if ((isNarrowingExpression(expr.left) && (expr.right.kind === SyntaxKind.NullKeyword || expr.right.kind === SyntaxKind.Identifier)) ||
(isNarrowingExpression(expr.right) && (expr.left.kind === SyntaxKind.NullKeyword || expr.left.kind === SyntaxKind.Identifier))) {
return true;
}
if (isTypeOfNarrowingBinaryExpression(expr)) {
return true;
}
return false;
return isNarrowingNullCheckOperands(expr.right, expr.left) || isNarrowingNullCheckOperands(expr.left, expr.right) ||
isNarrowingTypeofOperands(expr.right, expr.left) || isNarrowingTypeofOperands(expr.left, expr.right) ||
isNarrowingDiscriminant(expr.left) || isNarrowingDiscriminant(expr.right);
case SyntaxKind.InstanceOfKeyword:
return isNarrowingExpression(expr.left);
return isNarrowableOperand(expr.left);
case SyntaxKind.CommaToken:
return isNarrowingExpression(expr.right);
}
return false;
}
function isTypeOfNarrowingBinaryExpression(expr: BinaryExpression) {
let typeOf: Expression;
if (expr.left.kind === SyntaxKind.StringLiteral) {
typeOf = expr.right;
function isNarrowableOperand(expr: Expression): boolean {
switch (expr.kind) {
case SyntaxKind.ParenthesizedExpression:
return isNarrowableOperand((<ParenthesizedExpression>expr).expression);
case SyntaxKind.BinaryExpression:
switch ((<BinaryExpression>expr).operatorToken.kind) {
case SyntaxKind.EqualsToken:
return isNarrowableOperand((<BinaryExpression>expr).left);
case SyntaxKind.CommaToken:
return isNarrowableOperand((<BinaryExpression>expr).right);
}
}
else if (expr.right.kind === SyntaxKind.StringLiteral) {
typeOf = expr.left;
}
else {
typeOf = undefined;
}
return typeOf && typeOf.kind === SyntaxKind.TypeOfExpression && isNarrowingExpression((<TypeOfExpression>typeOf).expression);
return isNarrowableReference(expr);
}
function isNarrowingSwitchStatement(switchStatement: SwitchStatement) {
const expr = switchStatement.expression;
return expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((<PropertyAccessExpression>expr).expression);
}
function createBranchLabel(): FlowLabel {
@@ -704,8 +735,22 @@ namespace ts {
setFlowNodeReferenced(antecedent);
return <FlowCondition>{
flags,
antecedent,
expression,
antecedent
};
}
function createFlowSwitchClause(antecedent: FlowNode, switchStatement: SwitchStatement, clauseStart: number, clauseEnd: number): FlowNode {
if (!isNarrowingSwitchStatement(switchStatement)) {
return antecedent;
}
setFlowNodeReferenced(antecedent);
return <FlowSwitchClause>{
flags: FlowFlags.SwitchClause,
switchStatement,
clauseStart,
clauseEnd,
antecedent
};
}
@@ -934,9 +979,12 @@ namespace ts {
preSwitchCaseFlow = currentFlow;
bind(node.caseBlock);
addAntecedent(postSwitchLabel, currentFlow);
const hasNonEmptyDefault = forEach(node.caseBlock.clauses, c => c.kind === SyntaxKind.DefaultClause && c.statements.length);
if (!hasNonEmptyDefault) {
addAntecedent(postSwitchLabel, preSwitchCaseFlow);
const hasDefault = forEach(node.caseBlock.clauses, c => c.kind === SyntaxKind.DefaultClause);
// We mark a switch statement as possibly exhaustive if it has no default clause and if all
// case clauses have unreachable end points (e.g. they all return).
node.possiblyExhaustive = !hasDefault && !postSwitchLabel.antecedents;
if (!hasDefault) {
addAntecedent(postSwitchLabel, createFlowSwitchClause(preSwitchCaseFlow, node, 0, 0));
}
currentBreakTarget = saveBreakTarget;
preSwitchCaseFlow = savePreSwitchCaseFlow;
@@ -945,29 +993,34 @@ namespace ts {
function bindCaseBlock(node: CaseBlock): void {
const clauses = node.clauses;
let fallthroughFlow = unreachableFlow;
for (let i = 0; i < clauses.length; i++) {
const clause = clauses[i];
if (clause.statements.length) {
if (currentFlow.flags & FlowFlags.Unreachable) {
currentFlow = preSwitchCaseFlow;
}
else {
const preCaseLabel = createBranchLabel();
addAntecedent(preCaseLabel, preSwitchCaseFlow);
addAntecedent(preCaseLabel, currentFlow);
currentFlow = finishFlowLabel(preCaseLabel);
}
bind(clause);
if (!(currentFlow.flags & FlowFlags.Unreachable) && i !== clauses.length - 1 && options.noFallthroughCasesInSwitch) {
errorOnFirstToken(clause, Diagnostics.Fallthrough_case_in_switch);
}
const clauseStart = i;
while (!clauses[i].statements.length && i + 1 < clauses.length) {
bind(clauses[i]);
i++;
}
else {
bind(clause);
const preCaseLabel = createBranchLabel();
addAntecedent(preCaseLabel, createFlowSwitchClause(preSwitchCaseFlow, <SwitchStatement>node.parent, clauseStart, i + 1));
addAntecedent(preCaseLabel, fallthroughFlow);
currentFlow = finishFlowLabel(preCaseLabel);
const clause = clauses[i];
bind(clause);
fallthroughFlow = currentFlow;
if (!(currentFlow.flags & FlowFlags.Unreachable) && i !== clauses.length - 1 && options.noFallthroughCasesInSwitch) {
errorOnFirstToken(clause, Diagnostics.Fallthrough_case_in_switch);
}
}
}
function bindCaseClause(node: CaseClause): void {
const saveCurrentFlow = currentFlow;
currentFlow = preSwitchCaseFlow;
bind(node.expression);
currentFlow = saveCurrentFlow;
forEach(node.statements, bind);
}
function pushActiveLabel(name: string, breakTarget: FlowLabel, continueTarget: FlowLabel): ActiveLabel {
const activeLabel = {
name,
+675 -216
View File
File diff suppressed because it is too large Load Diff
+368 -61
View File
@@ -137,6 +137,16 @@ namespace ts {
type: "boolean",
description: Diagnostics.Raise_error_on_this_expressions_with_an_implied_any_type,
},
{
name: "noUnusedLocals",
type: "boolean",
description: Diagnostics.Report_Errors_on_Unused_Locals,
},
{
name: "noUnusedParameters",
type: "boolean",
description: Diagnostics.Report_Errors_on_Unused_Parameters
},
{
name: "noLib",
type: "boolean",
@@ -331,16 +341,6 @@ namespace ts {
isFilePath: true
}
},
{
name: "typesSearchPaths",
type: "list",
isTSConfigOnly: true,
element: {
name: "typesSearchPaths",
type: "string",
isFilePath: true
}
},
{
name: "typeRoots",
type: "list",
@@ -379,6 +379,11 @@ namespace ts {
type: "boolean",
description: Diagnostics.Do_not_emit_use_strict_directives_in_module_output
},
{
name: "maxNodeModuleJsDepth",
type: "number",
description: Diagnostics.The_maximum_dependency_depth_to_search_under_node_modules_and_load_JavaScript_files
},
{
name: "listEmittedFiles",
type: "boolean"
@@ -417,6 +422,10 @@ namespace ts {
},
description: Diagnostics.Specify_library_files_to_be_included_in_the_compilation_Colon
},
{
name: "disableSizeLimit",
type: "boolean"
},
{
name: "strictNullChecks",
type: "boolean",
@@ -692,7 +701,7 @@ namespace ts {
// Skip over any minified JavaScript files (ending in ".min.js")
// Skip over dotted files and folders as well
const IgnoreFileNamePattern = /(\.min\.js$)|([\\/]\.[\w.])/;
const ignoreFileNamePattern = /(\.min\.js$)|([\\/]\.[\w.])/;
/**
* Parse the contents of a config file (tsconfig.json).
* @param json The contents of the config file to parse
@@ -708,78 +717,66 @@ namespace ts {
options.configFilePath = configFileName;
const fileNames = getFileNames(errors);
const { fileNames, wildcardDirectories } = getFileNames(errors);
return {
options,
fileNames,
typingOptions,
raw: json,
errors
errors,
wildcardDirectories
};
function getFileNames(errors: Diagnostic[]): string[] {
let fileNames: string[] = [];
function getFileNames(errors: Diagnostic[]): ExpandResult {
let fileNames: string[];
if (hasProperty(json, "files")) {
if (isArray(json["files"])) {
fileNames = map(<string[]>json["files"], s => combinePaths(basePath, s));
fileNames = <string[]>json["files"];
}
else {
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "files", "Array"));
}
}
else {
const filesSeen: Map<boolean> = {};
let exclude: string[] = [];
if (isArray(json["exclude"])) {
exclude = json["exclude"];
let includeSpecs: string[];
if (hasProperty(json, "include")) {
if (isArray(json["include"])) {
includeSpecs = <string[]>json["include"];
}
else {
// by default exclude node_modules, and any specificied output directory
exclude = ["node_modules", "bower_components", "jspm_packages"];
}
const outDir = json["compilerOptions"] && json["compilerOptions"]["outDir"];
if (outDir) {
exclude.push(outDir);
}
exclude = map(exclude, e => getNormalizedAbsolutePath(e, basePath));
const supportedExtensions = getSupportedExtensions(options);
Debug.assert(indexOf(supportedExtensions, ".ts") < indexOf(supportedExtensions, ".d.ts"), "Changed priority of extensions to pick");
// Get files of supported extensions in their order of resolution
for (const extension of supportedExtensions) {
const filesInDirWithExtension = host.readDirectory(basePath, extension, exclude);
for (const fileName of filesInDirWithExtension) {
// .ts extension would read the .d.ts extension files too but since .d.ts is lower priority extension,
// lets pick them when its turn comes up
if (extension === ".ts" && fileExtensionIs(fileName, ".d.ts")) {
continue;
}
if (IgnoreFileNamePattern.test(fileName)) {
continue;
}
// If this is one of the output extension (which would be .d.ts and .js if we are allowing compilation of js files)
// do not include this file if we included .ts or .tsx file with same base name as it could be output of the earlier compilation
if (extension === ".d.ts" || (options.allowJs && contains(supportedJavascriptExtensions, extension))) {
const baseName = fileName.substr(0, fileName.length - extension.length);
if (hasProperty(filesSeen, baseName + ".ts") || hasProperty(filesSeen, baseName + ".tsx")) {
continue;
}
}
filesSeen[fileName] = true;
fileNames.push(fileName);
}
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "include", "Array"));
}
}
if (hasProperty(json, "excludes") && !hasProperty(json, "exclude")) {
let excludeSpecs: string[];
if (hasProperty(json, "exclude")) {
if (isArray(json["exclude"])) {
excludeSpecs = <string[]>json["exclude"];
}
else {
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "exclude", "Array"));
}
}
else if (hasProperty(json, "excludes")) {
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_option_excludes_Did_you_mean_exclude));
}
return fileNames;
else {
// By default, exclude common package folders
excludeSpecs = ["node_modules", "bower_components", "jspm_packages"];
}
// Always exclude the output directory unless explicitly included
const outDir = json["compilerOptions"] && json["compilerOptions"]["outDir"];
if (outDir) {
excludeSpecs.push(outDir);
}
if (fileNames === undefined && includeSpecs === undefined) {
includeSpecs = ["**/*"];
}
return matchFileNames(fileNames, includeSpecs, excludeSpecs, basePath, options, host, errors);
}
}
@@ -875,4 +872,314 @@ namespace ts {
function trimString(s: string) {
return typeof s.trim === "function" ? s.trim() : s.replace(/^[\s]+|[\s]+$/g, "");
}
/**
* Tests for a path that ends in a recursive directory wildcard.
* Matches **, \**, **\, and \**\, but not a**b.
*
* NOTE: used \ in place of / above to avoid issues with multiline comments.
*
* Breakdown:
* (^|\/) # matches either the beginning of the string or a directory separator.
* \*\* # matches the recursive directory wildcard "**".
* \/?$ # matches an optional trailing directory separator at the end of the string.
*/
const invalidTrailingRecursionPattern = /(^|\/)\*\*\/?$/;
/**
* Tests for a path with multiple recursive directory wildcards.
* Matches **\** and **\a\**, but not **\a**b.
*
* NOTE: used \ in place of / above to avoid issues with multiline comments.
*
* Breakdown:
* (^|\/) # matches either the beginning of the string or a directory separator.
* \*\*\/ # matches a recursive directory wildcard "**" followed by a directory separator.
* (.*\/)? # optionally matches any number of characters followed by a directory separator.
* \*\* # matches a recursive directory wildcard "**"
* ($|\/) # matches either the end of the string or a directory separator.
*/
const invalidMultipleRecursionPatterns = /(^|\/)\*\*\/(.*\/)?\*\*($|\/)/;
/**
* Tests for a path where .. appears after a recursive directory wildcard.
* Matches **\..\*, **\a\..\*, and **\.., but not ..\**\*
*
* NOTE: used \ in place of / above to avoid issues with multiline comments.
*
* Breakdown:
* (^|\/) # matches either the beginning of the string or a directory separator.
* \*\*\/ # matches a recursive directory wildcard "**" followed by a directory separator.
* (.*\/)? # optionally matches any number of characters followed by a directory separator.
* \.\. # matches a parent directory path component ".."
* ($|\/) # matches either the end of the string or a directory separator.
*/
const invalidDotDotAfterRecursiveWildcardPattern = /(^|\/)\*\*\/(.*\/)?\.\.($|\/)/;
/**
* Tests for a path containing a wildcard character in a directory component of the path.
* Matches \*\, \?\, and \a*b\, but not \a\ or \a\*.
*
* NOTE: used \ in place of / above to avoid issues with multiline comments.
*
* Breakdown:
* \/ # matches a directory separator.
* [^/]*? # matches any number of characters excluding directory separators (non-greedy).
* [*?] # matches either a wildcard character (* or ?)
* [^/]* # matches any number of characters excluding directory separators (greedy).
* \/ # matches a directory separator.
*/
const watchRecursivePattern = /\/[^/]*?[*?][^/]*\//;
/**
* Matches the portion of a wildcard path that does not contain wildcards.
* Matches \a of \a\*, or \a\b\c of \a\b\c\?\d.
*
* NOTE: used \ in place of / above to avoid issues with multiline comments.
*
* Breakdown:
* ^ # matches the beginning of the string
* [^*?]* # matches any number of non-wildcard characters
* (?=\/[^/]*[*?]) # lookahead that matches a directory separator followed by
* # a path component that contains at least one wildcard character (* or ?).
*/
const wildcardDirectoryPattern = /^[^*?]*(?=\/[^/]*[*?])/;
/**
* Expands an array of file specifications.
*
* @param fileNames The literal file names to include.
* @param include The wildcard file specifications to include.
* @param exclude The wildcard file specifications to exclude.
* @param basePath The base path for any relative file specifications.
* @param options Compiler options.
* @param host The host used to resolve files and directories.
* @param errors An array for diagnostic reporting.
*/
function matchFileNames(fileNames: string[], include: string[], exclude: string[], basePath: string, options: CompilerOptions, host: ParseConfigHost, errors: Diagnostic[]): ExpandResult {
basePath = normalizePath(basePath);
// The exclude spec list is converted into a regular expression, which allows us to quickly
// test whether a file or directory should be excluded before recursively traversing the
// file system.
const keyMapper = host.useCaseSensitiveFileNames ? caseSensitiveKeyMapper : caseInsensitiveKeyMapper;
// Literal file names (provided via the "files" array in tsconfig.json) are stored in a
// file map with a possibly case insensitive key. We use this map later when when including
// wildcard paths.
const literalFileMap: Map<string> = {};
// Wildcard paths (provided via the "includes" array in tsconfig.json) are stored in a
// file map with a possibly case insensitive key. We use this map to store paths matched
// via wildcard, and to handle extension priority.
const wildcardFileMap: Map<string> = {};
if (include) {
include = validateSpecs(include, errors, /*allowTrailingRecursion*/ false);
}
if (exclude) {
exclude = validateSpecs(exclude, errors, /*allowTrailingRecursion*/ true);
}
// Wildcard directories (provided as part of a wildcard path) are stored in a
// file map that marks whether it was a regular wildcard match (with a `*` or `?` token),
// or a recursive directory. This information is used by filesystem watchers to monitor for
// new entries in these paths.
const wildcardDirectories: Map<WatchDirectoryFlags> = getWildcardDirectories(include, exclude, basePath, host.useCaseSensitiveFileNames);
// Rather than requery this for each file and filespec, we query the supported extensions
// once and store it on the expansion context.
const supportedExtensions = getSupportedExtensions(options);
// Literal files are always included verbatim. An "include" or "exclude" specification cannot
// remove a literal file.
if (fileNames) {
for (const fileName of fileNames) {
const file = combinePaths(basePath, fileName);
literalFileMap[keyMapper(file)] = file;
}
}
if (include && include.length > 0) {
for (const file of host.readDirectory(basePath, supportedExtensions, exclude, include)) {
// If we have already included a literal or wildcard path with a
// higher priority extension, we should skip this file.
//
// This handles cases where we may encounter both <file>.ts and
// <file>.d.ts (or <file>.js if "allowJs" is enabled) in the same
// directory when they are compilation outputs.
if (hasFileWithHigherPriorityExtension(file, literalFileMap, wildcardFileMap, supportedExtensions, keyMapper)) {
continue;
}
if (ignoreFileNamePattern.test(file)) {
continue;
}
// We may have included a wildcard path with a lower priority
// extension due to the user-defined order of entries in the
// "include" array. If there is a lower priority extension in the
// same directory, we should remove it.
removeWildcardFilesWithLowerPriorityExtension(file, wildcardFileMap, supportedExtensions, keyMapper);
const key = keyMapper(file);
if (!hasProperty(literalFileMap, key) && !hasProperty(wildcardFileMap, key)) {
wildcardFileMap[key] = file;
}
}
}
const literalFiles = reduceProperties(literalFileMap, addFileToOutput, []);
const wildcardFiles = reduceProperties(wildcardFileMap, addFileToOutput, []);
wildcardFiles.sort(host.useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive);
return {
fileNames: literalFiles.concat(wildcardFiles),
wildcardDirectories
};
}
function validateSpecs(specs: string[], errors: Diagnostic[], allowTrailingRecursion: boolean) {
const validSpecs: string[] = [];
for (const spec of specs) {
if (!allowTrailingRecursion && invalidTrailingRecursionPattern.test(spec)) {
errors.push(createCompilerDiagnostic(Diagnostics.File_specification_cannot_end_in_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec));
}
else if (invalidMultipleRecursionPatterns.test(spec)) {
errors.push(createCompilerDiagnostic(Diagnostics.File_specification_cannot_contain_multiple_recursive_directory_wildcards_Asterisk_Asterisk_Colon_0, spec));
}
else if (invalidDotDotAfterRecursiveWildcardPattern.test(spec)) {
errors.push(createCompilerDiagnostic(Diagnostics.File_specification_cannot_contain_a_parent_directory_that_appears_after_a_recursive_directory_wildcard_Asterisk_Asterisk_Colon_0, spec));
}
else {
validSpecs.push(spec);
}
}
return validSpecs;
}
/**
* Gets directories in a set of include patterns that should be watched for changes.
*/
function getWildcardDirectories(include: string[], exclude: string[], path: string, useCaseSensitiveFileNames: boolean) {
// We watch a directory recursively if it contains a wildcard anywhere in a directory segment
// of the pattern:
//
// /a/b/**/d - Watch /a/b recursively to catch changes to any d in any subfolder recursively
// /a/b/*/d - Watch /a/b recursively to catch any d in any immediate subfolder, even if a new subfolder is added
//
// We watch a directory without recursion if it contains a wildcard in the file segment of
// the pattern:
//
// /a/b/* - Watch /a/b directly to catch any new file
// /a/b/a?z - Watch /a/b directly to catch any new file matching a?z
const rawExcludeRegex = getRegularExpressionForWildcard(exclude, path, "exclude");
const excludeRegex = rawExcludeRegex && new RegExp(rawExcludeRegex, useCaseSensitiveFileNames ? "" : "i");
const wildcardDirectories: Map<WatchDirectoryFlags> = {};
if (include !== undefined) {
const recursiveKeys: string[] = [];
for (const file of include) {
const name = normalizePath(combinePaths(path, file));
if (excludeRegex && excludeRegex.test(name)) {
continue;
}
const match = wildcardDirectoryPattern.exec(name);
if (match) {
const key = useCaseSensitiveFileNames ? match[0] : match[0].toLowerCase();
const flags = watchRecursivePattern.test(name) ? WatchDirectoryFlags.Recursive : WatchDirectoryFlags.None;
const existingFlags = getProperty(wildcardDirectories, key);
if (existingFlags === undefined || existingFlags < flags) {
wildcardDirectories[key] = flags;
if (flags === WatchDirectoryFlags.Recursive) {
recursiveKeys.push(key);
}
}
}
}
// Remove any subpaths under an existing recursively watched directory.
for (const key in wildcardDirectories) {
if (hasProperty(wildcardDirectories, key)) {
for (const recursiveKey of recursiveKeys) {
if (key !== recursiveKey && containsPath(recursiveKey, key, path, !useCaseSensitiveFileNames)) {
delete wildcardDirectories[key];
}
}
}
}
}
return wildcardDirectories;
}
/**
* Determines whether a literal or wildcard file has already been included that has a higher
* extension priority.
*
* @param file The path to the file.
* @param extensionPriority The priority of the extension.
* @param context The expansion context.
*/
function hasFileWithHigherPriorityExtension(file: string, literalFiles: Map<string>, wildcardFiles: Map<string>, extensions: string[], keyMapper: (value: string) => string) {
const extensionPriority = getExtensionPriority(file, extensions);
const adjustedExtensionPriority = adjustExtensionPriority(extensionPriority);
for (let i = ExtensionPriority.Highest; i < adjustedExtensionPriority; i++) {
const higherPriorityExtension = extensions[i];
const higherPriorityPath = keyMapper(changeExtension(file, higherPriorityExtension));
if (hasProperty(literalFiles, higherPriorityPath) || hasProperty(wildcardFiles, higherPriorityPath)) {
return true;
}
}
return false;
}
/**
* Removes files included via wildcard expansion with a lower extension priority that have
* already been included.
*
* @param file The path to the file.
* @param extensionPriority The priority of the extension.
* @param context The expansion context.
*/
function removeWildcardFilesWithLowerPriorityExtension(file: string, wildcardFiles: Map<string>, extensions: string[], keyMapper: (value: string) => string) {
const extensionPriority = getExtensionPriority(file, extensions);
const nextExtensionPriority = getNextLowestExtensionPriority(extensionPriority);
for (let i = nextExtensionPriority; i < extensions.length; i++) {
const lowerPriorityExtension = extensions[i];
const lowerPriorityPath = keyMapper(changeExtension(file, lowerPriorityExtension));
delete wildcardFiles[lowerPriorityPath];
}
}
/**
* Adds a file to an array of files.
*
* @param output The output array.
* @param file The file path.
*/
function addFileToOutput(output: string[], file: string) {
output.push(file);
return output;
}
/**
* Gets a case sensitive key.
*
* @param key The original key.
*/
function caseSensitiveKeyMapper(key: string) {
return key;
}
/**
* Gets a case insensitive key.
*
* @param key The original key.
*/
function caseInsensitiveKeyMapper(key: string) {
return key.toLowerCase();
}
}
+365 -1
View File
@@ -25,7 +25,7 @@ namespace ts {
contains,
remove,
forEachValue: forEachValueInMap,
clear
clear,
};
function forEachValueInMap(f: (key: Path, value: T) => void) {
@@ -130,6 +130,15 @@ namespace ts {
return -1;
}
export function indexOfAnyCharCode(text: string, charCodes: number[], start?: number): number {
for (let i = start || 0, len = text.length; i < len; i++) {
if (contains(charCodes, text.charCodeAt(i))) {
return i;
}
}
return -1;
}
export function countWhere<T>(array: T[], predicate: (x: T, i: number) => boolean): number {
let count = 0;
if (array) {
@@ -159,6 +168,17 @@ namespace ts {
return result;
}
export function filterMutate<T>(array: T[], f: (x: T) => boolean): void {
let outIndex = 0;
for (const item of array) {
if (f(item)) {
array[outIndex] = item;
outIndex++;
}
}
array.length = outIndex;
}
export function map<T, U>(array: T[], f: (x: T, i: number) => U): U[] {
let result: U[];
if (array) {
@@ -697,6 +717,28 @@ namespace ts {
return a < b ? Comparison.LessThan : Comparison.GreaterThan;
}
export function compareStrings(a: string, b: string, ignoreCase?: boolean): Comparison {
if (a === b) return Comparison.EqualTo;
if (a === undefined) return Comparison.LessThan;
if (b === undefined) return Comparison.GreaterThan;
if (ignoreCase) {
if (String.prototype.localeCompare) {
const result = a.localeCompare(b, /*locales*/ undefined, { usage: "sort", sensitivity: "accent" });
return result < 0 ? Comparison.LessThan : result > 0 ? Comparison.GreaterThan : Comparison.EqualTo;
}
a = a.toUpperCase();
b = b.toUpperCase();
if (a === b) return Comparison.EqualTo;
}
return a < b ? Comparison.LessThan : Comparison.GreaterThan;
}
export function compareStringsCaseInsensitive(a: string, b: string) {
return compareStrings(a, b, /*ignoreCase*/ true);
}
function getDiagnosticFileName(diagnostic: Diagnostic): string {
return diagnostic.file ? diagnostic.file.fileName : undefined;
}
@@ -966,12 +1008,277 @@ namespace ts {
return path1 + directorySeparator + path2;
}
/**
* Removes a trailing directory separator from a path.
* @param path The path.
*/
export function removeTrailingDirectorySeparator(path: string) {
if (path.charAt(path.length - 1) === directorySeparator) {
return path.substr(0, path.length - 1);
}
return path;
}
/**
* Adds a trailing directory separator to a path, if it does not already have one.
* @param path The path.
*/
export function ensureTrailingDirectorySeparator(path: string) {
if (path.charAt(path.length - 1) !== directorySeparator) {
return path + directorySeparator;
}
return path;
}
export function comparePaths(a: string, b: string, currentDirectory: string, ignoreCase?: boolean) {
if (a === b) return Comparison.EqualTo;
if (a === undefined) return Comparison.LessThan;
if (b === undefined) return Comparison.GreaterThan;
a = removeTrailingDirectorySeparator(a);
b = removeTrailingDirectorySeparator(b);
const aComponents = getNormalizedPathComponents(a, currentDirectory);
const bComponents = getNormalizedPathComponents(b, currentDirectory);
const sharedLength = Math.min(aComponents.length, bComponents.length);
for (let i = 0; i < sharedLength; i++) {
const result = compareStrings(aComponents[i], bComponents[i], ignoreCase);
if (result !== Comparison.EqualTo) {
return result;
}
}
return compareValues(aComponents.length, bComponents.length);
}
export function containsPath(parent: string, child: string, currentDirectory: string, ignoreCase?: boolean) {
if (parent === undefined || child === undefined) return false;
if (parent === child) return true;
parent = removeTrailingDirectorySeparator(parent);
child = removeTrailingDirectorySeparator(child);
if (parent === child) return true;
const parentComponents = getNormalizedPathComponents(parent, currentDirectory);
const childComponents = getNormalizedPathComponents(child, currentDirectory);
if (childComponents.length < parentComponents.length) {
return false;
}
for (let i = 0; i < parentComponents.length; i++) {
const result = compareStrings(parentComponents[i], childComponents[i], ignoreCase);
if (result !== Comparison.EqualTo) {
return false;
}
}
return true;
}
export function fileExtensionIs(path: string, extension: string): boolean {
const pathLen = path.length;
const extLen = extension.length;
return pathLen > extLen && path.substr(pathLen - extLen, extLen) === extension;
}
export function fileExtensionIsAny(path: string, extensions: string[]): boolean {
for (const extension of extensions) {
if (fileExtensionIs(path, extension)) {
return true;
}
}
return false;
}
// Reserved characters, forces escaping of any non-word (or digit), non-whitespace character.
// It may be inefficient (we could just match (/[-[\]{}()*+?.,\\^$|#\s]/g), but this is future
// proof.
const reservedCharacterPattern = /[^\w\s\/]/g;
const wildcardCharCodes = [CharacterCodes.asterisk, CharacterCodes.question];
export function getRegularExpressionForWildcard(specs: string[], basePath: string, usage: "files" | "directories" | "exclude") {
if (specs === undefined || specs.length === 0) {
return undefined;
}
let pattern = "";
let hasWrittenSubpattern = false;
spec: for (const spec of specs) {
if (!spec) {
continue;
}
let subpattern = "";
let hasRecursiveDirectoryWildcard = false;
let hasWrittenComponent = false;
const components = getNormalizedPathComponents(spec, basePath);
if (usage !== "exclude" && components[components.length - 1] === "**") {
continue spec;
}
// getNormalizedPathComponents includes the separator for the root component.
// We need to remove to create our regex correctly.
components[0] = removeTrailingDirectorySeparator(components[0]);
let optionalCount = 0;
for (const component of components) {
if (component === "**") {
if (hasRecursiveDirectoryWildcard) {
continue spec;
}
subpattern += "(/.+?)?";
hasRecursiveDirectoryWildcard = true;
hasWrittenComponent = true;
}
else {
if (usage === "directories") {
subpattern += "(";
optionalCount++;
}
if (hasWrittenComponent) {
subpattern += directorySeparator;
}
subpattern += component.replace(reservedCharacterPattern, replaceWildcardCharacter);
hasWrittenComponent = true;
}
}
while (optionalCount > 0) {
subpattern += ")?";
optionalCount--;
}
if (hasWrittenSubpattern) {
pattern += "|";
}
pattern += "(" + subpattern + ")";
hasWrittenSubpattern = true;
}
if (!pattern) {
return undefined;
}
return "^(" + pattern + (usage === "exclude" ? ")($|/)" : ")$");
}
function replaceWildcardCharacter(match: string) {
return match === "*" ? "[^/]*" : match === "?" ? "[^/]" : "\\" + match;
}
export interface FileSystemEntries {
files: string[];
directories: string[];
}
export interface FileMatcherPatterns {
includeFilePattern: string;
includeDirectoryPattern: string;
excludePattern: string;
basePaths: string[];
}
export function getFileMatcherPatterns(path: string, extensions: string[], excludes: string[], includes: string[], useCaseSensitiveFileNames: boolean, currentDirectory: string): FileMatcherPatterns {
path = normalizePath(path);
currentDirectory = normalizePath(currentDirectory);
const absolutePath = combinePaths(currentDirectory, path);
return {
includeFilePattern: getRegularExpressionForWildcard(includes, absolutePath, "files"),
includeDirectoryPattern: getRegularExpressionForWildcard(includes, absolutePath, "directories"),
excludePattern: getRegularExpressionForWildcard(excludes, absolutePath, "exclude"),
basePaths: getBasePaths(path, includes, useCaseSensitiveFileNames)
};
}
export function matchFiles(path: string, extensions: string[], excludes: string[], includes: string[], useCaseSensitiveFileNames: boolean, currentDirectory: string, getFileSystemEntries: (path: string) => FileSystemEntries): string[] {
path = normalizePath(path);
currentDirectory = normalizePath(currentDirectory);
const patterns = getFileMatcherPatterns(path, extensions, excludes, includes, useCaseSensitiveFileNames, currentDirectory);
const regexFlag = useCaseSensitiveFileNames ? "" : "i";
const includeFileRegex = patterns.includeFilePattern && new RegExp(patterns.includeFilePattern, regexFlag);
const includeDirectoryRegex = patterns.includeDirectoryPattern && new RegExp(patterns.includeDirectoryPattern, regexFlag);
const excludeRegex = patterns.excludePattern && new RegExp(patterns.excludePattern, regexFlag);
const result: string[] = [];
for (const basePath of patterns.basePaths) {
visitDirectory(basePath, combinePaths(currentDirectory, basePath));
}
return result;
function visitDirectory(path: string, absolutePath: string) {
const { files, directories } = getFileSystemEntries(path);
for (const current of files) {
const name = combinePaths(path, current);
const absoluteName = combinePaths(absolutePath, current);
if ((!extensions || fileExtensionIsAny(name, extensions)) &&
(!includeFileRegex || includeFileRegex.test(absoluteName)) &&
(!excludeRegex || !excludeRegex.test(absoluteName))) {
result.push(name);
}
}
for (const current of directories) {
const name = combinePaths(path, current);
const absoluteName = combinePaths(absolutePath, current);
if ((!includeDirectoryRegex || includeDirectoryRegex.test(absoluteName)) &&
(!excludeRegex || !excludeRegex.test(absoluteName))) {
visitDirectory(name, absoluteName);
}
}
}
}
/**
* Computes the unique non-wildcard base paths amongst the provided include patterns.
*/
function getBasePaths(path: string, includes: string[], useCaseSensitiveFileNames: boolean) {
// Storage for our results in the form of literal paths (e.g. the paths as written by the user).
const basePaths: string[] = [path];
if (includes) {
// Storage for literal base paths amongst the include patterns.
const includeBasePaths: string[] = [];
for (const include of includes) {
// We also need to check the relative paths by converting them to absolute and normalizing
// in case they escape the base path (e.g "..\somedirectory")
const absolute: string = isRootedDiskPath(include) ? include : normalizePath(combinePaths(path, include));
const wildcardOffset = indexOfAnyCharCode(absolute, wildcardCharCodes);
const includeBasePath = wildcardOffset < 0
? removeTrailingDirectorySeparator(getDirectoryPath(absolute))
: absolute.substring(0, absolute.lastIndexOf(directorySeparator, wildcardOffset));
// Append the literal and canonical candidate base paths.
includeBasePaths.push(includeBasePath);
}
// Sort the offsets array using either the literal or canonical path representations.
includeBasePaths.sort(useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive);
// Iterate over each include base path and include unique base paths that are not a
// subpath of an existing base path
include: for (let i = 0; i < includeBasePaths.length; i++) {
const includeBasePath = includeBasePaths[i];
for (let j = 0; j < basePaths.length; j++) {
if (containsPath(basePaths[j], includeBasePath, path, !useCaseSensitiveFileNames)) {
continue include;
}
}
basePaths.push(includeBasePath);
}
}
return basePaths;
}
export function ensureScriptKind(fileName: string, scriptKind?: ScriptKind): ScriptKind {
// Using scriptKind as a condition handles both:
// - 'scriptKind' is unspecified and thus it is `undefined`
@@ -1020,6 +1327,59 @@ namespace ts {
return false;
}
/**
* Extension boundaries by priority. Lower numbers indicate higher priorities, and are
* aligned to the offset of the highest priority extension in the
* allSupportedExtensions array.
*/
export const enum ExtensionPriority {
TypeScriptFiles = 0,
DeclarationAndJavaScriptFiles = 2,
Limit = 5,
Highest = TypeScriptFiles,
Lowest = DeclarationAndJavaScriptFiles,
}
export function getExtensionPriority(path: string, supportedExtensions: string[]): ExtensionPriority {
for (let i = supportedExtensions.length - 1; i >= 0; i--) {
if (fileExtensionIs(path, supportedExtensions[i])) {
return adjustExtensionPriority(<ExtensionPriority>i);
}
}
// If its not in the list of supported extensions, this is likely a
// TypeScript file with a non-ts extension
return ExtensionPriority.Highest;
}
/**
* Adjusts an extension priority to be the highest priority within the same range.
*/
export function adjustExtensionPriority(extensionPriority: ExtensionPriority): ExtensionPriority {
if (extensionPriority < ExtensionPriority.DeclarationAndJavaScriptFiles) {
return ExtensionPriority.TypeScriptFiles;
}
else if (extensionPriority < ExtensionPriority.Limit) {
return ExtensionPriority.DeclarationAndJavaScriptFiles;
}
else {
return ExtensionPriority.Limit;
}
}
/**
* Gets the next lowest extension priority for a given priority.
*/
export function getNextLowestExtensionPriority(extensionPriority: ExtensionPriority): ExtensionPriority {
if (extensionPriority < ExtensionPriority.DeclarationAndJavaScriptFiles) {
return ExtensionPriority.DeclarationAndJavaScriptFiles;
}
else {
return ExtensionPriority.Limit;
}
}
const extensionsToRemove = [".d.ts", ".ts", ".js", ".tsx", ".jsx"];
export function removeFileExtension(path: string): string {
for (const ext of extensionsToRemove) {
@@ -1039,6 +1399,10 @@ namespace ts {
return ext === ".jsx" || ext === ".tsx";
}
export function changeExtension<T extends string | Path>(path: T, newExtension: string): T {
return <T>(removeFileExtension(path) + newExtension);
}
export interface ObjectAllocator {
getNodeConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => Node;
getSourceFileConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => SourceFile;
+43 -8
View File
@@ -571,7 +571,7 @@
"category": "Error",
"code": 1186
},
"A parameter property may not be a binding pattern.": {
"A parameter property may not be declared using a binding pattern.": {
"category": "Error",
"code": 1187
},
@@ -847,6 +847,10 @@
"category": "Error",
"code": 1316
},
"A parameter property cannot be declared using a rest parameter.": {
"category": "Error",
"code": 1317
},
"Duplicate identifier '{0}'.": {
"category": "Error",
"code": 2300
@@ -1931,6 +1935,10 @@
"category": "Error",
"code": 2688
},
"Cannot extend an interface '{0}'. Did you mean 'implements'?": {
"category": "Error",
"code": 2689
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
"code": 4000
@@ -2224,6 +2232,14 @@
"category": "Error",
"code": 5009
},
"File specification cannot end in a recursive directory wildcard ('**'): '{0}'.": {
"category": "Error",
"code": 5010
},
"File specification cannot contain multiple recursive directory wildcards ('**'): '{0}'.": {
"category": "Error",
"code": 5011
},
"Cannot read file '{0}': {1}": {
"category": "Error",
"code": 5012
@@ -2312,6 +2328,10 @@
"category": "Error",
"code": 5064
},
"File specification cannot contain a parent directory ('..') that appears after a recursive directory wildcard ('**'): '{0}'.": {
"category": "Error",
"code": 5065
},
"Concatenate and emit output to single file.": {
"category": "Message",
"code": 6001
@@ -2772,11 +2792,30 @@
"category": "Message",
"code": 6132
},
"Import emit helpers from 'tslib'.": {
"category": "Message",
"'{0}' is declared but never used.": {
"category": "Error",
"code": 6133
},
"Report Errors on Unused Locals.": {
"category": "Message",
"code": 6134
},
"Report Errors on Unused Parameters.": {
"category": "Message",
"code": 6135
},
"The maximum dependency depth to search under node_modules and load JavaScript files": {
"category": "Message",
"code": 6136
},
"No types specified in 'package.json' but 'allowJs' is set, so returning 'main' value of '{0}'": {
"category": "Message",
"code": 6137
},
"Import emit helpers from 'tslib'.": {
"category": "Message",
"code": 6138
},
"Variable '{0}' implicitly has an '{1}' type.": {
"category": "Error",
"code": 7005
@@ -2921,10 +2960,6 @@
"category": "Error",
"code": 8012
},
"'property declarations' can only be used in a .ts file.": {
"category": "Error",
"code": 8014
},
"'enum declarations' can only be used in a .ts file.": {
"category": "Error",
"code": 8015
+10 -3
View File
@@ -1132,8 +1132,15 @@ const _super = (function (geti, seti) {
return;
}
const indentBeforeDot = needsIndentation(node, node.expression, node.dotToken);
const indentAfterDot = needsIndentation(node, node.dotToken, node.name);
let indentBeforeDot = false;
let indentAfterDot = false;
if (!(node.emitFlags & NodeEmitFlags.NoIndentation)) {
const dotRangeStart = node.expression.end;
const dotRangeEnd = skipTrivia(currentText, node.expression.end) + 1;
const dotToken = <Node>{ kind: SyntaxKind.DotToken, pos: dotRangeStart, end: dotRangeEnd };
indentBeforeDot = needsIndentation(node, node.expression, dotToken);
indentAfterDot = needsIndentation(node, dotToken, node.name);
}
const shouldEmitDotDot = !indentBeforeDot && needsDotDotForPropertyAccess(node.expression);
emitExpression(node.expression);
@@ -1984,7 +1991,7 @@ const _super = (function (geti, seti) {
}
}
function emitJsxTagName(node: EntityName) {
function emitJsxTagName(node: JsxTagNameExpression) {
if (node.kind === SyntaxKind.Identifier) {
emitExpression(<Identifier>node);
}
+11 -15
View File
@@ -340,21 +340,20 @@ namespace ts {
return node;
}
export function createPropertyAccess(expression: Expression, name: string | Identifier, location?: TextRange) {
return createPropertyAccessWithDotToken(expression, createSynthesizedNode(SyntaxKind.DotToken), name, location, /*flags*/ undefined);
}
export function createPropertyAccessWithDotToken(expression: Expression, dotToken: Node, name: string | Identifier, location?: TextRange, flags?: NodeFlags) {
export function createPropertyAccess(expression: Expression, name: string | Identifier, location?: TextRange, flags?: NodeFlags) {
const node = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, location, flags);
node.expression = parenthesizeForAccess(expression);
node.dotToken = dotToken;
node.emitFlags = NodeEmitFlags.NoIndentation;
node.name = typeof name === "string" ? createIdentifier(name) : name;
return node;
}
export function updatePropertyAccess(node: PropertyAccessExpression, expression: Expression, name: Identifier) {
if (node.expression !== expression || node.name !== name) {
return updateNode(createPropertyAccessWithDotToken(expression, node.dotToken, name, /*location*/ node, node.flags), node);
const propertyAccess = createPropertyAccess(expression, name, /*location*/ node, node.flags);
// Because we are updating existed propertyAccess we want to inherit its emitFlags instead of using default from createPropertyAccess
propertyAccess.emitFlags = node.emitFlags;
return updateNode(propertyAccess, node);
}
return node;
}
@@ -990,16 +989,13 @@ namespace ts {
}
export function createMemberAccessForPropertyName(target: Expression, memberName: PropertyName, location?: TextRange): MemberExpression {
if (isIdentifier(memberName)) {
const expression = createPropertyAccess(target, memberName, location);
expression.emitFlags |= NodeEmitFlags.NoNestedSourceMaps;
return expression;
}
else if (isComputedPropertyName(memberName)) {
return createElementAccess(target, memberName.expression, location);
if (isComputedPropertyName(memberName)) {
return createElementAccess(target, memberName.expression, location);
}
else {
return createElementAccess(target, memberName, location);
const expression = isIdentifier(memberName) ? createPropertyAccess(target, memberName, location) : createElementAccess(target, memberName, location);
expression.emitFlags |= NodeEmitFlags.NoNestedSourceMaps;
return expression;
}
}
+34 -19
View File
@@ -138,7 +138,6 @@ namespace ts {
return visitNodes(cbNodes, (<ObjectLiteralExpression>node).properties);
case SyntaxKind.PropertyAccessExpression:
return visitNode(cbNode, (<PropertyAccessExpression>node).expression) ||
visitNode(cbNode, (<PropertyAccessExpression>node).dotToken) ||
visitNode(cbNode, (<PropertyAccessExpression>node).name);
case SyntaxKind.ElementAccessExpression:
return visitNode(cbNode, (<ElementAccessExpression>node).expression) ||
@@ -1169,12 +1168,12 @@ namespace ts {
if (token === SyntaxKind.ExportKeyword) {
nextToken();
if (token === SyntaxKind.DefaultKeyword) {
return lookAhead(nextTokenIsClassOrFunction);
return lookAhead(nextTokenIsClassOrFunctionOrAsync);
}
return token !== SyntaxKind.AsteriskToken && token !== SyntaxKind.AsKeyword && token !== SyntaxKind.OpenBraceToken && canFollowModifier();
}
if (token === SyntaxKind.DefaultKeyword) {
return nextTokenIsClassOrFunction();
return nextTokenIsClassOrFunctionOrAsync();
}
if (token === SyntaxKind.StaticKeyword) {
nextToken();
@@ -1192,12 +1191,14 @@ namespace ts {
return token === SyntaxKind.OpenBracketToken
|| token === SyntaxKind.OpenBraceToken
|| token === SyntaxKind.AsteriskToken
|| token === SyntaxKind.DotDotDotToken
|| isLiteralPropertyName();
}
function nextTokenIsClassOrFunction(): boolean {
function nextTokenIsClassOrFunctionOrAsync(): boolean {
nextToken();
return token === SyntaxKind.ClassKeyword || token === SyntaxKind.FunctionKeyword;
return token === SyntaxKind.ClassKeyword || token === SyntaxKind.FunctionKeyword ||
(token === SyntaxKind.AsyncKeyword && lookAhead(nextTokenIsFunctionKeywordOnSameLine));
}
// True if positioned at the start of a list element
@@ -3568,12 +3569,12 @@ namespace ts {
// If it wasn't then just try to parse out a '.' and report an error.
const node = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
node.expression = expression;
node.dotToken = parseExpectedToken(SyntaxKind.DotToken, /*reportAtCurrentPosition*/ false, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access);
parseExpectedToken(SyntaxKind.DotToken, /*reportAtCurrentPosition*/ false, Diagnostics.super_must_be_followed_by_an_argument_list_or_member_access);
node.name = parseRightSideOfDot(/*allowIdentifierNames*/ true);
return finishNode(node);
}
function tagNamesAreEquivalent(lhs: EntityName, rhs: EntityName): boolean {
function tagNamesAreEquivalent(lhs: JsxTagNameExpression, rhs: JsxTagNameExpression): boolean {
if (lhs.kind !== rhs.kind) {
return false;
}
@@ -3582,8 +3583,15 @@ namespace ts {
return (<Identifier>lhs).text === (<Identifier>rhs).text;
}
return (<QualifiedName>lhs).right.text === (<QualifiedName>rhs).right.text &&
tagNamesAreEquivalent((<QualifiedName>lhs).left, (<QualifiedName>rhs).left);
if (lhs.kind === SyntaxKind.ThisKeyword) {
return true;
}
// If we are at this statement then we must have PropertyAccessExpression and because tag name in Jsx element can only
// take forms of JsxTagNameExpression which includes an identifier, "this" expression, or another propertyAccessExpression
// it is safe to case the expression property as such. See parseJsxElementName for how we parse tag name in Jsx element
return (<PropertyAccessExpression>lhs).name.text === (<PropertyAccessExpression>rhs).name.text &&
tagNamesAreEquivalent((<PropertyAccessExpression>lhs).expression as JsxTagNameExpression, (<PropertyAccessExpression>rhs).expression as JsxTagNameExpression);
}
@@ -3651,7 +3659,7 @@ namespace ts {
Debug.fail("Unknown JSX child kind " + token);
}
function parseJsxChildren(openingTagName: EntityName): NodeArray<JsxChild> {
function parseJsxChildren(openingTagName: LeftHandSideExpression): NodeArray<JsxChild> {
const result = createNodeArray<JsxChild>();
const saveParsingContext = parsingContext;
parsingContext |= 1 << ParsingContext.JsxChildren;
@@ -3713,17 +3721,22 @@ namespace ts {
return finishNode(node);
}
function parseJsxElementName(): EntityName {
function parseJsxElementName(): JsxTagNameExpression {
scanJsxIdentifier();
let elementName: EntityName = parseIdentifierName();
// JsxElement can have name in the form of
// propertyAccessExpression
// primaryExpression in the form of an identifier and "this" keyword
// We can't just simply use parseLeftHandSideExpressionOrHigher because then we will start consider class,function etc as a keyword
// We only want to consider "this" as a primaryExpression
let expression: JsxTagNameExpression = token === SyntaxKind.ThisKeyword ?
parseTokenNode<PrimaryExpression>() : parseIdentifierName();
while (parseOptional(SyntaxKind.DotToken)) {
scanJsxIdentifier();
const node: QualifiedName = <QualifiedName>createNode(SyntaxKind.QualifiedName, elementName.pos); // !!!
node.left = elementName;
node.right = parseIdentifierName();
elementName = finishNode(node);
const propertyAccess: PropertyAccessExpression = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
propertyAccess.expression = expression;
propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true);
expression = finishNode(propertyAccess);
}
return elementName;
return expression;
}
function parseJsxExpression(inExpressionContext: boolean): JsxExpression {
@@ -3803,7 +3816,6 @@ namespace ts {
if (dotToken) {
const propertyAccess = <PropertyAccessExpression>createNode(SyntaxKind.PropertyAccessExpression, expression.pos);
propertyAccess.expression = expression;
propertyAccess.dotToken = dotToken;
propertyAccess.name = parseRightSideOfDot(/*allowIdentifierNames*/ true);
expression = finishNode(propertyAccess);
continue;
@@ -6355,6 +6367,9 @@ namespace ts {
case SyntaxKind.AtToken:
if (canParseTag) {
parentTagTerminated = !tryParseChildTag(jsDocTypeLiteral);
if (!parentTagTerminated) {
resumePos = scanner.getStartPos();
}
}
seenAsterisk = false;
break;
+129 -28
View File
@@ -4,7 +4,7 @@
namespace ts {
/** The version of the TypeScript compiler release */
export const version = "1.9.0";
export const version = "2.0.0";
const emptyArray: any[] = [];
@@ -125,10 +125,10 @@ namespace ts {
}
function tryReadTypesSection(packageJsonPath: string, baseDirectory: string, state: ModuleResolutionState): string {
let jsonContent: { typings?: string, types?: string };
let jsonContent: { typings?: string, types?: string, main?: string };
try {
const jsonText = state.host.readFile(packageJsonPath);
jsonContent = jsonText ? <{ typings?: string, types?: string }>JSON.parse(jsonText) : {};
jsonContent = jsonText ? <{ typings?: string, types?: string, main?: string }>JSON.parse(jsonText) : {};
}
catch (e) {
// gracefully handle if readFile fails or returns not JSON
@@ -168,14 +168,36 @@ namespace ts {
}
return typesFilePath;
}
// Use the main module for inferring types if no types package specified and the allowJs is set
if (state.compilerOptions.allowJs && jsonContent.main && typeof jsonContent.main === "string") {
if (state.traceEnabled) {
trace(state.host, Diagnostics.No_types_specified_in_package_json_but_allowJs_is_set_so_returning_main_value_of_0, jsonContent.main);
}
const mainFilePath = normalizePath(combinePaths(baseDirectory, jsonContent.main));
return mainFilePath;
}
return undefined;
}
const typeReferenceExtensions = [".d.ts"];
function getEffectiveTypeRoots(options: CompilerOptions, host: ModuleResolutionHost) {
return options.typeRoots ||
defaultTypeRoots.map(d => combinePaths(options.configFilePath ? getDirectoryPath(options.configFilePath) : host.getCurrentDirectory(), d));
if (options.typeRoots) {
return options.typeRoots;
}
let currentDirectory: string;
if (options.configFilePath) {
currentDirectory = getDirectoryPath(options.configFilePath);
}
else if (host.getCurrentDirectory) {
currentDirectory = host.getCurrentDirectory();
}
if (!currentDirectory) {
return undefined;
}
return map(defaultTypeRoots, d => combinePaths(currentDirectory, d));
}
/**
@@ -215,7 +237,7 @@ namespace ts {
const failedLookupLocations: string[] = [];
// Check primary library paths
if (typeRoots.length) {
if (typeRoots && typeRoots.length) {
if (traceEnabled) {
trace(host, Diagnostics.Resolving_with_primary_search_path_0, typeRoots.join(", "));
}
@@ -605,7 +627,7 @@ namespace ts {
failedLookupLocations, supportedExtensions, state);
let isExternalLibraryImport = false;
if (!resolvedFileName) {
if (!resolvedFileName) {
if (moduleHasNonRelativeName(moduleName)) {
if (traceEnabled) {
trace(host, Diagnostics.Loading_module_0_from_node_modules_folder, moduleName);
@@ -735,12 +757,13 @@ namespace ts {
const nodeModulesFolder = combinePaths(directory, "node_modules");
const nodeModulesFolderExists = directoryProbablyExists(nodeModulesFolder, state.host);
const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
// Load only typescript files irrespective of allowJs option if loading from node modules
let result = loadModuleFromFile(candidate, supportedTypeScriptExtensions, failedLookupLocations, !nodeModulesFolderExists, state);
const supportedExtensions = getSupportedExtensions(state.compilerOptions);
let result = loadModuleFromFile(candidate, supportedExtensions, failedLookupLocations, !nodeModulesFolderExists, state);
if (result) {
return result;
}
result = loadNodeModuleFromDirectory(supportedTypeScriptExtensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state);
result = loadNodeModuleFromDirectory(supportedExtensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state);
if (result) {
return result;
}
@@ -751,13 +774,18 @@ namespace ts {
while (true) {
const baseName = getBaseFileName(directory);
if (baseName !== "node_modules") {
const result =
// first: try to load module as-is
loadModuleFromNodeModulesFolder(moduleName, directory, failedLookupLocations, state) ||
// second: try to load module from the scope '@types'
loadModuleFromNodeModulesFolder(combinePaths("@types", moduleName), directory, failedLookupLocations, state);
if (result) {
return result;
// Try to load source from the package
const packageResult = loadModuleFromNodeModulesFolder(moduleName, directory, failedLookupLocations, state);
if (packageResult && hasTypeScriptFileExtension(packageResult)) {
// Always prefer a TypeScript (.ts, .tsx, .d.ts) file shipped with the package
return packageResult;
}
else {
// Else prefer a types package over non-TypeScript results (e.g. JavaScript files)
const typesResult = loadModuleFromNodeModulesFolder(combinePaths("@types", moduleName), directory, failedLookupLocations, state);
if (typesResult || packageResult) {
return typesResult || packageResult;
}
}
}
@@ -1033,9 +1061,11 @@ namespace ts {
let result: string[] = [];
if (host.directoryExists && host.getDirectories) {
const typeRoots = getEffectiveTypeRoots(options, host);
for (const root of typeRoots) {
if (host.directoryExists(root)) {
result = result.concat(host.getDirectories(root));
if (typeRoots) {
for (const root of typeRoots) {
if (host.directoryExists(root)) {
result = result.concat(host.getDirectories(root));
}
}
}
}
@@ -1054,6 +1084,22 @@ namespace ts {
let fileProcessingDiagnostics = createDiagnosticCollection();
const programStart = performance.mark();
// The below settings are to track if a .js file should be add to the program if loaded via searching under node_modules.
// This works as imported modules are discovered recursively in a depth first manner, specifically:
// - For each root file, findSourceFile is called.
// - This calls processImportedModules for each module imported in the source file.
// - This calls resolveModuleNames, and then calls findSourceFile for each resolved module.
// As all these operations happen - and are nested - within the createProgram call, they close over the below variables.
// The current resolution depth is tracked by incrementing/decrementing as the depth first search progresses.
const maxNodeModulesJsDepth = typeof options.maxNodeModuleJsDepth === "number" ? options.maxNodeModuleJsDepth : 2;
let currentNodeModulesDepth = 0;
// If a module has some of its imports skipped due to being at the depth limit under node_modules, then track
// this, as it may be imported at a shallower depth later, and then it will need its skipped imports processed.
const modulesWithElidedImports: Map<boolean> = {};
// Track source files that are source files found by searching under node_modules, as these shouldn't be compiled.
const sourceFilesFoundSearchingNodeModules: Map<boolean> = {};
host = host || createCompilerHost(options);
@@ -1207,6 +1253,7 @@ namespace ts {
(oldOptions.rootDir !== options.rootDir) ||
(oldOptions.configFilePath !== options.configFilePath) ||
(oldOptions.baseUrl !== options.baseUrl) ||
(oldOptions.maxNodeModuleJsDepth !== options.maxNodeModuleJsDepth) ||
!arrayIsEqualTo(oldOptions.typeRoots, oldOptions.typeRoots) ||
!arrayIsEqualTo(oldOptions.rootDirs, options.rootDirs) ||
!mapIsEqualTo(oldOptions.paths, options.paths)) {
@@ -1331,6 +1378,7 @@ namespace ts {
getSourceFile: program.getSourceFile,
getSourceFileByPath: program.getSourceFileByPath,
getSourceFiles: program.getSourceFiles,
isSourceFileFromExternalLibrary: (file: SourceFile) => !!lookUp(sourceFilesFoundSearchingNodeModules, file.path),
writeFile: writeFileCallback || (
(fileName, data, writeByteOrderMark, onError, sourceFiles) => host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles)),
isEmitBlocked,
@@ -1346,7 +1394,7 @@ namespace ts {
}
function emit(sourceFile?: SourceFile, writeFileCallback?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult {
return runWithCancellationToken(() => emitWorker(this, sourceFile, writeFileCallback, cancellationToken));
return runWithCancellationToken(() => emitWorker(program, sourceFile, writeFileCallback, cancellationToken));
}
function isEmitBlocked(emitFileName: string): boolean {
@@ -1598,8 +1646,19 @@ namespace ts {
}
break;
case SyntaxKind.PropertyDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.property_declarations_can_only_be_used_in_a_ts_file));
return true;
const propertyDeclaration = <PropertyDeclaration>node;
if (propertyDeclaration.modifiers) {
for (const modifier of propertyDeclaration.modifiers) {
if (modifier.kind !== SyntaxKind.StaticKeyword) {
diagnostics.push(createDiagnosticForNode(modifier, Diagnostics._0_can_only_be_used_in_a_ts_file, tokenToString(modifier.kind)));
return true;
}
}
}
if (checkTypeAnnotation((<PropertyDeclaration>node).type)) {
return true;
}
break;
case SyntaxKind.EnumDeclaration:
diagnostics.push(createDiagnosticForNode(node, Diagnostics.enum_declarations_can_only_be_used_in_a_ts_file));
return true;
@@ -1866,6 +1925,26 @@ namespace ts {
reportFileNamesDifferOnlyInCasingError(fileName, file.fileName, refFile, refPos, refEnd);
}
// If the file was previously found via a node_modules search, but is now being processed as a root file,
// then everything it sucks in may also be marked incorrectly, and needs to be checked again.
if (file && lookUp(sourceFilesFoundSearchingNodeModules, file.path) && currentNodeModulesDepth == 0) {
sourceFilesFoundSearchingNodeModules[file.path] = false;
if (!options.noResolve) {
processReferencedFiles(file, getDirectoryPath(fileName), isDefaultLib);
processTypeReferenceDirectives(file);
}
modulesWithElidedImports[file.path] = false;
processImportedModules(file, getDirectoryPath(fileName));
}
// See if we need to reprocess the imports due to prior skipped imports
else if (file && lookUp(modulesWithElidedImports, file.path)) {
if (currentNodeModulesDepth < maxNodeModulesJsDepth) {
modulesWithElidedImports[file.path] = false;
processImportedModules(file, getDirectoryPath(fileName));
}
}
return file;
}
@@ -1882,6 +1961,7 @@ namespace ts {
filesByName.set(path, file);
if (file) {
sourceFilesFoundSearchingNodeModules[path] = (currentNodeModulesDepth > 0);
file.path = path;
if (host.useCaseSensitiveFileNames()) {
@@ -2004,16 +2084,37 @@ namespace ts {
for (let i = 0; i < moduleNames.length; i++) {
const resolution = resolutions[i];
setResolvedModule(file, moduleNames[i], resolution);
const resolvedPath = resolution ? toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName) : undefined;
// add file to program only if:
// - resolution was successful
// - noResolve is falsy
// - module name comes from the list of imports
const shouldAddFile = resolution &&
!options.noResolve &&
i < file.imports.length;
// - it's not a top level JavaScript module that exceeded the search max
const isFromNodeModulesSearch = resolution && resolution.isExternalLibraryImport;
const isJsFileFromNodeModules = isFromNodeModulesSearch && hasJavaScriptFileExtension(resolution.resolvedFileName);
if (shouldAddFile) {
findSourceFile(resolution.resolvedFileName, toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName), /*isDefaultLib*/ false, /*isReference*/ false, file, skipTrivia(file.text, file.imports[i].pos), file.imports[i].end);
if (isFromNodeModulesSearch) {
currentNodeModulesDepth++;
}
const elideImport = isJsFileFromNodeModules && currentNodeModulesDepth > maxNodeModulesJsDepth;
const shouldAddFile = resolution && !options.noResolve && i < file.imports.length && !elideImport;
if (elideImport) {
modulesWithElidedImports[file.path] = true;
}
else if (shouldAddFile) {
findSourceFile(resolution.resolvedFileName,
resolvedPath,
/*isDefaultLib*/ false, /*isReference*/ false,
file,
skipTrivia(file.text, file.imports[i].pos),
file.imports[i].end);
}
if (isFromNodeModulesSearch) {
currentNodeModulesDepth--;
}
}
}
+15 -4
View File
@@ -31,6 +31,7 @@ namespace ts {
scanJsxToken(): SyntaxKind;
scanJSDocToken(): SyntaxKind;
scan(): SyntaxKind;
getText(): string;
// Sets the text for the scanner to scan. An optional subrange starting point and length
// can be provided to have the scanner only scan a portion of the text.
setText(text: string, start?: number, length?: number): void;
@@ -365,6 +366,11 @@ namespace ts {
const hasOwnProperty = Object.prototype.hasOwnProperty;
export function isWhiteSpace(ch: number): boolean {
return isWhiteSpaceSingleLine(ch) || isLineBreak(ch);
}
/** Does not include line breaks. For that, see isWhiteSpaceLike. */
export function isWhiteSpaceSingleLine(ch: number): boolean {
// Note: nextLine is in the Zs space, and should be considered to be a whitespace.
// It is explicitly not a line-break as it isn't in the exact set specified by EcmaScript.
return ch === CharacterCodes.space ||
@@ -503,7 +509,7 @@ namespace ts {
break;
default:
if (ch > CharacterCodes.maxAsciiCharacter && (isWhiteSpace(ch) || isLineBreak(ch))) {
if (ch > CharacterCodes.maxAsciiCharacter && (isWhiteSpace(ch))) {
pos++;
continue;
}
@@ -817,6 +823,7 @@ namespace ts {
scanJsxToken,
scanJSDocToken,
scan,
getText,
setText,
setScriptTarget,
setLanguageVariant,
@@ -1256,7 +1263,7 @@ namespace ts {
continue;
}
else {
while (pos < end && isWhiteSpace(text.charCodeAt(pos))) {
while (pos < end && isWhiteSpaceSingleLine(text.charCodeAt(pos))) {
pos++;
}
return token = SyntaxKind.WhitespaceTrivia;
@@ -1574,7 +1581,7 @@ namespace ts {
}
return token = getIdentifierToken();
}
else if (isWhiteSpace(ch)) {
else if (isWhiteSpaceSingleLine(ch)) {
pos++;
continue;
}
@@ -1743,7 +1750,7 @@ namespace ts {
let ch = text.charCodeAt(pos);
while (pos < end) {
ch = text.charCodeAt(pos);
if (isWhiteSpace(ch)) {
if (isWhiteSpaceSingleLine(ch)) {
pos++;
}
else {
@@ -1843,6 +1850,10 @@ namespace ts {
return speculationHelper(callback, /*isLookahead*/ false);
}
function getText(): string {
return text;
}
function setText(newText: string, start: number, length: number) {
text = newText || "";
end = length === undefined ? text.length : start + length;
+69 -64
View File
@@ -15,6 +15,7 @@ namespace ts {
useCaseSensitiveFileNames: boolean;
write(s: string): void;
readFile(path: string, encoding?: string): string;
getFileSize?(path: string): number;
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
@@ -25,7 +26,7 @@ namespace ts {
getExecutingFilePath(): string;
getCurrentDirectory(): string;
getDirectories(path: string): string[];
readDirectory(path: string, extension?: string, exclude?: string[]): string[];
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[];
getModifiedTime?(path: string): Date;
createHash?(data: string): string;
getMemoryUsage?(): number;
@@ -75,18 +76,19 @@ namespace ts {
readFile(path: string): string;
writeFile(path: string, contents: string): void;
getDirectories(path: string): string[];
readDirectory(path: string, extension?: string, exclude?: string[]): string[];
readDirectory(path: string, extensions?: string[], basePaths?: string[], excludeEx?: string, includeFileEx?: string, includeDirEx?: string): string[];
watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
realpath(path: string): string;
getEnvironmentVariable?(name: string): string;
};
export var sys: System = (function () {
export var sys: System = (function() {
function getWScriptSystem(): System {
const fso = new ActiveXObject("Scripting.FileSystemObject");
const shell = new ActiveXObject("WScript.Shell");
const fileStream = new ActiveXObject("ADODB.Stream");
fileStream.Type = 2 /*text*/;
@@ -154,10 +156,6 @@ namespace ts {
}
}
function getCanonicalPath(path: string): string {
return path.toLowerCase();
}
function getNames(collection: any): string[] {
const result: string[] = [];
for (let e = new Enumerator(collection); !e.atEnd(); e.moveNext()) {
@@ -171,28 +169,20 @@ namespace ts {
return getNames(folder.subfolders);
}
function readDirectory(path: string, extension?: string, exclude?: string[]): string[] {
const result: string[] = [];
exclude = map(exclude, s => getCanonicalPath(combinePaths(path, s)));
visitDirectory(path);
return result;
function visitDirectory(path: string) {
function getAccessibleFileSystemEntries(path: string): FileSystemEntries {
try {
const folder = fso.GetFolder(path || ".");
const files = getNames(folder.files);
for (const current of files) {
const name = combinePaths(path, current);
if ((!extension || fileExtensionIs(name, extension)) && !contains(exclude, getCanonicalPath(name))) {
result.push(name);
}
}
const subfolders = getNames(folder.subfolders);
for (const current of subfolders) {
const name = combinePaths(path, current);
if (!contains(exclude, getCanonicalPath(name))) {
visitDirectory(name);
}
}
const directories = getNames(folder.subfolders);
return { files, directories };
}
catch (e) {
return { files: [], directories: [] };
}
}
function readDirectory(path: string, extensions?: string[], excludes?: string[], includes?: string[]): string[] {
return matchFiles(path, extensions, excludes, includes, /*useCaseSensitiveFileNames*/ false, shell.CurrentDirectory, getAccessibleFileSystemEntries);
}
return {
@@ -222,7 +212,7 @@ namespace ts {
return WScript.ScriptFullName;
},
getCurrentDirectory() {
return new ActiveXObject("WScript.Shell").CurrentDirectory;
return shell.CurrentDirectory;
},
getDirectories,
getEnvironmentVariable(name: string) {
@@ -386,8 +376,43 @@ namespace ts {
}
}
function getCanonicalPath(path: string): string {
return useCaseSensitiveFileNames ? path : path.toLowerCase();
function getAccessibleFileSystemEntries(path: string): FileSystemEntries {
try {
const entries = _fs.readdirSync(path || ".").sort();
const files: string[] = [];
const directories: string[] = [];
for (const entry of entries) {
// This is necessary because on some file system node fails to exclude
// "." and "..". See https://github.com/nodejs/node/issues/4002
if (entry === "." || entry === "..") {
continue;
}
const name = combinePaths(path, entry);
let stat: any;
try {
stat = _fs.statSync(name);
}
catch (e) {
continue;
}
if (stat.isFile()) {
files.push(entry);
}
else if (stat.isDirectory()) {
directories.push(entry);
}
}
return { files, directories };
}
catch (e) {
return { files: [], directories: [] };
}
}
function readDirectory(path: string, extensions?: string[], excludes?: string[], includes?: string[]): string[] {
return matchFiles(path, extensions, excludes, includes, useCaseSensitiveFileNames, process.cwd(), getAccessibleFileSystemEntries);
}
const enum FileSystemEntryKind {
@@ -420,39 +445,6 @@ namespace ts {
return filter<string>(_fs.readdirSync(path), p => fileSystemEntryExists(combinePaths(path, p), FileSystemEntryKind.Directory));
}
function readDirectory(path: string, extension?: string, exclude?: string[]): string[] {
const result: string[] = [];
exclude = map(exclude, s => getCanonicalPath(combinePaths(path, s)));
visitDirectory(path);
return result;
function visitDirectory(path: string) {
const files = _fs.readdirSync(path || ".").sort();
const directories: string[] = [];
for (const current of files) {
// This is necessary because on some file system node fails to exclude
// "." and "..". See https://github.com/nodejs/node/issues/4002
if (current === "." || current === "..") {
continue;
}
const name = combinePaths(path, current);
if (!contains(exclude, getCanonicalPath(name))) {
const stat = _fs.statSync(name);
if (stat.isFile()) {
if (!extension || fileExtensionIs(name, extension)) {
result.push(name);
}
}
else if (stat.isDirectory()) {
directories.push(name);
}
}
}
for (const current of directories) {
visitDirectory(current);
}
}
}
return {
args: process.argv.slice(2),
newLine: _os.EOL,
@@ -509,7 +501,7 @@ namespace ts {
}
);
},
resolvePath: function (path: string): string {
resolvePath: function(path: string): string {
return _path.resolve(path);
},
fileExists,
@@ -549,6 +541,16 @@ namespace ts {
}
return process.memoryUsage().heapUsed;
},
getFileSize(path) {
try {
const stat = _fs.statSync(path);
if (stat.isFile()) {
return stat.size;
}
}
catch (e) { }
return 0;
},
exit(exitCode?: number): void {
process.exit(exitCode);
},
@@ -593,7 +595,10 @@ namespace ts {
getCurrentDirectory: () => ChakraHost.currentDirectory,
getDirectories: ChakraHost.getDirectories,
getEnvironmentVariable: ChakraHost.getEnvironmentVariable || ((name: string) => ""),
readDirectory: ChakraHost.readDirectory,
readDirectory: (path: string, extensions?: string[], excludes?: string[], includes?: string[]) => {
const pattern = getFileMatcherPatterns(path, extensions, excludes, includes, !!ChakraHost.useCaseSensitiveFileNames, ChakraHost.currentDirectory);
return ChakraHost.readDirectory(path, extensions, pattern.basePaths, pattern.excludePattern, pattern.includeFilePattern, pattern.includeDirectoryPattern);
},
exit: ChakraHost.quit,
realpath
};
+31 -57
View File
@@ -13,7 +13,7 @@ namespace ts {
const enum TypeScriptSubstitutionFlags {
/** Enables substitutions for decorated classes. */
DecoratedClasses = 1 << 0,
ClassAliases = 1 << 0,
/** Enables substitutions for namespace exports. */
NamespaceExports = 1 << 1,
/** Enables substitutions for async methods with `super` calls. */
@@ -63,13 +63,7 @@ namespace ts {
* A map that keeps track of aliases created for classes with decorators to avoid issues
* with the double-binding behavior of classes.
*/
let decoratedClassAliases: Map<Identifier>;
/**
* A map that keeps track of currently active aliases defined in `decoratedClassAliases`
* when just-in-time substitution occurs while printing an expression identifier.
*/
let currentDecoratedClassAliases: Map<Identifier>;
let classAliases: Map<Identifier>;
/**
* Keeps track of whether we are within any containing namespaces when performing
@@ -495,7 +489,7 @@ namespace ts {
const staticProperties = getInitializedProperties(node, /*isStatic*/ true);
const hasExtendsClause = getClassExtendsHeritageClauseElement(node) !== undefined;
const isDecoratedClass = shouldEmitDecorateCallForClass(node);
let decoratedClassAlias: Identifier;
let classAlias: Identifier;
// emit name if
// - node has a name
@@ -529,7 +523,7 @@ namespace ts {
statements.push(classDeclaration);
}
else {
decoratedClassAlias = addClassDeclarationHeadWithDecorators(statements, node, name, hasExtendsClause);
classAlias = addClassDeclarationHeadWithDecorators(statements, node, name, hasExtendsClause);
}
// Emit static property assignment. Because classDeclaration is lexically evaluated,
@@ -544,7 +538,7 @@ namespace ts {
// Write any decorators of the node.
addClassElementDecorationStatements(statements, node, /*isStatic*/ false);
addClassElementDecorationStatements(statements, node, /*isStatic*/ true);
addConstructorDecorationStatement(statements, node, decoratedClassAlias);
addConstructorDecorationStatement(statements, node, classAlias);
// If the class is exported as part of a TypeScript namespace, emit the namespace export.
// Otherwise, if the class was exported at the top level and was decorated, emit an export
@@ -679,11 +673,11 @@ namespace ts {
}
// Record an alias to avoid class double-binding.
let decoratedClassAlias: Identifier;
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.DecoratedClassWithSelfReference) {
enableSubstitutionForDecoratedClasses();
decoratedClassAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? node.name.text : "default");
decoratedClassAliases[getOriginalNodeId(node)] = decoratedClassAlias;
let classAlias: Identifier;
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference) {
enableSubstitutionForClassAliases();
classAlias = createUniqueName(node.name && !isGeneratedIdentifier(node.name) ? node.name.text : "default");
classAliases[getOriginalNodeId(node)] = classAlias;
}
const declaredName = getDeclarationName(node, /*allowComments*/ true);
@@ -696,7 +690,7 @@ namespace ts {
/*modifiers*/ undefined,
createLetDeclarationList([
createVariableDeclaration(
decoratedClassAlias || declaredName,
classAlias || declaredName,
/*type*/ undefined,
classExpression
)
@@ -707,7 +701,7 @@ namespace ts {
)
);
if (decoratedClassAlias) {
if (classAlias) {
// We emit the class alias as a `let` declaration here so that it has the same
// TDZ as the class.
@@ -720,7 +714,7 @@ namespace ts {
createVariableDeclaration(
declaredName,
/*type*/ undefined,
decoratedClassAlias
classAlias
)
]),
/*location*/ location
@@ -730,7 +724,7 @@ namespace ts {
);
}
return decoratedClassAlias;
return classAlias;
}
/**
@@ -760,6 +754,11 @@ namespace ts {
if (staticProperties.length > 0) {
const expressions: Expression[] = [];
const temp = createTempVariable(hoistVariableDeclaration);
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithConstructorReference) {
// record an alias as the class name is not in scope for statics.
enableSubstitutionForClassAliases();
classAliases[getOriginalNodeId(node)] = temp;
}
// To preserve the behavior of the old emitter, we explicitly indent
// the body of a class with static initializers.
@@ -1085,9 +1084,6 @@ namespace ts {
const propertyName = visitPropertyNameOfClassElement(property);
const initializer = visitNode(property.initializer, visitor, isExpression);
const memberAccess = createMemberAccessForPropertyName(receiver, propertyName, /*location*/ propertyName);
if (!isComputedPropertyName(propertyName)) {
setNodeEmitFlags(memberAccess, NodeEmitFlags.NoNestedSourceMaps);
}
return createAssignment(memberAccess, initializer);
}
@@ -3100,18 +3096,16 @@ namespace ts {
}
}
function enableSubstitutionForDecoratedClasses() {
if ((enabledSubstitutions & TypeScriptSubstitutionFlags.DecoratedClasses) === 0) {
enabledSubstitutions |= TypeScriptSubstitutionFlags.DecoratedClasses;
function enableSubstitutionForClassAliases() {
if ((enabledSubstitutions & TypeScriptSubstitutionFlags.ClassAliases) === 0) {
enabledSubstitutions |= TypeScriptSubstitutionFlags.ClassAliases;
// We need to enable substitutions for identifiers. This allows us to
// substitute class names inside of a class declaration.
context.enableSubstitution(SyntaxKind.Identifier);
context.enableEmitNotification(SyntaxKind.Identifier);
// Keep track of class aliases.
decoratedClassAliases = {};
currentDecoratedClassAliases = {};
classAliases = {};
}
}
@@ -3129,10 +3123,6 @@ namespace ts {
}
}
function isClassWithDecorators(node: Node): node is ClassDeclaration {
return node.kind === SyntaxKind.ClassDeclaration && node.decorators !== undefined;
}
function isSuperContainer(node: Node): node is SuperContainer {
const kind = node.kind;
return kind === SyntaxKind.ClassDeclaration
@@ -3159,21 +3149,6 @@ namespace ts {
function onEmitNode(node: Node, emit: (node: Node) => void): void {
const savedApplicableSubstitutions = applicableSubstitutions;
const savedCurrentSuperContainer = currentSuperContainer;
// If we need support substitutions for aliases for decorated classes,
// we should enable it here.
if (enabledSubstitutions & TypeScriptSubstitutionFlags.DecoratedClasses) {
if (isClassWithDecorators(node)) {
currentDecoratedClassAliases[getOriginalNodeId(node)] = decoratedClassAliases[getOriginalNodeId(node)];
}
else if (node.kind === SyntaxKind.Identifier) {
const declaration = resolver.getReferencedValueDeclaration(<Identifier>node);
if (declaration && isClassWithDecorators(declaration)) {
currentDecoratedClassAliases[getOriginalNodeId(declaration)] = decoratedClassAliases[getOriginalNodeId(declaration)];
}
}
}
// If we need to support substitutions for `super` in an async method,
// we should track it here.
if (enabledSubstitutions & TypeScriptSubstitutionFlags.AsyncMethodsWithSuper && isSuperContainer(node)) {
@@ -3183,16 +3158,13 @@ namespace ts {
if (enabledSubstitutions & TypeScriptSubstitutionFlags.NamespaceExports && isTransformedModuleDeclaration(node)) {
applicableSubstitutions |= TypeScriptSubstitutionFlags.NamespaceExports;
}
if (enabledSubstitutions & TypeScriptSubstitutionFlags.NonQualifiedEnumMembers && isTransformedEnumDeclaration(node)) {
applicableSubstitutions |= TypeScriptSubstitutionFlags.NonQualifiedEnumMembers;
}
previousOnEmitNode(node, emit);
if (enabledSubstitutions & TypeScriptSubstitutionFlags.DecoratedClasses && isClassWithDecorators(node)) {
currentDecoratedClassAliases[getOriginalNodeId(node)] = undefined;
}
applicableSubstitutions = savedApplicableSubstitutions;
currentSuperContainer = savedCurrentSuperContainer;
}
@@ -3254,20 +3226,22 @@ namespace ts {
}
function substituteExpressionIdentifier(node: Identifier): Expression {
return trySubstituteDecoratedClassName(node)
return trySubstituteClassAlias(node)
|| trySubstituteNamespaceExportedName(node)
|| node;
}
function trySubstituteDecoratedClassName(node: Identifier): Expression {
if (enabledSubstitutions & TypeScriptSubstitutionFlags.DecoratedClasses) {
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.SelfReferenceInDecoratedClass) {
function trySubstituteClassAlias(node: Identifier): Expression {
if (enabledSubstitutions & TypeScriptSubstitutionFlags.ClassAliases) {
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ConstructorReferenceInClass) {
// Due to the emit for class decorators, any reference to the class from inside of the class body
// must instead be rewritten to point to a temporary variable to avoid issues with the double-bind
// behavior of class names in ES6.
// Also, when emitting statics for class expressions, we must substitute a class alias for
// constructor references in static property initializers.
const declaration = resolver.getReferencedValueDeclaration(node);
if (declaration) {
const classAlias = currentDecoratedClassAliases[getOriginalNodeId(declaration)];
const classAlias = classAliases[declaration.id];
if (classAlias) {
const clone = getSynthesizedClone(classAlias);
setSourceMapRange(clone, node);
+7 -5
View File
@@ -3,14 +3,15 @@
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"out": "../../built/local/tsc.js",
"sourceMap": true
"outFile": "../../built/local/tsc.js",
"sourceMap": true,
"declaration": true,
"stripInternal": true
},
"files": [
"types.ts",
"core.ts",
"sys.ts",
"diagnosticInformationMap.generated.ts",
"types.ts",
"scanner.ts",
"parser.ts",
"utilities.ts",
@@ -34,6 +35,7 @@
"emitter.ts",
"program.ts",
"commandLineParser.ts",
"tsc.ts"
"tsc.ts",
"diagnosticInformationMap.generated.ts"
]
}
+62 -18
View File
@@ -493,6 +493,10 @@ namespace ts {
hasTrailingComma?: boolean;
}
export interface ModifiersArray extends NodeArray<Modifier> {
flags: NodeFlags;
}
// @kind(SyntaxKind.AbstractKeyword)
// @kind(SyntaxKind.AsyncKeyword)
// @kind(SyntaxKind.ConstKeyword)
@@ -1036,7 +1040,6 @@ namespace ts {
// @kind(SyntaxKind.PropertyAccessExpression)
export interface PropertyAccessExpression extends MemberExpression, Declaration {
expression: LeftHandSideExpression;
dotToken: Node;
name: Identifier;
}
@@ -1099,12 +1102,14 @@ namespace ts {
closingElement: JsxClosingElement;
}
export type JsxTagNameExpression = PrimaryExpression | PropertyAccessExpression;
/// The opening element of a <Tag>...</Tag> JsxElement
// @kind(SyntaxKind.JsxOpeningElement)
export interface JsxOpeningElement extends Expression {
_openingElementBrand?: any;
tagName: EntityName;
attributes: NodeArray<JsxAttributeLike>;
tagName: JsxTagNameExpression;
attributes: NodeArray<JsxAttribute | JsxSpreadAttribute>;
}
/// A JSX expression of the form <TagName attrs />
@@ -1132,7 +1137,7 @@ namespace ts {
// @kind(SyntaxKind.JsxClosingElement)
export interface JsxClosingElement extends Node {
tagName: EntityName;
tagName: JsxTagNameExpression;
}
// @kind(SyntaxKind.JsxExpression)
@@ -1256,6 +1261,7 @@ namespace ts {
export interface SwitchStatement extends Statement {
expression: Expression;
caseBlock: CaseBlock;
possiblyExhaustive?: boolean;
}
// @kind(SyntaxKind.CaseBlock)
@@ -1628,8 +1634,9 @@ namespace ts {
Assignment = 1 << 4, // Assignment
TrueCondition = 1 << 5, // Condition known to be true
FalseCondition = 1 << 6, // Condition known to be false
Referenced = 1 << 7, // Referenced as antecedent once
Shared = 1 << 8, // Referenced as antecedent more than once
SwitchClause = 1 << 7, // Switch statement clause
Referenced = 1 << 8, // Referenced as antecedent once
Shared = 1 << 9, // Referenced as antecedent more than once
Label = BranchLabel | LoopLabel,
Condition = TrueCondition | FalseCondition
}
@@ -1665,6 +1672,13 @@ namespace ts {
antecedent: FlowNode;
}
export interface FlowSwitchClause extends FlowNode {
switchStatement: SwitchStatement;
clauseStart: number; // Start index of case/default clause range
clauseEnd: number; // End index of case/default clause range
antecedent: FlowNode;
}
export interface AmdDependency {
path: string;
name: string;
@@ -1745,7 +1759,15 @@ namespace ts {
}
export interface ParseConfigHost {
readDirectory(rootDir: string, extension: string, exclude: string[]): string[];
useCaseSensitiveFileNames: boolean;
readDirectory(rootDir: string, extensions: string[], excludes: string[], includes: string[]): string[];
/**
* Gets a value indicating whether the specified path exists and is a file.
* @param path The path to test.
*/
fileExists(path: string): boolean;
}
export interface WriteFileCallback {
@@ -1934,7 +1956,7 @@ namespace ts {
buildTypeParameterDisplay(tp: TypeParameter, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
buildTypePredicateDisplay(predicate: TypePredicate, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
buildTypeParameterDisplayFromSymbol(symbol: Symbol, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
buildDisplayForParametersAndDelimiters(thisType: Type, parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
buildDisplayForParametersAndDelimiters(thisParameter: Symbol, parameters: Symbol[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
buildDisplayForTypeParametersAndDelimiters(typeParameters: TypeParameter[], writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
buildReturnTypeDisplay(signature: Signature, writer: SymbolWriter, enclosingDeclaration?: Node, flags?: TypeFormatFlags): void;
}
@@ -2166,6 +2188,8 @@ namespace ts {
PropertyOrAccessor = Property | Accessor,
Export = ExportNamespace | ExportType | ExportValue,
ClassMember = Method | Accessor | Property,
/* @internal */
// The set of things we consider semantically classifiable. Used to speed up the LS during
// classification.
@@ -2181,11 +2205,13 @@ namespace ts {
members?: SymbolTable; // Class, interface or literal instance members
exports?: SymbolTable; // Module exports
globalExports?: SymbolTable; // Conditional global UMD exports
/* @internal */ isReadonly?: boolean; // readonly? (set only for intersections and unions)
/* @internal */ id?: number; // Unique id (used to look up SymbolLinks)
/* @internal */ mergeId?: number; // Merge id (used to look up merged symbol)
/* @internal */ parent?: Symbol; // Parent symbol
/* @internal */ exportSymbol?: Symbol; // Exported symbol associated with this symbol
/* @internal */ constEnumOnlyModule?: boolean; // True if module contains only const enums or other modules with only const enums
/* @internal */ isReferenced?: boolean; // True if the symbol is referenced elsewhere
}
/* @internal */
@@ -2243,8 +2269,8 @@ namespace ts {
LoopWithCapturedBlockScopedBinding = 0x00010000, // Loop that contains block scoped variable captured in closure
CapturedBlockScopedBinding = 0x00020000, // Block-scoped binding that is captured in some function
BlockScopedBindingInLoop = 0x00040000, // Block-scoped binding with declaration nested inside iteration statement
DecoratedClassWithSelfReference = 0x00080000, // Decorated class that contains a binding to itself inside of the class body.
SelfReferenceInDecoratedClass = 0x00100000, // Binding to a decorated class inside of the class's body.
ClassWithConstructorReference = 0x00080000, // Class that contains a binding to its constructor inside of the class body.
ConstructorReferenceInClass = 0x00100000, // Binding to a class constructor inside of the class's body.
NeedsLoopOutParameter = 0x00200000, // Block scoped binding whose value should be explicitly copied outside of the converted loop
}
@@ -2262,6 +2288,7 @@ namespace ts {
resolvedJsxType?: Type; // resolved element attributes type of a JSX openinglike element
hasSuperCall?: boolean; // recorded result when we try to find super-call. We only try to find one if this flag is undefined, indicating that we haven't made an attempt.
superCall?: ExpressionStatement; // Cached first super-call found in the constructor. Used in checking whether super is called before this-accessing
switchTypes?: Type[]; // Cached array of switch case expression types
}
export const enum TypeFlags {
@@ -2301,7 +2328,8 @@ namespace ts {
/* @internal */
Nullable = Undefined | Null,
Falsy = String | Number | Boolean | Void | Undefined | Null,
/* @internal */
Falsy = Void | Undefined | Null, // TODO: Add false, 0, and ""
/* @internal */
Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null | Never,
/* @internal */
@@ -2453,7 +2481,8 @@ namespace ts {
declaration: SignatureDeclaration; // Originating declaration
typeParameters: TypeParameter[]; // Type parameters (undefined if non-generic)
parameters: Symbol[]; // Parameters
thisType?: Type; // type of this-type
/* @internal */
thisParameter?: Symbol; // symbol of this-type parameter
/* @internal */
resolvedReturnType: Type; // Resolved return type
/* @internal */
@@ -2588,6 +2617,7 @@ namespace ts {
declarationDir?: string;
/* @internal */ diagnostics?: boolean;
/*@internal*/ extendedDiagnostics?: boolean;
disableSizeLimit?: boolean;
emitBOM?: boolean;
emitDecoratorMetadata?: boolean;
experimentalDecorators?: boolean;
@@ -2604,6 +2634,7 @@ namespace ts {
/*@internal*/listFiles?: boolean;
locale?: string;
mapRoot?: string;
maxNodeModuleJsDepth?: number;
module?: ModuleKind;
moduleResolution?: ModuleResolutionKind;
newLine?: NewLineKind;
@@ -2615,6 +2646,8 @@ namespace ts {
noImplicitAny?: boolean;
noImplicitReturns?: boolean;
noImplicitThis?: boolean;
noUnusedLocals?: boolean;
noUnusedParameters?: boolean;
noImplicitUseStrict?: boolean;
noLib?: boolean;
noResolve?: boolean;
@@ -2643,7 +2676,6 @@ namespace ts {
types?: string[];
/** Paths used to used to compute primary types search locations */
typeRoots?: string[];
typesSearchPaths?: string[];
/*@internal*/ version?: boolean;
/*@internal*/ watch?: boolean;
@@ -2728,6 +2760,17 @@ namespace ts {
fileNames: string[];
raw?: any;
errors: Diagnostic[];
wildcardDirectories?: Map<WatchDirectoryFlags>;
}
export const enum WatchDirectoryFlags {
None = 0,
Recursive = 1 << 0,
}
export interface ExpandResult {
fileNames: string[];
wildcardDirectories: Map<WatchDirectoryFlags>;
}
/* @internal */
@@ -3063,16 +3106,17 @@ namespace ts {
ExportName = 1 << 17, // Ensure an export prefix is added for an identifier that points to an exported declaration with a local name (see SymbolFlags.ExportHasLocal).
LocalName = 1 << 18, // Ensure an export prefix is not added for an identifier that points to an exported declaration.
Indented = 1 << 19, // Adds an explicit extra indentation level for class and function bodies when printing (used to match old emitter).
AsyncFunctionBody = 1 << 20,
ReuseTempVariableScope = 1 << 21, // Reuse the existing temp variable scope during emit.
CustomPrologue = 1 << 22, // Treat the statement as if it were a prologue directive (NOTE: Prologue directives are *not* transformed).
NoIndentation = 1 << 20, // Do not indent the node.
AsyncFunctionBody = 1 << 21,
ReuseTempVariableScope = 1 << 22, // Reuse the existing temp variable scope during emit.
CustomPrologue = 1 << 23, // Treat the statement as if it were a prologue directive (NOTE: Prologue directives are *not* transformed).
// SourceMap Specialization.
// TODO(rbuckton): These should be removed once source maps are aligned with the old
// emitter and new baselines are taken. This exists solely to
// align with the old emitter.
SourceMapEmitOpenBraceAsToken = 1 << 22, // Emits the open brace of a block function body as a source mapped token.
SourceMapAdjustRestParameterLoop = 1 << 23, // Emits adjusted source map positions for a ForStatement generated when transforming a rest parameter for ES5/3.
SourceMapEmitOpenBraceAsToken = 1 << 24, // Emits the open brace of a block function body as a source mapped token.
SourceMapAdjustRestParameterLoop = 1 << 25, // Emits adjusted source map positions for a ForStatement generated when transforming a rest parameter for ES5/3.
}
/** Additional context provided to `visitEachChild` */
+23 -11
View File
@@ -31,6 +31,9 @@ namespace ts {
export interface EmitHost extends ScriptReferenceHost {
getSourceFiles(): SourceFile[];
/* @internal */
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
getCommonSourceDirectory(): string;
getCanonicalFileName(fileName: string): string;
getNewLine(): string;
@@ -1725,7 +1728,7 @@ namespace ts {
node.kind === SyntaxKind.ExportAssignment && (<ExportAssignment>node).expression.kind === SyntaxKind.Identifier;
}
export function getClassExtendsHeritageClauseElement(node: ClassLikeDeclaration) {
export function getClassExtendsHeritageClauseElement(node: ClassLikeDeclaration | InterfaceDeclaration) {
const heritageClause = getHeritageClause(node.heritageClauses, SyntaxKind.ExtendsKeyword);
return heritageClause && heritageClause.types.length > 0 ? heritageClause.types[0] : undefined;
}
@@ -2563,7 +2566,8 @@ namespace ts {
}
else {
for (const sourceFile of sourceFiles) {
if (!isDeclarationFile(sourceFile)) {
// Don't emit if source file is a declaration file, or was located under node_modules
if (!isDeclarationFile(sourceFile) && !host.isSourceFileFromExternalLibrary(sourceFile)) {
onSingleFileEmit(host, sourceFile);
}
}
@@ -2625,7 +2629,8 @@ namespace ts {
else {
const sourceFiles = targetSourceFile === undefined ? host.getSourceFiles() : [targetSourceFile];
for (const sourceFile of sourceFiles) {
if (!isDeclarationFile(sourceFile)) {
// Don't emit if source file is a declaration file, or was located under node_modules
if (!isDeclarationFile(sourceFile) && !host.isSourceFileFromExternalLibrary(sourceFile)) {
onSingleFileEmit(host, sourceFile);
}
}
@@ -2657,12 +2662,13 @@ namespace ts {
}
function onBundledEmit(host: EmitHost) {
const moduleKind = getEmitModuleKind(options);
const moduleEmitEnabled = moduleKind === ModuleKind.AMD || moduleKind === ModuleKind.System;
// Can emit only sources that are not declaration file and are either non module code or module with --module or --target es6 specified
const bundledSources = filter(host.getSourceFiles(), sourceFile =>
!isDeclarationFile(sourceFile) // Not a declaration file
&& (!isExternalModule(sourceFile) || moduleEmitEnabled)); // and not a module, unless module emit enabled
// Can emit only sources that are not declaration file and are either non module code or module with
// --module or --target es6 specified. Files included by searching under node_modules are also not emitted.
const bundledSources = filter(host.getSourceFiles(),
sourceFile => !isDeclarationFile(sourceFile) &&
!host.isSourceFileFromExternalLibrary(sourceFile) &&
(!isExternalModule(sourceFile) ||
!!getEmitModuleKind(options)));
if (bundledSources.length) {
const jsFilePath = options.outFile || options.out;
@@ -2678,7 +2684,9 @@ namespace ts {
export function getSourceFilePathInNewDir(sourceFile: SourceFile, host: EmitHost, newDirPath: string) {
let sourceFilePath = getNormalizedAbsolutePath(sourceFile.fileName, host.getCurrentDirectory());
sourceFilePath = sourceFilePath.replace(host.getCommonSourceDirectory(), "");
const commonSourceDirectory = host.getCommonSourceDirectory();
const isSourceFileInCommonSourceDirectory = host.getCanonicalFileName(sourceFilePath).indexOf(host.getCanonicalFileName(commonSourceDirectory)) === 0;
sourceFilePath = isSourceFileInCommonSourceDirectory ? sourceFilePath.substring(commonSourceDirectory.length) : sourceFilePath;
return combinePaths(newDirPath, sourceFilePath);
}
@@ -2971,7 +2979,7 @@ namespace ts {
function calculateIndent(text: string, pos: number, end: number) {
let currentLineIndent = 0;
for (; pos < end && isWhiteSpace(text.charCodeAt(pos)); pos++) {
for (; pos < end && isWhiteSpaceSingleLine(text.charCodeAt(pos)); pos++) {
if (text.charCodeAt(pos) === CharacterCodes.tab) {
// Tabs = TabSize = indent size and go to next tabStop
currentLineIndent += getIndentSize() - (currentLineIndent % getIndentSize());
@@ -3100,6 +3108,10 @@ namespace ts {
return forEach(supportedJavascriptExtensions, extension => fileExtensionIs(fileName, extension));
}
export function hasTypeScriptFileExtension(fileName: string) {
return forEach(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension));
}
/**
* Replace each instance of non-ascii characters by one, two, three, or four escape sequences
* representing the UTF-8 encoding of the character, and return the expanded char code list.
+5
View File
@@ -167,8 +167,13 @@ declare module chai {
module assert {
function equal(actual: any, expected: any, message?: string): void;
function notEqual(actual: any, expected: any, message?: string): void;
function deepEqual<T>(actual: T, expected: T, message?: string): void;
function notDeepEqual<T>(actual: T, expected: T, message?: string): void;
function lengthOf(object: any[], length: number, message?: string): void;
function isTrue(value: any, message?: string): void;
function isFalse(value: any, message?: string): void;
function isOk(actual: any, message?: string): void;
function isUndefined(value: any, message?: string): void;
function isDefined(value: any, message?: string): void;
}
}
+142 -60
View File
@@ -310,6 +310,7 @@ namespace FourSlash {
}
this.formatCodeOptions = {
BaseIndentSize: 0,
IndentSize: 4,
TabSize: 4,
NewLineCharacter: Harness.IO.newLine(),
@@ -323,6 +324,7 @@ namespace FourSlash {
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
InsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
PlaceOpenBraceOnNewLineForFunctions: false,
PlaceOpenBraceOnNewLineForControlBlocks: false,
};
@@ -730,30 +732,6 @@ namespace FourSlash {
}
}
public verifyReferencesAtPositionListContains(fileName: string, start: number, end: number, isWriteAccess?: boolean, isDefinition?: boolean) {
const references = this.getReferencesAtCaret();
if (!references || references.length === 0) {
this.raiseError("verifyReferencesAtPositionListContains failed - found 0 references, expected at least one.");
}
for (let i = 0; i < references.length; i++) {
const reference = references[i];
if (reference && reference.fileName === fileName && reference.textSpan.start === start && ts.textSpanEnd(reference.textSpan) === end) {
if (typeof isWriteAccess !== "undefined" && reference.isWriteAccess !== isWriteAccess) {
this.raiseError(`verifyReferencesAtPositionListContains failed - item isWriteAccess value does not match, actual: ${reference.isWriteAccess}, expected: ${isWriteAccess}.`);
}
if (typeof isDefinition !== "undefined" && reference.isDefinition !== isDefinition) {
this.raiseError(`verifyReferencesAtPositionListContains failed - item isDefinition value does not match, actual: ${reference.isDefinition}, expected: ${isDefinition}.`);
}
return;
}
}
const missingItem = { fileName, start, end, isWriteAccess, isDefinition };
this.raiseError(`verifyReferencesAtPositionListContains failed - could not find the item: ${stringify(missingItem)} in the returned list: (${stringify(references)})`);
}
public verifyReferencesCountIs(count: number, localFilesOnly = true) {
const references = this.getReferencesAtCaret();
let referencesCount = 0;
@@ -777,6 +755,68 @@ namespace FourSlash {
}
}
public verifyReferencesAre(expectedReferences: Range[]) {
const actualReferences = this.getReferencesAtCaret() || [];
if (actualReferences.length > expectedReferences.length) {
// Find the unaccounted-for reference.
for (const actual of actualReferences) {
if (!ts.forEach(expectedReferences, r => r.start === actual.textSpan.start)) {
this.raiseError(`A reference ${stringify(actual)} is unaccounted for.`);
}
}
// Probably will never reach here.
this.raiseError(`There are ${actualReferences.length} references but only ${expectedReferences.length} were expected.`);
}
for (const reference of expectedReferences) {
const {fileName, start, end} = reference;
if (reference.marker && reference.marker.data) {
const {isWriteAccess, isDefinition} = reference.marker.data;
this.verifyReferencesWorker(actualReferences, fileName, start, end, isWriteAccess, isDefinition);
}
else {
this.verifyReferencesWorker(actualReferences, fileName, start, end);
}
}
}
public verifyReferencesOf({fileName, start}: Range, references: Range[]) {
this.openFile(fileName);
this.goToPosition(start);
this.verifyReferencesAre(references);
}
public verifyRangesReferenceEachOther(ranges?: Range[]) {
ranges = ranges || this.getRanges();
assert(ranges.length);
for (const range of ranges) {
this.verifyReferencesOf(range, ranges);
}
}
public verifyRangesWithSameTextReferenceEachOther() {
ts.forEachValue(this.rangesByText(), ranges => this.verifyRangesReferenceEachOther(ranges));
}
private verifyReferencesWorker(references: ts.ReferenceEntry[], fileName: string, start: number, end: number, isWriteAccess?: boolean, isDefinition?: boolean) {
for (let i = 0; i < references.length; i++) {
const reference = references[i];
if (reference && reference.fileName === fileName && reference.textSpan.start === start && ts.textSpanEnd(reference.textSpan) === end) {
if (typeof isWriteAccess !== "undefined" && reference.isWriteAccess !== isWriteAccess) {
this.raiseError(`verifyReferencesAtPositionListContains failed - item isWriteAccess value does not match, actual: ${reference.isWriteAccess}, expected: ${isWriteAccess}.`);
}
if (typeof isDefinition !== "undefined" && reference.isDefinition !== isDefinition) {
this.raiseError(`verifyReferencesAtPositionListContains failed - item isDefinition value does not match, actual: ${reference.isDefinition}, expected: ${isDefinition}.`);
}
return;
}
}
const missingItem = { fileName, start, end, isWriteAccess, isDefinition };
this.raiseError(`verifyReferencesAtPositionListContains failed - could not find the item: ${stringify(missingItem)} in the returned list: (${stringify(references)})`);
}
private getMemberListAtCaret() {
return this.languageService.getCompletionsAtPosition(this.activeFile.fileName, this.currentCaretPosition);
}
@@ -864,13 +904,13 @@ namespace FourSlash {
assert.equal(getDisplayPartsJson(actualQuickInfo.documentation), getDisplayPartsJson(documentation), this.messageAtLastKnownMarker("QuickInfo documentation"));
}
public verifyRenameLocations(findInStrings: boolean, findInComments: boolean) {
public verifyRenameLocations(findInStrings: boolean, findInComments: boolean, ranges?: Range[]) {
const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition);
if (renameInfo.canRename) {
let references = this.languageService.findRenameLocations(
this.activeFile.fileName, this.currentCaretPosition, findInStrings, findInComments);
let ranges = this.getRanges();
ranges = ranges || this.getRanges();
if (!references) {
if (ranges.length !== 0) {
@@ -1498,19 +1538,32 @@ namespace FourSlash {
}
private updateMarkersForEdit(fileName: string, minChar: number, limChar: number, text: string) {
for (let i = 0; i < this.testData.markers.length; i++) {
const marker = this.testData.markers[i];
for (const marker of this.testData.markers) {
if (marker.fileName === fileName) {
if (marker.position > minChar) {
if (marker.position < limChar) {
// Marker is inside the edit - mark it as invalidated (?)
marker.position = -1;
}
else {
// Move marker back/forward by the appropriate amount
marker.position += (minChar - limChar) + text.length;
}
marker.position = updatePosition(marker.position);
}
}
for (const range of this.testData.ranges) {
if (range.fileName === fileName) {
range.start = updatePosition(range.start);
range.end = updatePosition(range.end);
}
}
function updatePosition(position: number) {
if (position > minChar) {
if (position < limChar) {
// Inside the edit - mark it as invalidated (?)
return -1;
}
else {
// Move marker back/forward by the appropriate amount
return position + (minChar - limChar) + text.length;
}
}
else {
return position;
}
}
}
@@ -1605,8 +1658,20 @@ namespace FourSlash {
}
public getRanges(): Range[] {
// Return a copy of the list
return this.testData.ranges.slice(0);
return this.testData.ranges;
}
public rangesByText(): ts.Map<Range[]> {
const result: ts.Map<Range[]> = {};
for (const range of this.getRanges()) {
const text = this.rangeText(range);
(ts.getProperty(result, text) || (result[text] = [])).push(range);
}
return result;
}
private rangeText({fileName, start, end}: Range, more = false): string {
return this.getFileContent(fileName).slice(start, end);
}
public verifyCaretAtMarker(markerName = "") {
@@ -1619,24 +1684,25 @@ namespace FourSlash {
}
}
private getIndentation(fileName: string, position: number, indentStyle: ts.IndentStyle): number {
private getIndentation(fileName: string, position: number, indentStyle: ts.IndentStyle, baseIndentSize: number): number {
const formatOptions = ts.clone(this.formatCodeOptions);
formatOptions.IndentStyle = indentStyle;
formatOptions.BaseIndentSize = baseIndentSize;
return this.languageService.getIndentationAtPosition(fileName, position, formatOptions);
}
public verifyIndentationAtCurrentPosition(numberOfSpaces: number, indentStyle: ts.IndentStyle = ts.IndentStyle.Smart) {
const actual = this.getIndentation(this.activeFile.fileName, this.currentCaretPosition, indentStyle);
public verifyIndentationAtCurrentPosition(numberOfSpaces: number, indentStyle: ts.IndentStyle = ts.IndentStyle.Smart, baseIndentSize = 0) {
const actual = this.getIndentation(this.activeFile.fileName, this.currentCaretPosition, indentStyle, baseIndentSize);
const lineCol = this.getLineColStringAtPosition(this.currentCaretPosition);
if (actual !== numberOfSpaces) {
this.raiseError(`verifyIndentationAtCurrentPosition failed at ${lineCol} - expected: ${numberOfSpaces}, actual: ${actual}`);
}
}
public verifyIndentationAtPosition(fileName: string, position: number, numberOfSpaces: number, indentStyle: ts.IndentStyle = ts.IndentStyle.Smart) {
const actual = this.getIndentation(fileName, position, indentStyle);
public verifyIndentationAtPosition(fileName: string, position: number, numberOfSpaces: number, indentStyle: ts.IndentStyle = ts.IndentStyle.Smart, baseIndentSize = 0) {
const actual = this.getIndentation(fileName, position, indentStyle, baseIndentSize);
const lineCol = this.getLineColStringAtPosition(position);
if (actual !== numberOfSpaces) {
this.raiseError(`verifyIndentationAtPosition failed at ${lineCol} - expected: ${numberOfSpaces}, actual: ${actual}`);
@@ -1852,7 +1918,7 @@ namespace FourSlash {
});
}
public verifyBraceCompletionAtPostion(negative: boolean, openingBrace: string) {
public verifyBraceCompletionAtPosition(negative: boolean, openingBrace: string) {
const openBraceMap: ts.Map<ts.CharacterCodes> = {
"(": ts.CharacterCodes.openParen,
@@ -1872,7 +1938,7 @@ namespace FourSlash {
const position = this.currentCaretPosition;
const validBraceCompletion = this.languageService.isValidBraceCompletionAtPostion(this.activeFile.fileName, position, charCode);
const validBraceCompletion = this.languageService.isValidBraceCompletionAtPosition(this.activeFile.fileName, position, charCode);
if (!negative && !validBraceCompletion) {
this.raiseError(`${position} is not a valid brace completion position for ${openingBrace}`);
@@ -2729,6 +2795,10 @@ namespace FourSlashInterface {
return this.state.getRanges();
}
public rangesByText(): ts.Map<FourSlash.Range[]> {
return this.state.rangesByText();
}
public markerByName(s: string): FourSlash.Marker {
return this.state.getMarkerByName(s);
}
@@ -2836,14 +2906,6 @@ namespace FourSlashInterface {
this.state.verifyMemberListIsEmpty(this.negative);
}
public referencesCountIs(count: number) {
this.state.verifyReferencesCountIs(count, /*localFilesOnly*/ false);
}
public referencesAtPositionContains(range: FourSlash.Range, isWriteAccess?: boolean, isDefinition?: boolean) {
this.state.verifyReferencesAtPositionListContains(range.fileName, range.start, range.end, isWriteAccess, isDefinition);
}
public signatureHelpPresent() {
this.state.verifySignatureHelpPresent(!this.negative);
}
@@ -2884,8 +2946,8 @@ namespace FourSlashInterface {
this.state.verifyDefinitionsName(this.negative, name, containerName);
}
public isValidBraceCompletionAtPostion(openingBrace: string) {
this.state.verifyBraceCompletionAtPostion(this.negative, openingBrace);
public isValidBraceCompletionAtPosition(openingBrace: string) {
this.state.verifyBraceCompletionAtPosition(this.negative, openingBrace);
}
}
@@ -2902,8 +2964,8 @@ namespace FourSlashInterface {
this.state.verifyIndentationAtCurrentPosition(numberOfSpaces);
}
public indentationAtPositionIs(fileName: string, position: number, numberOfSpaces: number, indentStyle = ts.IndentStyle.Smart) {
this.state.verifyIndentationAtPosition(fileName, position, numberOfSpaces, indentStyle);
public indentationAtPositionIs(fileName: string, position: number, numberOfSpaces: number, indentStyle = ts.IndentStyle.Smart, baseIndentSize = 0) {
this.state.verifyIndentationAtPosition(fileName, position, numberOfSpaces, indentStyle, baseIndentSize);
}
public textAtCaretIs(text: string) {
@@ -2935,6 +2997,26 @@ namespace FourSlashInterface {
this.state.verifyGetEmitOutputContentsForCurrentFile(expected);
}
public referencesCountIs(count: number) {
this.state.verifyReferencesCountIs(count, /*localFilesOnly*/ false);
}
public referencesAre(ranges: FourSlash.Range[]) {
this.state.verifyReferencesAre(ranges);
}
public referencesOf(start: FourSlash.Range, references: FourSlash.Range[]) {
this.state.verifyReferencesOf(start, references);
}
public rangesReferenceEachOther(ranges?: FourSlash.Range[]) {
this.state.verifyRangesReferenceEachOther(ranges);
}
public rangesWithSameTextReferenceEachOther() {
this.state.verifyRangesWithSameTextReferenceEachOther();
}
public currentParameterHelpArgumentNameIs(name: string) {
this.state.verifyCurrentParameterHelpName(name);
}
@@ -3077,8 +3159,8 @@ namespace FourSlashInterface {
this.state.verifyRenameInfoFailed(message);
}
public renameLocations(findInStrings: boolean, findInComments: boolean) {
this.state.verifyRenameLocations(findInStrings, findInComments);
public renameLocations(findInStrings: boolean, findInComments: boolean, ranges?: FourSlash.Range[]) {
this.state.verifyRenameLocations(findInStrings, findInComments, ranges);
}
public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: { start: number; length: number; },
+24 -8
View File
@@ -23,6 +23,7 @@
/// <reference path="external\chai.d.ts"/>
/// <reference path="sourceMapRecorder.ts"/>
/// <reference path="runnerbase.ts"/>
/// <reference path="virtualFileSystem.ts" />
// Block scoped definitions work poorly for global variables, temporarily enable var
/* tslint:disable:no-var-keyword */
@@ -497,7 +498,7 @@ namespace Harness {
args(): string[];
getExecutingFilePath(): string;
exit(exitCode?: number): void;
readDirectory(path: string, extension?: string, exclude?: string[]): string[];
readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[]): string[];
tryEnableSourceMapsForHost?(): void;
getEnvironmentVariable?(name: string): string;
}
@@ -538,8 +539,8 @@ namespace Harness {
export const directoryExists: typeof IO.directoryExists = fso.FolderExists;
export const fileExists: typeof IO.fileExists = fso.FileExists;
export const log: typeof IO.log = global.WScript && global.WScript.StdOut.WriteLine;
export const readDirectory: typeof IO.readDirectory = (path, extension, exclude) => ts.sys.readDirectory(path, extension, exclude);
export const getEnvironmentVariable: typeof IO.getEnvironmentVariable = name => ts.sys.getEnvironmentVariable(name);
export const readDirectory: typeof IO.readDirectory = (path, extension, exclude, include) => ts.sys.readDirectory(path, extension, exclude, include);
export function createDirectory(path: string) {
if (directoryExists(path)) {
@@ -608,8 +609,6 @@ namespace Harness {
export const writeFile: typeof IO.writeFile = (path, content) => ts.sys.writeFile(path, content);
export const fileExists: typeof IO.fileExists = fs.existsSync;
export const log: typeof IO.log = s => console.log(s);
export const readDirectory: typeof IO.readDirectory = (path, extension, exclude) => ts.sys.readDirectory(path, extension, exclude);
export const getEnvironmentVariable: typeof IO.getEnvironmentVariable = name => ts.sys.getEnvironmentVariable(name);
export function tryEnableSourceMapsForHost() {
@@ -617,6 +616,7 @@ namespace Harness {
ts.sys.tryEnableSourceMapsForHost();
}
}
export const readDirectory: typeof IO.readDirectory = (path, extension, exclude, include) => ts.sys.readDirectory(path, extension, exclude, include);
export function createDirectory(path: string) {
if (!directoryExists(path)) {
@@ -813,8 +813,22 @@ namespace Harness {
Http.writeToServerSync(serverRoot + path, "WRITE", contents);
}
export function readDirectory(path: string, extension?: string, exclude?: string[]) {
return listFiles(path).filter(f => !extension || ts.fileExtensionIs(f, extension));
export function readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[]) {
const fs = new Utils.VirtualFileSystem(path, useCaseSensitiveFileNames());
for (const file in listFiles(path)) {
fs.addFile(file);
}
return ts.matchFiles(path, extension, exclude, include, useCaseSensitiveFileNames(), getCurrentDirectory(), path => {
const entry = fs.traversePath(path);
if (entry && entry.isDirectory()) {
const directory = <Utils.VirtualDirectory>entry;
return {
files: ts.map(directory.getFiles(), f => f.name),
directories: ts.map(directory.getDirectories(), d => d.name)
};
}
return { files: [], directories: [] };
});
}
}
}
@@ -1126,7 +1140,7 @@ namespace Harness {
options.target = options.target || ts.ScriptTarget.ES3;
options.newLine = options.newLine || ts.NewLineKind.CarriageReturnLineFeed;
options.noErrorTruncation = true;
options.skipDefaultLibCheck = true;
options.skipDefaultLibCheck = typeof options.skipDefaultLibCheck === "undefined" ? true : options.skipDefaultLibCheck;
if (typeof currentDirectory === "undefined") {
currentDirectory = Harness.IO.getCurrentDirectory();
@@ -1606,7 +1620,9 @@ namespace Harness {
// unit tests always list files explicitly
const parseConfigHost: ts.ParseConfigHost = {
readDirectory: (name) => []
useCaseSensitiveFileNames: false,
readDirectory: (name) => [],
fileExists: (name) => true
};
// check if project has tsconfig.json in the list of files
+10 -4
View File
@@ -274,7 +274,7 @@ namespace Harness.LanguageService {
getCompilationSettings(): string { return JSON.stringify(this.nativeHost.getCompilationSettings()); }
getCancellationToken(): ts.HostCancellationToken { return this.nativeHost.getCancellationToken(); }
getCurrentDirectory(): string { return this.nativeHost.getCurrentDirectory(); }
getDirectories(path: string) { return this.nativeHost.getDirectories(path); }
getDirectories(path: string): string { return JSON.stringify(this.nativeHost.getDirectories(path)); }
getDefaultLibFileName(): string { return this.nativeHost.getDefaultLibFileName(); }
getScriptFileNames(): string { return JSON.stringify(this.nativeHost.getScriptFileNames()); }
getScriptSnapshot(fileName: string): ts.ScriptSnapshotShim {
@@ -288,6 +288,12 @@ namespace Harness.LanguageService {
readDirectory(rootDir: string, extension: string): string {
throw new Error("NYI");
}
readDirectoryNames(path: string): string {
throw new Error("Not implemented.");
}
readFileNames(path: string): string {
throw new Error("Not implemented.");
}
fileExists(fileName: string) { return this.getScriptInfo(fileName) !== undefined; }
readFile(fileName: string) {
const snapshot = this.nativeHost.getScriptSnapshot(fileName);
@@ -444,8 +450,8 @@ namespace Harness.LanguageService {
getDocCommentTemplateAtPosition(fileName: string, position: number): ts.TextInsertion {
return unwrapJSONCallResult(this.shim.getDocCommentTemplateAtPosition(fileName, position));
}
isValidBraceCompletionAtPostion(fileName: string, position: number, openingBrace: number): boolean {
return unwrapJSONCallResult(this.shim.isValidBraceCompletionAtPostion(fileName, position, openingBrace));
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean {
return unwrapJSONCallResult(this.shim.isValidBraceCompletionAtPosition(fileName, position, openingBrace));
}
getEmitOutput(fileName: string): ts.EmitOutput {
return unwrapJSONCallResult(this.shim.getEmitOutput(fileName));
@@ -615,7 +621,7 @@ namespace Harness.LanguageService {
return ts.sys.getEnvironmentVariable(name);
}
readDirectory(path: string, extension?: string): string[] {
readDirectory(path: string, extension?: string[], exclude?: string[], include?: string[]): string[] {
throw new Error("Not implemented Yet.");
}
+35 -33
View File
@@ -8,7 +8,12 @@ interface FileInformation {
}
interface FindFileResult {
}
interface IOLogFile {
path: string;
codepage: number;
result?: FileInformation;
}
interface IOLog {
@@ -17,11 +22,7 @@ interface IOLog {
executingPath: string;
currentDirectory: string;
useCustomLibraryFile?: boolean;
filesRead: {
path: string;
codepage: number;
result?: FileInformation;
}[];
filesRead: IOLogFile[];
filesWritten: {
path: string;
contents: string;
@@ -61,8 +62,9 @@ interface IOLog {
}[];
directoriesRead: {
path: string,
extension: string,
extensions: string[],
exclude: string[],
include: string[],
result: string[]
}[];
}
@@ -169,8 +171,7 @@ namespace Playback {
path => callAndRecord(underlying.fileExists(path), recordLog.fileExists, { path }),
memoize(path => {
// If we read from the file, it must exist
const noResult = {};
if (findResultByPath(wrapper, replayLog.filesRead, path, noResult) !== noResult) {
if (findFileByPath(wrapper, replayLog.filesRead, path, /*throwFileNotFoundError*/ false)) {
return true;
}
else {
@@ -214,21 +215,30 @@ namespace Playback {
recordLog.filesRead.push(logEntry);
return result;
},
memoize(path => findResultByPath(wrapper, replayLog.filesRead, path).contents));
memoize(path => findFileByPath(wrapper, replayLog.filesRead, path, /*throwFileNotFoundError*/ true).contents));
wrapper.readDirectory = recordReplay(wrapper.readDirectory, underlying)(
(path, extension, exclude) => {
const result = (<ts.System>underlying).readDirectory(path, extension, exclude);
const logEntry = { path, extension, exclude, result };
(path, extensions, exclude, include) => {
const result = (<ts.System>underlying).readDirectory(path, extensions, exclude, include);
const logEntry = { path, extensions, exclude, include, result };
recordLog.directoriesRead.push(logEntry);
return result;
},
(path, extension, exclude) => findResultByPath(wrapper,
replayLog.directoriesRead.filter(
d => {
return d.extension === extension;
}
), path));
(path, extensions, exclude) => {
// Because extensions is an array of all allowed extension, we will want to merge each of the replayLog.directoriesRead into one
// if each of the directoriesRead has matched path with the given path (directory with same path but different extension will considered
// different entry).
// TODO (yuisu): We can certainly remove these once we recapture the RWC using new API
const normalizedPath = ts.normalizePath(path).toLowerCase();
const result: string[] = [];
for (const directory of replayLog.directoriesRead) {
if (ts.normalizeSlashes(directory.path).toLowerCase() === normalizedPath) {
result.push(...directory.result);
}
}
return result;
});
wrapper.writeFile = recordReplay(wrapper.writeFile, underlying)(
(path: string, contents: string) => callAndRecord(underlying.writeFile(path, contents), recordLog.filesWritten, { path, contents, bom: false }),
@@ -283,30 +293,22 @@ namespace Playback {
return results[0].result;
}
function findResultByPath<T>(wrapper: { resolvePath(s: string): string }, logArray: { path: string; result?: T }[], expectedPath: string, defaultValue?: T): T {
function findFileByPath(wrapper: { resolvePath(s: string): string }, logArray: IOLogFile[],
expectedPath: string, throwFileNotFoundError: boolean): FileInformation {
const normalizedName = ts.normalizePath(expectedPath).toLowerCase();
// Try to find the result through normal fileName
for (let i = 0; i < logArray.length; i++) {
if (ts.normalizeSlashes(logArray[i].path).toLowerCase() === normalizedName) {
return logArray[i].result;
}
}
// Fallback, try to resolve the target paths as well
if (replayLog.pathsResolved.length > 0) {
const normalizedResolvedName = wrapper.resolvePath(expectedPath).toLowerCase();
for (let i = 0; i < logArray.length; i++) {
if (wrapper.resolvePath(logArray[i].path).toLowerCase() === normalizedResolvedName) {
return logArray[i].result;
}
for (const log of logArray) {
if (ts.normalizeSlashes(log.path).toLowerCase() === normalizedName) {
return log.result;
}
}
// If we got here, we didn't find a match
if (defaultValue === undefined) {
if (throwFileNotFoundError) {
throw new Error("No matching result in log array for path: " + expectedPath);
}
else {
return defaultValue;
return undefined;
}
}
+15 -8
View File
@@ -218,7 +218,12 @@ class ProjectRunner extends RunnerBase {
}
const configObject = result.config;
const configParseResult = ts.parseJsonConfigFileContent(configObject, { readDirectory }, ts.getDirectoryPath(configFileName), compilerOptions);
const configParseHost: ts.ParseConfigHost = {
useCaseSensitiveFileNames: Harness.IO.useCaseSensitiveFileNames(),
fileExists,
readDirectory,
};
const configParseResult = ts.parseJsonConfigFileContent(configObject, configParseHost, ts.getDirectoryPath(configFileName), compilerOptions);
if (configParseResult.errors.length > 0) {
return {
moduleKind,
@@ -276,8 +281,8 @@ class ProjectRunner extends RunnerBase {
: ts.normalizeSlashes(testCase.projectRoot) + "/" + ts.normalizeSlashes(fileName);
}
function readDirectory(rootDir: string, extension: string, exclude: string[]): string[] {
const harnessReadDirectoryResult = Harness.IO.readDirectory(getFileNameInTheProjectTest(rootDir), extension, exclude);
function readDirectory(rootDir: string, extension: string[], exclude: string[], include: string[]): string[] {
const harnessReadDirectoryResult = Harness.IO.readDirectory(getFileNameInTheProjectTest(rootDir), extension, exclude, include);
const result: string[] = [];
for (let i = 0; i < harnessReadDirectoryResult.length; i++) {
result[i] = ts.getRelativePathToDirectoryOrUrl(testCase.projectRoot, harnessReadDirectoryResult[i],
@@ -473,8 +478,10 @@ class ProjectRunner extends RunnerBase {
it("Baseline of emitted result (" + moduleNameToString(moduleKind) + "): " + testCaseFileName, () => {
if (testCase.baselineCheck) {
let lastError: any = undefined;
const errs: Error[] = [];
ts.forEach(compilerResult.outputFiles, outputFile => {
// There may be multiple files with different baselines. Run all and report at the end, else
// it stops copying the remaining emitted files from 'local/projectOutput' to 'local/project'.
try {
Harness.Baseline.runBaseline("Baseline of emitted result (" + moduleNameToString(compilerResult.moduleKind) + "): " + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + outputFile.fileName, () => {
try {
@@ -486,16 +493,16 @@ class ProjectRunner extends RunnerBase {
});
}
catch (e) {
lastError = e;
errs.push(e);
}
});
if (lastError) {
throw lastError;
if (errs.length) {
throw Error(errs.join("\n "));
}
}
});
// it("SourceMapRecord for (" + moduleNameToString(moduleKind) + "): " + testCaseFileName, () => {
// if (compilerResult.sourceMapData) {
// Harness.Baseline.runBaseline("SourceMapRecord for (" + moduleNameToString(compilerResult.moduleKind) + "): " + testCaseFileName, getBaselineFolder(compilerResult.moduleKind) + testCaseJustName + ".sourcemap.txt", () => {
+3 -3
View File
@@ -201,7 +201,7 @@ if (taskConfigsFolder) {
for (let i = 0; i < workerCount; i++) {
const startPos = i * chunkSize;
const len = Math.min(chunkSize, files.length - startPos);
if (len !== 0) {
if (len > 0) {
workerConfigs[i].tasks.push({
runner: runner.kind(),
files: files.slice(startPos, startPos + len)
@@ -222,5 +222,5 @@ else {
}
if (!runUnitTests) {
// patch `describe` to skip unit tests
describe = <any>describe.skip;
}
describe = <any>(function () { });
}
+3 -9
View File
@@ -31,18 +31,12 @@ abstract class RunnerBase {
/** Replaces instances of full paths with fileNames only */
static removeFullPaths(path: string) {
let fixedPath = path;
// full paths either start with a drive letter or / for *nix, shouldn't have \ in the path at this point
const fullPath = /(\w+:|\/)?([\w+\-\.]|\/)*\.tsx?/g;
const fullPathList = fixedPath.match(fullPath);
if (fullPathList) {
fullPathList.forEach((match: string) => fixedPath = fixedPath.replace(match, Harness.Path.getFileName(match)));
}
// If its a full path (starts with "C:" or "/") replace with just the filename
let fixedPath = /^(\w:|\/)/.test(path) ? Harness.Path.getFileName(path) : path;
// when running in the browser the 'full path' is the host name, shows up in error baselines
const localHost = /http:\/localhost:\d+/g;
fixedPath = fixedPath.replace(localHost, "");
return fixedPath;
}
}
}
+6 -1
View File
@@ -75,7 +75,12 @@ namespace RWC {
if (tsconfigFile) {
const tsconfigFileContents = getHarnessCompilerInputUnit(tsconfigFile.path);
const parsedTsconfigFileContents = ts.parseConfigFileTextToJson(tsconfigFile.path, tsconfigFileContents.content);
const configParseResult = ts.parseJsonConfigFileContent(parsedTsconfigFileContents.config, Harness.IO, ts.getDirectoryPath(tsconfigFile.path));
const configParseHost: ts.ParseConfigHost = {
useCaseSensitiveFileNames: Harness.IO.useCaseSensitiveFileNames(),
fileExists: Harness.IO.fileExists,
readDirectory: Harness.IO.readDirectory,
};
const configParseResult = ts.parseJsonConfigFileContent(parsedTsconfigFileContents.config, configParseHost, ts.getDirectoryPath(tsconfigFile.path));
fileNames = configParseResult.fileNames;
opts.options = ts.extend(opts.options, configParseResult.options);
}
+186
View File
@@ -0,0 +1,186 @@
/// <reference path="harness.ts" />
/// <reference path="..\compiler\commandLineParser.ts"/>
namespace Utils {
export class VirtualFileSystemEntry {
fileSystem: VirtualFileSystem;
name: string;
constructor(fileSystem: VirtualFileSystem, name: string) {
this.fileSystem = fileSystem;
this.name = name;
}
isDirectory() { return false; }
isFile() { return false; }
isFileSystem() { return false; }
}
export class VirtualFile extends VirtualFileSystemEntry {
content: string;
isFile() { return true; }
}
export abstract class VirtualFileSystemContainer extends VirtualFileSystemEntry {
abstract getFileSystemEntries(): VirtualFileSystemEntry[];
getFileSystemEntry(name: string): VirtualFileSystemEntry {
for (const entry of this.getFileSystemEntries()) {
if (this.fileSystem.sameName(entry.name, name)) {
return entry;
}
}
return undefined;
}
getDirectories(): VirtualDirectory[] {
return <VirtualDirectory[]>ts.filter(this.getFileSystemEntries(), entry => entry.isDirectory());
}
getFiles(): VirtualFile[] {
return <VirtualFile[]>ts.filter(this.getFileSystemEntries(), entry => entry.isFile());
}
getDirectory(name: string): VirtualDirectory {
const entry = this.getFileSystemEntry(name);
return entry.isDirectory() ? <VirtualDirectory>entry : undefined;
}
getFile(name: string): VirtualFile {
const entry = this.getFileSystemEntry(name);
return entry.isFile() ? <VirtualFile>entry : undefined;
}
}
export class VirtualDirectory extends VirtualFileSystemContainer {
private entries: VirtualFileSystemEntry[] = [];
isDirectory() { return true; }
getFileSystemEntries() { return this.entries.slice(); }
addDirectory(name: string): VirtualDirectory {
const entry = this.getFileSystemEntry(name);
if (entry === undefined) {
const directory = new VirtualDirectory(this.fileSystem, name);
this.entries.push(directory);
return directory;
}
else if (entry.isDirectory()) {
return <VirtualDirectory>entry;
}
else {
return undefined;
}
}
addFile(name: string, content?: string): VirtualFile {
const entry = this.getFileSystemEntry(name);
if (entry === undefined) {
const file = new VirtualFile(this.fileSystem, name);
file.content = content;
this.entries.push(file);
return file;
}
else if (entry.isFile()) {
const file = <VirtualFile>entry;
file.content = content;
return file;
}
else {
return undefined;
}
}
}
export class VirtualFileSystem extends VirtualFileSystemContainer {
private root: VirtualDirectory;
currentDirectory: string;
useCaseSensitiveFileNames: boolean;
constructor(currentDirectory: string, useCaseSensitiveFileNames: boolean) {
super(undefined, "");
this.fileSystem = this;
this.root = new VirtualDirectory(this, "");
this.currentDirectory = currentDirectory;
this.useCaseSensitiveFileNames = useCaseSensitiveFileNames;
}
isFileSystem() { return true; }
getFileSystemEntries() { return this.root.getFileSystemEntries(); }
addDirectory(path: string) {
const components = ts.getNormalizedPathComponents(path, this.currentDirectory);
let directory: VirtualDirectory = this.root;
for (const component of components) {
directory = directory.addDirectory(component);
if (directory === undefined) {
break;
}
}
return directory;
}
addFile(path: string, content?: string) {
const absolutePath = ts.getNormalizedAbsolutePath(path, this.currentDirectory);
const fileName = ts.getBaseFileName(path);
const directoryPath = ts.getDirectoryPath(absolutePath);
const directory = this.addDirectory(directoryPath);
return directory ? directory.addFile(fileName, content) : undefined;
}
fileExists(path: string) {
const entry = this.traversePath(path);
return entry !== undefined && entry.isFile();
}
sameName(a: string, b: string) {
return this.useCaseSensitiveFileNames ? a === b : a.toLowerCase() === b.toLowerCase();
}
traversePath(path: string) {
let directory: VirtualDirectory = this.root;
for (const component of ts.getNormalizedPathComponents(path, this.currentDirectory)) {
const entry = directory.getFileSystemEntry(component);
if (entry === undefined) {
return undefined;
}
else if (entry.isDirectory()) {
directory = <VirtualDirectory>entry;
}
else {
return entry;
}
}
return directory;
}
}
export class MockParseConfigHost extends VirtualFileSystem implements ts.ParseConfigHost {
constructor(currentDirectory: string, ignoreCase: boolean, files: string[]) {
super(currentDirectory, ignoreCase);
for (const file of files) {
this.addFile(file);
}
}
readDirectory(path: string, extensions: string[], excludes: string[], includes: string[]) {
return ts.matchFiles(path, extensions, excludes, includes, this.useCaseSensitiveFileNames, this.currentDirectory, (path: string) => this.getAccessibleFileSystemEntries(path));
}
getAccessibleFileSystemEntries(path: string) {
const entry = this.traversePath(path);
if (entry && entry.isDirectory()) {
const directory = <VirtualDirectory>entry;
return {
files: ts.map(directory.getFiles(), f => f.name),
directories: ts.map(directory.getDirectories(), d => d.name)
};
}
return { files: [], directories: [] };
}
}
}
+2477 -1937
View File
File diff suppressed because it is too large Load Diff
+105 -15
View File
@@ -3,59 +3,149 @@
*/
interface Promise<T> {
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled?: (value: T) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => TResult | PromiseLike<TResult>): Promise<TResult>;
then<TResult>(onfulfilled?: (value: T) => TResult | PromiseLike<TResult>, onrejected?: (reason: any) => void): Promise<TResult>;
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult1, TResult2>(onfulfilled: (value: T) => TResult1 | PromiseLike<TResult1>, onrejected: (reason: any) => TResult2 | PromiseLike<TResult2>): Promise<TResult1 | TResult2>;
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled: (value: T) => TResult | PromiseLike<TResult>, onrejected: (reason: any) => TResult | PromiseLike<TResult>): Promise<TResult>;
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
* @returns A Promise for the completion of which ever callback is executed.
*/
then<TResult>(onfulfilled: (value: T) => TResult | PromiseLike<TResult>): Promise<TResult>;
/**
* Creates a new Promise with the same internal state of this Promise.
* @returns A Promise.
*/
then(): Promise<T>;
/**
* Attaches a callback for only the rejection of the Promise.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of the callback.
*/
catch(onrejected?: (reason: any) => T | PromiseLike<T>): Promise<T>;
catch(onrejected?: (reason: any) => void): Promise<T>;
catch<TResult>(onrejected: (reason: any) => TResult | PromiseLike<TResult>): Promise<T | TResult>;
/**
* Attaches a callback for only the rejection of the Promise.
* @param onrejected The callback to execute when the Promise is rejected.
* @returns A Promise for the completion of the callback.
*/
catch(onrejected: (reason: any) => T | PromiseLike<T>): Promise<T>;
}
interface PromiseConstructor {
/**
* A reference to the prototype.
/**
* A reference to the prototype.
*/
readonly prototype: Promise<any>;
/**
* Creates a new Promise.
* @param executor A callback used to initialize the promise. This callback is passed two arguments:
* a resolve callback used resolve the promise with a value or the result of another promise,
* @param executor A callback used to initialize the promise. This callback is passed two arguments:
* a resolve callback used resolve the promise with a value or the result of another promise,
* and a reject callback used to reject the promise with a provided reason or error.
*/
new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;
/**
* Creates a Promise that is resolved with an array of results when all of the provided Promises
* Creates a Promise that is resolved with an array of results when all of the provided Promises
* resolve, or rejected when any Promise is rejected.
* @param values An array of Promises.
* @returns A new Promise.
*/
all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>, T10 | PromiseLike<T10>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;
/**
* Creates a Promise that is resolved with an array of results when all of the provided Promises
* resolve, or rejected when any Promise is rejected.
* @param values An array of Promises.
* @returns A new Promise.
*/
all<T1, T2, T3, T4, T5, T6, T7, T8, T9>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;
/**
* Creates a Promise that is resolved with an array of results when all of the provided Promises
* resolve, or rejected when any Promise is rejected.
* @param values An array of Promises.
* @returns A new Promise.
*/
all<T1, T2, T3, T4, T5, T6, T7, T8>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>;
/**
* Creates a Promise that is resolved with an array of results when all of the provided Promises
* resolve, or rejected when any Promise is rejected.
* @param values An array of Promises.
* @returns A new Promise.
*/
all<T1, T2, T3, T4, T5, T6, T7>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>]): Promise<[T1, T2, T3, T4, T5, T6, T7]>;
/**
* Creates a Promise that is resolved with an array of results when all of the provided Promises
* resolve, or rejected when any Promise is rejected.
* @param values An array of Promises.
* @returns A new Promise.
*/
all<T1, T2, T3, T4, T5, T6>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>]): Promise<[T1, T2, T3, T4, T5, T6]>;
/**
* Creates a Promise that is resolved with an array of results when all of the provided Promises
* resolve, or rejected when any Promise is rejected.
* @param values An array of Promises.
* @returns A new Promise.
*/
all<T1, T2, T3, T4, T5>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>]): Promise<[T1, T2, T3, T4, T5]>;
/**
* Creates a Promise that is resolved with an array of results when all of the provided Promises
* resolve, or rejected when any Promise is rejected.
* @param values An array of Promises.
* @returns A new Promise.
*/
all<T1, T2, T3, T4>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>]): Promise<[T1, T2, T3, T4]>;
/**
* Creates a Promise that is resolved with an array of results when all of the provided Promises
* resolve, or rejected when any Promise is rejected.
* @param values An array of Promises.
* @returns A new Promise.
*/
all<T1, T2, T3>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>]): Promise<[T1, T2, T3]>;
/**
* Creates a Promise that is resolved with an array of results when all of the provided Promises
* resolve, or rejected when any Promise is rejected.
* @param values An array of Promises.
* @returns A new Promise.
*/
all<T1, T2>(values: [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<[T1, T2]>;
/**
* Creates a Promise that is resolved with an array of results when all of the provided Promises
* resolve, or rejected when any Promise is rejected.
* @param values An array of Promises.
* @returns A new Promise.
*/
all<T>(values: (T | PromiseLike<T>)[]): Promise<T[]>;
/**
* Creates a new rejected promise for the provided reason.
* @param reason The reason the promise was rejected.
* @returns A new rejected Promise.
*/
reject(reason: any): Promise<void>;
reject(reason: any): Promise<never>;
/**
* Creates a new rejected promise for the provided reason.
+10 -10
View File
@@ -971,7 +971,7 @@ interface JSON {
/**
* Converts a JavaScript value to a JavaScript Object Notation (JSON) string.
* @param value A JavaScript value, usually an object or array, to be converted.
* @param replacer An array of strings and numbers that acts as a white list for selecting the object properties that will be stringified.
* @param replacer An array of strings and numbers that acts as a approved list for selecting the object properties that will be stringified.
* @param space Adds indentation, white space, and line break characters to the return-value JSON text to make it easier to read.
*/
stringify(value: any, replacer?: (number | string)[] | null, space?: string | number): string;
@@ -1524,7 +1524,7 @@ interface Int8Array {
* Returns the index of the first element in the array where predicate is true, and undefined
* otherwise.
* @param predicate find calls predicate once for each element of the array, in ascending
* order, until it finds one where predicate returns true. If such an element is found,
* order, until it finds one where predicate returns true. If such an element is found,
* findIndex immediately returns that element index. Otherwise, findIndex returns -1.
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
@@ -1797,7 +1797,7 @@ interface Uint8Array {
* Returns the index of the first element in the array where predicate is true, and undefined
* otherwise.
* @param predicate find calls predicate once for each element of the array, in ascending
* order, until it finds one where predicate returns true. If such an element is found,
* order, until it finds one where predicate returns true. If such an element is found,
* findIndex immediately returns that element index. Otherwise, findIndex returns -1.
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
@@ -2071,7 +2071,7 @@ interface Uint8ClampedArray {
* Returns the index of the first element in the array where predicate is true, and undefined
* otherwise.
* @param predicate find calls predicate once for each element of the array, in ascending
* order, until it finds one where predicate returns true. If such an element is found,
* order, until it finds one where predicate returns true. If such an element is found,
* findIndex immediately returns that element index. Otherwise, findIndex returns -1.
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
@@ -2344,7 +2344,7 @@ interface Int16Array {
* Returns the index of the first element in the array where predicate is true, and undefined
* otherwise.
* @param predicate find calls predicate once for each element of the array, in ascending
* order, until it finds one where predicate returns true. If such an element is found,
* order, until it finds one where predicate returns true. If such an element is found,
* findIndex immediately returns that element index. Otherwise, findIndex returns -1.
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
@@ -2618,7 +2618,7 @@ interface Uint16Array {
* Returns the index of the first element in the array where predicate is true, and undefined
* otherwise.
* @param predicate find calls predicate once for each element of the array, in ascending
* order, until it finds one where predicate returns true. If such an element is found,
* order, until it finds one where predicate returns true. If such an element is found,
* findIndex immediately returns that element index. Otherwise, findIndex returns -1.
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
@@ -2891,7 +2891,7 @@ interface Int32Array {
* Returns the index of the first element in the array where predicate is true, and undefined
* otherwise.
* @param predicate find calls predicate once for each element of the array, in ascending
* order, until it finds one where predicate returns true. If such an element is found,
* order, until it finds one where predicate returns true. If such an element is found,
* findIndex immediately returns that element index. Otherwise, findIndex returns -1.
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
@@ -3164,7 +3164,7 @@ interface Uint32Array {
* Returns the index of the first element in the array where predicate is true, and undefined
* otherwise.
* @param predicate find calls predicate once for each element of the array, in ascending
* order, until it finds one where predicate returns true. If such an element is found,
* order, until it finds one where predicate returns true. If such an element is found,
* findIndex immediately returns that element index. Otherwise, findIndex returns -1.
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
@@ -3437,7 +3437,7 @@ interface Float32Array {
* Returns the index of the first element in the array where predicate is true, and undefined
* otherwise.
* @param predicate find calls predicate once for each element of the array, in ascending
* order, until it finds one where predicate returns true. If such an element is found,
* order, until it finds one where predicate returns true. If such an element is found,
* findIndex immediately returns that element index. Otherwise, findIndex returns -1.
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
@@ -3711,7 +3711,7 @@ interface Float64Array {
* Returns the index of the first element in the array where predicate is true, and undefined
* otherwise.
* @param predicate find calls predicate once for each element of the array, in ascending
* order, until it finds one where predicate returns true. If such an element is found,
* order, until it finds one where predicate returns true. If such an element is found,
* findIndex immediately returns that element index. Otherwise, findIndex returns -1.
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
+13
View File
@@ -276,3 +276,16 @@ interface VBArrayConstructor {
}
declare var VBArray: VBArrayConstructor;
/**
* Automation date (VT_DATE)
*/
interface VarDate { }
interface DateConstructor {
new (vd: VarDate): Date;
}
interface Date {
getVarDate: () => VarDate;
}
+284 -85
View File
@@ -3,6 +3,10 @@
/// IE Worker APIs
/////////////////////////////
interface Algorithm {
name: string;
}
interface EventInit {
bubbles?: boolean;
cancelable?: boolean;
@@ -18,6 +22,10 @@ interface IDBObjectStoreParameters {
keyPath?: IDBKeyPath;
}
interface KeyAlgorithm {
name?: string;
}
interface EventListener {
(evt: Event): void;
}
@@ -107,6 +115,18 @@ declare var Coordinates: {
new(): Coordinates;
}
interface CryptoKey {
readonly algorithm: KeyAlgorithm;
readonly extractable: boolean;
readonly type: string;
readonly usages: string[];
}
declare var CryptoKey: {
prototype: CryptoKey;
new(): CryptoKey;
}
interface DOMError {
readonly name: string;
toString(): string;
@@ -322,8 +342,8 @@ declare var IDBCursorWithValue: {
interface IDBDatabase extends EventTarget {
readonly name: string;
readonly objectStoreNames: DOMStringList;
onabort: (ev: Event) => any;
onerror: (ev: Event) => any;
onabort: (this: this, ev: Event) => any;
onerror: (this: this, ev: ErrorEvent) => any;
version: number;
onversionchange: (ev: IDBVersionChangeEvent) => any;
close(): void;
@@ -331,8 +351,8 @@ interface IDBDatabase extends EventTarget {
deleteObjectStore(name: string): void;
transaction(storeNames: string | string[], mode?: string): IDBTransaction;
addEventListener(type: "versionchange", listener: (ev: IDBVersionChangeEvent) => any, useCapture?: boolean): void;
addEventListener(type: "abort", listener: (ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "abort", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (this: this, ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
@@ -410,12 +430,12 @@ declare var IDBObjectStore: {
}
interface IDBOpenDBRequest extends IDBRequest {
onblocked: (ev: Event) => any;
onupgradeneeded: (ev: IDBVersionChangeEvent) => any;
addEventListener(type: "blocked", listener: (ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "success", listener: (ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "upgradeneeded", listener: (ev: IDBVersionChangeEvent) => any, useCapture?: boolean): void;
onblocked: (this: this, ev: Event) => any;
onupgradeneeded: (this: this, ev: IDBVersionChangeEvent) => any;
addEventListener(type: "blocked", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (this: this, ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "success", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "upgradeneeded", listener: (this: this, ev: IDBVersionChangeEvent) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
@@ -426,14 +446,14 @@ declare var IDBOpenDBRequest: {
interface IDBRequest extends EventTarget {
readonly error: DOMError;
onerror: (ev: Event) => any;
onsuccess: (ev: Event) => any;
onerror: (this: this, ev: ErrorEvent) => any;
onsuccess: (this: this, ev: Event) => any;
readonly readyState: string;
readonly result: any;
source: IDBObjectStore | IDBIndex | IDBCursor;
readonly transaction: IDBTransaction;
addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "success", listener: (ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (this: this, ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "success", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
@@ -446,17 +466,17 @@ interface IDBTransaction extends EventTarget {
readonly db: IDBDatabase;
readonly error: DOMError;
readonly mode: string;
onabort: (ev: Event) => any;
oncomplete: (ev: Event) => any;
onerror: (ev: Event) => any;
onabort: (this: this, ev: Event) => any;
oncomplete: (this: this, ev: Event) => any;
onerror: (this: this, ev: ErrorEvent) => any;
abort(): void;
objectStore(name: string): IDBObjectStore;
readonly READ_ONLY: string;
readonly READ_WRITE: string;
readonly VERSION_CHANGE: string;
addEventListener(type: "abort", listener: (ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "complete", listener: (ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "abort", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "complete", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (this: this, ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
@@ -515,16 +535,16 @@ declare var MSApp: MSApp;
interface MSAppAsyncOperation extends EventTarget {
readonly error: DOMError;
oncomplete: (ev: Event) => any;
onerror: (ev: Event) => any;
oncomplete: (this: this, ev: Event) => any;
onerror: (this: this, ev: ErrorEvent) => any;
readonly readyState: number;
readonly result: any;
start(): void;
readonly COMPLETED: number;
readonly ERROR: number;
readonly STARTED: number;
addEventListener(type: "complete", listener: (ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "complete", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (this: this, ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
@@ -608,11 +628,11 @@ declare var MessageEvent: {
}
interface MessagePort extends EventTarget {
onmessage: (ev: MessageEvent) => any;
onmessage: (this: this, ev: MessageEvent) => any;
close(): void;
postMessage(message?: any, ports?: any): void;
start(): void;
addEventListener(type: "message", listener: (ev: MessageEvent) => any, useCapture?: boolean): void;
addEventListener(type: "message", listener: (this: this, ev: MessageEvent) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
@@ -664,10 +684,10 @@ interface WebSocket extends EventTarget {
binaryType: string;
readonly bufferedAmount: number;
readonly extensions: string;
onclose: (ev: CloseEvent) => any;
onerror: (ev: Event) => any;
onmessage: (ev: MessageEvent) => any;
onopen: (ev: Event) => any;
onclose: (this: this, ev: CloseEvent) => any;
onerror: (this: this, ev: ErrorEvent) => any;
onmessage: (this: this, ev: MessageEvent) => any;
onopen: (this: this, ev: Event) => any;
readonly protocol: string;
readonly readyState: number;
readonly url: string;
@@ -677,10 +697,10 @@ interface WebSocket extends EventTarget {
readonly CLOSING: number;
readonly CONNECTING: number;
readonly OPEN: number;
addEventListener(type: "close", listener: (ev: CloseEvent) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "message", listener: (ev: MessageEvent) => any, useCapture?: boolean): void;
addEventListener(type: "open", listener: (ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "close", listener: (this: this, ev: CloseEvent) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (this: this, ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "message", listener: (this: this, ev: MessageEvent) => any, useCapture?: boolean): void;
addEventListener(type: "open", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
@@ -694,11 +714,11 @@ declare var WebSocket: {
}
interface Worker extends EventTarget, AbstractWorker {
onmessage: (ev: MessageEvent) => any;
onmessage: (this: this, ev: MessageEvent) => any;
postMessage(message: any, ports?: any): void;
terminate(): void;
addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "message", listener: (ev: MessageEvent) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (this: this, ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "message", listener: (this: this, ev: MessageEvent) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
@@ -708,8 +728,7 @@ declare var Worker: {
}
interface XMLHttpRequest extends EventTarget, XMLHttpRequestEventTarget {
msCaching: string;
onreadystatechange: (ev: ProgressEvent) => any;
onreadystatechange: (this: this, ev: ProgressEvent) => any;
readonly readyState: number;
readonly response: any;
readonly responseText: string;
@@ -720,6 +739,7 @@ interface XMLHttpRequest extends EventTarget, XMLHttpRequestEventTarget {
timeout: number;
readonly upload: XMLHttpRequestUpload;
withCredentials: boolean;
msCaching?: string;
abort(): void;
getAllResponseHeaders(): string;
getResponseHeader(header: string): string | null;
@@ -734,14 +754,14 @@ interface XMLHttpRequest extends EventTarget, XMLHttpRequestEventTarget {
readonly LOADING: number;
readonly OPENED: number;
readonly UNSENT: number;
addEventListener(type: "abort", listener: (ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "load", listener: (ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "loadend", listener: (ev: ProgressEvent) => any, useCapture?: boolean): void;
addEventListener(type: "loadstart", listener: (ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "progress", listener: (ev: ProgressEvent) => any, useCapture?: boolean): void;
addEventListener(type: "readystatechange", listener: (ev: ProgressEvent) => any, useCapture?: boolean): void;
addEventListener(type: "timeout", listener: (ev: ProgressEvent) => any, useCapture?: boolean): void;
addEventListener(type: "abort", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (this: this, ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "load", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "loadend", listener: (this: this, ev: ProgressEvent) => any, useCapture?: boolean): void;
addEventListener(type: "loadstart", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "progress", listener: (this: this, ev: ProgressEvent) => any, useCapture?: boolean): void;
addEventListener(type: "readystatechange", listener: (this: this, ev: ProgressEvent) => any, useCapture?: boolean): void;
addEventListener(type: "timeout", listener: (this: this, ev: ProgressEvent) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
@@ -766,30 +786,30 @@ declare var XMLHttpRequestUpload: {
}
interface AbstractWorker {
onerror: (ev: Event) => any;
addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void;
onerror: (this: this, ev: ErrorEvent) => any;
addEventListener(type: "error", listener: (this: this, ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
interface MSBaseReader {
onabort: (ev: Event) => any;
onerror: (ev: Event) => any;
onload: (ev: Event) => any;
onloadend: (ev: ProgressEvent) => any;
onloadstart: (ev: Event) => any;
onprogress: (ev: ProgressEvent) => any;
onabort: (this: this, ev: Event) => any;
onerror: (this: this, ev: ErrorEvent) => any;
onload: (this: this, ev: Event) => any;
onloadend: (this: this, ev: ProgressEvent) => any;
onloadstart: (this: this, ev: Event) => any;
onprogress: (this: this, ev: ProgressEvent) => any;
readonly readyState: number;
readonly result: any;
abort(): void;
readonly DONE: number;
readonly EMPTY: number;
readonly LOADING: number;
addEventListener(type: "abort", listener: (ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "load", listener: (ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "loadend", listener: (ev: ProgressEvent) => any, useCapture?: boolean): void;
addEventListener(type: "loadstart", listener: (ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "progress", listener: (ev: ProgressEvent) => any, useCapture?: boolean): void;
addEventListener(type: "abort", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (this: this, ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "load", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "loadend", listener: (this: this, ev: ProgressEvent) => any, useCapture?: boolean): void;
addEventListener(type: "loadstart", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "progress", listener: (this: this, ev: ProgressEvent) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
@@ -818,20 +838,20 @@ interface WindowConsole {
}
interface XMLHttpRequestEventTarget {
onabort: (ev: Event) => any;
onerror: (ev: Event) => any;
onload: (ev: Event) => any;
onloadend: (ev: ProgressEvent) => any;
onloadstart: (ev: Event) => any;
onprogress: (ev: ProgressEvent) => any;
ontimeout: (ev: ProgressEvent) => any;
addEventListener(type: "abort", listener: (ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "load", listener: (ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "loadend", listener: (ev: ProgressEvent) => any, useCapture?: boolean): void;
addEventListener(type: "loadstart", listener: (ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "progress", listener: (ev: ProgressEvent) => any, useCapture?: boolean): void;
addEventListener(type: "timeout", listener: (ev: ProgressEvent) => any, useCapture?: boolean): void;
onabort: (this: this, ev: Event) => any;
onerror: (this: this, ev: ErrorEvent) => any;
onload: (this: this, ev: Event) => any;
onloadend: (this: this, ev: ProgressEvent) => any;
onloadstart: (this: this, ev: Event) => any;
onprogress: (this: this, ev: ProgressEvent) => any;
ontimeout: (this: this, ev: ProgressEvent) => any;
addEventListener(type: "abort", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (this: this, ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "load", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "loadend", listener: (this: this, ev: ProgressEvent) => any, useCapture?: boolean): void;
addEventListener(type: "loadstart", listener: (this: this, ev: Event) => any, useCapture?: boolean): void;
addEventListener(type: "progress", listener: (this: this, ev: ProgressEvent) => any, useCapture?: boolean): void;
addEventListener(type: "timeout", listener: (this: this, ev: ProgressEvent) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
@@ -849,13 +869,13 @@ declare var FileReaderSync: {
interface WorkerGlobalScope extends EventTarget, WorkerUtils, DedicatedWorkerGlobalScope, WindowConsole {
readonly location: WorkerLocation;
onerror: (ev: Event) => any;
onerror: (this: this, ev: ErrorEvent) => any;
readonly self: WorkerGlobalScope;
close(): void;
msWriteProfilerMark(profilerMarkName: string): void;
toString(): string;
addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "message", listener: (ev: MessageEvent) => any, useCapture?: boolean): void;
addEventListener(type: "error", listener: (this: this, ev: ErrorEvent) => any, useCapture?: boolean): void;
addEventListener(type: "message", listener: (this: this, ev: MessageEvent) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
@@ -891,9 +911,9 @@ declare var WorkerNavigator: {
}
interface DedicatedWorkerGlobalScope {
onmessage: (ev: MessageEvent) => any;
onmessage: (this: this, ev: MessageEvent) => any;
postMessage(data: any): void;
addEventListener(type: "message", listener: (ev: MessageEvent) => any, useCapture?: boolean): void;
addEventListener(type: "message", listener: (this: this, ev: MessageEvent) => any, useCapture?: boolean): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
}
@@ -905,8 +925,11 @@ interface WorkerUtils extends Object, WindowBase64 {
clearInterval(handle: number): void;
clearTimeout(handle: number): void;
importScripts(...urls: string[]): void;
setImmediate(handler: (...args: any[]) => void): number;
setImmediate(handler: any, ...args: any[]): number;
setInterval(handler: (...args: any[]) => void, timeout: number): number;
setInterval(handler: any, timeout?: any, ...args: any[]): number;
setTimeout(handler: (...args: any[]) => void, timeout: number): number;
setTimeout(handler: any, timeout?: any, ...args: any[]): number;
}
@@ -942,6 +965,177 @@ interface ProgressEventInit extends EventInit {
interface IDBArrayKey extends Array<IDBValidKey> {
}
interface RsaKeyGenParams extends Algorithm {
modulusLength: number;
publicExponent: Uint8Array;
}
interface RsaHashedKeyGenParams extends RsaKeyGenParams {
hash: AlgorithmIdentifier;
}
interface RsaKeyAlgorithm extends KeyAlgorithm {
modulusLength: number;
publicExponent: Uint8Array;
}
interface RsaHashedKeyAlgorithm extends RsaKeyAlgorithm {
hash: AlgorithmIdentifier;
}
interface RsaHashedImportParams {
hash: AlgorithmIdentifier;
}
interface RsaPssParams {
saltLength: number;
}
interface RsaOaepParams extends Algorithm {
label?: BufferSource;
}
interface EcdsaParams extends Algorithm {
hash: AlgorithmIdentifier;
}
interface EcKeyGenParams extends Algorithm {
typedCurve: string;
}
interface EcKeyAlgorithm extends KeyAlgorithm {
typedCurve: string;
}
interface EcKeyImportParams {
namedCurve: string;
}
interface EcdhKeyDeriveParams extends Algorithm {
public: CryptoKey;
}
interface AesCtrParams extends Algorithm {
counter: BufferSource;
length: number;
}
interface AesKeyAlgorithm extends KeyAlgorithm {
length: number;
}
interface AesKeyGenParams extends Algorithm {
length: number;
}
interface AesDerivedKeyParams extends Algorithm {
length: number;
}
interface AesCbcParams extends Algorithm {
iv: BufferSource;
}
interface AesCmacParams extends Algorithm {
length: number;
}
interface AesGcmParams extends Algorithm {
iv: BufferSource;
additionalData?: BufferSource;
tagLength?: number;
}
interface AesCfbParams extends Algorithm {
iv: BufferSource;
}
interface HmacImportParams extends Algorithm {
hash?: AlgorithmIdentifier;
length?: number;
}
interface HmacKeyAlgorithm extends KeyAlgorithm {
hash: AlgorithmIdentifier;
length: number;
}
interface HmacKeyGenParams extends Algorithm {
hash: AlgorithmIdentifier;
length?: number;
}
interface DhKeyGenParams extends Algorithm {
prime: Uint8Array;
generator: Uint8Array;
}
interface DhKeyAlgorithm extends KeyAlgorithm {
prime: Uint8Array;
generator: Uint8Array;
}
interface DhKeyDeriveParams extends Algorithm {
public: CryptoKey;
}
interface DhImportKeyParams extends Algorithm {
prime: Uint8Array;
generator: Uint8Array;
}
interface ConcatParams extends Algorithm {
hash?: AlgorithmIdentifier;
algorithmId: Uint8Array;
partyUInfo: Uint8Array;
partyVInfo: Uint8Array;
publicInfo?: Uint8Array;
privateInfo?: Uint8Array;
}
interface HkdfCtrParams extends Algorithm {
hash: AlgorithmIdentifier;
label: BufferSource;
context: BufferSource;
}
interface Pbkdf2Params extends Algorithm {
salt: BufferSource;
iterations: number;
hash: AlgorithmIdentifier;
}
interface RsaOtherPrimesInfo {
r: string;
d: string;
t: string;
}
interface JsonWebKey {
kty: string;
use?: string;
key_ops?: string[];
alg?: string;
kid?: string;
x5u?: string;
x5c?: string;
x5t?: string;
ext?: boolean;
crv?: string;
x?: string;
y?: string;
d?: string;
n?: string;
e?: string;
p?: string;
q?: string;
dp?: string;
dq?: string;
qi?: string;
oth?: RsaOtherPrimesInfo[];
k?: string;
}
declare type EventListenerOrEventListenerObject = EventListener | EventListenerObject;
interface ErrorEventHandler {
@@ -975,7 +1169,7 @@ interface FunctionStringCallback {
(data: string): void;
}
declare var location: WorkerLocation;
declare var onerror: (ev: Event) => any;
declare var onerror: (this: WorkerGlobalScope, ev: ErrorEvent) => any;
declare var self: WorkerGlobalScope;
declare function close(): void;
declare function msWriteProfilerMark(profilerMarkName: string): void;
@@ -990,16 +1184,21 @@ declare function clearImmediate(handle: number): void;
declare function clearInterval(handle: number): void;
declare function clearTimeout(handle: number): void;
declare function importScripts(...urls: string[]): void;
declare function setImmediate(handler: (...args: any[]) => void): number;
declare function setImmediate(handler: any, ...args: any[]): number;
declare function setInterval(handler: (...args: any[]) => void, timeout: number): number;
declare function setInterval(handler: any, timeout?: any, ...args: any[]): number;
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): number;
declare function setTimeout(handler: any, timeout?: any, ...args: any[]): number;
declare function atob(encodedString: string): string;
declare function btoa(rawString: string): string;
declare var onmessage: (ev: MessageEvent) => any;
declare var onmessage: (this: WorkerGlobalScope, ev: MessageEvent) => any;
declare function postMessage(data: any): void;
declare var console: Console;
declare function addEventListener(type: "error", listener: (ev: ErrorEvent) => any, useCapture?: boolean): void;
declare function addEventListener(type: "message", listener: (ev: MessageEvent) => any, useCapture?: boolean): void;
declare function addEventListener(type: "error", listener: (this: WorkerGlobalScope, ev: ErrorEvent) => any, useCapture?: boolean): void;
declare function addEventListener(type: "message", listener: (this: WorkerGlobalScope, ev: MessageEvent) => any, useCapture?: boolean): void;
declare function addEventListener(type: string, listener: EventListenerOrEventListenerObject, useCapture?: boolean): void;
type AlgorithmIdentifier = string | Algorithm;
type IDBKeyPath = string;
type IDBValidKey = number | string | Date | IDBArrayKey;
type IDBValidKey = number | string | Date | IDBArrayKey;
type BufferSource = ArrayBuffer | ArrayBufferView;
+12 -7
View File
@@ -45,8 +45,9 @@ namespace ts.server {
return lineMap;
}
private lineOffsetToPosition(fileName: string, lineOffset: protocol.Location): number {
return ts.computePositionOfLineAndCharacter(this.getLineMap(fileName), lineOffset.line - 1, lineOffset.offset - 1);
private lineOffsetToPosition(fileName: string, lineOffset: protocol.Location, lineMap?: number[]): number {
lineMap = lineMap || this.getLineMap(fileName);
return ts.computePositionOfLineAndCharacter(lineMap, lineOffset.line - 1, lineOffset.offset - 1);
}
private positionToOneBasedLineOffset(fileName: string, position: number): protocol.Location {
@@ -449,7 +450,7 @@ namespace ts.server {
return this.lastRenameEntry.locations;
}
decodeNavigationBarItems(items: protocol.NavigationBarItem[], fileName: string): NavigationBarItem[] {
decodeNavigationBarItems(items: protocol.NavigationBarItem[], fileName: string, lineMap: number[]): NavigationBarItem[] {
if (!items) {
return [];
}
@@ -458,8 +459,11 @@ namespace ts.server {
text: item.text,
kind: item.kind,
kindModifiers: item.kindModifiers || "",
spans: item.spans.map(span => createTextSpanFromBounds(this.lineOffsetToPosition(fileName, span.start), this.lineOffsetToPosition(fileName, span.end))),
childItems: this.decodeNavigationBarItems(item.childItems, fileName),
spans: item.spans.map(span =>
createTextSpanFromBounds(
this.lineOffsetToPosition(fileName, span.start, lineMap),
this.lineOffsetToPosition(fileName, span.end, lineMap))),
childItems: this.decodeNavigationBarItems(item.childItems, fileName, lineMap),
indent: item.indent,
bolded: false,
grayed: false
@@ -474,7 +478,8 @@ namespace ts.server {
const request = this.processRequest<protocol.NavBarRequest>(CommandNames.NavBar, args);
const response = this.processResponse<protocol.NavBarResponse>(request);
return this.decodeNavigationBarItems(response.body, fileName);
const lineMap = this.getLineMap(fileName);
return this.decodeNavigationBarItems(response.body, fileName, lineMap);
}
getNameOrDottedNameSpan(fileName: string, startPos: number, endPos: number): TextSpan {
@@ -583,7 +588,7 @@ namespace ts.server {
throw new Error("Not Implemented Yet.");
}
isValidBraceCompletionAtPostion(fileName: string, position: number, openingBrace: number): boolean {
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean {
throw new Error("Not Implemented Yet.");
}
+195 -15
View File
@@ -27,6 +27,8 @@ namespace ts.server {
});
}
export const maxProgramSizeForNonTsFiles = 20 * 1024 * 1024;
export class ScriptInfo {
svc: ScriptVersionCache;
children: ScriptInfo[] = []; // files referenced by this file
@@ -36,7 +38,7 @@ namespace ts.server {
path: Path;
scriptKind: ScriptKind;
constructor(private host: ServerHost, public fileName: string, public content: string, public isOpen = false) {
constructor(private host: ServerHost, public fileName: string, content: string, public isOpen = false) {
this.path = toPath(fileName, host.getCurrentDirectory(), createGetCanonicalFileName(host.useCaseSensitiveFileNames));
this.svc = ScriptVersionCache.fromString(host, content);
}
@@ -357,18 +359,23 @@ namespace ts.server {
* @param line 1-based index
* @param offset 1-based index
*/
positionToLineOffset(filename: string, position: number): ILineInfo {
positionToLineOffset(filename: string, position: number, lineIndex?: LineIndex): ILineInfo {
lineIndex = lineIndex || this.getLineIndex(filename);
const lineOffset = lineIndex.charOffsetToLineNumberAndPos(position);
return { line: lineOffset.line, offset: lineOffset.offset + 1 };
}
getLineIndex(filename: string): LineIndex {
const path = toPath(filename, this.host.getCurrentDirectory(), this.getCanonicalFileName);
const script: ScriptInfo = this.filenameToScript.get(path);
const index = script.snap().index;
const lineOffset = index.charOffsetToLineNumberAndPos(position);
return { line: lineOffset.line, offset: lineOffset.offset + 1 };
return script.snap().index;
}
}
export interface ProjectOptions {
// these fields can be present in the project file
files?: string[];
wildcardDirectories?: ts.Map<ts.WatchDirectoryFlags>;
compilerOptions?: ts.CompilerOptions;
}
@@ -377,6 +384,7 @@ namespace ts.server {
projectFilename: string;
projectFileWatcher: FileWatcher;
directoryWatcher: FileWatcher;
directoriesWatchedForWildcards: Map<FileWatcher>;
// Used to keep track of what directories are watched for this project
directoriesWatchedForTsconfig: string[] = [];
program: ts.Program;
@@ -385,12 +393,29 @@ namespace ts.server {
/** Used for configured projects which may have multiple open roots */
openRefCount = 0;
constructor(public projectService: ProjectService, public projectOptions?: ProjectOptions) {
constructor(
public projectService: ProjectService,
public projectOptions?: ProjectOptions,
public languageServiceDiabled = false) {
if (projectOptions && projectOptions.files) {
// If files are listed explicitly, allow all extensions
projectOptions.compilerOptions.allowNonTsExtensions = true;
}
this.compilerService = new CompilerService(this, projectOptions && projectOptions.compilerOptions);
if (!languageServiceDiabled) {
this.compilerService = new CompilerService(this, projectOptions && projectOptions.compilerOptions);
}
}
enableLanguageService() {
// if the language service was disabled, we should re-initiate the compiler service
if (this.languageServiceDiabled) {
this.compilerService = new CompilerService(this, this.projectOptions && this.projectOptions.compilerOptions);
}
this.languageServiceDiabled = false;
}
disableLanguageService() {
this.languageServiceDiabled = true;
}
addOpenRef() {
@@ -407,19 +432,45 @@ namespace ts.server {
}
getRootFiles() {
if (this.languageServiceDiabled) {
// When the languageService was disabled, only return file list if it is a configured project
return this.projectOptions ? this.projectOptions.files : undefined;
}
return this.compilerService.host.roots.map(info => info.fileName);
}
getFileNames() {
if (this.languageServiceDiabled) {
if (!this.projectOptions) {
return undefined;
}
const fileNames: string[] = [];
if (this.projectOptions && this.projectOptions.compilerOptions) {
fileNames.push(getDefaultLibFilePath(this.projectOptions.compilerOptions));
}
ts.addRange(fileNames, this.projectOptions.files);
return fileNames;
}
const sourceFiles = this.program.getSourceFiles();
return sourceFiles.map(sourceFile => sourceFile.fileName);
}
getSourceFile(info: ScriptInfo) {
if (this.languageServiceDiabled) {
return undefined;
}
return this.filenameToSourceFile[info.fileName];
}
getSourceFileFromName(filename: string, requireOpen?: boolean) {
if (this.languageServiceDiabled) {
return undefined;
}
const info = this.projectService.getScriptInfo(filename);
if (info) {
if ((!requireOpen) || info.isOpen) {
@@ -429,15 +480,27 @@ namespace ts.server {
}
isRoot(info: ScriptInfo) {
if (this.languageServiceDiabled) {
return undefined;
}
return this.compilerService.host.roots.some(root => root === info);
}
removeReferencedFile(info: ScriptInfo) {
if (this.languageServiceDiabled) {
return;
}
this.compilerService.host.removeReferencedFile(info);
this.updateGraph();
}
updateFileMap() {
if (this.languageServiceDiabled) {
return;
}
this.filenameToSourceFile = {};
const sourceFiles = this.program.getSourceFiles();
for (let i = 0, len = sourceFiles.length; i < len; i++) {
@@ -447,11 +510,19 @@ namespace ts.server {
}
finishGraph() {
if (this.languageServiceDiabled) {
return;
}
this.updateGraph();
this.compilerService.languageService.getNavigateToItems(".*");
}
updateGraph() {
if (this.languageServiceDiabled) {
return;
}
this.program = this.compilerService.languageService.getProgram();
this.updateFileMap();
}
@@ -462,15 +533,32 @@ namespace ts.server {
// add a root file to project
addRoot(info: ScriptInfo) {
if (this.languageServiceDiabled) {
return;
}
this.compilerService.host.addRoot(info);
}
// remove a root file from project
removeRoot(info: ScriptInfo) {
if (this.languageServiceDiabled) {
return;
}
this.compilerService.host.removeRoot(info);
}
filesToString() {
if (this.languageServiceDiabled) {
if (this.projectOptions) {
let strBuilder = "";
ts.forEach(this.projectOptions.files,
file => { strBuilder += file + "\n"; });
return strBuilder;
}
}
let strBuilder = "";
ts.forEachValue(this.filenameToSourceFile,
sourceFile => { strBuilder += sourceFile.fileName + "\n"; });
@@ -481,7 +569,9 @@ namespace ts.server {
this.projectOptions = projectOptions;
if (projectOptions.compilerOptions) {
projectOptions.compilerOptions.allowNonTsExtensions = true;
this.compilerService.setCompilerOptions(projectOptions.compilerOptions);
if (!this.languageServiceDiabled) {
this.compilerService.setCompilerOptions(projectOptions.compilerOptions);
}
}
}
}
@@ -764,6 +854,8 @@ namespace ts.server {
if (project.isConfiguredProject()) {
project.projectFileWatcher.close();
project.directoryWatcher.close();
forEachValue(project.directoriesWatchedForWildcards, watcher => { watcher.close(); });
delete project.directoriesWatchedForWildcards;
this.configuredProjects = copyListRemovingItem(project, this.configuredProjects);
}
else {
@@ -807,6 +899,7 @@ namespace ts.server {
else {
this.findReferencingProjects(info);
if (info.defaultProject) {
info.defaultProject.addOpenRef();
this.openFilesReferenced.push(info);
}
else {
@@ -1255,12 +1348,30 @@ namespace ts.server {
else {
const projectOptions: ProjectOptions = {
files: parsedCommandLine.fileNames,
compilerOptions: parsedCommandLine.options
wildcardDirectories: parsedCommandLine.wildcardDirectories,
compilerOptions: parsedCommandLine.options,
};
return { succeeded: true, projectOptions };
}
}
}
private exceedTotalNonTsFileSizeLimit(fileNames: string[]) {
let totalNonTsFileSize = 0;
if (!this.host.getFileSize) {
return false;
}
for (const fileName of fileNames) {
if (hasTypeScriptFileExtension(fileName)) {
continue;
}
totalNonTsFileSize += this.host.getFileSize(fileName);
if (totalNonTsFileSize > maxProgramSizeForNonTsFiles) {
return true;
}
}
return false;
}
openConfigFile(configFilename: string, clientFileName?: string): { success: boolean, project?: Project, errors?: Diagnostic[] } {
@@ -1269,6 +1380,19 @@ namespace ts.server {
return { success: false, errors };
}
else {
if (!projectOptions.compilerOptions.disableSizeLimit && projectOptions.compilerOptions.allowJs) {
if (this.exceedTotalNonTsFileSizeLimit(projectOptions.files)) {
const project = this.createProject(configFilename, projectOptions, /*languageServiceDisabled*/ true);
// for configured projects with languageService disabled, we only watch its config file,
// do not care about the directory changes in the folder.
project.projectFileWatcher = this.host.watchFile(
toPath(configFilename, configFilename, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)),
_ => this.watchedProjectConfigFileChanged(project));
return { success: true, project };
}
}
const project = this.createProject(configFilename, projectOptions);
let errors: Diagnostic[];
for (const rootFilename of projectOptions.files) {
@@ -1282,17 +1406,35 @@ namespace ts.server {
}
project.finishGraph();
project.projectFileWatcher = this.host.watchFile(configFilename, _ => this.watchedProjectConfigFileChanged(project));
this.log("Add recursive watcher for: " + ts.getDirectoryPath(configFilename));
const configDirectoryPath = ts.getDirectoryPath(configFilename);
this.log("Add recursive watcher for: " + configDirectoryPath);
project.directoryWatcher = this.host.watchDirectory(
ts.getDirectoryPath(configFilename),
configDirectoryPath,
path => this.directoryWatchedForSourceFilesChanged(project, path),
/*recursive*/ true
);
project.directoriesWatchedForWildcards = reduceProperties(projectOptions.wildcardDirectories, (watchers, flag, directory) => {
if (comparePaths(configDirectoryPath, directory, ".", !this.host.useCaseSensitiveFileNames) !== Comparison.EqualTo) {
const recursive = (flag & WatchDirectoryFlags.Recursive) !== 0;
this.log(`Add ${ recursive ? "recursive " : ""}watcher for: ${directory}`);
watchers[directory] = this.host.watchDirectory(
directory,
path => this.directoryWatchedForSourceFilesChanged(project, path),
recursive
);
}
return watchers;
}, <Map<FileWatcher>>{});
return { success: true, project: project, errors };
}
}
updateConfiguredProject(project: Project) {
updateConfiguredProject(project: Project): Diagnostic[] {
if (!this.host.fileExists(project.projectFilename)) {
this.log("Config file deleted");
this.removeProject(project);
@@ -1303,7 +1445,43 @@ namespace ts.server {
return errors;
}
else {
const oldFileNames = project.compilerService.host.roots.map(info => info.fileName);
if (projectOptions.compilerOptions && !projectOptions.compilerOptions.disableSizeLimit && this.exceedTotalNonTsFileSizeLimit(projectOptions.files)) {
project.setProjectOptions(projectOptions);
if (project.languageServiceDiabled) {
return;
}
project.disableLanguageService();
if (project.directoryWatcher) {
project.directoryWatcher.close();
project.directoryWatcher = undefined;
}
return;
}
if (project.languageServiceDiabled) {
project.setProjectOptions(projectOptions);
project.enableLanguageService();
project.directoryWatcher = this.host.watchDirectory(
ts.getDirectoryPath(project.projectFilename),
path => this.directoryWatchedForSourceFilesChanged(project, path),
/*recursive*/ true
);
for (const rootFilename of projectOptions.files) {
if (this.host.fileExists(rootFilename)) {
const info = this.openFile(rootFilename, /*openedByClient*/ false);
project.addRoot(info);
}
}
project.finishGraph();
return;
}
// if the project is too large, the root files might not have been all loaded if the total
// program size reached the upper limit. In that case project.projectOptions.files should
// be more precise. However this would only happen for configured project.
const oldFileNames = project.projectOptions ? project.projectOptions.files : project.compilerService.host.roots.map(info => info.fileName);
const newFileNames = ts.filter(projectOptions.files, f => this.host.fileExists(f));
const fileNamesToRemove = oldFileNames.filter(f => newFileNames.indexOf(f) < 0);
const fileNamesToAdd = newFileNames.filter(f => oldFileNames.indexOf(f) < 0);
@@ -1346,8 +1524,8 @@ namespace ts.server {
}
}
createProject(projectFilename: string, projectOptions?: ProjectOptions) {
const project = new Project(this, projectOptions);
createProject(projectFilename: string, projectOptions?: ProjectOptions, languageServiceDisabled?: boolean) {
const project = new Project(this, projectOptions, languageServiceDisabled);
project.projectFilename = projectFilename;
return project;
}
@@ -1388,6 +1566,7 @@ namespace ts.server {
static getDefaultFormatCodeOptions(host: ServerHost): ts.FormatCodeOptions {
return ts.clone({
BaseIndentSize: 0,
IndentSize: 4,
TabSize: 4,
NewLineCharacter: host.newLine || "\n",
@@ -1401,6 +1580,7 @@ namespace ts.server {
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
InsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
PlaceOpenBraceOnNewLineForFunctions: false,
PlaceOpenBraceOnNewLineForControlBlocks: false,
});
+34 -2
View File
@@ -123,6 +123,10 @@ declare namespace ts.server.protocol {
* The list of normalized file name in the project, including 'lib.d.ts'
*/
fileNames?: string[];
/**
* Indicates if the project has a active language service instance
*/
languageServiceDisabled?: boolean;
}
/**
@@ -434,6 +438,9 @@ declare namespace ts.server.protocol {
/** Number of spaces to indent during formatting. Default value is 4. */
indentSize?: number;
/** Number of additional spaces to indent during formatting to preserve base indentation (ex. script block indentation). Default value is 0. */
baseIndentSize?: number;
/** The new line character to be used. Default value is the OS line delimiter. */
newLineCharacter?: string;
@@ -474,7 +481,7 @@ declare namespace ts.server.protocol {
placeOpenBraceOnNewLineForControlBlocks?: boolean;
/** Index operator */
[key: string]: string | number | boolean;
[key: string]: string | number | boolean | undefined;
}
/**
@@ -900,7 +907,6 @@ declare namespace ts.server.protocol {
* Arguments of a signature help request.
*/
export interface SignatureHelpRequestArgs extends FileLocationRequestArgs {
}
/**
@@ -919,6 +925,32 @@ declare namespace ts.server.protocol {
body?: SignatureHelpItems;
}
/**
* Synchronous request for semantic diagnostics of one file.
*/
export interface SemanticDiagnosticsSyncRequest extends FileRequest {
}
/**
* Response object for synchronous sematic diagnostics request.
*/
export interface SemanticDiagnosticsSyncResponse extends Response {
body?: Diagnostic[];
}
/**
* Synchronous request for syntactic diagnostics of one file.
*/
export interface SyntacticDiagnosticsSyncRequest extends FileRequest {
}
/**
* Response object for synchronous syntactic diagnostics request.
*/
export interface SyntacticDiagnosticsSyncResponse extends Response {
body?: Diagnostic[];
}
/**
* Arguments for GeterrForProject request.
*/
+78 -34
View File
@@ -111,6 +111,8 @@ namespace ts.server {
export const Formatonkey = "formatonkey";
export const Geterr = "geterr";
export const GeterrForProject = "geterrForProject";
export const SemanticDiagnosticsSync = "semanticDiagnosticsSync";
export const SyntacticDiagnosticsSync = "syntacticDiagnosticsSync";
export const NavBar = "navbar";
export const Navto = "navto";
export const Occurrences = "occurrences";
@@ -130,6 +132,7 @@ namespace ts.server {
namespace Errors {
export const NoProject = new Error("No Project.");
export const ProjectLanguageServiceDisabled = new Error("The project's language service is disabled.");
}
export interface ServerHost extends ts.System {
@@ -313,7 +316,7 @@ namespace ts.server {
private getDefinition(line: number, offset: number, fileName: string): protocol.FileSpan[] {
const file = ts.normalizePath(fileName);
const project = this.projectService.getProjectForFile(file);
if (!project) {
if (!project || project.languageServiceDiabled) {
throw Errors.NoProject;
}
@@ -335,7 +338,7 @@ namespace ts.server {
private getTypeDefinition(line: number, offset: number, fileName: string): protocol.FileSpan[] {
const file = ts.normalizePath(fileName);
const project = this.projectService.getProjectForFile(file);
if (!project) {
if (!project || project.languageServiceDiabled) {
throw Errors.NoProject;
}
@@ -358,7 +361,7 @@ namespace ts.server {
fileName = ts.normalizePath(fileName);
const project = this.projectService.getProjectForFile(fileName);
if (!project) {
if (!project || project.languageServiceDiabled) {
throw Errors.NoProject;
}
@@ -384,11 +387,32 @@ namespace ts.server {
});
}
private getDiagnosticsWorker(args: protocol.FileRequestArgs, selector: (project: Project, file: string) => Diagnostic[]) {
const file = normalizePath(args.file);
const project = this.projectService.getProjectForFile(file);
if (!project) {
throw Errors.NoProject;
}
if (project.languageServiceDiabled) {
throw Errors.ProjectLanguageServiceDisabled;
}
const diagnostics = selector(project, file);
return ts.map(diagnostics, originalDiagnostic => formatDiag(file, project, originalDiagnostic));
}
private getSyntacticDiagnosticsSync(args: protocol.FileRequestArgs): protocol.Diagnostic[] {
return this.getDiagnosticsWorker(args, (project, file) => project.compilerService.languageService.getSyntacticDiagnostics(file));
}
private getSemanticDiagnosticsSync(args: protocol.FileRequestArgs): protocol.Diagnostic[] {
return this.getDiagnosticsWorker(args, (project, file) => project.compilerService.languageService.getSemanticDiagnostics(file));
}
private getDocumentHighlights(line: number, offset: number, fileName: string, filesToSearch: string[]): protocol.DocumentHighlightsItem[] {
fileName = ts.normalizePath(fileName);
const project = this.projectService.getProjectForFile(fileName);
if (!project) {
if (!project || project.languageServiceDiabled) {
throw Errors.NoProject;
}
@@ -423,15 +447,18 @@ namespace ts.server {
private getProjectInfo(fileName: string, needFileNameList: boolean): protocol.ProjectInfo {
fileName = ts.normalizePath(fileName);
const project = this.projectService.getProjectForFile(fileName);
if (!project) {
throw Errors.NoProject;
}
const projectInfo: protocol.ProjectInfo = {
configFileName: project.projectFilename
configFileName: project.projectFilename,
languageServiceDisabled: project.languageServiceDiabled
};
if (needFileNameList) {
projectInfo.fileNames = project.getFileNames();
}
return projectInfo;
}
@@ -439,11 +466,12 @@ namespace ts.server {
const file = ts.normalizePath(fileName);
const info = this.projectService.getScriptInfo(file);
const projects = this.projectService.findReferencingProjects(info);
if (!projects.length) {
const projectsWithLanguageServiceEnabeld = ts.filter(projects, p => !p.languageServiceDiabled);
if (projectsWithLanguageServiceEnabeld.length === 0) {
throw Errors.NoProject;
}
const defaultProject = projects[0];
const defaultProject = projectsWithLanguageServiceEnabeld[0];
// The rename info should be the same for every project
const defaultProjectCompilerService = defaultProject.compilerService;
const position = defaultProjectCompilerService.host.lineOffsetToPosition(file, line, offset);
@@ -460,7 +488,7 @@ namespace ts.server {
}
const fileSpans = combineProjectOutput(
projects,
projectsWithLanguageServiceEnabeld,
(project: Project) => {
const compilerService = project.compilerService;
const renameLocations = compilerService.languageService.findRenameLocations(file, position, findInStrings, findInComments);
@@ -521,11 +549,12 @@ namespace ts.server {
const file = ts.normalizePath(fileName);
const info = this.projectService.getScriptInfo(file);
const projects = this.projectService.findReferencingProjects(info);
if (!projects.length) {
const projectsWithLanguageServiceEnabeld = ts.filter(projects, p => !p.languageServiceDiabled);
if (projectsWithLanguageServiceEnabeld.length === 0) {
throw Errors.NoProject;
}
const defaultProject = projects[0];
const defaultProject = projectsWithLanguageServiceEnabeld[0];
const position = defaultProject.compilerService.host.lineOffsetToPosition(file, line, offset);
const nameInfo = defaultProject.compilerService.languageService.getQuickInfoAtPosition(file, position);
if (!nameInfo) {
@@ -537,7 +566,7 @@ namespace ts.server {
const nameColStart = defaultProject.compilerService.host.positionToLineOffset(file, nameSpan.start).offset;
const nameText = defaultProject.compilerService.host.getScriptSnapshot(file).getText(nameSpan.start, ts.textSpanEnd(nameSpan));
const refs = combineProjectOutput<protocol.ReferencesResponseItem>(
projects,
projectsWithLanguageServiceEnabeld,
(project: Project) => {
const compilerService = project.compilerService;
const references = compilerService.languageService.getReferencesAtPosition(file, position);
@@ -596,7 +625,7 @@ namespace ts.server {
private getQuickInfo(line: number, offset: number, fileName: string): protocol.QuickInfoResponseBody {
const file = ts.normalizePath(fileName);
const project = this.projectService.getProjectForFile(file);
if (!project) {
if (!project || project.languageServiceDiabled) {
throw Errors.NoProject;
}
@@ -622,7 +651,7 @@ namespace ts.server {
private getFormattingEditsForRange(line: number, offset: number, endLine: number, endOffset: number, fileName: string): protocol.CodeEdit[] {
const file = ts.normalizePath(fileName);
const project = this.projectService.getProjectForFile(file);
if (!project) {
if (!project || project.languageServiceDiabled) {
throw Errors.NoProject;
}
@@ -650,7 +679,7 @@ namespace ts.server {
const file = ts.normalizePath(fileName);
const project = this.projectService.getProjectForFile(file);
if (!project) {
if (!project || project.languageServiceDiabled) {
throw Errors.NoProject;
}
@@ -674,6 +703,7 @@ namespace ts.server {
if (lineText.search("\\S") < 0) {
// TODO: get these options from host
const editorOptions: ts.EditorOptions = {
BaseIndentSize: formatOptions.BaseIndentSize,
IndentSize: formatOptions.IndentSize,
TabSize: formatOptions.TabSize,
NewLineCharacter: formatOptions.NewLineCharacter,
@@ -728,7 +758,7 @@ namespace ts.server {
}
const file = ts.normalizePath(fileName);
const project = this.projectService.getProjectForFile(file);
if (!project) {
if (!project || project.languageServiceDiabled) {
throw Errors.NoProject;
}
@@ -752,7 +782,7 @@ namespace ts.server {
entryNames: string[], fileName: string): protocol.CompletionEntryDetails[] {
const file = ts.normalizePath(fileName);
const project = this.projectService.getProjectForFile(file);
if (!project) {
if (!project || project.languageServiceDiabled) {
throw Errors.NoProject;
}
@@ -771,7 +801,7 @@ namespace ts.server {
private getSignatureHelpItems(line: number, offset: number, fileName: string): protocol.SignatureHelpItems {
const file = ts.normalizePath(fileName);
const project = this.projectService.getProjectForFile(file);
if (!project) {
if (!project || project.languageServiceDiabled) {
throw Errors.NoProject;
}
@@ -801,7 +831,7 @@ namespace ts.server {
const checkList = fileNames.reduce((accum: PendingErrorCheck[], fileName: string) => {
fileName = ts.normalizePath(fileName);
const project = this.projectService.getProjectForFile(fileName);
if (project) {
if (project && !project.languageServiceDiabled) {
accum.push({ fileName, project });
}
return accum;
@@ -815,7 +845,7 @@ namespace ts.server {
private change(line: number, offset: number, endLine: number, endOffset: number, insertString: string, fileName: string) {
const file = ts.normalizePath(fileName);
const project = this.projectService.getProjectForFile(file);
if (project) {
if (project && !project.languageServiceDiabled) {
const compilerService = project.compilerService;
const start = compilerService.host.lineOffsetToPosition(file, line, offset);
const end = compilerService.host.lineOffsetToPosition(file, endLine, endOffset);
@@ -831,7 +861,7 @@ namespace ts.server {
const file = ts.normalizePath(fileName);
const tmpfile = ts.normalizePath(tempFileName);
const project = this.projectService.getProjectForFile(file);
if (project) {
if (project && !project.languageServiceDiabled) {
this.changeSeq++;
// make sure no changes happen before this one is finished
project.compilerService.host.reloadScript(file, tmpfile, () => {
@@ -845,7 +875,7 @@ namespace ts.server {
const tmpfile = ts.normalizePath(tempFileName);
const project = this.projectService.getProjectForFile(file);
if (project) {
if (project && !project.languageServiceDiabled) {
project.compilerService.host.saveTo(file, tmpfile);
}
}
@@ -858,7 +888,7 @@ namespace ts.server {
this.projectService.closeClientFile(file);
}
private decorateNavigationBarItem(project: Project, fileName: string, items: ts.NavigationBarItem[]): protocol.NavigationBarItem[] {
private decorateNavigationBarItem(project: Project, fileName: string, items: ts.NavigationBarItem[], lineIndex: LineIndex): protocol.NavigationBarItem[] {
if (!items) {
return undefined;
}
@@ -870,10 +900,10 @@ namespace ts.server {
kind: item.kind,
kindModifiers: item.kindModifiers,
spans: item.spans.map(span => ({
start: compilerService.host.positionToLineOffset(fileName, span.start),
end: compilerService.host.positionToLineOffset(fileName, ts.textSpanEnd(span))
start: compilerService.host.positionToLineOffset(fileName, span.start, lineIndex),
end: compilerService.host.positionToLineOffset(fileName, ts.textSpanEnd(span), lineIndex)
})),
childItems: this.decorateNavigationBarItem(project, fileName, item.childItems),
childItems: this.decorateNavigationBarItem(project, fileName, item.childItems, lineIndex),
indent: item.indent
}));
}
@@ -881,7 +911,7 @@ namespace ts.server {
private getNavigationBarItems(fileName: string): protocol.NavigationBarItem[] {
const file = ts.normalizePath(fileName);
const project = this.projectService.getProjectForFile(file);
if (!project) {
if (!project || project.languageServiceDiabled) {
throw Errors.NoProject;
}
@@ -891,20 +921,20 @@ namespace ts.server {
return undefined;
}
return this.decorateNavigationBarItem(project, fileName, items);
return this.decorateNavigationBarItem(project, fileName, items, compilerService.host.getLineIndex(fileName));
}
private getNavigateToItems(searchValue: string, fileName: string, maxResultCount?: number): protocol.NavtoItem[] {
const file = ts.normalizePath(fileName);
const info = this.projectService.getScriptInfo(file);
const projects = this.projectService.findReferencingProjects(info);
const defaultProject = projects[0];
if (!defaultProject) {
const projectsWithLanguageServiceEnabeld = ts.filter(projects, p => !p.languageServiceDiabled);
if (projectsWithLanguageServiceEnabeld.length === 0) {
throw Errors.NoProject;
}
const allNavToItems = combineProjectOutput(
projects,
projectsWithLanguageServiceEnabeld,
(project: Project) => {
const compilerService = project.compilerService;
const navItems = compilerService.languageService.getNavigateToItems(searchValue, maxResultCount);
@@ -956,7 +986,7 @@ namespace ts.server {
const file = ts.normalizePath(fileName);
const project = this.projectService.getProjectForFile(file);
if (!project) {
if (!project || project.languageServiceDiabled) {
throw Errors.NoProject;
}
@@ -975,7 +1005,11 @@ namespace ts.server {
}
getDiagnosticsForProject(delay: number, fileName: string) {
const { fileNames } = this.getProjectInfo(fileName, /*needFileNameList*/ true);
const { fileNames, languageServiceDisabled } = this.getProjectInfo(fileName, /*needFileNameList*/ true);
if (languageServiceDisabled) {
return;
}
// No need to analyze lib.d.ts
let fileNamesInProject = fileNames.filter((value, index, array) => value.indexOf("lib.d.ts") < 0);
@@ -1023,6 +1057,10 @@ namespace ts.server {
exit() {
}
private requiredResponse(response: any) {
return { response, responseRequired: true };
}
private handlers: Map<(request: protocol.Request) => { response?: any, responseRequired?: boolean }> = {
[CommandNames.Exit]: () => {
this.exit();
@@ -1091,6 +1129,12 @@ namespace ts.server {
const signatureHelpArgs = <protocol.SignatureHelpRequestArgs>request.arguments;
return { response: this.getSignatureHelpItems(signatureHelpArgs.line, signatureHelpArgs.offset, signatureHelpArgs.file), responseRequired: true };
},
[CommandNames.SemanticDiagnosticsSync]: (request: protocol.FileRequest) => {
return this.requiredResponse(this.getSemanticDiagnosticsSync(request.arguments));
},
[CommandNames.SyntacticDiagnosticsSync]: (request: protocol.FileRequest) => {
return this.requiredResponse(this.getSyntacticDiagnosticsSync(request.arguments));
},
[CommandNames.Geterr]: (request: protocol.Request) => {
const geterrArgs = <protocol.GeterrRequestArgs>request.arguments;
return { response: this.getDiagnostics(geterrArgs.delay, geterrArgs.files), responseRequired: false };
@@ -1114,7 +1158,7 @@ namespace ts.server {
[CommandNames.Reload]: (request: protocol.Request) => {
const reloadArgs = <protocol.ReloadRequestArgs>request.arguments;
this.reload(reloadArgs.file, reloadArgs.tmpfile, request.seq);
return {response: { reloadFinished: true }, responseRequired: true};
return { response: { reloadFinished: true }, responseRequired: true };
},
[CommandNames.Saveto]: (request: protocol.Request) => {
const savetoArgs = <protocol.SavetoRequestArgs>request.arguments;
+6 -3
View File
@@ -4,13 +4,16 @@
"removeComments": true,
"preserveConstEnums": true,
"out": "../../built/local/tsserver.js",
"sourceMap": true
"sourceMap": true,
"stripInternal": true
},
"files": [
"../services/shims.ts",
"../services/utilities.ts",
"node.d.ts",
"editorServices.ts",
"protocol.d.ts",
"server.ts",
"session.ts"
"session.ts",
"server.ts"
]
}
+10 -4
View File
@@ -78,7 +78,7 @@ namespace ts.formatting {
// 1. the end of the previous line
// 2. the last non-whitespace character in the current line
let endOfFormatSpan = getEndLinePosition(line, sourceFile);
while (isWhiteSpace(sourceFile.text.charCodeAt(endOfFormatSpan)) && !isLineBreak(sourceFile.text.charCodeAt(endOfFormatSpan))) {
while (isWhiteSpaceSingleLine(sourceFile.text.charCodeAt(endOfFormatSpan))) {
endOfFormatSpan--;
}
// if the character at the end of the span is a line break, we shouldn't include it, because it indicates we don't want to
@@ -394,7 +394,10 @@ namespace ts.formatting {
const startLinePosition = getLineStartPositionForPosition(startPos, sourceFile);
const column = SmartIndenter.findFirstNonWhitespaceColumn(startLinePosition, startPos, sourceFile, options);
if (startLine !== parentStartLine || startPos === column) {
return column;
// Use the base indent size if it is greater than
// the indentation of the inherited predecessor.
const baseIndentSize = SmartIndenter.getBaseIndentation(options);
return baseIndentSize > column ? baseIndentSize : column;
}
}
@@ -596,6 +599,9 @@ namespace ts.formatting {
// child node is outside the target range - do not dive inside
if (!rangeOverlapsWithStartEnd(originalRange, child.pos, child.end)) {
if (child.end < originalRange.pos) {
formattingScanner.skipToEndOf(child);
}
return inheritedIndentation;
}
@@ -960,7 +966,7 @@ namespace ts.formatting {
const whitespaceStart = getTrailingWhitespaceStartPosition(lineStartPosition, lineEndPosition);
if (whitespaceStart !== -1) {
Debug.assert(whitespaceStart === lineStartPosition || !isWhiteSpace(sourceFile.text.charCodeAt(whitespaceStart - 1)));
Debug.assert(whitespaceStart === lineStartPosition || !isWhiteSpaceSingleLine(sourceFile.text.charCodeAt(whitespaceStart - 1)));
recordDelete(whitespaceStart, lineEndPosition + 1 - whitespaceStart);
}
}
@@ -972,7 +978,7 @@ namespace ts.formatting {
*/
function getTrailingWhitespaceStartPosition(start: number, end: number) {
let pos = end;
while (pos >= start && isWhiteSpace(sourceFile.text.charCodeAt(pos))) {
while (pos >= start && isWhiteSpaceSingleLine(sourceFile.text.charCodeAt(pos))) {
pos--;
}
if (pos !== end) {
+16 -4
View File
@@ -17,6 +17,7 @@ namespace ts.formatting {
readTokenInfo(n: Node): TokenInfo;
getCurrentLeadingTrivia(): TextRangeWithKind[];
lastTrailingTriviaWasNewLine(): boolean;
skipToEndOf(node: Node): void;
close(): void;
}
@@ -36,12 +37,12 @@ namespace ts.formatting {
scanner.setTextPos(startPos);
let wasNewLine = true;
let leadingTrivia: TextRangeWithKind[];
let trailingTrivia: TextRangeWithKind[];
let leadingTrivia: TextRangeWithKind[] | undefined;
let trailingTrivia: TextRangeWithKind[] | undefined;
let savedPos: number;
let lastScanAction: ScanAction;
let lastTokenInfo: TokenInfo;
let lastScanAction: ScanAction | undefined;
let lastTokenInfo: TokenInfo | undefined;
return {
advance,
@@ -49,6 +50,7 @@ namespace ts.formatting {
isOnToken,
getCurrentLeadingTrivia: () => leadingTrivia,
lastTrailingTriviaWasNewLine: () => wasNewLine,
skipToEndOf,
close: () => {
Debug.assert(scanner !== undefined);
@@ -278,5 +280,15 @@ namespace ts.formatting {
}
return tokenInfo;
}
function skipToEndOf(node: Node): void {
scanner.setTextPos(node.end);
savedPos = scanner.getStartPos();
lastScanAction = undefined;
lastTokenInfo = undefined;
wasNewLine = false;
leadingTrivia = undefined;
trailingTrivia = undefined;
}
}
}
+32 -6
View File
@@ -225,6 +225,12 @@ namespace ts.formatting {
public NoSpaceBeforeTemplateMiddleAndTail: Rule;
public SpaceBeforeTemplateMiddleAndTail: Rule;
// No space after { and before } in JSX expression
public NoSpaceAfterOpenBraceInJsxExpression: Rule;
public SpaceAfterOpenBraceInJsxExpression: Rule;
public NoSpaceBeforeCloseBraceInJsxExpression: Rule;
public SpaceBeforeCloseBraceInJsxExpression: Rule;
constructor() {
///
/// Common Rules
@@ -264,7 +270,7 @@ namespace ts.formatting {
this.SpaceBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext, Rules.IsBeforeBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);
// Place a space before open brace in a TypeScript declaration that has braces as children (class, module, enum, etc)
this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.ClassKeyword]);
this.TypeScriptOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.ClassKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ImportKeyword]);
this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsTypeScriptDeclWithBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeMultilineBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);
// Place a space before open brace in a control flow construct
@@ -316,7 +322,7 @@ namespace ts.formatting {
// 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]
this.SpaceBetweenStatements = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.DoKeyword, SyntaxKind.ElseKeyword, SyntaxKind.CaseKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNotForContext), RuleAction.Space));
this.SpaceBetweenStatements = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.DoKeyword, SyntaxKind.ElseKeyword, SyntaxKind.CaseKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.isNonJsxElementContext, Rules.IsNotForContext), RuleAction.Space));
// This low-pri rule takes care of "try {" and "finally {" in case the rule SpaceBeforeOpenBraceInControl didn't execute on FormatOnEnter.
this.SpaceAfterTryFinally = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.TryKeyword, SyntaxKind.FinallyKeyword]), SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
@@ -338,8 +344,8 @@ namespace ts.formatting {
this.NoSpaceAfterModuleImport = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.ModuleKeyword, SyntaxKind.RequireKeyword]), SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
// Add a space around certain TypeScript keywords
this.SpaceAfterCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.AbstractKeyword, SyntaxKind.ClassKeyword, SyntaxKind.DeclareKeyword, SyntaxKind.DefaultKeyword, SyntaxKind.EnumKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ExtendsKeyword, SyntaxKind.GetKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.ImportKeyword, SyntaxKind.InterfaceKeyword, SyntaxKind.ModuleKeyword, SyntaxKind.NamespaceKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.PublicKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.SetKeyword, SyntaxKind.StaticKeyword, SyntaxKind.TypeKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
this.SpaceBeforeCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.ExtendsKeyword, SyntaxKind.ImplementsKeyword])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
this.SpaceAfterCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.AbstractKeyword, SyntaxKind.ClassKeyword, SyntaxKind.DeclareKeyword, SyntaxKind.DefaultKeyword, SyntaxKind.EnumKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ExtendsKeyword, SyntaxKind.GetKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.ImportKeyword, SyntaxKind.InterfaceKeyword, SyntaxKind.ModuleKeyword, SyntaxKind.NamespaceKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.PublicKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.SetKeyword, SyntaxKind.StaticKeyword, SyntaxKind.TypeKeyword, SyntaxKind.FromKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
this.SpaceBeforeCertainTypeScriptKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.ExtendsKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.FromKeyword])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
// Treat string literals in module names as identifiers, and add a space between the literal and the opening Brace braces, e.g.: module "m2" {
this.SpaceAfterModuleName = new Rule(RuleDescriptor.create1(SyntaxKind.StringLiteral, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsModuleDeclContext), RuleAction.Space));
@@ -444,8 +450,8 @@ namespace ts.formatting {
///
// Insert space after comma delimiter
this.SpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNextTokenNotCloseBracket), RuleAction.Space));
this.NoSpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
this.SpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.isNonJsxElementContext, Rules.IsNextTokenNotCloseBracket), RuleAction.Space));
this.NoSpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.isNonJsxElementContext), RuleAction.Delete));
// Insert space before and after binary operators
this.SpaceBeforeBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
@@ -491,6 +497,12 @@ namespace ts.formatting {
this.NoSpaceBeforeTemplateMiddleAndTail = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
this.SpaceBeforeTemplateMiddleAndTail = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
// No space after { and before } in JSX expression
this.NoSpaceAfterOpenBraceInJsxExpression = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.isJsxExpressionContext), RuleAction.Delete));
this.SpaceAfterOpenBraceInJsxExpression = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.isJsxExpressionContext), RuleAction.Space));
this.NoSpaceBeforeCloseBraceInJsxExpression = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.isJsxExpressionContext), RuleAction.Delete));
this.SpaceBeforeCloseBraceInJsxExpression = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.isJsxExpressionContext), RuleAction.Space));
// Insert space after function keyword for anonymous functions
this.SpaceAfterAnonymousFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space));
this.NoSpaceAfterAnonymousFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Delete));
@@ -514,6 +526,8 @@ namespace ts.formatting {
case SyntaxKind.BinaryExpression:
case SyntaxKind.ConditionalExpression:
case SyntaxKind.AsExpression:
case SyntaxKind.ExportSpecifier:
case SyntaxKind.ImportSpecifier:
case SyntaxKind.TypePredicate:
case SyntaxKind.UnionType:
case SyntaxKind.IntersectionType:
@@ -650,6 +664,10 @@ namespace ts.formatting {
case SyntaxKind.EnumDeclaration:
case SyntaxKind.TypeLiteral:
case SyntaxKind.ModuleDeclaration:
case SyntaxKind.ExportDeclaration:
case SyntaxKind.NamedExports:
case SyntaxKind.ImportDeclaration:
case SyntaxKind.NamedImports:
return true;
}
@@ -723,6 +741,14 @@ namespace ts.formatting {
return context.TokensAreOnSameLine() && context.contextNode.kind !== SyntaxKind.JsxText;
}
static isNonJsxElementContext(context: FormattingContext): boolean {
return context.contextNode.kind !== SyntaxKind.JsxElement;
}
static isJsxExpressionContext(context: FormattingContext): boolean {
return context.contextNode.kind === SyntaxKind.JsxExpression;
}
static IsNotBeforeBlockInFunctionDeclarationContext(context: FormattingContext): boolean {
return !Rules.IsFunctionDeclContext(context) && !Rules.IsBeforeBlockContext(context);
}
+9
View File
@@ -90,6 +90,15 @@ namespace ts.formatting {
rules.push(this.globalRules.NoSpaceBeforeTemplateMiddleAndTail);
}
if (options.InsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces) {
rules.push(this.globalRules.SpaceAfterOpenBraceInJsxExpression);
rules.push(this.globalRules.SpaceBeforeCloseBraceInJsxExpression);
}
else {
rules.push(this.globalRules.NoSpaceAfterOpenBraceInJsxExpression);
rules.push(this.globalRules.NoSpaceBeforeCloseBraceInJsxExpression);
}
if (options.InsertSpaceAfterSemicolonInForStatements) {
rules.push(this.globalRules.SpaceAfterSemicolonInFor);
}
+19 -7
View File
@@ -10,7 +10,7 @@ namespace ts.formatting {
export function getIndentation(position: number, sourceFile: SourceFile, options: EditorOptions): number {
if (position > sourceFile.text.length) {
return 0; // past EOF
return getBaseIndentation(options); // past EOF
}
// no indentation when the indent style is set to none,
@@ -21,7 +21,7 @@ namespace ts.formatting {
const precedingToken = findPrecedingToken(position, sourceFile);
if (!precedingToken) {
return 0;
return getBaseIndentation(options);
}
// no indentation in string \regex\template literals
@@ -42,7 +42,7 @@ namespace ts.formatting {
let current = position;
while (current > 0) {
const char = sourceFile.text.charCodeAt(current);
if (!isWhiteSpace(char) && !isLineBreak(char)) {
if (!isWhiteSpace(char)) {
break;
}
current--;
@@ -96,13 +96,17 @@ namespace ts.formatting {
}
if (!current) {
// no parent was found - return 0 to be indented on the level of SourceFile
return 0;
// no parent was found - return the base indentation of the SourceFile
return getBaseIndentation(options);
}
return getIndentationForNodeWorker(current, currentStart, /*ignoreActualIndentationRange*/ undefined, indentationDelta, sourceFile, options);
}
export function getBaseIndentation(options: EditorOptions) {
return options.BaseIndentSize || 0;
}
export function getIndentationForNode(n: Node, ignoreActualIndentationRange: TextRange, sourceFile: SourceFile, options: FormatCodeOptions): number {
const start = sourceFile.getLineAndCharacterOfPosition(n.getStart(sourceFile));
return getIndentationForNodeWorker(n, start, ignoreActualIndentationRange, /*indentationDelta*/ 0, sourceFile, options);
@@ -162,7 +166,7 @@ namespace ts.formatting {
parent = current.parent;
}
return indentationDelta;
return indentationDelta + getBaseIndentation(options);
}
@@ -402,7 +406,7 @@ namespace ts.formatting {
let column = 0;
for (let pos = startPos; pos < endPos; pos++) {
const ch = sourceFile.text.charCodeAt(pos);
if (!isWhiteSpace(ch)) {
if (!isWhiteSpaceSingleLine(ch)) {
break;
}
@@ -462,7 +466,10 @@ namespace ts.formatting {
case SyntaxKind.ParenthesizedType:
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.AwaitExpression:
case SyntaxKind.NamedExports:
case SyntaxKind.NamedImports:
case SyntaxKind.ExportSpecifier:
case SyntaxKind.ImportSpecifier:
return true;
}
return false;
@@ -486,6 +493,11 @@ namespace ts.formatting {
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
return childKind !== SyntaxKind.Block;
case SyntaxKind.ExportDeclaration:
return childKind !== SyntaxKind.NamedExports;
case SyntaxKind.ImportDeclaration:
return childKind !== SyntaxKind.ImportClause ||
((<ImportClause>child).namedBindings && (<ImportClause>child).namedBindings.kind !== SyntaxKind.NamedImports);
case SyntaxKind.JsxElement:
return childKind !== SyntaxKind.JsxClosingElement;
}
+2 -2
View File
@@ -10,7 +10,7 @@ namespace ts.JsTyping {
directoryExists: (path: string) => boolean;
fileExists: (fileName: string) => boolean;
readFile: (path: string, encoding?: string) => string;
readDirectory: (path: string, extension?: string, exclude?: string[], depth?: number) => string[];
readDirectory: (rootDir: string, extensions: string[], excludes: string[], includes: string[], depth?: number) => string[];
};
interface PackageJson {
@@ -187,7 +187,7 @@ namespace ts.JsTyping {
}
const typingNames: string[] = [];
const fileNames = host.readDirectory(nodeModulesPath, "*.json", /*exclude*/ undefined, /*depth*/ 2);
const fileNames = host.readDirectory(nodeModulesPath, ["*.json"], /*excludes*/ undefined, /*includes*/ undefined, /*depth*/ 2);
for (const fileName of fileNames) {
const normalizedFileName = normalizePath(fileName);
if (getBaseFileName(normalizedFileName) !== "package.json") {
File diff suppressed because it is too large Load Diff
+57 -27
View File
@@ -1,4 +1,5 @@
/// <reference path="..\compiler\program.ts"/>
/// <reference path="..\compiler\commandLineParser.ts"/>
/// <reference path='breakpoints.ts' />
/// <reference path='outliningElementsCollector.ts' />
@@ -479,8 +480,7 @@ namespace ts {
for (; pos < end; pos++) {
const ch = sourceFile.text.charCodeAt(pos);
if (!isWhiteSpace(ch) || isLineBreak(ch)) {
// Either found lineBreak or non whiteSpace
if (!isWhiteSpaceSingleLine(ch)) {
return pos;
}
}
@@ -499,8 +499,7 @@ namespace ts {
function isName(pos: number, end: number, sourceFile: SourceFile, name: string) {
return pos + name.length < end &&
sourceFile.text.substr(pos, name.length) === name &&
(isWhiteSpace(sourceFile.text.charCodeAt(pos + name.length)) ||
isLineBreak(sourceFile.text.charCodeAt(pos + name.length)));
isWhiteSpace(sourceFile.text.charCodeAt(pos + name.length));
}
function isParamTag(pos: number, end: number, sourceFile: SourceFile) {
@@ -695,7 +694,7 @@ namespace ts {
return paramDocComments;
function consumeWhiteSpaces(pos: number) {
while (pos < end && isWhiteSpace(sourceFile.text.charCodeAt(pos))) {
while (pos < end && isWhiteSpaceSingleLine(sourceFile.text.charCodeAt(pos))) {
pos++;
}
@@ -784,7 +783,7 @@ namespace ts {
declaration: SignatureDeclaration;
typeParameters: TypeParameter[];
parameters: Symbol[];
thisType: Type;
thisParameter: Symbol;
resolvedReturnType: Type;
minArgumentCount: number;
hasRestParameter: boolean;
@@ -1152,7 +1151,7 @@ namespace ts {
getDocCommentTemplateAtPosition(fileName: string, position: number): TextInsertion;
isValidBraceCompletionAtPostion(fileName: string, position: number, openingBrace: number): boolean;
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean;
getEmitOutput(fileName: string): EmitOutput;
@@ -1249,6 +1248,7 @@ namespace ts {
}
export interface EditorOptions {
BaseIndentSize?: number;
IndentSize: number;
TabSize: number;
NewLineCharacter: string;
@@ -1271,9 +1271,10 @@ namespace ts {
InsertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: boolean;
InsertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: boolean;
InsertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: boolean;
InsertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces?: boolean;
PlaceOpenBraceOnNewLineForFunctions: boolean;
PlaceOpenBraceOnNewLineForControlBlocks: boolean;
[s: string]: boolean | number | string;
[s: string]: boolean | number | string | undefined;
}
export interface DefinitionInfo {
@@ -2007,6 +2008,18 @@ namespace ts {
// so pass --noLib to avoid reporting a file not found error.
options.noLib = true;
// Clear out other settings that would not be used in transpiling this module
options.lib = undefined;
options.types = undefined;
options.noEmit = undefined;
options.noEmitOnError = undefined;
options.paths = undefined;
options.rootDirs = undefined;
options.declaration = undefined;
options.declarationDir = undefined;
options.out = undefined;
options.outFile = undefined;
// We are not doing a full typecheck, we are not resolving the whole context,
// so pass --noResolve to avoid reporting missing file errors.
options.noResolve = true;
@@ -2989,7 +3002,8 @@ namespace ts {
oldSettings.moduleResolution !== newSettings.moduleResolution ||
oldSettings.noResolve !== newSettings.noResolve ||
oldSettings.jsx !== newSettings.jsx ||
oldSettings.allowJs !== newSettings.allowJs);
oldSettings.allowJs !== newSettings.allowJs ||
oldSettings.disableSizeLimit !== oldSettings.disableSizeLimit);
// Now create a new compiler
const compilerHost: CompilerHost = {
@@ -5722,7 +5736,7 @@ namespace ts {
// Avoid recalculating getStart() by iterating backwards.
for (let j = ifKeyword.getStart() - 1; j >= elseKeyword.end; j--) {
if (!isWhiteSpace(sourceFile.text.charCodeAt(j))) {
if (!isWhiteSpaceSingleLine(sourceFile.text.charCodeAt(j))) {
shouldCombindElseAndIf = false;
break;
}
@@ -5816,17 +5830,32 @@ namespace ts {
return undefined;
}
if (node.kind !== SyntaxKind.Identifier &&
// TODO (drosen): This should be enabled in a later release - currently breaks rename.
// node.kind !== SyntaxKind.ThisKeyword &&
// node.kind !== SyntaxKind.SuperKeyword &&
node.kind !== SyntaxKind.StringLiteral &&
!isLiteralNameOfPropertyDeclarationOrIndexAccess(node)) {
return undefined;
switch (node.kind) {
case SyntaxKind.NumericLiteral:
if (!isLiteralNameOfPropertyDeclarationOrIndexAccess(node)) {
break;
}
// Fallthrough
case SyntaxKind.Identifier:
case SyntaxKind.ThisKeyword:
// case SyntaxKind.SuperKeyword: TODO:GH#9268
case SyntaxKind.StringLiteral:
return getReferencedSymbolsForNode(node, program.getSourceFiles(), findInStrings, findInComments);
}
return undefined;
}
Debug.assert(node.kind === SyntaxKind.Identifier || node.kind === SyntaxKind.NumericLiteral || node.kind === SyntaxKind.StringLiteral);
return getReferencedSymbolsForNode(node, program.getSourceFiles(), findInStrings, findInComments);
function isThis(node: Node): boolean {
switch (node.kind) {
case SyntaxKind.ThisKeyword:
// case SyntaxKind.ThisType: TODO: GH#9267
return true;
case SyntaxKind.Identifier:
// 'this' as a parameter
return (node as Identifier).originalKeywordKind === SyntaxKind.ThisKeyword && node.parent.kind === SyntaxKind.Parameter;
default:
return false;
}
}
function getReferencedSymbolsForNode(node: Node, sourceFiles: SourceFile[], findInStrings: boolean, findInComments: boolean): ReferencedSymbol[] {
@@ -5846,7 +5875,7 @@ namespace ts {
}
}
if (node.kind === SyntaxKind.ThisKeyword || node.kind === SyntaxKind.ThisType) {
if (isThis(node)) {
return getReferencesForThisKeyword(node, sourceFiles);
}
@@ -6381,7 +6410,7 @@ namespace ts {
cancellationToken.throwIfCancellationRequested();
const node = getTouchingWord(sourceFile, position);
if (!node || (node.kind !== SyntaxKind.ThisKeyword && node.kind !== SyntaxKind.ThisType)) {
if (!node || !isThis(node)) {
return;
}
@@ -7044,7 +7073,7 @@ namespace ts {
function getNavigationBarItems(fileName: string): NavigationBarItem[] {
const sourceFile = syntaxTreeCache.getCurrentSourceFile(fileName);
return NavigationBar.getNavigationBarItems(sourceFile, host.getCompilationSettings());
return NavigationBar.getNavigationBarItems(sourceFile);
}
function getSemanticClassifications(fileName: string, span: TextSpan): ClassifiedSpan[] {
@@ -7538,7 +7567,8 @@ namespace ts {
return;
case SyntaxKind.Parameter:
if ((<ParameterDeclaration>token.parent).name === token) {
return ClassificationType.parameterName;
const isThis = token.kind === SyntaxKind.Identifier && (<Identifier>token).originalKeywordKind === SyntaxKind.ThisKeyword;
return isThis ? ClassificationType.keyword : ClassificationType.parameterName;
}
return;
}
@@ -7765,7 +7795,7 @@ namespace ts {
return { newText: result, caretOffset: preamble.length };
}
function isValidBraceCompletionAtPostion(fileName: string, position: number, openingBrace: number): boolean {
function isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): boolean {
// '<' is currently not supported, figuring out if we're in a Generic Type vs. a comparison is too
// expensive to do during typing scenarios
@@ -8008,11 +8038,11 @@ namespace ts {
const node = getTouchingWord(sourceFile, position, /*includeJsDocComment*/ true);
// Can only rename an identifier.
if (node) {
if (node.kind === SyntaxKind.Identifier ||
node.kind === SyntaxKind.StringLiteral ||
isLiteralNameOfPropertyDeclarationOrIndexAccess(node)) {
isLiteralNameOfPropertyDeclarationOrIndexAccess(node) ||
isThis(node)) {
const symbol = typeChecker.getSymbolAtLocation(node);
// Only allow a symbol to be renamed if it actually has at least one declaration.
@@ -8133,7 +8163,7 @@ namespace ts {
getFormattingEditsForDocument,
getFormattingEditsAfterKeystroke,
getDocCommentTemplateAtPosition,
isValidBraceCompletionAtPostion,
isValidBraceCompletionAtPosition,
getEmitOutput,
getNonBoundSourceFile,
getProgram
+53 -14
View File
@@ -61,7 +61,7 @@ namespace ts {
getLocalizedDiagnosticMessages(): string;
getCancellationToken(): HostCancellationToken;
getCurrentDirectory(): string;
getDirectories(path: string): string[];
getDirectories(path: string): string;
getDefaultLibFileName(options: string): string;
getNewLine?(): string;
getProjectVersion?(): string;
@@ -80,8 +80,9 @@ namespace ts {
* @param exclude A JSON encoded string[] containing the paths to exclude
* when enumerating the directory.
*/
readDirectory(rootDir: string, extension: string, exclude?: string, depth?: number): string;
readDirectory(rootDir: string, extension: string, basePaths?: string, excludeEx?: string, includeFileEx?: string, includeDirEx?: string, depth?: number): string;
useCaseSensitiveFileNames?(): boolean;
getCurrentDirectory(): string;
trace(s: string): void;
}
@@ -227,9 +228,10 @@ namespace ts {
* at the current position.
* E.g. we don't want brace completion inside string-literals, comments, etc.
*/
isValidBraceCompletionAtPostion(fileName: string, position: number, openingBrace: number): string;
isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): string;
getEmitOutput(fileName: string): string;
getEmitOutputObject(fileName: string): EmitOutput;
}
export interface ClassifierShim extends Shim {
@@ -402,7 +404,7 @@ namespace ts {
}
public getDirectories(path: string): string[] {
return this.shimHost.getDirectories(path);
return JSON.parse(this.shimHost.getDirectories(path));
}
public getDefaultLibFileName(options: CompilerOptions): string {
@@ -437,8 +439,10 @@ namespace ts {
public directoryExists: (directoryName: string) => boolean;
public realpath: (path: string) => string;
public useCaseSensitiveFileNames: boolean;
constructor(private shimHost: CoreServicesShimHost) {
this.useCaseSensitiveFileNames = this.shimHost.useCaseSensitiveFileNames ? this.shimHost.useCaseSensitiveFileNames() : false;
if ("directoryExists" in this.shimHost) {
this.directoryExists = directoryName => this.shimHost.directoryExists(directoryName);
}
@@ -447,17 +451,34 @@ namespace ts {
}
}
public readDirectory(rootDir: string, extension: string, exclude: string[], depth?: number): string[] {
public readDirectory(rootDir: string, extensions: string[], exclude: string[], include: string[], depth?: number): string[] {
// Wrap the API changes for 2.0 release. This try/catch
// should be removed once TypeScript 2.0 has shipped.
let encoded: string;
try {
encoded = this.shimHost.readDirectory(rootDir, extension, JSON.stringify(exclude), depth);
const pattern = getFileMatcherPatterns(rootDir, extensions, exclude, include,
this.shimHost.useCaseSensitiveFileNames(), this.shimHost.getCurrentDirectory());
return JSON.parse(this.shimHost.readDirectory(
rootDir,
JSON.stringify(extensions),
JSON.stringify(pattern.basePaths),
pattern.excludePattern,
pattern.includeFilePattern,
pattern.includeDirectoryPattern,
depth
));
}
catch (e) {
encoded = this.shimHost.readDirectory(rootDir, extension, JSON.stringify(exclude));
const results: string[] = [];
for (const extension of extensions) {
for (const file of this.readDirectoryFallback(rootDir, extension, exclude))
{
if (!contains(results, file)) {
results.push(file);
}
}
}
return results;
}
return JSON.parse(encoded);
}
public fileExists(fileName: string): boolean {
@@ -467,6 +488,10 @@ namespace ts {
public readFile(fileName: string): string {
return this.shimHost.readFile(fileName);
}
private readDirectoryFallback(rootDir: string, extension: string, exclude: string[]) {
return JSON.parse(this.shimHost.readDirectory(rootDir, extension, JSON.stringify(exclude)));
}
}
function simpleForwardCall(logger: Logger, actionDescription: string, action: () => any, logPerformance: boolean): any {
@@ -494,9 +519,13 @@ namespace ts {
}
function forwardJSONCall(logger: Logger, actionDescription: string, action: () => any, logPerformance: boolean): string {
return <string>forwardCall(logger, actionDescription, /*returnJson*/ true, action, logPerformance);
}
function forwardCall<T>(logger: Logger, actionDescription: string, returnJson: boolean, action: () => T, logPerformance: boolean): T | string {
try {
const result = simpleForwardCall(logger, actionDescription, action, logPerformance);
return JSON.stringify({ result });
return returnJson ? JSON.stringify({ result }) : result;
}
catch (err) {
if (err instanceof OperationCanceledException) {
@@ -508,6 +537,7 @@ namespace ts {
}
}
class ShimBase implements Shim {
constructor(private factory: ShimFactory) {
factory.registerShim(this);
@@ -749,10 +779,10 @@ namespace ts {
);
}
public isValidBraceCompletionAtPostion(fileName: string, position: number, openingBrace: number): string {
public isValidBraceCompletionAtPosition(fileName: string, position: number, openingBrace: number): string {
return this.forwardJSONCall(
`isValidBraceCompletionAtPostion('${fileName}', ${position}, ${openingBrace})`,
() => this.languageService.isValidBraceCompletionAtPostion(fileName, position, openingBrace)
`isValidBraceCompletionAtPosition('${fileName}', ${position}, ${openingBrace})`,
() => this.languageService.isValidBraceCompletionAtPosition(fileName, position, openingBrace)
);
}
@@ -894,6 +924,15 @@ namespace ts {
() => this.languageService.getEmitOutput(fileName)
);
}
public getEmitOutputObject(fileName: string): any {
return forwardCall(
this.logger,
`getEmitOutput('${fileName}')`,
/*returnJson*/ false,
() => this.languageService.getEmitOutput(fileName),
this.logPerformance);
}
}
function convertClassifications(classifications: Classifications): { spans: string, endOfLineState: EndOfLineState } {
+5 -5
View File
@@ -357,8 +357,8 @@ namespace ts.SignatureHelp {
}
function getArgumentIndex(argumentsList: Node, node: Node) {
// The list we got back can include commas. In the presence of errors it may
// also just have nodes without commas. For example "Foo(a b c)" will have 3
// The list we got back can include commas. In the presence of errors it may
// also just have nodes without commas. For example "Foo(a b c)" will have 3
// args without commas. We want to find what index we're at. So we count
// forward until we hit ourselves, only incrementing the index if it isn't a
// comma.
@@ -390,8 +390,8 @@ namespace ts.SignatureHelp {
// 'a' '<comma>'. So, in the case where the last child is a comma, we increase the
// arg count by one to compensate.
//
// Note: this subtlety only applies to the last comma. If you had "Foo(a,," then
// we'll have: 'a' '<comma>' '<missing>'
// Note: this subtlety only applies to the last comma. If you had "Foo(a,," then
// we'll have: 'a' '<comma>' '<missing>'
// That will give us 2 non-commas. We then add one for the last comma, givin us an
// arg count of 3.
const listChildren = argumentsList.getChildren();
@@ -563,7 +563,7 @@ namespace ts.SignatureHelp {
signatureHelpParameters = typeParameters && typeParameters.length > 0 ? map(typeParameters, createSignatureHelpParameterForTypeParameter) : emptyArray;
suffixDisplayParts.push(punctuationPart(SyntaxKind.GreaterThanToken));
const parameterParts = mapToDisplayParts(writer =>
typeChecker.getSymbolDisplayBuilder().buildDisplayForParametersAndDelimiters(candidateSignature.thisType, candidateSignature.parameters, writer, invocation));
typeChecker.getSymbolDisplayBuilder().buildDisplayForParametersAndDelimiters(candidateSignature.thisParameter, candidateSignature.parameters, writer, invocation));
addRange(suffixDisplayParts, parameterParts);
}
else {
+8 -5
View File
@@ -1,10 +1,13 @@
{
"compilerOptions": {
"noImplicitAny": true,
"removeComments": true,
"removeComments": false,
"preserveConstEnums": true,
"out": "../../built/local/typescriptServices.js",
"sourceMap": true
"outFile": "../../built/local/typescriptServices.js",
"sourceMap": true,
"stripInternal": true,
"noResolve": false,
"declaration": true
},
"files": [
"../compiler/core.ts",
@@ -29,11 +32,11 @@
"../compiler/transformer.ts",
"../compiler/comments.ts",
"../compiler/sourcemap.ts",
"../compiler/declarationEmitter.ts",
"../compiler/emitter.ts",
"../compiler/program.ts",
"../compiler/declarationEmitter.ts",
"../compiler/diagnosticInformationMap.generated.ts",
"../compiler/commandLineParser.ts",
"../compiler/diagnosticInformationMap.generated.ts",
"breakpoints.ts",
"navigateTo.ts",
"navigationBar.ts",
+6
View File
@@ -53,6 +53,8 @@ namespace ts {
case SyntaxKind.Block:
case SyntaxKind.ModuleBlock:
case SyntaxKind.CaseBlock:
case SyntaxKind.NamedImports:
case SyntaxKind.NamedExports:
return nodeEndsWith(n, SyntaxKind.CloseBraceToken, sourceFile);
case SyntaxKind.CatchClause:
return isCompletedNode((<CatchClause>n).block, sourceFile);
@@ -156,6 +158,10 @@ namespace ts {
case SyntaxKind.TemplateSpan:
return nodeIsPresent((<TemplateSpan>n).literal);
case SyntaxKind.ExportDeclaration:
case SyntaxKind.ImportDeclaration:
return nodeIsPresent((<ExportDeclaration | ImportDeclaration>n).moduleSpecifier);
case SyntaxKind.PrefixUnaryExpression:
return isCompletedNode((<PrefixUnaryExpression>n).operand, sourceFile);
case SyntaxKind.BinaryExpression: