mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'transforms' into transforms-generators
This commit is contained in:
+101
-48
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
Vendored
+5
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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", () => {
|
||||
|
||||
@@ -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 () { });
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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: [] };
|
||||
}
|
||||
}
|
||||
}
|
||||
Vendored
+2477
-1937
File diff suppressed because it is too large
Load Diff
Vendored
+105
-15
@@ -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.
|
||||
|
||||
Vendored
+10
-10
@@ -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.
|
||||
|
||||
Vendored
+13
@@ -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;
|
||||
}
|
||||
|
||||
Vendored
+284
-85
@@ -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
@@ -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
@@ -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,
|
||||
});
|
||||
|
||||
Vendored
+34
-2
@@ -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
@@ -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;
|
||||
|
||||
@@ -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"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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") {
|
||||
|
||||
+586
-787
File diff suppressed because it is too large
Load Diff
+57
-27
@@ -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
@@ -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 } {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user