diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000000..f83d0f77c9e
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,15 @@
+[submodule "tests/cases/user/TypeScript-React-Starter/TypeScript-React-Starter"]
+ path = tests/cases/user/TypeScript-React-Starter/TypeScript-React-Starter
+ url = https://github.com/Microsoft/TypeScript-React-Starter
+[submodule "tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter"]
+ path = tests/cases/user/TypeScript-Node-Starter/TypeScript-Node-Starter
+ url = https://github.com/Microsoft/TypeScript-Node-Starter.git
+[submodule "tests/cases/user/TypeScript-React-Native-Starter/TypeScript-React-Native-Starter"]
+ path = tests/cases/user/TypeScript-React-Native-Starter/TypeScript-React-Native-Starter
+ url = https://github.com/Microsoft/TypeScript-React-Native-Starter.git
+[submodule "tests/cases/user/TypeScript-Vue-Starter/TypeScript-Vue-Starter"]
+ path = tests/cases/user/TypeScript-Vue-Starter/TypeScript-Vue-Starter
+ url = https://github.com/Microsoft/TypeScript-Vue-Starter.git
+[submodule "tests/cases/user/TypeScript-WeChat-Starter/TypeScript-WeChat-Starter"]
+ path = tests/cases/user/TypeScript-WeChat-Starter/TypeScript-WeChat-Starter
+ url = https://github.com/Microsoft/TypeScript-WeChat-Starter.git
diff --git a/Gulpfile.ts b/Gulpfile.ts
index a75882c5f46..aedde5c33d9 100644
--- a/Gulpfile.ts
+++ b/Gulpfile.ts
@@ -46,15 +46,15 @@ const cmdLineOptions = minimist(process.argv.slice(2), {
boolean: ["debug", "inspect", "light", "colors", "lint", "soft"],
string: ["browser", "tests", "host", "reporter", "stackTraceLimit", "timeout"],
alias: {
- b: "browser",
- d: "debug", "debug-brk": "debug",
- i: "inspect", "inspect-brk": "inspect",
- t: "tests", test: "tests",
- ru: "runners", runner: "runners",
- r: "reporter",
- c: "colors", color: "colors",
- f: "files", file: "files",
- w: "workers",
+ "b": "browser",
+ "d": "debug", "debug-brk": "debug",
+ "i": "inspect", "inspect-brk": "inspect",
+ "t": "tests", "test": "tests",
+ "ru": "runners", "runner": "runners",
+ "r": "reporter",
+ "c": "colors", "color": "colors",
+ "f": "files", "file": "files",
+ "w": "workers",
},
default: {
soft: false,
@@ -74,7 +74,8 @@ const cmdLineOptions = minimist(process.argv.slice(2), {
}
});
-function exec(cmd: string, args: string[], complete: () => void = (() => { }), error: (e: any, status: number) => void = (() => { })) {
+const noop = () => {}; // tslint:disable-line no-empty
+function exec(cmd: string, args: string[], complete: () => void = noop, error: (e: any, status: number) => void = noop) {
console.log(`${cmd} ${args.join(" ")}`);
// TODO (weswig): Update child_process types to add windowsVerbatimArguments to the type definition
const subshellFlag = isWin ? "/c" : "-c";
@@ -1034,7 +1035,7 @@ gulp.task("update-sublime", "Updates the sublime plugin's tsserver", ["local", s
});
gulp.task("build-rules", "Compiles tslint rules to js", () => {
- const settings: tsc.Settings = getCompilerSettings({ module: "commonjs", "lib": ["es6"] }, /*useBuiltCompiler*/ false);
+ const settings: tsc.Settings = getCompilerSettings({ module: "commonjs", lib: ["es6"] }, /*useBuiltCompiler*/ false);
const dest = path.join(builtLocalDirectory, "tslint");
return gulp.src("scripts/tslint/**/*.ts")
.pipe(newer({
diff --git a/Jakefile.js b/Jakefile.js
index 89fcb6500dd..4f39d6af5c6 100644
--- a/Jakefile.js
+++ b/Jakefile.js
@@ -105,7 +105,7 @@ var harnessCoreSources = [
"projectsRunner.ts",
"loggedIO.ts",
"rwcRunner.ts",
- "userRunner.ts",
+ "externalCompileRunner.ts",
"test262Runner.ts",
"./parallel/shared.ts",
"./parallel/host.ts",
@@ -731,7 +731,10 @@ compileFile(word2mdJs,
[word2mdTs],
[word2mdTs],
[],
- /*useBuiltCompiler*/ false);
+ /*useBuiltCompiler*/ false,
+ {
+ lib: "scripthost,es5"
+ });
// The generated spec.md; built for the 'generate-spec' task
file(specMd, [word2mdJs, specWord], function () {
diff --git a/scripts/processDiagnosticMessages.ts b/scripts/processDiagnosticMessages.ts
index 20085022c04..dd66564b134 100644
--- a/scripts/processDiagnosticMessages.ts
+++ b/scripts/processDiagnosticMessages.ts
@@ -1,4 +1,5 @@
///
+///
interface DiagnosticDetails {
category: string;
@@ -9,57 +10,55 @@ interface DiagnosticDetails {
type InputDiagnosticMessageTable = ts.Map;
function main(): void {
- var sys = ts.sys;
+ const sys = ts.sys;
if (sys.args.length < 1) {
- sys.write("Usage:" + sys.newLine)
+ sys.write("Usage:" + sys.newLine);
sys.write("\tnode processDiagnosticMessages.js " + sys.newLine);
return;
}
function writeFile(fileName: string, contents: string) {
- // TODO: Fix path joining
- var inputDirectory = inputFilePath.substr(0,inputFilePath.lastIndexOf("/"));
- var fileOutputPath = inputDirectory + "/" + fileName;
+ const inputDirectory = ts.getDirectoryPath(inputFilePath);
+ const fileOutputPath = ts.combinePaths(inputDirectory, fileName);
sys.writeFile(fileOutputPath, contents);
}
- var inputFilePath = sys.args[0].replace(/\\/g, "/");
- var inputStr = sys.readFile(inputFilePath);
+ const inputFilePath = sys.args[0].replace(/\\/g, "/");
+ const inputStr = sys.readFile(inputFilePath);
- var diagnosticMessagesJson: { [key: string]: DiagnosticDetails } = JSON.parse(inputStr);
- // Check that there are no duplicates.
- const seenNames = ts.createMap();
- for (const name of Object.keys(diagnosticMessagesJson)) {
- if (seenNames.has(name))
- throw new Error(`Name ${name} appears twice`);
- seenNames.set(name, true);
- }
+ const diagnosticMessagesJson: { [key: string]: DiagnosticDetails } = JSON.parse(inputStr);
const diagnosticMessages: InputDiagnosticMessageTable = ts.createMapFromTemplate(diagnosticMessagesJson);
- var infoFileOutput = buildInfoFileOutput(diagnosticMessages);
+ const outputFilesDir = ts.getDirectoryPath(inputFilePath);
+ const thisFilePathRel = ts.getRelativePathToDirectoryOrUrl(outputFilesDir, sys.getExecutingFilePath(),
+ sys.getCurrentDirectory(), ts.createGetCanonicalFileName(sys.useCaseSensitiveFileNames), /* isAbsolutePathAnUrl */ false);
+
+ const infoFileOutput = buildInfoFileOutput(diagnosticMessages, "./diagnosticInformationMap.generated.ts", thisFilePathRel);
checkForUniqueCodes(diagnosticMessages);
writeFile("diagnosticInformationMap.generated.ts", infoFileOutput);
- var messageOutput = buildDiagnosticMessageOutput(diagnosticMessages);
+ const messageOutput = buildDiagnosticMessageOutput(diagnosticMessages);
writeFile("diagnosticMessages.generated.json", messageOutput);
}
function checkForUniqueCodes(diagnosticTable: InputDiagnosticMessageTable) {
const allCodes: { [key: number]: true | undefined } = [];
diagnosticTable.forEach(({ code }) => {
- if (allCodes[code])
+ if (allCodes[code]) {
throw new Error(`Diagnostic code ${code} appears more than once.`);
+ }
allCodes[code] = true;
});
}
-function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable): string {
- var result =
- '// \r\n' +
- '/// \r\n' +
- '/* @internal */\r\n' +
- 'namespace ts {\r\n' +
+function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable, inputFilePathRel: string, thisFilePathRel: string): string {
+ let result =
+ "// \r\n" +
+ "// generated from '" + inputFilePathRel + "' by '" + thisFilePathRel + "'\r\n" +
+ "/// \r\n" +
+ "/* @internal */\r\n" +
+ "namespace ts {\r\n" +
" function diag(code: number, category: DiagnosticCategory, key: string, message: string): DiagnosticMessage {\r\n" +
" return { code, category, key, message };\r\n" +
" }\r\n" +
@@ -70,20 +69,20 @@ function buildInfoFileOutput(messageTable: InputDiagnosticMessageTable): string
result += ` ${propName}: diag(${code}, DiagnosticCategory.${category}, "${createKey(propName, code)}", ${JSON.stringify(name)}),\r\n`;
});
- result += ' };\r\n}';
+ result += " };\r\n}";
return result;
}
function buildDiagnosticMessageOutput(messageTable: InputDiagnosticMessageTable): string {
- let result = '{';
+ let result = "{";
messageTable.forEach(({ code }, name) => {
const propName = convertPropertyName(name);
result += `\r\n "${createKey(propName, code)}" : "${name.replace(/[\"]/g, '\\"')}",`;
});
// Shave trailing comma, then add newline and ending brace
- result = result.slice(0, result.length - 1) + '\r\n}';
+ result = result.slice(0, result.length - 1) + "\r\n}";
// Assert that we generated valid JSON
JSON.parse(result);
@@ -91,15 +90,15 @@ function buildDiagnosticMessageOutput(messageTable: InputDiagnosticMessageTable)
return result;
}
-function createKey(name: string, code: number) : string {
- return name.slice(0, 100) + '_' + code;
+function createKey(name: string, code: number): string {
+ return name.slice(0, 100) + "_" + code;
}
function convertPropertyName(origName: string): string {
- var result = origName.split("").map(char => {
- if (char === '*') { return "_Asterisk"; }
- if (char === '/') { return "_Slash"; }
- if (char === ':') { return "_Colon"; }
+ let result = origName.split("").map(char => {
+ if (char === "*") { return "_Asterisk"; }
+ if (char === "/") { return "_Slash"; }
+ if (char === ":") { return "_Colon"; }
return /\w/.test(char) ? char : "_";
}).join("");
@@ -107,7 +106,7 @@ function convertPropertyName(origName: string): string {
result = result.replace(/_+/g, "_");
// remove any leading underscore, unless it is followed by a number.
- result = result.replace(/^_([^\d])/, "$1")
+ result = result.replace(/^_([^\d])/, "$1");
// get rid of all trailing underscores.
result = result.replace(/_$/, "");
diff --git a/src/compiler/binder.ts b/src/compiler/binder.ts
index 15b429a0868..1f3470cc730 100644
--- a/src/compiler/binder.ts
+++ b/src/compiler/binder.ts
@@ -1570,7 +1570,7 @@ namespace ts {
else {
let pattern: Pattern | undefined;
if (node.name.kind === SyntaxKind.StringLiteral) {
- const text = (node.name).text;
+ const { text } = node.name;
if (hasZeroOrOneAsteriskCharacter(text)) {
pattern = tryParsePattern(text);
}
@@ -1589,22 +1589,13 @@ namespace ts {
else {
const state = declareModuleSymbol(node);
if (state !== ModuleInstanceState.NonInstantiated) {
- if (node.symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.RegularEnum)) {
- // if module was already merged with some function, class or non-const enum
- // treat is a non-const-enum-only
- node.symbol.constEnumOnlyModule = false;
- }
- else {
- const currentModuleIsConstEnumOnly = state === ModuleInstanceState.ConstEnumOnly;
- if (node.symbol.constEnumOnlyModule === undefined) {
- // non-merged case - use the current state
- node.symbol.constEnumOnlyModule = currentModuleIsConstEnumOnly;
- }
- else {
- // merged case: module is const enum only if all its pieces are non-instantiated or const enum
- node.symbol.constEnumOnlyModule = node.symbol.constEnumOnlyModule && currentModuleIsConstEnumOnly;
- }
- }
+ const { symbol } = node;
+ // if module was already merged with some function, class or non-const enum, treat it as non-const-enum-only
+ symbol.constEnumOnlyModule = (!(symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.RegularEnum)))
+ // Current must be `const enum` only
+ && state === ModuleInstanceState.ConstEnumOnly
+ // Can't have been set to 'false' in a previous merged symbol. ('undefined' OK)
+ && symbol.constEnumOnlyModule !== false;
}
}
}
@@ -2205,15 +2196,14 @@ namespace ts {
bindAnonymousDeclaration(node, SymbolFlags.Alias, getDeclarationName(node));
}
else {
- // An export default clause with an expression exports a value
- // We want to exclude both class and function here, this is necessary to issue an error when there are both
- // default export-assignment and default export function and class declaration.
- const flags = node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node)
+ const flags = node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node)
// An export default clause with an EntityNameExpression exports all meanings of that identifier
? SymbolFlags.Alias
// An export default clause with any other expression exports a value
: SymbolFlags.Property;
- declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.Property | SymbolFlags.AliasExcludes | SymbolFlags.Class | SymbolFlags.Function);
+ // If there is an `export default x;` alias declaration, can't `export default` anything else.
+ // (In contrast, you can still have `export default function f() {}` and `export default interface I {}`.)
+ declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.All);
}
}
diff --git a/src/compiler/checker.ts b/src/compiler/checker.ts
index ff8a80d370d..62802cd3b2b 100644
--- a/src/compiler/checker.ts
+++ b/src/compiler/checker.ts
@@ -66,7 +66,7 @@ namespace ts {
const languageVersion = getEmitScriptTarget(compilerOptions);
const modulekind = getEmitModuleKind(compilerOptions);
const noUnusedIdentifiers = !!compilerOptions.noUnusedLocals || !!compilerOptions.noUnusedParameters;
- const allowSyntheticDefaultImports = typeof compilerOptions.allowSyntheticDefaultImports !== "undefined" ? compilerOptions.allowSyntheticDefaultImports : modulekind === ModuleKind.System;
+ const allowSyntheticDefaultImports = getAllowSyntheticDefaultImports(compilerOptions);
const strictNullChecks = getStrictOptionValue(compilerOptions, "strictNullChecks");
const strictFunctionTypes = getStrictOptionValue(compilerOptions, "strictFunctionTypes");
const noImplicitAny = getStrictOptionValue(compilerOptions, "noImplicitAny");
@@ -455,29 +455,29 @@ namespace ts {
}
const typeofEQFacts = createMapFromTemplate({
- "string": TypeFacts.TypeofEQString,
- "number": TypeFacts.TypeofEQNumber,
- "boolean": TypeFacts.TypeofEQBoolean,
- "symbol": TypeFacts.TypeofEQSymbol,
- "undefined": TypeFacts.EQUndefined,
- "object": TypeFacts.TypeofEQObject,
- "function": TypeFacts.TypeofEQFunction
+ string: TypeFacts.TypeofEQString,
+ number: TypeFacts.TypeofEQNumber,
+ boolean: TypeFacts.TypeofEQBoolean,
+ symbol: TypeFacts.TypeofEQSymbol,
+ undefined: TypeFacts.EQUndefined,
+ object: TypeFacts.TypeofEQObject,
+ function: TypeFacts.TypeofEQFunction
});
const typeofNEFacts = createMapFromTemplate({
- "string": TypeFacts.TypeofNEString,
- "number": TypeFacts.TypeofNENumber,
- "boolean": TypeFacts.TypeofNEBoolean,
- "symbol": TypeFacts.TypeofNESymbol,
- "undefined": TypeFacts.NEUndefined,
- "object": TypeFacts.TypeofNEObject,
- "function": TypeFacts.TypeofNEFunction
+ string: TypeFacts.TypeofNEString,
+ number: TypeFacts.TypeofNENumber,
+ boolean: TypeFacts.TypeofNEBoolean,
+ symbol: TypeFacts.TypeofNESymbol,
+ undefined: TypeFacts.NEUndefined,
+ object: TypeFacts.TypeofNEObject,
+ function: TypeFacts.TypeofNEFunction
});
const typeofTypesByName = createMapFromTemplate({
- "string": stringType,
- "number": numberType,
- "boolean": booleanType,
- "symbol": esSymbolType,
- "undefined": undefinedType
+ string: stringType,
+ number: numberType,
+ boolean: booleanType,
+ symbol: esSymbolType,
+ undefined: undefinedType
});
const typeofType = createTypeofType();
@@ -2184,7 +2184,6 @@ namespace ts {
return forEachEntry(symbols, symbolFromSymbolTable => {
if (symbolFromSymbolTable.flags & SymbolFlags.Alias
&& symbolFromSymbolTable.escapedName !== "export="
- && !getDeclarationOfKind(symbolFromSymbolTable, SyntaxKind.ExportSpecifier)
&& !(isUMDExportSymbol(symbolFromSymbolTable) && enclosingDeclaration && isExternalModule(getSourceFileOfNode(enclosingDeclaration)))
// If `!useOnlyExternalAliasing`, we can use any type of alias to get the name
&& (!useOnlyExternalAliasing || some(symbolFromSymbolTable.declarations, isExternalModuleImportEqualsDeclaration))) {
@@ -7578,6 +7577,9 @@ namespace ts {
property.type = typeParameter;
properties.push(property);
}
+ const lengthSymbol = createSymbol(SymbolFlags.Property, "length" as __String);
+ lengthSymbol.type = getLiteralType(arity);
+ properties.push(lengthSymbol);
const type = createObjectType(ObjectFlags.Tuple | ObjectFlags.Reference);
type.typeParameters = typeParameters;
type.outerTypeParameters = undefined;
@@ -7628,28 +7630,12 @@ namespace ts {
unionIndex?: number;
}
- function binarySearchTypes(types: Type[], type: Type): number {
- let low = 0;
- let high = types.length - 1;
- const typeId = type.id;
- while (low <= high) {
- const middle = low + ((high - low) >> 1);
- const id = types[middle].id;
- if (id === typeId) {
- return middle;
- }
- else if (id > typeId) {
- high = middle - 1;
- }
- else {
- low = middle + 1;
- }
- }
- return ~low;
+ function getTypeId(type: Type) {
+ return type.id;
}
function containsType(types: Type[], type: Type): boolean {
- return binarySearchTypes(types, type) >= 0;
+ return binarySearch(types, type, getTypeId, compareValues) >= 0;
}
// Return true if the given intersection type contains (a) more than one unit type or (b) an object
@@ -7691,7 +7677,7 @@ namespace ts {
if (flags & TypeFlags.ESSymbol) typeSet.containsESSymbol = true;
if (flags & TypeFlags.StringOrNumberLiteralOrUnique) typeSet.containsLiteralOrUniqueESSymbol = true;
const len = typeSet.length;
- const index = len && type.id > typeSet[len - 1].id ? ~len : binarySearchTypes(typeSet, type);
+ const index = len && type.id > typeSet[len - 1].id ? ~len : binarySearch(typeSet, type, getTypeId, compareValues);
if (index < 0) {
if (!(flags & TypeFlags.Object && (type).objectFlags & ObjectFlags.Anonymous &&
type.symbol && type.symbol.flags & (SymbolFlags.Function | SymbolFlags.Method) && containsIdenticalType(typeSet, type))) {
@@ -9216,7 +9202,9 @@ namespace ts {
if (target.flags & TypeFlags.StringOrNumberLiteral && target.flags & TypeFlags.FreshLiteral) {
target = (target).regularType;
}
- if (source === target || relation !== identityRelation && isSimpleTypeRelatedTo(source, target, relation)) {
+ if (source === target ||
+ relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) ||
+ relation !== identityRelation && isSimpleTypeRelatedTo(source, target, relation)) {
return true;
}
if (source.flags & TypeFlags.Object && target.flags & TypeFlags.Object) {
@@ -9353,7 +9341,8 @@ namespace ts {
return isIdenticalTo(source, target);
}
- if (isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True;
+ if (relation === comparableRelation && !(target.flags & TypeFlags.Never) && isSimpleTypeRelatedTo(target, source, relation) ||
+ isSimpleTypeRelatedTo(source, target, relation, reportErrors ? reportError : undefined)) return Ternary.True;
if (isObjectLiteralType(source) && source.flags & TypeFlags.FreshLiteral) {
if (hasExcessProperties(source, target, reportErrors)) {
@@ -11217,22 +11206,25 @@ namespace ts {
// it as an inference candidate. Hopefully, a better candidate will come along that does
// not contain anyFunctionType when we come back to this argument for its second round
// of inference. Also, we exclude inferences for silentNeverType (which is used as a wildcard
- // when constructing types from type parameters that had no inference candidates) and
- // implicitNeverType (which is used as the element type for empty array literals).
- if (source.flags & TypeFlags.ContainsAnyFunctionType || source === silentNeverType || source === implicitNeverType) {
+ // when constructing types from type parameters that had no inference candidates).
+ if (source.flags & TypeFlags.ContainsAnyFunctionType || source === silentNeverType) {
return;
}
const inference = getInferenceInfoForType(target);
if (inference) {
if (!inference.isFixed) {
- if (!inference.candidates || priority < inference.priority) {
+ // We give lowest priority to inferences of implicitNeverType (which is used as the
+ // element type for empty array literals). Thus, inferences from empty array literals
+ // only matter when no other inferences are made.
+ const p = priority | (source === implicitNeverType ? InferencePriority.NeverType : 0);
+ if (!inference.candidates || p < inference.priority) {
inference.candidates = [source];
- inference.priority = priority;
+ inference.priority = p;
}
- else if (priority === inference.priority) {
+ else if (p === inference.priority) {
inference.candidates.push(source);
}
- if (!(priority & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, target)) {
+ if (!(p & InferencePriority.ReturnType) && target.flags & TypeFlags.TypeParameter && !isTypeParameterAtTopLevel(originalTarget, target)) {
inference.topLevel = false;
}
}
@@ -14699,19 +14691,7 @@ namespace ts {
const parent = openingLikeElement.parent.kind === SyntaxKind.JsxElement ? openingLikeElement.parent as JsxElement : undefined;
// We have to check that openingElement of the parent is the one we are visiting as this may not be true for selfClosingElement
if (parent && parent.openingElement === openingLikeElement && parent.children.length > 0) {
- const childrenTypes: Type[] = [];
- for (const child of (parent as JsxElement).children) {
- // In React, JSX text that contains only whitespaces will be ignored so we don't want to type-check that
- // because then type of children property will have constituent of string type.
- if (child.kind === SyntaxKind.JsxText) {
- if (!child.containsOnlyWhiteSpaces) {
- childrenTypes.push(stringType);
- }
- }
- else {
- childrenTypes.push(checkExpression(child, checkMode));
- }
- }
+ const childrenTypes: Type[] = checkJsxChildren(parent as JsxElement, checkMode);
if (!hasSpreadAnyType && jsxChildrenPropertyName && jsxChildrenPropertyName !== "") {
// Error if there is a attribute named "children" explicitly specified and children element.
@@ -14751,6 +14731,23 @@ namespace ts {
}
}
+ function checkJsxChildren(node: JsxElement | JsxFragment, checkMode?: CheckMode) {
+ const childrenTypes: Type[] = [];
+ for (const child of node.children) {
+ // In React, JSX text that contains only whitespaces will be ignored so we don't want to type-check that
+ // because then type of children property will have constituent of string type.
+ if (child.kind === SyntaxKind.JsxText) {
+ if (!child.containsOnlyWhiteSpaces) {
+ childrenTypes.push(stringType);
+ }
+ }
+ else {
+ childrenTypes.push(checkExpression(child, checkMode));
+ }
+ }
+ return childrenTypes;
+ }
+
/**
* Check attributes property of opening-like element. This function is called during chooseOverload to get call signature of a JSX opening-like element.
* (See "checkApplicableSignatureForJsxOpeningLikeElement" for how the function is used)
@@ -15285,6 +15282,9 @@ namespace ts {
if (isNodeOpeningLikeElement) {
checkJsxAttributesAssignableToTagNameAttributes(node);
}
+ else {
+ checkJsxChildren((node as JsxOpeningFragment).parent);
+ }
}
/**
@@ -15488,12 +15488,11 @@ namespace ts {
if (flags & ModifierFlags.Static) {
return true;
}
- // An instance property must be accessed through an instance of the enclosing class
- if (type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType) {
+ if (type.flags & TypeFlags.TypeParameter) {
// get the original type -- represented as the type constraint of the 'this' type
- type = getConstraintOfTypeParameter(type);
+ type = (type as TypeParameter).isThisType ? getConstraintOfTypeParameter(type) : getBaseConstraintOfType(type);
}
- if (!(getObjectFlags(getTargetType(type)) & ObjectFlags.ClassOrInterface && hasBaseType(type, enclosingClass))) {
+ if (!type || !hasBaseType(type, enclosingClass)) {
error(errorNode, Diagnostics.Property_0_is_protected_and_only_accessible_through_an_instance_of_class_1, symbolToString(prop), typeToString(enclosingClass));
return false;
}
@@ -15550,7 +15549,7 @@ namespace ts {
if (indexInfo.isReadonly && (isAssignmentTarget(node) || isDeleteTarget(node))) {
error(node, Diagnostics.Index_signature_in_type_0_only_permits_reading, typeToString(apparentType));
}
- return indexInfo.type;
+ return getFlowTypeOfPropertyAccess(node, /*prop*/ undefined, indexInfo.type, getAssignmentTargetKind(node));
}
if (right.escapedText && !checkAndReportErrorForExtendingInterface(node)) {
reportNonexistentProperty(right, type.flags & TypeFlags.TypeParameter && (type as TypeParameter).isThisType ? apparentType : type);
@@ -15575,16 +15574,21 @@ namespace ts {
return unknownType;
}
}
+ return getFlowTypeOfPropertyAccess(node, prop, propType, assignmentKind);
+ }
- // Only compute control flow type if this is a property access expression that isn't an
- // assignment target, and the referenced property was declared as a variable, property,
- // accessor, or optional method.
- if (node.kind !== SyntaxKind.PropertyAccessExpression || assignmentKind === AssignmentKind.Definite ||
- !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) &&
- !(prop.flags & SymbolFlags.Method && propType.flags & TypeFlags.Union)) {
- return propType;
+ /**
+ * Only compute control flow type if this is a property access expression that isn't an
+ * assignment target, and the referenced property was declared as a variable, property,
+ * accessor, or optional method.
+ */
+ function getFlowTypeOfPropertyAccess(node: PropertyAccessExpression | QualifiedName, prop: Symbol | undefined, type: Type, assignmentKind: AssignmentKind) {
+ if (node.kind !== SyntaxKind.PropertyAccessExpression ||
+ assignmentKind === AssignmentKind.Definite ||
+ prop && !(prop.flags & (SymbolFlags.Variable | SymbolFlags.Property | SymbolFlags.Accessor)) && !(prop.flags & SymbolFlags.Method && type.flags & TypeFlags.Union)) {
+ return type;
}
- const flowType = getFlowTypeOfReference(node, propType);
+ const flowType = getFlowTypeOfReference(node, type);
return assignmentKind ? getBaseTypeOfLiteralType(flowType) : flowType;
}
@@ -15673,9 +15677,10 @@ namespace ts {
return suggestion && symbolName(suggestion);
}
- function getSuggestionForNonexistentSymbol(location: Node, name: __String, meaning: SymbolFlags): string {
- const result = resolveNameHelper(location, name, meaning, /*nameNotFoundMessage*/ undefined, name, /*isUse*/ false, (symbols, name, meaning) => {
- // `name` from the callback === the outer `name`
+ function getSuggestionForNonexistentSymbol(location: Node, outerName: __String, meaning: SymbolFlags): string {
+ Debug.assert(outerName !== undefined, "outername should always be defined");
+ const result = resolveNameHelper(location, outerName, meaning, /*nameNotFoundMessage*/ undefined, outerName, /*isUse*/ false, (symbols, name, meaning) => {
+ Debug.assertEqual(outerName, name, "name should equal outerName");
const symbol = getSymbol(symbols, name, meaning);
// Sometimes the symbol is found when location is a return type of a function: `typeof x` and `x` is declared in the body of the function
// So the table *contains* `x` but `x` isn't actually in scope.
@@ -17054,7 +17059,7 @@ namespace ts {
// only the class declaration node will have the Abstract flag set.
const valueDecl = expressionType.symbol && getClassLikeDeclarationOfSymbol(expressionType.symbol);
if (valueDecl && hasModifier(valueDecl, ModifierFlags.Abstract)) {
- error(node, Diagnostics.Cannot_create_an_instance_of_the_abstract_class_0, declarationNameToString(getNameOfDeclaration(valueDecl)));
+ error(node, Diagnostics.Cannot_create_an_instance_of_an_abstract_class);
return resolveErrorCall(node);
}
@@ -20634,6 +20639,10 @@ namespace ts {
case SyntaxKind.Parameter:
markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(node));
+ const containingSignature = (node as ParameterDeclaration).parent;
+ for (const parameter of containingSignature.parameters) {
+ markDecoratorMedataDataTypeNodeAsReferenced(getParameterTypeNodeForDecoratorCheck(parameter));
+ }
break;
}
}
@@ -22784,7 +22793,7 @@ namespace ts {
const declaration = memberSymbol.valueDeclaration;
if (declaration !== member) {
if (isBlockScopedNameDeclaredBeforeUse(declaration, member)) {
- return getNodeLinks(declaration).enumMemberValue;
+ return getEnumMemberValue(declaration as EnumMember);
}
error(expr, Diagnostics.A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_members_defined_in_other_enums);
return 0;
diff --git a/src/compiler/commandLineParser.ts b/src/compiler/commandLineParser.ts
index 7ba9bd80843..43ea77c8020 100644
--- a/src/compiler/commandLineParser.ts
+++ b/src/compiler/commandLineParser.ts
@@ -76,13 +76,13 @@ namespace ts {
name: "target",
shortName: "t",
type: createMapFromTemplate({
- "es3": ScriptTarget.ES3,
- "es5": ScriptTarget.ES5,
- "es6": ScriptTarget.ES2015,
- "es2015": ScriptTarget.ES2015,
- "es2016": ScriptTarget.ES2016,
- "es2017": ScriptTarget.ES2017,
- "esnext": ScriptTarget.ESNext,
+ es3: ScriptTarget.ES3,
+ es5: ScriptTarget.ES5,
+ es6: ScriptTarget.ES2015,
+ es2015: ScriptTarget.ES2015,
+ es2016: ScriptTarget.ES2016,
+ es2017: ScriptTarget.ES2017,
+ esnext: ScriptTarget.ESNext,
}),
paramType: Diagnostics.VERSION,
showInSimplifiedHelpView: true,
@@ -93,14 +93,14 @@ namespace ts {
name: "module",
shortName: "m",
type: createMapFromTemplate({
- "none": ModuleKind.None,
- "commonjs": ModuleKind.CommonJS,
- "amd": ModuleKind.AMD,
- "system": ModuleKind.System,
- "umd": ModuleKind.UMD,
- "es6": ModuleKind.ES2015,
- "es2015": ModuleKind.ES2015,
- "esnext": ModuleKind.ESNext
+ none: ModuleKind.None,
+ commonjs: ModuleKind.CommonJS,
+ amd: ModuleKind.AMD,
+ system: ModuleKind.System,
+ umd: ModuleKind.UMD,
+ es6: ModuleKind.ES2015,
+ es2015: ModuleKind.ES2015,
+ esnext: ModuleKind.ESNext
}),
paramType: Diagnostics.KIND,
showInSimplifiedHelpView: true,
@@ -326,8 +326,8 @@ namespace ts {
{
name: "moduleResolution",
type: createMapFromTemplate({
- "node": ModuleResolutionKind.NodeJs,
- "classic": ModuleResolutionKind.Classic,
+ node: ModuleResolutionKind.NodeJs,
+ classic: ModuleResolutionKind.Classic,
}),
paramType: Diagnostics.STRATEGY,
category: Diagnostics.Module_Resolution_Options,
@@ -522,8 +522,8 @@ namespace ts {
{
name: "newLine",
type: createMapFromTemplate({
- "crlf": NewLineKind.CarriageReturnLineFeed,
- "lf": NewLineKind.LineFeed
+ crlf: NewLineKind.CarriageReturnLineFeed,
+ lf: NewLineKind.LineFeed
}),
paramType: Diagnostics.NEWLINE,
category: Diagnostics.Advanced_Options,
diff --git a/src/compiler/comments.ts b/src/compiler/comments.ts
index 025a4f36d26..1fec1e9562f 100644
--- a/src/compiler/comments.ts
+++ b/src/compiler/comments.ts
@@ -260,7 +260,7 @@ namespace ts {
}
}
- function emitLeadingComment(commentPos: number, commentEnd: number, _kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) {
+ function emitLeadingComment(commentPos: number, commentEnd: number, kind: SyntaxKind, hasTrailingNewLine: boolean, rangePos: number) {
if (!hasWrittenComment) {
emitNewLineBeforeLeadingCommentOfPosition(currentLineMap, writer, rangePos, commentPos);
hasWrittenComment = true;
@@ -274,7 +274,7 @@ namespace ts {
if (hasTrailingNewLine) {
writer.writeLine();
}
- else {
+ else if (kind === SyntaxKind.MultiLineCommentTrivia) {
writer.write(" ");
}
}
diff --git a/src/compiler/core.ts b/src/compiler/core.ts
index f2249641ff4..f3dd99ee5bf 100644
--- a/src/compiler/core.ts
+++ b/src/compiler/core.ts
@@ -20,12 +20,6 @@ namespace ts {
/* @internal */
namespace ts {
-
- // More efficient to create a collator once and use its `compare` than to call `a.localeCompare(b)` many times.
- export const collator: { compare(a: string, b: string): number } = typeof Intl === "object" && typeof Intl.Collator === "function" ? new Intl.Collator(/*locales*/ undefined, { usage: "sort", sensitivity: "accent" }) : undefined;
- // Intl is missing in Safari, and node 0.10 treats "a" as greater than "B".
- export const localeCompareIsCorrect = ts.collator && ts.collator.compare("a", "B") < 0;
-
/** Create a MapLike with good performance. */
function createDictionaryObject(): MapLike {
const map = Object.create(/*prototype*/ null); // tslint:disable-line:no-null-keyword
@@ -74,13 +68,13 @@ namespace ts {
}
// The global Map object. This may not be available, so we must test for it.
- declare const Map: { new(): Map } | undefined;
+ declare const Map: { new (): Map } | undefined;
// Internet Explorer's Map doesn't support iteration, so don't use it.
// tslint:disable-next-line no-in-operator variable-name
const MapCtr = typeof Map !== "undefined" && "entries" in Map.prototype ? Map : shimMap();
// Keep the class inside a function so it doesn't get compiled if it's not used.
- function shimMap(): { new(): Map } {
+ function shimMap(): { new (): Map } {
class MapIterator {
private data: MapLike;
@@ -103,7 +97,7 @@ namespace ts {
}
}
- return class implements Map {
+ return class implements Map {
private data = createDictionaryObject();
public size = 0;
@@ -165,12 +159,6 @@ namespace ts {
return getCanonicalFileName(nonCanonicalizedPath);
}
- export const enum Comparison {
- LessThan = -1,
- EqualTo = 0,
- GreaterThan = 1
- }
-
export function length(array: ReadonlyArray) {
return array ? array.length : 0;
}
@@ -307,10 +295,10 @@ namespace ts {
Debug.fail();
}
- export function contains(array: ReadonlyArray, value: T): boolean {
+ export function contains(array: ReadonlyArray, value: T, equalityComparer: EqualityComparer = equateValues): boolean {
if (array) {
for (const v of array) {
- if (v === value) {
+ if (equalityComparer(v, value)) {
return true;
}
}
@@ -655,24 +643,85 @@ namespace ts {
return [...array1, ...array2];
}
- // TODO: fixme (N^2) - add optional comparer so collection can be sorted before deduplication.
- export function deduplicate(array: ReadonlyArray, areEqual?: (a: T, b: T) => boolean): T[] {
- let result: T[];
- if (array) {
- result = [];
- loop: for (const item of array) {
- for (const res of result) {
- if (areEqual ? areEqual(res, item) : res === item) {
- continue loop;
- }
- }
- result.push(item);
+ function deduplicateRelational(array: ReadonlyArray, equalityComparer: EqualityComparer, comparer: Comparer) {
+ // Perform a stable sort of the array. This ensures the first entry in a list of
+ // duplicates remains the first entry in the result.
+ const indices = array.map((_, i) => i);
+ stableSortIndices(array, indices, comparer);
+
+ let last = array[indices[0]];
+ const deduplicated: number[] = [indices[0]];
+ for (let i = 1; i < indices.length; i++) {
+ const index = indices[i];
+ const item = array[index];
+ if (!equalityComparer(last, item)) {
+ deduplicated.push(index);
+ last = item;
}
}
+
+ // restore original order
+ deduplicated.sort();
+ return deduplicated.map(i => array[i]);
+ }
+
+ function deduplicateEquality(array: ReadonlyArray, equalityComparer: EqualityComparer) {
+ const result: T[] = [];
+ for (const item of array) {
+ pushIfUnique(result, item, equalityComparer);
+ }
return result;
}
- export function arrayIsEqualTo(array1: ReadonlyArray, array2: ReadonlyArray, equaler?: (a: T, b: T) => boolean): boolean {
+ /**
+ * Deduplicates an unsorted array.
+ * @param equalityComparer An optional `EqualityComparer` used to determine if two values are duplicates.
+ * @param comparer An optional `Comparer` used to sort entries before comparison, though the
+ * result will remain in the original order in `array`.
+ */
+ export function deduplicate(array: ReadonlyArray, equalityComparer: EqualityComparer, comparer?: Comparer): T[] {
+ return !array ? undefined :
+ array.length === 0 ? [] :
+ array.length === 1 ? array.slice() :
+ comparer ? deduplicateRelational(array, equalityComparer, comparer) :
+ deduplicateEquality(array, equalityComparer);
+ }
+
+ /**
+ * Deduplicates an array that has already been sorted.
+ */
+ function deduplicateSorted(array: ReadonlyArray, comparer: EqualityComparer | Comparer) {
+ if (!array) return undefined;
+ if (array.length === 0) return [];
+
+ let last = array[0];
+ const deduplicated: T[] = [last];
+ for (let i = 1; i < array.length; i++) {
+ const next = array[i];
+ switch (comparer(next, last)) {
+ // equality comparison
+ case true:
+
+ // relational comparison
+ case Comparison.EqualTo:
+ continue;
+
+ case Comparison.LessThan:
+ // If `array` is sorted, `next` should **never** be less than `last`.
+ return Debug.fail("Array is unsorted.");
+ }
+
+ deduplicated.push(last = next);
+ }
+
+ return deduplicated;
+ }
+
+ export function sortAndDeduplicate(array: ReadonlyArray, comparer: Comparer, equalityComparer?: EqualityComparer) {
+ return deduplicateSorted(sort(array, comparer), equalityComparer || comparer);
+ }
+
+ export function arrayIsEqualTo(array1: ReadonlyArray, array2: ReadonlyArray, equalityComparer: (a: T, b: T) => boolean = equateValues): boolean {
if (!array1 || !array2) {
return array1 === array2;
}
@@ -682,8 +731,7 @@ namespace ts {
}
for (let i = 0; i < array1.length; i++) {
- const equals = equaler ? equaler(array1[i], array2[i]) : array1[i] === array2[i];
- if (!equals) {
+ if (!equalityComparer(array1[i], array2[i])) {
return false;
}
}
@@ -734,22 +782,44 @@ namespace ts {
}
/**
- * Gets the relative complement of `arrayA` with respect to `b`, returning the elements that
+ * Gets the relative complement of `arrayA` with respect to `arrayB`, returning the elements that
* are not present in `arrayA` but are present in `arrayB`. Assumes both arrays are sorted
* based on the provided comparer.
*/
- export function relativeComplement(arrayA: T[] | undefined, arrayB: T[] | undefined, comparer: Comparer = compareValues, offsetA = 0, offsetB = 0): T[] | undefined {
+ export function relativeComplement(arrayA: T[] | undefined, arrayB: T[] | undefined, comparer: Comparer): T[] | undefined {
if (!arrayB || !arrayA || arrayB.length === 0 || arrayA.length === 0) return arrayB;
const result: T[] = [];
- outer: for (; offsetB < arrayB.length; offsetB++) {
- inner: for (; offsetA < arrayA.length; offsetA++) {
+ loopB: for (let offsetA = 0, offsetB = 0; offsetB < arrayB.length; offsetB++) {
+ if (offsetB > 0) {
+ // Ensure `arrayB` is properly sorted.
+ Debug.assertGreaterThanOrEqual(comparer(arrayB[offsetB], arrayB[offsetB - 1]), Comparison.EqualTo);
+ }
+
+ loopA: for (const startA = offsetA; offsetA < arrayA.length; offsetA++) {
+ if (offsetA > startA) {
+ // Ensure `arrayA` is properly sorted. We only need to perform this check if
+ // `offsetA` has changed since we entered the loop.
+ Debug.assertGreaterThanOrEqual(comparer(arrayA[offsetA], arrayA[offsetA - 1]), Comparison.EqualTo);
+ }
+
switch (comparer(arrayB[offsetB], arrayA[offsetA])) {
- case Comparison.LessThan: break inner;
- case Comparison.EqualTo: continue outer;
- case Comparison.GreaterThan: continue inner;
+ case Comparison.LessThan:
+ // If B is less than A, B does not exist in arrayA. Add B to the result and
+ // move to the next element in arrayB without changing the current position
+ // in arrayA.
+ result.push(arrayB[offsetB]);
+ continue loopB;
+ case Comparison.EqualTo:
+ // If B is equal to A, B exists in arrayA. Move to the next element in
+ // arrayB without adding B to the result or changing the current position
+ // in arrayA.
+ continue loopB;
+ case Comparison.GreaterThan:
+ // If B is greater than A, we need to keep looking for B in arrayA. Move to
+ // the next element in arrayA and recheck.
+ continue loopA;
}
}
- result.push(arrayB[offsetB]);
}
return result;
}
@@ -802,8 +872,7 @@ namespace ts {
start = start === undefined ? 0 : toOffset(from, start);
end = end === undefined ? from.length : toOffset(from, end);
for (let i = start; i < end && i < from.length; i++) {
- const v = from[i];
- if (v !== undefined) {
+ if (from[i] !== undefined) {
to.push(from[i]);
}
}
@@ -813,8 +882,8 @@ namespace ts {
/**
* @return Whether the value was added.
*/
- export function pushIfUnique(array: T[], toAdd: T): boolean {
- if (contains(array, toAdd)) {
+ export function pushIfUnique(array: T[], toAdd: T, equalityComparer?: EqualityComparer): boolean {
+ if (contains(array, toAdd, equalityComparer)) {
return false;
}
else {
@@ -826,9 +895,9 @@ namespace ts {
/**
* Unlike `pushIfUnique`, this can take `undefined` as an input, and returns a new array.
*/
- export function appendIfUnique(array: T[] | undefined, toAdd: T): T[] {
+ export function appendIfUnique(array: T[] | undefined, toAdd: T, equalityComparer?: EqualityComparer): T[] {
if (array) {
- pushIfUnique(array, toAdd);
+ pushIfUnique(array, toAdd, equalityComparer);
return array;
}
else {
@@ -836,14 +905,25 @@ namespace ts {
}
}
+ function stableSortIndices(array: ReadonlyArray, indices: number[], comparer: Comparer) {
+ // sort indices by value then position
+ indices.sort((x, y) => comparer(array[x], array[y]) || compareValues(x, y));
+ }
+
+ /**
+ * Returns a new sorted array.
+ */
+ export function sort(array: ReadonlyArray, comparer: Comparer) {
+ return array.slice().sort(comparer);
+ }
+
/**
* Stable sort of an array. Elements equal to each other maintain their relative position in the array.
*/
- export function stableSort(array: ReadonlyArray, comparer: Comparer = compareValues) {
- return array
- .map((_, i) => i) // create array of indices
- .sort((x, y) => comparer(array[x], array[y]) || compareValues(x, y)) // sort indices by value then position
- .map(i => array[i]); // get sorted array
+ export function stableSort(array: ReadonlyArray, comparer: Comparer) {
+ const indices = array.map((_, i) => i);
+ stableSortIndices(array, indices, comparer);
+ return indices.map(i => array[i]);
}
export function rangeEquals(array1: ReadonlyArray, array2: ReadonlyArray, pos: number, end: number) {
@@ -921,38 +1001,37 @@ namespace ts {
return result;
}
- export type Comparer = (a: T, b: T) => Comparison;
-
/**
- * Performs a binary search, finding the index at which 'value' occurs in 'array'.
+ * Performs a binary search, finding the index at which `value` occurs in `array`.
* If no such index is found, returns the 2's-complement of first index at which
- * number[index] exceeds number.
+ * `array[index]` exceeds `value`.
* @param array A sorted array whose first element must be no larger than number
- * @param number The value to be searched for in the array.
+ * @param value The value to be searched for in the array.
+ * @param keySelector A callback used to select the search key from `value` and each element of
+ * `array`.
+ * @param keyComparer A callback used to compare two keys in a sorted array.
+ * @param offset An offset into `array` at which to start the search.
*/
- export function binarySearch(array: ReadonlyArray, value: T, comparer?: Comparer, offset?: number): number {
+ export function binarySearch(array: ReadonlyArray, value: T, keySelector: (v: T) => U, keyComparer: Comparer, offset?: number): number {
if (!array || array.length === 0) {
return -1;
}
let low = offset || 0;
let high = array.length - 1;
- comparer = comparer !== undefined
- ? comparer
- : (v1, v2) => (v1 < v2 ? -1 : (v1 > v2 ? 1 : 0));
-
+ const key = keySelector(value);
while (low <= high) {
const middle = low + ((high - low) >> 1);
- const midValue = array[middle];
-
- if (comparer(midValue, value) === 0) {
- return middle;
- }
- else if (comparer(midValue, value) > 0) {
- high = middle - 1;
- }
- else {
- low = middle + 1;
+ const midKey = keySelector(array[middle]);
+ switch (keyComparer(midKey, key)) {
+ case Comparison.LessThan:
+ low = middle + 1;
+ break;
+ case Comparison.EqualTo:
+ return middle;
+ case Comparison.GreaterThan:
+ high = middle - 1;
+ break;
}
}
@@ -1104,13 +1183,13 @@ namespace ts {
* @param left A map-like whose properties should be compared.
* @param right A map-like whose properties should be compared.
*/
- export function equalOwnProperties(left: MapLike, right: MapLike, equalityComparer?: (left: T, right: T) => boolean) {
+ export function equalOwnProperties(left: MapLike, right: MapLike, equalityComparer: EqualityComparer = equateValues) {
if (left === right) return true;
if (!left || !right) return false;
for (const key in left) {
if (hasOwnProperty.call(left, key)) {
if (!hasOwnProperty.call(right, key) === undefined) return false;
- if (equalityComparer ? !equalityComparer(left[key], right[key]) : left[key] !== right[key]) return false;
+ if (!equalityComparer(left[key], right[key])) return false;
}
}
@@ -1262,7 +1341,7 @@ namespace ts {
}
/** Does nothing. */
- export function noop(): void { }
+ export function noop(_?: {} | null | undefined): void { } // tslint:disable-line no-empty
/** Do nothing and return false */
export function returnFalse(): false { return false; }
@@ -1463,37 +1542,210 @@ namespace ts {
return headChain;
}
- export function compareValues(a: T, b: T): Comparison {
- if (a === b) return Comparison.EqualTo;
- if (a === undefined) return Comparison.LessThan;
- if (b === undefined) return Comparison.GreaterThan;
- return a < b ? Comparison.LessThan : Comparison.GreaterThan;
+ export function equateValues(a: T, b: T) {
+ return a === b;
}
- export function compareStrings(a: string, b: string, ignoreCase?: boolean): Comparison {
+ /**
+ * Compare the equality of two strings using a case-sensitive ordinal comparison.
+ *
+ * Case-sensitive comparisons compare both strings one code-point at a time using the integer
+ * value of each code-point after applying `toUpperCase` to each string. We always map both
+ * strings to their upper-case form as some unicode characters do not properly round-trip to
+ * lowercase (such as `ẞ` (German sharp capital s)).
+ */
+ export function equateStringsCaseInsensitive(a: string, b: string) {
+ return a === b
+ || a !== undefined
+ && b !== undefined
+ && a.toUpperCase() === b.toUpperCase();
+ }
+
+ /**
+ * Compare the equality of two strings using a case-sensitive ordinal comparison.
+ *
+ * Case-sensitive comparisons compare both strings one code-point at a time using the
+ * integer value of each code-point.
+ */
+ export function equateStringsCaseSensitive(a: string, b: string) {
+ return equateValues(a, b);
+ }
+
+ function compareComparableValues(a: string, b: string): Comparison;
+ function compareComparableValues(a: number, b: number): Comparison;
+ function compareComparableValues(a: string | number, b: string | number) {
+ return a === b ? Comparison.EqualTo :
+ a === undefined ? Comparison.LessThan :
+ b === undefined ? Comparison.GreaterThan :
+ a < b ? Comparison.LessThan :
+ Comparison.GreaterThan;
+ }
+
+ /**
+ * Compare two numeric values for their order relative to each other.
+ * To compare strings, use any of the `compareStrings` functions.
+ */
+ export function compareValues(a: number, b: number) {
+ return compareComparableValues(a, b);
+ }
+
+ /**
+ * Compare two strings using a case-insensitive ordinal comparison.
+ *
+ * Ordinal comparisons are based on the difference between the unicode code points of both
+ * strings. Characters with multiple unicode representations are considered unequal. Ordinal
+ * comparisons provide predictable ordering, but place "a" after "B".
+ *
+ * Case-insensitive comparisons compare both strings one code-point at a time using the integer
+ * value of each code-point after applying `toUpperCase` to each string. We always map both
+ * strings to their upper-case form as some unicode characters do not properly round-trip to
+ * lowercase (such as `ẞ` (German sharp capital s)).
+ */
+ export function compareStringsCaseInsensitive(a: string, b: string) {
if (a === b) return Comparison.EqualTo;
if (a === undefined) return Comparison.LessThan;
if (b === undefined) return Comparison.GreaterThan;
- if (ignoreCase) {
- // Checking if "collator exists indicates that Intl is available.
- // We still have to check if "collator.compare" is correct. If it is not, use "String.localeComapre"
- if (collator) {
- const result = localeCompareIsCorrect ?
- collator.compare(a, b) :
- a.localeCompare(b, /*locales*/ undefined, { usage: "sort", sensitivity: "accent" }); // accent means a ≠ b, a ≠ á, a = A
- return result < 0 ? Comparison.LessThan : result > 0 ? Comparison.GreaterThan : Comparison.EqualTo;
- }
+ a = a.toUpperCase();
+ b = b.toUpperCase();
+ return a < b ? Comparison.LessThan : a > b ? Comparison.GreaterThan : Comparison.EqualTo;
+ }
- a = a.toUpperCase();
- b = b.toUpperCase();
+ /**
+ * Compare two strings using a case-sensitive ordinal comparison.
+ *
+ * Ordinal comparisons are based on the difference between the unicode code points of both
+ * strings. Characters with multiple unicode representations are considered unequal. Ordinal
+ * comparisons provide predictable ordering, but place "a" after "B".
+ *
+ * Case-sensitive comparisons compare both strings one code-point at a time using the integer
+ * value of each code-point.
+ */
+ export function compareStringsCaseSensitive(a: string, b: string) {
+ return compareComparableValues(a, b);
+ }
+
+ /**
+ * Creates a string comparer for use with string collation in the UI.
+ */
+ const createUIStringComparer = (() => {
+ let defaultComparer: Comparer | undefined;
+ let enUSComparer: Comparer | undefined;
+
+ const stringComparerFactory = getStringComparerFactory();
+ return createStringComparer;
+
+ function compareWithCallback(a: string | undefined, b: string | undefined, comparer: (a: string, b: string) => number) {
if (a === b) return Comparison.EqualTo;
+ if (a === undefined) return Comparison.LessThan;
+ if (b === undefined) return Comparison.GreaterThan;
+ const value = comparer(a, b);
+ return value < 0 ? Comparison.LessThan : value > 0 ? Comparison.GreaterThan : Comparison.EqualTo;
}
- return a < b ? Comparison.LessThan : Comparison.GreaterThan;
+ function createIntlCollatorStringComparer(locale: string | undefined): Comparer {
+ // Intl.Collator.prototype.compare is bound to the collator. See NOTE in
+ // http://www.ecma-international.org/ecma-402/2.0/#sec-Intl.Collator.prototype.compare
+ const comparer = new Intl.Collator(locale, { usage: "sort", sensitivity: "variant" }).compare;
+ return (a, b) => compareWithCallback(a, b, comparer);
+ }
+
+ function createLocaleCompareStringComparer(locale: string | undefined): Comparer {
+ // if the locale is not the default locale (`undefined`), use the fallback comparer.
+ if (locale !== undefined) return createFallbackStringComparer();
+
+ return (a, b) => compareWithCallback(a, b, compareStrings);
+
+ function compareStrings(a: string, b: string) {
+ return a.localeCompare(b);
+ }
+ }
+
+ function createFallbackStringComparer(): Comparer {
+ // An ordinal comparison puts "A" after "b", but for the UI we want "A" before "b".
+ // We first sort case insensitively. So "Aaa" will come before "baa".
+ // Then we sort case sensitively, so "aaa" will come before "Aaa".
+ //
+ // For case insensitive comparisons we always map both strings to their
+ // upper-case form as some unicode characters do not properly round-trip to
+ // lowercase (such as `ẞ` (German sharp capital s)).
+ return (a, b) => compareWithCallback(a, b, compareDictionaryOrder);
+
+ function compareDictionaryOrder(a: string, b: string) {
+ return compareStrings(a.toUpperCase(), b.toUpperCase()) || compareStrings(a, b);
+ }
+
+ function compareStrings(a: string, b: string) {
+ return a < b ? Comparison.LessThan : a > b ? Comparison.GreaterThan : Comparison.EqualTo;
+ }
+ }
+
+ function getStringComparerFactory() {
+ // If the host supports Intl, we use it for comparisons using the default locale.
+ if (typeof Intl === "object" && typeof Intl.Collator === "function") {
+ return createIntlCollatorStringComparer;
+ }
+
+ // If the host does not support Intl, we fall back to localeCompare.
+ // localeCompare in Node v0.10 is just an ordinal comparison, so don't use it.
+ if (typeof String.prototype.localeCompare === "function" &&
+ typeof String.prototype.toLocaleUpperCase === "function" &&
+ "a".localeCompare("B") < 0) {
+ return createLocaleCompareStringComparer;
+ }
+
+ // Otherwise, fall back to ordinal comparison:
+ return createFallbackStringComparer;
+ }
+
+ function createStringComparer(locale: string | undefined) {
+ // Hold onto common string comparers. This avoids constantly reallocating comparers during
+ // tests.
+ if (locale === undefined) {
+ return defaultComparer || (defaultComparer = stringComparerFactory(locale));
+ }
+ else if (locale === "en-US") {
+ return enUSComparer || (enUSComparer = stringComparerFactory(locale));
+ }
+ else {
+ return stringComparerFactory(locale);
+ }
+ }
+ })();
+
+ let uiComparerCaseSensitive: Comparer | undefined;
+ let uiLocale: string | undefined;
+
+ export function getUILocale() {
+ return uiLocale;
}
- export function compareStringsCaseInsensitive(a: string, b: string) {
- return compareStrings(a, b, /*ignoreCase*/ true);
+ export function setUILocale(value: string) {
+ if (uiLocale !== value) {
+ uiLocale = value;
+ uiComparerCaseSensitive = undefined;
+ }
+ }
+
+ /**
+ * Compare two strings in a using the case-sensitive sort behavior of the UI locale.
+ *
+ * Ordering is not predictable between different host locales, but is best for displaying
+ * ordered data for UI presentation. Characters with multiple unicode representations may
+ * be considered equal.
+ *
+ * Case-sensitive comparisons compare strings that differ in base characters, or
+ * accents/diacritic marks, or case as unequal.
+ */
+ export function compareStringsCaseSensitiveUI(a: string, b: string) {
+ const comparer = uiComparerCaseSensitive || (uiComparerCaseSensitive = createUIStringComparer(uiLocale));
+ return comparer(a, b);
+ }
+
+ export function compareProperties(a: T, b: T, key: K, comparer: Comparer) {
+ return a === b ? Comparison.EqualTo :
+ a === undefined ? Comparison.LessThan :
+ b === undefined ? Comparison.GreaterThan :
+ comparer(a[key], b[key]);
}
function getDiagnosticFileName(diagnostic: Diagnostic): string {
@@ -1501,7 +1753,7 @@ namespace ts {
}
export function compareDiagnostics(d1: Diagnostic, d2: Diagnostic): Comparison {
- return compareValues(getDiagnosticFileName(d1), getDiagnosticFileName(d2)) ||
+ return compareStringsCaseSensitive(getDiagnosticFileName(d1), getDiagnosticFileName(d2)) ||
compareValues(d1.start, d2.start) ||
compareValues(d1.length, d2.length) ||
compareValues(d1.code, d2.code) ||
@@ -1515,7 +1767,7 @@ namespace ts {
const string1 = isString(text1) ? text1 : text1.messageText;
const string2 = isString(text2) ? text2 : text2.messageText;
- const res = compareValues(string1, string2);
+ const res = compareStringsCaseSensitive(string1, string2);
if (res) {
return res;
}
@@ -1533,27 +1785,8 @@ namespace ts {
return text1 ? Comparison.GreaterThan : Comparison.LessThan;
}
- export function sortAndDeduplicateDiagnostics(diagnostics: Diagnostic[]): Diagnostic[] {
- return deduplicateSortedDiagnostics(diagnostics.sort(compareDiagnostics));
- }
-
- export function deduplicateSortedDiagnostics(diagnostics: Diagnostic[]): Diagnostic[] {
- if (diagnostics.length < 2) {
- return diagnostics;
- }
-
- const newDiagnostics = [diagnostics[0]];
- let previousDiagnostic = diagnostics[0];
- for (let i = 1; i < diagnostics.length; i++) {
- const currentDiagnostic = diagnostics[i];
- const isDupe = compareDiagnostics(currentDiagnostic, previousDiagnostic) === Comparison.EqualTo;
- if (!isDupe) {
- newDiagnostics.push(currentDiagnostic);
- previousDiagnostic = currentDiagnostic;
- }
- }
-
- return newDiagnostics;
+ export function sortAndDeduplicateDiagnostics(diagnostics: ReadonlyArray): Diagnostic[] {
+ return sortAndDeduplicate(diagnostics, compareDiagnostics);
}
export function normalizeSlashes(path: string): string {
@@ -1683,6 +1916,13 @@ namespace ts {
return moduleResolution;
}
+ export function getAllowSyntheticDefaultImports(compilerOptions: CompilerOptions) {
+ const moduleKind = getEmitModuleKind(compilerOptions);
+ return compilerOptions.allowSyntheticDefaultImports !== undefined
+ ? compilerOptions.allowSyntheticDefaultImports
+ : moduleKind === ModuleKind.System;
+ }
+
export type StrictOptionName = "noImplicitAny" | "noImplicitThis" | "strictNullChecks" | "strictFunctionTypes" | "alwaysStrict";
export function getStrictOptionValue(compilerOptions: CompilerOptions, flag: StrictOptionName): boolean {
@@ -1883,8 +2123,9 @@ namespace ts {
const aComponents = getNormalizedPathComponents(a, currentDirectory);
const bComponents = getNormalizedPathComponents(b, currentDirectory);
const sharedLength = Math.min(aComponents.length, bComponents.length);
+ const comparer = ignoreCase ? compareStringsCaseInsensitive : compareStringsCaseSensitive;
for (let i = 0; i < sharedLength; i++) {
- const result = compareStrings(aComponents[i], bComponents[i], ignoreCase);
+ const result = comparer(aComponents[i], bComponents[i]);
if (result !== Comparison.EqualTo) {
return result;
}
@@ -1905,9 +2146,9 @@ namespace ts {
return false;
}
+ const equalityComparer = ignoreCase ? equateStringsCaseInsensitive : equateStringsCaseSensitive;
for (let i = 0; i < parentComponents.length; i++) {
- const result = compareStrings(parentComponents[i], childComponents[i], ignoreCase);
- if (result !== Comparison.EqualTo) {
+ if (!equalityComparer(parentComponents[i], childComponents[i])) {
return false;
}
}
@@ -2152,6 +2393,7 @@ namespace ts {
path = normalizePath(path);
currentDirectory = normalizePath(currentDirectory);
+ const comparer = useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive;
const patterns = getFileMatcherPatterns(path, excludes, includes, useCaseSensitiveFileNames, currentDirectory);
const regexFlag = useCaseSensitiveFileNames ? "" : "i";
@@ -2163,7 +2405,6 @@ namespace ts {
// If there are no "includes", then just put everything in results[0].
const results: string[][] = includeFileRegexes ? includeFileRegexes.map(() => []) : [[]];
- const comparer = useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive;
for (const basePath of patterns.basePaths) {
visitDirectory(basePath, combinePaths(currentDirectory, basePath), depth);
}
@@ -2171,10 +2412,9 @@ namespace ts {
return flatten(results);
function visitDirectory(path: string, absolutePath: string, depth: number | undefined) {
- let { files, directories } = getFileSystemEntries(path);
- files = files.slice().sort(comparer);
+ const { files, directories } = getFileSystemEntries(path);
- for (const current of files) {
+ for (const current of sort(files, comparer)) {
const name = combinePaths(path, current);
const absoluteName = combinePaths(absolutePath, current);
if (extensions && !fileExtensionIsOneOf(name, extensions)) continue;
@@ -2197,8 +2437,7 @@ namespace ts {
}
}
- directories = directories.slice().sort(comparer);
- for (const current of directories) {
+ for (const current of sort(directories, comparer)) {
const name = combinePaths(path, current);
const absoluteName = combinePaths(absolutePath, current);
if ((!includeDirectoryRegex || includeDirectoryRegex.test(absoluteName)) &&
@@ -2228,7 +2467,7 @@ namespace ts {
}
// Sort the offsets array using either the literal or canonical path representations.
- includeBasePaths.sort(useCaseSensitiveFileNames ? compareStrings : compareStringsCaseInsensitive);
+ includeBasePaths.sort(useCaseSensitiveFileNames ? compareStringsCaseSensitive : compareStringsCaseInsensitive);
// Iterate over each include base path and include unique base paths that are not a
// subpath of an existing base path
@@ -2295,7 +2534,11 @@ namespace ts {
if (!extraFileExtensions || extraFileExtensions.length === 0 || !needAllExtensions) {
return needAllExtensions ? allSupportedExtensions : supportedTypeScriptExtensions;
}
- return deduplicate([...allSupportedExtensions, ...extraFileExtensions.map(e => e.extension)]);
+ return deduplicate(
+ [...allSupportedExtensions, ...extraFileExtensions.map(e => e.extension)],
+ equateStringsCaseSensitive,
+ compareStringsCaseSensitive
+ );
}
export function hasJavaScriptFileExtension(fileName: string) {
@@ -2392,6 +2635,17 @@ namespace ts {
return (removeFileExtension(path) + newExtension);
}
+ /**
+ * Takes a string like "jquery-min.4.2.3" and returns "jquery"
+ */
+ export function removeMinAndVersionNumbers(fileName: string) {
+ // Match a "." or "-" followed by a version number or 'min' at the end of the name
+ const trailingMinOrVersion = /[.-]((min)|(\d+(\.\d+)*))$/;
+
+ // The "min" or version may both be present, in either order, so try applying the above twice.
+ return fileName.replace(trailingMinOrVersion, "").replace(trailingMinOrVersion, "");
+ }
+
export interface ObjectAllocator {
getNodeConstructor(): new (kind: SyntaxKind, pos?: number, end?: number) => Node;
getTokenConstructor(): new (kind: TKind, pos?: number, end?: number) => Token;
@@ -2416,8 +2670,7 @@ namespace ts {
}
}
- function Signature() {
- }
+ function Signature() {} // tslint:disable-line no-empty
function Node(this: Node, kind: SyntaxKind, pos: number, end: number) {
this.id = 0;
@@ -2593,7 +2846,7 @@ namespace ts {
return findBestPatternMatch(patterns, _ => _, candidate);
}
- export function patternText({prefix, suffix}: Pattern): string {
+ export function patternText({ prefix, suffix }: Pattern): string {
return `${prefix}*${suffix}`;
}
@@ -2623,7 +2876,7 @@ namespace ts {
return matchedValue;
}
- function isPatternMatch({prefix, suffix}: Pattern, candidate: string) {
+ function isPatternMatch({ prefix, suffix }: Pattern, candidate: string) {
return candidate.length >= prefix.length + suffix.length &&
startsWith(candidate, prefix) &&
endsWith(candidate, suffix);
@@ -2688,7 +2941,7 @@ namespace ts {
return (arg: T) => f(arg) && g(arg);
}
- export function assertTypeIsNever(_: never): void { }
+ export function assertTypeIsNever(_: never): void { } // tslint:disable-line no-empty
export interface FileAndDirectoryExistence {
fileExists: boolean;
@@ -2855,10 +3108,9 @@ namespace ts {
function addOrDeleteFileOrDirectory(fileOrDirectory: string, fileOrDirectoryPath: Path) {
const existingResult = getCachedFileSystemEntries(fileOrDirectoryPath);
if (existingResult) {
- // This was a folder already present, remove it if this doesnt exist any more
- if (!host.directoryExists(fileOrDirectory)) {
- cachedReadDirectoryResult.delete(fileOrDirectoryPath);
- }
+ // Just clear the cache for now
+ // For now just clear the cache, since this could mean that multiple level entries might need to be re-evaluated
+ clearCache();
}
else {
// This was earlier a file (hence not in cached directory contents)
@@ -2871,8 +3123,14 @@ namespace ts {
fileExists: host.fileExists(fileOrDirectoryPath),
directoryExists: host.directoryExists(fileOrDirectoryPath)
};
- updateFilesOfFileSystemEntry(parentResult, baseName, fsQueryResult.fileExists);
- updateFileSystemEntry(parentResult.directories, baseName, fsQueryResult.directoryExists);
+ if (fsQueryResult.directoryExists || hasEntry(parentResult.directories, baseName)) {
+ // Folder added or removed, clear the cache instead of updating the folder and its structure
+ clearCache();
+ }
+ else {
+ // No need to update the directory structure, just files
+ updateFilesOfFileSystemEntry(parentResult, baseName, fsQueryResult.fileExists);
+ }
return fsQueryResult;
}
}
diff --git a/src/compiler/declarationEmitter.ts b/src/compiler/declarationEmitter.ts
index 7912d042c0f..ebd2985dd45 100644
--- a/src/compiler/declarationEmitter.ts
+++ b/src/compiler/declarationEmitter.ts
@@ -1469,45 +1469,40 @@ namespace ts {
function getAccessorDeclarationTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic {
let diagnosticMessage: DiagnosticMessage;
if (accessorWithTypeAnnotation.kind === SyntaxKind.SetAccessor) {
- // Setters have to have type named and cannot infer it so, the type should always be named
- if (hasModifier(accessorWithTypeAnnotation.parent, ModifierFlags.Static)) {
+ // Getters can infer the return type from the returned expression, but setters cannot, so the
+ // "_from_external_module_1_but_cannot_be_named" case cannot occur.
+ if (hasModifier(accessorWithTypeAnnotation, ModifierFlags.Static)) {
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
- Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
- Diagnostics.Parameter_0_of_public_static_property_setter_from_exported_class_has_or_is_using_private_name_1;
+ Diagnostics.Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
+ Diagnostics.Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_private_name_1;
}
else {
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
- Diagnostics.Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
- Diagnostics.Parameter_0_of_public_property_setter_from_exported_class_has_or_is_using_private_name_1;
+ Diagnostics.Parameter_type_of_public_setter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
+ Diagnostics.Parameter_type_of_public_setter_0_from_exported_class_has_or_is_using_private_name_1;
}
- return {
- diagnosticMessage,
- errorNode: accessorWithTypeAnnotation.parameters[0],
- // TODO(jfreeman): Investigate why we are passing node.name instead of node.parameters[0].name
- typeName: accessorWithTypeAnnotation.name
- };
}
else {
if (hasModifier(accessorWithTypeAnnotation, ModifierFlags.Static)) {
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
- Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
- Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
- Diagnostics.Return_type_of_public_static_property_getter_from_exported_class_has_or_is_using_private_name_0;
+ Diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
+ Diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
+ Diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_private_name_1;
}
else {
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
- Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
- Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
- Diagnostics.Return_type_of_public_property_getter_from_exported_class_has_or_is_using_private_name_0;
+ Diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
+ Diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
+ Diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_private_name_1;
}
- return {
- diagnosticMessage,
- errorNode: accessorWithTypeAnnotation.name,
- typeName: undefined
- };
}
+ return {
+ diagnosticMessage,
+ errorNode: accessorWithTypeAnnotation.name,
+ typeName: accessorWithTypeAnnotation.name
+ };
}
}
diff --git a/src/compiler/diagnosticMessages.json b/src/compiler/diagnosticMessages.json
index c98fd856ebe..f39b1cf9590 100644
--- a/src/compiler/diagnosticMessages.json
+++ b/src/compiler/diagnosticMessages.json
@@ -1740,7 +1740,7 @@
"category": "Error",
"code": 2510
},
- "Cannot create an instance of the abstract class '{0}'.": {
+ "Cannot create an instance of an abstract class.": {
"category": "Error",
"code": 2511
},
@@ -2353,43 +2353,43 @@
"category": "Error",
"code": 4033
},
- "Parameter '{0}' of public static property setter from exported class has or is using name '{1}' from private module '{2}'.": {
+ "Parameter type of public static setter '{0}' from exported class has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4034
},
- "Parameter '{0}' of public static property setter from exported class has or is using private name '{1}'.": {
+ "Parameter type of public static setter '{0}' from exported class has or is using private name '{1}'.": {
"category": "Error",
"code": 4035
},
- "Parameter '{0}' of public property setter from exported class has or is using name '{1}' from private module '{2}'.": {
+ "Parameter type of public setter '{0}' from exported class has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4036
},
- "Parameter '{0}' of public property setter from exported class has or is using private name '{1}'.": {
+ "Parameter type of public setter '{0}' from exported class has or is using private name '{1}'.": {
"category": "Error",
"code": 4037
},
- "Return type of public static property getter from exported class has or is using name '{0}' from external module {1} but cannot be named.": {
+ "Return type of public static getter '{0}' from exported class has or is using name '{1}' from external module {2} but cannot be named.": {
"category": "Error",
"code": 4038
},
- "Return type of public static property getter from exported class has or is using name '{0}' from private module '{1}'.": {
+ "Return type of public static getter '{0}' from exported class has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4039
},
- "Return type of public static property getter from exported class has or is using private name '{0}'.": {
+ "Return type of public static getter '{0}' from exported class has or is using private name '{1}'.": {
"category": "Error",
"code": 4040
},
- "Return type of public property getter from exported class has or is using name '{0}' from external module {1} but cannot be named.": {
+ "Return type of public getter '{0}' from exported class has or is using name '{1}' from external module {2} but cannot be named.": {
"category": "Error",
"code": 4041
},
- "Return type of public property getter from exported class has or is using name '{0}' from private module '{1}'.": {
+ "Return type of public getter '{0}' from exported class has or is using name '{1}' from private module '{2}'.": {
"category": "Error",
"code": 4042
},
- "Return type of public property getter from exported class has or is using private name '{0}'.": {
+ "Return type of public getter '{0}' from exported class has or is using private name '{1}'.": {
"category": "Error",
"code": 4043
},
@@ -3866,5 +3866,13 @@
"Install '{0}'": {
"category": "Message",
"code": 95014
+ },
+ "Import '{0}' = require(\"{1}\").": {
+ "category": "Message",
+ "code": 95015
+ },
+ "Import * as '{0}' from \"{1}\".": {
+ "category": "Message",
+ "code": 95016
}
}
diff --git a/src/compiler/factory.ts b/src/compiler/factory.ts
index 760f4ddc2fa..351c39bc880 100644
--- a/src/compiler/factory.ts
+++ b/src/compiler/factory.ts
@@ -70,11 +70,10 @@ namespace ts {
// Literals
- export function createLiteral(value: string): StringLiteral;
+ /** If a node is passed, creates a string literal whose source text is read from a source node during emit. */
+ export function createLiteral(value: string | StringLiteral | NumericLiteral | Identifier): StringLiteral;
export function createLiteral(value: number): NumericLiteral;
export function createLiteral(value: boolean): BooleanLiteral;
- /** Create a string literal whose source text is read from a source node during emit. */
- export function createLiteral(sourceNode: StringLiteral | NumericLiteral | Identifier): StringLiteral;
export function createLiteral(value: string | number | boolean): PrimaryExpression;
export function createLiteral(value: string | number | boolean | StringLiteral | NumericLiteral | Identifier): PrimaryExpression {
if (typeof value === "number") {
@@ -113,6 +112,7 @@ namespace ts {
export function createIdentifier(text: string): Identifier;
/* @internal */
+ // tslint:disable-next-line unified-signatures
export function createIdentifier(text: string, typeArguments: ReadonlyArray): Identifier;
export function createIdentifier(text: string, typeArguments?: ReadonlyArray): Identifier {
const node = createSynthesizedNode(SyntaxKind.Identifier);
@@ -166,6 +166,7 @@ namespace ts {
/** Create a unique name generated for a node. */
export function getGeneratedNameForNode(node: Node): Identifier;
+ // tslint:disable-next-line unified-signatures
/*@internal*/ export function getGeneratedNameForNode(node: Node, shouldSkipNameGenerationScope?: boolean): Identifier;
export function getGeneratedNameForNode(node: Node, shouldSkipNameGenerationScope?: boolean): Identifier {
const name = createIdentifier("");
@@ -4320,7 +4321,7 @@ namespace ts {
const namespaceDeclaration = getNamespaceDeclarationNode(node);
if (namespaceDeclaration && !isDefaultImport(node)) {
const name = namespaceDeclaration.name;
- return isGeneratedIdentifier(name) ? name : createIdentifier(getSourceTextOfNodeFromSourceFile(sourceFile, namespaceDeclaration.name));
+ return isGeneratedIdentifier(name) ? name : createIdentifier(getSourceTextOfNodeFromSourceFile(sourceFile, name) || idText(name));
}
if (node.kind === SyntaxKind.ImportDeclaration && (node).importClause) {
return getGeneratedNameForNode(node);
diff --git a/src/compiler/parser.ts b/src/compiler/parser.ts
index 84e372c19da..56ecc8904d1 100644
--- a/src/compiler/parser.ts
+++ b/src/compiler/parser.ts
@@ -531,6 +531,18 @@ namespace ts {
let TokenConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
let IdentifierConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
let SourceFileConstructor: new (kind: SyntaxKind, pos: number, end: number) => Node;
+ interface Fail extends Node { kind: SyntaxKind.Unknown; }
+ interface FailList extends NodeArray { pos: -1; }
+ let Fail: Fail;
+ let FailList: FailList;
+ function isFail(x: Node | undefined): x is Fail {
+ Debug.assert(Fail !== undefined);
+ return x === Fail;
+ }
+ function isFailList(x: NodeArray | undefined): x is FailList {
+ Debug.assert(Fail !== undefined);
+ return x === FailList;
+ }
// tslint:enable variable-name
let sourceFile: SourceFile;
@@ -681,6 +693,9 @@ namespace ts {
IdentifierConstructor = objectAllocator.getIdentifierConstructor();
SourceFileConstructor = objectAllocator.getSourceFileConstructor();
+ Fail = createNode(SyntaxKind.Unknown) as Fail;
+ FailList = createNodeArray([], -1) as FailList;
+
sourceText = _sourceText;
syntaxCursor = _syntaxCursor;
@@ -736,7 +751,7 @@ namespace ts {
processReferenceComments(sourceFile);
sourceFile.statements = parseList(ParsingContext.SourceElements, parseStatement);
- Debug.assert(token() === SyntaxKind.EndOfFileToken);
+ Debug.assertEqual(token(), SyntaxKind.EndOfFileToken);
sourceFile.endOfFileToken = addJSDocComment(parseTokenNode() as EndOfFileToken);
setExternalModuleIndicator(sourceFile);
@@ -1003,7 +1018,7 @@ namespace ts {
return currentToken = scanner.scanJsxAttributeValue();
}
- function speculationHelper(callback: () => T, isLookAhead: boolean): T {
+ function speculationHelper(callback: () => T, isLookAhead: boolean): T | undefined {
// Keep track of the state we'll need to rollback to if lookahead fails (or if the
// caller asked us to always reset our state).
const saveToken = currentToken;
@@ -1015,6 +1030,7 @@ namespace ts {
// descent nature of our parser. However, we still store this here just so we can
// assert that invariant holds.
const saveContextFlags = contextFlags;
+ const saveParsingContext = parsingContext;
// If we're only looking ahead, then tell the scanner to only lookahead as well.
// Otherwise, if we're actually speculatively parsing, then tell the scanner to do the
@@ -1023,7 +1039,8 @@ namespace ts {
? scanner.lookAhead(callback)
: scanner.tryScan(callback);
- Debug.assert(saveContextFlags === contextFlags);
+ Debug.assertEqual(saveContextFlags, contextFlags);
+ Debug.assertEqual(saveParsingContext, parsingContext);
// If our callback returned something 'falsy' or we're just looking ahead,
// then unconditionally restore us to where we were.
@@ -1577,7 +1594,7 @@ namespace ts {
return createNodeArray(list, listPos);
}
- function parseListElement(parsingContext: ParsingContext, parseElement: () => T): T {
+ function parseListElement(parsingContext: ParsingContext, parseElement: () => T): T {
const node = currentNode(parsingContext);
if (node) {
return consumeNode(node);
@@ -1901,17 +1918,24 @@ namespace ts {
}
// Parses a comma-delimited list of elements
- function parseDelimitedList(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray {
+ function parseDelimitedList(kind: ParsingContext, parseElement: () => T, considerSemicolonAsDelimiter?: boolean): NodeArray;
+ function parseDelimitedList(kind: ParsingContext, parseElement: () => T | Fail, considerSemicolonAsDelimiter?: boolean): NodeArray | FailList;
+ function parseDelimitedList(kind: ParsingContext, parseElement: () => T | Fail, considerSemicolonAsDelimiter?: boolean): NodeArray | FailList {
const saveParsingContext = parsingContext;
parsingContext |= 1 << kind;
- const list = [];
+ const list: T[] = [];
const listPos = getNodePos();
let commaStart = -1; // Meaning the previous token was not a comma
while (true) {
if (isListElement(kind, /*inErrorRecovery*/ false)) {
const startPos = scanner.getStartPos();
- list.push(parseListElement(kind, parseElement));
+ const elem = parseListElement(kind, parseElement);
+ if (isFail(elem)) {
+ parsingContext = saveParsingContext;
+ return FailList;
+ }
+ list.push(elem);
commaStart = scanner.getTokenPos();
if (parseOptional(SyntaxKind.CommaToken)) {
@@ -2271,7 +2295,13 @@ namespace ts {
isStartOfType(/*inStartOfParameter*/ true);
}
- function parseParameter(requireEqualsToken?: boolean): ParameterDeclaration {
+ function tryParseParameter(): ParameterDeclaration | Fail {
+ return parseParameterWorker(/*inSpeculation*/ true);
+ }
+ function parseParameter(): ParameterDeclaration {
+ return parseParameterWorker(/*inSpeculation*/ false) as ParameterDeclaration;
+ }
+ function parseParameterWorker(inSpeculation: boolean): ParameterDeclaration | Fail {
const node = createNode(SyntaxKind.Parameter);
if (token() === SyntaxKind.ThisKeyword) {
node.name = createIdentifier(/*isIdentifier*/ true);
@@ -2285,7 +2315,11 @@ namespace ts {
// FormalParameter [Yield,Await]:
// BindingElement[?Yield,?Await]
- node.name = parseIdentifierOrPattern();
+ const name = parseIdentifierOrPattern(inSpeculation);
+ if (isFail(name)) {
+ return Fail;
+ }
+ node.name = name;
if (getFullWidth(node.name) === 0 && !hasModifiers(node) && isModifierKind(token())) {
// in cases like
// 'use strict'
@@ -2300,20 +2334,27 @@ namespace ts {
node.questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
node.type = parseParameterType();
- node.initializer = parseInitializer(/*inParameter*/ true, requireEqualsToken);
+ const initializer = parseInitializer(/*inParameter*/ true, inSpeculation);
+ if (isFail(initializer)) {
+ return Fail;
+ }
+ node.initializer = initializer;
return addJSDocComment(finishNode(node));
}
- function fillSignature(
- returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken,
- flags: SignatureFlags,
- signature: SignatureDeclaration): void {
+ /** @return 'true' on success. */
+ function fillSignature(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, flags: SignatureFlags, signature: SignatureDeclaration, inSpeculation?: boolean): boolean {
if (!(flags & SignatureFlags.JSDoc)) {
signature.typeParameters = parseTypeParameters();
}
- signature.parameters = parseParameterList(flags);
+ const parameters = parseParameterList(flags, inSpeculation);
+ if (isFailList(parameters)) {
+ return false;
+ }
+ signature.parameters = parameters;
signature.type = parseReturnType(returnToken, !!(flags & SignatureFlags.Type));
+ return true;
}
function parseReturnType(returnToken: SyntaxKind.ColonToken | SyntaxKind.EqualsGreaterThanToken, isType: boolean): TypeNode | undefined {
@@ -2336,7 +2377,7 @@ namespace ts {
return false;
}
- function parseParameterList(flags: SignatureFlags) {
+ function parseParameterList(flags: SignatureFlags, inSpeculation: boolean): NodeArray | FailList {
// FormalParameters [Yield,Await]: (modified)
// [empty]
// FormalParameterList[?Yield,Await]
@@ -2357,9 +2398,9 @@ namespace ts {
setYieldContext(!!(flags & SignatureFlags.Yield));
setAwaitContext(!!(flags & SignatureFlags.Await));
- const result = parseDelimitedList(ParsingContext.Parameters,
- flags & SignatureFlags.JSDoc ? parseJSDocParameter : () => parseParameter(!!(flags & SignatureFlags.RequireCompleteParameterList)));
-
+ const result = parseDelimitedList(
+ ParsingContext.Parameters,
+ flags & SignatureFlags.JSDoc ? parseJSDocParameter : inSpeculation ? tryParseParameter : parseParameter);
setYieldContext(savedYieldContext);
setAwaitContext(savedAwaitContext);
@@ -3035,14 +3076,16 @@ namespace ts {
while ((operatorToken = parseOptionalToken(SyntaxKind.CommaToken))) {
expr = makeBinaryExpression(expr, operatorToken, parseAssignmentExpressionOrHigher());
}
-
if (saveDecoratorContext) {
setDecoratorContext(/*val*/ true);
}
+
return expr;
}
- function parseInitializer(inParameter: boolean, requireEqualsToken?: boolean): Expression {
+ function parseInitializer(inParameter: boolean): Expression | undefined;
+ function parseInitializer(inParameter: boolean, inSpeculation?: boolean): Expression | Fail | undefined;
+ function parseInitializer(inParameter: boolean, inSpeculation?: boolean): Expression | Fail | undefined {
if (token() !== SyntaxKind.EqualsToken) {
// It's not uncommon during typing for the user to miss writing the '=' token. Check if
// there is no newline after the last token and if we're on an expression. If so, parse
@@ -3057,12 +3100,8 @@ namespace ts {
// do not try to parse initializer
return undefined;
}
- if (inParameter && requireEqualsToken) {
- // = is required when speculatively parsing arrow function parameters,
- // so return a fake initializer as a signal that the equals token was missing
- const result = createMissingNode(SyntaxKind.Identifier, /*reportAtCurrentPosition*/ true, Diagnostics._0_expected, "=") as Identifier;
- result.escapedText = "= not found" as __String;
- return result;
+ if (inSpeculation) {
+ return Fail;
}
}
@@ -3228,7 +3267,7 @@ namespace ts {
// it out, but don't allow any ambiguity, and return 'undefined' if this could be an
// expression instead.
const arrowFunction = triState === Tristate.True
- ? parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity*/ true)
+ ? parseParenthesizedArrowFunctionExpressionHead(/*inSpeculation*/ false)
: tryParse(parsePossibleParenthesizedArrowFunctionExpressionHead);
if (!arrowFunction) {
@@ -3376,7 +3415,7 @@ namespace ts {
}
function parsePossibleParenthesizedArrowFunctionExpressionHead(): ArrowFunction {
- return parseParenthesizedArrowFunctionExpressionHead(/*allowAmbiguity*/ false);
+ return parseParenthesizedArrowFunctionExpressionHead(/*inSpeculation*/ true);
}
function tryParseAsyncSimpleArrowFunctionExpression(): ArrowFunction | undefined {
@@ -3412,7 +3451,7 @@ namespace ts {
return Tristate.False;
}
- function parseParenthesizedArrowFunctionExpressionHead(allowAmbiguity: boolean): ArrowFunction {
+ function parseParenthesizedArrowFunctionExpressionHead(inSpeculation: boolean): ArrowFunction | undefined {
const node = createNode(SyntaxKind.ArrowFunction);
node.modifiers = parseModifiersForArrowFunction();
const isAsync = hasModifier(node, ModifierFlags.Async) ? SignatureFlags.Await : SignatureFlags.None;
@@ -3423,7 +3462,10 @@ namespace ts {
// a => (b => c)
// And think that "(b =>" was actually a parenthesized arrow function with a missing
// close paren.
- fillSignature(SyntaxKind.ColonToken, isAsync | (allowAmbiguity ? SignatureFlags.None : SignatureFlags.RequireCompleteParameterList), node);
+
+ if (!fillSignature(SyntaxKind.ColonToken, isAsync | (inSpeculation ? SignatureFlags.RequireCompleteParameterList : SignatureFlags.None), node, inSpeculation)) {
+ return undefined;
+ }
// If we couldn't get parameters, we definitely could not parse out an arrow function.
if (!node.parameters) {
@@ -3438,8 +3480,7 @@ namespace ts {
// - "a ? (b): c" will have "(b):" parsed as a signature with a return type annotation.
//
// So we need just a bit of lookahead to ensure that it can only be a signature.
- if (!allowAmbiguity && ((token() !== SyntaxKind.EqualsGreaterThanToken && token() !== SyntaxKind.OpenBraceToken) ||
- find(node.parameters, p => p.initializer && ts.isIdentifier(p.initializer) && p.initializer.escapedText === "= not found"))) {
+ if (inSpeculation && token() !== SyntaxKind.EqualsGreaterThanToken && token() !== SyntaxKind.OpenBraceToken) {
// Returning undefined here will cause our caller to rewind to where we started from.
return undefined;
}
@@ -4577,7 +4618,6 @@ namespace ts {
if (saveDecoratorContext) {
setDecoratorContext(/*val*/ false);
}
-
const node = createNode(SyntaxKind.FunctionExpression);
node.modifiers = parseModifiers();
parseExpected(SyntaxKind.FunctionKeyword);
@@ -4593,7 +4633,6 @@ namespace ts {
fillSignature(SyntaxKind.ColonToken, isGenerator | isAsync, node);
node.body = parseFunctionBlock(isGenerator | isAsync);
-
if (saveDecoratorContext) {
setDecoratorContext(/*val*/ true);
}
@@ -4656,7 +4695,6 @@ namespace ts {
}
const block = parseBlock(!!(flags & SignatureFlags.IgnoreMissingOpenBrace), diagnosticMessage);
-
if (saveDecoratorContext) {
setDecoratorContext(/*val*/ true);
}
@@ -5230,18 +5268,38 @@ namespace ts {
// DECLARATIONS
+ function tryParseArrayBindingElement(): ArrayBindingElement | Fail {
+ return parseArrayBindingElementWorker(/*inSpeculation*/ true);
+ }
function parseArrayBindingElement(): ArrayBindingElement {
+ return parseArrayBindingElementWorker(/*inSpeculation*/ false) as ArrayBindingElement;
+ }
+ function parseArrayBindingElementWorker(inSpeculation: boolean): ArrayBindingElement | Fail {
if (token() === SyntaxKind.CommaToken) {
return createNode(SyntaxKind.OmittedExpression);
}
const node = createNode(SyntaxKind.BindingElement);
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
- node.name = parseIdentifierOrPattern();
- node.initializer = parseInitializer(/*inParameter*/ false);
+ const name = parseIdentifierOrPattern(inSpeculation);
+ if (isFail(name)) {
+ return Fail;
+ }
+ node.name = name;
+ const init = parseInitializer(/*inParameter*/ false, inSpeculation);
+ if (isFail(init)) {
+ return Fail;
+ }
+ node.initializer = init;
return finishNode(node);
}
+ function tryParseObjectBindingElement(): BindingElement | Fail {
+ return parseObjectBindingElementWorker(/*inSpeculation*/ true);
+ }
function parseObjectBindingElement(): BindingElement {
+ return parseObjectBindingElementWorker(/*inSpeculation*/ false) as BindingElement;
+ }
+ function parseObjectBindingElementWorker(inSpeculation: boolean): BindingElement | Fail {
const node = createNode(SyntaxKind.BindingElement);
node.dotDotDotToken = parseOptionalToken(SyntaxKind.DotDotDotToken);
const tokenIsIdentifier = isIdentifier();
@@ -5252,24 +5310,46 @@ namespace ts {
else {
parseExpected(SyntaxKind.ColonToken);
node.propertyName = propertyName;
- node.name = parseIdentifierOrPattern();
+ const name = parseIdentifierOrPattern(inSpeculation);
+ if (isFail(name)) {
+ return Fail;
+ }
+ node.name = name;
}
- node.initializer = parseInitializer(/*inParameter*/ false);
+ const init = parseInitializer(/*inParameter*/ false, inSpeculation);
+ if (isFail(init)) {
+ return Fail;
+ }
+ node.initializer = init;
return finishNode(node);
}
- function parseObjectBindingPattern(): ObjectBindingPattern {
+ function parseObjectBindingPattern(inSpeculation: boolean): ObjectBindingPattern | Fail {
const node = createNode(SyntaxKind.ObjectBindingPattern);
parseExpected(SyntaxKind.OpenBraceToken);
- node.elements = parseDelimitedList(ParsingContext.ObjectBindingElements, parseObjectBindingElement);
+ const elements = parseDelimitedList(
+ ParsingContext.ObjectBindingElements,
+ inSpeculation ? tryParseObjectBindingElement : parseObjectBindingElement,
+ /*considerSemicolonAsDelimiter*/ undefined);
+ if (isFailList(elements)) {
+ return Fail;
+ }
+ node.elements = elements;
parseExpected(SyntaxKind.CloseBraceToken);
return finishNode(node);
}
- function parseArrayBindingPattern(): ArrayBindingPattern {
+ function parseArrayBindingPattern(inSpeculation: boolean): ArrayBindingPattern | Fail {
const node = createNode(SyntaxKind.ArrayBindingPattern);
parseExpected(SyntaxKind.OpenBracketToken);
- node.elements = parseDelimitedList(ParsingContext.ArrayBindingElements, parseArrayBindingElement);
+ const elements = parseDelimitedList(
+ ParsingContext.ArrayBindingElements,
+ inSpeculation ? tryParseArrayBindingElement : parseArrayBindingElement,
+ /*considerSemicolonAsDelimiter*/ undefined);
+ if (isFailList(elements)) {
+ return Fail;
+ }
+ node.elements = elements;
parseExpected(SyntaxKind.CloseBracketToken);
return finishNode(node);
}
@@ -5278,12 +5358,14 @@ namespace ts {
return token() === SyntaxKind.OpenBraceToken || token() === SyntaxKind.OpenBracketToken || isIdentifier();
}
- function parseIdentifierOrPattern(): Identifier | BindingPattern {
+ function parseIdentifierOrPattern(): Identifier | BindingPattern;
+ function parseIdentifierOrPattern(inSpeculation: boolean): Identifier | BindingPattern | Fail;
+ function parseIdentifierOrPattern(inSpeculation?: boolean): Identifier | BindingPattern | Fail {
if (token() === SyntaxKind.OpenBracketToken) {
- return parseArrayBindingPattern();
+ return parseArrayBindingPattern(inSpeculation);
}
if (token() === SyntaxKind.OpenBraceToken) {
- return parseObjectBindingPattern();
+ return parseObjectBindingPattern(inSpeculation);
}
return parseIdentifier();
}
@@ -5331,9 +5413,7 @@ namespace ts {
else {
const savedDisallowIn = inDisallowInContext();
setDisallowInContext(inForStatementInitializer);
-
node.declarations = parseDelimitedList(ParsingContext.VariableDeclarations, parseVariableDeclaration);
-
setDisallowInContext(savedDisallowIn);
}
@@ -5431,7 +5511,7 @@ namespace ts {
}
}
- function parseNonParameterInitializer() {
+ function parseNonParameterInitializer(): Expression | undefined {
return parseInitializer(/*inParameter*/ false);
}
@@ -6149,7 +6229,7 @@ namespace ts {
const checkJsDirectiveMatchResult = checkJsDirectiveRegEx.exec(comment);
if (checkJsDirectiveMatchResult) {
checkJsDirective = {
- enabled: compareStrings(checkJsDirectiveMatchResult[1], "@ts-check", /*ignoreCase*/ true) === Comparison.EqualTo,
+ enabled: equateStringsCaseInsensitive(checkJsDirectiveMatchResult[1], "@ts-check"),
end: range.end,
pos: range.pos
};
diff --git a/src/compiler/performance.ts b/src/compiler/performance.ts
index 8c24b3b9f1b..104148ed4ab 100644
--- a/src/compiler/performance.ts
+++ b/src/compiler/performance.ts
@@ -10,9 +10,8 @@ namespace ts {
namespace ts.performance {
declare const onProfilerEvent: { (markName: string): void; profiler: boolean; };
- const profilerEvent = typeof onProfilerEvent === "function" && onProfilerEvent.profiler === true
- ? onProfilerEvent
- : (_markName: string) => { };
+ // NOTE: cannot use ts.noop as core.ts loads after this
+ const profilerEvent: (markName: string) => void = typeof onProfilerEvent === "function" && onProfilerEvent.profiler === true ? onProfilerEvent : () => { /*empty*/ };
let enabled = false;
let profilerStart = 0;
diff --git a/src/compiler/program.ts b/src/compiler/program.ts
index 49f9cb98835..cf7c03556f1 100755
--- a/src/compiler/program.ts
+++ b/src/compiler/program.ts
@@ -1093,11 +1093,12 @@ namespace ts {
// If '--lib' is not specified, include default library file according to '--target'
// otherwise, using options specified in '--lib' instead of '--target' default library file
+ const equalityComparer = host.useCaseSensitiveFileNames() ? equateStringsCaseSensitive : equateStringsCaseInsensitive;
if (!options.lib) {
- return compareStrings(file.fileName, getDefaultLibraryFileName(), /*ignoreCase*/ !host.useCaseSensitiveFileNames()) === Comparison.EqualTo;
+ return equalityComparer(file.fileName, getDefaultLibraryFileName());
}
else {
- return forEach(options.lib, libFileName => compareStrings(file.fileName, combinePaths(defaultLibraryPath, libFileName), /*ignoreCase*/ !host.useCaseSensitiveFileNames()) === Comparison.EqualTo);
+ return forEach(options.lib, libFileName => equalityComparer(file.fileName, combinePaths(defaultLibraryPath, libFileName)));
}
}
@@ -1178,11 +1179,11 @@ namespace ts {
return emitResult;
}
- function getSourceFile(fileName: string): SourceFile {
+ function getSourceFile(fileName: string): SourceFile | undefined {
return getSourceFileByPath(toPath(fileName));
}
- function getSourceFileByPath(path: Path): SourceFile {
+ function getSourceFileByPath(path: Path): SourceFile | undefined {
return filesByName.get(path);
}
diff --git a/src/compiler/scanner.ts b/src/compiler/scanner.ts
index 025bf786f84..153b3693b46 100644
--- a/src/compiler/scanner.ts
+++ b/src/compiler/scanner.ts
@@ -295,7 +295,7 @@ namespace ts {
}
/* @internal */
- export function stringToToken(s: string): SyntaxKind {
+ export function stringToToken(s: string): SyntaxKind | undefined {
return textToToken.get(s);
}
@@ -356,7 +356,7 @@ namespace ts {
* We assume the first line starts at position 0 and 'position' is non-negative.
*/
export function computeLineAndCharacterOfPosition(lineStarts: ReadonlyArray, position: number): LineAndCharacter {
- let lineNumber = binarySearch(lineStarts, position);
+ let lineNumber = binarySearch(lineStarts, position, identity, compareValues);
if (lineNumber < 0) {
// If the actual position was not found,
// the binary search returns the 2's-complement of the next line start
diff --git a/src/compiler/sys.ts b/src/compiler/sys.ts
index 2400266f9c7..529ece36fa6 100644
--- a/src/compiler/sys.ts
+++ b/src/compiler/sys.ts
@@ -511,7 +511,7 @@ namespace ts {
return stat.size;
}
}
- catch (e) { }
+ catch { /*ignore*/ }
return 0;
},
exit(exitCode?: number): void {
@@ -525,7 +525,7 @@ namespace ts {
try {
require("source-map-support").install();
}
- catch (e) {
+ catch {
// Could not enable source maps.
}
},
diff --git a/src/compiler/transformers/jsx.ts b/src/compiler/transformers/jsx.ts
index 2be6cdef0bc..ab44db8ef4b 100644
--- a/src/compiler/transformers/jsx.ts
+++ b/src/compiler/transformers/jsx.ts
@@ -309,258 +309,258 @@ namespace ts {
}
const entities = createMapFromTemplate({
- "quot": 0x0022,
- "amp": 0x0026,
- "apos": 0x0027,
- "lt": 0x003C,
- "gt": 0x003E,
- "nbsp": 0x00A0,
- "iexcl": 0x00A1,
- "cent": 0x00A2,
- "pound": 0x00A3,
- "curren": 0x00A4,
- "yen": 0x00A5,
- "brvbar": 0x00A6,
- "sect": 0x00A7,
- "uml": 0x00A8,
- "copy": 0x00A9,
- "ordf": 0x00AA,
- "laquo": 0x00AB,
- "not": 0x00AC,
- "shy": 0x00AD,
- "reg": 0x00AE,
- "macr": 0x00AF,
- "deg": 0x00B0,
- "plusmn": 0x00B1,
- "sup2": 0x00B2,
- "sup3": 0x00B3,
- "acute": 0x00B4,
- "micro": 0x00B5,
- "para": 0x00B6,
- "middot": 0x00B7,
- "cedil": 0x00B8,
- "sup1": 0x00B9,
- "ordm": 0x00BA,
- "raquo": 0x00BB,
- "frac14": 0x00BC,
- "frac12": 0x00BD,
- "frac34": 0x00BE,
- "iquest": 0x00BF,
- "Agrave": 0x00C0,
- "Aacute": 0x00C1,
- "Acirc": 0x00C2,
- "Atilde": 0x00C3,
- "Auml": 0x00C4,
- "Aring": 0x00C5,
- "AElig": 0x00C6,
- "Ccedil": 0x00C7,
- "Egrave": 0x00C8,
- "Eacute": 0x00C9,
- "Ecirc": 0x00CA,
- "Euml": 0x00CB,
- "Igrave": 0x00CC,
- "Iacute": 0x00CD,
- "Icirc": 0x00CE,
- "Iuml": 0x00CF,
- "ETH": 0x00D0,
- "Ntilde": 0x00D1,
- "Ograve": 0x00D2,
- "Oacute": 0x00D3,
- "Ocirc": 0x00D4,
- "Otilde": 0x00D5,
- "Ouml": 0x00D6,
- "times": 0x00D7,
- "Oslash": 0x00D8,
- "Ugrave": 0x00D9,
- "Uacute": 0x00DA,
- "Ucirc": 0x00DB,
- "Uuml": 0x00DC,
- "Yacute": 0x00DD,
- "THORN": 0x00DE,
- "szlig": 0x00DF,
- "agrave": 0x00E0,
- "aacute": 0x00E1,
- "acirc": 0x00E2,
- "atilde": 0x00E3,
- "auml": 0x00E4,
- "aring": 0x00E5,
- "aelig": 0x00E6,
- "ccedil": 0x00E7,
- "egrave": 0x00E8,
- "eacute": 0x00E9,
- "ecirc": 0x00EA,
- "euml": 0x00EB,
- "igrave": 0x00EC,
- "iacute": 0x00ED,
- "icirc": 0x00EE,
- "iuml": 0x00EF,
- "eth": 0x00F0,
- "ntilde": 0x00F1,
- "ograve": 0x00F2,
- "oacute": 0x00F3,
- "ocirc": 0x00F4,
- "otilde": 0x00F5,
- "ouml": 0x00F6,
- "divide": 0x00F7,
- "oslash": 0x00F8,
- "ugrave": 0x00F9,
- "uacute": 0x00FA,
- "ucirc": 0x00FB,
- "uuml": 0x00FC,
- "yacute": 0x00FD,
- "thorn": 0x00FE,
- "yuml": 0x00FF,
- "OElig": 0x0152,
- "oelig": 0x0153,
- "Scaron": 0x0160,
- "scaron": 0x0161,
- "Yuml": 0x0178,
- "fnof": 0x0192,
- "circ": 0x02C6,
- "tilde": 0x02DC,
- "Alpha": 0x0391,
- "Beta": 0x0392,
- "Gamma": 0x0393,
- "Delta": 0x0394,
- "Epsilon": 0x0395,
- "Zeta": 0x0396,
- "Eta": 0x0397,
- "Theta": 0x0398,
- "Iota": 0x0399,
- "Kappa": 0x039A,
- "Lambda": 0x039B,
- "Mu": 0x039C,
- "Nu": 0x039D,
- "Xi": 0x039E,
- "Omicron": 0x039F,
- "Pi": 0x03A0,
- "Rho": 0x03A1,
- "Sigma": 0x03A3,
- "Tau": 0x03A4,
- "Upsilon": 0x03A5,
- "Phi": 0x03A6,
- "Chi": 0x03A7,
- "Psi": 0x03A8,
- "Omega": 0x03A9,
- "alpha": 0x03B1,
- "beta": 0x03B2,
- "gamma": 0x03B3,
- "delta": 0x03B4,
- "epsilon": 0x03B5,
- "zeta": 0x03B6,
- "eta": 0x03B7,
- "theta": 0x03B8,
- "iota": 0x03B9,
- "kappa": 0x03BA,
- "lambda": 0x03BB,
- "mu": 0x03BC,
- "nu": 0x03BD,
- "xi": 0x03BE,
- "omicron": 0x03BF,
- "pi": 0x03C0,
- "rho": 0x03C1,
- "sigmaf": 0x03C2,
- "sigma": 0x03C3,
- "tau": 0x03C4,
- "upsilon": 0x03C5,
- "phi": 0x03C6,
- "chi": 0x03C7,
- "psi": 0x03C8,
- "omega": 0x03C9,
- "thetasym": 0x03D1,
- "upsih": 0x03D2,
- "piv": 0x03D6,
- "ensp": 0x2002,
- "emsp": 0x2003,
- "thinsp": 0x2009,
- "zwnj": 0x200C,
- "zwj": 0x200D,
- "lrm": 0x200E,
- "rlm": 0x200F,
- "ndash": 0x2013,
- "mdash": 0x2014,
- "lsquo": 0x2018,
- "rsquo": 0x2019,
- "sbquo": 0x201A,
- "ldquo": 0x201C,
- "rdquo": 0x201D,
- "bdquo": 0x201E,
- "dagger": 0x2020,
- "Dagger": 0x2021,
- "bull": 0x2022,
- "hellip": 0x2026,
- "permil": 0x2030,
- "prime": 0x2032,
- "Prime": 0x2033,
- "lsaquo": 0x2039,
- "rsaquo": 0x203A,
- "oline": 0x203E,
- "frasl": 0x2044,
- "euro": 0x20AC,
- "image": 0x2111,
- "weierp": 0x2118,
- "real": 0x211C,
- "trade": 0x2122,
- "alefsym": 0x2135,
- "larr": 0x2190,
- "uarr": 0x2191,
- "rarr": 0x2192,
- "darr": 0x2193,
- "harr": 0x2194,
- "crarr": 0x21B5,
- "lArr": 0x21D0,
- "uArr": 0x21D1,
- "rArr": 0x21D2,
- "dArr": 0x21D3,
- "hArr": 0x21D4,
- "forall": 0x2200,
- "part": 0x2202,
- "exist": 0x2203,
- "empty": 0x2205,
- "nabla": 0x2207,
- "isin": 0x2208,
- "notin": 0x2209,
- "ni": 0x220B,
- "prod": 0x220F,
- "sum": 0x2211,
- "minus": 0x2212,
- "lowast": 0x2217,
- "radic": 0x221A,
- "prop": 0x221D,
- "infin": 0x221E,
- "ang": 0x2220,
- "and": 0x2227,
- "or": 0x2228,
- "cap": 0x2229,
- "cup": 0x222A,
- "int": 0x222B,
- "there4": 0x2234,
- "sim": 0x223C,
- "cong": 0x2245,
- "asymp": 0x2248,
- "ne": 0x2260,
- "equiv": 0x2261,
- "le": 0x2264,
- "ge": 0x2265,
- "sub": 0x2282,
- "sup": 0x2283,
- "nsub": 0x2284,
- "sube": 0x2286,
- "supe": 0x2287,
- "oplus": 0x2295,
- "otimes": 0x2297,
- "perp": 0x22A5,
- "sdot": 0x22C5,
- "lceil": 0x2308,
- "rceil": 0x2309,
- "lfloor": 0x230A,
- "rfloor": 0x230B,
- "lang": 0x2329,
- "rang": 0x232A,
- "loz": 0x25CA,
- "spades": 0x2660,
- "clubs": 0x2663,
- "hearts": 0x2665,
- "diams": 0x2666
+ quot: 0x0022,
+ amp: 0x0026,
+ apos: 0x0027,
+ lt: 0x003C,
+ gt: 0x003E,
+ nbsp: 0x00A0,
+ iexcl: 0x00A1,
+ cent: 0x00A2,
+ pound: 0x00A3,
+ curren: 0x00A4,
+ yen: 0x00A5,
+ brvbar: 0x00A6,
+ sect: 0x00A7,
+ uml: 0x00A8,
+ copy: 0x00A9,
+ ordf: 0x00AA,
+ laquo: 0x00AB,
+ not: 0x00AC,
+ shy: 0x00AD,
+ reg: 0x00AE,
+ macr: 0x00AF,
+ deg: 0x00B0,
+ plusmn: 0x00B1,
+ sup2: 0x00B2,
+ sup3: 0x00B3,
+ acute: 0x00B4,
+ micro: 0x00B5,
+ para: 0x00B6,
+ middot: 0x00B7,
+ cedil: 0x00B8,
+ sup1: 0x00B9,
+ ordm: 0x00BA,
+ raquo: 0x00BB,
+ frac14: 0x00BC,
+ frac12: 0x00BD,
+ frac34: 0x00BE,
+ iquest: 0x00BF,
+ Agrave: 0x00C0,
+ Aacute: 0x00C1,
+ Acirc: 0x00C2,
+ Atilde: 0x00C3,
+ Auml: 0x00C4,
+ Aring: 0x00C5,
+ AElig: 0x00C6,
+ Ccedil: 0x00C7,
+ Egrave: 0x00C8,
+ Eacute: 0x00C9,
+ Ecirc: 0x00CA,
+ Euml: 0x00CB,
+ Igrave: 0x00CC,
+ Iacute: 0x00CD,
+ Icirc: 0x00CE,
+ Iuml: 0x00CF,
+ ETH: 0x00D0,
+ Ntilde: 0x00D1,
+ Ograve: 0x00D2,
+ Oacute: 0x00D3,
+ Ocirc: 0x00D4,
+ Otilde: 0x00D5,
+ Ouml: 0x00D6,
+ times: 0x00D7,
+ Oslash: 0x00D8,
+ Ugrave: 0x00D9,
+ Uacute: 0x00DA,
+ Ucirc: 0x00DB,
+ Uuml: 0x00DC,
+ Yacute: 0x00DD,
+ THORN: 0x00DE,
+ szlig: 0x00DF,
+ agrave: 0x00E0,
+ aacute: 0x00E1,
+ acirc: 0x00E2,
+ atilde: 0x00E3,
+ auml: 0x00E4,
+ aring: 0x00E5,
+ aelig: 0x00E6,
+ ccedil: 0x00E7,
+ egrave: 0x00E8,
+ eacute: 0x00E9,
+ ecirc: 0x00EA,
+ euml: 0x00EB,
+ igrave: 0x00EC,
+ iacute: 0x00ED,
+ icirc: 0x00EE,
+ iuml: 0x00EF,
+ eth: 0x00F0,
+ ntilde: 0x00F1,
+ ograve: 0x00F2,
+ oacute: 0x00F3,
+ ocirc: 0x00F4,
+ otilde: 0x00F5,
+ ouml: 0x00F6,
+ divide: 0x00F7,
+ oslash: 0x00F8,
+ ugrave: 0x00F9,
+ uacute: 0x00FA,
+ ucirc: 0x00FB,
+ uuml: 0x00FC,
+ yacute: 0x00FD,
+ thorn: 0x00FE,
+ yuml: 0x00FF,
+ OElig: 0x0152,
+ oelig: 0x0153,
+ Scaron: 0x0160,
+ scaron: 0x0161,
+ Yuml: 0x0178,
+ fnof: 0x0192,
+ circ: 0x02C6,
+ tilde: 0x02DC,
+ Alpha: 0x0391,
+ Beta: 0x0392,
+ Gamma: 0x0393,
+ Delta: 0x0394,
+ Epsilon: 0x0395,
+ Zeta: 0x0396,
+ Eta: 0x0397,
+ Theta: 0x0398,
+ Iota: 0x0399,
+ Kappa: 0x039A,
+ Lambda: 0x039B,
+ Mu: 0x039C,
+ Nu: 0x039D,
+ Xi: 0x039E,
+ Omicron: 0x039F,
+ Pi: 0x03A0,
+ Rho: 0x03A1,
+ Sigma: 0x03A3,
+ Tau: 0x03A4,
+ Upsilon: 0x03A5,
+ Phi: 0x03A6,
+ Chi: 0x03A7,
+ Psi: 0x03A8,
+ Omega: 0x03A9,
+ alpha: 0x03B1,
+ beta: 0x03B2,
+ gamma: 0x03B3,
+ delta: 0x03B4,
+ epsilon: 0x03B5,
+ zeta: 0x03B6,
+ eta: 0x03B7,
+ theta: 0x03B8,
+ iota: 0x03B9,
+ kappa: 0x03BA,
+ lambda: 0x03BB,
+ mu: 0x03BC,
+ nu: 0x03BD,
+ xi: 0x03BE,
+ omicron: 0x03BF,
+ pi: 0x03C0,
+ rho: 0x03C1,
+ sigmaf: 0x03C2,
+ sigma: 0x03C3,
+ tau: 0x03C4,
+ upsilon: 0x03C5,
+ phi: 0x03C6,
+ chi: 0x03C7,
+ psi: 0x03C8,
+ omega: 0x03C9,
+ thetasym: 0x03D1,
+ upsih: 0x03D2,
+ piv: 0x03D6,
+ ensp: 0x2002,
+ emsp: 0x2003,
+ thinsp: 0x2009,
+ zwnj: 0x200C,
+ zwj: 0x200D,
+ lrm: 0x200E,
+ rlm: 0x200F,
+ ndash: 0x2013,
+ mdash: 0x2014,
+ lsquo: 0x2018,
+ rsquo: 0x2019,
+ sbquo: 0x201A,
+ ldquo: 0x201C,
+ rdquo: 0x201D,
+ bdquo: 0x201E,
+ dagger: 0x2020,
+ Dagger: 0x2021,
+ bull: 0x2022,
+ hellip: 0x2026,
+ permil: 0x2030,
+ prime: 0x2032,
+ Prime: 0x2033,
+ lsaquo: 0x2039,
+ rsaquo: 0x203A,
+ oline: 0x203E,
+ frasl: 0x2044,
+ euro: 0x20AC,
+ image: 0x2111,
+ weierp: 0x2118,
+ real: 0x211C,
+ trade: 0x2122,
+ alefsym: 0x2135,
+ larr: 0x2190,
+ uarr: 0x2191,
+ rarr: 0x2192,
+ darr: 0x2193,
+ harr: 0x2194,
+ crarr: 0x21B5,
+ lArr: 0x21D0,
+ uArr: 0x21D1,
+ rArr: 0x21D2,
+ dArr: 0x21D3,
+ hArr: 0x21D4,
+ forall: 0x2200,
+ part: 0x2202,
+ exist: 0x2203,
+ empty: 0x2205,
+ nabla: 0x2207,
+ isin: 0x2208,
+ notin: 0x2209,
+ ni: 0x220B,
+ prod: 0x220F,
+ sum: 0x2211,
+ minus: 0x2212,
+ lowast: 0x2217,
+ radic: 0x221A,
+ prop: 0x221D,
+ infin: 0x221E,
+ ang: 0x2220,
+ and: 0x2227,
+ or: 0x2228,
+ cap: 0x2229,
+ cup: 0x222A,
+ int: 0x222B,
+ there4: 0x2234,
+ sim: 0x223C,
+ cong: 0x2245,
+ asymp: 0x2248,
+ ne: 0x2260,
+ equiv: 0x2261,
+ le: 0x2264,
+ ge: 0x2265,
+ sub: 0x2282,
+ sup: 0x2283,
+ nsub: 0x2284,
+ sube: 0x2286,
+ supe: 0x2287,
+ oplus: 0x2295,
+ otimes: 0x2297,
+ perp: 0x22A5,
+ sdot: 0x22C5,
+ lceil: 0x2308,
+ rceil: 0x2309,
+ lfloor: 0x230A,
+ rfloor: 0x230B,
+ lang: 0x2329,
+ rang: 0x232A,
+ loz: 0x25CA,
+ spades: 0x2660,
+ clubs: 0x2663,
+ hearts: 0x2665,
+ diams: 0x2666
});
}
\ No newline at end of file
diff --git a/src/compiler/transformers/module/module.ts b/src/compiler/transformers/module/module.ts
index f60e50ea365..0c8e2cda0f5 100644
--- a/src/compiler/transformers/module/module.ts
+++ b/src/compiler/transformers/module/module.ts
@@ -57,7 +57,7 @@ namespace ts {
* @param node The SourceFile node.
*/
function transformSourceFile(node: SourceFile) {
- if (node.isDeclarationFile || !(isExternalModule(node) || compilerOptions.isolatedModules || node.transformFlags & TransformFlags.ContainsDynamicImport)) {
+ if (node.isDeclarationFile || !(isEffectiveExternalModule(node, compilerOptions) || node.transformFlags & TransformFlags.ContainsDynamicImport)) {
return node;
}
diff --git a/src/compiler/tsc.ts b/src/compiler/tsc.ts
index fe4365de265..01fb45e4f7d 100644
--- a/src/compiler/tsc.ts
+++ b/src/compiler/tsc.ts
@@ -294,7 +294,7 @@ namespace ts {
// Sort our options by their names, (e.g. "--noImplicitAny" comes before "--watch")
const optsList = showAllOptions ?
- optionDeclarations.slice().sort((a, b) => compareValues(a.name.toLowerCase(), b.name.toLowerCase())) :
+ sort(optionDeclarations, (a, b) => compareStringsCaseInsensitive(a.name, b.name)) :
filter(optionDeclarations.slice(), v => v.showInSimplifiedHelpView);
// We want our descriptions to align at the same column in our output,
diff --git a/src/compiler/types.ts b/src/compiler/types.ts
index bbb6da48d23..df06606e316 100644
--- a/src/compiler/types.ts
+++ b/src/compiler/types.ts
@@ -36,6 +36,19 @@ namespace ts {
push(...values: T[]): void;
}
+ /* @internal */
+ export type EqualityComparer = (a: T, b: T) => boolean;
+
+ /* @internal */
+ export type Comparer = (a: T, b: T) => Comparison;
+
+ /* @internal */
+ export const enum Comparison {
+ LessThan = -1,
+ EqualTo = 0,
+ GreaterThan = 1
+ }
+
// branded string type used to store absolute, normalized and canonicalized paths
// arbitrary file name can be converted to Path via toPath function
export type Path = string & { __pathBrand: any };
@@ -202,7 +215,7 @@ namespace ts {
UniqueKeyword,
FromKeyword,
GlobalKeyword,
- OfKeyword, // LastKeyword and LastToken
+ OfKeyword, // LastKeyword and LastToken and LastContextualKeyword
// Parse tree nodes
@@ -419,7 +432,9 @@ namespace ts {
FirstJSDocNode = JSDocTypeExpression,
LastJSDocNode = JSDocPropertyTag,
FirstJSDocTagNode = JSDocTag,
- LastJSDocTagNode = JSDocPropertyTag
+ LastJSDocTagNode = JSDocPropertyTag,
+ /* @internal */ FirstContextualKeyword = AbstractKeyword,
+ /* @internal */ LastContextualKeyword = OfKeyword,
}
export const enum NodeFlags {
@@ -2476,8 +2491,8 @@ namespace ts {
export interface ScriptReferenceHost {
getCompilerOptions(): CompilerOptions;
- getSourceFile(fileName: string): SourceFile;
- getSourceFileByPath(path: Path): SourceFile;
+ getSourceFile(fileName: string): SourceFile | undefined;
+ getSourceFileByPath(path: Path): SourceFile | undefined;
getCurrentDirectory(): string;
}
@@ -3034,6 +3049,10 @@ namespace ts {
Optional = 1 << 24, // Optional property
Transient = 1 << 25, // Transient symbol (created during type check)
+ /* @internal */
+ All = FunctionScopedVariable | BlockScopedVariable | Property | EnumMember | Function | Class | Interface | ConstEnum | RegularEnum | ValueModule | NamespaceModule | TypeLiteral
+ | ObjectLiteral | Method | Constructor | GetAccessor | SetAccessor | Signature | TypeParameter | TypeAlias | ExportValue | Alias | Prototype | ExportStar | Optional | Transient,
+
Enum = RegularEnum | ConstEnum,
Variable = FunctionScopedVariable | BlockScopedVariable,
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor,
@@ -3635,6 +3654,7 @@ namespace ts {
NakedTypeVariable = 1 << 1, // Naked type variable in union or intersection type
MappedType = 1 << 2, // Reverse inference for mapped type
ReturnType = 1 << 3, // Inference made from return type of generic function
+ NeverType = 1 << 4, // Inference made from the never type
}
export interface InferenceInfo {
diff --git a/src/compiler/utilities.ts b/src/compiler/utilities.ts
index 4c94220e2f1..fca56d5d72e 100644
--- a/src/compiler/utilities.ts
+++ b/src/compiler/utilities.ts
@@ -322,16 +322,16 @@ namespace ts {
return getSourceTextOfNodeFromSourceFile(getSourceFileOfNode(node), node, includeTrivia);
}
+ function getPos(range: Node) {
+ return range.pos;
+ }
+
/**
* Note: it is expected that the `nodeArray` and the `node` are within the same file.
* For example, searching for a `SourceFile` in a `SourceFile[]` wouldn't work.
*/
export function indexOfNode(nodeArray: ReadonlyArray, node: Node) {
- return binarySearch(nodeArray, node, compareNodePos);
- }
-
- function compareNodePos({ pos: aPos }: Node, { pos: bPos}: Node) {
- return aPos < bPos ? Comparison.LessThan : bPos < aPos ? Comparison.GreaterThan : Comparison.EqualTo;
+ return binarySearch(nodeArray, node, getPos, compareValues);
}
/**
@@ -364,8 +364,10 @@ namespace ts {
case SyntaxKind.NoSubstitutionTemplateLiteral:
return "`" + escapeText(node.text, CharacterCodes.backtick) + "`";
case SyntaxKind.TemplateHead:
+ // tslint:disable-next-line no-invalid-template-strings
return "`" + escapeText(node.text, CharacterCodes.backtick) + "${";
case SyntaxKind.TemplateMiddle:
+ // tslint:disable-next-line no-invalid-template-strings
return "}" + escapeText(node.text, CharacterCodes.backtick) + "${";
case SyntaxKind.TemplateTail:
return "}" + escapeText(node.text, CharacterCodes.backtick) + "`";
@@ -460,7 +462,7 @@ namespace ts {
}
export function isEffectiveExternalModule(node: SourceFile, compilerOptions: CompilerOptions) {
- return isExternalModule(node) || compilerOptions.isolatedModules;
+ return isExternalModule(node) || compilerOptions.isolatedModules || ((getEmitModuleKind(compilerOptions) === ModuleKind.CommonJS) && !!node.commonJsModuleIndicator);
}
/* @internal */
@@ -1939,6 +1941,14 @@ namespace ts {
return SyntaxKind.FirstKeyword <= token && token <= SyntaxKind.LastKeyword;
}
+ export function isContextualKeyword(token: SyntaxKind): boolean {
+ return SyntaxKind.FirstContextualKeyword <= token && token <= SyntaxKind.LastContextualKeyword;
+ }
+
+ export function isNonContextualKeyword(token: SyntaxKind): boolean {
+ return isKeyword(token) && !isContextualKeyword(token);
+ }
+
export function isTrivia(token: SyntaxKind) {
return SyntaxKind.FirstTriviaToken <= token && token <= SyntaxKind.LastTriviaToken;
}
@@ -2328,6 +2338,7 @@ namespace ts {
let nonFileDiagnostics: Diagnostic[] = [];
const fileDiagnostics = createMap();
+ let hasReadNonFileDiagnostics = false;
let diagnosticsModified = false;
let modificationCount = 0;
@@ -2357,6 +2368,12 @@ namespace ts {
}
}
else {
+ // If we've already read the non-file diagnostics, do not modify the existing array.
+ if (hasReadNonFileDiagnostics) {
+ hasReadNonFileDiagnostics = false;
+ nonFileDiagnostics = nonFileDiagnostics.slice();
+ }
+
diagnostics = nonFileDiagnostics;
}
@@ -2367,6 +2384,7 @@ namespace ts {
function getGlobalDiagnostics(): Diagnostic[] {
sortAndDeduplicate();
+ hasReadNonFileDiagnostics = true;
return nonFileDiagnostics;
}
@@ -3994,6 +4012,9 @@ namespace ts {
trySetLanguageAndTerritory(language, /*territory*/ undefined, errors);
}
+ // Set the UI locale for string collation
+ setUILocale(locale);
+
function trySetLanguageAndTerritory(language: string, territory: string, errors?: Push): boolean {
const compilerFilePath = normalizePath(sys.getExecutingFilePath());
const containingDirectoryPath = getDirectoryPath(compilerFilePath);
diff --git a/src/compiler/visitor.ts b/src/compiler/visitor.ts
index 0428d2d2d2e..0b40e20a7b7 100644
--- a/src/compiler/visitor.ts
+++ b/src/compiler/visitor.ts
@@ -1585,13 +1585,13 @@ namespace ts {
// Add additional properties in debug mode to assist with debugging.
Object.defineProperties(objectAllocator.getSymbolConstructor().prototype, {
- "__debugFlags": { get(this: Symbol) { return formatSymbolFlags(this.flags); } }
+ __debugFlags: { get(this: Symbol) { return formatSymbolFlags(this.flags); } }
});
Object.defineProperties(objectAllocator.getTypeConstructor().prototype, {
- "__debugFlags": { get(this: Type) { return formatTypeFlags(this.flags); } },
- "__debugObjectFlags": { get(this: Type) { return this.flags & TypeFlags.Object ? formatObjectFlags((this).objectFlags) : ""; } },
- "__debugTypeToString": { value(this: Type) { return this.checker.typeToString(this); } },
+ __debugFlags: { get(this: Type) { return formatTypeFlags(this.flags); } },
+ __debugObjectFlags: { get(this: Type) { return this.flags & TypeFlags.Object ? formatObjectFlags((this).objectFlags) : ""; } },
+ __debugTypeToString: { value(this: Type) { return this.checker.typeToString(this); } },
});
const nodeConstructors = [
@@ -1604,11 +1604,11 @@ namespace ts {
for (const ctor of nodeConstructors) {
if (!ctor.prototype.hasOwnProperty("__debugKind")) {
Object.defineProperties(ctor.prototype, {
- "__debugKind": { get(this: Node) { return formatSyntaxKind(this.kind); } },
- "__debugModifierFlags": { get(this: Node) { return formatModifierFlags(getModifierFlagsNoCache(this)); } },
- "__debugTransformFlags": { get(this: Node) { return formatTransformFlags(this.transformFlags); } },
- "__debugEmitFlags": { get(this: Node) { return formatEmitFlags(getEmitFlags(this)); } },
- "__debugGetText": {
+ __debugKind: { get(this: Node) { return formatSyntaxKind(this.kind); } },
+ __debugModifierFlags: { get(this: Node) { return formatModifierFlags(getModifierFlagsNoCache(this)); } },
+ __debugTransformFlags: { get(this: Node) { return formatTransformFlags(this.transformFlags); } },
+ __debugEmitFlags: { get(this: Node) { return formatEmitFlags(getEmitFlags(this)); } },
+ __debugGetText: {
value(this: Node, includeTrivia?: boolean) {
if (nodeIsSynthesized(this)) return "";
const parseNode = getParseTreeNode(this);
diff --git a/src/compiler/watch.ts b/src/compiler/watch.ts
index 53692fe1e04..8e49bb71a15 100644
--- a/src/compiler/watch.ts
+++ b/src/compiler/watch.ts
@@ -230,7 +230,7 @@ namespace ts {
function createWatchMode(rootFileNames: string[], compilerOptions: CompilerOptions, watchingHost?: WatchingSystemHost, configFileName?: string, configFileSpecs?: ConfigFileSpecs, configFileWildCardDirectories?: MapLike, optionsToExtendForConfigFile?: CompilerOptions) {
let program: Program;
- let needsReload: boolean; // true if the config file changed and needs to reload it from the disk
+ let reloadLevel: ConfigFileProgramReloadLevel; // level to indicate if the program needs to be reloaded from config file/just filenames etc
let missingFilesMap: Map; // Map of file watchers for the missing files
let watchedWildcardDirectories: Map; // map of watchers for the wild card directories in the config file
let timerToUpdateProgram: any; // timer callback to recompile the program
@@ -488,7 +488,7 @@ namespace ts {
function scheduleProgramReload() {
Debug.assert(!!configFileName);
- needsReload = true;
+ reloadLevel = ConfigFileProgramReloadLevel.Full;
scheduleProgramUpdate();
}
@@ -496,17 +496,30 @@ namespace ts {
timerToUpdateProgram = undefined;
reportWatchDiagnostic(createCompilerDiagnostic(Diagnostics.File_change_detected_Starting_incremental_compilation));
- if (needsReload) {
- reloadConfigFile();
+ switch (reloadLevel) {
+ case ConfigFileProgramReloadLevel.Partial:
+ return reloadFileNamesFromConfigFile();
+ case ConfigFileProgramReloadLevel.Full:
+ return reloadConfigFile();
+ default:
+ return synchronizeProgram();
}
- else {
- synchronizeProgram();
+ }
+
+ function reloadFileNamesFromConfigFile() {
+ const result = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFileName), compilerOptions, directoryStructureHost);
+ if (!configFileSpecs.filesSpecs && result.fileNames.length === 0) {
+ reportDiagnostic(getErrorForNoInputFiles(configFileSpecs, configFileName));
}
+ rootFileNames = result.fileNames;
+
+ // Update the program
+ synchronizeProgram();
}
function reloadConfigFile() {
writeLog(`Reloading config file: ${configFileName}`);
- needsReload = false;
+ reloadLevel = ConfigFileProgramReloadLevel.None;
const cachedHost = directoryStructureHost as CachedDirectoryStructureHost;
cachedHost.clearCache();
@@ -611,18 +624,14 @@ namespace ts {
// If the the added or created file or directory is not supported file name, ignore the file
// But when watched directory is added/removed, we need to reload the file list
- if (fileOrDirectoryPath !== directory && !isSupportedSourceFileName(fileOrDirectory, compilerOptions)) {
+ if (fileOrDirectoryPath !== directory && hasExtension(fileOrDirectoryPath) && !isSupportedSourceFileName(fileOrDirectory, compilerOptions)) {
writeLog(`Project: ${configFileName} Detected file add/remove of non supported extension: ${fileOrDirectory}`);
return;
}
// Reload is pending, do the reload
- if (!needsReload) {
- const result = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFileName), compilerOptions, directoryStructureHost);
- if (!configFileSpecs.filesSpecs && result.fileNames.length === 0) {
- reportDiagnostic(getErrorForNoInputFiles(configFileSpecs, configFileName));
- }
- rootFileNames = result.fileNames;
+ if (reloadLevel !== ConfigFileProgramReloadLevel.Full) {
+ reloadLevel = ConfigFileProgramReloadLevel.Partial;
// Schedule Update the program
scheduleProgramUpdate();
diff --git a/src/compiler/watchUtilities.ts b/src/compiler/watchUtilities.ts
index f39024d5a7c..0cf38f372d9 100644
--- a/src/compiler/watchUtilities.ts
+++ b/src/compiler/watchUtilities.ts
@@ -2,6 +2,14 @@
/* @internal */
namespace ts {
+ export enum ConfigFileProgramReloadLevel {
+ None,
+ /** Update the file name list from the disk */
+ Partial,
+ /** Reload completely by re-reading contents of config file from disk and updating program */
+ Full
+ }
+
/**
* Updates the existing missing file watches with the new set of missing files after new program is created
*/
diff --git a/src/harness/externalCompileRunner.ts b/src/harness/externalCompileRunner.ts
new file mode 100644
index 00000000000..2a44badd813
--- /dev/null
+++ b/src/harness/externalCompileRunner.ts
@@ -0,0 +1,162 @@
+///
+///
+const fs = require("fs");
+const path = require("path");
+
+interface ExecResult {
+ stdout: Buffer;
+ stderr: Buffer;
+ status: number;
+}
+
+interface UserConfig {
+ types: string[];
+}
+
+abstract class ExternalCompileRunnerBase extends RunnerBase {
+ abstract testDir: string;
+ abstract report(result: ExecResult, cwd: string): string;
+ enumerateTestFiles() {
+ return Harness.IO.getDirectories(this.testDir);
+ }
+ /** Setup the runner's tests so that they are ready to be executed by the harness
+ * The first test should be a describe/it block that sets up the harness's compiler instance appropriately
+ */
+ initializeTests(): void {
+ // Read in and evaluate the test list
+ const testList = this.tests && this.tests.length ? this.tests : this.enumerateTestFiles();
+
+ describe(`${this.kind()} code samples`, () => {
+ for (const test of testList) {
+ this.runTest(test);
+ }
+ });
+ }
+ private runTest(directoryName: string) {
+ describe(directoryName, () => {
+ const cp = require("child_process");
+
+ it("should build successfully", () => {
+ let cwd = path.join(__dirname, "../../", this.testDir, directoryName);
+ const timeout = 600000; // 600s = 10 minutes
+ const stdio = isWorker ? "pipe" : "inherit";
+ let types: string[];
+ if (fs.existsSync(path.join(cwd, "test.json"))) {
+ const update = cp.spawnSync("git", ["submodule", "update", "--remote"], { cwd, timeout, shell: true, stdio });
+ if (update.status !== 0) throw new Error(`git submodule update for ${directoryName} failed!`);
+
+ const config = JSON.parse(fs.readFileSync(path.join(cwd, "test.json"), { encoding: "utf8" })) as UserConfig;
+ ts.Debug.assert(!!config.types, "Bad format from test.json: Types field must be present.");
+ types = config.types;
+
+ cwd = path.join(cwd, directoryName);
+ }
+ if (fs.existsSync(path.join(cwd, "package.json"))) {
+ if (fs.existsSync(path.join(cwd, "package-lock.json"))) {
+ fs.unlinkSync(path.join(cwd, "package-lock.json"));
+ }
+ const install = cp.spawnSync(`npm`, ["i"], { cwd, timeout, shell: true, stdio });
+ if (install.status !== 0) throw new Error(`NPM Install for ${directoryName} failed!`);
+ }
+ const args = [path.join(__dirname, "tsc.js")];
+ if (types) {
+ args.push("--types", types.join(","));
+ }
+ args.push("--noEmit");
+ Harness.Baseline.runBaseline(`${this.kind()}/${directoryName}.log`, () => {
+ return this.report(cp.spawnSync(`node`, args, { cwd, timeout, shell: true }), cwd);
+ });
+ });
+ });
+ }
+}
+
+class UserCodeRunner extends ExternalCompileRunnerBase {
+ readonly testDir = "tests/cases/user/";
+ kind(): TestRunnerKind {
+ return "user";
+ }
+ report(result: ExecResult) {
+ // tslint:disable-next-line:no-null-keyword
+ return result.status === 0 && !result.stdout.length && !result.stderr.length ? null : `Exit Code: ${result.status}
+Standard output:
+${result.stdout.toString().replace(/\r\n/g, "\n")}
+
+
+Standard error:
+${result.stderr.toString().replace(/\r\n/g, "\n")}`;
+ }
+}
+
+class DefinitelyTypedRunner extends ExternalCompileRunnerBase {
+ readonly testDir = "../DefinitelyTyped/types/";
+ workingDirectory = this.testDir;
+ kind(): TestRunnerKind {
+ return "dt";
+ }
+ report(result: ExecResult, cwd: string) {
+ const stdout = removeExpectedErrors(result.stdout.toString(), cwd);
+ const stderr = result.stderr.toString();
+ // tslint:disable-next-line:no-null-keyword
+ return !stdout.length && !stderr.length ? null : `Exit Code: ${result.status}
+Standard output:
+${stdout.replace(/\r\n/g, "\n")}
+
+
+Standard error:
+${stderr.replace(/\r\n/g, "\n")}`;
+ }
+}
+
+function removeExpectedErrors(errors: string, cwd: string): string {
+ return ts.flatten(splitBy(errors.split("\n"), s => /^\S+/.test(s)).filter(isUnexpectedError(cwd))).join("\n");
+}
+/**
+ * Returns true if the line that caused the error contains '$ExpectError',
+ * or if the line before that one contains '$ExpectError'.
+ * '$ExpectError' is a marker used in Definitely Typed tests,
+ * meaning that the error should not contribute toward our error baslines.
+ */
+function isUnexpectedError(cwd: string) {
+ return (error: string[]) => {
+ ts.Debug.assertGreaterThanOrEqual(error.length, 1);
+ const match = error[0].match(/(.+\.ts)\((\d+),\d+\): error TS/);
+ if (!match) {
+ return true;
+ }
+ const [, errorFile, lineNumberString] = match;
+ const lines = fs.readFileSync(path.join(cwd, errorFile), { encoding: "utf8" }).split("\n");
+ const lineNumber = parseInt(lineNumberString);
+ ts.Debug.assertGreaterThanOrEqual(lineNumber, 0);
+ ts.Debug.assertLessThan(lineNumber, lines.length);
+ const previousLine = lineNumber - 1 > 0 ? lines[lineNumber - 1] : "";
+ return !ts.stringContains(lines[lineNumber], "$ExpectError") && !ts.stringContains(previousLine, "$ExpectError");
+ };
+}
+/**
+ * Split an array into multiple arrays whenever `isStart` returns true.
+ * @example
+ * splitBy([1,2,3,4,5,6], isOdd)
+ * ==> [[1, 2], [3, 4], [5, 6]]
+ * where
+ * const isOdd = n => !!(n % 2)
+ */
+function splitBy(xs: T[], isStart: (x: T) => boolean): T[][] {
+ const result = [];
+ let group: T[] = [];
+ for (const x of xs) {
+ if (isStart(x)) {
+ if (group.length) {
+ result.push(group);
+ }
+ group = [x];
+ }
+ else {
+ group.push(x);
+ }
+ }
+ if (group.length) {
+ result.push(group);
+ }
+ return result;
+}
diff --git a/src/harness/fourslash.ts b/src/harness/fourslash.ts
index 85011525d52..2687a660ca8 100644
--- a/src/harness/fourslash.ts
+++ b/src/harness/fourslash.ts
@@ -483,9 +483,7 @@ namespace FourSlash {
}
// Opens a file given its 0-based index or fileName
- public openFile(index: number, content?: string, scriptKindName?: string): void;
- public openFile(name: string, content?: string, scriptKindName?: string): void;
- public openFile(indexOrName: any, content?: string, scriptKindName?: string) {
+ public openFile(indexOrName: number | string, content?: string, scriptKindName?: string): void {
const fileToOpen: FourSlashFile = this.findFile(indexOrName);
fileToOpen.fileName = ts.normalizeSlashes(fileToOpen.fileName);
this.activeFile = fileToOpen;
@@ -566,15 +564,31 @@ namespace FourSlash {
}
for (const { start, length, messageText, file } of errors) {
- Harness.IO.log(" from: " + showPosition(file, start) +
- ", to: " + showPosition(file, start + length) +
+ Harness.IO.log(" " + this.formatRange(file, start, length) +
", message: " + ts.flattenDiagnosticMessageText(messageText, Harness.IO.newLine()) + "\n");
}
+ }
- function showPosition(file: ts.SourceFile, pos: number) {
+ private formatRange(file: ts.SourceFile, start: number, length: number) {
+ if (file) {
+ return `from: ${this.formatLineAndCharacterOfPosition(file, start)}, to: ${this.formatLineAndCharacterOfPosition(file, start + length)}`;
+ }
+ return "global";
+ }
+
+ private formatLineAndCharacterOfPosition(file: ts.SourceFile, pos: number) {
+ if (file) {
const { line, character } = ts.getLineAndCharacterOfPosition(file, pos);
return `${line}:${character}`;
}
+ return "global";
+ }
+
+ private formatPosition(file: ts.SourceFile, pos: number) {
+ if (file) {
+ return file.fileName + "@" + pos;
+ }
+ return "global";
}
public verifyNoErrors() {
@@ -584,7 +598,7 @@ namespace FourSlash {
if (errors.length) {
this.printErrorLog(/*expectErrors*/ false, errors);
const error = errors[0];
- this.raiseError(`Found an error: ${error.file.fileName}@${error.start}: ${error.messageText}`);
+ this.raiseError(`Found an error: ${this.formatPosition(error.file, error.start)}: ${error.messageText}`);
}
});
}
@@ -3088,12 +3102,12 @@ Actual: ${stringify(fullActual)}`);
}
}
- const itemsString = items.map(item => stringify({ name: item.name, kind: item.kind })).join(",\n");
+ const itemsString = items.map(item => stringify({ name: item.name, source: item.source, kind: item.kind })).join(",\n");
this.raiseError(`Expected "${stringify({ entryId, text, documentation, kind })}" to be in list [${itemsString}]`);
}
- private findFile(indexOrName: any) {
+ private findFile(indexOrName: string | number) {
let result: FourSlashFile;
if (typeof indexOrName === "number") {
const index = indexOrName;
@@ -3745,9 +3759,7 @@ namespace FourSlashInterface {
this.state.goToImplementation();
}
- public position(position: number, fileIndex?: number): void;
- public position(position: number, fileName?: string): void;
- public position(position: number, fileNameOrIndex?: any): void {
+ public position(position: number, fileNameOrIndex?: string | number): void {
if (fileNameOrIndex !== undefined) {
this.file(fileNameOrIndex);
}
@@ -3757,9 +3769,7 @@ namespace FourSlashInterface {
// Opens a file, given either its index as it
// appears in the test source, or its filename
// as specified in the test metadata
- public file(index: number, content?: string, scriptKindName?: string): void;
- public file(name: string, content?: string, scriptKindName?: string): void;
- public file(indexOrName: any, content?: string, scriptKindName?: string): void {
+ public file(indexOrName: number | string, content?: string, scriptKindName?: string): void {
this.state.openFile(indexOrName, content, scriptKindName);
}
@@ -3966,17 +3976,14 @@ namespace FourSlashInterface {
this.state.verifyGoToDefinitionIs(endMarkers);
}
- public goToDefinition(startMarkerName: string | string[], endMarkerName: string | string[]): void;
- public goToDefinition(startMarkerName: string | string[], endMarkerName: string | string[], range: FourSlash.Range): void;
- public goToDefinition(startsAndEnds: [string | string[], string | string[]][]): void;
- public goToDefinition(startsAndEnds: { [startMarkerName: string]: string | string[] }): void;
+ public goToDefinition(startMarkerName: string | string[], endMarkerName: string | string[], range?: FourSlash.Range): void;
+ public goToDefinition(startsAndEnds: [string | string[], string | string[]][] | { [startMarkerName: string]: string | string[] }): void;
public goToDefinition(arg0: any, endMarkerName?: string | string[]) {
this.state.verifyGoToDefinition(arg0, endMarkerName);
}
public goToType(startMarkerName: string | string[], endMarkerName: string | string[]): void;
- public goToType(startsAndEnds: [string | string[], string | string[]][]): void;
- public goToType(startsAndEnds: { [startMarkerName: string]: string | string[] }): void;
+ public goToType(startsAndEnds: [string | string[], string | string[]][] | { [startMarkerName: string]: string | string[] }): void;
public goToType(arg0: any, endMarkerName?: string | string[]) {
this.state.verifyGoToType(arg0, endMarkerName);
}
diff --git a/src/harness/harness.ts b/src/harness/harness.ts
index 61ea4508363..8a3202b88be 100644
--- a/src/harness/harness.ts
+++ b/src/harness/harness.ts
@@ -555,8 +555,7 @@ namespace Harness {
try {
fs.unlinkSync(path);
}
- catch (e) {
- }
+ catch { /*ignore*/ }
}
export function directoryExists(path: string): boolean {
@@ -615,7 +614,7 @@ namespace Harness {
namespace Http {
function waitForXHR(xhr: XMLHttpRequest) {
- while (xhr.readyState !== 4) { }
+ while (xhr.readyState !== 4) { } // tslint:disable-line no-empty
return { status: xhr.status, responseText: xhr.responseText };
}
@@ -1324,7 +1323,7 @@ namespace Harness {
export const diagnosticSummaryMarker = "__diagnosticSummary";
export const globalErrorsMarker = "__globalErrors";
export function *iterateErrorBaseline(inputFiles: ReadonlyArray, diagnostics: ReadonlyArray, pretty?: boolean): IterableIterator<[string, string, number]> {
- diagnostics = diagnostics.slice().sort(ts.compareDiagnostics);
+ diagnostics = ts.sort(diagnostics, ts.compareDiagnostics);
let outputLines = "";
// Count up all errors that were found in files other than lib.d.ts so we don't miss any
let totalErrorsReportedInNonLibraryFiles = 0;
@@ -1707,7 +1706,7 @@ namespace Harness {
export function *iterateOutputs(outputFiles: Harness.Compiler.GeneratedFile[]): IterableIterator<[string, string]> {
// Collect, test, and sort the fileNames
- outputFiles.sort((a, b) => ts.compareStrings(cleanName(a.fileName), cleanName(b.fileName)));
+ outputFiles.sort((a, b) => ts.compareStringsCaseSensitive(cleanName(a.fileName), cleanName(b.fileName)));
const dupeCase = ts.createMap();
// Yield them
for (const outputFile of outputFiles) {
@@ -2147,8 +2146,8 @@ namespace Harness {
return filePath.indexOf(Harness.libFolder) === 0;
}
- export function getDefaultLibraryFile(io: Harness.Io): Harness.Compiler.TestFile {
- const libFile = Harness.userSpecifiedRoot + Harness.libFolder + Harness.Compiler.defaultLibFileName;
+ export function getDefaultLibraryFile(filePath: string, io: Harness.Io): Harness.Compiler.TestFile {
+ const libFile = Harness.userSpecifiedRoot + Harness.libFolder + ts.getBaseFileName(ts.normalizeSlashes(filePath));
return { unitName: libFile, content: io.readFile(libFile) };
}
diff --git a/src/harness/harnessLanguageService.ts b/src/harness/harnessLanguageService.ts
index f8f09049d4d..d4b5a9c2a16 100644
--- a/src/harness/harnessLanguageService.ts
+++ b/src/harness/harnessLanguageService.ts
@@ -166,8 +166,7 @@ namespace Harness.LanguageService {
throw new Error("No script with name '" + fileName + "'");
}
- public openFile(_fileName: string, _content?: string, _scriptKindName?: string): void {
- }
+ public openFile(_fileName: string, _content?: string, _scriptKindName?: string): void { /*overridden*/ }
/**
* @param line 0 based index
@@ -237,9 +236,9 @@ namespace Harness.LanguageService {
}
- log(_: string): void { }
- trace(_: string): void { }
- error(_: string): void { }
+ log = ts.noop;
+ trace = ts.noop;
+ error = ts.noop;
}
export class NativeLanguageServiceAdapter implements LanguageServiceAdapter {
@@ -596,13 +595,8 @@ namespace Harness.LanguageService {
super(cancellationToken, settings);
}
- onMessage(): void {
-
- }
-
- writeMessage(): void {
-
- }
+ onMessage = ts.noop;
+ writeMessage = ts.noop;
setClient(client: ts.server.SessionClient) {
this.client = client;
@@ -628,13 +622,8 @@ namespace Harness.LanguageService {
this.newLine = this.host.getNewLine();
}
- onMessage(): void {
-
- }
-
- writeMessage(_message: string): void {
- }
-
+ onMessage = ts.noop;
+ writeMessage = ts.noop; // overridden
write(message: string): void {
this.writeMessage(message);
}
@@ -648,8 +637,7 @@ namespace Harness.LanguageService {
return snapshot && snapshot.getText(0, snapshot.getLength());
}
- writeFile(): void {
- }
+ writeFile = ts.noop;
resolvePath(path: string): string {
return path;
@@ -668,8 +656,7 @@ namespace Harness.LanguageService {
return "";
}
- exit(): void {
- }
+ exit = ts.noop;
createDirectory(_directoryName: string): void {
return ts.notImplemented();
@@ -697,8 +684,7 @@ namespace Harness.LanguageService {
return { close: ts.noop };
}
- close(): void {
- }
+ close = ts.noop;
info(message: string): void {
this.host.log(message);
diff --git a/src/harness/parallel/host.ts b/src/harness/parallel/host.ts
index f37a3b1099e..e278d267e1f 100644
--- a/src/harness/parallel/host.ts
+++ b/src/harness/parallel/host.ts
@@ -77,18 +77,18 @@ namespace Harness.Parallel.Host {
console.log("Discovering runner-based tests...");
const discoverStart = +(new Date());
const { statSync }: { statSync(path: string): { size: number }; } = require("fs");
+ const path: { join: (...args: string[]) => string } = require("path");
for (const runner of runners) {
- const files = runner.enumerateTestFiles();
- for (const file of files) {
+ for (const file of runner.enumerateTestFiles()) {
let size: number;
if (!perfData) {
try {
- size = statSync(file).size;
+ size = statSync(path.join(runner.workingDirectory, file)).size;
}
catch {
// May be a directory
try {
- size = Harness.IO.listFiles(file, /.*/g, { recursive: true }).reduce((acc, elem) => acc + statSync(elem).size, 0);
+ size = Harness.IO.listFiles(path.join(runner.workingDirectory, file), /.*/g, { recursive: true }).reduce((acc, elem) => acc + statSync(elem).size, 0);
}
catch {
// Unknown test kind, just return 0 and let the historical analysis take over after one run
diff --git a/src/harness/projectsRunner.ts b/src/harness/projectsRunner.ts
index fccbba88ff6..c617cc7a0a3 100644
--- a/src/harness/projectsRunner.ts
+++ b/src/harness/projectsRunner.ts
@@ -396,7 +396,7 @@ class ProjectRunner extends RunnerBase {
});
// Dont allow config files since we are compiling existing source options
- return compileProjectFiles(compilerResult.moduleKind, compilerResult.configFileSourceFiles, getInputFiles, getSourceFileText, writeFile, compilerResult.compilerOptions);
+ return compileProjectFiles(compilerResult.moduleKind, compilerResult.configFileSourceFiles, getInputFiles, getSourceFileText, /*writeFile*/ ts.noop, compilerResult.compilerOptions);
function findOutputDtsFile(fileName: string) {
return ts.forEach(compilerResult.outputFiles, outputFile => outputFile.emittedFileName === fileName ? outputFile : undefined);
@@ -416,9 +416,6 @@ class ProjectRunner extends RunnerBase {
}
return undefined;
}
-
- function writeFile() {
- }
}
function getErrorsBaseline(compilerResult: CompileProjectFilesResult) {
diff --git a/src/harness/runner.ts b/src/harness/runner.ts
index 70954e9e853..2bd098b742d 100644
--- a/src/harness/runner.ts
+++ b/src/harness/runner.ts
@@ -18,7 +18,7 @@
///
///
///
-///
+///
///
///
@@ -62,6 +62,8 @@ function createRunner(kind: TestRunnerKind): RunnerBase {
return new Test262BaselineRunner();
case "user":
return new UserCodeRunner();
+ case "dt":
+ return new DefinitelyTypedRunner();
}
ts.Debug.fail(`Unknown runner kind ${kind}`);
}
@@ -183,6 +185,9 @@ function handleTestConfig() {
case "user":
runners.push(new UserCodeRunner());
break;
+ case "dt":
+ runners.push(new DefinitelyTypedRunner());
+ break;
}
}
}
@@ -220,6 +225,14 @@ function beginTests() {
ts.Debug.enableDebugInfo();
}
+ // run tests in en-US by default.
+ let savedUILocale: string | undefined;
+ beforeEach(() => {
+ savedUILocale = ts.getUILocale();
+ ts.setUILocale("en-US");
+ });
+ afterEach(() => ts.setUILocale(savedUILocale));
+
runTests(runners);
if (!runUnitTests) {
diff --git a/src/harness/runnerbase.ts b/src/harness/runnerbase.ts
index 2fef2264b73..80532d30b6f 100644
--- a/src/harness/runnerbase.ts
+++ b/src/harness/runnerbase.ts
@@ -1,13 +1,11 @@
///
-type TestRunnerKind = CompilerTestKind | FourslashTestKind | "project" | "rwc" | "test262" | "user";
+type TestRunnerKind = CompilerTestKind | FourslashTestKind | "project" | "rwc" | "test262" | "user" | "dt";
type CompilerTestKind = "conformance" | "compiler";
type FourslashTestKind = "fourslash" | "fourslash-shims" | "fourslash-shims-pp" | "fourslash-server";
abstract class RunnerBase {
- constructor() { }
-
// contains the tests to run
public tests: string[] = [];
@@ -24,6 +22,9 @@ abstract class RunnerBase {
abstract enumerateTestFiles(): string[];
+ /** The working directory where tests are found. Needed for batch testing where the input path will differ from the output path inside baselines */
+ public workingDirectory = "";
+
/** Setup the runner's tests so that they are ready to be executed by the harness
* The first test should be a describe/it block that sets up the harness's compiler instance appropriately
*/
diff --git a/src/harness/rwcRunner.ts b/src/harness/rwcRunner.ts
index af6e8c95c5c..ef7a371b0c4 100644
--- a/src/harness/rwcRunner.ts
+++ b/src/harness/rwcRunner.ts
@@ -131,13 +131,14 @@ namespace RWC {
}
else {
// set the flag to put default library to the beginning of the list
- inputFiles.unshift(Harness.getDefaultLibraryFile(oldIO));
+ inputFiles.unshift(Harness.getDefaultLibraryFile(fileRead.path, oldIO));
}
}
}
}
// do not use lib since we already read it in above
+ opts.options.lib = undefined;
opts.options.noLib = true;
// Emit the results
diff --git a/src/harness/tsconfig.json b/src/harness/tsconfig.json
index 6e61b7690bc..db38b95ba6a 100644
--- a/src/harness/tsconfig.json
+++ b/src/harness/tsconfig.json
@@ -60,20 +60,11 @@
"../services/jsTyping.ts",
"../services/formatting/formatting.ts",
"../services/formatting/formattingContext.ts",
- "../services/formatting/formattingRequestKind.ts",
"../services/formatting/formattingScanner.ts",
- "../services/formatting/references.ts",
"../services/formatting/rule.ts",
- "../services/formatting/ruleAction.ts",
- "../services/formatting/ruleDescriptor.ts",
- "../services/formatting/ruleFlag.ts",
- "../services/formatting/ruleOperation.ts",
- "../services/formatting/ruleOperationContext.ts",
"../services/formatting/rules.ts",
"../services/formatting/rulesMap.ts",
- "../services/formatting/rulesProvider.ts",
"../services/formatting/smartIndenter.ts",
- "../services/formatting/tokenRange.ts",
"../services/codeFixProvider.ts",
"../services/codefixes/fixes.ts",
"../services/codefixes/helpers.ts",
@@ -92,7 +83,7 @@
"projectsRunner.ts",
"loggedIO.ts",
"rwcRunner.ts",
- "userRunner.ts",
+ "externalCompileRunner.ts",
"test262Runner.ts",
"./parallel/shared.ts",
"./parallel/host.ts",
diff --git a/src/harness/unittests/compileOnSave.ts b/src/harness/unittests/compileOnSave.ts
index 0a3b5f46f0f..7ef3e2aa1af 100644
--- a/src/harness/unittests/compileOnSave.ts
+++ b/src/harness/unittests/compileOnSave.ts
@@ -13,8 +13,8 @@ namespace ts.projectSystem {
describe("CompileOnSave affected list", () => {
function sendAffectedFileRequestAndCheckResult(session: server.Session, request: server.protocol.Request, expectedFileList: { projectFileName: string, files: FileOrFolder[] }[]) {
const response = session.executeCommand(request).response as server.protocol.CompileOnSaveAffectedFileListSingleProject[];
- const actualResult = response.sort((list1, list2) => compareStrings(list1.projectFileName, list2.projectFileName));
- expectedFileList = expectedFileList.sort((list1, list2) => compareStrings(list1.projectFileName, list2.projectFileName));
+ const actualResult = response.sort((list1, list2) => ts.compareStringsCaseSensitive(list1.projectFileName, list2.projectFileName));
+ expectedFileList = expectedFileList.sort((list1, list2) => ts.compareStringsCaseSensitive(list1.projectFileName, list2.projectFileName));
assert.equal(actualResult.length, expectedFileList.length, `Actual result project number is different from the expected project number`);
diff --git a/src/harness/unittests/configurationExtension.ts b/src/harness/unittests/configurationExtension.ts
index 0032505aba1..5a1b155fbcf 100644
--- a/src/harness/unittests/configurationExtension.ts
+++ b/src/harness/unittests/configurationExtension.ts
@@ -25,9 +25,9 @@ namespace ts {
},
"/dev/configs/tests.json": {
compilerOptions: {
- "preserveConstEnums": true,
- "removeComments": false,
- "sourceMap": true
+ preserveConstEnums: true,
+ removeComments: false,
+ sourceMap: true
},
exclude: [
"../tests/baselines",
@@ -52,7 +52,7 @@ namespace ts {
"/dev/missing.json": {
extends: "./missing2",
compilerOptions: {
- "types": []
+ types: []
}
},
"/dev/failure.json": {
diff --git a/src/harness/unittests/convertCompilerOptionsFromJson.ts b/src/harness/unittests/convertCompilerOptionsFromJson.ts
index cbbe41ceadf..3a73971d7a3 100644
--- a/src/harness/unittests/convertCompilerOptionsFromJson.ts
+++ b/src/harness/unittests/convertCompilerOptionsFromJson.ts
@@ -58,12 +58,12 @@ namespace ts {
it("Convert correctly format tsconfig.json to compiler-options ", () => {
assertCompilerOptions(
{
- "compilerOptions": {
- "module": "commonjs",
- "target": "es5",
- "noImplicitAny": false,
- "sourceMap": false,
- "lib": ["es5", "es2015.core", "es2015.symbol"]
+ compilerOptions: {
+ module: "commonjs",
+ target: "es5",
+ noImplicitAny: false,
+ sourceMap: false,
+ lib: ["es5", "es2015.core", "es2015.symbol"]
}
}, "tsconfig.json",
{
@@ -82,13 +82,13 @@ namespace ts {
it("Convert correctly format tsconfig.json with allowJs is false to compiler-options ", () => {
assertCompilerOptions(
{
- "compilerOptions": {
- "module": "commonjs",
- "target": "es5",
- "noImplicitAny": false,
- "sourceMap": false,
- "allowJs": false,
- "lib": ["es5", "es2015.core", "es2015.symbol"]
+ compilerOptions: {
+ module: "commonjs",
+ target: "es5",
+ noImplicitAny: false,
+ sourceMap: false,
+ allowJs: false,
+ lib: ["es5", "es2015.core", "es2015.symbol"]
}
}, "tsconfig.json",
{
@@ -108,12 +108,12 @@ namespace ts {
it("Convert incorrect option of jsx to compiler-options ", () => {
assertCompilerOptions(
{
- "compilerOptions": {
- "module": "commonjs",
- "target": "es5",
- "noImplicitAny": false,
- "sourceMap": false,
- "jsx": ""
+ compilerOptions: {
+ module: "commonjs",
+ target: "es5",
+ noImplicitAny: false,
+ sourceMap: false,
+ jsx: ""
}
}, "tsconfig.json",
{
@@ -138,11 +138,11 @@ namespace ts {
it("Convert incorrect option of module to compiler-options ", () => {
assertCompilerOptions(
{
- "compilerOptions": {
- "module": "",
- "target": "es5",
- "noImplicitAny": false,
- "sourceMap": false,
+ compilerOptions: {
+ module: "",
+ target: "es5",
+ noImplicitAny: false,
+ sourceMap: false,
}
}, "tsconfig.json",
{
@@ -166,11 +166,11 @@ namespace ts {
it("Convert incorrect option of newLine to compiler-options ", () => {
assertCompilerOptions(
{
- "compilerOptions": {
- "newLine": "",
- "target": "es5",
- "noImplicitAny": false,
- "sourceMap": false,
+ compilerOptions: {
+ newLine: "",
+ target: "es5",
+ noImplicitAny: false,
+ sourceMap: false,
}
}, "tsconfig.json",
{
@@ -194,10 +194,10 @@ namespace ts {
it("Convert incorrect option of target to compiler-options ", () => {
assertCompilerOptions(
{
- "compilerOptions": {
- "target": "",
- "noImplicitAny": false,
- "sourceMap": false,
+ compilerOptions: {
+ target: "",
+ noImplicitAny: false,
+ sourceMap: false,
}
}, "tsconfig.json",
{
@@ -220,10 +220,10 @@ namespace ts {
it("Convert incorrect option of module-resolution to compiler-options ", () => {
assertCompilerOptions(
{
- "compilerOptions": {
- "moduleResolution": "",
- "noImplicitAny": false,
- "sourceMap": false,
+ compilerOptions: {
+ moduleResolution: "",
+ noImplicitAny: false,
+ sourceMap: false,
}
}, "tsconfig.json",
{
@@ -246,12 +246,12 @@ namespace ts {
it("Convert incorrect option of libs to compiler-options ", () => {
assertCompilerOptions(
{
- "compilerOptions": {
- "module": "commonjs",
- "target": "es5",
- "noImplicitAny": false,
- "sourceMap": false,
- "lib": ["es5", "es2015.core", "incorrectLib"]
+ compilerOptions: {
+ module: "commonjs",
+ target: "es5",
+ noImplicitAny: false,
+ sourceMap: false,
+ lib: ["es5", "es2015.core", "incorrectLib"]
}
}, "tsconfig.json",
{
@@ -277,12 +277,12 @@ namespace ts {
it("Convert empty string option of libs to compiler-options ", () => {
assertCompilerOptions(
{
- "compilerOptions": {
- "module": "commonjs",
- "target": "es5",
- "noImplicitAny": false,
- "sourceMap": false,
- "lib": ["es5", ""]
+ compilerOptions: {
+ module: "commonjs",
+ target: "es5",
+ noImplicitAny: false,
+ sourceMap: false,
+ lib: ["es5", ""]
}
}, "tsconfig.json",
{
@@ -308,12 +308,12 @@ namespace ts {
it("Convert empty string option of libs to compiler-options ", () => {
assertCompilerOptions(
{
- "compilerOptions": {
- "module": "commonjs",
- "target": "es5",
- "noImplicitAny": false,
- "sourceMap": false,
- "lib": [""]
+ compilerOptions: {
+ module: "commonjs",
+ target: "es5",
+ noImplicitAny: false,
+ sourceMap: false,
+ lib: [""]
}
}, "tsconfig.json",
{
@@ -339,12 +339,12 @@ namespace ts {
it("Convert trailing-whitespace string option of libs to compiler-options ", () => {
assertCompilerOptions(
{
- "compilerOptions": {
- "module": "commonjs",
- "target": "es5",
- "noImplicitAny": false,
- "sourceMap": false,
- "lib": [" "]
+ compilerOptions: {
+ module: "commonjs",
+ target: "es5",
+ noImplicitAny: false,
+ sourceMap: false,
+ lib: [" "]
}
}, "tsconfig.json",
{
@@ -370,12 +370,12 @@ namespace ts {
it("Convert empty option of libs to compiler-options ", () => {
assertCompilerOptions(
{
- "compilerOptions": {
- "module": "commonjs",
- "target": "es5",
- "noImplicitAny": false,
- "sourceMap": false,
- "lib": []
+ compilerOptions: {
+ module: "commonjs",
+ target: "es5",
+ noImplicitAny: false,
+ sourceMap: false,
+ lib: []
}
}, "tsconfig.json",
{
@@ -394,8 +394,8 @@ namespace ts {
it("Convert incorrectly format tsconfig.json to compiler-options ", () => {
assertCompilerOptions(
{
- "compilerOptions": {
- "modu": "commonjs",
+ compilerOptions: {
+ modu: "commonjs",
}
}, "tsconfig.json",
{
@@ -424,9 +424,9 @@ namespace ts {
it("Convert negative numbers in tsconfig.json ", () => {
assertCompilerOptions(
{
- "compilerOptions": {
- "allowJs": true,
- "maxNodeModuleJsDepth": -1
+ compilerOptions: {
+ allowJs: true,
+ maxNodeModuleJsDepth: -1
}
}, "tsconfig.json",
{
@@ -443,12 +443,12 @@ namespace ts {
it("Convert correctly format jsconfig.json to compiler-options ", () => {
assertCompilerOptions(
{
- "compilerOptions": {
- "module": "commonjs",
- "target": "es5",
- "noImplicitAny": false,
- "sourceMap": false,
- "lib": ["es5", "es2015.core", "es2015.symbol"]
+ compilerOptions: {
+ module: "commonjs",
+ target: "es5",
+ noImplicitAny: false,
+ sourceMap: false,
+ lib: ["es5", "es2015.core", "es2015.symbol"]
}
}, "jsconfig.json",
{
@@ -471,13 +471,13 @@ namespace ts {
it("Convert correctly format jsconfig.json with allowJs is false to compiler-options ", () => {
assertCompilerOptions(
{
- "compilerOptions": {
- "module": "commonjs",
- "target": "es5",
- "noImplicitAny": false,
- "sourceMap": false,
- "allowJs": false,
- "lib": ["es5", "es2015.core", "es2015.symbol"]
+ compilerOptions: {
+ module: "commonjs",
+ target: "es5",
+ noImplicitAny: false,
+ sourceMap: false,
+ allowJs: false,
+ lib: ["es5", "es2015.core", "es2015.symbol"]
}
}, "jsconfig.json",
{
@@ -500,8 +500,8 @@ namespace ts {
it("Convert incorrectly format jsconfig.json to compiler-options ", () => {
assertCompilerOptions(
{
- "compilerOptions": {
- "modu": "commonjs",
+ compilerOptions: {
+ modu: "commonjs",
}
}, "jsconfig.json",
{
diff --git a/src/harness/unittests/convertTypeAcquisitionFromJson.ts b/src/harness/unittests/convertTypeAcquisitionFromJson.ts
index 5a367edebbb..be1ada10a97 100644
--- a/src/harness/unittests/convertTypeAcquisitionFromJson.ts
+++ b/src/harness/unittests/convertTypeAcquisitionFromJson.ts
@@ -55,11 +55,11 @@ namespace ts {
it("Convert deprecated typingOptions.enableAutoDiscovery format tsconfig.json to typeAcquisition ", () => {
assertTypeAcquisition(
{
- "typingOptions":
+ typingOptions:
{
- "enableAutoDiscovery": true,
- "include": ["0.d.ts", "1.d.ts"],
- "exclude": ["0.js", "1.js"]
+ enableAutoDiscovery: true,
+ include: ["0.d.ts", "1.d.ts"],
+ exclude: ["0.js", "1.js"]
}
},
"tsconfig.json",
@@ -77,11 +77,11 @@ namespace ts {
it("Convert correctly format tsconfig.json to typeAcquisition ", () => {
assertTypeAcquisition(
{
- "typeAcquisition":
+ typeAcquisition:
{
- "enable": true,
- "include": ["0.d.ts", "1.d.ts"],
- "exclude": ["0.js", "1.js"]
+ enable: true,
+ include: ["0.d.ts", "1.d.ts"],
+ exclude: ["0.js", "1.js"]
}
},
"tsconfig.json",
@@ -99,9 +99,9 @@ namespace ts {
it("Convert incorrect format tsconfig.json to typeAcquisition ", () => {
assertTypeAcquisition(
{
- "typeAcquisition":
+ typeAcquisition:
{
- "enableAutoDiscovy": true,
+ enableAutoDiscovy: true,
}
}, "tsconfig.json",
{
@@ -140,9 +140,9 @@ namespace ts {
it("Convert tsconfig.json with only enable property to typeAcquisition ", () => {
assertTypeAcquisition(
{
- "typeAcquisition":
+ typeAcquisition:
{
- "enable": true
+ enable: true
}
}, "tsconfig.json",
{
@@ -160,11 +160,11 @@ namespace ts {
it("Convert jsconfig.json to typeAcquisition ", () => {
assertTypeAcquisition(
{
- "typeAcquisition":
+ typeAcquisition:
{
- "enable": false,
- "include": ["0.d.ts"],
- "exclude": ["0.js"]
+ enable: false,
+ include: ["0.d.ts"],
+ exclude: ["0.js"]
}
}, "jsconfig.json",
{
@@ -194,9 +194,9 @@ namespace ts {
it("Convert incorrect format jsconfig.json to typeAcquisition ", () => {
assertTypeAcquisition(
{
- "typeAcquisition":
+ typeAcquisition:
{
- "enableAutoDiscovy": true,
+ enableAutoDiscovy: true,
}
}, "jsconfig.json",
{
@@ -222,9 +222,9 @@ namespace ts {
it("Convert jsconfig.json with only enable property to typeAcquisition ", () => {
assertTypeAcquisition(
{
- "typeAcquisition":
+ typeAcquisition:
{
- "enable": false
+ enable: false
}
}, "jsconfig.json",
{
diff --git a/src/harness/unittests/extractTestHelpers.ts b/src/harness/unittests/extractTestHelpers.ts
index b8974694cfe..a04f443c3c9 100644
--- a/src/harness/unittests/extractTestHelpers.ts
+++ b/src/harness/unittests/extractTestHelpers.ts
@@ -67,33 +67,27 @@ namespace ts {
}
export const newLineCharacter = "\n";
- export const getRuleProvider = memoize(getRuleProviderInternal);
- function getRuleProviderInternal() {
- const options = {
- indentSize: 4,
- tabSize: 4,
- newLineCharacter,
- convertTabsToSpaces: true,
- indentStyle: ts.IndentStyle.Smart,
- insertSpaceAfterConstructor: false,
- insertSpaceAfterCommaDelimiter: true,
- insertSpaceAfterSemicolonInForStatements: true,
- insertSpaceBeforeAndAfterBinaryOperators: true,
- insertSpaceAfterKeywordsInControlFlowStatements: true,
- insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
- insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
- insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
- insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
- insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
- insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
- insertSpaceBeforeFunctionParenthesis: false,
- placeOpenBraceOnNewLineForFunctions: false,
- placeOpenBraceOnNewLineForControlBlocks: false,
- };
- const rulesProvider = new formatting.RulesProvider();
- rulesProvider.ensureUpToDate(options);
- return rulesProvider;
- }
+ export const testFormatOptions: ts.FormatCodeSettings = {
+ indentSize: 4,
+ tabSize: 4,
+ newLineCharacter,
+ convertTabsToSpaces: true,
+ indentStyle: ts.IndentStyle.Smart,
+ insertSpaceAfterConstructor: false,
+ insertSpaceAfterCommaDelimiter: true,
+ insertSpaceAfterSemicolonInForStatements: true,
+ insertSpaceBeforeAndAfterBinaryOperators: true,
+ insertSpaceAfterKeywordsInControlFlowStatements: true,
+ insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
+ insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
+ insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
+ insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
+ insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
+ insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
+ insertSpaceBeforeFunctionParenthesis: false,
+ placeOpenBraceOnNewLineForFunctions: false,
+ placeOpenBraceOnNewLineForControlBlocks: false,
+ };
const notImplementedHost: LanguageServiceHost = {
getCompilationSettings: notImplemented,
@@ -126,14 +120,14 @@ namespace ts {
const sourceFile = program.getSourceFile(path);
const context: RefactorContext = {
- cancellationToken: { throwIfCancellationRequested() { }, isCancellationRequested() { return false; } },
+ cancellationToken: { throwIfCancellationRequested: noop, isCancellationRequested: returnFalse },
newLineCharacter,
program,
file: sourceFile,
startPosition: selectionRange.start,
endPosition: selectionRange.end,
host: notImplementedHost,
- rulesProvider: getRuleProvider()
+ formatContext: formatting.getFormatContext(testFormatOptions),
};
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
assert.equal(rangeToExtract.errors, undefined, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText);
@@ -190,14 +184,14 @@ namespace ts {
const program = projectService.inferredProjects[0].getLanguageService().getProgram();
const sourceFile = program.getSourceFile(f.path);
const context: RefactorContext = {
- cancellationToken: { throwIfCancellationRequested() { }, isCancellationRequested() { return false; } },
+ cancellationToken: { throwIfCancellationRequested: noop, isCancellationRequested: returnFalse },
newLineCharacter,
program,
file: sourceFile,
startPosition: selectionRange.start,
endPosition: selectionRange.end,
host: notImplementedHost,
- rulesProvider: getRuleProvider()
+ formatContext: formatting.getFormatContext(testFormatOptions),
};
const rangeToExtract = refactor.extractSymbol.getRangeToExtract(sourceFile, createTextSpanFromBounds(selectionRange.start, selectionRange.end));
assert.isUndefined(rangeToExtract.errors, rangeToExtract.errors && "Range error: " + rangeToExtract.errors[0].messageText);
diff --git a/src/harness/unittests/hostNewLineSupport.ts b/src/harness/unittests/hostNewLineSupport.ts
index 9f6b09dfb72..95a05f101f7 100644
--- a/src/harness/unittests/hostNewLineSupport.ts
+++ b/src/harness/unittests/hostNewLineSupport.ts
@@ -5,10 +5,10 @@ namespace ts {
function snapFor(path: string): IScriptSnapshot {
if (path === "lib.d.ts") {
return {
- dispose() {},
+ dispose: noop,
getChangeRange() { return undefined; },
getLength() { return 0; },
- getText(_start, _end) {
+ getText() {
return "";
}
};
@@ -16,7 +16,7 @@ namespace ts {
const result = forEach(files, f => f.unitName === path ? f : undefined);
if (result) {
return {
- dispose() {},
+ dispose: noop,
getChangeRange() { return undefined; },
getLength() { return result.content.length; },
getText(start, end) {
diff --git a/src/harness/unittests/moduleResolution.ts b/src/harness/unittests/moduleResolution.ts
index 6f62c78208f..de79ba06cf9 100644
--- a/src/harness/unittests/moduleResolution.ts
+++ b/src/harness/unittests/moduleResolution.ts
@@ -127,7 +127,7 @@ namespace ts {
function test(hasDirectoryExists: boolean) {
const containingFile = { name: containingFileName };
- const packageJson = { name: packageJsonFileName, content: JSON.stringify({ "typings": fieldRef }) };
+ const packageJson = { name: packageJsonFileName, content: JSON.stringify({ typings: fieldRef }) };
const moduleFile = { name: moduleFileName };
const resolution = nodeModuleNameResolver(moduleName, containingFile.name, {}, createModuleResolutionHost(hasDirectoryExists, containingFile, packageJson, moduleFile));
checkResolvedModule(resolution.resolvedModule, createResolvedModule(moduleFile.name));
@@ -149,7 +149,7 @@ namespace ts {
function test(hasDirectoryExists: boolean) {
const containingFile = { name: "/a/b.ts" };
- const packageJson = { name: "/node_modules/b/package.json", content: JSON.stringify({ "typings": typings }) };
+ const packageJson = { name: "/node_modules/b/package.json", content: JSON.stringify({ typings }) };
const moduleFile = { name: "/a/b.d.ts" };
const indexPath = "/node_modules/b/index.d.ts";
@@ -163,7 +163,7 @@ namespace ts {
it("module name as directory - handle invalid 'typings'", () => {
testTypingsIgnored(["a", "b"]);
- testTypingsIgnored({ "a": "b" });
+ testTypingsIgnored({ a: "b" });
testTypingsIgnored(/*typings*/ true);
testTypingsIgnored(/*typings*/ null); // tslint:disable-line no-null-keyword
testTypingsIgnored(/*typings*/ undefined);
diff --git a/src/harness/unittests/printer.ts b/src/harness/unittests/printer.ts
index 4aaddce5c00..ad60484d963 100644
--- a/src/harness/unittests/printer.ts
+++ b/src/harness/unittests/printer.ts
@@ -55,6 +55,7 @@ namespace ts {
printsCorrectly("removeComments", { removeComments: true }, printer => printer.printFile(sourceFile));
// github #14948
+ // tslint:disable-next-line no-invalid-template-strings
printsCorrectly("templateLiteral", {}, printer => printer.printFile(createSourceFile("source.ts", "let greeting = `Hi ${name}, how are you?`;", ScriptTarget.ES2017)));
// github #18071
diff --git a/src/harness/unittests/reuseProgramStructure.ts b/src/harness/unittests/reuseProgramStructure.ts
index 6278742a0bd..fdccc8a7795 100644
--- a/src/harness/unittests/reuseProgramStructure.ts
+++ b/src/harness/unittests/reuseProgramStructure.ts
@@ -360,7 +360,7 @@ namespace ts {
const options: CompilerOptions = { target };
const program1 = newProgram(files, ["a.ts"], options);
- checkResolvedModulesCache(program1, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts") }));
+ checkResolvedModulesCache(program1, "a.ts", createMapFromTemplate({ b: createResolvedModule("b.ts") }));
checkResolvedModulesCache(program1, "b.ts", /*expectedContent*/ undefined);
const program2 = updateProgram(program1, ["a.ts"], options, files => {
@@ -369,7 +369,7 @@ namespace ts {
assert.equal(program1.structureIsReused, StructureIsReused.Completely);
// content of resolution cache should not change
- checkResolvedModulesCache(program1, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts") }));
+ checkResolvedModulesCache(program1, "a.ts", createMapFromTemplate({ b: createResolvedModule("b.ts") }));
checkResolvedModulesCache(program1, "b.ts", /*expectedContent*/ undefined);
// imports has changed - program is not reused
@@ -386,7 +386,7 @@ namespace ts {
files[0].text = files[0].text.updateImportsAndExports(newImports);
});
assert.equal(program3.structureIsReused, StructureIsReused.SafeModules);
- checkResolvedModulesCache(program4, "a.ts", createMapFromTemplate({ "b": createResolvedModule("b.ts"), "c": undefined }));
+ checkResolvedModulesCache(program4, "a.ts", createMapFromTemplate({ b: createResolvedModule("b.ts"), c: undefined }));
});
it("resolved type directives cache follows type directives", () => {
@@ -397,7 +397,7 @@ namespace ts {
const options: CompilerOptions = { target, typeRoots: ["/types"] };
const program1 = newProgram(files, ["/a.ts"], options);
- checkResolvedTypeDirectivesCache(program1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
+ checkResolvedTypeDirectivesCache(program1, "/a.ts", createMapFromTemplate({ typedefs: { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
checkResolvedTypeDirectivesCache(program1, "/types/typedefs/index.d.ts", /*expectedContent*/ undefined);
const program2 = updateProgram(program1, ["/a.ts"], options, files => {
@@ -406,7 +406,7 @@ namespace ts {
assert.equal(program1.structureIsReused, StructureIsReused.Completely);
// content of resolution cache should not change
- checkResolvedTypeDirectivesCache(program1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
+ checkResolvedTypeDirectivesCache(program1, "/a.ts", createMapFromTemplate({ typedefs: { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
checkResolvedTypeDirectivesCache(program1, "/types/typedefs/index.d.ts", /*expectedContent*/ undefined);
// type reference directives has changed - program is not reused
@@ -424,7 +424,7 @@ namespace ts {
files[0].text = files[0].text.updateReferences(newReferences);
});
assert.equal(program3.structureIsReused, StructureIsReused.SafeModules);
- checkResolvedTypeDirectivesCache(program1, "/a.ts", createMapFromTemplate({ "typedefs": { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
+ checkResolvedTypeDirectivesCache(program1, "/a.ts", createMapFromTemplate({ typedefs: { resolvedFileName: "/types/typedefs/index.d.ts", primary: true } }));
});
it("fetches imports after npm install", () => {
diff --git a/src/harness/unittests/services/colorization.ts b/src/harness/unittests/services/colorization.ts
index 6dbc7732a00..17d4132e9e5 100644
--- a/src/harness/unittests/services/colorization.ts
+++ b/src/harness/unittests/services/colorization.ts
@@ -1,5 +1,7 @@
///
+// tslint:disable no-invalid-template-strings (lots of tests use quoted code)
+
interface ClassificationEntry {
value: any;
classification: ts.TokenClass;
diff --git a/src/harness/unittests/services/preProcessFile.ts b/src/harness/unittests/services/preProcessFile.ts
index d4195573cba..1e13bc3e345 100644
--- a/src/harness/unittests/services/preProcessFile.ts
+++ b/src/harness/unittests/services/preProcessFile.ts
@@ -278,7 +278,7 @@ describe("PreProcessFile:", () => {
referencedFiles: [],
typeReferenceDirectives: [],
importedFiles: [
- { "fileName": "../Observable", "pos": 28, "end": 41 }
+ { fileName: "../Observable", pos: 28, end: 41 }
],
ambientExternalModules: undefined,
isLibFile: false
@@ -298,8 +298,8 @@ describe("PreProcessFile:", () => {
referencedFiles: [],
typeReferenceDirectives: [],
importedFiles: [
- { "fileName": "m", "pos": 123, "end": 124 },
- { "fileName": "../Observable", "pos": 28, "end": 41 }
+ { fileName: "m", pos: 123, end: 124 },
+ { fileName: "../Observable", pos: 28, end: 41 }
],
ambientExternalModules: undefined,
isLibFile: false
@@ -319,8 +319,8 @@ describe("PreProcessFile:", () => {
referencedFiles: [],
typeReferenceDirectives: [],
importedFiles: [
- { "fileName": "m", "pos": 123, "end": 124 },
- { "fileName": "../Observable", "pos": 28, "end": 41 }
+ { fileName: "m", pos: 123, end: 124 },
+ { fileName: "../Observable", pos: 28, end: 41 }
],
ambientExternalModules: undefined,
isLibFile: false
@@ -340,7 +340,7 @@ describe("PreProcessFile:", () => {
referencedFiles: [],
typeReferenceDirectives: [],
importedFiles: [
- { "fileName": "../Observable", "pos": 28, "end": 41 }
+ { fileName: "../Observable", pos: 28, end: 41 }
],
ambientExternalModules: undefined,
isLibFile: false
@@ -360,7 +360,7 @@ describe("PreProcessFile:", () => {
referencedFiles: [],
typeReferenceDirectives: [],
importedFiles: [
- { "fileName": "../Observable", "pos": 28, "end": 41 }
+ { fileName: "../Observable", pos: 28, end: 41 }
],
ambientExternalModules: undefined,
isLibFile: false
@@ -379,7 +379,7 @@ describe("PreProcessFile:", () => {
referencedFiles: [],
typeReferenceDirectives: [],
importedFiles: [
- { "fileName": "../Observable", "pos": 28, "end": 41 }
+ { fileName: "../Observable", pos: 28, end: 41 }
],
ambientExternalModules: undefined,
isLibFile: false
@@ -400,8 +400,8 @@ describe("PreProcessFile:", () => {
referencedFiles: [],
typeReferenceDirectives: [],
importedFiles: [
- { "fileName": "m2", "pos": 65, "end": 67 },
- { "fileName": "augmentation", "pos": 102, "end": 114 }
+ { fileName: "m2", pos: 65, end: 67 },
+ { fileName: "augmentation", pos: 102, end: 114 }
],
ambientExternalModules: ["m1"],
isLibFile: false
@@ -424,8 +424,8 @@ describe("PreProcessFile:", () => {
referencedFiles: [],
typeReferenceDirectives: [],
importedFiles: [
- { "fileName": "m2", "pos": 127, "end": 129 },
- { "fileName": "augmentation", "pos": 164, "end": 176 }
+ { fileName: "m2", pos: 127, end: 129 },
+ { fileName: "augmentation", pos: 164, end: 176 }
],
ambientExternalModules: ["m1"],
isLibFile: false
@@ -442,12 +442,12 @@ describe("PreProcessFile:", () => {
/*detectJavaScriptImports*/ false,
{
referencedFiles: [
- { "pos": 34, "end": 35, "fileName": "a" },
- { "pos": 112, "end": 114, "fileName": "a2" }
+ { pos: 34, end: 35, fileName: "a" },
+ { pos: 112, end: 114, fileName: "a2" }
],
typeReferenceDirectives: [
- { "pos": 73, "end": 75, "fileName": "a1" },
- { "pos": 152, "end": 154, "fileName": "a3" }
+ { pos: 73, end: 75, fileName: "a1" },
+ { pos: 152, end: 154, fileName: "a3" }
],
importedFiles: [],
ambientExternalModules: undefined,
diff --git a/src/harness/unittests/textChanges.ts b/src/harness/unittests/textChanges.ts
index c37e50a2565..ed571b37399 100644
--- a/src/harness/unittests/textChanges.ts
+++ b/src/harness/unittests/textChanges.ts
@@ -23,60 +23,8 @@ namespace ts {
const printerOptions = { newLine: NewLineKind.LineFeed };
const newLineCharacter = getNewLineCharacter(printerOptions);
- const getRuleProviderDefault = memoize(() => {
- const options = {
- indentSize: 4,
- tabSize: 4,
- newLineCharacter,
- convertTabsToSpaces: true,
- indentStyle: ts.IndentStyle.Smart,
- insertSpaceAfterConstructor: false,
- insertSpaceAfterCommaDelimiter: true,
- insertSpaceAfterSemicolonInForStatements: true,
- insertSpaceBeforeAndAfterBinaryOperators: true,
- insertSpaceAfterKeywordsInControlFlowStatements: true,
- insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
- insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
- insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
- insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
- insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
- insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
- insertSpaceBeforeFunctionParenthesis: false,
- placeOpenBraceOnNewLineForFunctions: false,
- placeOpenBraceOnNewLineForControlBlocks: false,
- };
- const rulesProvider = new formatting.RulesProvider();
- rulesProvider.ensureUpToDate(options);
- return rulesProvider;
- });
- const getRuleProviderNewlineBrace = memoize(() => {
- const options = {
- indentSize: 4,
- tabSize: 4,
- newLineCharacter,
- convertTabsToSpaces: true,
- indentStyle: ts.IndentStyle.Smart,
- insertSpaceAfterConstructor: false,
- insertSpaceAfterCommaDelimiter: true,
- insertSpaceAfterSemicolonInForStatements: true,
- insertSpaceBeforeAndAfterBinaryOperators: true,
- insertSpaceAfterKeywordsInControlFlowStatements: true,
- insertSpaceAfterFunctionKeywordForAnonymousFunctions: false,
- insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis: false,
- insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets: false,
- insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces: true,
- insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces: false,
- insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces: false,
- insertSpaceBeforeFunctionParenthesis: false,
- placeOpenBraceOnNewLineForFunctions: true,
- placeOpenBraceOnNewLineForControlBlocks: false,
- };
- const rulesProvider = new formatting.RulesProvider();
- rulesProvider.ensureUpToDate(options);
- return rulesProvider;
- });
- function getRuleProvider(placeOpenBraceOnNewLineForFunctions: boolean) {
- return placeOpenBraceOnNewLineForFunctions ? getRuleProviderNewlineBrace() : getRuleProviderDefault();
+ function getRuleProvider(placeOpenBraceOnNewLineForFunctions: boolean): formatting.FormatContext {
+ return formatting.getFormatContext(placeOpenBraceOnNewLineForFunctions ? { ...testFormatOptions, placeOpenBraceOnNewLineForFunctions: true } : testFormatOptions);
}
// validate that positions that were recovered from the printed text actually match positions that will be created if the same text is parsed.
@@ -122,9 +70,9 @@ namespace ts {
{
const text = `
-namespace M
+namespace M
{
- namespace M2
+ namespace M2
{
function foo() {
// comment 1
@@ -572,7 +520,7 @@ const x = 1;`;
}
{
const text = `
-const x = 1,
+const x = 1,
y = 2;`;
runSingleFileTest("insertNodeInListAfter6", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createVariableDeclaration("z", /*type*/ undefined, createLiteral(1)));
@@ -583,7 +531,7 @@ const x = 1,
}
{
const text = `
-const /*x*/ x = 1,
+const /*x*/ x = 1,
/*y*/ y = 2;`;
runSingleFileTest("insertNodeInListAfter8", /*placeOpenBraceOnNewLineForFunctions*/ false, text, /*validateNodes*/ false, (sourceFile, changeTracker) => {
changeTracker.insertNodeInListAfter(sourceFile, findChild("x", sourceFile), createVariableDeclaration("z", /*type*/ undefined, createLiteral(1)));
diff --git a/src/harness/unittests/transform.ts b/src/harness/unittests/transform.ts
index 72f7072535c..a39249bb225 100644
--- a/src/harness/unittests/transform.ts
+++ b/src/harness/unittests/transform.ts
@@ -192,6 +192,38 @@ namespace ts {
};
}
});
+
+ // https://github.com/Microsoft/TypeScript/issues/19618
+ testBaseline("transformAddImportStar", () => {
+ return ts.transpileModule("", {
+ transformers: {
+ before: [transformAddImportStar],
+ },
+ compilerOptions: {
+ target: ts.ScriptTarget.ES5,
+ module: ts.ModuleKind.System,
+ newLine: NewLineKind.CarriageReturnLineFeed,
+ }
+ }).outputText;
+
+ function transformAddImportStar(_context: ts.TransformationContext) {
+ return (sourceFile: ts.SourceFile): ts.SourceFile => {
+ return visitNode(sourceFile);
+ };
+ function visitNode(sf: ts.SourceFile) {
+ // produce `import * as i0 from './comp';
+ const importStar = ts.createImportDeclaration(
+ /*decorators*/ undefined,
+ /*modifiers*/ undefined,
+ /*importClause*/ ts.createImportClause(
+ /*name*/ undefined,
+ ts.createNamespaceImport(ts.createIdentifier("i0"))
+ ),
+ /*moduleSpecifier*/ ts.createLiteral("./comp1"));
+ return ts.updateSourceFileNode(sf, [importStar]);
+ }
+ }
+ });
});
}
diff --git a/src/harness/unittests/transpile.ts b/src/harness/unittests/transpile.ts
index 16bef6500f2..7c4af8be167 100644
--- a/src/harness/unittests/transpile.ts
+++ b/src/harness/unittests/transpile.ts
@@ -149,21 +149,21 @@ var x = 0;`, {
`import {foo} from "SomeName";\n` +
`declare function use(a: any);\n` +
`use(foo);`, {
- options: { compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } }
+ options: { compilerOptions: { module: ModuleKind.System, newLine: NewLineKind.LineFeed }, renamedDependencies: { SomeName: "SomeOtherName" } }
});
transpilesCorrectly("Rename dependencies - AMD",
`import {foo} from "SomeName";\n` +
`declare function use(a: any);\n` +
`use(foo);`, {
- options: { compilerOptions: { module: ModuleKind.AMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } }
+ options: { compilerOptions: { module: ModuleKind.AMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { SomeName: "SomeOtherName" } }
});
transpilesCorrectly("Rename dependencies - UMD",
`import {foo} from "SomeName";\n` +
`declare function use(a: any);\n` +
`use(foo);`, {
- options: { compilerOptions: { module: ModuleKind.UMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { "SomeName": "SomeOtherName" } }
+ options: { compilerOptions: { module: ModuleKind.UMD, newLine: NewLineKind.LineFeed }, renamedDependencies: { SomeName: "SomeOtherName" } }
});
transpilesCorrectly("Transpile with emit decorators and emit metadata",
diff --git a/src/harness/unittests/tscWatchMode.ts b/src/harness/unittests/tscWatchMode.ts
index cddbfba9dc0..4e2d63cec90 100644
--- a/src/harness/unittests/tscWatchMode.ts
+++ b/src/harness/unittests/tscWatchMode.ts
@@ -710,12 +710,12 @@ namespace ts.tscWatch {
path: "/src/tsconfig.json",
content: JSON.stringify(
{
- "compilerOptions": {
- "module": "commonjs",
- "target": "es5",
- "noImplicitAny": true,
- "sourceMap": false,
- "lib": [
+ compilerOptions: {
+ module: "commonjs",
+ target: "es5",
+ noImplicitAny: true,
+ sourceMap: false,
+ lib: [
"es5"
]
}
@@ -725,12 +725,12 @@ namespace ts.tscWatch {
path: config1.path,
content: JSON.stringify(
{
- "compilerOptions": {
- "module": "commonjs",
- "target": "es5",
- "noImplicitAny": true,
- "sourceMap": false,
- "lib": [
+ compilerOptions: {
+ module: "commonjs",
+ target: "es5",
+ noImplicitAny: true,
+ sourceMap: false,
+ lib: [
"es5",
"es2015.promise"
]
@@ -1616,6 +1616,36 @@ namespace ts.tscWatch {
return files.slice(0, 2);
}
});
+
+ it("Elides const enums correctly in incremental compilation", () => {
+ const currentDirectory = "/user/someone/projects/myproject";
+ const file1: FileOrFolder = {
+ path: `${currentDirectory}/file1.ts`,
+ content: "export const enum E1 { V = 1 }"
+ };
+ const file2: FileOrFolder = {
+ path: `${currentDirectory}/file2.ts`,
+ content: `import { E1 } from "./file1"; export const enum E2 { V = E1.V }`
+ };
+ const file3: FileOrFolder = {
+ path: `${currentDirectory}/file3.ts`,
+ content: `import { E2 } from "./file2"; const v: E2 = E2.V;`
+ };
+ const strictAndEsModule = `"use strict";\nexports.__esModule = true;\n`;
+ verifyEmittedFileContents("\n", [file3, file2, file1], [
+ `${strictAndEsModule}var v = 1 /* V */;\n`,
+ strictAndEsModule,
+ strictAndEsModule
+ ], modifyFiles);
+
+ function modifyFiles(files: FileOrFolderEmit[], emittedFiles: EmittedFile[]) {
+ files[0].content += `function foo2() { return 2; }`;
+ emittedFiles[0].content += `function foo2() { return 2; }\n`;
+ emittedFiles[1].shouldBeWritten = false;
+ emittedFiles[2].shouldBeWritten = false;
+ return [files[0]];
+ }
+ });
});
describe("tsc-watch module resolution caching", () => {
@@ -1963,12 +1993,12 @@ declare module "fs" {
const configFile: FileOrFolder = {
path: "/a/rootFolder/project/tsconfig.json",
content: JSON.stringify({
- "compilerOptions": {
- "module": "none",
- "allowJs": true,
- "outDir": "Static/scripts/"
+ compilerOptions: {
+ module: "none",
+ allowJs: true,
+ outDir: "Static/scripts/"
},
- "include": [
+ include: [
"Scripts/**/*"
],
})
diff --git a/src/harness/unittests/tsserverProjectSystem.ts b/src/harness/unittests/tsserverProjectSystem.ts
index 55d767d24a7..ea573726eb8 100644
--- a/src/harness/unittests/tsserverProjectSystem.ts
+++ b/src/harness/unittests/tsserverProjectSystem.ts
@@ -85,8 +85,7 @@ namespace ts.projectSystem {
assert.equal(this.postExecActions.length, expectedCount, `Expected ${expectedCount} post install actions`);
}
- onProjectClosed() {
- }
+ onProjectClosed = noop;
attach(projectService: server.ProjectService) {
this.projectService = projectService;
@@ -1540,6 +1539,42 @@ namespace ts.projectSystem {
}
});
+ it("removes version numbers correctly", () => {
+ const testData: [string, string][] = [
+ ["jquery-max", "jquery-max"],
+ ["jquery.min", "jquery"],
+ ["jquery-min.4.2.3", "jquery"],
+ ["jquery.min.4.2.1", "jquery"],
+ ["minimum", "minimum"],
+ ["min", "min"],
+ ["min.3.2", "min"],
+ ["jquery", "jquery"]
+ ];
+ for (const t of testData) {
+ assert.equal(removeMinAndVersionNumbers(t[0]), t[1], t[0]);
+ }
+ });
+
+ it("ignores files excluded by a legacy safe type list", () => {
+ const file1 = {
+ path: "/a/b/bliss.js",
+ content: "let x = 5"
+ };
+ const file2 = {
+ path: "/a/b/foo.js",
+ content: ""
+ };
+ const host = createServerHost([file1, file2, customTypesMap]);
+ const projectService = createProjectService(host);
+ try {
+ projectService.openExternalProject({ projectFileName: "project", options: {}, rootFiles: toExternalFiles([file1.path, file2.path]), typeAcquisition: { enable: true } });
+ const proj = projectService.externalProjects[0];
+ assert.deepEqual(proj.getFileNames(), [file2.path]);
+ } finally {
+ projectService.resetSafeList();
+ }
+ });
+
it("open file become a part of configured project if it is referenced from root file", () => {
const file1 = {
path: "/a/b/f1.ts",
@@ -2607,7 +2642,7 @@ namespace ts.projectSystem {
projectFileName,
rootFiles: [toExternalFile(site.path), toExternalFile(configFile.path)],
options: { allowJs: false },
- typeAcquisition: { "include": [] }
+ typeAcquisition: { include: [] }
};
projectService.openExternalProjects([externalProject]);
@@ -2767,6 +2802,7 @@ namespace ts.projectSystem {
watchedRecursiveDirectories.push(`${root}/a/b/src`, `${root}/a/b/node_modules`);
checkWatchedDirectories(host, watchedRecursiveDirectories, /*recursive*/ true);
});
+
});
describe("Proper errors", () => {
@@ -2869,6 +2905,58 @@ namespace ts.projectSystem {
verifyNonExistentFile(/*useProjectRoot*/ false);
});
});
+
+ it("folder rename updates project structure and reports no errors", () => {
+ const projectDir = "/a/b/projects/myproject";
+ const app: FileOrFolder = {
+ path: `${projectDir}/bar/app.ts`,
+ content: "class Bar implements foo.Foo { getFoo() { return ''; } get2() { return 1; } }"
+ };
+ const foo: FileOrFolder = {
+ path: `${projectDir}/foo/foo.ts`,
+ content: "declare namespace foo { interface Foo { get2(): number; getFoo(): string; } }"
+ };
+ const configFile: FileOrFolder = {
+ path: `${projectDir}/tsconfig.json`,
+ content: JSON.stringify({ compilerOptions: { module: "none", targer: "es5" }, exclude: ["node_modules"] })
+ };
+ const host = createServerHost([app, foo, configFile]);
+ const session = createSession(host, { canUseEvents: true, });
+ const projectService = session.getProjectService();
+
+ session.executeCommandSeq({
+ command: server.CommandNames.Open,
+ arguments: { file: app.path, }
+ });
+ checkNumberOfProjects(projectService, { configuredProjects: 1 });
+ assert.isDefined(projectService.configuredProjects.get(configFile.path));
+ verifyErrorsInApp();
+
+ host.renameFolder(`${projectDir}/foo`, `${projectDir}/foo2`);
+ host.runQueuedTimeoutCallbacks();
+ host.runQueuedTimeoutCallbacks();
+ verifyErrorsInApp();
+
+ function verifyErrorsInApp() {
+ host.clearOutput();
+ const expectedSequenceId = session.getNextSeq();
+ session.executeCommandSeq({
+ command: server.CommandNames.Geterr,
+ arguments: {
+ delay: 0,
+ files: [app.path]
+ }
+ });
+ host.checkTimeoutQueueLengthAndRun(1);
+ checkErrorMessage(host, "syntaxDiag", { file: app.path, diagnostics: [] });
+ host.clearOutput();
+
+ host.runQueuedImmediateCallbacks();
+ checkErrorMessage(host, "semanticDiag", { file: app.path, diagnostics: [] });
+ checkCompleteEvent(host, 2, expectedSequenceId);
+ host.clearOutput();
+ }
+ });
});
describe("autoDiscovery", () => {
@@ -3114,12 +3202,12 @@ namespace ts.projectSystem {
path: "/src/tsconfig.json",
content: JSON.stringify(
{
- "compilerOptions": {
- "module": "commonjs",
- "target": "es5",
- "noImplicitAny": true,
- "sourceMap": false,
- "lib": [
+ compilerOptions: {
+ module: "commonjs",
+ target: "es5",
+ noImplicitAny: true,
+ sourceMap: false,
+ lib: [
"es5"
]
}
@@ -3129,12 +3217,12 @@ namespace ts.projectSystem {
path: config1.path,
content: JSON.stringify(
{
- "compilerOptions": {
- "module": "commonjs",
- "target": "es5",
- "noImplicitAny": true,
- "sourceMap": false,
- "lib": [
+ compilerOptions: {
+ module: "commonjs",
+ target: "es5",
+ noImplicitAny: true,
+ sourceMap: false,
+ lib: [
"es5",
"es2015.promise"
]
@@ -4717,7 +4805,7 @@ namespace ts.projectSystem {
const host = createServerHost([f1, config]);
const session = createSession(host, {
canUseEvents: true,
- eventHandler: () => { },
+ eventHandler: noop,
cancellationToken
});
{
@@ -4854,7 +4942,7 @@ namespace ts.projectSystem {
const host = createServerHost([f1, config]);
const session = createSession(host, {
canUseEvents: true,
- eventHandler: () => { },
+ eventHandler: noop,
cancellationToken,
throttleWaitMilliseconds: 0
});
@@ -5483,31 +5571,31 @@ namespace ts.projectSystem {
const tsconfigFile: FileOrFolder = {
path: `${frontendDir}/tsconfig.json`,
content: JSON.stringify({
- "compilerOptions": {
- "strict": true,
- "strictNullChecks": true,
- "target": "es2016",
- "module": "commonjs",
- "moduleResolution": "node",
- "sourceMap": true,
- "noEmitOnError": true,
- "experimentalDecorators": true,
- "emitDecoratorMetadata": true,
+ compilerOptions: {
+ strict: true,
+ strictNullChecks: true,
+ target: "es2016",
+ module: "commonjs",
+ moduleResolution: "node",
+ sourceMap: true,
+ noEmitOnError: true,
+ experimentalDecorators: true,
+ emitDecoratorMetadata: true,
types,
- "noUnusedLocals": true,
- "outDir": "./compiled",
+ noUnusedLocals: true,
+ outDir: "./compiled",
typeRoots,
- "baseUrl": ".",
- "paths": {
+ baseUrl: ".",
+ paths: {
"*": [
"types/*"
]
}
},
- "include": [
+ include: [
"src/**/*"
],
- "exclude": [
+ exclude: [
"node_modules",
"compiled"
]
@@ -5632,66 +5720,66 @@ namespace ts.projectSystem {
// Simulate npm install
const filesAndFoldersToAdd: FileOrFolder[] = [
- { "path": "/a/b/node_modules" },
- { "path": "/a/b/node_modules/.staging/@types" },
- { "path": "/a/b/node_modules/.staging/lodash-b0733faa" },
- { "path": "/a/b/node_modules/.staging/@types/lodash-e56c4fe7" },
- { "path": "/a/b/node_modules/.staging/symbol-observable-24bcbbff" },
- { "path": "/a/b/node_modules/.staging/rxjs-22375c61" },
- { "path": "/a/b/node_modules/.staging/typescript-8493ea5d" },
- { "path": "/a/b/node_modules/.staging/symbol-observable-24bcbbff/package.json", "content": "{\n \"name\": \"symbol-observable\",\n \"version\": \"1.0.4\",\n \"description\": \"Symbol.observable ponyfill\",\n \"license\": \"MIT\",\n \"repository\": \"blesh/symbol-observable\",\n \"author\": {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n \"engines\": {\n \"node\": \">=0.10.0\"\n },\n \"scripts\": {\n \"test\": \"npm run build && mocha && tsc ./ts-test/test.ts && node ./ts-test/test.js && check-es3-syntax -p lib/ --kill\",\n \"build\": \"babel es --out-dir lib\",\n \"prepublish\": \"npm test\"\n },\n \"files\": [\n \"" },
- { "path": "/a/b/node_modules/.staging/lodash-b0733faa/package.json", "content": "{\n \"name\": \"lodash\",\n \"version\": \"4.17.4\",\n \"description\": \"Lodash modular utilities.\",\n \"keywords\": \"modules, stdlib, util\",\n \"homepage\": \"https://lodash.com/\",\n \"repository\": \"lodash/lodash\",\n \"icon\": \"https://lodash.com/icon.svg\",\n \"license\": \"MIT\",\n \"main\": \"lodash.js\",\n \"author\": \"John-David Dalton (http://allyoucanleet.com/)\",\n \"contributors\": [\n \"John-David Dalton (http://allyoucanleet.com/)\",\n \"Mathias Bynens \",\n \"contributors\": [\n {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n {\n \"name\": \"Paul Taylor\",\n \"email\": \"paul.e.taylor@me.com\"\n },\n {\n \"name\": \"Jeff Cross\",\n \"email\": \"crossj@google.com\"\n },\n {\n \"name\": \"Matthew Podwysocki\",\n \"email\": \"matthewp@microsoft.com\"\n },\n {\n \"name\": \"OJ Kwon\",\n \"email\": \"kwon.ohjoong@gmail.com\"\n },\n {\n \"name\": \"Andre Staltz\",\n \"email\": \"andre@staltz.com\"\n }\n ],\n \"license\": \"Apache-2.0\",\n \"bugs\": {\n \"url\": \"https://github.com/ReactiveX/RxJS/issues\"\n },\n \"homepage\": \"https://github.com/ReactiveX/RxJS\",\n \"devDependencies\": {\n \"babel-polyfill\": \"^6.23.0\",\n \"benchmark\": \"^2.1.0\",\n \"benchpress\": \"2.0.0-beta.1\",\n \"chai\": \"^3.5.0\",\n \"color\": \"^0.11.1\",\n \"colors\": \"1.1.2\",\n \"commitizen\": \"^2.8.6\",\n \"coveralls\": \"^2.11.13\",\n \"cz-conventional-changelog\": \"^1.2.0\",\n \"danger\": \"^1.1.0\",\n \"doctoc\": \"^1.0.0\",\n \"escape-string-regexp\": \"^1.0.5 \",\n \"esdoc\": \"^0.4.7\",\n \"eslint\": \"^3.8.0\",\n \"fs-extra\": \"^2.1.2\",\n \"get-folder-size\": \"^1.0.0\",\n \"glob\": \"^7.0.3\",\n \"gm\": \"^1.22.0\",\n \"google-closure-compiler-js\": \"^20170218.0.0\",\n \"gzip-size\": \"^3.0.0\",\n \"http-server\": \"^0.9.0\",\n \"husky\": \"^0.13.3\",\n \"lint-staged\": \"3.2.5\",\n \"lodash\": \"^4.15.0\",\n \"madge\": \"^1.4.3\",\n \"markdown-doctest\": \"^0.9.1\",\n \"minimist\": \"^1.2.0\",\n \"mkdirp\": \"^0.5.1\",\n \"mocha\": \"^3.0.2\",\n \"mocha-in-sauce\": \"0.0.1\",\n \"npm-run-all\": \"^4.0.2\",\n \"npm-scripts-info\": \"^0.3.4\",\n \"nyc\": \"^10.2.0\",\n \"opn-cli\": \"^3.1.0\",\n \"platform\": \"^1.3.1\",\n \"promise\": \"^7.1.1\",\n \"protractor\": \"^3.1.1\",\n \"rollup\": \"0.36.3\",\n \"rollup-plugin-inject\": \"^2.0.0\",\n \"rollup-plugin-node-resolve\": \"^2.0.0\",\n \"rx\": \"latest\",\n \"rxjs\": \"latest\",\n \"shx\": \"^0.2.2\",\n \"sinon\": \"^2.1.0\",\n \"sinon-chai\": \"^2.9.0\",\n \"source-map-support\": \"^0.4.0\",\n \"tslib\": \"^1.5.0\",\n \"tslint\": \"^4.4.2\",\n \"typescript\": \"~2.0.6\",\n \"typings\": \"^2.0.0\",\n \"validate-commit-msg\": \"^2.14.0\",\n \"watch\": \"^1.0.1\",\n \"webpack\": \"^1.13.1\",\n \"xmlhttprequest\": \"1.8.0\"\n },\n \"engines\": {\n \"npm\": \">=2.0.0\"\n },\n \"typings\": \"Rx.d.ts\",\n \"dependencies\": {\n \"symbol-observable\": \"^1.0.1\"\n }\n}" },
- { "path": "/a/b/node_modules/.staging/typescript-8493ea5d/package.json", "content": "{\n \"name\": \"typescript\",\n \"author\": \"Microsoft Corp.\",\n \"homepage\": \"http://typescriptlang.org/\",\n \"version\": \"2.4.2\",\n \"license\": \"Apache-2.0\",\n \"description\": \"TypeScript is a language for application scale JavaScript development\",\n \"keywords\": [\n \"TypeScript\",\n \"Microsoft\",\n \"compiler\",\n \"language\",\n \"javascript\"\n ],\n \"bugs\": {\n \"url\": \"https://github.com/Microsoft/TypeScript/issues\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/Microsoft/TypeScript.git\"\n },\n \"main\": \"./lib/typescript.js\",\n \"typings\": \"./lib/typescript.d.ts\",\n \"bin\": {\n \"tsc\": \"./bin/tsc\",\n \"tsserver\": \"./bin/tsserver\"\n },\n \"engines\": {\n \"node\": \">=4.2.0\"\n },\n \"devDependencies\": {\n \"@types/browserify\": \"latest\",\n \"@types/chai\": \"latest\",\n \"@types/convert-source-map\": \"latest\",\n \"@types/del\": \"latest\",\n \"@types/glob\": \"latest\",\n \"@types/gulp\": \"latest\",\n \"@types/gulp-concat\": \"latest\",\n \"@types/gulp-help\": \"latest\",\n \"@types/gulp-newer\": \"latest\",\n \"@types/gulp-sourcemaps\": \"latest\",\n \"@types/merge2\": \"latest\",\n \"@types/minimatch\": \"latest\",\n \"@types/minimist\": \"latest\",\n \"@types/mkdirp\": \"latest\",\n \"@types/mocha\": \"latest\",\n \"@types/node\": \"latest\",\n \"@types/q\": \"latest\",\n \"@types/run-sequence\": \"latest\",\n \"@types/through2\": \"latest\",\n \"browserify\": \"latest\",\n \"chai\": \"latest\",\n \"convert-source-map\": \"latest\",\n \"del\": \"latest\",\n \"gulp\": \"latest\",\n \"gulp-clone\": \"latest\",\n \"gulp-concat\": \"latest\",\n \"gulp-help\": \"latest\",\n \"gulp-insert\": \"latest\",\n \"gulp-newer\": \"latest\",\n \"gulp-sourcemaps\": \"latest\",\n \"gulp-typescript\": \"latest\",\n \"into-stream\": \"latest\",\n \"istanbul\": \"latest\",\n \"jake\": \"latest\",\n \"merge2\": \"latest\",\n \"minimist\": \"latest\",\n \"mkdirp\": \"latest\",\n \"mocha\": \"latest\",\n \"mocha-fivemat-progress-reporter\": \"latest\",\n \"q\": \"latest\",\n \"run-sequence\": \"latest\",\n \"sorcery\": \"latest\",\n \"through2\": \"latest\",\n \"travis-fold\": \"latest\",\n \"ts-node\": \"latest\",\n \"tslint\": \"latest\",\n \"typescript\": \"^2.4\"\n },\n \"scripts\": {\n \"pretest\": \"jake tests\",\n \"test\": \"jake runtests-parallel\",\n \"build\": \"npm run build:compiler && npm run build:tests\",\n \"build:compiler\": \"jake local\",\n \"build:tests\": \"jake tests\",\n \"start\": \"node lib/tsc\",\n \"clean\": \"jake clean\",\n \"gulp\": \"gulp\",\n \"jake\": \"jake\",\n \"lint\": \"jake lint\",\n \"setup-hooks\": \"node scripts/link-hooks.js\"\n },\n \"browser\": {\n \"buffer\": false,\n \"fs\": false,\n \"os\": false,\n \"path\": false\n }\n}" },
- { "path": "/a/b/node_modules/.staging/symbol-observable-24bcbbff/index.js", "content": "module.exports = require('./lib/index');\n" },
- { "path": "/a/b/node_modules/.staging/symbol-observable-24bcbbff/index.d.ts", "content": "declare const observableSymbol: symbol;\nexport default observableSymbol;\n" },
- { "path": "/a/b/node_modules/.staging/symbol-observable-24bcbbff/lib" },
- { "path": "/a/b/node_modules/.staging/symbol-observable-24bcbbff/lib/index.js", "content": "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _ponyfill = require('./ponyfill');\n\nvar _ponyfill2 = _interopRequireDefault(_ponyfill);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar root; /* global window */\n\n\nif (typeof self !== 'undefined') {\n root = self;\n} else if (typeof window !== 'undefined') {\n root = window;\n} else if (typeof global !== 'undefined') {\n root = global;\n} else if (typeof module !== 'undefined') {\n root = module;\n} else {\n root = Function('return this')();\n}\n\nvar result = (0, _ponyfill2['default'])(root);\nexports['default'] = result;" },
+ { path: "/a/b/node_modules" },
+ { path: "/a/b/node_modules/.staging/@types" },
+ { path: "/a/b/node_modules/.staging/lodash-b0733faa" },
+ { path: "/a/b/node_modules/.staging/@types/lodash-e56c4fe7" },
+ { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff" },
+ { path: "/a/b/node_modules/.staging/rxjs-22375c61" },
+ { path: "/a/b/node_modules/.staging/typescript-8493ea5d" },
+ { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/package.json", content: "{\n \"name\": \"symbol-observable\",\n \"version\": \"1.0.4\",\n \"description\": \"Symbol.observable ponyfill\",\n \"license\": \"MIT\",\n \"repository\": \"blesh/symbol-observable\",\n \"author\": {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n \"engines\": {\n \"node\": \">=0.10.0\"\n },\n \"scripts\": {\n \"test\": \"npm run build && mocha && tsc ./ts-test/test.ts && node ./ts-test/test.js && check-es3-syntax -p lib/ --kill\",\n \"build\": \"babel es --out-dir lib\",\n \"prepublish\": \"npm test\"\n },\n \"files\": [\n \"" },
+ { path: "/a/b/node_modules/.staging/lodash-b0733faa/package.json", content: "{\n \"name\": \"lodash\",\n \"version\": \"4.17.4\",\n \"description\": \"Lodash modular utilities.\",\n \"keywords\": \"modules, stdlib, util\",\n \"homepage\": \"https://lodash.com/\",\n \"repository\": \"lodash/lodash\",\n \"icon\": \"https://lodash.com/icon.svg\",\n \"license\": \"MIT\",\n \"main\": \"lodash.js\",\n \"author\": \"John-David Dalton (http://allyoucanleet.com/)\",\n \"contributors\": [\n \"John-David Dalton (http://allyoucanleet.com/)\",\n \"Mathias Bynens \",\n \"contributors\": [\n {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n {\n \"name\": \"Paul Taylor\",\n \"email\": \"paul.e.taylor@me.com\"\n },\n {\n \"name\": \"Jeff Cross\",\n \"email\": \"crossj@google.com\"\n },\n {\n \"name\": \"Matthew Podwysocki\",\n \"email\": \"matthewp@microsoft.com\"\n },\n {\n \"name\": \"OJ Kwon\",\n \"email\": \"kwon.ohjoong@gmail.com\"\n },\n {\n \"name\": \"Andre Staltz\",\n \"email\": \"andre@staltz.com\"\n }\n ],\n \"license\": \"Apache-2.0\",\n \"bugs\": {\n \"url\": \"https://github.com/ReactiveX/RxJS/issues\"\n },\n \"homepage\": \"https://github.com/ReactiveX/RxJS\",\n \"devDependencies\": {\n \"babel-polyfill\": \"^6.23.0\",\n \"benchmark\": \"^2.1.0\",\n \"benchpress\": \"2.0.0-beta.1\",\n \"chai\": \"^3.5.0\",\n \"color\": \"^0.11.1\",\n \"colors\": \"1.1.2\",\n \"commitizen\": \"^2.8.6\",\n \"coveralls\": \"^2.11.13\",\n \"cz-conventional-changelog\": \"^1.2.0\",\n \"danger\": \"^1.1.0\",\n \"doctoc\": \"^1.0.0\",\n \"escape-string-regexp\": \"^1.0.5 \",\n \"esdoc\": \"^0.4.7\",\n \"eslint\": \"^3.8.0\",\n \"fs-extra\": \"^2.1.2\",\n \"get-folder-size\": \"^1.0.0\",\n \"glob\": \"^7.0.3\",\n \"gm\": \"^1.22.0\",\n \"google-closure-compiler-js\": \"^20170218.0.0\",\n \"gzip-size\": \"^3.0.0\",\n \"http-server\": \"^0.9.0\",\n \"husky\": \"^0.13.3\",\n \"lint-staged\": \"3.2.5\",\n \"lodash\": \"^4.15.0\",\n \"madge\": \"^1.4.3\",\n \"markdown-doctest\": \"^0.9.1\",\n \"minimist\": \"^1.2.0\",\n \"mkdirp\": \"^0.5.1\",\n \"mocha\": \"^3.0.2\",\n \"mocha-in-sauce\": \"0.0.1\",\n \"npm-run-all\": \"^4.0.2\",\n \"npm-scripts-info\": \"^0.3.4\",\n \"nyc\": \"^10.2.0\",\n \"opn-cli\": \"^3.1.0\",\n \"platform\": \"^1.3.1\",\n \"promise\": \"^7.1.1\",\n \"protractor\": \"^3.1.1\",\n \"rollup\": \"0.36.3\",\n \"rollup-plugin-inject\": \"^2.0.0\",\n \"rollup-plugin-node-resolve\": \"^2.0.0\",\n \"rx\": \"latest\",\n \"rxjs\": \"latest\",\n \"shx\": \"^0.2.2\",\n \"sinon\": \"^2.1.0\",\n \"sinon-chai\": \"^2.9.0\",\n \"source-map-support\": \"^0.4.0\",\n \"tslib\": \"^1.5.0\",\n \"tslint\": \"^4.4.2\",\n \"typescript\": \"~2.0.6\",\n \"typings\": \"^2.0.0\",\n \"validate-commit-msg\": \"^2.14.0\",\n \"watch\": \"^1.0.1\",\n \"webpack\": \"^1.13.1\",\n \"xmlhttprequest\": \"1.8.0\"\n },\n \"engines\": {\n \"npm\": \">=2.0.0\"\n },\n \"typings\": \"Rx.d.ts\",\n \"dependencies\": {\n \"symbol-observable\": \"^1.0.1\"\n }\n}" },
+ { path: "/a/b/node_modules/.staging/typescript-8493ea5d/package.json", content: "{\n \"name\": \"typescript\",\n \"author\": \"Microsoft Corp.\",\n \"homepage\": \"http://typescriptlang.org/\",\n \"version\": \"2.4.2\",\n \"license\": \"Apache-2.0\",\n \"description\": \"TypeScript is a language for application scale JavaScript development\",\n \"keywords\": [\n \"TypeScript\",\n \"Microsoft\",\n \"compiler\",\n \"language\",\n \"javascript\"\n ],\n \"bugs\": {\n \"url\": \"https://github.com/Microsoft/TypeScript/issues\"\n },\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/Microsoft/TypeScript.git\"\n },\n \"main\": \"./lib/typescript.js\",\n \"typings\": \"./lib/typescript.d.ts\",\n \"bin\": {\n \"tsc\": \"./bin/tsc\",\n \"tsserver\": \"./bin/tsserver\"\n },\n \"engines\": {\n \"node\": \">=4.2.0\"\n },\n \"devDependencies\": {\n \"@types/browserify\": \"latest\",\n \"@types/chai\": \"latest\",\n \"@types/convert-source-map\": \"latest\",\n \"@types/del\": \"latest\",\n \"@types/glob\": \"latest\",\n \"@types/gulp\": \"latest\",\n \"@types/gulp-concat\": \"latest\",\n \"@types/gulp-help\": \"latest\",\n \"@types/gulp-newer\": \"latest\",\n \"@types/gulp-sourcemaps\": \"latest\",\n \"@types/merge2\": \"latest\",\n \"@types/minimatch\": \"latest\",\n \"@types/minimist\": \"latest\",\n \"@types/mkdirp\": \"latest\",\n \"@types/mocha\": \"latest\",\n \"@types/node\": \"latest\",\n \"@types/q\": \"latest\",\n \"@types/run-sequence\": \"latest\",\n \"@types/through2\": \"latest\",\n \"browserify\": \"latest\",\n \"chai\": \"latest\",\n \"convert-source-map\": \"latest\",\n \"del\": \"latest\",\n \"gulp\": \"latest\",\n \"gulp-clone\": \"latest\",\n \"gulp-concat\": \"latest\",\n \"gulp-help\": \"latest\",\n \"gulp-insert\": \"latest\",\n \"gulp-newer\": \"latest\",\n \"gulp-sourcemaps\": \"latest\",\n \"gulp-typescript\": \"latest\",\n \"into-stream\": \"latest\",\n \"istanbul\": \"latest\",\n \"jake\": \"latest\",\n \"merge2\": \"latest\",\n \"minimist\": \"latest\",\n \"mkdirp\": \"latest\",\n \"mocha\": \"latest\",\n \"mocha-fivemat-progress-reporter\": \"latest\",\n \"q\": \"latest\",\n \"run-sequence\": \"latest\",\n \"sorcery\": \"latest\",\n \"through2\": \"latest\",\n \"travis-fold\": \"latest\",\n \"ts-node\": \"latest\",\n \"tslint\": \"latest\",\n \"typescript\": \"^2.4\"\n },\n \"scripts\": {\n \"pretest\": \"jake tests\",\n \"test\": \"jake runtests-parallel\",\n \"build\": \"npm run build:compiler && npm run build:tests\",\n \"build:compiler\": \"jake local\",\n \"build:tests\": \"jake tests\",\n \"start\": \"node lib/tsc\",\n \"clean\": \"jake clean\",\n \"gulp\": \"gulp\",\n \"jake\": \"jake\",\n \"lint\": \"jake lint\",\n \"setup-hooks\": \"node scripts/link-hooks.js\"\n },\n \"browser\": {\n \"buffer\": false,\n \"fs\": false,\n \"os\": false,\n \"path\": false\n }\n}" },
+ { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/index.js", content: "module.exports = require('./lib/index');\n" },
+ { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/index.d.ts", content: "declare const observableSymbol: symbol;\nexport default observableSymbol;\n" },
+ { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/lib" },
+ { path: "/a/b/node_modules/.staging/symbol-observable-24bcbbff/lib/index.js", content: "'use strict';\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _ponyfill = require('./ponyfill');\n\nvar _ponyfill2 = _interopRequireDefault(_ponyfill);\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }\n\nvar root; /* global window */\n\n\nif (typeof self !== 'undefined') {\n root = self;\n} else if (typeof window !== 'undefined') {\n root = window;\n} else if (typeof global !== 'undefined') {\n root = global;\n} else if (typeof module !== 'undefined') {\n root = module;\n} else {\n root = Function('return this')();\n}\n\nvar result = (0, _ponyfill2['default'])(root);\nexports['default'] = result;" },
].map(getRootedFileOrFolder);
verifyAfterPartialOrCompleteNpmInstall(2);
filesAndFoldersToAdd.push(...[
- { "path": "/a/b/node_modules/.staging/typescript-8493ea5d/lib" },
- { "path": "/a/b/node_modules/.staging/rxjs-22375c61/add/operator" },
- { "path": "/a/b/node_modules/.staging/@types/lodash-e56c4fe7/package.json", "content": "{\n \"name\": \"@types/lodash\",\n \"version\": \"4.14.74\",\n \"description\": \"TypeScript definitions for Lo-Dash\",\n \"license\": \"MIT\",\n \"contributors\": [\n {\n \"name\": \"Brian Zengel\",\n \"url\": \"https://github.com/bczengel\"\n },\n {\n \"name\": \"Ilya Mochalov\",\n \"url\": \"https://github.com/chrootsu\"\n },\n {\n \"name\": \"Stepan Mikhaylyuk\",\n \"url\": \"https://github.com/stepancar\"\n },\n {\n \"name\": \"Eric L Anderson\",\n \"url\": \"https://github.com/ericanderson\"\n },\n {\n \"name\": \"AJ Richardson\",\n \"url\": \"https://github.com/aj-r\"\n },\n {\n \"name\": \"Junyoung Clare Jang\",\n \"url\": \"https://github.com/ailrun\"\n }\n ],\n \"main\": \"\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://www.github.com/DefinitelyTyped/DefinitelyTyped.git\"\n },\n \"scripts\": {},\n \"dependencies\": {},\n \"typesPublisherContentHash\": \"12af578ffaf8d86d2df37e591857906a86b983fa9258414326544a0fe6af0de8\",\n \"typeScriptVersion\": \"2.2\"\n}" },
- { "path": "/a/b/node_modules/.staging/lodash-b0733faa/index.js", "content": "module.exports = require('./lodash');" },
- { "path": "/a/b/node_modules/.staging/typescript-8493ea5d/package.json.3017591594" }
+ { path: "/a/b/node_modules/.staging/typescript-8493ea5d/lib" },
+ { path: "/a/b/node_modules/.staging/rxjs-22375c61/add/operator" },
+ { path: "/a/b/node_modules/.staging/@types/lodash-e56c4fe7/package.json", content: "{\n \"name\": \"@types/lodash\",\n \"version\": \"4.14.74\",\n \"description\": \"TypeScript definitions for Lo-Dash\",\n \"license\": \"MIT\",\n \"contributors\": [\n {\n \"name\": \"Brian Zengel\",\n \"url\": \"https://github.com/bczengel\"\n },\n {\n \"name\": \"Ilya Mochalov\",\n \"url\": \"https://github.com/chrootsu\"\n },\n {\n \"name\": \"Stepan Mikhaylyuk\",\n \"url\": \"https://github.com/stepancar\"\n },\n {\n \"name\": \"Eric L Anderson\",\n \"url\": \"https://github.com/ericanderson\"\n },\n {\n \"name\": \"AJ Richardson\",\n \"url\": \"https://github.com/aj-r\"\n },\n {\n \"name\": \"Junyoung Clare Jang\",\n \"url\": \"https://github.com/ailrun\"\n }\n ],\n \"main\": \"\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://www.github.com/DefinitelyTyped/DefinitelyTyped.git\"\n },\n \"scripts\": {},\n \"dependencies\": {},\n \"typesPublisherContentHash\": \"12af578ffaf8d86d2df37e591857906a86b983fa9258414326544a0fe6af0de8\",\n \"typeScriptVersion\": \"2.2\"\n}" },
+ { path: "/a/b/node_modules/.staging/lodash-b0733faa/index.js", content: "module.exports = require('./lodash');" },
+ { path: "/a/b/node_modules/.staging/typescript-8493ea5d/package.json.3017591594" }
].map(getRootedFileOrFolder));
- // Since we didnt add any supported extension file, there wont be any timeout scheduled
- verifyAfterPartialOrCompleteNpmInstall(0);
+ // Since we added/removed folder, scheduled project update
+ verifyAfterPartialOrCompleteNpmInstall(2);
// Remove file "/a/b/node_modules/.staging/typescript-8493ea5d/package.json.3017591594"
filesAndFoldersToAdd.length--;
verifyAfterPartialOrCompleteNpmInstall(0);
filesAndFoldersToAdd.push(...[
- { "path": "/a/b/node_modules/.staging/rxjs-22375c61/bundles" },
- { "path": "/a/b/node_modules/.staging/rxjs-22375c61/operator" },
- { "path": "/a/b/node_modules/.staging/rxjs-22375c61/src/add/observable/dom" },
- { "path": "/a/b/node_modules/.staging/@types/lodash-e56c4fe7/index.d.ts", "content": "\n// Stub for lodash\nexport = _;\nexport as namespace _;\ndeclare var _: _.LoDashStatic;\ndeclare namespace _ {\n interface LoDashStatic {\n someProp: string;\n }\n class SomeClass {\n someMethod(): void;\n }\n}" }
+ { path: "/a/b/node_modules/.staging/rxjs-22375c61/bundles" },
+ { path: "/a/b/node_modules/.staging/rxjs-22375c61/operator" },
+ { path: "/a/b/node_modules/.staging/rxjs-22375c61/src/add/observable/dom" },
+ { path: "/a/b/node_modules/.staging/@types/lodash-e56c4fe7/index.d.ts", content: "\n// Stub for lodash\nexport = _;\nexport as namespace _;\ndeclare var _: _.LoDashStatic;\ndeclare namespace _ {\n interface LoDashStatic {\n someProp: string;\n }\n class SomeClass {\n someMethod(): void;\n }\n}" }
].map(getRootedFileOrFolder));
verifyAfterPartialOrCompleteNpmInstall(2);
filesAndFoldersToAdd.push(...[
- { "path": "/a/b/node_modules/.staging/rxjs-22375c61/src/scheduler" },
- { "path": "/a/b/node_modules/.staging/rxjs-22375c61/src/util" },
- { "path": "/a/b/node_modules/.staging/rxjs-22375c61/symbol" },
- { "path": "/a/b/node_modules/.staging/rxjs-22375c61/testing" },
- { "path": "/a/b/node_modules/.staging/rxjs-22375c61/package.json.2252192041", "content": "{\n \"_args\": [\n [\n {\n \"raw\": \"rxjs@^5.4.2\",\n \"scope\": null,\n \"escapedName\": \"rxjs\",\n \"name\": \"rxjs\",\n \"rawSpec\": \"^5.4.2\",\n \"spec\": \">=5.4.2 <6.0.0\",\n \"type\": \"range\"\n },\n \"C:\\\\Users\\\\shkamat\\\\Desktop\\\\app\"\n ]\n ],\n \"_from\": \"rxjs@>=5.4.2 <6.0.0\",\n \"_id\": \"rxjs@5.4.3\",\n \"_inCache\": true,\n \"_location\": \"/rxjs\",\n \"_nodeVersion\": \"7.7.2\",\n \"_npmOperationalInternal\": {\n \"host\": \"s3://npm-registry-packages\",\n \"tmp\": \"tmp/rxjs-5.4.3.tgz_1502407898166_0.6800217325799167\"\n },\n \"_npmUser\": {\n \"name\": \"blesh\",\n \"email\": \"ben@benlesh.com\"\n },\n \"_npmVersion\": \"5.3.0\",\n \"_phantomChildren\": {},\n \"_requested\": {\n \"raw\": \"rxjs@^5.4.2\",\n \"scope\": null,\n \"escapedName\": \"rxjs\",\n \"name\": \"rxjs\",\n \"rawSpec\": \"^5.4.2\",\n \"spec\": \">=5.4.2 <6.0.0\",\n \"type\": \"range\"\n },\n \"_requiredBy\": [\n \"/\"\n ],\n \"_resolved\": \"https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz\",\n \"_shasum\": \"0758cddee6033d68e0fd53676f0f3596ce3d483f\",\n \"_shrinkwrap\": null,\n \"_spec\": \"rxjs@^5.4.2\",\n \"_where\": \"C:\\\\Users\\\\shkamat\\\\Desktop\\\\app\",\n \"author\": {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/ReactiveX/RxJS/issues\"\n },\n \"config\": {\n \"commitizen\": {\n \"path\": \"cz-conventional-changelog\"\n }\n },\n \"contributors\": [\n {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n {\n \"name\": \"Paul Taylor\",\n \"email\": \"paul.e.taylor@me.com\"\n },\n {\n \"name\": \"Jeff Cross\",\n \"email\": \"crossj@google.com\"\n },\n {\n \"name\": \"Matthew Podwysocki\",\n \"email\": \"matthewp@microsoft.com\"\n },\n {\n \"name\": \"OJ Kwon\",\n \"email\": \"kwon.ohjoong@gmail.com\"\n },\n {\n \"name\": \"Andre Staltz\",\n \"email\": \"andre@staltz.com\"\n }\n ],\n \"dependencies\": {\n \"symbol-observable\": \"^1.0.1\"\n },\n \"description\": \"Reactive Extensions for modern JavaScript\",\n \"devDependencies\": {\n \"babel-polyfill\": \"^6.23.0\",\n \"benchmark\": \"^2.1.0\",\n \"benchpress\": \"2.0.0-beta.1\",\n \"chai\": \"^3.5.0\",\n \"color\": \"^0.11.1\",\n \"colors\": \"1.1.2\",\n \"commitizen\": \"^2.8.6\",\n \"coveralls\": \"^2.11.13\",\n \"cz-conventional-changelog\": \"^1.2.0\",\n \"danger\": \"^1.1.0\",\n \"doctoc\": \"^1.0.0\",\n \"escape-string-regexp\": \"^1.0.5 \",\n \"esdoc\": \"^0.4.7\",\n \"eslint\": \"^3.8.0\",\n \"fs-extra\": \"^2.1.2\",\n \"get-folder-size\": \"^1.0.0\",\n \"glob\": \"^7.0.3\",\n \"gm\": \"^1.22.0\",\n \"google-closure-compiler-js\": \"^20170218.0.0\",\n \"gzip-size\": \"^3.0.0\",\n \"http-server\": \"^0.9.0\",\n \"husky\": \"^0.13.3\",\n \"lint-staged\": \"3.2.5\",\n \"lodash\": \"^4.15.0\",\n \"madge\": \"^1.4.3\",\n \"markdown-doctest\": \"^0.9.1\",\n \"minimist\": \"^1.2.0\",\n \"mkdirp\": \"^0.5.1\",\n \"mocha\": \"^3.0.2\",\n \"mocha-in-sauce\": \"0.0.1\",\n \"npm-run-all\": \"^4.0.2\",\n \"npm-scripts-info\": \"^0.3.4\",\n \"nyc\": \"^10.2.0\",\n \"opn-cli\": \"^3.1.0\",\n \"platform\": \"^1.3.1\",\n \"promise\": \"^7.1.1\",\n \"protractor\": \"^3.1.1\",\n \"rollup\": \"0.36.3\",\n \"rollup-plugin-inject\": \"^2.0.0\",\n \"rollup-plugin-node-resolve\": \"^2.0.0\",\n \"rx\": \"latest\",\n \"rxjs\": \"latest\",\n \"shx\": \"^0.2.2\",\n \"sinon\": \"^2.1.0\",\n \"sinon-chai\": \"^2.9.0\",\n \"source-map-support\": \"^0.4.0\",\n \"tslib\": \"^1.5.0\",\n \"tslint\": \"^4.4.2\",\n \"typescript\": \"~2.0.6\",\n \"typings\": \"^2.0.0\",\n \"validate-commit-msg\": \"^2.14.0\",\n \"watch\": \"^1.0.1\",\n \"webpack\": \"^1.13.1\",\n \"xmlhttprequest\": \"1.8.0\"\n },\n \"directories\": {},\n \"dist\": {\n \"integrity\": \"sha512-fSNi+y+P9ss+EZuV0GcIIqPUK07DEaMRUtLJvdcvMyFjc9dizuDjere+A4V7JrLGnm9iCc+nagV/4QdMTkqC4A==\",\n \"shasum\": \"0758cddee6033d68e0fd53676f0f3596ce3d483f\",\n \"tarball\": \"https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz\"\n },\n \"engines\": {\n \"npm\": \">=2.0.0\"\n },\n \"homepage\": \"https://github.com/ReactiveX/RxJS\",\n \"keywords\": [\n \"Rx\",\n \"RxJS\",\n \"ReactiveX\",\n \"ReactiveExtensions\",\n \"Streams\",\n \"Observables\",\n \"Observable\",\n \"Stream\",\n \"ES6\",\n \"ES2015\"\n ],\n \"license\": \"Apache-2.0\",\n \"lint-staged\": {\n \"*.@(js)\": [\n \"eslint --fix\",\n \"git add\"\n ],\n \"*.@(ts)\": [\n \"tslint --fix\",\n \"git add\"\n ]\n },\n \"main\": \"Rx.js\",\n \"maintainers\": [\n {\n \"name\": \"blesh\",\n \"email\": \"ben@benlesh.com\"\n }\n ],\n \"name\": \"rxjs\",\n \"optionalDependencies\": {},\n \"readme\": \"ERROR: No README data found!\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+ssh://git@github.com/ReactiveX/RxJS.git\"\n },\n \"scripts-info\": {\n \"info\": \"List available script\",\n \"build_all\": \"Build all packages (ES6, CJS, UMD) and generate packages\",\n \"build_cjs\": \"Build CJS package with clean up existing build, copy source into dist\",\n \"build_es6\": \"Build ES6 package with clean up existing build, copy source into dist\",\n \"build_closure_core\": \"Minify Global core build using closure compiler\",\n \"build_global\": \"Build Global package, then minify build\",\n \"build_perf\": \"Build CJS & Global build, run macro performance test\",\n \"build_test\": \"Build CJS package & test spec, execute mocha test runner\",\n \"build_cover\": \"Run lint to current code, build CJS & test spec, execute test coverage\",\n \"build_docs\": \"Build ES6 & global package, create documentation using it\",\n \"build_spec\": \"Build test specs\",\n \"check_circular_dependencies\": \"Check codebase has circular dependencies\",\n \"clean_spec\": \"Clean up existing test spec build output\",\n \"clean_dist_cjs\": \"Clean up existing CJS package output\",\n \"clean_dist_es6\": \"Clean up existing ES6 package output\",\n \"clean_dist_global\": \"Clean up existing Global package output\",\n \"commit\": \"Run git commit wizard\",\n \"compile_dist_cjs\": \"Compile codebase into CJS module\",\n \"compile_module_es6\": \"Compile codebase into ES6\",\n \"cover\": \"Execute test coverage\",\n \"lint_perf\": \"Run lint against performance test suite\",\n \"lint_spec\": \"Run lint against test spec\",\n \"lint_src\": \"Run lint against source\",\n \"lint\": \"Run lint against everything\",\n \"perf\": \"Run macro performance benchmark\",\n \"perf_micro\": \"Run micro performance benchmark\",\n \"test_mocha\": \"Execute mocha test runner against existing test spec build\",\n \"test_browser\": \"Execute mocha test runner on browser against existing test spec build\",\n \"test\": \"Clean up existing test spec build, build test spec and execute mocha test runner\",\n \"tests2png\": \"Generate marble diagram image from test spec\",\n \"watch\": \"Watch codebase, trigger compile when source code changes\"\n },\n \"typings\": \"Rx.d.ts\",\n \"version\": \"5.4.3\"\n}\n" }
+ { path: "/a/b/node_modules/.staging/rxjs-22375c61/src/scheduler" },
+ { path: "/a/b/node_modules/.staging/rxjs-22375c61/src/util" },
+ { path: "/a/b/node_modules/.staging/rxjs-22375c61/symbol" },
+ { path: "/a/b/node_modules/.staging/rxjs-22375c61/testing" },
+ { path: "/a/b/node_modules/.staging/rxjs-22375c61/package.json.2252192041", content: "{\n \"_args\": [\n [\n {\n \"raw\": \"rxjs@^5.4.2\",\n \"scope\": null,\n \"escapedName\": \"rxjs\",\n \"name\": \"rxjs\",\n \"rawSpec\": \"^5.4.2\",\n \"spec\": \">=5.4.2 <6.0.0\",\n \"type\": \"range\"\n },\n \"C:\\\\Users\\\\shkamat\\\\Desktop\\\\app\"\n ]\n ],\n \"_from\": \"rxjs@>=5.4.2 <6.0.0\",\n \"_id\": \"rxjs@5.4.3\",\n \"_inCache\": true,\n \"_location\": \"/rxjs\",\n \"_nodeVersion\": \"7.7.2\",\n \"_npmOperationalInternal\": {\n \"host\": \"s3://npm-registry-packages\",\n \"tmp\": \"tmp/rxjs-5.4.3.tgz_1502407898166_0.6800217325799167\"\n },\n \"_npmUser\": {\n \"name\": \"blesh\",\n \"email\": \"ben@benlesh.com\"\n },\n \"_npmVersion\": \"5.3.0\",\n \"_phantomChildren\": {},\n \"_requested\": {\n \"raw\": \"rxjs@^5.4.2\",\n \"scope\": null,\n \"escapedName\": \"rxjs\",\n \"name\": \"rxjs\",\n \"rawSpec\": \"^5.4.2\",\n \"spec\": \">=5.4.2 <6.0.0\",\n \"type\": \"range\"\n },\n \"_requiredBy\": [\n \"/\"\n ],\n \"_resolved\": \"https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz\",\n \"_shasum\": \"0758cddee6033d68e0fd53676f0f3596ce3d483f\",\n \"_shrinkwrap\": null,\n \"_spec\": \"rxjs@^5.4.2\",\n \"_where\": \"C:\\\\Users\\\\shkamat\\\\Desktop\\\\app\",\n \"author\": {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/ReactiveX/RxJS/issues\"\n },\n \"config\": {\n \"commitizen\": {\n \"path\": \"cz-conventional-changelog\"\n }\n },\n \"contributors\": [\n {\n \"name\": \"Ben Lesh\",\n \"email\": \"ben@benlesh.com\"\n },\n {\n \"name\": \"Paul Taylor\",\n \"email\": \"paul.e.taylor@me.com\"\n },\n {\n \"name\": \"Jeff Cross\",\n \"email\": \"crossj@google.com\"\n },\n {\n \"name\": \"Matthew Podwysocki\",\n \"email\": \"matthewp@microsoft.com\"\n },\n {\n \"name\": \"OJ Kwon\",\n \"email\": \"kwon.ohjoong@gmail.com\"\n },\n {\n \"name\": \"Andre Staltz\",\n \"email\": \"andre@staltz.com\"\n }\n ],\n \"dependencies\": {\n \"symbol-observable\": \"^1.0.1\"\n },\n \"description\": \"Reactive Extensions for modern JavaScript\",\n \"devDependencies\": {\n \"babel-polyfill\": \"^6.23.0\",\n \"benchmark\": \"^2.1.0\",\n \"benchpress\": \"2.0.0-beta.1\",\n \"chai\": \"^3.5.0\",\n \"color\": \"^0.11.1\",\n \"colors\": \"1.1.2\",\n \"commitizen\": \"^2.8.6\",\n \"coveralls\": \"^2.11.13\",\n \"cz-conventional-changelog\": \"^1.2.0\",\n \"danger\": \"^1.1.0\",\n \"doctoc\": \"^1.0.0\",\n \"escape-string-regexp\": \"^1.0.5 \",\n \"esdoc\": \"^0.4.7\",\n \"eslint\": \"^3.8.0\",\n \"fs-extra\": \"^2.1.2\",\n \"get-folder-size\": \"^1.0.0\",\n \"glob\": \"^7.0.3\",\n \"gm\": \"^1.22.0\",\n \"google-closure-compiler-js\": \"^20170218.0.0\",\n \"gzip-size\": \"^3.0.0\",\n \"http-server\": \"^0.9.0\",\n \"husky\": \"^0.13.3\",\n \"lint-staged\": \"3.2.5\",\n \"lodash\": \"^4.15.0\",\n \"madge\": \"^1.4.3\",\n \"markdown-doctest\": \"^0.9.1\",\n \"minimist\": \"^1.2.0\",\n \"mkdirp\": \"^0.5.1\",\n \"mocha\": \"^3.0.2\",\n \"mocha-in-sauce\": \"0.0.1\",\n \"npm-run-all\": \"^4.0.2\",\n \"npm-scripts-info\": \"^0.3.4\",\n \"nyc\": \"^10.2.0\",\n \"opn-cli\": \"^3.1.0\",\n \"platform\": \"^1.3.1\",\n \"promise\": \"^7.1.1\",\n \"protractor\": \"^3.1.1\",\n \"rollup\": \"0.36.3\",\n \"rollup-plugin-inject\": \"^2.0.0\",\n \"rollup-plugin-node-resolve\": \"^2.0.0\",\n \"rx\": \"latest\",\n \"rxjs\": \"latest\",\n \"shx\": \"^0.2.2\",\n \"sinon\": \"^2.1.0\",\n \"sinon-chai\": \"^2.9.0\",\n \"source-map-support\": \"^0.4.0\",\n \"tslib\": \"^1.5.0\",\n \"tslint\": \"^4.4.2\",\n \"typescript\": \"~2.0.6\",\n \"typings\": \"^2.0.0\",\n \"validate-commit-msg\": \"^2.14.0\",\n \"watch\": \"^1.0.1\",\n \"webpack\": \"^1.13.1\",\n \"xmlhttprequest\": \"1.8.0\"\n },\n \"directories\": {},\n \"dist\": {\n \"integrity\": \"sha512-fSNi+y+P9ss+EZuV0GcIIqPUK07DEaMRUtLJvdcvMyFjc9dizuDjere+A4V7JrLGnm9iCc+nagV/4QdMTkqC4A==\",\n \"shasum\": \"0758cddee6033d68e0fd53676f0f3596ce3d483f\",\n \"tarball\": \"https://registry.npmjs.org/rxjs/-/rxjs-5.4.3.tgz\"\n },\n \"engines\": {\n \"npm\": \">=2.0.0\"\n },\n \"homepage\": \"https://github.com/ReactiveX/RxJS\",\n \"keywords\": [\n \"Rx\",\n \"RxJS\",\n \"ReactiveX\",\n \"ReactiveExtensions\",\n \"Streams\",\n \"Observables\",\n \"Observable\",\n \"Stream\",\n \"ES6\",\n \"ES2015\"\n ],\n \"license\": \"Apache-2.0\",\n \"lint-staged\": {\n \"*.@(js)\": [\n \"eslint --fix\",\n \"git add\"\n ],\n \"*.@(ts)\": [\n \"tslint --fix\",\n \"git add\"\n ]\n },\n \"main\": \"Rx.js\",\n \"maintainers\": [\n {\n \"name\": \"blesh\",\n \"email\": \"ben@benlesh.com\"\n }\n ],\n \"name\": \"rxjs\",\n \"optionalDependencies\": {},\n \"readme\": \"ERROR: No README data found!\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+ssh://git@github.com/ReactiveX/RxJS.git\"\n },\n \"scripts-info\": {\n \"info\": \"List available script\",\n \"build_all\": \"Build all packages (ES6, CJS, UMD) and generate packages\",\n \"build_cjs\": \"Build CJS package with clean up existing build, copy source into dist\",\n \"build_es6\": \"Build ES6 package with clean up existing build, copy source into dist\",\n \"build_closure_core\": \"Minify Global core build using closure compiler\",\n \"build_global\": \"Build Global package, then minify build\",\n \"build_perf\": \"Build CJS & Global build, run macro performance test\",\n \"build_test\": \"Build CJS package & test spec, execute mocha test runner\",\n \"build_cover\": \"Run lint to current code, build CJS & test spec, execute test coverage\",\n \"build_docs\": \"Build ES6 & global package, create documentation using it\",\n \"build_spec\": \"Build test specs\",\n \"check_circular_dependencies\": \"Check codebase has circular dependencies\",\n \"clean_spec\": \"Clean up existing test spec build output\",\n \"clean_dist_cjs\": \"Clean up existing CJS package output\",\n \"clean_dist_es6\": \"Clean up existing ES6 package output\",\n \"clean_dist_global\": \"Clean up existing Global package output\",\n \"commit\": \"Run git commit wizard\",\n \"compile_dist_cjs\": \"Compile codebase into CJS module\",\n \"compile_module_es6\": \"Compile codebase into ES6\",\n \"cover\": \"Execute test coverage\",\n \"lint_perf\": \"Run lint against performance test suite\",\n \"lint_spec\": \"Run lint against test spec\",\n \"lint_src\": \"Run lint against source\",\n \"lint\": \"Run lint against everything\",\n \"perf\": \"Run macro performance benchmark\",\n \"perf_micro\": \"Run micro performance benchmark\",\n \"test_mocha\": \"Execute mocha test runner against existing test spec build\",\n \"test_browser\": \"Execute mocha test runner on browser against existing test spec build\",\n \"test\": \"Clean up existing test spec build, build test spec and execute mocha test runner\",\n \"tests2png\": \"Generate marble diagram image from test spec\",\n \"watch\": \"Watch codebase, trigger compile when source code changes\"\n },\n \"typings\": \"Rx.d.ts\",\n \"version\": \"5.4.3\"\n}\n" }
].map(getRootedFileOrFolder));
- verifyAfterPartialOrCompleteNpmInstall(0);
+ verifyAfterPartialOrCompleteNpmInstall(2);
// remove /a/b/node_modules/.staging/rxjs-22375c61/package.json.2252192041
filesAndFoldersToAdd.length--;
// and add few more folders/files
filesAndFoldersToAdd.push(...[
- { "path": "/a/b/node_modules/symbol-observable" },
- { "path": "/a/b/node_modules/@types" },
- { "path": "/a/b/node_modules/@types/lodash" },
- { "path": "/a/b/node_modules/lodash" },
- { "path": "/a/b/node_modules/rxjs" },
- { "path": "/a/b/node_modules/typescript" },
- { "path": "/a/b/node_modules/.bin" }
+ { path: "/a/b/node_modules/symbol-observable" },
+ { path: "/a/b/node_modules/@types" },
+ { path: "/a/b/node_modules/@types/lodash" },
+ { path: "/a/b/node_modules/lodash" },
+ { path: "/a/b/node_modules/rxjs" },
+ { path: "/a/b/node_modules/typescript" },
+ { path: "/a/b/node_modules/.bin" }
].map(getRootedFileOrFolder));
// From the type root update
verifyAfterPartialOrCompleteNpmInstall(2);
diff --git a/src/harness/unittests/typingsInstaller.ts b/src/harness/unittests/typingsInstaller.ts
index fb1a7a26a7a..e321fb1c99d 100644
--- a/src/harness/unittests/typingsInstaller.ts
+++ b/src/harness/unittests/typingsInstaller.ts
@@ -776,8 +776,8 @@ namespace ts.projectSystem {
const bowerJson = {
path: "/bower.json",
content: JSON.stringify({
- "dependencies": {
- "jquery": "^3.1.0"
+ dependencies: {
+ jquery: "^3.1.0"
}
})
};
@@ -1012,7 +1012,7 @@ namespace ts.projectSystem {
const packageJson = {
path: "/a/b/package.json",
content: JSON.stringify({
- "dependencies": {
+ dependencies: {
"; say ‘Hello from TypeScript!’ #": "0.0.x"
}
})
@@ -1057,11 +1057,12 @@ namespace ts.projectSystem {
const host = createServerHost([app, jquery, chroma]);
const logger = trackingLogger();
const result = JsTyping.discoverTypings(host, logger.log, [app.path, jquery.path, chroma.path], getDirectoryPath(app.path), safeList, emptyMap, { enable: true }, emptyArray);
- assert.deepEqual(logger.finish(), [
+ const finish = logger.finish();
+ assert.deepEqual(finish, [
'Inferred typings from file names: ["jquery","chroma-js"]',
"Inferred typings from unresolved imports: []",
'Result: {"cachedTypingPaths":[],"newTypingNames":["jquery","chroma-js"],"filesToWatch":["/a/b/bower_components","/a/b/node_modules"]}',
- ]);
+ ], finish.join("\r\n"));
assert.deepEqual(result.newTypingNames, ["jquery", "chroma-js"]);
});
@@ -1094,7 +1095,7 @@ namespace ts.projectSystem {
content: ""
};
const host = createServerHost([f, node]);
- const cache = createMapFromTemplate({ "node": node.path });
+ const cache = createMapFromTemplate({ node: node.path });
const logger = trackingLogger();
const result = JsTyping.discoverTypings(host, logger.log, [f.path], getDirectoryPath(f.path), emptySafeList, cache, { enable: true }, ["fs", "bar"]);
assert.deepEqual(logger.finish(), [
@@ -1144,7 +1145,7 @@ namespace ts.projectSystem {
};
const packageFile = {
path: "/a/package.json",
- content: JSON.stringify({ dependencies: { "commander": "1.0.0" } })
+ content: JSON.stringify({ dependencies: { commander: "1.0.0" } })
};
const cachePath = "/a/cache/";
const commander = {
@@ -1194,7 +1195,7 @@ namespace ts.projectSystem {
};
const packageFile = {
path: "/a/package.json",
- content: JSON.stringify({ dependencies: { "commander": "1.0.0" } })
+ content: JSON.stringify({ dependencies: { commander: "1.0.0" } })
};
const cachePath = "/a/cache/";
const commander = {
@@ -1246,7 +1247,7 @@ namespace ts.projectSystem {
};
const packageFile = {
path: "/a/package.json",
- content: JSON.stringify({ dependencies: { "commander": "1.0.0" } })
+ content: JSON.stringify({ dependencies: { commander: "1.0.0" } })
};
const cachePath = "/a/cache/";
const host = createServerHost([f1, packageFile]);
diff --git a/src/harness/userRunner.ts b/src/harness/userRunner.ts
deleted file mode 100644
index 9be652aebf8..00000000000
--- a/src/harness/userRunner.ts
+++ /dev/null
@@ -1,51 +0,0 @@
-///
-///
-class UserCodeRunner extends RunnerBase {
- private static readonly testDir = "tests/cases/user/";
- public enumerateTestFiles() {
- return Harness.IO.getDirectories(UserCodeRunner.testDir);
- }
-
- public kind(): TestRunnerKind {
- return "user";
- }
-
- /** Setup the runner's tests so that they are ready to be executed by the harness
- * The first test should be a describe/it block that sets up the harness's compiler instance appropriately
- */
- public initializeTests(): void {
- // Read in and evaluate the test list
- const testList = this.tests && this.tests.length ? this.tests : this.enumerateTestFiles();
-
- describe(`${this.kind()} code samples`, () => {
- for (const test of testList) {
- this.runTest(test);
- }
- });
- }
-
- private runTest(directoryName: string) {
- describe(directoryName, () => {
- const cp = require("child_process");
- const path = require("path");
-
- it("should build successfully", () => {
- const cwd = path.join(__dirname, "../../", UserCodeRunner.testDir, directoryName);
- const timeout = 600000; // 10 minutes
- const stdio = isWorker ? "pipe" : "inherit";
- const install = cp.spawnSync(`npm`, ["i"], { cwd, timeout, shell: true, stdio });
- if (install.status !== 0) throw new Error(`NPM Install for ${directoryName} failed!`);
- Harness.Baseline.runBaseline(`${this.kind()}/${directoryName}.log`, () => {
- const result = cp.spawnSync(`node`, ["../../../../built/local/tsc.js"], { cwd, timeout, shell: true });
- return `Exit Code: ${result.status}
-Standard output:
-${result.stdout.toString().replace(/\r\n/g, "\n")}
-
-
-Standard error:
-${result.stderr.toString().replace(/\r\n/g, "\n")}`;
- });
- });
- });
- }
-}
diff --git a/src/harness/virtualFileSystemWithWatch.ts b/src/harness/virtualFileSystemWithWatch.ts
index 6c3bd8a635a..25581093f3d 100644
--- a/src/harness/virtualFileSystemWithWatch.ts
+++ b/src/harness/virtualFileSystemWithWatch.ts
@@ -346,6 +346,39 @@ interface Array {}`
}
}
+ renameFolder(folderName: string, newFolderName: string) {
+ const fullPath = getNormalizedAbsolutePath(folderName, this.currentDirectory);
+ const path = this.toPath(fullPath);
+ const folder = this.fs.get(path) as Folder;
+ Debug.assert(!!folder);
+
+ // Only remove the folder
+ this.removeFileOrFolder(folder, returnFalse, /*isRenaming*/ true);
+
+ // Add updated folder with new folder name
+ const newFullPath = getNormalizedAbsolutePath(newFolderName, this.currentDirectory);
+ const newFolder = this.toFolder(newFullPath);
+ const newPath = newFolder.path;
+ const basePath = getDirectoryPath(path);
+ Debug.assert(basePath !== path);
+ Debug.assert(basePath === getDirectoryPath(newPath));
+ const baseFolder = this.fs.get(basePath) as Folder;
+ this.addFileOrFolderInFolder(baseFolder, newFolder);
+
+ // Invoke watches for files in the folder as deleted (from old path)
+ for (const entry of folder.entries) {
+ Debug.assert(isFile(entry));
+ this.fs.delete(entry.path);
+ this.invokeFileWatcher(entry.fullPath, FileWatcherEventKind.Deleted);
+
+ entry.fullPath = combinePaths(newFullPath, getBaseFileName(entry.fullPath));
+ entry.path = this.toPath(entry.fullPath);
+ newFolder.entries.push(entry);
+ this.fs.set(entry.path, entry);
+ this.invokeFileWatcher(entry.fullPath, FileWatcherEventKind.Created);
+ }
+ }
+
ensureFileOrFolder(fileOrDirectory: FileOrFolder, ignoreWatchInvokedWithTriggerAsFileCreate?: boolean) {
if (isString(fileOrDirectory.content)) {
const file = this.toFile(fileOrDirectory);
@@ -393,7 +426,7 @@ interface Array {}`
this.invokeDirectoryWatcher(folder.fullPath, fileOrDirectory.fullPath);
}
- private removeFileOrFolder(fileOrDirectory: File | Folder, isRemovableLeafFolder: (folder: Folder) => boolean) {
+ private removeFileOrFolder(fileOrDirectory: File | Folder, isRemovableLeafFolder: (folder: Folder) => boolean, isRenaming?: boolean) {
const basePath = getDirectoryPath(fileOrDirectory.path);
const baseFolder = this.fs.get(basePath) as Folder;
if (basePath !== fileOrDirectory.path) {
@@ -406,7 +439,7 @@ interface Array {}`
this.invokeFileWatcher(fileOrDirectory.fullPath, FileWatcherEventKind.Deleted);
}
else {
- Debug.assert(fileOrDirectory.entries.length === 0);
+ Debug.assert(fileOrDirectory.entries.length === 0 || isRenaming);
const relativePath = this.getRelativePathToDirectory(fileOrDirectory.fullPath, fileOrDirectory.fullPath);
// Invoke directory and recursive directory watcher for the folder
// Here we arent invoking recursive directory watchers for the base folders
diff --git a/src/lib/es2015.core.d.ts b/src/lib/es2015.core.d.ts
index 0e1b46f2eb0..ccff68968f1 100644
--- a/src/lib/es2015.core.d.ts
+++ b/src/lib/es2015.core.d.ts
@@ -449,7 +449,7 @@ interface String {
/**
* Returns a String value that is made from count copies appended together. If count is 0,
- * T is the empty String is returned.
+ * the empty string is returned.
* @param count number of copies to append
*/
repeat(count: number): string;
diff --git a/src/lib/es2015.symbol.wellknown.d.ts b/src/lib/es2015.symbol.wellknown.d.ts
index 268570ff232..23d836c6515 100644
--- a/src/lib/es2015.symbol.wellknown.d.ts
+++ b/src/lib/es2015.symbol.wellknown.d.ts
@@ -150,7 +150,7 @@ interface Promise {
}
interface PromiseConstructor {
- readonly [Symbol.species]: Function;
+ readonly [Symbol.species]: PromiseConstructor;
}
interface RegExp {
@@ -202,7 +202,7 @@ interface RegExp {
}
interface RegExpConstructor {
- [Symbol.species](): RegExpConstructor;
+ readonly [Symbol.species]: RegExpConstructor;
}
interface String {
@@ -283,3 +283,16 @@ interface Float32Array {
interface Float64Array {
readonly [Symbol.toStringTag]: "Float64Array";
}
+
+interface ArrayConstructor {
+ readonly [Symbol.species]: ArrayConstructor;
+}
+interface MapConstructor {
+ readonly [Symbol.species]: MapConstructor;
+}
+interface SetConstructor {
+ readonly [Symbol.species]: SetConstructor;
+}
+interface ArrayBufferConstructor {
+ readonly [Symbol.species]: ArrayBufferConstructor;
+}
\ No newline at end of file
diff --git a/src/lib/es5.d.ts b/src/lib/es5.d.ts
index fd2ae5b3fdf..aaefeec7d1a 100644
--- a/src/lib/es5.d.ts
+++ b/src/lib/es5.d.ts
@@ -62,6 +62,18 @@ declare function encodeURI(uri: string): string;
*/
declare function encodeURIComponent(uriComponent: string): string;
+/**
+ * Computes a new string in which certain characters have been replaced by a hexadecimal escape sequence.
+ * @param string A string value
+ */
+declare function escape(string: string): string;
+
+/**
+ * Computes a new string in which hexadecimal escape sequences are replaced with the character that it represents.
+ * @param string A string value
+ */
+declare function unescape(string: string): string;
+
interface PropertyDescriptor {
configurable?: boolean;
enumerable?: boolean;
diff --git a/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl
index c59e9c20060..292a20a49bf 100644
--- a/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl
+++ b/src/loc/lcl/chs/diagnosticMessages/diagnosticMessages.generated.json.lcl
@@ -1611,12 +1611,9 @@
- -
+
-
-
-
-
-
+
@@ -3726,6 +3723,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -3957,6 +3972,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -5202,24 +5226,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5247,24 +5253,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5283,6 +5271,30 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5988,6 +6000,24 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -6015,30 +6045,21 @@
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
@@ -6069,33 +6090,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
diff --git a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl
index 3ea6148617a..a55da48f2c2 100644
--- a/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl
+++ b/src/loc/lcl/cht/diagnosticMessages/diagnosticMessages.generated.json.lcl
@@ -1611,12 +1611,9 @@
- -
+
-
-
-
-
-
+
@@ -2241,6 +2238,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -2970,6 +2976,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -3708,6 +3723,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -3939,6 +3972,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -4212,6 +4254,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -5166,24 +5226,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5211,24 +5253,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5247,6 +5271,30 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5952,6 +6000,24 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5979,30 +6045,21 @@
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
@@ -6033,33 +6090,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
diff --git a/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl
index 078b17179a4..3bb9642d207 100644
--- a/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl
+++ b/src/loc/lcl/csy/diagnosticMessages/diagnosticMessages.generated.json.lcl
@@ -1620,12 +1620,9 @@
- -
+
-
-
-
-
-
+
@@ -2250,6 +2247,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -2979,6 +2985,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -3717,6 +3732,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -3948,6 +3981,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -4221,6 +4263,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -5175,24 +5235,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5220,24 +5262,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5256,6 +5280,30 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5961,6 +6009,24 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5988,30 +6054,21 @@
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
@@ -6042,33 +6099,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -8320,7 +8350,7 @@
-
+
diff --git a/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl
index 6c74cb8ca90..d362101e51f 100644
--- a/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl
+++ b/src/loc/lcl/deu/diagnosticMessages/diagnosticMessages.generated.json.lcl
@@ -1605,12 +1605,9 @@
- -
+
-
-
-
-
-
+
@@ -2232,6 +2229,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -2964,6 +2970,9 @@
-
+
+
+
@@ -3702,6 +3711,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -3933,6 +3960,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -4209,12 +4245,18 @@
-
+
+
+
-
+
+
+
@@ -5172,24 +5214,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5217,24 +5241,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5253,6 +5259,30 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5952,6 +5982,24 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5979,30 +6027,21 @@
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
@@ -6033,33 +6072,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
diff --git a/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl
index d96fb42d4ea..58a00519e04 100644
--- a/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl
+++ b/src/loc/lcl/esn/diagnosticMessages/diagnosticMessages.generated.json.lcl
@@ -1620,12 +1620,9 @@
- -
+
-
-
-
-
-
+
@@ -2250,6 +2247,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -2979,6 +2985,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -3717,6 +3732,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -3948,6 +3981,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -4221,6 +4263,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -5175,24 +5235,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5220,24 +5262,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5256,6 +5280,30 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5961,6 +6009,24 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5988,30 +6054,21 @@
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
@@ -6042,33 +6099,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
diff --git a/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl
index 326158fcca0..803d5940ac2 100644
--- a/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl
+++ b/src/loc/lcl/fra/diagnosticMessages/diagnosticMessages.generated.json.lcl
@@ -1620,12 +1620,9 @@
- -
+
-
-
-
-
-
+
@@ -2250,6 +2247,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -2979,6 +2985,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -3717,6 +3732,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -3948,6 +3981,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -4221,6 +4263,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -5175,24 +5235,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5220,24 +5262,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5256,6 +5280,30 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5961,6 +6009,24 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5988,30 +6054,21 @@
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
@@ -6042,33 +6099,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
diff --git a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl
index 31f3bfdefd5..2e603f114b6 100644
--- a/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl
+++ b/src/loc/lcl/ita/diagnosticMessages/diagnosticMessages.generated.json.lcl
@@ -1611,12 +1611,9 @@
- -
+
-
-
-
-
-
+
@@ -3726,6 +3723,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -3957,6 +3972,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -5202,24 +5226,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5247,24 +5253,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5283,6 +5271,30 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5988,6 +6000,24 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -6015,30 +6045,21 @@
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
@@ -6069,33 +6090,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
diff --git a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl
index 34a98237a2a..6ea7ba86fc7 100644
--- a/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl
+++ b/src/loc/lcl/jpn/diagnosticMessages/diagnosticMessages.generated.json.lcl
@@ -1611,12 +1611,9 @@
- -
+
-
-
-
-
-
+
@@ -2241,6 +2238,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -2970,6 +2976,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -3708,6 +3723,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -3939,6 +3972,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -4212,6 +4254,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -5166,24 +5226,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5211,24 +5253,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5247,6 +5271,30 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5952,6 +6000,24 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5979,30 +6045,21 @@
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
@@ -6033,33 +6090,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
diff --git a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl
index 2653d211440..80c5f4e15d2 100644
--- a/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl
+++ b/src/loc/lcl/kor/diagnosticMessages/diagnosticMessages.generated.json.lcl
@@ -1611,12 +1611,9 @@
- -
+
-
-
-
-
-
+
@@ -2241,6 +2238,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -2970,6 +2976,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -3708,6 +3723,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -3939,6 +3972,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -4212,6 +4254,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -5166,24 +5226,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5211,24 +5253,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5247,6 +5271,30 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5952,6 +6000,24 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5979,30 +6045,21 @@
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
@@ -6033,33 +6090,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
diff --git a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl
index 3b132575e58..0badf531a75 100644
--- a/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl
+++ b/src/loc/lcl/plk/diagnosticMessages/diagnosticMessages.generated.json.lcl
@@ -1598,12 +1598,9 @@
- -
+
-
-
-
-
-
+
@@ -2225,6 +2222,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -2954,6 +2960,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -3689,6 +3704,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -3920,6 +3953,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -4193,6 +4235,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -5147,24 +5207,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5192,24 +5234,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5228,6 +5252,30 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5927,6 +5975,24 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5954,30 +6020,21 @@
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
@@ -6008,33 +6065,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
diff --git a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl
index b0897a56d25..7677920dd1d 100644
--- a/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl
+++ b/src/loc/lcl/ptb/diagnosticMessages/diagnosticMessages.generated.json.lcl
@@ -1598,12 +1598,9 @@
- -
+
-
-
-
-
-
+
@@ -2225,6 +2222,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -2954,6 +2960,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -3689,6 +3704,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -3920,6 +3953,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -4193,6 +4235,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -5147,24 +5207,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5192,24 +5234,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5228,6 +5252,30 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5927,6 +5975,24 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5954,30 +6020,21 @@
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
@@ -6008,33 +6065,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
diff --git a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl
index 17236daf66b..b71915fbd67 100644
--- a/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl
+++ b/src/loc/lcl/rus/diagnosticMessages/diagnosticMessages.generated.json.lcl
@@ -1610,12 +1610,9 @@
- -
+
-
-
-
-
-
+
@@ -2240,6 +2237,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -2969,6 +2975,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -3707,6 +3722,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -3938,6 +3971,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -4211,6 +4253,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -5165,24 +5225,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5210,24 +5252,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5246,6 +5270,30 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5951,6 +5999,24 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5978,30 +6044,21 @@
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
@@ -6032,33 +6089,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
diff --git a/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl b/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl
index 34f080a97cc..6c92a1c0bd1 100644
--- a/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl
+++ b/src/loc/lcl/trk/diagnosticMessages/diagnosticMessages.generated.json.lcl
@@ -1604,12 +1604,9 @@
- -
+
-
-
-
-
-
+
@@ -2234,6 +2231,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -2963,6 +2969,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -3701,6 +3716,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -3932,6 +3965,15 @@
+ -
+
+
+
+
+
+
+
+
-
@@ -4205,6 +4247,24 @@
+ -
+
+
+
+
+
+
+
+
+ -
+
+
+
+
+
+
+
+
-
@@ -5159,24 +5219,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5204,24 +5246,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
@@ -5240,6 +5264,30 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5945,6 +5993,24 @@
+ -
+
+
+
+
+
+ -
+
+
+
+
+
+ -
+
+
+
+
+
-
@@ -5972,30 +6038,21 @@
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
- -
+
-
-
-
-
-
+
@@ -6026,33 +6083,6 @@
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
diff --git a/src/server/editorServices.ts b/src/server/editorServices.ts
index 086bb6b38d8..726621a540d 100644
--- a/src/server/editorServices.ts
+++ b/src/server/editorServices.ts
@@ -103,14 +103,14 @@ namespace ts.server {
const compilerOptionConverters = prepareConvertersForEnumLikeCompilerOptions(optionDeclarations);
const indentStyle = createMapFromTemplate({
- "none": IndentStyle.None,
- "block": IndentStyle.Block,
- "smart": IndentStyle.Smart
+ none: IndentStyle.None,
+ block: IndentStyle.Block,
+ smart: IndentStyle.Smart
});
export interface TypesMapFile {
typesMap: SafeList;
- simpleMap: string[];
+ simpleMap: { [libName: string]: string };
}
/**
@@ -134,31 +134,31 @@ namespace ts.server {
const defaultTypeSafeList: SafeList = {
"jquery": {
// jquery files can have names like "jquery-1.10.2.min.js" (or "jquery.intellisense.js")
- "match": /jquery(-(\.?\d+)+)?(\.intellisense)?(\.min)?\.js$/i,
- "types": ["jquery"]
+ match: /jquery(-(\.?\d+)+)?(\.intellisense)?(\.min)?\.js$/i,
+ types: ["jquery"]
},
"WinJS": {
// e.g. c:/temp/UWApp1/lib/winjs-4.0.1/js/base.js
- "match": /^(.*\/winjs-[.\d]+)\/js\/base\.js$/i, // If the winjs/base.js file is found..
- "exclude": [["^", 1, "/.*"]], // ..then exclude all files under the winjs folder
- "types": ["winjs"] // And fetch the @types package for WinJS
+ match: /^(.*\/winjs-[.\d]+)\/js\/base\.js$/i, // If the winjs/base.js file is found..
+ exclude: [["^", 1, "/.*"]], // ..then exclude all files under the winjs folder
+ types: ["winjs"] // And fetch the @types package for WinJS
},
"Kendo": {
// e.g. /Kendo3/wwwroot/lib/kendo/kendo.all.min.js
- "match": /^(.*\/kendo)\/kendo\.all\.min\.js$/i,
- "exclude": [["^", 1, "/.*"]],
- "types": ["kendo-ui"]
+ match: /^(.*\/kendo)\/kendo\.all\.min\.js$/i,
+ exclude: [["^", 1, "/.*"]],
+ types: ["kendo-ui"]
},
"Office Nuget": {
// e.g. /scripts/Office/1/excel-15.debug.js
- "match": /^(.*\/office\/1)\/excel-\d+\.debug\.js$/i, // Office NuGet package is installed under a "1/office" folder
- "exclude": [["^", 1, "/.*"]], // Exclude that whole folder if the file indicated above is found in it
- "types": ["office"] // @types package to fetch instead
+ match: /^(.*\/office\/1)\/excel-\d+\.debug\.js$/i, // Office NuGet package is installed under a "1/office" folder
+ exclude: [["^", 1, "/.*"]], // Exclude that whole folder if the file indicated above is found in it
+ types: ["office"] // @types package to fetch instead
},
"Minified files": {
// e.g. /whatever/blah.min.js
- "match": /^(.+\.min\.js)$/i,
- "exclude": [["^", 1, "$"]]
+ match: /^(.+\.min\.js)$/i,
+ exclude: [["^", 1, "$"]]
}
};
@@ -203,8 +203,10 @@ namespace ts.server {
* This helper function processes a list of projects and return the concatenated, sortd and deduplicated output of processing each project.
*/
export function combineProjectOutput(projects: ReadonlyArray, action: (project: Project) => ReadonlyArray, comparer?: (a: T, b: T) => number, areEqual?: (a: T, b: T) => boolean) {
- const result = flatMap(projects, action).sort(comparer);
- return projects.length > 1 ? deduplicate(result, areEqual) : result;
+ const outputs = flatMap(projects, action);
+ return comparer
+ ? sortAndDeduplicate(outputs, comparer, areEqual)
+ : deduplicate(outputs, areEqual);
}
export interface HostConfiguration {
@@ -378,6 +380,7 @@ namespace ts.server {
private readonly hostConfiguration: HostConfiguration;
private safelist: SafeList = defaultTypeSafeList;
+ private legacySafelist: { [key: string]: string } = {};
private changedFiles: ScriptInfo[];
private pendingProjectUpdates = createMap();
@@ -430,9 +433,12 @@ namespace ts.server {
this.toCanonicalFileName = createGetCanonicalFileName(this.host.useCaseSensitiveFileNames);
this.throttledOperations = new ThrottledOperations(this.host, this.logger);
- if (opts.typesMapLocation) {
+ if (this.typesMapLocation) {
this.loadTypesMap();
}
+ else {
+ this.logger.info("No types map provided; using the default");
+ }
this.typingsInstaller.attach(this);
@@ -522,10 +528,12 @@ namespace ts.server {
}
// raw is now fixed and ready
this.safelist = raw.typesMap;
+ this.legacySafelist = raw.simpleMap;
}
catch (e) {
this.logger.info(`Error loading types map: ${e}`);
this.safelist = defaultTypeSafeList;
+ this.legacySafelist = {};
}
}
@@ -799,17 +807,14 @@ namespace ts.server {
// If the the added or created file or directory is not supported file name, ignore the file
// But when watched directory is added/removed, we need to reload the file list
- if (fileOrDirectoryPath !== directory && !isSupportedSourceFileName(fileOrDirectory, project.getCompilationSettings(), this.hostConfiguration.extraFileExtensions)) {
+ if (fileOrDirectoryPath !== directory && hasExtension(fileOrDirectoryPath) && !isSupportedSourceFileName(fileOrDirectory, project.getCompilationSettings(), this.hostConfiguration.extraFileExtensions)) {
this.logger.info(`Project: ${configFilename} Detected file add/remove of non supported extension: ${fileOrDirectory}`);
return;
}
// Reload is pending, do the reload
- if (!project.pendingReload) {
- const configFileSpecs = project.configFileSpecs;
- const result = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFilename), project.getCompilationSettings(), project.getCachedDirectoryStructureHost(), this.hostConfiguration.extraFileExtensions);
- project.updateErrorOnNoInputFiles(result.fileNames.length !== 0);
- this.updateNonInferredProjectFiles(project, result.fileNames, fileNamePropertyReader);
+ if (project.pendingReload !== ConfigFileProgramReloadLevel.Full) {
+ project.pendingReload = ConfigFileProgramReloadLevel.Partial;
this.delayUpdateProjectGraphAndInferredProjectsRefresh(project);
}
},
@@ -842,7 +847,7 @@ namespace ts.server {
}
else {
this.logConfigFileWatchUpdate(project.getConfigFilePath(), project.canonicalConfigFilePath, configFileExistenceInfo, ConfigFileWatcherStatus.ReloadingInferredRootFiles);
- project.pendingReload = true;
+ project.pendingReload = ConfigFileProgramReloadLevel.Full;
this.delayUpdateProjectGraph(project);
// As we scheduled the update on configured project graph,
// we would need to schedule the project reload for only the root of inferred projects
@@ -1419,7 +1424,7 @@ namespace ts.server {
}
}
- private createExternalProject(projectFileName: string, files: protocol.ExternalFile[], options: protocol.ExternalProjectCompilerOptions, typeAcquisition: TypeAcquisition) {
+ private createExternalProject(projectFileName: string, files: protocol.ExternalFile[], options: protocol.ExternalProjectCompilerOptions, typeAcquisition: TypeAcquisition, excludedFiles: NormalizedPath[]) {
const compilerOptions = convertCompilerOptions(options);
const project = new ExternalProject(
projectFileName,
@@ -1428,6 +1433,7 @@ namespace ts.server {
compilerOptions,
/*languageServiceEnabled*/ !this.exceededTotalSizeLimitForNonTsFiles(projectFileName, compilerOptions, files, externalFilePropertyReader),
options.compileOnSave === undefined ? true : options.compileOnSave);
+ project.excludedFiles = excludedFiles;
this.addFilesToNonInferredProjectAndUpdateGraph(project, files, externalFilePropertyReader, typeAcquisition);
this.externalProjects.push(project);
@@ -1590,6 +1596,19 @@ namespace ts.server {
this.addFilesToNonInferredProjectAndUpdateGraph(project, newUncheckedFiles, propertyReader, newTypeAcquisition);
}
+ /**
+ * Reload the file names from config file specs and update the project graph
+ */
+ /*@internal*/
+ reloadFileNamesOfConfiguredProject(project: ConfiguredProject): boolean {
+ const configFileSpecs = project.configFileSpecs;
+ const configFileName = project.getConfigFilePath();
+ const fileNamesResult = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFileName), project.getCompilationSettings(), project.getCachedDirectoryStructureHost(), this.hostConfiguration.extraFileExtensions);
+ project.updateErrorOnNoInputFiles(fileNamesResult.fileNames.length !== 0);
+ this.updateNonInferredProjectFiles(project, fileNamesResult.fileNames, fileNamePropertyReader);
+ return project.updateGraph();
+ }
+
/**
* Read the config file of the project again and update the project
*/
@@ -1884,7 +1903,7 @@ namespace ts.server {
}
else if (!updatedProjects.has(configFileName)) {
if (delayReload) {
- project.pendingReload = true;
+ project.pendingReload = ConfigFileProgramReloadLevel.Full;
this.delayUpdateProjectGraph(project);
}
else {
@@ -2185,7 +2204,7 @@ namespace ts.server {
const rule = this.safelist[name];
for (const root of normalizedNames) {
if (rule.match.test(root)) {
- this.logger.info(`Excluding files based on rule ${name}`);
+ this.logger.info(`Excluding files based on rule ${name} matching file '${root}'`);
// If the file matches, collect its types packages and exclude rules
if (rule.types) {
@@ -2244,7 +2263,22 @@ namespace ts.server {
excludedFiles.push(normalizedNames[i]);
}
else {
- filesToKeep.push(proj.rootFiles[i]);
+ let exclude = false;
+ if (typeAcquisition && (typeAcquisition.enable || typeAcquisition.enableAutoDiscovery)) {
+ const baseName = getBaseFileName(normalizedNames[i].toLowerCase());
+ if (fileExtensionIs(baseName, "js")) {
+ const inferredTypingName = removeFileExtension(baseName);
+ const cleanedTypingName = removeMinAndVersionNumbers(inferredTypingName);
+ if (this.legacySafelist[cleanedTypingName]) {
+ this.logger.info(`Excluded '${normalizedNames[i]}' because it matched ${cleanedTypingName} from the legacy safelist`);
+ excludedFiles.push(normalizedNames[i]);
+ exclude = true;
+ }
+ }
+ }
+ if (!exclude) {
+ filesToKeep.push(proj.rootFiles[i]);
+ }
}
}
proj.rootFiles = filesToKeep;
@@ -2352,8 +2386,7 @@ namespace ts.server {
else {
// no config files - remove the item from the collection
this.externalProjectToConfiguredProjectMap.delete(proj.projectFileName);
- const newProj = this.createExternalProject(proj.projectFileName, rootFiles, proj.options, proj.typeAcquisition);
- newProj.excludedFiles = excludedFiles;
+ this.createExternalProject(proj.projectFileName, rootFiles, proj.options, proj.typeAcquisition, excludedFiles);
}
if (!suppressRefreshOfInferredProjects) {
this.ensureProjectStructuresUptoDate(/*refreshInferredProjects*/ true);
diff --git a/src/server/project.ts b/src/server/project.ts
index edb1d6730e9..d2526ab2abb 100644
--- a/src/server/project.ts
+++ b/src/server/project.ts
@@ -858,7 +858,8 @@ namespace ts.server {
const scriptInfo = this.projectService.getOrCreateScriptInfoNotOpenedByClient(inserted, this.currentDirectory, this.directoryStructureHost);
scriptInfo.attachToProject(this);
},
- removed => this.detachScriptInfoFromProject(removed)
+ removed => this.detachScriptInfoFromProject(removed),
+ compareStringsCaseSensitive
);
const elapsed = timestamp() - start;
this.writeLog(`Finishing updateGraphWorker: Project: ${this.getProjectName()} structureChanged: ${hasChanges} Elapsed: ${elapsed}ms`);
@@ -1121,7 +1122,7 @@ namespace ts.server {
readonly canonicalConfigFilePath: NormalizedPath;
/* @internal */
- pendingReload: boolean;
+ pendingReload: ConfigFileProgramReloadLevel;
/*@internal*/
configFileSpecs: ConfigFileSpecs;
@@ -1161,12 +1162,17 @@ namespace ts.server {
* @returns: true if set of files in the project stays the same and false - otherwise.
*/
updateGraph(): boolean {
- if (this.pendingReload) {
- this.pendingReload = false;
- this.projectService.reloadConfiguredProject(this);
- return true;
+ const reloadLevel = this.pendingReload;
+ this.pendingReload = ConfigFileProgramReloadLevel.None;
+ switch (reloadLevel) {
+ case ConfigFileProgramReloadLevel.Partial:
+ return this.projectService.reloadFileNamesOfConfiguredProject(this);
+ case ConfigFileProgramReloadLevel.Full:
+ this.projectService.reloadConfiguredProject(this);
+ return true;
+ default:
+ return super.updateGraph();
}
- return super.updateGraph();
}
/*@internal*/
diff --git a/src/server/protocol.ts b/src/server/protocol.ts
index 93d5c69d361..3761049017d 100644
--- a/src/server/protocol.ts
+++ b/src/server/protocol.ts
@@ -16,7 +16,7 @@ namespace ts.server.protocol {
CompletionsFull = "completions-full",
CompletionDetails = "completionEntryDetails",
/* @internal */
- CompletionDetailsFull = "completionEntryDetailsFull",
+ CompletionDetailsFull = "completionEntryDetails-full",
CompileOnSaveAffectedFileList = "compileOnSaveAffectedFileList",
CompileOnSaveEmitFile = "compileOnSaveEmitFile",
Configure = "configure",
@@ -586,6 +586,7 @@ namespace ts.server.protocol {
}
export interface ApplyCodeActionCommandRequestArgs extends FileRequestArgs {
+ /** May also be an array of commands. */
command: {};
}
diff --git a/src/server/server.ts b/src/server/server.ts
index 457be4a9b9a..f4faa0d3c77 100644
--- a/src/server/server.ts
+++ b/src/server/server.ts
@@ -200,7 +200,7 @@ namespace ts.server {
return this.loggingEnabled() && this.level >= level;
}
- msg(s: string, type: Msg.Types = Msg.Err) {
+ msg(s: string, type: Msg = Msg.Err) {
if (!this.canWrite) return;
s = `[${nowString()}] ${s}\n`;
@@ -828,7 +828,7 @@ namespace ts.server {
if (logger.hasLevel(LogLevel.verbose)) {
logger.info(`Starting ${process.execPath} with args:${stringifyIndented(args)}`);
}
- childProcess.execFileSync(process.execPath, args, { stdio: "ignore", env: { "ELECTRON_RUN_AS_NODE": "1" } });
+ childProcess.execFileSync(process.execPath, args, { stdio: "ignore", env: { ELECTRON_RUN_AS_NODE: "1" } });
status = true;
if (logger.hasLevel(LogLevel.verbose)) {
logger.info(`WatchGuard for path ${path} returned: OK`);
diff --git a/src/server/session.ts b/src/server/session.ts
index dc9ddab7ae1..f9a145d16fd 100644
--- a/src/server/session.ts
+++ b/src/server/session.ts
@@ -974,7 +974,7 @@ namespace ts.server {
projects,
project => project.getLanguageService().findReferences(file, position),
/*comparer*/ undefined,
- /*areEqual (TODO: fixme)*/ undefined
+ equateValues
);
}
@@ -1209,7 +1209,7 @@ namespace ts.server {
// Use `hasAction || undefined` to avoid serializing `false`.
return { name, kind, kindModifiers, sortText, replacementSpan: convertedSpan, hasAction: hasAction || undefined, source };
}
- }).sort((a, b) => compareStrings(a.name, b.name));
+ }).sort((a, b) => compareStringsCaseSensitiveUI(a.name, b.name));
}
else {
return completions;
@@ -1571,9 +1571,12 @@ namespace ts.server {
private applyCodeActionCommand(commandName: string, requestSeq: number, args: protocol.ApplyCodeActionCommandRequestArgs): void {
const { file, project } = this.getFileAndProject(args);
const output = (success: boolean, message: string) => this.doOutput({}, commandName, requestSeq, success, message);
- const command = args.command as CodeActionCommand; // They should be sending back the command we sent them.
+ const command = args.command as CodeActionCommand | CodeActionCommand[]; // They should be sending back the command we sent them.
+
project.getLanguageService().applyCodeActionCommand(file, command).then(
- ({ successMessage }) => { output(/*success*/ true, successMessage); },
+ result => {
+ output(/*success*/ true, isArray(result) ? result.map(res => res.successMessage).join(`${this.host.newLine}${this.host.newLine}`) : result.successMessage);
+ },
error => { output(/*success*/ false, error); });
}
@@ -1687,8 +1690,7 @@ namespace ts.server {
return normalizePath(name);
}
- exit() {
- }
+ exit() { /*overridden*/ }
private notRequired(): HandlerResponse {
return { responseRequired: false };
diff --git a/src/server/utilities.ts b/src/server/utilities.ts
index 096d4484154..c57d3b40dee 100644
--- a/src/server/utilities.ts
+++ b/src/server/utilities.ts
@@ -19,20 +19,19 @@ namespace ts.server {
info(s: string): void;
startGroup(): void;
endGroup(): void;
- msg(s: string, type?: Msg.Types): void;
+ msg(s: string, type?: Msg): void;
getLogFileName(): string;
}
+ // TODO: Use a const enum (https://github.com/Microsoft/TypeScript/issues/16804)
+ export enum Msg {
+ Err = "Err",
+ Info = "Info",
+ Perf = "Perf",
+ }
export namespace Msg {
- // tslint:disable variable-name
- export type Err = "Err";
- export const Err: Err = "Err";
- export type Info = "Info";
- export const Info: Info = "Info";
- export type Perf = "Perf";
- export const Perf: Perf = "Perf";
- export type Types = Err | Info | Perf;
- // tslint:enable variable-name
+ /** @deprecated Only here for backwards-compatibility. Prefer just `Msg`. */
+ export type Types = Msg;
}
function getProjectRootPath(project: Project): Path {
@@ -252,7 +251,7 @@ namespace ts.server {
return;
}
- const insertIndex = binarySearch(array, insert, compare);
+ const insertIndex = binarySearch(array, insert, identity, compare);
if (insertIndex < 0) {
array.splice(~insertIndex, 0, insert);
}
@@ -268,7 +267,7 @@ namespace ts.server {
return;
}
- const removeIndex = binarySearch(array, remove, compare);
+ const removeIndex = binarySearch(array, remove, identity, compare);
if (removeIndex >= 0) {
array.splice(removeIndex, 1);
}
@@ -290,8 +289,7 @@ namespace ts.server {
return index === 0 || value !== array[index - 1];
}
- export function enumerateInsertsAndDeletes(newItems: SortedReadonlyArray, oldItems: SortedReadonlyArray, inserted: (newItem: T) => void, deleted: (oldItem: T) => void, compare?: Comparer) {
- compare = compare || compareValues;
+ export function enumerateInsertsAndDeletes(newItems: SortedReadonlyArray, oldItems: SortedReadonlyArray, inserted: (newItem: T) => void, deleted: (oldItem: T) => void, comparer: Comparer) {
let newIndex = 0;
let oldIndex = 0;
const newLen = newItems.length;
@@ -299,7 +297,7 @@ namespace ts.server {
while (newIndex < newLen && oldIndex < oldLen) {
const newItem = newItems[newIndex];
const oldItem = oldItems[oldIndex];
- const compareResult = compare(newItem, oldItem);
+ const compareResult = comparer(newItem, oldItem);
if (compareResult === Comparison.LessThan) {
inserted(newItem);
newIndex++;
diff --git a/src/server/watchGuard/watchGuard.ts b/src/server/watchGuard/watchGuard.ts
index f57369aecb9..8ec248ebb87 100644
--- a/src/server/watchGuard/watchGuard.ts
+++ b/src/server/watchGuard/watchGuard.ts
@@ -14,6 +14,5 @@ try {
const watcher = fs.watch(directoryName, { recursive: true }, () => ({}));
watcher.close();
}
-catch (_e) {
-}
+catch { /*ignore*/ }
process.exit(0);
\ No newline at end of file
diff --git a/src/services/codefixes/fixSpelling.ts b/src/services/codefixes/fixSpelling.ts
index ff3bd455291..2546a92a32f 100644
--- a/src/services/codefixes/fixSpelling.ts
+++ b/src/services/codefixes/fixSpelling.ts
@@ -22,7 +22,9 @@ namespace ts.codefix {
}
else {
const meaning = getMeaningFromLocation(node);
- suggestion = checker.getSuggestionForNonexistentSymbol(node, getTextOfNode(node), convertSemanticMeaningToSymbolFlags(meaning));
+ const name = getTextOfNode(node);
+ Debug.assert(name !== undefined, "name should be defined");
+ suggestion = checker.getSuggestionForNonexistentSymbol(node, name, convertSemanticMeaningToSymbolFlags(meaning));
}
if (suggestion) {
return [{
diff --git a/src/services/codefixes/importFixes.ts b/src/services/codefixes/importFixes.ts
index 3f0d27e5b07..838e19fa35d 100644
--- a/src/services/codefixes/importFixes.ts
+++ b/src/services/codefixes/importFixes.ts
@@ -166,7 +166,7 @@ namespace ts.codefix {
return {
host: context.host,
newLineCharacter: context.newLineCharacter,
- rulesProvider: context.rulesProvider,
+ formatContext: context.formatContext,
sourceFile: context.sourceFile,
checker,
compilerOptions: context.program.getCompilerOptions(),
@@ -181,6 +181,7 @@ namespace ts.codefix {
Named,
Default,
Namespace,
+ Equals
}
export function getCodeActionForImport(moduleSymbol: Symbol, context: ImportCodeFixOptions): ImportCodeAction[] {
@@ -212,7 +213,7 @@ namespace ts.codefix {
function getNamespaceImportName(declaration: AnyImportSyntax): Identifier {
if (declaration.kind === SyntaxKind.ImportDeclaration) {
- const namedBindings = declaration.importClause && declaration.importClause.namedBindings;
+ const namedBindings = declaration.importClause && isImportClause(declaration.importClause) && declaration.importClause.namedBindings;
return namedBindings && namedBindings.kind === SyntaxKind.NamespaceImport ? namedBindings.name : undefined;
}
else {
@@ -237,10 +238,12 @@ namespace ts.codefix {
return parent as ImportDeclaration;
case SyntaxKind.ExternalModuleReference:
return (parent as ExternalModuleReference).parent;
- default:
- Debug.assert(parent.kind === SyntaxKind.ExportDeclaration);
+ case SyntaxKind.ExportDeclaration:
+ case SyntaxKind.CallExpression: // For "require()" calls
// Ignore these, can't add imports to them.
return undefined;
+ default:
+ Debug.fail();
}
}
@@ -249,11 +252,19 @@ namespace ts.codefix {
const lastImportDeclaration = findLast(sourceFile.statements, isAnyImportSyntax);
const moduleSpecifierWithoutQuotes = stripQuotes(moduleSpecifier);
- const importDecl = createImportDeclaration(
- /*decorators*/ undefined,
- /*modifiers*/ undefined,
- createImportClauseOfKind(kind, symbolName),
- createStringLiteralWithQuoteStyle(sourceFile, moduleSpecifierWithoutQuotes));
+ const quotedModuleSpecifier = createStringLiteralWithQuoteStyle(sourceFile, moduleSpecifierWithoutQuotes);
+ const importDecl = kind !== ImportKind.Equals
+ ? createImportDeclaration(
+ /*decorators*/ undefined,
+ /*modifiers*/ undefined,
+ createImportClauseOfKind(kind, symbolName),
+ quotedModuleSpecifier)
+ : createImportEqualsDeclaration(
+ /*decorators*/ undefined,
+ /*modifiers*/ undefined,
+ createIdentifier(symbolName),
+ createExternalModuleReference(quotedModuleSpecifier));
+
const changes = ChangeTracker.with(context, changeTracker => {
if (lastImportDeclaration) {
changeTracker.insertNodeAfter(sourceFile, lastImportDeclaration, importDecl, { suffix: newLineCharacter });
@@ -263,11 +274,17 @@ namespace ts.codefix {
}
});
+ const actionFormat = kind === ImportKind.Equals
+ ? Diagnostics.Import_0_require_1
+ : kind === ImportKind.Namespace
+ ? Diagnostics.Import_Asterisk_as_0_from_1
+ : Diagnostics.Import_0_from_1;
+
// if this file doesn't have any import statements, insert an import statement and then insert a new line
// between the only import statement and user code. Otherwise just insert the statement because chances
// are there are already a new line seperating code and import statements.
return createCodeAction(
- Diagnostics.Import_0_from_1,
+ actionFormat,
[symbolName, moduleSpecifierWithoutQuotes],
changes,
"NewImport",
@@ -282,7 +299,7 @@ namespace ts.codefix {
return literal;
}
- function createImportClauseOfKind(kind: ImportKind, symbolName: string) {
+ function createImportClauseOfKind(kind: ImportKind.Default | ImportKind.Named | ImportKind.Namespace, symbolName: string) {
const id = createIdentifier(symbolName);
switch (kind) {
case ImportKind.Default:
@@ -534,7 +551,7 @@ namespace ts.codefix {
declarations: ReadonlyArray): ImportCodeAction {
const fromExistingImport = firstDefined(declarations, declaration => {
if (declaration.kind === SyntaxKind.ImportDeclaration && declaration.importClause) {
- const changes = tryUpdateExistingImport(ctx, declaration.importClause);
+ const changes = tryUpdateExistingImport(ctx, isImportClause(declaration.importClause) && declaration.importClause || undefined);
if (changes) {
const moduleSpecifierWithoutQuotes = stripQuotes(declaration.moduleSpecifier.getText());
return createCodeAction(
@@ -564,9 +581,10 @@ namespace ts.codefix {
return expression && isStringLiteral(expression) ? expression.text : undefined;
}
- function tryUpdateExistingImport(context: SymbolContext & { kind: ImportKind }, importClause: ImportClause): FileTextChanges[] | undefined {
+ function tryUpdateExistingImport(context: SymbolContext & { kind: ImportKind }, importClause: ImportClause | ImportEqualsDeclaration): FileTextChanges[] | undefined {
const { symbolName, sourceFile, kind } = context;
- const { name, namedBindings } = importClause;
+ const { name } = importClause;
+ const { namedBindings } = importClause.kind !== SyntaxKind.ImportEqualsDeclaration && importClause;
switch (kind) {
case ImportKind.Default:
return name ? undefined : ChangeTracker.with(context, t =>
@@ -592,6 +610,9 @@ namespace ts.codefix {
return namedBindings ? undefined : ChangeTracker.with(context, t =>
t.replaceNode(sourceFile, importClause, createImportClause(name, createNamespaceImport(createIdentifier(symbolName)))));
+ case ImportKind.Equals:
+ return undefined;
+
default:
Debug.assertNever(kind);
}
@@ -627,7 +648,7 @@ namespace ts.codefix {
}
function getActionsForUMDImport(context: ImportCodeFixContext): ImportCodeAction[] {
- const { checker, symbolToken } = context;
+ const { checker, symbolToken, compilerOptions } = context;
const umdSymbol = checker.getSymbolAtLocation(symbolToken);
let symbol: ts.Symbol;
let symbolName: string;
@@ -644,6 +665,20 @@ namespace ts.codefix {
Debug.fail("Either the symbol or the JSX namespace should be a UMD global if we got here");
}
+ const allowSyntheticDefaultImports = getAllowSyntheticDefaultImports(compilerOptions);
+
+ // Import a synthetic `default` if enabled.
+ if (allowSyntheticDefaultImports) {
+ return getCodeActionForImport(symbol, { ...context, symbolName, kind: ImportKind.Default });
+ }
+ const moduleKind = getEmitModuleKind(compilerOptions);
+
+ // When a synthetic `default` is unavailable, use `import..require` if the module kind supports it.
+ if (moduleKind === ModuleKind.AMD || moduleKind === ModuleKind.CommonJS || moduleKind === ModuleKind.UMD) {
+ return getCodeActionForImport(symbol, { ...context, symbolName, kind: ImportKind.Equals });
+ }
+
+ // Fall back to the `import * as ns` style import.
return getCodeActionForImport(symbol, { ...context, symbolName, kind: ImportKind.Namespace });
}
@@ -664,9 +699,10 @@ namespace ts.codefix {
const defaultExport = checker.tryGetMemberInModuleExports("default", moduleSymbol);
if (defaultExport) {
const localSymbol = getLocalSymbolForExportDefault(defaultExport);
- if (localSymbol && localSymbol.escapedName === symbolName && checkSymbolHasMeaning(localSymbol, currentTokenMeaning)) {
+ if ((localSymbol && localSymbol.escapedName === symbolName || moduleSymbolToValidIdentifier(moduleSymbol, context.compilerOptions.target) === symbolName)
+ && checkSymbolHasMeaning(localSymbol || defaultExport, currentTokenMeaning)) {
// check if this symbol is already used
- const symbolId = getUniqueSymbolId(localSymbol, checker);
+ const symbolId = getUniqueSymbolId(localSymbol || defaultExport, checker);
symbolIdActionMap.addActions(symbolId, getCodeActionForImport(moduleSymbol, { ...context, kind: ImportKind.Default }));
}
}
@@ -696,4 +732,35 @@ namespace ts.codefix {
}
}
}
+
+ export function moduleSymbolToValidIdentifier(moduleSymbol: Symbol, target: ScriptTarget): string {
+ return moduleSpecifierToValidIdentifier(removeFileExtension(getBaseFileName(moduleSymbol.name)), target);
+ }
+
+ function moduleSpecifierToValidIdentifier(moduleSpecifier: string, target: ScriptTarget): string {
+ let res = "";
+ let lastCharWasValid = true;
+ const firstCharCode = moduleSpecifier.charCodeAt(0);
+ if (isIdentifierStart(firstCharCode, target)) {
+ res += String.fromCharCode(firstCharCode);
+ }
+ else {
+ lastCharWasValid = false;
+ }
+ for (let i = 1; i < moduleSpecifier.length; i++) {
+ const ch = moduleSpecifier.charCodeAt(i);
+ const isValid = isIdentifierPart(ch, target);
+ if (isValid) {
+ let char = String.fromCharCode(ch);
+ if (!lastCharWasValid) {
+ char = char.toUpperCase();
+ }
+ res += char;
+ }
+ lastCharWasValid = isValid;
+ }
+ // Need `|| "_"` to ensure result isn't empty.
+ const token = stringToToken(res);
+ return token === undefined || !isNonContextualKeyword(token) ? res || "_" : `_${res}`;
+ }
}
diff --git a/src/services/completions.ts b/src/services/completions.ts
index 3c233f4dbe8..6a9af1e1941 100644
--- a/src/services/completions.ts
+++ b/src/services/completions.ts
@@ -39,7 +39,7 @@ namespace ts.Completions {
return getStringLiteralCompletionEntries(sourceFile, position, typeChecker, compilerOptions, host, log);
}
- const completionData = getCompletionData(typeChecker, log, sourceFile, position, allSourceFiles, options);
+ const completionData = getCompletionData(typeChecker, log, sourceFile, position, allSourceFiles, options, compilerOptions.target);
if (!completionData) {
return undefined;
}
@@ -136,12 +136,12 @@ namespace ts.Completions {
typeChecker: TypeChecker,
target: ScriptTarget,
allowStringLiteral: boolean,
- origin: SymbolOriginInfo,
+ origin: SymbolOriginInfo | undefined,
): CompletionEntry | undefined {
// Try to get a valid display name for this symbol, if we could not find one, then ignore it.
// We would like to only show things that can be added after a dot, so for instance numeric properties can
// not be accessed with a dot (a.1 <- invalid)
- const displayName = getCompletionEntryDisplayNameForSymbol(symbol, target, performCharacterChecks, allowStringLiteral);
+ const displayName = getCompletionEntryDisplayNameForSymbol(symbol, target, performCharacterChecks, allowStringLiteral, origin);
if (!displayName) {
return undefined;
}
@@ -381,7 +381,7 @@ namespace ts.Completions {
{ name, source }: CompletionEntryIdentifier,
allSourceFiles: ReadonlyArray,
): { type: "symbol", symbol: Symbol, location: Node, symbolToOriginInfoMap: SymbolOriginInfoMap } | { type: "request", request: Request } | { type: "none" } {
- const completionData = getCompletionData(typeChecker, log, sourceFile, position, allSourceFiles, { includeExternalModuleExports: true });
+ const completionData = getCompletionData(typeChecker, log, sourceFile, position, allSourceFiles, { includeExternalModuleExports: true }, compilerOptions.target);
if (!completionData) {
return { type: "none" };
}
@@ -395,12 +395,18 @@ namespace ts.Completions {
// We don't need to perform character checks here because we're only comparing the
// name against 'entryName' (which is known to be good), not building a new
// completion entry.
- const symbol = find(symbols, s =>
- getCompletionEntryDisplayNameForSymbol(s, compilerOptions.target, /*performCharacterChecks*/ false, allowStringLiteral) === name
- && getSourceFromOrigin(symbolToOriginInfoMap[getSymbolId(s)]) === source);
+ const symbol = find(symbols, s => {
+ const origin = symbolToOriginInfoMap[getSymbolId(s)];
+ return getCompletionEntryDisplayNameForSymbol(s, compilerOptions.target, /*performCharacterChecks*/ false, allowStringLiteral, origin) === name
+ && getSourceFromOrigin(origin) === source;
+ });
return symbol ? { type: "symbol", symbol, location, symbolToOriginInfoMap } : { type: "none" };
}
+ function getSymbolName(symbol: Symbol, origin: SymbolOriginInfo | undefined, target: ScriptTarget): string {
+ return origin && origin.isDefaultExport && symbol.name === "default" ? codefix.moduleSymbolToValidIdentifier(origin.moduleSymbol, target) : symbol.name;
+ }
+
export interface CompletionEntryIdentifier {
name: string;
source?: string;
@@ -415,7 +421,7 @@ namespace ts.Completions {
entryId: CompletionEntryIdentifier,
allSourceFiles: ReadonlyArray,
host: LanguageServiceHost,
- rulesProvider: formatting.RulesProvider,
+ formatContext: formatting.FormatContext,
): CompletionEntryDetails {
const { name, source } = entryId;
// Compute all the completion symbols again.
@@ -436,7 +442,7 @@ namespace ts.Completions {
}
case "symbol": {
const { symbol, location, symbolToOriginInfoMap } = symbolCompletion;
- const codeActions = getCompletionEntryCodeActions(symbolToOriginInfoMap, symbol, typeChecker, host, compilerOptions, sourceFile, rulesProvider);
+ const codeActions = getCompletionEntryCodeActions(symbolToOriginInfoMap, symbol, typeChecker, host, compilerOptions, sourceFile, formatContext);
const kindModifiers = SymbolDisplay.getSymbolModifiers(symbol);
const { displayParts, documentation, symbolKind, tags } = SymbolDisplay.getSymbolDisplayPartsDocumentationAndSymbolKind(typeChecker, symbol, sourceFile, location, location, SemanticMeaning.All);
return { name, kindModifiers, kind: symbolKind, displayParts, documentation, tags, codeActions, source: source === undefined ? undefined : [textPart(source)] };
@@ -467,7 +473,7 @@ namespace ts.Completions {
host: LanguageServiceHost,
compilerOptions: CompilerOptions,
sourceFile: SourceFile,
- rulesProvider: formatting.RulesProvider,
+ formatContext: formatting.FormatContext,
): CodeAction[] | undefined {
const symbolOriginInfo = symbolToOriginInfoMap[getSymbolId(symbol)];
if (!symbolOriginInfo) {
@@ -481,8 +487,8 @@ namespace ts.Completions {
newLineCharacter: host.getNewLine(),
compilerOptions,
sourceFile,
- rulesProvider,
- symbolName: symbol.name,
+ formatContext,
+ symbolName: getSymbolName(symbol, symbolOriginInfo, compilerOptions.target),
getCanonicalFileName: createGetCanonicalFileName(host.useCaseSensitiveFileNames ? host.useCaseSensitiveFileNames() : false),
symbolToken: undefined,
kind: isDefaultExport ? codefix.ImportKind.Default : codefix.ImportKind.Named,
@@ -523,6 +529,7 @@ namespace ts.Completions {
position: number,
allSourceFiles: ReadonlyArray,
options: GetCompletionsAtPositionOptions,
+ target: ScriptTarget,
): CompletionData | undefined {
const isJavaScriptFile = isSourceFileJavaScript(sourceFile);
@@ -921,7 +928,7 @@ namespace ts.Completions {
symbols = typeChecker.getSymbolsInScope(scopeNode, symbolMeanings);
if (options.includeExternalModuleExports) {
- getSymbolsFromOtherSourceFileExports(symbols, previousToken && isIdentifier(previousToken) ? previousToken.text : "");
+ getSymbolsFromOtherSourceFileExports(symbols, previousToken && isIdentifier(previousToken) ? previousToken.text : "", target);
}
filterGlobalCompletion(symbols);
@@ -1003,7 +1010,7 @@ namespace ts.Completions {
}
}
- function getSymbolsFromOtherSourceFileExports(symbols: Symbol[], tokenText: string): void {
+ function getSymbolsFromOtherSourceFileExports(symbols: Symbol[], tokenText: string, target: ScriptTarget): void {
const tokenTextLowerCase = tokenText.toLowerCase();
codefix.forEachExternalModule(typeChecker, allSourceFiles, moduleSymbol => {
@@ -1020,6 +1027,9 @@ namespace ts.Completions {
symbol = localSymbol;
name = localSymbol.name;
}
+ else {
+ name = codefix.moduleSymbolToValidIdentifier(moduleSymbol, target);
+ }
}
if (symbol.declarations && symbol.declarations.some(d => isExportSpecifier(d) && !!d.parent.parent.moduleSpecifier)) {
@@ -1847,8 +1857,8 @@ namespace ts.Completions {
*
* @return undefined if the name is of external module
*/
- function getCompletionEntryDisplayNameForSymbol(symbol: Symbol, target: ScriptTarget, performCharacterChecks: boolean, allowStringLiteral: boolean): string | undefined {
- const name = symbol.name;
+ function getCompletionEntryDisplayNameForSymbol(symbol: Symbol, target: ScriptTarget, performCharacterChecks: boolean, allowStringLiteral: boolean, origin: SymbolOriginInfo | undefined): string | undefined {
+ const name = getSymbolName(symbol, origin, target);
if (!name) return undefined;
// First check of the displayName is not external module; if it is an external module, it is not valid entry
diff --git a/src/services/formatting/formatting.ts b/src/services/formatting/formatting.ts
index 529fdae0545..b8122827491 100644
--- a/src/services/formatting/formatting.ts
+++ b/src/services/formatting/formatting.ts
@@ -1,10 +1,14 @@
-///
-///
-///
-///
+///
+///
+///
+///
/* @internal */
namespace ts.formatting {
+ export interface FormatContext {
+ readonly options: ts.FormatCodeSettings;
+ readonly getRule: ts.formatting.RulesMap;
+ }
export interface TextRangeWithKind extends TextRange {
kind: SyntaxKind;
@@ -67,7 +71,7 @@ namespace ts.formatting {
delta: number;
}
- export function formatOnEnter(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): TextChange[] {
+ export function formatOnEnter(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] {
const line = sourceFile.getLineAndCharacterOfPosition(position).line;
if (line === 0) {
return [];
@@ -93,15 +97,15 @@ namespace ts.formatting {
// end value is exclusive so add 1 to the result
end: endOfFormatSpan + 1
};
- return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnEnter);
+ return formatSpan(span, sourceFile, formatContext, FormattingRequestKind.FormatOnEnter);
}
- export function formatOnSemicolon(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): TextChange[] {
+ export function formatOnSemicolon(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] {
const semicolon = findImmediatelyPrecedingTokenOfKind(position, SyntaxKind.SemicolonToken, sourceFile);
- return formatNodeLines(findOutermostNodeWithinListLevel(semicolon), sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnSemicolon);
+ return formatNodeLines(findOutermostNodeWithinListLevel(semicolon), sourceFile, formatContext, FormattingRequestKind.FormatOnSemicolon);
}
- export function formatOnOpeningCurly(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): TextChange[] {
+ export function formatOnOpeningCurly(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] {
const openingCurly = findImmediatelyPrecedingTokenOfKind(position, SyntaxKind.OpenBraceToken, sourceFile);
if (!openingCurly) {
return [];
@@ -126,29 +130,29 @@ namespace ts.formatting {
end: position
};
- return formatSpan(textRange, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnOpeningCurlyBrace);
+ return formatSpan(textRange, sourceFile, formatContext, FormattingRequestKind.FormatOnOpeningCurlyBrace);
}
- export function formatOnClosingCurly(position: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): TextChange[] {
+ export function formatOnClosingCurly(position: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] {
const precedingToken = findImmediatelyPrecedingTokenOfKind(position, SyntaxKind.CloseBraceToken, sourceFile);
- return formatNodeLines(findOutermostNodeWithinListLevel(precedingToken), sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnClosingCurlyBrace);
+ return formatNodeLines(findOutermostNodeWithinListLevel(precedingToken), sourceFile, formatContext, FormattingRequestKind.FormatOnClosingCurlyBrace);
}
- export function formatDocument(sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): TextChange[] {
+ export function formatDocument(sourceFile: SourceFile, formatContext: FormatContext): TextChange[] {
const span = {
pos: 0,
end: sourceFile.text.length
};
- return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatDocument);
+ return formatSpan(span, sourceFile, formatContext, FormattingRequestKind.FormatDocument);
}
- export function formatSelection(start: number, end: number, sourceFile: SourceFile, rulesProvider: RulesProvider, options: FormatCodeSettings): TextChange[] {
+ export function formatSelection(start: number, end: number, sourceFile: SourceFile, formatContext: FormatContext): TextChange[] {
// format from the beginning of the line
const span = {
pos: getLineStartPositionForPosition(start, sourceFile),
end,
};
- return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatSelection);
+ return formatSpan(span, sourceFile, formatContext, FormattingRequestKind.FormatSelection);
}
/**
@@ -337,7 +341,7 @@ namespace ts.formatting {
}
/* @internal */
- export function formatNodeGivenIndentation(node: Node, sourceFileLike: SourceFileLike, languageVariant: LanguageVariant, initialIndentation: number, delta: number, rulesProvider: RulesProvider): TextChange[] {
+ export function formatNodeGivenIndentation(node: Node, sourceFileLike: SourceFileLike, languageVariant: LanguageVariant, initialIndentation: number, delta: number, formatContext: FormatContext): TextChange[] {
const range = { pos: 0, end: sourceFileLike.text.length };
return getFormattingScanner(sourceFileLike.text, languageVariant, range.pos, range.end, scanner => formatSpanWorker(
range,
@@ -345,14 +349,13 @@ namespace ts.formatting {
initialIndentation,
delta,
scanner,
- rulesProvider.getFormatOptions(),
- rulesProvider,
+ formatContext,
FormattingRequestKind.FormatSelection,
_ => false, // assume that node does not have any errors
sourceFileLike));
}
- function formatNodeLines(node: Node, sourceFile: SourceFile, options: FormatCodeSettings, rulesProvider: RulesProvider, requestKind: FormattingRequestKind): TextChange[] {
+ function formatNodeLines(node: Node, sourceFile: SourceFile, formatContext: FormatContext, requestKind: FormattingRequestKind): TextChange[] {
if (!node) {
return [];
}
@@ -362,24 +365,19 @@ namespace ts.formatting {
end: node.end
};
- return formatSpan(span, sourceFile, options, rulesProvider, requestKind);
+ return formatSpan(span, sourceFile, formatContext, requestKind);
}
- function formatSpan(originalRange: TextRange,
- sourceFile: SourceFile,
- options: FormatCodeSettings,
- rulesProvider: RulesProvider,
- requestKind: FormattingRequestKind): TextChange[] {
+ function formatSpan(originalRange: TextRange, sourceFile: SourceFile, formatContext: FormatContext, requestKind: FormattingRequestKind): TextChange[] {
// find the smallest node that fully wraps the range and compute the initial indentation for the node
const enclosingNode = findEnclosingNode(originalRange, sourceFile);
return getFormattingScanner(sourceFile.text, sourceFile.languageVariant, getScanStartPosition(enclosingNode, originalRange, sourceFile), originalRange.end, scanner => formatSpanWorker(
originalRange,
enclosingNode,
- SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, options),
- getOwnOrInheritedDelta(enclosingNode, options, sourceFile),
+ SmartIndenter.getIndentationForNode(enclosingNode, originalRange, sourceFile, formatContext.options),
+ getOwnOrInheritedDelta(enclosingNode, formatContext.options, sourceFile),
scanner,
- options,
- rulesProvider,
+ formatContext,
requestKind,
prepareRangeContainsErrorFunction(sourceFile.parseDiagnostics, originalRange),
sourceFile));
@@ -390,8 +388,7 @@ namespace ts.formatting {
initialIndentation: number,
delta: number,
formattingScanner: FormattingScanner,
- options: FormatCodeSettings,
- rulesProvider: RulesProvider,
+ { options, getRule }: FormatContext,
requestKind: FormattingRequestKind,
rangeContainsError: (r: TextRange) => boolean,
sourceFile: SourceFileLike): TextChange[] {
@@ -917,14 +914,14 @@ namespace ts.formatting {
formattingContext.updateContext(previousItem, previousParent, currentItem, currentParent, contextNode);
- const rule = rulesProvider.getRulesMap().GetRule(formattingContext);
+ const rule = getRule(formattingContext);
let trimTrailingWhitespaces: boolean;
let lineAdded: boolean;
if (rule) {
applyRuleEdits(rule, previousItem, previousStartLine, currentItem, currentStartLine);
- if (rule.operation.action & (RuleAction.Space | RuleAction.Delete) && currentStartLine !== previousStartLine) {
+ if (rule.action & (RuleAction.Space | RuleAction.Delete) && currentStartLine !== previousStartLine) {
lineAdded = false;
// Handle the case where the next line is moved to be the end of this line.
// In this case we don't indent the next line in the next pass.
@@ -932,7 +929,7 @@ namespace ts.formatting {
dynamicIndentation.recomputeIndentation(/*lineAddedByFormatting*/ false);
}
}
- else if (rule.operation.action & RuleAction.NewLine && currentStartLine === previousStartLine) {
+ else if (rule.action & RuleAction.NewLine && currentStartLine === previousStartLine) {
lineAdded = true;
// Handle the case where token2 is moved to the new line.
// In this case we indent token2 in the next pass but we set
@@ -943,7 +940,7 @@ namespace ts.formatting {
}
// We need to trim trailing whitespace between the tokens if they were on different lines, and no rule was applied to put them on the same line
- trimTrailingWhitespaces = !(rule.operation.action & RuleAction.Delete) && rule.flag !== RuleFlags.CanDeleteNewLines;
+ trimTrailingWhitespaces = !(rule.action & RuleAction.Delete) && rule.flags !== RuleFlags.CanDeleteNewLines;
}
else {
trimTrailingWhitespaces = true;
@@ -1118,7 +1115,7 @@ namespace ts.formatting {
currentRange: TextRangeWithKind,
currentStartLine: number): void {
- switch (rule.operation.action) {
+ switch (rule.action) {
case RuleAction.Ignore:
// no action required
return;
@@ -1132,7 +1129,7 @@ namespace ts.formatting {
// exit early if we on different lines and rule cannot change number of newlines
// if line1 and line2 are on subsequent lines then no edits are required - ok to exit
// if line1 and line2 are separated with more than one newline - ok to exit since we cannot delete extra new lines
- if (rule.flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) {
+ if (rule.flags !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) {
return;
}
@@ -1144,7 +1141,7 @@ namespace ts.formatting {
break;
case RuleAction.Space:
// exit early if we on different lines and rule cannot change number of newlines
- if (rule.flag !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) {
+ if (rule.flags !== RuleFlags.CanDeleteNewLines && previousStartLine !== currentStartLine) {
return;
}
diff --git a/src/services/formatting/formattingContext.ts b/src/services/formatting/formattingContext.ts
index 043df72f434..2ba987e4af3 100644
--- a/src/services/formatting/formattingContext.ts
+++ b/src/services/formatting/formattingContext.ts
@@ -1,7 +1,14 @@
-///
-
/* @internal */
namespace ts.formatting {
+ export const enum FormattingRequestKind {
+ FormatDocument,
+ FormatSelection,
+ FormatOnEnter,
+ FormatOnSemicolon,
+ FormatOnOpeningCurlyBrace,
+ FormatOnClosingCurlyBrace
+ }
+
export class FormattingContext {
public currentTokenSpan: TextRangeWithKind;
public nextTokenSpan: TextRangeWithKind;
diff --git a/src/services/formatting/formattingRequestKind.ts b/src/services/formatting/formattingRequestKind.ts
deleted file mode 100644
index 6c671e1b888..00000000000
--- a/src/services/formatting/formattingRequestKind.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-///
-
-/* @internal */
-namespace ts.formatting {
- export const enum FormattingRequestKind {
- FormatDocument,
- FormatSelection,
- FormatOnEnter,
- FormatOnSemicolon,
- FormatOnOpeningCurlyBrace,
- FormatOnClosingCurlyBrace
- }
-}
\ No newline at end of file
diff --git a/src/services/formatting/references.ts b/src/services/formatting/references.ts
deleted file mode 100644
index 318f10c664e..00000000000
--- a/src/services/formatting/references.ts
+++ /dev/null
@@ -1,12 +0,0 @@
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
-///
\ No newline at end of file
diff --git a/src/services/formatting/rule.ts b/src/services/formatting/rule.ts
index 8fd432586b4..aa1bb6b43e9 100644
--- a/src/services/formatting/rule.ts
+++ b/src/services/formatting/rule.ts
@@ -1,14 +1,30 @@
-///
-
/* @internal */
namespace ts.formatting {
- export class Rule {
+ export interface Rule {
// Used for debugging to identify each rule based on the property name it's assigned to.
- public debugName?: string;
- constructor(
- readonly descriptor: RuleDescriptor,
- readonly operation: RuleOperation,
- readonly flag: RuleFlags = RuleFlags.None) {
- }
+ readonly debugName: string;
+ readonly context: ReadonlyArray;
+ readonly action: RuleAction;
+ readonly flags: RuleFlags;
+ }
+
+ export type ContextPredicate = (context: FormattingContext) => boolean;
+ export const anyContext: ReadonlyArray = emptyArray;
+
+ export const enum RuleAction {
+ Ignore = 1 << 0,
+ Space = 1 << 1,
+ NewLine = 1 << 2,
+ Delete = 1 << 3,
+ }
+
+ export const enum RuleFlags {
+ None,
+ CanDeleteNewLines,
+ }
+
+ export interface TokenRange {
+ readonly tokens: ReadonlyArray;
+ readonly isSpecific: boolean;
}
}
\ No newline at end of file
diff --git a/src/services/formatting/ruleAction.ts b/src/services/formatting/ruleAction.ts
deleted file mode 100644
index 13e9043e1c6..00000000000
--- a/src/services/formatting/ruleAction.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-///
-
-/* @internal */
-namespace ts.formatting {
- export const enum RuleAction {
- Ignore = 0x00000001,
- Space = 0x00000002,
- NewLine = 0x00000004,
- Delete = 0x00000008
- }
-}
\ No newline at end of file
diff --git a/src/services/formatting/ruleDescriptor.ts b/src/services/formatting/ruleDescriptor.ts
deleted file mode 100644
index b8529496956..00000000000
--- a/src/services/formatting/ruleDescriptor.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-///
-
-/* @internal */
-namespace ts.formatting {
- export class RuleDescriptor {
- constructor(public leftTokenRange: Shared.TokenRange, public rightTokenRange: Shared.TokenRange) {
- }
-
- public toString(): string {
- return "[leftRange=" + this.leftTokenRange + "," +
- "rightRange=" + this.rightTokenRange + "]";
- }
-
- static create1(left: SyntaxKind, right: SyntaxKind): RuleDescriptor {
- return RuleDescriptor.create4(Shared.TokenRange.FromToken(left), Shared.TokenRange.FromToken(right));
- }
-
- static create2(left: Shared.TokenRange, right: SyntaxKind): RuleDescriptor {
- return RuleDescriptor.create4(left, Shared.TokenRange.FromToken(right));
- }
-
- static create3(left: SyntaxKind, right: Shared.TokenRange): RuleDescriptor {
- return RuleDescriptor.create4(Shared.TokenRange.FromToken(left), right);
- }
-
- static create4(left: Shared.TokenRange, right: Shared.TokenRange): RuleDescriptor {
- return new RuleDescriptor(left, right);
- }
- }
-}
\ No newline at end of file
diff --git a/src/services/formatting/ruleFlag.ts b/src/services/formatting/ruleFlag.ts
deleted file mode 100644
index 7619f232ad4..00000000000
--- a/src/services/formatting/ruleFlag.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-///
-
-
-/* @internal */
-namespace ts.formatting {
- export const enum RuleFlags {
- None,
- CanDeleteNewLines
- }
-}
\ No newline at end of file
diff --git a/src/services/formatting/ruleOperation.ts b/src/services/formatting/ruleOperation.ts
deleted file mode 100644
index 462c27352d8..00000000000
--- a/src/services/formatting/ruleOperation.ts
+++ /dev/null
@@ -1,21 +0,0 @@
-///
-
-/* @internal */
-namespace ts.formatting {
- export class RuleOperation {
- constructor(readonly context: RuleOperationContext, readonly action: RuleAction) {}
-
- public toString(): string {
- return "[context=" + this.context + "," +
- "action=" + this.action + "]";
- }
-
- static create1(action: RuleAction) {
- return RuleOperation.create2(RuleOperationContext.any, action);
- }
-
- static create2(context: RuleOperationContext, action: RuleAction) {
- return new RuleOperation(context, action);
- }
- }
-}
\ No newline at end of file
diff --git a/src/services/formatting/ruleOperationContext.ts b/src/services/formatting/ruleOperationContext.ts
deleted file mode 100644
index c433d106372..00000000000
--- a/src/services/formatting/ruleOperationContext.ts
+++ /dev/null
@@ -1,32 +0,0 @@
-///
-
-/* @internal */
-namespace ts.formatting {
-
- export class RuleOperationContext {
- private readonly customContextChecks: ((context: FormattingContext) => boolean)[];
-
- constructor(...funcs: ((context: FormattingContext) => boolean)[]) {
- this.customContextChecks = funcs;
- }
-
- static readonly any: RuleOperationContext = new RuleOperationContext();
-
- public IsAny(): boolean {
- return this === RuleOperationContext.any;
- }
-
- public InContext(context: FormattingContext): boolean {
- if (this.IsAny()) {
- return true;
- }
-
- for (const check of this.customContextChecks) {
- if (!check(context)) {
- return false;
- }
- }
- return true;
- }
- }
-}
\ No newline at end of file
diff --git a/src/services/formatting/rules.ts b/src/services/formatting/rules.ts
index c5b59e818eb..8214ffd6f2d 100644
--- a/src/services/formatting/rules.ts
+++ b/src/services/formatting/rules.ts
@@ -1,929 +1,723 @@
-///
-
/* @internal */
namespace ts.formatting {
- // tslint:disable variable-name (TODO)
- export class Rules {
- public IgnoreBeforeComment: Rule;
- public IgnoreAfterLineComment: Rule;
+ export interface RuleSpec {
+ readonly leftTokenRange: TokenRange;
+ readonly rightTokenRange: TokenRange;
+ readonly rule: Rule;
+ }
- // Space after keyword but not before ; or : or ?
- public NoSpaceBeforeSemicolon: Rule;
- public NoSpaceBeforeColon: Rule;
- public NoSpaceBeforeQuestionMark: Rule;
- public SpaceAfterColon: Rule;
- // insert space after '?' only when it is used in conditional operator
- public SpaceAfterQuestionMarkInConditionalOperator: Rule;
- // in other cases there should be no space between '?' and next token
- public NoSpaceAfterQuestionMark: Rule;
+ export function getAllRules(): RuleSpec[] {
+ const allTokens: SyntaxKind[] = [];
+ for (let token = SyntaxKind.FirstToken; token <= SyntaxKind.LastToken; token++) {
+ allTokens.push(token);
+ }
+ function anyTokenExcept(token: SyntaxKind): TokenRange {
+ return { tokens: allTokens.filter(t => t !== token), isSpecific: false };
+ }
- public SpaceAfterSemicolon: Rule;
+ const anyToken: TokenRange = { tokens: allTokens, isSpecific: false };
+ const anyTokenIncludingMultilineComments = tokenRangeFrom([...allTokens, SyntaxKind.MultiLineCommentTrivia]);
+ const keywords = tokenRangeFromRange(SyntaxKind.FirstKeyword, SyntaxKind.LastKeyword);
+ const binaryOperators = tokenRangeFromRange(SyntaxKind.FirstBinaryOperator, SyntaxKind.LastBinaryOperator);
+ const binaryKeywordOperators = [SyntaxKind.InKeyword, SyntaxKind.InstanceOfKeyword, SyntaxKind.OfKeyword, SyntaxKind.AsKeyword, SyntaxKind.IsKeyword];
+ const unaryPrefixOperators = [SyntaxKind.PlusPlusToken, SyntaxKind.MinusMinusToken, SyntaxKind.TildeToken, SyntaxKind.ExclamationToken];
+ const unaryPrefixExpressions = [
+ SyntaxKind.NumericLiteral, SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken,
+ SyntaxKind.OpenBraceToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword];
+ const unaryPreincrementExpressions = [SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword];
+ const unaryPostincrementExpressions = [SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword];
+ const unaryPredecrementExpressions = [SyntaxKind.Identifier, SyntaxKind.OpenParenToken, SyntaxKind.ThisKeyword, SyntaxKind.NewKeyword];
+ const unaryPostdecrementExpressions = [SyntaxKind.Identifier, SyntaxKind.CloseParenToken, SyntaxKind.CloseBracketToken, SyntaxKind.NewKeyword];
+ const comments = [SyntaxKind.SingleLineCommentTrivia, SyntaxKind.MultiLineCommentTrivia];
+ const typeNames = [SyntaxKind.Identifier, ...typeKeywords];
- // Space/new line after }.
- public SpaceAfterCloseBrace: Rule;
-
- // Special case for (}, else) and (}, while) since else & while tokens are not part of the tree which makes SpaceAfterCloseBrace rule not applied
- // Also should not apply to })
- public SpaceBetweenCloseBraceAndElse: Rule;
- public SpaceBetweenCloseBraceAndWhile: Rule;
- public NoSpaceAfterCloseBrace: Rule;
-
- // No space for dot
- public NoSpaceBeforeDot: Rule;
- public NoSpaceAfterDot: Rule;
-
- // No space before and after indexer
- public NoSpaceBeforeOpenBracket: Rule;
- public NoSpaceAfterCloseBracket: Rule;
-
- // Insert a space after { and before } in single-line contexts, but remove space from empty object literals {}.
- public SpaceAfterOpenBrace: Rule;
- public SpaceBeforeCloseBrace: Rule;
- public NoSpaceAfterOpenBrace: Rule;
- public NoSpaceBeforeCloseBrace: Rule;
- public NoSpaceBetweenEmptyBraceBrackets: Rule;
-
- // Insert new line after { and before } in multi-line contexts.
- public NewLineAfterOpenBraceInBlockContext: Rule;
-
- // For functions and control block place } on a new line [multi-line rule]
- public NewLineBeforeCloseBraceInBlockContext: Rule;
-
- // Special handling of unary operators.
- // Prefix operators generally shouldn't have a space between
- // them and their target unary expression.
- public NoSpaceAfterUnaryPrefixOperator: Rule;
- public NoSpaceAfterUnaryPreincrementOperator: Rule;
- public NoSpaceAfterUnaryPredecrementOperator: Rule;
- public NoSpaceBeforeUnaryPostincrementOperator: Rule;
- public NoSpaceBeforeUnaryPostdecrementOperator: Rule;
-
- // More unary operator special-casing.
- // DevDiv 181814: Be careful when removing leading whitespace
- // around unary operators. Examples:
- // 1 - -2 --X--> 1--2
- // a + ++b --X--> a+++b
- public SpaceAfterPostincrementWhenFollowedByAdd: Rule;
- public SpaceAfterAddWhenFollowedByUnaryPlus: Rule;
- public SpaceAfterAddWhenFollowedByPreincrement: Rule;
- public SpaceAfterPostdecrementWhenFollowedBySubtract: Rule;
- public SpaceAfterSubtractWhenFollowedByUnaryMinus: Rule;
- public SpaceAfterSubtractWhenFollowedByPredecrement: Rule;
-
- public NoSpaceBeforeComma: Rule;
-
- public SpaceAfterCertainKeywords: Rule;
- public NoSpaceAfterNewKeywordOnConstructorSignature: Rule;
- public SpaceAfterLetConstInVariableDeclaration: Rule;
- public NoSpaceBeforeOpenParenInFuncCall: Rule;
- public SpaceAfterFunctionInFuncDecl: Rule;
- public SpaceBeforeOpenParenInFuncDecl: Rule;
- public NoSpaceBeforeOpenParenInFuncDecl: Rule;
- public SpaceAfterVoidOperator: Rule;
-
- public NoSpaceBetweenReturnAndSemicolon: Rule;
-
- // 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]
- public SpaceBetweenStatements: Rule;
-
- // This low-pri rule takes care of "try {" and "finally {" in case the rule SpaceBeforeOpenBraceInControl didn't execute on FormatOnEnter.
- public SpaceAfterTryFinally: Rule;
-
- // For get/set members, we check for (identifier,identifier) since get/set don't have tokens and they are represented as just an identifier token.
- // Though, we do extra check on the context to make sure we are dealing with get/set node. Example:
- // get x() {}
- // set x(val) {}
- public SpaceAfterGetSetInMember: Rule;
-
- // Special case for binary operators (that are keywords). For these we have to add a space and shouldn't follow any user options.
- public SpaceBeforeBinaryKeywordOperator: Rule;
- public SpaceAfterBinaryKeywordOperator: Rule;
-
- // TypeScript-specific rules
-
- // Treat constructor as an identifier in a function declaration, and remove spaces between constructor and following left parentheses
- public SpaceAfterConstructor: Rule;
- public NoSpaceAfterConstructor: Rule;
-
- // Use of module as a function call. e.g.: import m2 = module("m2");
- public NoSpaceAfterModuleImport: Rule;
-
- // Add a space around certain TypeScript keywords
- public SpaceAfterCertainTypeScriptKeywords: Rule;
- public SpaceBeforeCertainTypeScriptKeywords: Rule;
-
- // Treat string literals in module names as identifiers, and add a space between the literal and the opening Brace braces, e.g.: module "m2" {
- public SpaceAfterModuleName: Rule;
-
- // Lambda expressions
- public SpaceBeforeArrow: Rule;
- public SpaceAfterArrow: Rule;
-
- // Optional parameters and let args
- public NoSpaceAfterEllipsis: Rule;
- public NoSpaceAfterOptionalParameters: Rule;
-
- // generics
- public NoSpaceBeforeOpenAngularBracket: Rule;
- public NoSpaceBetweenCloseParenAndAngularBracket: Rule;
- public NoSpaceAfterOpenAngularBracket: Rule;
- public NoSpaceBeforeCloseAngularBracket: Rule;
- public NoSpaceAfterCloseAngularBracket: Rule;
-
- // Remove spaces in empty interface literals. e.g.: x: {}
- public NoSpaceBetweenEmptyInterfaceBraceBrackets: Rule;
-
- // These rules are higher in priority than user-configurable rules.
- public HighPriorityCommonRules: Rule[];
-
- // These rules are applied after high priority rules.
- public UserConfigurableRules: Rule[];
-
- // These rules are lower in priority than user-configurable rules.
- public LowPriorityCommonRules: Rule[];
-
- ///
- /// Rules controlled by user options
- ///
-
- // Insert space after comma delimiter
- public SpaceAfterComma: Rule;
- public NoSpaceAfterComma: Rule;
-
- // Insert space before and after binary operators
- public SpaceBeforeBinaryOperator: Rule;
- public SpaceAfterBinaryOperator: Rule;
- public NoSpaceBeforeBinaryOperator: Rule;
- public NoSpaceAfterBinaryOperator: Rule;
-
- // Insert space after keywords in control flow statements
- public SpaceAfterKeywordInControl: Rule;
- public NoSpaceAfterKeywordInControl: Rule;
-
- // Open Brace braces after function
+ // Place a space before open brace in a function declaration
// TypeScript: Function can have return types, which can be made of tons of different token kinds
- public FunctionOpenBraceLeftTokenRange: Shared.TokenRange;
- public SpaceBeforeOpenBraceInFunction: Rule;
- public NewLineBeforeOpenBraceInFunction: Rule;
+ const functionOpenBraceLeftTokenRange = anyTokenIncludingMultilineComments;
- // Open Brace braces after TypeScript module/class/interface
- public TypeScriptOpenBraceLeftTokenRange: Shared.TokenRange;
- public SpaceBeforeOpenBraceInTypeScriptDeclWithBlock: Rule;
- public NewLineBeforeOpenBraceInTypeScriptDeclWithBlock: Rule;
+ // Place a space before open brace in a TypeScript declaration that has braces as children (class, module, enum, etc)
+ const typeScriptOpenBraceLeftTokenRange = tokenRangeFrom([SyntaxKind.Identifier, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.ClassKeyword, SyntaxKind.ExportKeyword, SyntaxKind.ImportKeyword]);
- // Open Brace braces after control block
- public ControlOpenBraceLeftTokenRange: Shared.TokenRange;
- public SpaceBeforeOpenBraceInControl: Rule;
- public NewLineBeforeOpenBraceInControl: Rule;
-
- // Insert space after semicolon in for statement
- public SpaceAfterSemicolonInFor: Rule;
- public NoSpaceAfterSemicolonInFor: Rule;
-
- // Insert space after opening and before closing nonempty parenthesis
- public SpaceAfterOpenParen: Rule;
- public SpaceBeforeCloseParen: Rule;
- public SpaceBetweenOpenParens: Rule;
- public NoSpaceBetweenParens: Rule;
- public NoSpaceAfterOpenParen: Rule;
- public NoSpaceBeforeCloseParen: Rule;
-
- // Insert space after opening and before closing nonempty brackets
- public SpaceAfterOpenBracket: Rule;
- public SpaceBeforeCloseBracket: Rule;
- public NoSpaceBetweenBrackets: Rule;
- public NoSpaceAfterOpenBracket: Rule;
- public NoSpaceBeforeCloseBracket: Rule;
-
- // Insert space after function keyword for anonymous functions
- public SpaceAfterAnonymousFunctionKeyword: Rule;
- public NoSpaceAfterAnonymousFunctionKeyword: Rule;
-
- // Insert space after @ in decorator
- public SpaceBeforeAt: Rule;
- public NoSpaceAfterAt: Rule;
- public SpaceAfterDecorator: Rule;
-
- // Generator: function*
- public NoSpaceBetweenFunctionKeywordAndStar: Rule;
- public SpaceAfterStarInGeneratorDeclaration: Rule;
- public NoSpaceBetweenYieldKeywordAndStar: Rule;
- public SpaceBetweenYieldOrYieldStarAndOperand: Rule;
-
- // Async functions
- public SpaceBetweenAsyncAndOpenParen: Rule;
- public SpaceBetweenAsyncAndFunctionKeyword: Rule;
-
- // Template strings
- public NoSpaceBetweenTagAndTemplateString: Rule;
- public NoSpaceAfterTemplateHeadAndMiddle: Rule;
- public SpaceAfterTemplateHeadAndMiddle: Rule;
- 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;
-
- // JSX opening elements
- public SpaceBeforeJsxAttribute: Rule;
- public SpaceBeforeSlashInJsxOpeningElement: Rule;
- public NoSpaceBeforeGreaterThanTokenInJsxOpeningElement: Rule;
- public NoSpaceBeforeEqualInJsxAttribute: Rule;
- public NoSpaceAfterEqualInJsxAttribute: Rule;
-
- // No space after type assertions
- public NoSpaceAfterTypeAssertion: Rule;
- public SpaceAfterTypeAssertion: Rule;
-
- // No space before non-null assertion operator
- public NoSpaceBeforeNonNullAssertionOperator: Rule;
-
- constructor() {
- ///
- /// Common Rules
- ///
+ // Place a space before open brace in a control flow construct
+ const controlOpenBraceLeftTokenRange = tokenRangeFrom([SyntaxKind.CloseParenToken, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.DoKeyword, SyntaxKind.TryKeyword, SyntaxKind.FinallyKeyword, SyntaxKind.ElseKeyword]);
+ // These rules are higher in priority than user-configurable
+ const highPriorityCommonRules = [
// Leave comments alone
- this.IgnoreBeforeComment = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.Comments), RuleOperation.create1(RuleAction.Ignore));
- this.IgnoreAfterLineComment = new Rule(RuleDescriptor.create3(SyntaxKind.SingleLineCommentTrivia, Shared.TokenRange.Any), RuleOperation.create1(RuleAction.Ignore));
+ rule("IgnoreBeforeComment", anyToken, comments, anyContext, RuleAction.Ignore),
+ rule("IgnoreAfterLineComment", SyntaxKind.SingleLineCommentTrivia, anyToken, anyContext, RuleAction.Ignore),
- // Space after keyword but not before ; or : or ?
- this.NoSpaceBeforeSemicolon = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.SemicolonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.NoSpaceBeforeColon = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.ColonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete));
- this.NoSpaceBeforeQuestionMark = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.QuestionToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete));
- this.SpaceAfterColon = new Rule(RuleDescriptor.create3(SyntaxKind.ColonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Space));
- this.SpaceAfterQuestionMarkInConditionalOperator = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsConditionalOperatorContext), RuleAction.Space));
- this.NoSpaceAfterQuestionMark = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.SpaceAfterSemicolon = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
+ rule("NoSpaceBeforeColon", anyToken, SyntaxKind.ColonToken, [isNonJsxSameLineTokenContext, isNotBinaryOpContext], RuleAction.Delete),
+ rule("SpaceAfterColon", SyntaxKind.ColonToken, anyToken, [isNonJsxSameLineTokenContext, isNotBinaryOpContext], RuleAction.Space),
+ rule("NoSpaceBeforeQuestionMark", anyToken, SyntaxKind.QuestionToken, [isNonJsxSameLineTokenContext, isNotBinaryOpContext], RuleAction.Delete),
+ // insert space after '?' only when it is used in conditional operator
+ rule("SpaceAfterQuestionMarkInConditionalOperator", SyntaxKind.QuestionToken, anyToken, [isNonJsxSameLineTokenContext, isConditionalOperatorContext], RuleAction.Space),
- // Space after }.
- this.SpaceAfterCloseBrace = new Rule(RuleDescriptor.create3(SyntaxKind.CloseBraceToken, Shared.TokenRange.FromRange(SyntaxKind.FirstToken, SyntaxKind.LastToken, [SyntaxKind.CloseParenToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsAfterCodeBlockContext), RuleAction.Space));
+ // in other cases there should be no space between '?' and next token
+ rule("NoSpaceAfterQuestionMark", SyntaxKind.QuestionToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.Delete),
- // Special case for (}, else) and (}, while) since else & while tokens are not part of the tree which makes SpaceAfterCloseBrace rule not applied
- this.SpaceBetweenCloseBraceAndElse = new Rule(RuleDescriptor.create1(SyntaxKind.CloseBraceToken, SyntaxKind.ElseKeyword), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
- this.SpaceBetweenCloseBraceAndWhile = new Rule(RuleDescriptor.create1(SyntaxKind.CloseBraceToken, SyntaxKind.WhileKeyword), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
- this.NoSpaceAfterCloseBrace = new Rule(RuleDescriptor.create3(SyntaxKind.CloseBraceToken, Shared.TokenRange.FromTokens([SyntaxKind.CloseBracketToken, SyntaxKind.CommaToken, SyntaxKind.SemicolonToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
-
- // No space for dot
- this.NoSpaceBeforeDot = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.DotToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.NoSpaceAfterDot = new Rule(RuleDescriptor.create3(SyntaxKind.DotToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
-
- // No space before and after indexer
- this.NoSpaceBeforeOpenBracket = new Rule(
- RuleDescriptor.create2(Shared.TokenRange.AnyExcept(SyntaxKind.AsyncKeyword), SyntaxKind.OpenBracketToken),
- RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.NoSpaceAfterCloseBracket = new Rule(RuleDescriptor.create3(SyntaxKind.CloseBracketToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNotBeforeBlockInFunctionDeclarationContext), RuleAction.Delete));
-
- // Place a space before open brace in a function declaration
- this.FunctionOpenBraceLeftTokenRange = Shared.TokenRange.AnyIncludingMultilineComments;
- this.SpaceBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForFunctions"), Rules.IsFunctionDeclContext, Rules.IsBeforeBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeBlockContext), 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, SyntaxKind.ExportKeyword, SyntaxKind.ImportKeyword]);
- this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForFunctions"), Rules.IsTypeScriptDeclWithBlockContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);
-
- // Place a space before open brace in a control flow construct
- this.ControlOpenBraceLeftTokenRange = Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.MultiLineCommentTrivia, SyntaxKind.DoKeyword, SyntaxKind.TryKeyword, SyntaxKind.FinallyKeyword, SyntaxKind.ElseKeyword]);
- this.SpaceBeforeOpenBraceInControl = new Rule(RuleDescriptor.create2(this.ControlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForControlBlocks"), Rules.IsControlDeclContext, Rules.IsNotFormatOnEnter, Rules.IsSameLineTokenOrBeforeBlockContext), RuleAction.Space), RuleFlags.CanDeleteNewLines);
-
- // Insert a space after { and before } in single-line contexts, but remove space from empty object literals {}.
- this.SpaceAfterOpenBrace = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), Rules.IsBraceWrappedContext), RuleAction.Space));
- this.SpaceBeforeCloseBrace = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), Rules.IsBraceWrappedContext), RuleAction.Space));
- this.NoSpaceAfterOpenBrace = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.NoSpaceBeforeCloseBrace = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.NoSpaceBetweenEmptyBraceBrackets = new Rule(RuleDescriptor.create1(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsObjectContext), RuleAction.Delete));
-
- // Insert new line after { and before } in multi-line contexts.
- this.NewLineAfterOpenBraceInBlockContext = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsMultilineBlockContext), RuleAction.NewLine));
-
- // For functions and control block place } on a new line [multi-line rule]
- this.NewLineBeforeCloseBraceInBlockContext = new Rule(RuleDescriptor.create2(Shared.TokenRange.AnyIncludingMultilineComments, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsMultilineBlockContext), RuleAction.NewLine));
+ rule("NoSpaceBeforeDot", anyToken, SyntaxKind.DotToken, [isNonJsxSameLineTokenContext], RuleAction.Delete),
+ rule("NoSpaceAfterDot", SyntaxKind.DotToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.Delete),
// Special handling of unary operators.
// Prefix operators generally shouldn't have a space between
// them and their target unary expression.
- this.NoSpaceAfterUnaryPrefixOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.UnaryPrefixOperators, Shared.TokenRange.UnaryPrefixExpressions), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete));
- this.NoSpaceAfterUnaryPreincrementOperator = new Rule(RuleDescriptor.create3(SyntaxKind.PlusPlusToken, Shared.TokenRange.UnaryPreincrementExpressions), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.NoSpaceAfterUnaryPredecrementOperator = new Rule(RuleDescriptor.create3(SyntaxKind.MinusMinusToken, Shared.TokenRange.UnaryPredecrementExpressions), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.NoSpaceBeforeUnaryPostincrementOperator = new Rule(RuleDescriptor.create2(Shared.TokenRange.UnaryPostincrementExpressions, SyntaxKind.PlusPlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.NoSpaceBeforeUnaryPostdecrementOperator = new Rule(RuleDescriptor.create2(Shared.TokenRange.UnaryPostdecrementExpressions, SyntaxKind.MinusMinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
+ rule("NoSpaceAfterUnaryPrefixOperator", unaryPrefixOperators, unaryPrefixExpressions, [isNonJsxSameLineTokenContext, isNotBinaryOpContext], RuleAction.Delete),
+ rule("NoSpaceAfterUnaryPreincrementOperator", SyntaxKind.PlusPlusToken, unaryPreincrementExpressions, [isNonJsxSameLineTokenContext], RuleAction.Delete),
+ rule("NoSpaceAfterUnaryPredecrementOperator", SyntaxKind.MinusMinusToken, unaryPredecrementExpressions, [isNonJsxSameLineTokenContext], RuleAction.Delete),
+ rule("NoSpaceBeforeUnaryPostincrementOperator", unaryPostincrementExpressions, SyntaxKind.PlusPlusToken, [isNonJsxSameLineTokenContext], RuleAction.Delete),
+ rule("NoSpaceBeforeUnaryPostdecrementOperator", unaryPostdecrementExpressions, SyntaxKind.MinusMinusToken, [isNonJsxSameLineTokenContext], RuleAction.Delete),
// More unary operator special-casing.
// DevDiv 181814: Be careful when removing leading whitespace
// around unary operators. Examples:
// 1 - -2 --X--> 1--2
// a + ++b --X--> a+++b
- this.SpaceAfterPostincrementWhenFollowedByAdd = new Rule(RuleDescriptor.create1(SyntaxKind.PlusPlusToken, SyntaxKind.PlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
- this.SpaceAfterAddWhenFollowedByUnaryPlus = new Rule(RuleDescriptor.create1(SyntaxKind.PlusToken, SyntaxKind.PlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
- this.SpaceAfterAddWhenFollowedByPreincrement = new Rule(RuleDescriptor.create1(SyntaxKind.PlusToken, SyntaxKind.PlusPlusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
- this.SpaceAfterPostdecrementWhenFollowedBySubtract = new Rule(RuleDescriptor.create1(SyntaxKind.MinusMinusToken, SyntaxKind.MinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
- this.SpaceAfterSubtractWhenFollowedByUnaryMinus = new Rule(RuleDescriptor.create1(SyntaxKind.MinusToken, SyntaxKind.MinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
- this.SpaceAfterSubtractWhenFollowedByPredecrement = new Rule(RuleDescriptor.create1(SyntaxKind.MinusToken, SyntaxKind.MinusMinusToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
+ rule("SpaceAfterPostincrementWhenFollowedByAdd", SyntaxKind.PlusPlusToken, SyntaxKind.PlusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space),
+ rule("SpaceAfterAddWhenFollowedByUnaryPlus", SyntaxKind.PlusToken, SyntaxKind.PlusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space),
+ rule("SpaceAfterAddWhenFollowedByPreincrement", SyntaxKind.PlusToken, SyntaxKind.PlusPlusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space),
+ rule("SpaceAfterPostdecrementWhenFollowedBySubtract", SyntaxKind.MinusMinusToken, SyntaxKind.MinusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space),
+ rule("SpaceAfterSubtractWhenFollowedByUnaryMinus", SyntaxKind.MinusToken, SyntaxKind.MinusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space),
+ rule("SpaceAfterSubtractWhenFollowedByPredecrement", SyntaxKind.MinusToken, SyntaxKind.MinusMinusToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space),
- this.NoSpaceBeforeComma = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CommaToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
+ rule("NoSpaceAfterCloseBrace", SyntaxKind.CloseBraceToken, [SyntaxKind.CloseBracketToken, SyntaxKind.CommaToken, SyntaxKind.SemicolonToken], [isNonJsxSameLineTokenContext], RuleAction.Delete),
+ // For functions and control block place } on a new line [multi-line rule]
+ rule("NewLineBeforeCloseBraceInBlockContext", anyTokenIncludingMultilineComments, SyntaxKind.CloseBraceToken, [isMultilineBlockContext], RuleAction.NewLine),
- this.SpaceAfterCertainKeywords = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.VarKeyword, SyntaxKind.ThrowKeyword, SyntaxKind.NewKeyword, SyntaxKind.DeleteKeyword, SyntaxKind.ReturnKeyword, SyntaxKind.TypeOfKeyword, SyntaxKind.AwaitKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
- this.NoSpaceAfterNewKeywordOnConstructorSignature = new Rule(RuleDescriptor.create1(SyntaxKind.NewKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsConstructorSignatureContext), RuleAction.Delete));
- this.SpaceAfterLetConstInVariableDeclaration = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.LetKeyword, SyntaxKind.ConstKeyword]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsStartOfVariableDeclarationList), RuleAction.Space));
- this.NoSpaceBeforeOpenParenInFuncCall = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsFunctionCallOrNewContext, Rules.IsPreviousTokenNotComma), RuleAction.Delete));
- this.SpaceAfterFunctionInFuncDecl = new Rule(RuleDescriptor.create3(SyntaxKind.FunctionKeyword, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space));
- this.SpaceBeforeOpenParenInFuncDecl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceBeforeFunctionParenthesis"), Rules.IsNonJsxSameLineTokenContext, Rules.IsFunctionDeclContext), RuleAction.Space));
- this.NoSpaceBeforeOpenParenInFuncDecl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceBeforeFunctionParenthesis"), Rules.IsNonJsxSameLineTokenContext, Rules.IsFunctionDeclContext), RuleAction.Delete));
- this.SpaceAfterVoidOperator = new Rule(RuleDescriptor.create3(SyntaxKind.VoidKeyword, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsVoidOpContext), RuleAction.Space));
+ // Space/new line after }.
+ rule("SpaceAfterCloseBrace", SyntaxKind.CloseBraceToken, anyTokenExcept(SyntaxKind.CloseParenToken), [isNonJsxSameLineTokenContext, isAfterCodeBlockContext], RuleAction.Space),
+ // Special case for (}, else) and (}, while) since else & while tokens are not part of the tree which makes SpaceAfterCloseBrace rule not applied
+ // Also should not apply to })
+ rule("SpaceBetweenCloseBraceAndElse", SyntaxKind.CloseBraceToken, SyntaxKind.ElseKeyword, [isNonJsxSameLineTokenContext], RuleAction.Space),
+ rule("SpaceBetweenCloseBraceAndWhile", SyntaxKind.CloseBraceToken, SyntaxKind.WhileKeyword, [isNonJsxSameLineTokenContext], RuleAction.Space),
+ rule("NoSpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [isNonJsxSameLineTokenContext, isObjectContext], RuleAction.Delete),
- this.NoSpaceBetweenReturnAndSemicolon = new Rule(RuleDescriptor.create1(SyntaxKind.ReturnKeyword, SyntaxKind.SemicolonToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
+ rule("NoSpaceBetweenFunctionKeywordAndStar", SyntaxKind.FunctionKeyword, SyntaxKind.AsteriskToken, [isFunctionDeclarationOrFunctionExpressionContext], RuleAction.Delete),
+ rule("SpaceAfterStarInGeneratorDeclaration", SyntaxKind.AsteriskToken, [SyntaxKind.Identifier, SyntaxKind.OpenParenToken], [isFunctionDeclarationOrFunctionExpressionContext], RuleAction.Space),
- // Add a space between statements. All keywords except (do,else,case) has open/close parens after them.
- // So, we have a rule to add a space for [),Any], [do,Any], [else,Any], and [case,Any]
- 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));
+ rule("SpaceAfterFunctionInFuncDecl", SyntaxKind.FunctionKeyword, anyToken, [isFunctionDeclContext], RuleAction.Space),
+ // Insert new line after { and before } in multi-line contexts.
+ rule("NewLineAfterOpenBraceInBlockContext", SyntaxKind.OpenBraceToken, anyToken, [isMultilineBlockContext], RuleAction.NewLine),
+ // For get/set members, we check for (identifier,identifier) since get/set don't have tokens and they are represented as just an identifier token.
+ // Though, we do extra check on the context to make sure we are dealing with get/set node. Example:
// get x() {}
// set x(val) {}
- this.SpaceAfterGetSetInMember = new Rule(RuleDescriptor.create2(Shared.TokenRange.FromTokens([SyntaxKind.GetKeyword, SyntaxKind.SetKeyword]), SyntaxKind.Identifier), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclContext), RuleAction.Space));
+ rule("SpaceAfterGetSetInMember", [SyntaxKind.GetKeyword, SyntaxKind.SetKeyword], SyntaxKind.Identifier, [isFunctionDeclContext], RuleAction.Space),
+
+ rule("NoSpaceBetweenYieldKeywordAndStar", SyntaxKind.YieldKeyword, SyntaxKind.AsteriskToken, [isNonJsxSameLineTokenContext, isYieldOrYieldStarWithOperand], RuleAction.Delete),
+ rule("SpaceBetweenYieldOrYieldStarAndOperand", [SyntaxKind.YieldKeyword, SyntaxKind.AsteriskToken], anyToken, [isNonJsxSameLineTokenContext, isYieldOrYieldStarWithOperand], RuleAction.Space),
+
+ rule("NoSpaceBetweenReturnAndSemicolon", SyntaxKind.ReturnKeyword, SyntaxKind.SemicolonToken, [isNonJsxSameLineTokenContext], RuleAction.Delete),
+ rule("SpaceAfterCertainKeywords", [SyntaxKind.VarKeyword, SyntaxKind.ThrowKeyword, SyntaxKind.NewKeyword, SyntaxKind.DeleteKeyword, SyntaxKind.ReturnKeyword, SyntaxKind.TypeOfKeyword, SyntaxKind.AwaitKeyword], anyToken, [isNonJsxSameLineTokenContext], RuleAction.Space),
+ rule("SpaceAfterLetConstInVariableDeclaration", [SyntaxKind.LetKeyword, SyntaxKind.ConstKeyword], anyToken, [isNonJsxSameLineTokenContext, isStartOfVariableDeclarationList], RuleAction.Space),
+ rule("NoSpaceBeforeOpenParenInFuncCall", anyToken, SyntaxKind.OpenParenToken, [isNonJsxSameLineTokenContext, isFunctionCallOrNewContext, isPreviousTokenNotComma], RuleAction.Delete),
// Special case for binary operators (that are keywords). For these we have to add a space and shouldn't follow any user options.
- this.SpaceBeforeBinaryKeywordOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryKeywordOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
- this.SpaceAfterBinaryKeywordOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.BinaryKeywordOperators, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
+ rule("SpaceBeforeBinaryKeywordOperator", anyToken, binaryKeywordOperators, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space),
+ rule("SpaceAfterBinaryKeywordOperator", binaryKeywordOperators, anyToken, [isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space),
- // TypeScript-specific higher priority rules
-
- this.SpaceAfterConstructor = new Rule(RuleDescriptor.create1(SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterConstructor"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
- this.NoSpaceAfterConstructor = new Rule(RuleDescriptor.create1(SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterConstructor"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
-
- // Use of module as a function call. e.g.: import m2 = module("m2");
- 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.ReadonlyKeyword, SyntaxKind.SetKeyword, SyntaxKind.StaticKeyword, SyntaxKind.TypeKeyword, SyntaxKind.FromKeyword, SyntaxKind.KeyOfKeyword]), 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));
-
- // Lambda expressions
- this.SpaceBeforeArrow = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.EqualsGreaterThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
- this.SpaceAfterArrow = new Rule(RuleDescriptor.create3(SyntaxKind.EqualsGreaterThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
-
- // Optional parameters and let args
- this.NoSpaceAfterEllipsis = new Rule(RuleDescriptor.create1(SyntaxKind.DotDotDotToken, SyntaxKind.Identifier), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.NoSpaceAfterOptionalParameters = new Rule(RuleDescriptor.create3(SyntaxKind.QuestionToken, Shared.TokenRange.FromTokens([SyntaxKind.CloseParenToken, SyntaxKind.CommaToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNotBinaryOpContext), RuleAction.Delete));
-
- // generics and type assertions
- this.NoSpaceBeforeOpenAngularBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.TypeNames, SyntaxKind.LessThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsTypeArgumentOrParameterOrAssertionContext), RuleAction.Delete));
- this.NoSpaceBetweenCloseParenAndAngularBracket = new Rule(RuleDescriptor.create1(SyntaxKind.CloseParenToken, SyntaxKind.LessThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsTypeArgumentOrParameterOrAssertionContext), RuleAction.Delete));
- this.NoSpaceAfterOpenAngularBracket = new Rule(RuleDescriptor.create3(SyntaxKind.LessThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsTypeArgumentOrParameterOrAssertionContext), RuleAction.Delete));
- this.NoSpaceBeforeCloseAngularBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.GreaterThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsTypeArgumentOrParameterOrAssertionContext), RuleAction.Delete));
- this.NoSpaceAfterCloseAngularBracket = new Rule(RuleDescriptor.create3(SyntaxKind.GreaterThanToken, Shared.TokenRange.FromTokens([SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.GreaterThanToken, SyntaxKind.CommaToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsTypeArgumentOrParameterOrAssertionContext), RuleAction.Delete));
-
- // Remove spaces in empty interface literals. e.g.: x: {}
- this.NoSpaceBetweenEmptyInterfaceBraceBrackets = new Rule(RuleDescriptor.create1(SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsObjectTypeContext), RuleAction.Delete));
-
- // decorators
- this.SpaceBeforeAt = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.AtToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
- this.NoSpaceAfterAt = new Rule(RuleDescriptor.create3(SyntaxKind.AtToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.SpaceAfterDecorator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.AbstractKeyword, SyntaxKind.Identifier, SyntaxKind.ExportKeyword, SyntaxKind.DefaultKeyword, SyntaxKind.ClassKeyword, SyntaxKind.StaticKeyword, SyntaxKind.PublicKeyword, SyntaxKind.PrivateKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.GetKeyword, SyntaxKind.SetKeyword, SyntaxKind.OpenBracketToken, SyntaxKind.AsteriskToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsEndOfDecoratorContextOnSameLine), RuleAction.Space));
-
- this.NoSpaceBetweenFunctionKeywordAndStar = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.AsteriskToken), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclarationOrFunctionExpressionContext), RuleAction.Delete));
- this.SpaceAfterStarInGeneratorDeclaration = new Rule(RuleDescriptor.create3(SyntaxKind.AsteriskToken, Shared.TokenRange.FromTokens([SyntaxKind.Identifier, SyntaxKind.OpenParenToken])), RuleOperation.create2(new RuleOperationContext(Rules.IsFunctionDeclarationOrFunctionExpressionContext), RuleAction.Space));
- this.NoSpaceBetweenYieldKeywordAndStar = new Rule(RuleDescriptor.create1(SyntaxKind.YieldKeyword, SyntaxKind.AsteriskToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsYieldOrYieldStarWithOperand), RuleAction.Delete));
- this.SpaceBetweenYieldOrYieldStarAndOperand = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.YieldKeyword, SyntaxKind.AsteriskToken]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsYieldOrYieldStarWithOperand), RuleAction.Space));
+ rule("SpaceAfterVoidOperator", SyntaxKind.VoidKeyword, anyToken, [isNonJsxSameLineTokenContext, isVoidOpContext], RuleAction.Space),
// Async-await
- this.SpaceBetweenAsyncAndOpenParen = new Rule(RuleDescriptor.create1(SyntaxKind.AsyncKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsArrowFunctionContext, Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
- this.SpaceBetweenAsyncAndFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.AsyncKeyword, SyntaxKind.FunctionKeyword), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
+ rule("SpaceBetweenAsyncAndOpenParen", SyntaxKind.AsyncKeyword, SyntaxKind.OpenParenToken, [isArrowFunctionContext, isNonJsxSameLineTokenContext], RuleAction.Space),
+ rule("SpaceBetweenAsyncAndFunctionKeyword", SyntaxKind.AsyncKeyword, SyntaxKind.FunctionKeyword, [isNonJsxSameLineTokenContext], RuleAction.Space),
// template string
- this.NoSpaceBetweenTagAndTemplateString = new Rule(RuleDescriptor.create3(SyntaxKind.Identifier, Shared.TokenRange.FromTokens([SyntaxKind.NoSubstitutionTemplateLiteral, SyntaxKind.TemplateHead])), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
+ rule("NoSpaceBetweenTagAndTemplateString", SyntaxKind.Identifier, [SyntaxKind.NoSubstitutionTemplateLiteral, SyntaxKind.TemplateHead], [isNonJsxSameLineTokenContext], RuleAction.Delete),
- // jsx opening element
- this.SpaceBeforeJsxAttribute = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.Identifier), RuleOperation.create2(new RuleOperationContext(Rules.IsNextTokenParentJsxAttribute, Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
- this.SpaceBeforeSlashInJsxOpeningElement = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.SlashToken), RuleOperation.create2(new RuleOperationContext(Rules.IsJsxSelfClosingElementContext, Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
- this.NoSpaceBeforeGreaterThanTokenInJsxOpeningElement = new Rule(RuleDescriptor.create1(SyntaxKind.SlashToken, SyntaxKind.GreaterThanToken), RuleOperation.create2(new RuleOperationContext(Rules.IsJsxSelfClosingElementContext, Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.NoSpaceBeforeEqualInJsxAttribute = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.EqualsToken), RuleOperation.create2(new RuleOperationContext(Rules.IsJsxAttributeContext, Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.NoSpaceAfterEqualInJsxAttribute = new Rule(RuleDescriptor.create3(SyntaxKind.EqualsToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsJsxAttributeContext, Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
+ // JSX opening elements
+ rule("SpaceBeforeJsxAttribute", anyToken, SyntaxKind.Identifier, [isNextTokenParentJsxAttribute, isNonJsxSameLineTokenContext], RuleAction.Space),
+ rule("SpaceBeforeSlashInJsxOpeningElement", anyToken, SyntaxKind.SlashToken, [isJsxSelfClosingElementContext, isNonJsxSameLineTokenContext], RuleAction.Space),
+ rule("NoSpaceBeforeGreaterThanTokenInJsxOpeningElement", SyntaxKind.SlashToken, SyntaxKind.GreaterThanToken, [isJsxSelfClosingElementContext, isNonJsxSameLineTokenContext], RuleAction.Delete),
+ rule("NoSpaceBeforeEqualInJsxAttribute", anyToken, SyntaxKind.EqualsToken, [isJsxAttributeContext, isNonJsxSameLineTokenContext], RuleAction.Delete),
+ rule("NoSpaceAfterEqualInJsxAttribute", SyntaxKind.EqualsToken, anyToken, [isJsxAttributeContext, isNonJsxSameLineTokenContext], RuleAction.Delete),
- // No space before non-null assertion operator
- this.NoSpaceBeforeNonNullAssertionOperator = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.ExclamationToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext, Rules.IsNonNullAssertionContext), RuleAction.Delete));
+ // TypeScript-specific rules
+ // Use of module as a function call. e.g.: import m2 = module("m2");
+ rule("NoSpaceAfterModuleImport", [SyntaxKind.ModuleKeyword, SyntaxKind.RequireKeyword], SyntaxKind.OpenParenToken, [isNonJsxSameLineTokenContext], RuleAction.Delete),
+ // Add a space around certain TypeScript keywords
+ rule(
+ "SpaceAfterCertainTypeScriptKeywords",
+ [
+ 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.ReadonlyKeyword,
+ SyntaxKind.SetKeyword,
+ SyntaxKind.StaticKeyword,
+ SyntaxKind.TypeKeyword,
+ SyntaxKind.FromKeyword,
+ SyntaxKind.KeyOfKeyword,
+ ],
+ anyToken,
+ [isNonJsxSameLineTokenContext],
+ RuleAction.Space),
+ rule(
+ "SpaceBeforeCertainTypeScriptKeywords",
+ anyToken,
+ [SyntaxKind.ExtendsKeyword, SyntaxKind.ImplementsKeyword, SyntaxKind.FromKeyword],
+ [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" {
+ rule("SpaceAfterModuleName", SyntaxKind.StringLiteral, SyntaxKind.OpenBraceToken, [isModuleDeclContext], RuleAction.Space),
- ///
- /// Rules controlled by user options
- ///
+ // Lambda expressions
+ rule("SpaceBeforeArrow", anyToken, SyntaxKind.EqualsGreaterThanToken, [isNonJsxSameLineTokenContext], RuleAction.Space),
+ rule("SpaceAfterArrow", SyntaxKind.EqualsGreaterThanToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.Space),
- // Insert space after comma delimiter
- this.SpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterCommaDelimiter"), Rules.IsNonJsxSameLineTokenContext, Rules.IsNonJsxElementContext, Rules.IsNextTokenNotCloseBracket), RuleAction.Space));
- this.NoSpaceAfterComma = new Rule(RuleDescriptor.create3(SyntaxKind.CommaToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterCommaDelimiter"), Rules.IsNonJsxSameLineTokenContext, Rules.IsNonJsxElementContext), RuleAction.Delete));
+ // Optional parameters and let args
+ rule("NoSpaceAfterEllipsis", SyntaxKind.DotDotDotToken, SyntaxKind.Identifier, [isNonJsxSameLineTokenContext], RuleAction.Delete),
+ rule("NoSpaceAfterOptionalParameters", SyntaxKind.QuestionToken, [SyntaxKind.CloseParenToken, SyntaxKind.CommaToken], [isNonJsxSameLineTokenContext, isNotBinaryOpContext], 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.IsOptionEnabled("insertSpaceBeforeAndAfterBinaryOperators"), Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
- this.SpaceAfterBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.BinaryOperators, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceBeforeAndAfterBinaryOperators"), Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Space));
- this.NoSpaceBeforeBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.BinaryOperators), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceBeforeAndAfterBinaryOperators"), Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Delete));
- this.NoSpaceAfterBinaryOperator = new Rule(RuleDescriptor.create4(Shared.TokenRange.BinaryOperators, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceBeforeAndAfterBinaryOperators"), Rules.IsNonJsxSameLineTokenContext, Rules.IsBinaryOpContext), RuleAction.Delete));
+ // Remove spaces in empty interface literals. e.g.: x: {}
+ rule("NoSpaceBetweenEmptyInterfaceBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [isNonJsxSameLineTokenContext, isObjectTypeContext], RuleAction.Delete),
+
+ // generics and type assertions
+ rule("NoSpaceBeforeOpenAngularBracket", typeNames, SyntaxKind.LessThanToken, [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext], RuleAction.Delete),
+ rule("NoSpaceBetweenCloseParenAndAngularBracket", SyntaxKind.CloseParenToken, SyntaxKind.LessThanToken, [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext], RuleAction.Delete),
+ rule("NoSpaceAfterOpenAngularBracket", SyntaxKind.LessThanToken, anyToken, [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext], RuleAction.Delete),
+ rule("NoSpaceBeforeCloseAngularBracket", anyToken, SyntaxKind.GreaterThanToken, [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext], RuleAction.Delete),
+ rule("NoSpaceAfterCloseAngularBracket",
+ SyntaxKind.GreaterThanToken,
+ [SyntaxKind.OpenParenToken, SyntaxKind.OpenBracketToken, SyntaxKind.GreaterThanToken, SyntaxKind.CommaToken],
+ [isNonJsxSameLineTokenContext, isTypeArgumentOrParameterOrAssertionContext],
+ RuleAction.Delete),
+
+ // decorators
+ rule("SpaceBeforeAt", anyToken, SyntaxKind.AtToken, [isNonJsxSameLineTokenContext], RuleAction.Space),
+ rule("NoSpaceAfterAt", SyntaxKind.AtToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.Delete),
+ // Insert space after @ in decorator
+ rule("SpaceAfterDecorator",
+ anyToken,
+ [
+ SyntaxKind.AbstractKeyword,
+ SyntaxKind.Identifier,
+ SyntaxKind.ExportKeyword,
+ SyntaxKind.DefaultKeyword,
+ SyntaxKind.ClassKeyword,
+ SyntaxKind.StaticKeyword,
+ SyntaxKind.PublicKeyword,
+ SyntaxKind.PrivateKeyword,
+ SyntaxKind.ProtectedKeyword,
+ SyntaxKind.GetKeyword,
+ SyntaxKind.SetKeyword,
+ SyntaxKind.OpenBracketToken,
+ SyntaxKind.AsteriskToken,
+ ],
+ [isEndOfDecoratorContextOnSameLine],
+ RuleAction.Space),
+
+ rule("NoSpaceBeforeNonNullAssertionOperator", anyToken, SyntaxKind.ExclamationToken, [isNonJsxSameLineTokenContext, isNonNullAssertionContext], RuleAction.Delete),
+ rule("NoSpaceAfterNewKeywordOnConstructorSignature", SyntaxKind.NewKeyword, SyntaxKind.OpenParenToken, [isNonJsxSameLineTokenContext, isConstructorSignatureContext], RuleAction.Delete),
+ ];
+
+ // These rules are applied after high priority
+ const userConfigurableRules = [
+ // Treat constructor as an identifier in a function declaration, and remove spaces between constructor and following left parentheses
+ rule("SpaceAfterConstructor", SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceAfterConstructor"), isNonJsxSameLineTokenContext], RuleAction.Space),
+ rule("NoSpaceAfterConstructor", SyntaxKind.ConstructorKeyword, SyntaxKind.OpenParenToken, [isOptionDisabledOrUndefined("insertSpaceAfterConstructor"), isNonJsxSameLineTokenContext], RuleAction.Delete),
+
+ rule("SpaceAfterComma", SyntaxKind.CommaToken, anyToken, [isOptionEnabled("insertSpaceAfterCommaDelimiter"), isNonJsxSameLineTokenContext, isNonJsxElementContext, isNextTokenNotCloseBracket], RuleAction.Space),
+ rule("NoSpaceAfterComma", SyntaxKind.CommaToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterCommaDelimiter"), isNonJsxSameLineTokenContext, isNonJsxElementContext], RuleAction.Delete),
+
+ // Insert space after function keyword for anonymous functions
+ rule("SpaceAfterAnonymousFunctionKeyword", SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceAfterFunctionKeywordForAnonymousFunctions"), isFunctionDeclContext], RuleAction.Space),
+ rule("NoSpaceAfterAnonymousFunctionKeyword", SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken, [isOptionDisabledOrUndefined("insertSpaceAfterFunctionKeywordForAnonymousFunctions"), isFunctionDeclContext], RuleAction.Delete),
// Insert space after keywords in control flow statements
- this.SpaceAfterKeywordInControl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Keywords, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterKeywordsInControlFlowStatements"), Rules.IsControlDeclContext), RuleAction.Space));
- this.NoSpaceAfterKeywordInControl = new Rule(RuleDescriptor.create2(Shared.TokenRange.Keywords, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterKeywordsInControlFlowStatements"), Rules.IsControlDeclContext), RuleAction.Delete));
+ rule("SpaceAfterKeywordInControl", keywords, SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceAfterKeywordsInControlFlowStatements"), isControlDeclContext], RuleAction.Space),
+ rule("NoSpaceAfterKeywordInControl", keywords, SyntaxKind.OpenParenToken, [isOptionDisabledOrUndefined("insertSpaceAfterKeywordsInControlFlowStatements"), isControlDeclContext], RuleAction.Delete),
+
+ // Insert space after opening and before closing nonempty parenthesis
+ rule("SpaceAfterOpenParen", SyntaxKind.OpenParenToken, anyToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.Space),
+ rule("SpaceBeforeCloseParen", anyToken, SyntaxKind.CloseParenToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.Space),
+ rule("SpaceBetweenOpenParens", SyntaxKind.OpenParenToken, SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.Space),
+ rule("NoSpaceBetweenParens", SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken, [isNonJsxSameLineTokenContext], RuleAction.Delete),
+ rule("NoSpaceAfterOpenParen", SyntaxKind.OpenParenToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.Delete),
+ rule("NoSpaceBeforeCloseParen", anyToken, SyntaxKind.CloseParenToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), isNonJsxSameLineTokenContext], RuleAction.Delete),
+
+ // Insert space after opening and before closing nonempty brackets
+ rule("SpaceAfterOpenBracket", SyntaxKind.OpenBracketToken, anyToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), isNonJsxSameLineTokenContext], RuleAction.Space),
+ rule("SpaceBeforeCloseBracket", anyToken, SyntaxKind.CloseBracketToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), isNonJsxSameLineTokenContext], RuleAction.Space),
+ rule("NoSpaceBetweenBrackets", SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken, [isNonJsxSameLineTokenContext], RuleAction.Delete),
+ rule("NoSpaceAfterOpenBracket", SyntaxKind.OpenBracketToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), isNonJsxSameLineTokenContext], RuleAction.Delete),
+ rule("NoSpaceBeforeCloseBracket", anyToken, SyntaxKind.CloseBracketToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), isNonJsxSameLineTokenContext], RuleAction.Delete),
+
+ // Insert a space after { and before } in single-line contexts, but remove space from empty object literals {}.
+ rule("SpaceAfterOpenBrace", SyntaxKind.OpenBraceToken, anyToken, [isOptionEnabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), isBraceWrappedContext], RuleAction.Space),
+ rule("SpaceBeforeCloseBrace", anyToken, SyntaxKind.CloseBraceToken, [isOptionEnabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), isBraceWrappedContext], RuleAction.Space),
+ rule("NoSpaceBetweenEmptyBraceBrackets", SyntaxKind.OpenBraceToken, SyntaxKind.CloseBraceToken, [isNonJsxSameLineTokenContext, isObjectContext], RuleAction.Delete),
+ rule("NoSpaceAfterOpenBrace", SyntaxKind.OpenBraceToken, anyToken, [isOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), isNonJsxSameLineTokenContext], RuleAction.Delete),
+ rule("NoSpaceBeforeCloseBrace", anyToken, SyntaxKind.CloseBraceToken, [isOptionDisabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBraces"), isNonJsxSameLineTokenContext], RuleAction.Delete),
+
+ // Insert space after opening and before closing template string braces
+ rule("SpaceAfterTemplateHeadAndMiddle", [SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle], anyToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxSameLineTokenContext], RuleAction.Space),
+ rule("SpaceBeforeTemplateMiddleAndTail", anyToken, [SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail], [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxSameLineTokenContext], RuleAction.Space),
+ rule("NoSpaceAfterTemplateHeadAndMiddle", [SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle], anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxSameLineTokenContext], RuleAction.Delete),
+ rule("NoSpaceBeforeTemplateMiddleAndTail", anyToken, [SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail], [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), isNonJsxSameLineTokenContext], RuleAction.Delete),
+
+ // No space after { and before } in JSX expression
+ rule("SpaceAfterOpenBraceInJsxExpression", SyntaxKind.OpenBraceToken, anyToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), isNonJsxSameLineTokenContext, isJsxExpressionContext], RuleAction.Space),
+ rule("SpaceBeforeCloseBraceInJsxExpression", anyToken, SyntaxKind.CloseBraceToken, [isOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), isNonJsxSameLineTokenContext, isJsxExpressionContext], RuleAction.Space),
+ rule("NoSpaceAfterOpenBraceInJsxExpression", SyntaxKind.OpenBraceToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), isNonJsxSameLineTokenContext, isJsxExpressionContext], RuleAction.Delete),
+ rule("NoSpaceBeforeCloseBraceInJsxExpression", anyToken, SyntaxKind.CloseBraceToken, [isOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), isNonJsxSameLineTokenContext, isJsxExpressionContext], RuleAction.Delete),
+
+ // Insert space after semicolon in for statement
+ rule("SpaceAfterSemicolonInFor", SyntaxKind.SemicolonToken, anyToken, [isOptionEnabled("insertSpaceAfterSemicolonInForStatements"), isNonJsxSameLineTokenContext, isForContext], RuleAction.Space),
+ rule("NoSpaceAfterSemicolonInFor", SyntaxKind.SemicolonToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterSemicolonInForStatements"), isNonJsxSameLineTokenContext, isForContext], RuleAction.Delete),
+
+ // Insert space before and after binary operators
+ rule("SpaceBeforeBinaryOperator", anyToken, binaryOperators, [isOptionEnabled("insertSpaceBeforeAndAfterBinaryOperators"), isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space),
+ rule("SpaceAfterBinaryOperator", binaryOperators, anyToken, [isOptionEnabled("insertSpaceBeforeAndAfterBinaryOperators"), isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Space),
+ rule("NoSpaceBeforeBinaryOperator", anyToken, binaryOperators, [isOptionDisabledOrUndefined("insertSpaceBeforeAndAfterBinaryOperators"), isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Delete),
+ rule("NoSpaceAfterBinaryOperator", binaryOperators, anyToken, [isOptionDisabledOrUndefined("insertSpaceBeforeAndAfterBinaryOperators"), isNonJsxSameLineTokenContext, isBinaryOpContext], RuleAction.Delete),
+
+ rule("SpaceBeforeOpenParenInFuncDecl", anyToken, SyntaxKind.OpenParenToken, [isOptionEnabled("insertSpaceBeforeFunctionParenthesis"), isNonJsxSameLineTokenContext, isFunctionDeclContext], RuleAction.Space),
+ rule("NoSpaceBeforeOpenParenInFuncDecl", anyToken, SyntaxKind.OpenParenToken, [isOptionDisabledOrUndefined("insertSpaceBeforeFunctionParenthesis"), isNonJsxSameLineTokenContext, isFunctionDeclContext], RuleAction.Delete),
+
+ // Open Brace braces after control block
+ rule("NewLineBeforeOpenBraceInControl", controlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionEnabled("placeOpenBraceOnNewLineForControlBlocks"), isControlDeclContext, isBeforeMultilineBlockContext], RuleAction.NewLine, RuleFlags.CanDeleteNewLines),
// Open Brace braces after function
// TypeScript: Function can have return types, which can be made of tons of different token kinds
- this.NewLineBeforeOpenBraceInFunction = new Rule(RuleDescriptor.create2(this.FunctionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("placeOpenBraceOnNewLineForFunctions"), Rules.IsFunctionDeclContext, Rules.IsBeforeMultilineBlockContext), RuleAction.NewLine), RuleFlags.CanDeleteNewLines);
-
+ rule("NewLineBeforeOpenBraceInFunction", functionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionEnabled("placeOpenBraceOnNewLineForFunctions"), isFunctionDeclContext, isBeforeMultilineBlockContext], RuleAction.NewLine, RuleFlags.CanDeleteNewLines),
// Open Brace braces after TypeScript module/class/interface
- this.NewLineBeforeOpenBraceInTypeScriptDeclWithBlock = new Rule(RuleDescriptor.create2(this.TypeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("placeOpenBraceOnNewLineForFunctions"), Rules.IsTypeScriptDeclWithBlockContext, Rules.IsBeforeMultilineBlockContext), RuleAction.NewLine), RuleFlags.CanDeleteNewLines);
+ rule("NewLineBeforeOpenBraceInTypeScriptDeclWithBlock", typeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionEnabled("placeOpenBraceOnNewLineForFunctions"), isTypeScriptDeclWithBlockContext, isBeforeMultilineBlockContext], RuleAction.NewLine, RuleFlags.CanDeleteNewLines),
- // Open Brace braces after control block
- this.NewLineBeforeOpenBraceInControl = new Rule(RuleDescriptor.create2(this.ControlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("placeOpenBraceOnNewLineForControlBlocks"), Rules.IsControlDeclContext, Rules.IsBeforeMultilineBlockContext), RuleAction.NewLine), RuleFlags.CanDeleteNewLines);
+ rule("SpaceAfterTypeAssertion", SyntaxKind.GreaterThanToken, anyToken, [isOptionEnabled("insertSpaceAfterTypeAssertion"), isNonJsxSameLineTokenContext, isTypeAssertionContext], RuleAction.Space),
+ rule("NoSpaceAfterTypeAssertion", SyntaxKind.GreaterThanToken, anyToken, [isOptionDisabledOrUndefined("insertSpaceAfterTypeAssertion"), isNonJsxSameLineTokenContext, isTypeAssertionContext], RuleAction.Delete),
+ ];
- // Insert space after semicolon in for statement
- this.SpaceAfterSemicolonInFor = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterSemicolonInForStatements"), Rules.IsNonJsxSameLineTokenContext, Rules.IsForContext), RuleAction.Space));
- this.NoSpaceAfterSemicolonInFor = new Rule(RuleDescriptor.create3(SyntaxKind.SemicolonToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterSemicolonInForStatements"), Rules.IsNonJsxSameLineTokenContext, Rules.IsForContext), RuleAction.Delete));
+ // These rules are lower in priority than user-configurable
+ const lowPriorityCommonRules = [
+ // Space after keyword but not before ; or : or ?
+ rule("NoSpaceBeforeSemicolon", anyToken, SyntaxKind.SemicolonToken, [isNonJsxSameLineTokenContext], RuleAction.Delete),
- // Insert space after opening and before closing nonempty parenthesis
- this.SpaceAfterOpenParen = new Rule(RuleDescriptor.create3(SyntaxKind.OpenParenToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
- this.SpaceBeforeCloseParen = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
- this.SpaceBetweenOpenParens = new Rule(RuleDescriptor.create1(SyntaxKind.OpenParenToken, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
- this.NoSpaceBetweenParens = new Rule(RuleDescriptor.create1(SyntaxKind.OpenParenToken, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.NoSpaceAfterOpenParen = new Rule(RuleDescriptor.create3(SyntaxKind.OpenParenToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.NoSpaceBeforeCloseParen = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyParenthesis"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
+ rule("SpaceBeforeOpenBraceInControl", controlOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForControlBlocks"), isControlDeclContext, isNotFormatOnEnter, isSameLineTokenOrBeforeBlockContext], RuleAction.Space, RuleFlags.CanDeleteNewLines),
+ rule("SpaceBeforeOpenBraceInFunction", functionOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForFunctions"), isFunctionDeclContext, isBeforeBlockContext, isNotFormatOnEnter, isSameLineTokenOrBeforeBlockContext], RuleAction.Space, RuleFlags.CanDeleteNewLines),
+ rule("SpaceBeforeOpenBraceInTypeScriptDeclWithBlock", typeScriptOpenBraceLeftTokenRange, SyntaxKind.OpenBraceToken, [isOptionDisabledOrUndefinedOrTokensOnSameLine("placeOpenBraceOnNewLineForFunctions"), isTypeScriptDeclWithBlockContext, isNotFormatOnEnter, isSameLineTokenOrBeforeBlockContext], RuleAction.Space, RuleFlags.CanDeleteNewLines),
- // Insert space after opening and before closing nonempty brackets
- this.SpaceAfterOpenBracket = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBracketToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
- this.SpaceBeforeCloseBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBracketToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
- this.NoSpaceBetweenBrackets = new Rule(RuleDescriptor.create1(SyntaxKind.OpenBracketToken, SyntaxKind.CloseBracketToken), RuleOperation.create2(new RuleOperationContext(Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.NoSpaceAfterOpenBracket = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBracketToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.NoSpaceBeforeCloseBracket = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBracketToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingNonemptyBrackets"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
+ rule("NoSpaceBeforeComma", anyToken, SyntaxKind.CommaToken, [isNonJsxSameLineTokenContext], RuleAction.Delete),
+ // No space before and after indexer
+ rule("NoSpaceBeforeOpenBracket", anyTokenExcept(SyntaxKind.AsyncKeyword), SyntaxKind.OpenBracketToken, [isNonJsxSameLineTokenContext], RuleAction.Delete),
+ rule("NoSpaceAfterCloseBracket", SyntaxKind.CloseBracketToken, anyToken, [isNonJsxSameLineTokenContext, isNotBeforeBlockInFunctionDeclarationContext], RuleAction.Delete),
+ rule("SpaceAfterSemicolon", SyntaxKind.SemicolonToken, anyToken, [isNonJsxSameLineTokenContext], RuleAction.Space),
- // Insert space after opening and before closing template string braces
- this.NoSpaceAfterTemplateHeadAndMiddle = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Delete));
- this.SpaceAfterTemplateHeadAndMiddle = new Rule(RuleDescriptor.create4(Shared.TokenRange.FromTokens([SyntaxKind.TemplateHead, SyntaxKind.TemplateMiddle]), Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
- this.NoSpaceBeforeTemplateMiddleAndTail = new Rule(RuleDescriptor.create4(Shared.TokenRange.Any, Shared.TokenRange.FromTokens([SyntaxKind.TemplateMiddle, SyntaxKind.TemplateTail])), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), 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.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingTemplateStringBraces"), Rules.IsNonJsxSameLineTokenContext), RuleAction.Space));
+ // Add a space between statements. All keywords except (do,else,case) has open/close parens after them.
+ // So, we have a rule to add a space for [),Any], [do,Any], [else,Any], and [case,Any]
+ rule(
+ "SpaceBetweenStatements",
+ [SyntaxKind.CloseParenToken, SyntaxKind.DoKeyword, SyntaxKind.ElseKeyword, SyntaxKind.CaseKeyword],
+ anyToken,
+ [isNonJsxSameLineTokenContext, isNonJsxElementContext, isNotForContext],
+ RuleAction.Space),
+ // This low-pri rule takes care of "try {" and "finally {" in case the rule SpaceBeforeOpenBraceInControl didn't execute on FormatOnEnter.
+ rule("SpaceAfterTryFinally", [SyntaxKind.TryKeyword, SyntaxKind.FinallyKeyword], SyntaxKind.OpenBraceToken, [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.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), Rules.IsNonJsxSameLineTokenContext, Rules.IsJsxExpressionContext), RuleAction.Delete));
- this.SpaceAfterOpenBraceInJsxExpression = new Rule(RuleDescriptor.create3(SyntaxKind.OpenBraceToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), Rules.IsNonJsxSameLineTokenContext, Rules.IsJsxExpressionContext), RuleAction.Space));
- this.NoSpaceBeforeCloseBraceInJsxExpression = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), Rules.IsNonJsxSameLineTokenContext, Rules.IsJsxExpressionContext), RuleAction.Delete));
- this.SpaceBeforeCloseBraceInJsxExpression = new Rule(RuleDescriptor.create2(Shared.TokenRange.Any, SyntaxKind.CloseBraceToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterOpeningAndBeforeClosingJsxExpressionBraces"), Rules.IsNonJsxSameLineTokenContext, Rules.IsJsxExpressionContext), RuleAction.Space));
+ return [
+ ...highPriorityCommonRules,
+ ...userConfigurableRules,
+ ...lowPriorityCommonRules,
+ ];
+ }
- // Insert space after function keyword for anonymous functions
- this.SpaceAfterAnonymousFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterFunctionKeywordForAnonymousFunctions"), Rules.IsFunctionDeclContext), RuleAction.Space));
- this.NoSpaceAfterAnonymousFunctionKeyword = new Rule(RuleDescriptor.create1(SyntaxKind.FunctionKeyword, SyntaxKind.OpenParenToken), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterFunctionKeywordForAnonymousFunctions"), Rules.IsFunctionDeclContext), RuleAction.Delete));
+ function rule(
+ debugName: string,
+ left: SyntaxKind | ReadonlyArray | TokenRange,
+ right: SyntaxKind | ReadonlyArray | TokenRange,
+ context: ReadonlyArray,
+ action: RuleAction,
+ flags: RuleFlags = RuleFlags.None,
+ ): RuleSpec {
+ return { leftTokenRange: toTokenRange(left), rightTokenRange: toTokenRange(right), rule: { debugName, context, action, flags } };
+ }
- // No space after type assertion
- this.NoSpaceAfterTypeAssertion = new Rule(RuleDescriptor.create3(SyntaxKind.GreaterThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionDisabledOrUndefined("insertSpaceAfterTypeAssertion"), Rules.IsNonJsxSameLineTokenContext, Rules.IsTypeAssertionContext), RuleAction.Delete));
- this.SpaceAfterTypeAssertion = new Rule(RuleDescriptor.create3(SyntaxKind.GreaterThanToken, Shared.TokenRange.Any), RuleOperation.create2(new RuleOperationContext(Rules.IsOptionEnabled("insertSpaceAfterTypeAssertion"), Rules.IsNonJsxSameLineTokenContext, Rules.IsTypeAssertionContext), RuleAction.Space));
+ function tokenRangeFrom(tokens: ReadonlyArray): TokenRange {
+ return { tokens, isSpecific: true };
+ }
- // These rules are higher in priority than user-configurable rules.
- this.HighPriorityCommonRules = [
- this.IgnoreBeforeComment, this.IgnoreAfterLineComment,
- this.NoSpaceBeforeColon, this.SpaceAfterColon, this.NoSpaceBeforeQuestionMark, this.SpaceAfterQuestionMarkInConditionalOperator,
- this.NoSpaceAfterQuestionMark,
- this.NoSpaceBeforeDot, this.NoSpaceAfterDot,
- this.NoSpaceAfterUnaryPrefixOperator,
- this.NoSpaceAfterUnaryPreincrementOperator, this.NoSpaceAfterUnaryPredecrementOperator,
- this.NoSpaceBeforeUnaryPostincrementOperator, this.NoSpaceBeforeUnaryPostdecrementOperator,
- this.SpaceAfterPostincrementWhenFollowedByAdd,
- this.SpaceAfterAddWhenFollowedByUnaryPlus, this.SpaceAfterAddWhenFollowedByPreincrement,
- this.SpaceAfterPostdecrementWhenFollowedBySubtract,
- this.SpaceAfterSubtractWhenFollowedByUnaryMinus, this.SpaceAfterSubtractWhenFollowedByPredecrement,
- this.NoSpaceAfterCloseBrace,
- this.NewLineBeforeCloseBraceInBlockContext,
- this.SpaceAfterCloseBrace, this.SpaceBetweenCloseBraceAndElse, this.SpaceBetweenCloseBraceAndWhile, this.NoSpaceBetweenEmptyBraceBrackets,
- this.NoSpaceBetweenFunctionKeywordAndStar, this.SpaceAfterStarInGeneratorDeclaration,
- this.SpaceAfterFunctionInFuncDecl, this.NewLineAfterOpenBraceInBlockContext, this.SpaceAfterGetSetInMember,
- this.NoSpaceBetweenYieldKeywordAndStar, this.SpaceBetweenYieldOrYieldStarAndOperand,
- this.NoSpaceBetweenReturnAndSemicolon,
- this.SpaceAfterCertainKeywords,
- this.SpaceAfterLetConstInVariableDeclaration,
- this.NoSpaceBeforeOpenParenInFuncCall,
- this.SpaceBeforeBinaryKeywordOperator, this.SpaceAfterBinaryKeywordOperator,
- this.SpaceAfterVoidOperator,
- this.SpaceBetweenAsyncAndOpenParen, this.SpaceBetweenAsyncAndFunctionKeyword,
- this.NoSpaceBetweenTagAndTemplateString,
- this.SpaceBeforeJsxAttribute, this.SpaceBeforeSlashInJsxOpeningElement, this.NoSpaceBeforeGreaterThanTokenInJsxOpeningElement,
- this.NoSpaceBeforeEqualInJsxAttribute, this.NoSpaceAfterEqualInJsxAttribute,
+ function toTokenRange(arg: SyntaxKind | ReadonlyArray | TokenRange): TokenRange {
+ return typeof arg === "number" ? tokenRangeFrom([arg]) : isArray(arg) ? tokenRangeFrom(arg) : arg;
+ }
- // TypeScript-specific rules
- this.NoSpaceAfterModuleImport,
- this.SpaceAfterCertainTypeScriptKeywords, this.SpaceBeforeCertainTypeScriptKeywords,
- this.SpaceAfterModuleName,
- this.SpaceBeforeArrow, this.SpaceAfterArrow,
- this.NoSpaceAfterEllipsis,
- this.NoSpaceAfterOptionalParameters,
- this.NoSpaceBetweenEmptyInterfaceBraceBrackets,
- this.NoSpaceBeforeOpenAngularBracket,
- this.NoSpaceBetweenCloseParenAndAngularBracket,
- this.NoSpaceAfterOpenAngularBracket,
- this.NoSpaceBeforeCloseAngularBracket,
- this.NoSpaceAfterCloseAngularBracket,
- this.SpaceBeforeAt,
- this.NoSpaceAfterAt,
- this.SpaceAfterDecorator,
- this.NoSpaceBeforeNonNullAssertionOperator,
- this.NoSpaceAfterNewKeywordOnConstructorSignature
- ];
-
- // These rules are applied after high priority rules.
- this.UserConfigurableRules = [
- this.SpaceAfterConstructor, this.NoSpaceAfterConstructor,
- this.SpaceAfterComma, this.NoSpaceAfterComma,
- this.SpaceAfterAnonymousFunctionKeyword, this.NoSpaceAfterAnonymousFunctionKeyword,
- this.SpaceAfterKeywordInControl, this.NoSpaceAfterKeywordInControl,
- this.SpaceAfterOpenParen, this.SpaceBeforeCloseParen, this.SpaceBetweenOpenParens, this.NoSpaceBetweenParens, this.NoSpaceAfterOpenParen, this.NoSpaceBeforeCloseParen,
- this.SpaceAfterOpenBracket, this.SpaceBeforeCloseBracket, this.NoSpaceBetweenBrackets, this.NoSpaceAfterOpenBracket, this.NoSpaceBeforeCloseBracket,
- this.SpaceAfterOpenBrace, this.SpaceBeforeCloseBrace, this.NoSpaceBetweenEmptyBraceBrackets, this.NoSpaceAfterOpenBrace, this.NoSpaceBeforeCloseBrace,
- this.SpaceAfterTemplateHeadAndMiddle, this.SpaceBeforeTemplateMiddleAndTail, this.NoSpaceAfterTemplateHeadAndMiddle, this.NoSpaceBeforeTemplateMiddleAndTail,
- this.SpaceAfterOpenBraceInJsxExpression, this.SpaceBeforeCloseBraceInJsxExpression, this.NoSpaceAfterOpenBraceInJsxExpression, this.NoSpaceBeforeCloseBraceInJsxExpression,
- this.SpaceAfterSemicolonInFor, this.NoSpaceAfterSemicolonInFor,
- this.SpaceBeforeBinaryOperator, this.SpaceAfterBinaryOperator, this.NoSpaceBeforeBinaryOperator, this.NoSpaceAfterBinaryOperator,
- this.SpaceBeforeOpenParenInFuncDecl, this.NoSpaceBeforeOpenParenInFuncDecl,
- this.NewLineBeforeOpenBraceInControl,
- this.NewLineBeforeOpenBraceInFunction, this.NewLineBeforeOpenBraceInTypeScriptDeclWithBlock,
- this.SpaceAfterTypeAssertion, this.NoSpaceAfterTypeAssertion
- ];
-
- // These rules are lower in priority than user-configurable rules.
- this.LowPriorityCommonRules = [
- this.NoSpaceBeforeSemicolon,
- this.SpaceBeforeOpenBraceInControl, this.SpaceBeforeOpenBraceInFunction, this.SpaceBeforeOpenBraceInTypeScriptDeclWithBlock,
- this.NoSpaceBeforeComma,
- this.NoSpaceBeforeOpenBracket,
- this.NoSpaceAfterCloseBracket,
- this.SpaceAfterSemicolon,
- this.SpaceBetweenStatements, this.SpaceAfterTryFinally
- ];
-
- if (Debug.isDebugging) {
- const o: ts.MapLike = this;
- for (const name in o) {
- const rule = o[name];
- if (rule instanceof Rule) {
- rule.debugName = name;
- }
- }
+ function tokenRangeFromRange(from: SyntaxKind, to: SyntaxKind, except: ReadonlyArray = []): TokenRange {
+ const tokens: SyntaxKind[] = [];
+ for (let token = from; token <= to; token++) {
+ if (!contains(except, token)) {
+ tokens.push(token);
}
}
+ return tokenRangeFrom(tokens);
+ }
- ///
- /// Contexts
- ///
+ ///
+ /// Contexts
+ ///
- static IsOptionEnabled(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean {
- return (context) => context.options && context.options.hasOwnProperty(optionName) && !!context.options[optionName];
- }
+ function isOptionEnabled(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean {
+ return (context) => context.options && context.options.hasOwnProperty(optionName) && !!context.options[optionName];
+ }
- static IsOptionDisabled(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean {
- return (context) => context.options && context.options.hasOwnProperty(optionName) && !context.options[optionName];
- }
+ function isOptionDisabled(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean {
+ return (context) => context.options && context.options.hasOwnProperty(optionName) && !context.options[optionName];
+ }
- static IsOptionDisabledOrUndefined(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean {
- return (context) => !context.options || !context.options.hasOwnProperty(optionName) || !context.options[optionName];
- }
+ function isOptionDisabledOrUndefined(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean {
+ return (context) => !context.options || !context.options.hasOwnProperty(optionName) || !context.options[optionName];
+ }
- static isOptionDisabledOrUndefinedOrTokensOnSameLine(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean {
- return (context) => !context.options || !context.options.hasOwnProperty(optionName) || !context.options[optionName] || context.TokensAreOnSameLine();
- }
+ function isOptionDisabledOrUndefinedOrTokensOnSameLine(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean {
+ return (context) => !context.options || !context.options.hasOwnProperty(optionName) || !context.options[optionName] || context.TokensAreOnSameLine();
+ }
- static IsOptionEnabledOrUndefined(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean {
- return (context) => !context.options || !context.options.hasOwnProperty(optionName) || !!context.options[optionName];
- }
+ function isOptionEnabledOrUndefined(optionName: keyof FormatCodeSettings): (context: FormattingContext) => boolean {
+ return (context) => !context.options || !context.options.hasOwnProperty(optionName) || !!context.options[optionName];
+ }
- static IsForContext(context: FormattingContext): boolean {
- return context.contextNode.kind === SyntaxKind.ForStatement;
- }
+ function isForContext(context: FormattingContext): boolean {
+ return context.contextNode.kind === SyntaxKind.ForStatement;
+ }
- static IsNotForContext(context: FormattingContext): boolean {
- return !Rules.IsForContext(context);
- }
+ function isNotForContext(context: FormattingContext): boolean {
+ return !isForContext(context);
+ }
- static IsBinaryOpContext(context: FormattingContext): boolean {
+ function isBinaryOpContext(context: FormattingContext): boolean {
- switch (context.contextNode.kind) {
- case SyntaxKind.BinaryExpression:
- case SyntaxKind.ConditionalExpression:
- case SyntaxKind.AsExpression:
- case SyntaxKind.ExportSpecifier:
- case SyntaxKind.ImportSpecifier:
- case SyntaxKind.TypePredicate:
- case SyntaxKind.UnionType:
- case SyntaxKind.IntersectionType:
- return true;
-
- // equals in binding elements: function foo([[x, y] = [1, 2]])
- case SyntaxKind.BindingElement:
- // equals in type X = ...
- case SyntaxKind.TypeAliasDeclaration:
- // equal in import a = module('a');
- case SyntaxKind.ImportEqualsDeclaration:
- // equal in let a = 0;
- case SyntaxKind.VariableDeclaration:
- // equal in p = 0;
- case SyntaxKind.Parameter:
- case SyntaxKind.EnumMember:
- case SyntaxKind.PropertyDeclaration:
- case SyntaxKind.PropertySignature:
- return context.currentTokenSpan.kind === SyntaxKind.EqualsToken || context.nextTokenSpan.kind === SyntaxKind.EqualsToken;
- // "in" keyword in for (let x in []) { }
- case SyntaxKind.ForInStatement:
- // "in" keyword in [P in keyof T]: T[P]
- case SyntaxKind.TypeParameter:
- return context.currentTokenSpan.kind === SyntaxKind.InKeyword || context.nextTokenSpan.kind === SyntaxKind.InKeyword;
- // Technically, "of" is not a binary operator, but format it the same way as "in"
- case SyntaxKind.ForOfStatement:
- return context.currentTokenSpan.kind === SyntaxKind.OfKeyword || context.nextTokenSpan.kind === SyntaxKind.OfKeyword;
- }
- return false;
- }
-
- static IsNotBinaryOpContext(context: FormattingContext): boolean {
- return !Rules.IsBinaryOpContext(context);
- }
-
- static IsConditionalOperatorContext(context: FormattingContext): boolean {
- return context.contextNode.kind === SyntaxKind.ConditionalExpression;
- }
-
- static IsSameLineTokenOrBeforeBlockContext(context: FormattingContext): boolean {
- return context.TokensAreOnSameLine() || Rules.IsBeforeBlockContext(context);
- }
-
- static IsBraceWrappedContext(context: FormattingContext): boolean {
- return context.contextNode.kind === SyntaxKind.ObjectBindingPattern || Rules.IsSingleLineBlockContext(context);
- }
-
- // This check is done before an open brace in a control construct, a function, or a typescript block declaration
- static IsBeforeMultilineBlockContext(context: FormattingContext): boolean {
- return Rules.IsBeforeBlockContext(context) && !(context.NextNodeAllOnSameLine() || context.NextNodeBlockIsOnOneLine());
- }
-
- static IsMultilineBlockContext(context: FormattingContext): boolean {
- return Rules.IsBlockContext(context) && !(context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine());
- }
-
- static IsSingleLineBlockContext(context: FormattingContext): boolean {
- return Rules.IsBlockContext(context) && (context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine());
- }
-
- static IsBlockContext(context: FormattingContext): boolean {
- return Rules.NodeIsBlockContext(context.contextNode);
- }
-
- static IsBeforeBlockContext(context: FormattingContext): boolean {
- return Rules.NodeIsBlockContext(context.nextTokenParent);
- }
-
- // IMPORTANT!!! This method must return true ONLY for nodes with open and close braces as immediate children
- static NodeIsBlockContext(node: Node): boolean {
- if (Rules.NodeIsTypeScriptDeclWithBlockContext(node)) {
- // This means we are in a context that looks like a block to the user, but in the grammar is actually not a node (it's a class, module, enum, object type literal, etc).
+ switch (context.contextNode.kind) {
+ case SyntaxKind.BinaryExpression:
+ case SyntaxKind.ConditionalExpression:
+ case SyntaxKind.AsExpression:
+ case SyntaxKind.ExportSpecifier:
+ case SyntaxKind.ImportSpecifier:
+ case SyntaxKind.TypePredicate:
+ case SyntaxKind.UnionType:
+ case SyntaxKind.IntersectionType:
return true;
- }
- switch (node.kind) {
- case SyntaxKind.Block:
- case SyntaxKind.CaseBlock:
- case SyntaxKind.ObjectLiteralExpression:
- case SyntaxKind.ModuleBlock:
+ // equals in binding elements: function foo([[x, y] = [1, 2]])
+ case SyntaxKind.BindingElement:
+ // equals in type X = ...
+ case SyntaxKind.TypeAliasDeclaration:
+ // equal in import a = module('a');
+ case SyntaxKind.ImportEqualsDeclaration:
+ // equal in let a = 0;
+ case SyntaxKind.VariableDeclaration:
+ // equal in p = 0;
+ case SyntaxKind.Parameter:
+ case SyntaxKind.EnumMember:
+ case SyntaxKind.PropertyDeclaration:
+ case SyntaxKind.PropertySignature:
+ return context.currentTokenSpan.kind === SyntaxKind.EqualsToken || context.nextTokenSpan.kind === SyntaxKind.EqualsToken;
+ // "in" keyword in for (let x in []) { }
+ case SyntaxKind.ForInStatement:
+ // "in" keyword in [P in keyof T]: T[P]
+ case SyntaxKind.TypeParameter:
+ return context.currentTokenSpan.kind === SyntaxKind.InKeyword || context.nextTokenSpan.kind === SyntaxKind.InKeyword;
+ // Technically, "of" is not a binary operator, but format it the same way as "in"
+ case SyntaxKind.ForOfStatement:
+ return context.currentTokenSpan.kind === SyntaxKind.OfKeyword || context.nextTokenSpan.kind === SyntaxKind.OfKeyword;
+ }
+ return false;
+ }
+
+ function isNotBinaryOpContext(context: FormattingContext): boolean {
+ return !isBinaryOpContext(context);
+ }
+
+ function isConditionalOperatorContext(context: FormattingContext): boolean {
+ return context.contextNode.kind === SyntaxKind.ConditionalExpression;
+ }
+
+ function isSameLineTokenOrBeforeBlockContext(context: FormattingContext): boolean {
+ return context.TokensAreOnSameLine() || isBeforeBlockContext(context);
+ }
+
+ function isBraceWrappedContext(context: FormattingContext): boolean {
+ return context.contextNode.kind === SyntaxKind.ObjectBindingPattern || isSingleLineBlockContext(context);
+ }
+
+ // This check is done before an open brace in a control construct, a function, or a typescript block declaration
+ function isBeforeMultilineBlockContext(context: FormattingContext): boolean {
+ return isBeforeBlockContext(context) && !(context.NextNodeAllOnSameLine() || context.NextNodeBlockIsOnOneLine());
+ }
+
+ function isMultilineBlockContext(context: FormattingContext): boolean {
+ return isBlockContext(context) && !(context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine());
+ }
+
+ function isSingleLineBlockContext(context: FormattingContext): boolean {
+ return isBlockContext(context) && (context.ContextNodeAllOnSameLine() || context.ContextNodeBlockIsOnOneLine());
+ }
+
+ function isBlockContext(context: FormattingContext): boolean {
+ return nodeIsBlockContext(context.contextNode);
+ }
+
+ function isBeforeBlockContext(context: FormattingContext): boolean {
+ return nodeIsBlockContext(context.nextTokenParent);
+ }
+
+ // IMPORTANT!!! This method must return true ONLY for nodes with open and close braces as immediate children
+ function nodeIsBlockContext(node: Node): boolean {
+ if (nodeIsTypeScriptDeclWithBlockContext(node)) {
+ // This means we are in a context that looks like a block to the user, but in the grammar is actually not a node (it's a class, module, enum, object type literal, etc).
+ return true;
+ }
+
+ switch (node.kind) {
+ case SyntaxKind.Block:
+ case SyntaxKind.CaseBlock:
+ case SyntaxKind.ObjectLiteralExpression:
+ case SyntaxKind.ModuleBlock:
+ return true;
+ }
+
+ return false;
+ }
+
+ function isFunctionDeclContext(context: FormattingContext): boolean {
+ switch (context.contextNode.kind) {
+ case SyntaxKind.FunctionDeclaration:
+ case SyntaxKind.MethodDeclaration:
+ case SyntaxKind.MethodSignature:
+ // case SyntaxKind.MemberFunctionDeclaration:
+ case SyntaxKind.GetAccessor:
+ case SyntaxKind.SetAccessor:
+ // case SyntaxKind.MethodSignature:
+ case SyntaxKind.CallSignature:
+ case SyntaxKind.FunctionExpression:
+ case SyntaxKind.Constructor:
+ case SyntaxKind.ArrowFunction:
+ // case SyntaxKind.ConstructorDeclaration:
+ // case SyntaxKind.SimpleArrowFunctionExpression:
+ // case SyntaxKind.ParenthesizedArrowFunctionExpression:
+ case SyntaxKind.InterfaceDeclaration: // This one is not truly a function, but for formatting purposes, it acts just like one
+ return true;
+ }
+
+ return false;
+ }
+
+ function isFunctionDeclarationOrFunctionExpressionContext(context: FormattingContext): boolean {
+ return context.contextNode.kind === SyntaxKind.FunctionDeclaration || context.contextNode.kind === SyntaxKind.FunctionExpression;
+ }
+
+ function isTypeScriptDeclWithBlockContext(context: FormattingContext): boolean {
+ return nodeIsTypeScriptDeclWithBlockContext(context.contextNode);
+ }
+
+ function nodeIsTypeScriptDeclWithBlockContext(node: Node): boolean {
+ switch (node.kind) {
+ case SyntaxKind.ClassDeclaration:
+ case SyntaxKind.ClassExpression:
+ case SyntaxKind.InterfaceDeclaration:
+ case SyntaxKind.EnumDeclaration:
+ case SyntaxKind.TypeLiteral:
+ case SyntaxKind.ModuleDeclaration:
+ case SyntaxKind.ExportDeclaration:
+ case SyntaxKind.NamedExports:
+ case SyntaxKind.ImportDeclaration:
+ case SyntaxKind.NamedImports:
+ return true;
+ }
+
+ return false;
+ }
+
+ function isAfterCodeBlockContext(context: FormattingContext): boolean {
+ switch (context.currentTokenParent.kind) {
+ case SyntaxKind.ClassDeclaration:
+ case SyntaxKind.ModuleDeclaration:
+ case SyntaxKind.EnumDeclaration:
+ case SyntaxKind.CatchClause:
+ case SyntaxKind.ModuleBlock:
+ case SyntaxKind.SwitchStatement:
+ return true;
+ case SyntaxKind.Block: {
+ const blockParent = context.currentTokenParent.parent;
+ // In a codefix scenario, we can't rely on parents being set. So just always return true.
+ if (!blockParent || blockParent.kind !== SyntaxKind.ArrowFunction && blockParent.kind !== SyntaxKind.FunctionExpression) {
return true;
- }
-
- return false;
- }
-
- static IsFunctionDeclContext(context: FormattingContext): boolean {
- switch (context.contextNode.kind) {
- case SyntaxKind.FunctionDeclaration:
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.MethodSignature:
- // case SyntaxKind.MemberFunctionDeclaration:
- case SyntaxKind.GetAccessor:
- case SyntaxKind.SetAccessor:
- // case SyntaxKind.MethodSignature:
- case SyntaxKind.CallSignature:
- case SyntaxKind.FunctionExpression:
- case SyntaxKind.Constructor:
- case SyntaxKind.ArrowFunction:
- // case SyntaxKind.ConstructorDeclaration:
- // case SyntaxKind.SimpleArrowFunctionExpression:
- // case SyntaxKind.ParenthesizedArrowFunctionExpression:
- case SyntaxKind.InterfaceDeclaration: // This one is not truly a function, but for formatting purposes, it acts just like one
- return true;
- }
-
- return false;
- }
-
- static IsFunctionDeclarationOrFunctionExpressionContext(context: FormattingContext): boolean {
- return context.contextNode.kind === SyntaxKind.FunctionDeclaration || context.contextNode.kind === SyntaxKind.FunctionExpression;
- }
-
- static IsTypeScriptDeclWithBlockContext(context: FormattingContext): boolean {
- return Rules.NodeIsTypeScriptDeclWithBlockContext(context.contextNode);
- }
-
- static NodeIsTypeScriptDeclWithBlockContext(node: Node): boolean {
- switch (node.kind) {
- case SyntaxKind.ClassDeclaration:
- case SyntaxKind.ClassExpression:
- case SyntaxKind.InterfaceDeclaration:
- case SyntaxKind.EnumDeclaration:
- case SyntaxKind.TypeLiteral:
- case SyntaxKind.ModuleDeclaration:
- case SyntaxKind.ExportDeclaration:
- case SyntaxKind.NamedExports:
- case SyntaxKind.ImportDeclaration:
- case SyntaxKind.NamedImports:
- return true;
- }
-
- return false;
- }
-
- static IsAfterCodeBlockContext(context: FormattingContext): boolean {
- switch (context.currentTokenParent.kind) {
- case SyntaxKind.ClassDeclaration:
- case SyntaxKind.ModuleDeclaration:
- case SyntaxKind.EnumDeclaration:
- case SyntaxKind.CatchClause:
- case SyntaxKind.ModuleBlock:
- case SyntaxKind.SwitchStatement:
- return true;
- case SyntaxKind.Block: {
- const blockParent = context.currentTokenParent.parent;
- // In a codefix scenario, we can't rely on parents being set. So just always return true.
- if (!blockParent || blockParent.kind !== SyntaxKind.ArrowFunction && blockParent.kind !== SyntaxKind.FunctionExpression) {
- return true;
- }
}
}
- return false;
}
+ return false;
+ }
- static IsControlDeclContext(context: FormattingContext): boolean {
- switch (context.contextNode.kind) {
- case SyntaxKind.IfStatement:
- case SyntaxKind.SwitchStatement:
- case SyntaxKind.ForStatement:
- case SyntaxKind.ForInStatement:
- case SyntaxKind.ForOfStatement:
- case SyntaxKind.WhileStatement:
- case SyntaxKind.TryStatement:
- case SyntaxKind.DoStatement:
- case SyntaxKind.WithStatement:
- // TODO
- // case SyntaxKind.ElseClause:
- case SyntaxKind.CatchClause:
- return true;
+ function isControlDeclContext(context: FormattingContext): boolean {
+ switch (context.contextNode.kind) {
+ case SyntaxKind.IfStatement:
+ case SyntaxKind.SwitchStatement:
+ case SyntaxKind.ForStatement:
+ case SyntaxKind.ForInStatement:
+ case SyntaxKind.ForOfStatement:
+ case SyntaxKind.WhileStatement:
+ case SyntaxKind.TryStatement:
+ case SyntaxKind.DoStatement:
+ case SyntaxKind.WithStatement:
+ // TODO
+ // case SyntaxKind.ElseClause:
+ case SyntaxKind.CatchClause:
+ return true;
- default:
- return false;
- }
- }
-
- static IsObjectContext(context: FormattingContext): boolean {
- return context.contextNode.kind === SyntaxKind.ObjectLiteralExpression;
- }
-
- static IsFunctionCallContext(context: FormattingContext): boolean {
- return context.contextNode.kind === SyntaxKind.CallExpression;
- }
-
- static IsNewContext(context: FormattingContext): boolean {
- return context.contextNode.kind === SyntaxKind.NewExpression;
- }
-
- static IsFunctionCallOrNewContext(context: FormattingContext): boolean {
- return Rules.IsFunctionCallContext(context) || Rules.IsNewContext(context);
- }
-
- static IsPreviousTokenNotComma(context: FormattingContext): boolean {
- return context.currentTokenSpan.kind !== SyntaxKind.CommaToken;
- }
-
- static IsNextTokenNotCloseBracket(context: FormattingContext): boolean {
- return context.nextTokenSpan.kind !== SyntaxKind.CloseBracketToken;
- }
-
- static IsArrowFunctionContext(context: FormattingContext): boolean {
- return context.contextNode.kind === SyntaxKind.ArrowFunction;
- }
-
- static IsNonJsxSameLineTokenContext(context: FormattingContext): boolean {
- 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 IsNextTokenParentJsxAttribute(context: FormattingContext): boolean {
- return context.nextTokenParent.kind === SyntaxKind.JsxAttribute;
- }
-
- static IsJsxAttributeContext(context: FormattingContext): boolean {
- return context.contextNode.kind === SyntaxKind.JsxAttribute;
- }
-
- static IsJsxSelfClosingElementContext(context: FormattingContext): boolean {
- return context.contextNode.kind === SyntaxKind.JsxSelfClosingElement;
- }
-
- static IsNotBeforeBlockInFunctionDeclarationContext(context: FormattingContext): boolean {
- return !Rules.IsFunctionDeclContext(context) && !Rules.IsBeforeBlockContext(context);
- }
-
- static IsEndOfDecoratorContextOnSameLine(context: FormattingContext): boolean {
- return context.TokensAreOnSameLine() &&
- context.contextNode.decorators &&
- Rules.NodeIsInDecoratorContext(context.currentTokenParent) &&
- !Rules.NodeIsInDecoratorContext(context.nextTokenParent);
- }
-
- static NodeIsInDecoratorContext(node: Node): boolean {
- while (isExpressionNode(node)) {
- node = node.parent;
- }
- return node.kind === SyntaxKind.Decorator;
- }
-
- static IsStartOfVariableDeclarationList(context: FormattingContext): boolean {
- return context.currentTokenParent.kind === SyntaxKind.VariableDeclarationList &&
- context.currentTokenParent.getStart(context.sourceFile) === context.currentTokenSpan.pos;
- }
-
- static IsNotFormatOnEnter(context: FormattingContext): boolean {
- return context.formattingRequestKind !== FormattingRequestKind.FormatOnEnter;
- }
-
- static IsModuleDeclContext(context: FormattingContext): boolean {
- return context.contextNode.kind === SyntaxKind.ModuleDeclaration;
- }
-
- static IsObjectTypeContext(context: FormattingContext): boolean {
- return context.contextNode.kind === SyntaxKind.TypeLiteral; // && context.contextNode.parent.kind !== SyntaxKind.InterfaceDeclaration;
- }
-
- static IsConstructorSignatureContext(context: FormattingContext): boolean {
- return context.contextNode.kind === SyntaxKind.ConstructSignature;
- }
-
- static IsTypeArgumentOrParameterOrAssertion(token: TextRangeWithKind, parent: Node): boolean {
- if (token.kind !== SyntaxKind.LessThanToken && token.kind !== SyntaxKind.GreaterThanToken) {
+ default:
return false;
- }
- switch (parent.kind) {
- case SyntaxKind.TypeReference:
- case SyntaxKind.TypeAssertionExpression:
- case SyntaxKind.TypeAliasDeclaration:
- case SyntaxKind.ClassDeclaration:
- case SyntaxKind.ClassExpression:
- case SyntaxKind.InterfaceDeclaration:
- case SyntaxKind.FunctionDeclaration:
- case SyntaxKind.FunctionExpression:
- case SyntaxKind.ArrowFunction:
- case SyntaxKind.MethodDeclaration:
- case SyntaxKind.MethodSignature:
- case SyntaxKind.CallSignature:
- case SyntaxKind.ConstructSignature:
- case SyntaxKind.CallExpression:
- case SyntaxKind.NewExpression:
- case SyntaxKind.ExpressionWithTypeArguments:
- return true;
- default:
- return false;
-
- }
- }
-
- static IsTypeArgumentOrParameterOrAssertionContext(context: FormattingContext): boolean {
- return Rules.IsTypeArgumentOrParameterOrAssertion(context.currentTokenSpan, context.currentTokenParent) ||
- Rules.IsTypeArgumentOrParameterOrAssertion(context.nextTokenSpan, context.nextTokenParent);
- }
-
- static IsTypeAssertionContext(context: FormattingContext): boolean {
- return context.contextNode.kind === SyntaxKind.TypeAssertionExpression;
- }
-
- static IsVoidOpContext(context: FormattingContext): boolean {
- return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind === SyntaxKind.VoidExpression;
- }
-
- static IsYieldOrYieldStarWithOperand(context: FormattingContext): boolean {
- return context.contextNode.kind === SyntaxKind.YieldExpression && (context.contextNode).expression !== undefined;
- }
-
- static IsNonNullAssertionContext(context: FormattingContext): boolean {
- return context.contextNode.kind === SyntaxKind.NonNullExpression;
}
}
-}
\ No newline at end of file
+
+ function isObjectContext(context: FormattingContext): boolean {
+ return context.contextNode.kind === SyntaxKind.ObjectLiteralExpression;
+ }
+
+ function isFunctionCallContext(context: FormattingContext): boolean {
+ return context.contextNode.kind === SyntaxKind.CallExpression;
+ }
+
+ function isNewContext(context: FormattingContext): boolean {
+ return context.contextNode.kind === SyntaxKind.NewExpression;
+ }
+
+ function isFunctionCallOrNewContext(context: FormattingContext): boolean {
+ return isFunctionCallContext(context) || isNewContext(context);
+ }
+
+ function isPreviousTokenNotComma(context: FormattingContext): boolean {
+ return context.currentTokenSpan.kind !== SyntaxKind.CommaToken;
+ }
+
+ function isNextTokenNotCloseBracket(context: FormattingContext): boolean {
+ return context.nextTokenSpan.kind !== SyntaxKind.CloseBracketToken;
+ }
+
+ function isArrowFunctionContext(context: FormattingContext): boolean {
+ return context.contextNode.kind === SyntaxKind.ArrowFunction;
+ }
+
+ function isNonJsxSameLineTokenContext(context: FormattingContext): boolean {
+ return context.TokensAreOnSameLine() && context.contextNode.kind !== SyntaxKind.JsxText;
+ }
+
+ function isNonJsxElementContext(context: FormattingContext): boolean {
+ return context.contextNode.kind !== SyntaxKind.JsxElement;
+ }
+
+ function isJsxExpressionContext(context: FormattingContext): boolean {
+ return context.contextNode.kind === SyntaxKind.JsxExpression;
+ }
+
+ function isNextTokenParentJsxAttribute(context: FormattingContext): boolean {
+ return context.nextTokenParent.kind === SyntaxKind.JsxAttribute;
+ }
+
+ function isJsxAttributeContext(context: FormattingContext): boolean {
+ return context.contextNode.kind === SyntaxKind.JsxAttribute;
+ }
+
+ function isJsxSelfClosingElementContext(context: FormattingContext): boolean {
+ return context.contextNode.kind === SyntaxKind.JsxSelfClosingElement;
+ }
+
+ function isNotBeforeBlockInFunctionDeclarationContext(context: FormattingContext): boolean {
+ return !isFunctionDeclContext(context) && !isBeforeBlockContext(context);
+ }
+
+ function isEndOfDecoratorContextOnSameLine(context: FormattingContext): boolean {
+ return context.TokensAreOnSameLine() &&
+ context.contextNode.decorators &&
+ nodeIsInDecoratorContext(context.currentTokenParent) &&
+ !nodeIsInDecoratorContext(context.nextTokenParent);
+ }
+
+ function nodeIsInDecoratorContext(node: Node): boolean {
+ while (isExpressionNode(node)) {
+ node = node.parent;
+ }
+ return node.kind === SyntaxKind.Decorator;
+ }
+
+ function isStartOfVariableDeclarationList(context: FormattingContext): boolean {
+ return context.currentTokenParent.kind === SyntaxKind.VariableDeclarationList &&
+ context.currentTokenParent.getStart(context.sourceFile) === context.currentTokenSpan.pos;
+ }
+
+ function isNotFormatOnEnter(context: FormattingContext): boolean {
+ return context.formattingRequestKind !== FormattingRequestKind.FormatOnEnter;
+ }
+
+ function isModuleDeclContext(context: FormattingContext): boolean {
+ return context.contextNode.kind === SyntaxKind.ModuleDeclaration;
+ }
+
+ function isObjectTypeContext(context: FormattingContext): boolean {
+ return context.contextNode.kind === SyntaxKind.TypeLiteral; // && context.contextNode.parent.kind !== SyntaxKind.InterfaceDeclaration;
+ }
+
+ function isConstructorSignatureContext(context: FormattingContext): boolean {
+ return context.contextNode.kind === SyntaxKind.ConstructSignature;
+ }
+
+ function isTypeArgumentOrParameterOrAssertion(token: TextRangeWithKind, parent: Node): boolean {
+ if (token.kind !== SyntaxKind.LessThanToken && token.kind !== SyntaxKind.GreaterThanToken) {
+ return false;
+ }
+ switch (parent.kind) {
+ case SyntaxKind.TypeReference:
+ case SyntaxKind.TypeAssertionExpression:
+ case SyntaxKind.TypeAliasDeclaration:
+ case SyntaxKind.ClassDeclaration:
+ case SyntaxKind.ClassExpression:
+ case SyntaxKind.InterfaceDeclaration:
+ case SyntaxKind.FunctionDeclaration:
+ case SyntaxKind.FunctionExpression:
+ case SyntaxKind.ArrowFunction:
+ case SyntaxKind.MethodDeclaration:
+ case SyntaxKind.MethodSignature:
+ case SyntaxKind.CallSignature:
+ case SyntaxKind.ConstructSignature:
+ case SyntaxKind.CallExpression:
+ case SyntaxKind.NewExpression:
+ case SyntaxKind.ExpressionWithTypeArguments:
+ return true;
+ default:
+ return false;
+
+ }
+ }
+
+ function isTypeArgumentOrParameterOrAssertionContext(context: FormattingContext): boolean {
+ return isTypeArgumentOrParameterOrAssertion(context.currentTokenSpan, context.currentTokenParent) ||
+ isTypeArgumentOrParameterOrAssertion(context.nextTokenSpan, context.nextTokenParent);
+ }
+
+ function isTypeAssertionContext(context: FormattingContext): boolean {
+ return context.contextNode.kind === SyntaxKind.TypeAssertionExpression;
+ }
+
+ function isVoidOpContext(context: FormattingContext): boolean {
+ return context.currentTokenSpan.kind === SyntaxKind.VoidKeyword && context.currentTokenParent.kind === SyntaxKind.VoidExpression;
+ }
+
+ function isYieldOrYieldStarWithOperand(context: FormattingContext): boolean {
+ return context.contextNode.kind === SyntaxKind.YieldExpression && (context.contextNode).expression !== undefined;
+ }
+
+ function isNonNullAssertionContext(context: FormattingContext): boolean {
+ return context.contextNode.kind === SyntaxKind.NonNullExpression;
+ }
+}
diff --git a/src/services/formatting/rulesMap.ts b/src/services/formatting/rulesMap.ts
index 3b04308ebe8..d44e47a763a 100644
--- a/src/services/formatting/rulesMap.ts
+++ b/src/services/formatting/rulesMap.ts
@@ -1,60 +1,59 @@
-///
+///
/* @internal */
namespace ts.formatting {
- export class RulesMap {
- public map: RulesBucket[];
- public mapRowLength: number;
+ export function getFormatContext(options: FormatCodeSettings): formatting.FormatContext {
+ return { options, getRule: getRulesMap() };
+ }
- constructor(rules: ReadonlyArray) {
- this.mapRowLength = SyntaxKind.LastToken + 1;
- this.map = new Array(this.mapRowLength * this.mapRowLength);
+ let rulesMapCache: RulesMap | undefined;
- // This array is used only during construction of the rulesbucket in the map
- const rulesBucketConstructionStateList: RulesBucketConstructionState[] = new Array(this.map.length);
- for (const rule of rules) {
- this.FillRule(rule, rulesBucketConstructionStateList);
- }
+ function getRulesMap(): RulesMap {
+ if (rulesMapCache === undefined) {
+ rulesMapCache = createRulesMap(getAllRules());
}
+ return rulesMapCache;
+ }
- private GetRuleBucketIndex(row: number, column: number): number {
- Debug.assert(row <= SyntaxKind.LastKeyword && column <= SyntaxKind.LastKeyword, "Must compute formatting context from tokens");
- return (row * this.mapRowLength) + column;
- }
+ export type RulesMap = (context: FormattingContext) => Rule | undefined;
+ function createRulesMap(rules: ReadonlyArray): RulesMap {
+ const map = buildMap(rules);
+ return context => {
+ const bucket = map[getRuleBucketIndex(context.currentTokenSpan.kind, context.nextTokenSpan.kind)];
+ return bucket && find(bucket, rule => every(rule.context, c => c(context)));
+ };
+ }
- private FillRule(rule: Rule, rulesBucketConstructionStateList: RulesBucketConstructionState[]): void {
- const specificRule = rule.descriptor.leftTokenRange.isSpecific() && rule.descriptor.rightTokenRange.isSpecific();
+ function buildMap(rules: ReadonlyArray): ReadonlyArray> {
+ // Map from bucket index to array of rules
+ const map: Rule[][] = new Array(mapRowLength * mapRowLength);
+ // This array is used only during construction of the rulesbucket in the map
+ const rulesBucketConstructionStateList = new Array(map.length);
+ for (const rule of rules) {
+ const specificRule = rule.leftTokenRange.isSpecific && rule.rightTokenRange.isSpecific;
- rule.descriptor.leftTokenRange.GetTokens().forEach((left) => {
- rule.descriptor.rightTokenRange.GetTokens().forEach((right) => {
- const rulesBucketIndex = this.GetRuleBucketIndex(left, right);
-
- let rulesBucket = this.map[rulesBucketIndex];
+ for (const left of rule.leftTokenRange.tokens) {
+ for (const right of rule.rightTokenRange.tokens) {
+ const index = getRuleBucketIndex(left, right);
+ let rulesBucket = map[index];
if (rulesBucket === undefined) {
- rulesBucket = this.map[rulesBucketIndex] = new RulesBucket();
- }
-
- rulesBucket.AddRule(rule, specificRule, rulesBucketConstructionStateList, rulesBucketIndex);
- });
- });
- }
-
- public GetRule(context: FormattingContext): Rule | undefined {
- const bucketIndex = this.GetRuleBucketIndex(context.currentTokenSpan.kind, context.nextTokenSpan.kind);
- const bucket = this.map[bucketIndex];
- if (bucket) {
- for (const rule of bucket.Rules()) {
- if (rule.operation.context.InContext(context)) {
- return rule;
+ rulesBucket = map[index] = [];
}
+ addRule(rulesBucket, rule.rule, specificRule, rulesBucketConstructionStateList, index);
}
}
- return undefined;
}
+ return map;
+ }
+
+ function getRuleBucketIndex(row: number, column: number): number {
+ Debug.assert(row <= SyntaxKind.LastKeyword && column <= SyntaxKind.LastKeyword, "Must compute formatting context from tokens");
+ return (row * mapRowLength) + column;
}
const maskBitSize = 5;
- const mask = 0x1f;
+ const mask = 0b11111; // MaskBitSize bits
+ const mapRowLength = SyntaxKind.LastToken + 1;
enum RulesPosition {
IgnoreRulesSpecific = 0,
@@ -65,92 +64,44 @@ namespace ts.formatting {
NoContextRulesAny = maskBitSize * 5
}
- export class RulesBucketConstructionState {
- private rulesInsertionIndexBitmap: number;
-
- constructor() {
- //// The Rules list contains all the inserted rules into a rulebucket in the following order:
- //// 1- Ignore rules with specific token combination
- //// 2- Ignore rules with any token combination
- //// 3- Context rules with specific token combination
- //// 4- Context rules with any token combination
- //// 5- Non-context rules with specific token combination
- //// 6- Non-context rules with any token combination
- ////
- //// The member rulesInsertionIndexBitmap is used to describe the number of rules
- //// in each sub-bucket (above) hence can be used to know the index of where to insert
- //// the next rule. It's a bitmap which contains 6 different sections each is given 5 bits.
- ////
- //// Example:
- //// In order to insert a rule to the end of sub-bucket (3), we get the index by adding
- //// the values in the bitmap segments 3rd, 2nd, and 1st.
- this.rulesInsertionIndexBitmap = 0;
- }
-
- public GetInsertionIndex(maskPosition: RulesPosition): number {
- let index = 0;
-
- let pos = 0;
- let indexBitmap = this.rulesInsertionIndexBitmap;
-
- while (pos <= maskPosition) {
- index += (indexBitmap & mask);
- indexBitmap >>= maskBitSize;
- pos += maskBitSize;
- }
-
- return index;
- }
-
- public IncreaseInsertionIndex(maskPosition: RulesPosition): void {
- let value = (this.rulesInsertionIndexBitmap >> maskPosition) & mask;
- value++;
- Debug.assert((value & mask) === value, "Adding more rules into the sub-bucket than allowed. Maximum allowed is 32 rules.");
-
- let temp = this.rulesInsertionIndexBitmap & ~(mask << maskPosition);
- temp |= value << maskPosition;
-
- this.rulesInsertionIndexBitmap = temp;
- }
+ // The Rules list contains all the inserted rules into a rulebucket in the following order:
+ // 1- Ignore rules with specific token combination
+ // 2- Ignore rules with any token combination
+ // 3- Context rules with specific token combination
+ // 4- Context rules with any token combination
+ // 5- Non-context rules with specific token combination
+ // 6- Non-context rules with any token combination
+ //
+ // The member rulesInsertionIndexBitmap is used to describe the number of rules
+ // in each sub-bucket (above) hence can be used to know the index of where to insert
+ // the next rule. It's a bitmap which contains 6 different sections each is given 5 bits.
+ //
+ // Example:
+ // In order to insert a rule to the end of sub-bucket (3), we get the index by adding
+ // the values in the bitmap segments 3rd, 2nd, and 1st.
+ function addRule(rules: Rule[], rule: Rule, specificTokens: boolean, constructionState: number[], rulesBucketIndex: number): void {
+ const position = rule.action === RuleAction.Ignore
+ ? specificTokens ? RulesPosition.IgnoreRulesSpecific : RulesPosition.IgnoreRulesAny
+ : rule.context !== anyContext
+ ? specificTokens ? RulesPosition.ContextRulesSpecific : RulesPosition.ContextRulesAny
+ : specificTokens ? RulesPosition.NoContextRulesSpecific : RulesPosition.NoContextRulesAny;
+ const state = constructionState[rulesBucketIndex] || 0;
+ rules.splice(getInsertionIndex(state, position), 0, rule);
+ constructionState[rulesBucketIndex] = increaseInsertionIndex(state, position);
}
- export class RulesBucket {
- private rules: Rule[];
-
- constructor() {
- this.rules = [];
+ function getInsertionIndex(indexBitmap: number, maskPosition: RulesPosition) {
+ let index = 0;
+ for (let pos = 0; pos <= maskPosition; pos += maskBitSize) {
+ index += indexBitmap & mask;
+ indexBitmap >>= maskBitSize;
}
+ return index;
+ }
- public Rules(): Rule[] {
- return this.rules;
- }
-
- public AddRule(rule: Rule, specificTokens: boolean, constructionState: RulesBucketConstructionState[], rulesBucketIndex: number): void {
- let position: RulesPosition;
-
- if (rule.operation.action === RuleAction.Ignore) {
- position = specificTokens ?
- RulesPosition.IgnoreRulesSpecific :
- RulesPosition.IgnoreRulesAny;
- }
- else if (!rule.operation.context.IsAny()) {
- position = specificTokens ?
- RulesPosition.ContextRulesSpecific :
- RulesPosition.ContextRulesAny;
- }
- else {
- position = specificTokens ?
- RulesPosition.NoContextRulesSpecific :
- RulesPosition.NoContextRulesAny;
- }
-
- let state = constructionState[rulesBucketIndex];
- if (state === undefined) {
- state = constructionState[rulesBucketIndex] = new RulesBucketConstructionState();
- }
- const index = state.GetInsertionIndex(position);
- this.rules.splice(index, 0, rule);
- state.IncreaseInsertionIndex(position);
- }
+ function increaseInsertionIndex(indexBitmap: number, maskPosition: RulesPosition): number {
+ const value = ((indexBitmap >> maskPosition) & mask) + 1;
+ Debug.assert((value & mask) === value, "Adding more rules into the sub-bucket than allowed. Maximum allowed is 32 rules.");
+ return (indexBitmap & ~(mask << maskPosition)) | (value << maskPosition);
}
}
\ No newline at end of file
diff --git a/src/services/formatting/rulesProvider.ts b/src/services/formatting/rulesProvider.ts
deleted file mode 100644
index fcf08541890..00000000000
--- a/src/services/formatting/rulesProvider.ts
+++ /dev/null
@@ -1,30 +0,0 @@
-///