Merged with master

This commit is contained in:
Tingan Ho
2016-03-27 02:43:32 +08:00
1489 changed files with 19553 additions and 8293 deletions
+38 -2
View File
@@ -279,6 +279,7 @@ namespace ts {
Debug.assert(!hasDynamicName(node));
const isDefaultExport = node.flags & NodeFlags.Default;
// The exported symbol for an export default function/class node is always named "default"
const name = isDefaultExport && parent ? "default" : getDeclarationName(node);
@@ -753,6 +754,7 @@ namespace ts {
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
case SyntaxKind.FunctionType:
case SyntaxKind.JSDocFunctionType:
case SyntaxKind.ConstructorType:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
@@ -900,7 +902,12 @@ namespace ts {
if (node.flags & NodeFlags.Export) {
errorOnFirstToken(node, Diagnostics.export_modifier_cannot_be_applied_to_ambient_modules_and_module_augmentations_since_they_are_always_visible);
}
declareSymbolAndAddToSymbolTable(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes);
if (isExternalModuleAugmentation(node)) {
declareSymbolAndAddToSymbolTable(node, SymbolFlags.NamespaceModule, SymbolFlags.NamespaceModuleExcludes);
}
else {
declareSymbolAndAddToSymbolTable(node, SymbolFlags.ValueModule, SymbolFlags.ValueModuleExcludes);
}
}
else {
const state = getModuleInstanceState(node);
@@ -1349,6 +1356,8 @@ namespace ts {
case SyntaxKind.ImportSpecifier:
case SyntaxKind.ExportSpecifier:
return declareSymbolAndAddToSymbolTable(<Declaration>node, SymbolFlags.Alias, SymbolFlags.AliasExcludes);
case SyntaxKind.GlobalModuleExportDeclaration:
return bindGlobalModuleExportDeclaration(<GlobalModuleExportDeclaration>node);
case SyntaxKind.ImportClause:
return bindImportClause(<ImportClause>node);
case SyntaxKind.ExportDeclaration:
@@ -1398,6 +1407,33 @@ namespace ts {
}
}
function bindGlobalModuleExportDeclaration(node: GlobalModuleExportDeclaration) {
if (node.modifiers && node.modifiers.length) {
file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Modifiers_cannot_appear_here));
}
if (node.parent.kind !== SyntaxKind.SourceFile) {
file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Global_module_exports_may_only_appear_at_top_level));
return;
}
else {
const parent = node.parent as SourceFile;
if (!isExternalModule(parent)) {
file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Global_module_exports_may_only_appear_in_module_files));
return;
}
if (!parent.isDeclarationFile) {
file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Global_module_exports_may_only_appear_in_declaration_files));
return;
}
}
file.symbol.globalExports = file.symbol.globalExports || {};
declareSymbol(file.symbol.globalExports, file.symbol, node, SymbolFlags.Alias, SymbolFlags.AliasExcludes);
}
function bindExportDeclaration(node: ExportDeclaration) {
if (!container.symbol || !container.symbol.exports) {
// Export * in some sort of block construct
@@ -1432,7 +1468,7 @@ namespace ts {
function bindModuleExportsAssignment(node: BinaryExpression) {
// 'module.exports = expr' assignment
setCommonJsModuleIndicator(node);
bindExportAssignment(node);
declareSymbol(file.symbol.exports, file.symbol, node, SymbolFlags.Property | SymbolFlags.Export | SymbolFlags.ValueModule, SymbolFlags.None);
}
function bindThisPropertyAssignment(node: BinaryExpression) {
+918 -369
View File
File diff suppressed because it is too large Load Diff
+156 -118
View File
@@ -58,12 +58,11 @@ namespace ts {
},
paramType: Diagnostics.KIND,
description: Diagnostics.Specify_JSX_code_generation_Colon_preserve_or_react,
error: Diagnostics.Argument_for_jsx_must_be_preserve_or_react
},
{
name: "reactNamespace",
type: "string",
description: Diagnostics.Specifies_the_object_invoked_for_createElement_and_spread_when_targeting_react_JSX_emit
description: Diagnostics.Specify_the_object_invoked_for_createElement_and_spread_when_targeting_react_JSX_emit
},
{
name: "listFiles",
@@ -77,7 +76,7 @@ namespace ts {
name: "mapRoot",
type: "string",
isFilePath: true,
description: Diagnostics.Specifies_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations,
description: Diagnostics.Specify_the_location_where_debugger_should_locate_map_files_instead_of_generated_locations,
paramType: Diagnostics.LOCATION,
},
{
@@ -94,7 +93,6 @@ namespace ts {
},
description: Diagnostics.Specify_module_code_generation_Colon_commonjs_amd_system_umd_or_es2015,
paramType: Diagnostics.KIND,
error: Diagnostics.Argument_for_module_option_must_be_commonjs_amd_system_umd_es2015_or_none
},
{
name: "newLine",
@@ -102,9 +100,8 @@ namespace ts {
"crlf": NewLineKind.CarriageReturnLineFeed,
"lf": NewLineKind.LineFeed
},
description: Diagnostics.Specifies_the_end_of_line_sequence_to_be_used_when_emitting_files_Colon_CRLF_dos_or_LF_unix,
description: Diagnostics.Specify_the_end_of_line_sequence_to_be_used_when_emitting_files_Colon_CRLF_dos_or_LF_unix,
paramType: Diagnostics.NEWLINE,
error: Diagnostics.Argument_for_newLine_option_must_be_CRLF_or_LF
},
{
name: "noEmit",
@@ -186,8 +183,8 @@ namespace ts {
name: "rootDir",
type: "string",
isFilePath: true,
description: Diagnostics.Specifies_the_root_directory_of_input_files_Use_to_control_the_output_directory_structure_with_outDir,
paramType: Diagnostics.LOCATION,
description: Diagnostics.Specify_the_root_directory_of_input_files_Use_to_control_the_output_directory_structure_with_outDir,
},
{
name: "isolatedModules",
@@ -202,7 +199,7 @@ namespace ts {
name: "sourceRoot",
type: "string",
isFilePath: true,
description: Diagnostics.Specifies_the_location_where_debugger_should_locate_TypeScript_files_instead_of_source_locations,
description: Diagnostics.Specify_the_location_where_debugger_should_locate_TypeScript_files_instead_of_source_locations,
paramType: Diagnostics.LOCATION,
},
{
@@ -231,9 +228,8 @@ namespace ts {
"es6": ScriptTarget.ES6,
"es2015": ScriptTarget.ES2015,
},
description: Diagnostics.Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES2015_experimental,
description: Diagnostics.Specify_ECMAScript_target_version_Colon_ES3_default_ES5_or_ES2015,
paramType: Diagnostics.VERSION,
error: Diagnostics.Argument_for_target_option_must_be_ES3_ES5_or_ES2015
},
{
name: "version",
@@ -264,8 +260,7 @@ namespace ts {
"node": ModuleResolutionKind.NodeJs,
"classic": ModuleResolutionKind.Classic,
},
description: Diagnostics.Specifies_module_resolution_strategy_Colon_node_Node_js_or_classic_TypeScript_pre_1_6,
error: Diagnostics.Argument_for_moduleResolution_option_must_be_node_or_classic,
description: Diagnostics.Specify_module_resolution_strategy_Colon_node_Node_js_or_classic_TypeScript_pre_1_6,
},
{
name: "allowUnusedLabels",
@@ -309,9 +304,13 @@ namespace ts {
// this option can only be specified in tsconfig.json
// use type = object to copy the value as-is
name: "rootDirs",
type: "object",
type: "list",
isTSConfigOnly: true,
isFilePath: true
element: {
name: "rootDirs",
type: "string",
isFilePath: true
}
},
{
name: "traceModuleResolution",
@@ -332,6 +331,35 @@ namespace ts {
name: "noImplicitUseStrict",
type: "boolean",
description: Diagnostics.Do_not_emit_use_strict_directives_in_module_output
},
{
name: "strictNullChecks",
type: "boolean",
description: Diagnostics.Enable_strict_null_checks
}
];
/* @internal */
export let typingOptionDeclarations: CommandLineOption[] = [
{
name: "enableAutoDiscovery",
type: "boolean",
},
{
name: "include",
type: "list",
element: {
name: "include",
type: "string"
}
},
{
name: "exclude",
type: "list",
element: {
name: "exclude",
type: "string"
}
}
];
@@ -361,6 +389,16 @@ namespace ts {
return optionNameMapCache;
}
/* @internal */
export function createCompilerDiagnosticForInvalidCustomType(opt: CommandLineOptionOfCustomType): Diagnostic {
const namesOfType: string[] = [];
forEachKey(opt.type, key => {
namesOfType.push(` '${key}'`);
});
return createCompilerDiagnostic(Diagnostics.Argument_for_0_option_must_be_Colon_1, `--${opt.name}`, namesOfType);
}
export function parseCommandLine(commandLine: string[], readFile?: (path: string) => string): ParsedCommandLine {
const options: CompilerOptions = {};
const fileNames: string[] = [];
@@ -414,17 +452,15 @@ namespace ts {
options[opt.name] = args[i] || "";
i++;
break;
case "list":
options[opt.name] = parseListTypeOption(<CommandLineOptionOfListType>opt, args[i]);
i++;
break;
// If not a primitive, the possible types are specified in what is effectively a map of options.
default:
let map = <Map<number>>opt.type;
let key = (args[i] || "").toLowerCase();
options[opt.name] = parseCustomTypeOption(<CommandLineOptionOfCustomType>opt, args[i]);
i++;
if (hasProperty(map, key)) {
options[opt.name] = map[key];
}
else {
errors.push(createCompilerDiagnostic((<CommandLineOptionOfCustomType>opt).error));
}
break;
}
}
}
@@ -435,6 +471,29 @@ namespace ts {
else {
fileNames.push(s);
}
function parseCustomTypeOption(opt: CommandLineOptionOfCustomType, value: string) {
const key = (value || "").trim().toLowerCase();
const map = opt.type;
if (hasProperty(map, key)) {
return map[key];
}
else {
errors.push(createCompilerDiagnosticForInvalidCustomType(opt));
}
}
function parseListTypeOption(opt: CommandLineOptionOfListType, value: string): (string | number)[] {
const values = (value || "").trim().split(",");
switch (opt.element.type) {
case "number":
return ts.map(values, parseInt);
case "string":
return ts.map(values, v => v || "");
default:
return filter(map(values, v => parseCustomTypeOption(<CommandLineOptionOfCustomType>opt.element, v)), v => !!v);
}
}
}
}
@@ -502,7 +561,6 @@ namespace ts {
}
}
/**
* Remove the comments from a json like text.
* Comments can be single line comments (starting with # or //) or multiline comments using / * * /
@@ -536,21 +594,24 @@ namespace ts {
* file to. e.g. outDir
*/
export function parseJsonConfigFileContent(json: any, host: ParseConfigHost, basePath: string, existingOptions: CompilerOptions = {}, configFileName?: string): ParsedCommandLine {
const { options: optionsFromJsonConfigFile, errors } = convertCompilerOptionsFromJson(json["compilerOptions"], basePath, configFileName);
const errors: Diagnostic[] = [];
const compilerOptions: CompilerOptions = convertCompilerOptionsFromJsonWorker(json["compilerOptions"], basePath, errors, configFileName);
const options = extend(existingOptions, compilerOptions);
const typingOptions: TypingOptions = convertTypingOptionsFromJsonWorker(json["typingOptions"], basePath, errors, configFileName);
const options = extend(existingOptions, optionsFromJsonConfigFile);
const fileNames = getFileNames(errors);
return {
options,
fileNames: getFileNames(),
typingOptions: getTypingOptions(),
fileNames,
typingOptions,
errors
};
function getFileNames(): string[] {
function getFileNames(errors: Diagnostic[]): string[] {
let fileNames: string[] = [];
if (hasProperty(json, "files")) {
if (json["files"] instanceof Array) {
if (isArray(json["files"])) {
fileNames = map(<string[]>json["files"], s => combinePaths(basePath, s));
}
else {
@@ -561,7 +622,7 @@ namespace ts {
const filesSeen: Map<boolean> = {};
let exclude: string[] = [];
if (json["exclude"] instanceof Array) {
if (isArray(json["exclude"])) {
exclude = json["exclude"];
}
else {
@@ -608,47 +669,43 @@ namespace ts {
}
return fileNames;
}
function getTypingOptions(): TypingOptions {
const options: TypingOptions = getBaseFileName(configFileName) === "jsconfig.json"
? { enableAutoDiscovery: true, include: [], exclude: [] }
: { enableAutoDiscovery: false, include: [], exclude: [] };
const jsonTypingOptions = json["typingOptions"];
if (jsonTypingOptions) {
for (const id in jsonTypingOptions) {
if (id === "enableAutoDiscovery") {
if (typeof jsonTypingOptions[id] === "boolean") {
options.enableAutoDiscovery = jsonTypingOptions[id];
}
else {
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_typing_option_0, id));
}
}
else if (id === "include") {
options.include = convertJsonOptionToStringArray(id, jsonTypingOptions[id], errors);
}
else if (id === "exclude") {
options.exclude = convertJsonOptionToStringArray(id, jsonTypingOptions[id], errors);
}
else {
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_typing_option_0, id));
}
}
}
return options;
}
}
export function convertCompilerOptionsFromJson(jsonOptions: any, basePath: string, configFileName?: string): { options: CompilerOptions, errors: Diagnostic[] } {
const options: CompilerOptions = {};
const errors: Diagnostic[] = [];
const options = convertCompilerOptionsFromJsonWorker(jsonOptions, basePath, errors, configFileName);
return { options, errors };
}
if (configFileName && getBaseFileName(configFileName) === "jsconfig.json") {
options.allowJs = true;
}
export function convertTypingOptionsFromJson(jsonOptions: any, basePath: string, configFileName?: string): { options: CompilerOptions, errors: Diagnostic[] } {
const errors: Diagnostic[] = [];
const options = convertTypingOptionsFromJsonWorker(jsonOptions, basePath, errors, configFileName);
return { options, errors };
}
function convertCompilerOptionsFromJsonWorker(jsonOptions: any,
basePath: string, errors: Diagnostic[], configFileName?: string): CompilerOptions {
const options: CompilerOptions = getBaseFileName(configFileName) === "jsconfig.json" ? { allowJs: true } : {};
convertOptionsFromJson(optionDeclarations, jsonOptions, basePath, options, Diagnostics.Unknown_compiler_option_0, errors);
return options;
}
function convertTypingOptionsFromJsonWorker(jsonOptions: any,
basePath: string, errors: Diagnostic[], configFileName?: string): TypingOptions {
const options: TypingOptions = getBaseFileName(configFileName) === "jsconfig.json"
? { enableAutoDiscovery: true, include: [], exclude: [] }
: { enableAutoDiscovery: false, include: [], exclude: [] };
convertOptionsFromJson(typingOptionDeclarations, jsonOptions, basePath, options, Diagnostics.Unknown_typing_option_0, errors);
return options;
}
function convertOptionsFromJson(optionDeclarations: CommandLineOption[], jsonOptions: any, basePath: string,
defaultOptions: CompilerOptions | TypingOptions, diagnosticMessage: DiagnosticMessage, errors: Diagnostic[]) {
if (!jsonOptions) {
return { options, errors };
return ;
}
const optionNameMap = arrayToMap(optionDeclarations, opt => opt.name);
@@ -656,69 +713,50 @@ namespace ts {
for (const id in jsonOptions) {
if (hasProperty(optionNameMap, id)) {
const opt = optionNameMap[id];
const optType = opt.type;
let value = jsonOptions[id];
const expectedType = typeof optType === "string" ? optType : "string";
if (typeof value === expectedType) {
if (typeof optType !== "string") {
const key = value.toLowerCase();
if (hasProperty(optType, key)) {
value = optType[key];
}
else {
errors.push(createCompilerDiagnostic((<CommandLineOptionOfCustomType>opt).error));
value = 0;
}
}
if (opt.isFilePath) {
switch (typeof value) {
case "string":
value = normalizePath(combinePaths(basePath, value));
break;
case "object":
// "object" options with 'isFilePath' = true expected to be string arrays
value = convertJsonOptionToStringArray(opt.name, value, errors, (element) => normalizePath(combinePaths(basePath, element)));
break;
}
if (value === "") {
value = ".";
}
}
options[opt.name] = value;
}
else {
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, id, expectedType));
}
defaultOptions[opt.name] = convertJsonOption(opt, jsonOptions[id], basePath, errors);
}
else {
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_compiler_option_0, id));
errors.push(createCompilerDiagnostic(diagnosticMessage, id));
}
}
return { options, errors };
}
function convertJsonOptionToStringArray(optionName: string, optionJson: any, errors: Diagnostic[], func?: (element: string) => string): string[] {
const items: string[] = [];
let invalidOptionType = false;
if (!isArray(optionJson)) {
invalidOptionType = true;
function convertJsonOption(opt: CommandLineOption, value: any, basePath: string, errors: Diagnostic[]): CompilerOptionsValue {
const optType = opt.type;
const expectedType = typeof optType === "string" ? optType : "string";
if (optType === "list" && isArray(value)) {
return convertJsonOptionOfListType(<CommandLineOptionOfListType>opt, value, basePath, errors);
}
else if (typeof value === expectedType) {
if (typeof optType !== "string") {
return convertJsonOptionOfCustomType(<CommandLineOptionOfCustomType>opt, value, errors);
}
else {
if (opt.isFilePath) {
value = normalizePath(combinePaths(basePath, value));
if (value === "") {
value = ".";
}
}
}
return value;
}
else {
for (const element of <any[]>optionJson) {
if (typeof element === "string") {
const item = func ? func(element) : element;
items.push(item);
}
else {
invalidOptionType = true;
break;
}
}
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, opt.name, expectedType));
}
if (invalidOptionType) {
errors.push(createCompilerDiagnostic(Diagnostics.Option_0_should_have_array_of_strings_as_a_value, optionName));
}
function convertJsonOptionOfCustomType(opt: CommandLineOptionOfCustomType, value: string, errors: Diagnostic[]) {
const key = value.toLowerCase();
if (hasProperty(opt.type, key)) {
return opt.type[key];
}
return items;
else {
errors.push(createCompilerDiagnosticForInvalidCustomType(opt));
}
}
function convertJsonOptionOfListType(option: CommandLineOptionOfListType, values: any[], basePath: string, errors: Diagnostic[]): any[] {
return filter(map(values, v => convertJsonOption(option.element, v, basePath, errors)), v => !!v);
}
}
+16 -4
View File
@@ -242,8 +242,14 @@ namespace ts {
const count = array.length;
if (count > 0) {
let pos = 0;
let result = arguments.length <= 2 ? array[pos] : initial;
pos++;
let result: T | U;
if (arguments.length <= 2) {
result = array[pos];
pos++;
}
else {
result = initial;
}
while (pos < count) {
result = f(<U>result, array[pos]);
pos++;
@@ -260,8 +266,14 @@ namespace ts {
if (array) {
let pos = array.length - 1;
if (pos >= 0) {
let result = arguments.length <= 2 ? array[pos] : initial;
pos--;
let result: T | U;
if (arguments.length <= 2) {
result = array[pos];
pos--;
}
else {
result = initial;
}
while (pos >= 0) {
result = f(<U>result, array[pos]);
pos--;
+6
View File
@@ -367,6 +367,8 @@ namespace ts {
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.UndefinedKeyword:
case SyntaxKind.NullKeyword:
case SyntaxKind.ThisType:
case SyntaxKind.StringLiteralType:
return writeTextOfNode(currentText, type);
@@ -987,6 +989,10 @@ namespace ts {
else if (!isImplementsList && node.expression.kind === SyntaxKind.NullKeyword) {
write("null");
}
else {
writer.getSymbolAccessibilityDiagnostic = getHeritageClauseVisibilityError;
resolver.writeBaseConstructorTypeOfClass(<ClassLikeDeclaration>enclosingDeclaration, enclosingDeclaration, TypeFormatFlags.UseTypeOfFunction, writer);
}
function getHeritageClauseVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic {
let diagnosticMessage: DiagnosticMessage;
+36 -24
View File
@@ -831,6 +831,18 @@
"category": "Error",
"code": 1313
},
"Global module exports may only appear in module files.": {
"category": "Error",
"code": 1314
},
"Global module exports may only appear in declaration files.": {
"category": "Error",
"code": 1315
},
"Global module exports may only appear at top level.": {
"category": "Error",
"code": 1316
},
"Duplicate identifier '{0}'.": {
"category": "Error",
"code": 2300
@@ -1091,6 +1103,10 @@
"category": "Error",
"code": 2365
},
"Function lacks ending return statement and return type does not include 'undefined'.": {
"category": "Error",
"code": 2366
},
"Type parameter name cannot be '{0}'": {
"category": "Error",
"code": 2368
@@ -1411,6 +1427,10 @@
"category": "Error",
"code": 2453
},
"Variable '{0}' is used before being assigned.": {
"category": "Error",
"code": 2454
},
"Type argument candidate '{1}' is not a valid type argument because it is not a supertype of candidate '{0}'.": {
"category": "Error",
"code": 2455
@@ -1707,6 +1727,10 @@
"category": "Error",
"code": 2530
},
"Object is possibly 'null' or 'undefined'.": {
"category": "Error",
"code": 2531
},
"JSX element attributes type '{0}' may not be a union type.": {
"category": "Error",
"code": 2600
@@ -2228,11 +2252,11 @@
"category": "Message",
"code": 6002
},
"Specifies the location where debugger should locate map files instead of generated locations.": {
"Specify the location where debugger should locate map files instead of generated locations.": {
"category": "Message",
"code": 6003
},
"Specifies the location where debugger should locate TypeScript files instead of source locations.": {
"Specify the location where debugger should locate TypeScript files instead of source locations.": {
"category": "Message",
"code": 6004
},
@@ -2264,7 +2288,7 @@
"category": "Message",
"code": 6011
},
"Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES2015' (experimental)": {
"Specify ECMAScript target version: 'ES3' (default), 'ES5', or 'ES2015'": {
"category": "Message",
"code": 6015
},
@@ -2352,14 +2376,10 @@
"category": "Error",
"code": 6045
},
"Argument for '--module' option must be 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'none'.": {
"Argument for '{0}' option must be: {1}": {
"category": "Error",
"code": 6046
},
"Argument for '--target' option must be 'ES3', 'ES5', or 'ES2015'.": {
"category": "Error",
"code": 6047
},
"Locale must be of the form <language> or <language>-<territory>. For example '{0}' or '{1}'.": {
"category": "Error",
"code": 6048
@@ -2396,7 +2416,7 @@
"category": "Message",
"code": 6056
},
"Specifies the root directory of input files. Use to control the output directory structure with --outDir.": {
"Specify the root directory of input files. Use to control the output directory structure with --outDir.": {
"category": "Message",
"code": 6058
},
@@ -2404,7 +2424,7 @@
"category": "Error",
"code": 6059
},
"Specifies the end of line sequence to be used when emitting files: 'CRLF' (dos) or 'LF' (unix).": {
"Specify the end of line sequence to be used when emitting files: 'CRLF' (dos) or 'LF' (unix).": {
"category": "Message",
"code": 6060
},
@@ -2412,14 +2432,6 @@
"category": "Message",
"code": 6061
},
"Argument for '--newLine' option must be 'CRLF' or 'LF'.": {
"category": "Error",
"code": 6062
},
"Argument for '--moduleResolution' option must be 'node' or 'classic'.": {
"category": "Error",
"code": 6063
},
"Option '{0}' can only be specified in 'tsconfig.json' file.": {
"category": "Error",
"code": 6064
@@ -2436,7 +2448,7 @@
"category": "Message",
"code": 6068
},
"Specifies module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6).": {
"Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6).": {
"category": "Message",
"code": 6069
},
@@ -2480,10 +2492,6 @@
"category": "Message",
"code": 6080
},
"Argument for '--jsx' must be 'preserve' or 'react'.": {
"category": "Message",
"code": 6081
},
"Only 'amd' and 'system' modules are supported alongside --{0}.": {
"category": "Error",
"code": 6082
@@ -2492,7 +2500,7 @@
"category": "Message",
"code": 6083
},
"Specifies the object invoked for createElement and __spread when targeting 'react' JSX emit": {
"Specify the object invoked for createElement and __spread when targeting 'react' JSX emit": {
"category": "Message",
"code": 6084
},
@@ -2608,6 +2616,10 @@
"category": "Message",
"code": 6112
},
"Enable strict null checks.": {
"category": "Message",
"code": 6113
},
"Variable '{0}' implicitly has an '{1}' type.": {
"category": "Error",
+87 -34
View File
@@ -296,11 +296,11 @@ namespace ts {
* If loop contains block scoped binding captured in some function then loop body is converted to a function.
* Lexical bindings declared in loop initializer will be passed into the loop body function as parameters,
* however if this binding is modified inside the body - this new value should be propagated back to the original binding.
* This is done by declaring new variable (out parameter holder) outside of the loop for every binding that is reassigned inside the body.
* This is done by declaring new variable (out parameter holder) outside of the loop for every binding that is reassigned inside the body.
* On every iteration this variable is initialized with value of corresponding binding.
* At every point where control flow leaves the loop either explicitly (break/continue) or implicitly (at the end of loop body)
* we copy the value inside the loop to the out parameter holder.
*
*
* for (let x;;) {
* let a = 1;
* let b = () => a;
@@ -308,9 +308,9 @@ namespace ts {
* if (...) break;
* ...
* }
*
*
* will be converted to
*
*
* var out_x;
* var loop = function(x) {
* var a = 1;
@@ -326,7 +326,7 @@ namespace ts {
* x = out_x;
* if (state === "break") break;
* }
*
*
* NOTE: values to out parameters are not copies if loop is abrupted with 'return' - in this case this will end the entire enclosing function
* so nobody can observe this new value.
*/
@@ -604,7 +604,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
write(`//# sourceMappingURL=${sourceMappingURL}`);
}
writeEmittedFiles(writer.getText(), jsFilePath, sourceMapFilePath, /*writeByteOrderMark*/ compilerOptions.emitBOM);
writeEmittedFiles(writer.getText(), jsFilePath, sourceMapFilePath, /*writeByteOrderMark*/ compilerOptions.emitBOM, sourceFiles);
// reset the state
sourceMap.reset();
@@ -748,16 +748,16 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
}
/** Write emitted output to disk */
function writeEmittedFiles(emitOutput: string, jsFilePath: string, sourceMapFilePath: string, writeByteOrderMark: boolean) {
function writeEmittedFiles(emitOutput: string, jsFilePath: string, sourceMapFilePath: string, writeByteOrderMark: boolean, sourceFiles: SourceFile[]) {
if (compilerOptions.sourceMap && !compilerOptions.inlineSourceMap) {
writeFile(host, emitterDiagnostics, sourceMapFilePath, sourceMap.getText(), /*writeByteOrderMark*/ false);
writeFile(host, emitterDiagnostics, sourceMapFilePath, sourceMap.getText(), /*writeByteOrderMark*/ false, sourceFiles);
}
if (sourceMapDataList) {
sourceMapDataList.push(sourceMap.getSourceMapData());
}
writeFile(host, emitterDiagnostics, jsFilePath, emitOutput, writeByteOrderMark);
writeFile(host, emitterDiagnostics, jsFilePath, emitOutput, writeByteOrderMark, sourceFiles);
}
// Create a temporary variable with a unique unused name.
@@ -1533,6 +1533,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
case SyntaxKind.JsxSpreadAttribute:
case SyntaxKind.JsxExpression:
case SyntaxKind.NewExpression:
case SyntaxKind.NonNullExpression:
case SyntaxKind.ParenthesizedExpression:
case SyntaxKind.PostfixUnaryExpression:
case SyntaxKind.PrefixUnaryExpression:
@@ -2077,8 +2078,10 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function parenthesizeForAccess(expr: Expression): LeftHandSideExpression {
// When diagnosing whether the expression needs parentheses, the decision should be based
// on the innermost expression in a chain of nested type assertions.
while (expr.kind === SyntaxKind.TypeAssertionExpression || expr.kind === SyntaxKind.AsExpression) {
expr = (<AssertionExpression>expr).expression;
while (expr.kind === SyntaxKind.TypeAssertionExpression ||
expr.kind === SyntaxKind.AsExpression ||
expr.kind === SyntaxKind.NonNullExpression) {
expr = (<AssertionExpression | NonNullExpression>expr).expression;
}
// isLeftHandSideExpression is almost the correct criterion for when it is not necessary
@@ -2138,6 +2141,12 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
return container && container.kind !== SyntaxKind.SourceFile;
}
// Return true if identifier resolves to an imported identifier
function isImportedReference(node: Identifier) {
const declaration = resolver.getReferencedImportDeclaration(node);
return declaration && (declaration.kind === SyntaxKind.ImportClause || declaration.kind === SyntaxKind.ImportSpecifier);
}
function emitShorthandPropertyAssignment(node: ShorthandPropertyAssignment) {
// The name property of a short-hand property assignment is considered an expression position, so here
// we manually emit the identifier to avoid rewriting.
@@ -2151,7 +2160,18 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
// let obj = { y };
// }
// Here we need to emit obj = { y : m.y } regardless of the output target.
if (modulekind !== ModuleKind.ES6 || isNamespaceExportReference(node.name)) {
// The same rules apply for imported identifiers when targeting module formats with indirect access to
// the imported identifiers. For example, when targeting CommonJS:
//
// import {foo} from './foo';
// export const baz = { foo };
//
// Must be transformed into:
//
// const foo_1 = require('./foo');
// exports.baz = { foo: foo_1.foo };
//
if (languageVersion < ScriptTarget.ES6 || (modulekind !== ModuleKind.ES6 && isImportedReference(node.name)) || isNamespaceExportReference(node.name) ) {
// Emit identifier as an identifier
write(": ");
emit(node.name);
@@ -2326,8 +2346,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
}
function skipParentheses(node: Expression): Expression {
while (node.kind === SyntaxKind.ParenthesizedExpression || node.kind === SyntaxKind.TypeAssertionExpression || node.kind === SyntaxKind.AsExpression) {
node = (<ParenthesizedExpression | AssertionExpression>node).expression;
while (node.kind === SyntaxKind.ParenthesizedExpression ||
node.kind === SyntaxKind.TypeAssertionExpression ||
node.kind === SyntaxKind.AsExpression ||
node.kind === SyntaxKind.NonNullExpression) {
node = (<ParenthesizedExpression | AssertionExpression | NonNullExpression>node).expression;
}
return node;
}
@@ -2501,13 +2524,17 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
// not the user. If we didn't want them, the emitter would not have put them
// there.
if (!nodeIsSynthesized(node) && node.parent.kind !== SyntaxKind.ArrowFunction) {
if (node.expression.kind === SyntaxKind.TypeAssertionExpression || node.expression.kind === SyntaxKind.AsExpression) {
let operand = (<TypeAssertion>node.expression).expression;
if (node.expression.kind === SyntaxKind.TypeAssertionExpression ||
node.expression.kind === SyntaxKind.AsExpression ||
node.expression.kind === SyntaxKind.NonNullExpression) {
let operand = (<TypeAssertion | NonNullExpression>node.expression).expression;
// Make sure we consider all nested cast expressions, e.g.:
// (<any><number><any>-A).x;
while (operand.kind === SyntaxKind.TypeAssertionExpression || operand.kind === SyntaxKind.AsExpression) {
operand = (<TypeAssertion>operand).expression;
while (operand.kind === SyntaxKind.TypeAssertionExpression ||
operand.kind === SyntaxKind.AsExpression ||
operand.kind === SyntaxKind.NonNullExpression) {
operand = (<TypeAssertion | NonNullExpression>operand).expression;
}
// We have an expression of the form: (<Type>SubExpr)
@@ -3073,7 +3100,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
}
writeLine();
// end of loop body -> copy out parameter
// end of loop body -> copy out parameter
copyLoopOutParameters(convertedLoopState, CopyDirection.ToOutParameter, /*emitAsStatements*/true);
decreaseIndent();
@@ -3572,7 +3599,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
}
else {
convertedLoopState.nonLocalJumps |= Jump.Continue;
// note: return value is emitted only to simplify debugging, call to converted loop body does not do any dispatching on it.
// note: return value is emitted only to simplify debugging, call to converted loop body does not do any dispatching on it.
write(`"continue";`);
}
}
@@ -4201,12 +4228,31 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
function emitVariableDeclaration(node: VariableDeclaration) {
if (isBindingPattern(node.name)) {
if (languageVersion < ScriptTarget.ES6) {
emitDestructuring(node, /*isAssignmentExpressionStatement*/ false);
}
else {
const isExported = getCombinedNodeFlags(node) & NodeFlags.Export;
if (languageVersion >= ScriptTarget.ES6 && (!isExported || modulekind === ModuleKind.ES6)) {
// emit ES6 destructuring only if target module is ES6 or variable is not exported
// exported variables in CJS/AMD are prefixed with 'exports.' so result javascript { exports.toString } = 1; is illegal
const isTopLevelDeclarationInSystemModule =
modulekind === ModuleKind.System &&
shouldHoistVariable(node, /*checkIfSourceFileLevelDecl*/true);
if (isTopLevelDeclarationInSystemModule) {
// In System modules top level variables are hoisted
// so variable declarations with destructuring are turned into destructuring assignments.
// As a result, they will need parentheses to disambiguate object binding assignments from blocks.
write("(");
}
emit(node.name);
emitOptional(" = ", node.initializer);
if (isTopLevelDeclarationInSystemModule) {
write(")");
}
}
else {
emitDestructuring(node, /*isAssignmentExpressionStatement*/ false);
}
}
else {
@@ -5261,9 +5307,11 @@ const _super = (function (geti, seti) {
function emitClassLikeDeclarationForES6AndHigher(node: ClassLikeDeclaration) {
let decoratedClassAlias: string;
const thisNodeIsDecorated = nodeIsDecorated(node);
const isHoistedDeclarationInSystemModule = shouldHoistDeclarationInSystemJsModule(node);
const isDecorated = nodeIsDecorated(node);
const rewriteAsClassExpression = isDecorated || isHoistedDeclarationInSystemModule;
if (node.kind === SyntaxKind.ClassDeclaration) {
if (thisNodeIsDecorated) {
if (rewriteAsClassExpression) {
// When we emit an ES6 class that has a class decorator, we must tailor the
// emit to certain specific cases.
//
@@ -5344,7 +5392,10 @@ const _super = (function (geti, seti) {
// [Example 4]
//
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithBodyScopedClassBinding) {
// NOTE: we reuse the same rewriting logic for cases when targeting ES6 and module kind is System.
// Because of hoisting top level class declaration need to be emitted as class expressions.
// Double bind case is only required if node is decorated.
if (isDecorated && resolver.getNodeCheckFlags(node) & NodeCheckFlags.ClassWithBodyScopedClassBinding) {
decoratedClassAlias = unescapeIdentifier(makeUniqueName(node.name ? node.name.text : "default"));
decoratedClassAliases[getNodeId(node)] = decoratedClassAlias;
write(`let ${decoratedClassAlias};`);
@@ -5355,7 +5406,9 @@ const _super = (function (geti, seti) {
write("export ");
}
write("let ");
if (!isHoistedDeclarationInSystemModule) {
write("let ");
}
emitDeclarationName(node);
if (decoratedClassAlias !== undefined) {
write(` = ${decoratedClassAlias}`);
@@ -5399,7 +5452,7 @@ const _super = (function (geti, seti) {
// emit name if
// - node has a name
// - this is default export with static initializers
if (node.name || (node.flags & NodeFlags.Default && (staticProperties.length > 0 || modulekind !== ModuleKind.ES6) && !thisNodeIsDecorated)) {
if (node.name || (node.flags & NodeFlags.Default && (staticProperties.length > 0 || modulekind !== ModuleKind.ES6) && !rewriteAsClassExpression)) {
write(" ");
emitDeclarationName(node);
}
@@ -5419,7 +5472,7 @@ const _super = (function (geti, seti) {
writeLine();
emitToken(SyntaxKind.CloseBraceToken, node.members.end);
if (thisNodeIsDecorated) {
if (rewriteAsClassExpression) {
decoratedClassAliases[getNodeId(node)] = undefined;
write(";");
}
@@ -5459,7 +5512,7 @@ const _super = (function (geti, seti) {
// module), export it
if (node.flags & NodeFlags.Default) {
// if this is a top level default export of decorated class, write the export after the declaration.
if (thisNodeIsDecorated) {
if (isDecorated) {
writeLine();
write("export default ");
emitDeclarationName(node);
@@ -7267,7 +7320,7 @@ const _super = (function (geti, seti) {
}
// text should be quoted string
// for deduplication purposes in key remove leading and trailing quotes so 'a' and "a" will be considered the same
// for deduplication purposes in key remove leading and trailing quotes so 'a' and "a" will be considered the same
const key = text.substr(1, text.length - 2);
if (hasProperty(groupIndices, key)) {
@@ -7885,9 +7938,9 @@ const _super = (function (geti, seti) {
case SyntaxKind.TaggedTemplateExpression:
return emitTaggedTemplateExpression(<TaggedTemplateExpression>node);
case SyntaxKind.TypeAssertionExpression:
return emit((<TypeAssertion>node).expression);
case SyntaxKind.AsExpression:
return emit((<AsExpression>node).expression);
case SyntaxKind.NonNullExpression:
return emit((<AssertionExpression | NonNullExpression>node).expression);
case SyntaxKind.ParenthesizedExpression:
return emitParenExpression(<ParenthesizedExpression>node);
case SyntaxKind.FunctionDeclaration:
+50 -7
View File
@@ -177,6 +177,8 @@ namespace ts {
case SyntaxKind.AsExpression:
return visitNode(cbNode, (<AsExpression>node).expression) ||
visitNode(cbNode, (<AsExpression>node).type);
case SyntaxKind.NonNullExpression:
return visitNode(cbNode, (<NonNullExpression>node).expression);
case SyntaxKind.ConditionalExpression:
return visitNode(cbNode, (<ConditionalExpression>node).condition) ||
visitNode(cbNode, (<ConditionalExpression>node).questionToken) ||
@@ -301,6 +303,9 @@ namespace ts {
case SyntaxKind.ImportClause:
return visitNode(cbNode, (<ImportClause>node).name) ||
visitNode(cbNode, (<ImportClause>node).namedBindings);
case SyntaxKind.GlobalModuleExportDeclaration:
return visitNode(cbNode, (<GlobalModuleExportDeclaration>node).name);
case SyntaxKind.NamespaceImport:
return visitNode(cbNode, (<NamespaceImport>node).name);
case SyntaxKind.NamedImports:
@@ -407,6 +412,10 @@ namespace ts {
return result;
}
export function isExternalModule(file: SourceFile): boolean {
return file.externalModuleIndicator !== undefined;
}
// Produces a new SourceFile for the 'newText' provided. The 'textChangeRange' parameter
// indicates what changed between the 'text' that this SourceFile has and the 'newText'.
// The SourceFile will be created with the compiler attempting to reuse as many nodes from
@@ -1121,7 +1130,7 @@ namespace ts {
if (token === SyntaxKind.DefaultKeyword) {
return lookAhead(nextTokenIsClassOrFunction);
}
return token !== SyntaxKind.AsteriskToken && token !== SyntaxKind.OpenBraceToken && canFollowModifier();
return token !== SyntaxKind.AsteriskToken && token !== SyntaxKind.AsKeyword && token !== SyntaxKind.OpenBraceToken && canFollowModifier();
}
if (token === SyntaxKind.DefaultKeyword) {
return nextTokenIsClassOrFunction();
@@ -2354,12 +2363,14 @@ namespace ts {
case SyntaxKind.NumberKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.UndefinedKeyword:
// If these are followed by a dot, then parse these out as a dotted type reference instead.
const node = tryParse(parseKeywordAndNoDot);
return node || parseTypeReference();
case SyntaxKind.StringLiteral:
return parseStringLiteralTypeNode();
case SyntaxKind.VoidKeyword:
case SyntaxKind.NullKeyword:
return parseTokenNode<TypeNode>();
case SyntaxKind.ThisKeyword: {
const thisKeyword = parseThisTypeNode();
@@ -2391,6 +2402,8 @@ namespace ts {
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.VoidKeyword:
case SyntaxKind.UndefinedKeyword:
case SyntaxKind.NullKeyword:
case SyntaxKind.ThisKeyword:
case SyntaxKind.TypeOfKeyword:
case SyntaxKind.OpenBraceToken:
@@ -3717,6 +3730,14 @@ namespace ts {
continue;
}
if (token === SyntaxKind.ExclamationToken && !scanner.hasPrecedingLineBreak()) {
nextToken();
const nonNullExpression = <NonNullExpression>createNode(SyntaxKind.NonNullExpression, expression.pos);
nonNullExpression.expression = expression;
expression = finishNode(nonNullExpression);
continue;
}
// when in the [Decorator] context, we do not parse ElementAccess as it could be part of a ComputedPropertyName
if (!inDecoratorContext() && parseOptional(SyntaxKind.OpenBracketToken)) {
const indexedAccess = <ElementAccessExpression>createNode(SyntaxKind.ElementAccessExpression, expression.pos);
@@ -3932,7 +3953,7 @@ namespace ts {
function tryParseAccessorDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: ModifiersArray): AccessorDeclaration {
if (parseContextualModifier(SyntaxKind.GetKeyword)) {
return parseAccessorDeclaration(SyntaxKind.GetAccessor, fullStart, decorators, modifiers);
return addJSDocComment(parseAccessorDeclaration(SyntaxKind.GetAccessor, fullStart, decorators, modifiers));
}
else if (parseContextualModifier(SyntaxKind.SetKeyword)) {
return parseAccessorDeclaration(SyntaxKind.SetAccessor, fullStart, decorators, modifiers);
@@ -4396,7 +4417,8 @@ namespace ts {
continue;
case SyntaxKind.GlobalKeyword:
return nextToken() === SyntaxKind.OpenBraceToken;
nextToken();
return token === SyntaxKind.OpenBraceToken || token === SyntaxKind.Identifier || token === SyntaxKind.ExportKeyword;
case SyntaxKind.ImportKeyword:
nextToken();
@@ -4405,7 +4427,8 @@ namespace ts {
case SyntaxKind.ExportKeyword:
nextToken();
if (token === SyntaxKind.EqualsToken || token === SyntaxKind.AsteriskToken ||
token === SyntaxKind.OpenBraceToken || token === SyntaxKind.DefaultKeyword) {
token === SyntaxKind.OpenBraceToken || token === SyntaxKind.DefaultKeyword ||
token === SyntaxKind.AsKeyword) {
return true;
}
continue;
@@ -4589,9 +4612,15 @@ namespace ts {
return parseImportDeclarationOrImportEqualsDeclaration(fullStart, decorators, modifiers);
case SyntaxKind.ExportKeyword:
nextToken();
return token === SyntaxKind.DefaultKeyword || token === SyntaxKind.EqualsToken ?
parseExportAssignment(fullStart, decorators, modifiers) :
parseExportDeclaration(fullStart, decorators, modifiers);
switch (token) {
case SyntaxKind.DefaultKeyword:
case SyntaxKind.EqualsToken:
return parseExportAssignment(fullStart, decorators, modifiers);
case SyntaxKind.AsKeyword:
return parseGlobalModuleExportDeclaration(fullStart, decorators, modifiers);
default:
return parseExportDeclaration(fullStart, decorators, modifiers);
}
default:
if (decorators || modifiers) {
// We reached this point because we encountered decorators and/or modifiers and assumed a declaration
@@ -5260,6 +5289,20 @@ namespace ts {
return nextToken() === SyntaxKind.SlashToken;
}
function parseGlobalModuleExportDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: ModifiersArray): GlobalModuleExportDeclaration {
const exportDeclaration = <GlobalModuleExportDeclaration>createNode(SyntaxKind.GlobalModuleExportDeclaration, fullStart);
exportDeclaration.decorators = decorators;
exportDeclaration.modifiers = modifiers;
parseExpected(SyntaxKind.AsKeyword);
parseExpected(SyntaxKind.NamespaceKeyword);
exportDeclaration.name = parseIdentifier();
parseExpected(SyntaxKind.SemicolonToken);
return finishNode(exportDeclaration);
}
function parseImportDeclarationOrImportEqualsDeclaration(fullStart: number, decorators: NodeArray<Decorator>, modifiers: ModifiersArray): ImportEqualsDeclaration | ImportDeclaration {
parseExpected(SyntaxKind.ImportKeyword);
const afterImportPos = scanner.getStartPos();
+23 -28
View File
@@ -931,7 +931,7 @@ namespace ts {
getSourceFile: program.getSourceFile,
getSourceFiles: program.getSourceFiles,
writeFile: writeFileCallback || (
(fileName, data, writeByteOrderMark, onError) => host.writeFile(fileName, data, writeByteOrderMark, onError)),
(fileName, data, writeByteOrderMark, onError, sourceFiles) => host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles)),
isEmitBlocked,
};
}
@@ -973,7 +973,11 @@ namespace ts {
}
if (diagnostics.length > 0 || declarationDiagnostics.length > 0) {
return { diagnostics, sourceMaps: undefined, emitSkipped: true };
return {
diagnostics: concatenate(diagnostics, declarationDiagnostics),
sourceMaps: undefined,
emitSkipped: true
};
}
}
@@ -1282,7 +1286,7 @@ namespace ts {
}
function processRootFile(fileName: string, isDefaultLib: boolean) {
processSourceFile(normalizePath(fileName), isDefaultLib);
processSourceFile(normalizePath(fileName), isDefaultLib, /*isReference*/ true);
}
function fileReferenceIsEqualTo(a: FileReference, b: FileReference): boolean {
@@ -1376,7 +1380,10 @@ namespace ts {
}
}
function processSourceFile(fileName: string, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number) {
/**
* 'isReference' indicates whether the file was brought in via a reference directive (rather than an import declaration)
*/
function processSourceFile(fileName: string, isDefaultLib: boolean, isReference: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number) {
let diagnosticArgument: string[];
let diagnostic: DiagnosticMessage;
if (hasExtension(fileName)) {
@@ -1384,7 +1391,7 @@ namespace ts {
diagnostic = Diagnostics.File_0_has_unsupported_extension_The_only_supported_extensions_are_1;
diagnosticArgument = [fileName, "'" + supportedExtensions.join("', '") + "'"];
}
else if (!findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd)) {
else if (!findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, isReference, refFile, refPos, refEnd)) {
diagnostic = Diagnostics.File_0_not_found;
diagnosticArgument = [fileName];
}
@@ -1394,13 +1401,13 @@ namespace ts {
}
}
else {
const nonTsFile: SourceFile = options.allowNonTsExtensions && findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd);
const nonTsFile: SourceFile = options.allowNonTsExtensions && findSourceFile(fileName, toPath(fileName, currentDirectory, getCanonicalFileName), isDefaultLib, isReference, refFile, refPos, refEnd);
if (!nonTsFile) {
if (options.allowNonTsExtensions) {
diagnostic = Diagnostics.File_0_not_found;
diagnosticArgument = [fileName];
}
else if (!forEach(supportedExtensions, extension => findSourceFile(fileName + extension, toPath(fileName + extension, currentDirectory, getCanonicalFileName), isDefaultLib, refFile, refPos, refEnd))) {
else if (!forEach(supportedExtensions, extension => findSourceFile(fileName + extension, toPath(fileName + extension, currentDirectory, getCanonicalFileName), isDefaultLib, isReference, refFile, refPos, refEnd))) {
diagnostic = Diagnostics.File_0_not_found;
fileName += ".ts";
diagnosticArgument = [fileName];
@@ -1429,7 +1436,7 @@ namespace ts {
}
// Get source file from normalized fileName
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile {
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, isReference: boolean, refFile?: SourceFile, refPos?: number, refEnd?: number): SourceFile {
if (filesByName.contains(path)) {
const file = filesByName.get(path);
// try to check if we've already seen this file but with a different casing in path
@@ -1438,6 +1445,10 @@ namespace ts {
reportFileNamesDifferOnlyInCasingError(fileName, file.fileName, refFile, refPos, refEnd);
}
if (file) {
file.wasReferenced = file.wasReferenced || isReference;
}
return file;
}
@@ -1454,6 +1465,7 @@ namespace ts {
filesByName.set(path, file);
if (file) {
file.wasReferenced = file.wasReferenced || isReference;
file.path = path;
if (host.useCaseSensitiveFileNames()) {
@@ -1491,7 +1503,7 @@ namespace ts {
function processReferencedFiles(file: SourceFile, basePath: string) {
forEach(file.referencedFiles, ref => {
const referencedFileName = resolveTripleslashReference(ref.fileName, file.fileName);
processSourceFile(referencedFileName, /*isDefaultLib*/ false, file, ref.pos, ref.end);
processSourceFile(referencedFileName, /*isDefaultLib*/ false, /*isReference*/ true, file, ref.pos, ref.end);
});
}
@@ -1517,7 +1529,7 @@ namespace ts {
i < file.imports.length;
if (shouldAddFile) {
const importedFile = findSourceFile(resolution.resolvedFileName, toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName), /*isDefaultLib*/ false, file, skipTrivia(file.text, file.imports[i].pos), file.imports[i].end);
const importedFile = findSourceFile(resolution.resolvedFileName, toPath(resolution.resolvedFileName, currentDirectory, getCanonicalFileName), /*isDefaultLib*/ false, /*isReference*/ false, file, skipTrivia(file.text, file.imports[i].pos), file.imports[i].end);
if (importedFile && resolution.isExternalLibraryImport) {
// Since currently irrespective of allowJs, we only look for supportedTypeScript extension external module files,
@@ -1734,24 +1746,7 @@ namespace ts {
}
}
if (options.noEmit) {
if (options.out) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noEmit", "out"));
}
if (options.outFile) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noEmit", "outFile"));
}
if (options.outDir) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noEmit", "outDir"));
}
if (options.declaration) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "noEmit", "declaration"));
}
}
else if (options.allowJs && options.declaration) {
if (!options.noEmit && options.allowJs && options.declaration) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration"));
}
+1
View File
@@ -114,6 +114,7 @@ namespace ts {
"try": SyntaxKind.TryKeyword,
"type": SyntaxKind.TypeKeyword,
"typeof": SyntaxKind.TypeOfKeyword,
"undefined": SyntaxKind.UndefinedKeyword,
"var": SyntaxKind.VarKeyword,
"void": SyntaxKind.VoidKeyword,
"while": SyntaxKind.WhileKeyword,
+54 -49
View File
@@ -1,8 +1,8 @@
/// <reference path="core.ts"/>
namespace ts {
export type FileWatcherCallback = (path: string, removed?: boolean) => void;
export type DirectoryWatcherCallback = (path: string) => void;
export type FileWatcherCallback = (fileName: string, removed?: boolean) => void;
export type DirectoryWatcherCallback = (directoryName: string) => void;
export interface System {
args: string[];
@@ -11,7 +11,7 @@ namespace ts {
write(s: string): void;
readFile(path: string, encoding?: string): string;
writeFile(path: string, data: string, writeByteOrderMark?: boolean): void;
watchFile?(path: Path, callback: FileWatcherCallback): FileWatcher;
watchFile?(path: string, callback: FileWatcherCallback): FileWatcher;
watchDirectory?(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
resolvePath(path: string): string;
fileExists(path: string): boolean;
@@ -25,7 +25,7 @@ namespace ts {
}
interface WatchedFile {
filePath: Path;
fileName: string;
callback: FileWatcherCallback;
mtime?: Date;
}
@@ -35,7 +35,7 @@ namespace ts {
}
export interface DirectoryWatcher extends FileWatcher {
directoryPath: Path;
directoryName: string;
referenceCount: number;
}
@@ -244,13 +244,13 @@ namespace ts {
return;
}
_fs.stat(watchedFile.filePath, (err: any, stats: any) => {
_fs.stat(watchedFile.fileName, (err: any, stats: any) => {
if (err) {
watchedFile.callback(watchedFile.filePath);
watchedFile.callback(watchedFile.fileName);
}
else if (watchedFile.mtime.getTime() !== stats.mtime.getTime()) {
watchedFile.mtime = getModifiedTime(watchedFile.filePath);
watchedFile.callback(watchedFile.filePath, watchedFile.mtime.getTime() === 0);
watchedFile.mtime = getModifiedTime(watchedFile.fileName);
watchedFile.callback(watchedFile.fileName, watchedFile.mtime.getTime() === 0);
}
});
}
@@ -278,11 +278,11 @@ namespace ts {
}, interval);
}
function addFile(filePath: Path, callback: FileWatcherCallback): WatchedFile {
function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile {
const file: WatchedFile = {
filePath,
fileName,
callback,
mtime: getModifiedTime(filePath)
mtime: getModifiedTime(fileName)
};
watchedFiles.push(file);
@@ -306,26 +306,26 @@ namespace ts {
}
function createWatchedFileSet() {
const dirWatchers = createFileMap<DirectoryWatcher>();
const dirWatchers: Map<DirectoryWatcher> = {};
// One file can have multiple watchers
const fileWatcherCallbacks = createFileMap<FileWatcherCallback[]>();
const fileWatcherCallbacks: Map<FileWatcherCallback[]> = {};
return { addFile, removeFile };
function reduceDirWatcherRefCountForFile(filePath: Path) {
const dirPath = getDirectoryPath(filePath);
if (dirWatchers.contains(dirPath)) {
const watcher = dirWatchers.get(dirPath);
function reduceDirWatcherRefCountForFile(fileName: string) {
const dirName = getDirectoryPath(fileName);
if (hasProperty(dirWatchers, dirName)) {
const watcher = dirWatchers[dirName];
watcher.referenceCount -= 1;
if (watcher.referenceCount <= 0) {
watcher.close();
dirWatchers.remove(dirPath);
delete dirWatchers[dirName];
}
}
}
function addDirWatcher(dirPath: Path): void {
if (dirWatchers.contains(dirPath)) {
const watcher = dirWatchers.get(dirPath);
function addDirWatcher(dirPath: string): void {
if (hasProperty(dirWatchers, dirPath)) {
const watcher = dirWatchers[dirPath];
watcher.referenceCount += 1;
return;
}
@@ -336,52 +336,52 @@ namespace ts {
(eventName: string, relativeFileName: string) => fileEventHandler(eventName, relativeFileName, dirPath)
);
watcher.referenceCount = 1;
dirWatchers.set(dirPath, watcher);
dirWatchers[dirPath] = watcher;
return;
}
function addFileWatcherCallback(filePath: Path, callback: FileWatcherCallback): void {
if (fileWatcherCallbacks.contains(filePath)) {
fileWatcherCallbacks.get(filePath).push(callback);
function addFileWatcherCallback(filePath: string, callback: FileWatcherCallback): void {
if (hasProperty(fileWatcherCallbacks, filePath)) {
fileWatcherCallbacks[filePath].push(callback);
}
else {
fileWatcherCallbacks.set(filePath, [callback]);
fileWatcherCallbacks[filePath] = [callback];
}
}
function addFile(filePath: Path, callback: FileWatcherCallback): WatchedFile {
addFileWatcherCallback(filePath, callback);
addDirWatcher(getDirectoryPath(filePath));
function addFile(fileName: string, callback: FileWatcherCallback): WatchedFile {
addFileWatcherCallback(fileName, callback);
addDirWatcher(getDirectoryPath(fileName));
return { filePath, callback };
return { fileName, callback };
}
function removeFile(watchedFile: WatchedFile) {
removeFileWatcherCallback(watchedFile.filePath, watchedFile.callback);
reduceDirWatcherRefCountForFile(watchedFile.filePath);
removeFileWatcherCallback(watchedFile.fileName, watchedFile.callback);
reduceDirWatcherRefCountForFile(watchedFile.fileName);
}
function removeFileWatcherCallback(filePath: Path, callback: FileWatcherCallback) {
if (fileWatcherCallbacks.contains(filePath)) {
const newCallbacks = copyListRemovingItem(callback, fileWatcherCallbacks.get(filePath));
function removeFileWatcherCallback(filePath: string, callback: FileWatcherCallback) {
if (hasProperty(fileWatcherCallbacks, filePath)) {
const newCallbacks = copyListRemovingItem(callback, fileWatcherCallbacks[filePath]);
if (newCallbacks.length === 0) {
fileWatcherCallbacks.remove(filePath);
delete fileWatcherCallbacks[filePath];
}
else {
fileWatcherCallbacks.set(filePath, newCallbacks);
fileWatcherCallbacks[filePath] = newCallbacks;
}
}
}
function fileEventHandler(eventName: string, relativeFileName: string, baseDirPath: Path) {
function fileEventHandler(eventName: string, relativeFileName: string, baseDirPath: string) {
// When files are deleted from disk, the triggered "rename" event would have a relativefileName of "undefined"
const filePath = typeof relativeFileName !== "string"
const fileName = typeof relativeFileName !== "string"
? undefined
: toPath(relativeFileName, baseDirPath, createGetCanonicalFileName(sys.useCaseSensitiveFileNames));
: ts.getNormalizedAbsolutePath(relativeFileName, baseDirPath);
// Some applications save a working file via rename operations
if ((eventName === "change" || eventName === "rename") && fileWatcherCallbacks.contains(filePath)) {
for (const fileCallback of fileWatcherCallbacks.get(filePath)) {
fileCallback(filePath);
if ((eventName === "change" || eventName === "rename") && hasProperty(fileWatcherCallbacks, fileName)) {
for (const fileCallback of fileWatcherCallbacks[fileName]) {
fileCallback(fileName);
}
}
}
@@ -498,6 +498,11 @@ namespace ts {
const files = _fs.readdirSync(path || ".").sort();
const directories: string[] = [];
for (const current of files) {
// This is necessary because on some file system node fails to exclude
// "." and "..". See https://github.com/nodejs/node/issues/4002
if (current === "." || current === "..") {
continue;
}
const name = combinePaths(path, current);
if (!contains(exclude, getCanonicalPath(name))) {
const stat = _fs.statSync(name);
@@ -526,18 +531,18 @@ namespace ts {
},
readFile,
writeFile,
watchFile: (filePath, callback) => {
watchFile: (fileName, callback) => {
// Node 4.0 stabilized the `fs.watch` function on Windows which avoids polling
// and is more efficient than `fs.watchFile` (ref: https://github.com/nodejs/node/pull/2649
// and https://github.com/Microsoft/TypeScript/issues/4643), therefore
// if the current node.js version is newer than 4, use `fs.watch` instead.
const watchSet = isNode4OrLater() ? watchedFileSet : pollingWatchedFileSet;
const watchedFile = watchSet.addFile(filePath, callback);
const watchedFile = watchSet.addFile(fileName, callback);
return {
close: () => watchSet.removeFile(watchedFile)
};
},
watchDirectory: (path, callback, recursive) => {
watchDirectory: (directoryName, callback, recursive) => {
// Node 4.0 `fs.watch` function supports the "recursive" option on both OSX and Windows
// (ref: https://github.com/nodejs/node/pull/2649 and https://github.com/Microsoft/TypeScript/issues/4643)
let options: any;
@@ -549,7 +554,7 @@ namespace ts {
}
return _fs.watch(
path,
directoryName,
options,
(eventName: string, relativeFileName: string) => {
// In watchDirectory we only care about adding and removing files (when event name is
@@ -557,7 +562,7 @@ namespace ts {
// event name is "change")
if (eventName === "rename") {
// When deleting a file, the passed baseFileName is null
callback(!relativeFileName ? relativeFileName : normalizePath(combinePaths(path, relativeFileName)));
callback(!relativeFileName ? relativeFileName : normalizePath(combinePaths(directoryName, relativeFileName)));
};
}
);
+5 -1
View File
@@ -386,6 +386,10 @@ namespace ts {
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
return;
}
if (isWatchSet(configParseResult.options) && !sys.watchFile) {
reportDiagnostic(createCompilerDiagnostic(Diagnostics.The_current_host_does_not_support_the_0_option, "--watch"), /* compilerHost */ undefined);
sys.exit(ExitStatus.DiagnosticsPresent_OutputsSkipped);
}
return configParseResult;
}
@@ -445,7 +449,7 @@ namespace ts {
}
// Use default host function
const sourceFile = hostGetSourceFile(fileName, languageVersion, onError);
if (sourceFile && isWatchSet(compilerOptions)) {
if (sourceFile && isWatchSet(compilerOptions) && sys.watchFile) {
// Attach a file watcher
const filePath = toPath(sourceFile.fileName, sys.getCurrentDirectory(), createGetCanonicalFileName(sys.useCaseSensitiveFileNames));
sourceFile.fileWatcher = sys.watchFile(filePath, (fileName: string, removed?: boolean) => sourceFileChanged(sourceFile, removed));
+52 -10
View File
@@ -171,6 +171,7 @@ namespace ts {
StringKeyword,
SymbolKeyword,
TypeKeyword,
UndefinedKeyword,
FromKeyword,
GlobalKeyword,
OfKeyword, // LastKeyword and LastToken
@@ -240,6 +241,7 @@ namespace ts {
OmittedExpression,
ExpressionWithTypeArguments,
AsExpression,
NonNullExpression,
// Misc
TemplateSpan,
@@ -274,6 +276,7 @@ namespace ts {
ModuleDeclaration,
ModuleBlock,
CaseBlock,
GlobalModuleExportDeclaration,
ImportEqualsDeclaration,
ImportDeclaration,
ImportClause,
@@ -474,6 +477,11 @@ namespace ts {
originalKeywordKind?: SyntaxKind; // Original syntaxKind which get set so that we can report an error later
}
// Transient identifier node (marked by id === -1)
export interface TransientIdentifier extends Identifier {
resolvedSymbol: Symbol;
}
// @kind(SyntaxKind.QualifiedName)
export interface QualifiedName extends Node {
// Must have same layout as PropertyAccess
@@ -967,6 +975,8 @@ namespace ts {
name: Identifier;
}
export type IdentifierOrPropertyAccess = Identifier | PropertyAccessExpression;
// @kind(SyntaxKind.ElementAccessExpression)
export interface ElementAccessExpression extends MemberExpression {
expression: LeftHandSideExpression;
@@ -1011,6 +1021,11 @@ namespace ts {
export type AssertionExpression = TypeAssertion | AsExpression;
// @kind(SyntaxKind.NonNullExpression)
export interface NonNullExpression extends LeftHandSideExpression {
expression: Expression;
}
/// A JSX expression of the form <TagName attrs>...</TagName>
// @kind(SyntaxKind.JsxElement)
export interface JsxElement extends PrimaryExpression {
@@ -1208,6 +1223,8 @@ namespace ts {
block: Block;
}
export type DeclarationWithTypeParameters = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration;
export interface ClassLikeDeclaration extends Declaration {
name?: Identifier;
typeParameters?: NodeArray<TypeParameterDeclaration>;
@@ -1324,6 +1341,12 @@ namespace ts {
name: Identifier;
}
// @kind(SyntaxKind.GlobalModuleImport)
export interface GlobalModuleExportDeclaration extends DeclarationStatement {
name: Identifier;
moduleReference: LiteralLikeNode;
}
// @kind(SyntaxKind.ExportDeclaration)
export interface ExportDeclaration extends DeclarationStatement {
exportClause?: NamedExports;
@@ -1537,6 +1560,8 @@ namespace ts {
/* @internal */ externalModuleIndicator: Node;
// The first node that causes this file to be a CommonJS module
/* @internal */ commonJsModuleIndicator: Node;
// True if the file was a root file in a compilation or a /// reference targets
/* @internal */ wasReferenced?: boolean;
/* @internal */ identifiers: Map<string>;
/* @internal */ nodeCount: number;
@@ -1573,7 +1598,7 @@ namespace ts {
}
export interface WriteFileCallback {
(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void): void;
(fileName: string, data: string, writeByteOrderMark: boolean, onError?: (message: string) => void, sourceFiles?: SourceFile[]): void;
}
export class OperationCanceledException { }
@@ -1889,6 +1914,7 @@ namespace ts {
writeTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
writeReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
writeTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
writeBaseConstructorTypeOfClass(node: ClassLikeDeclaration, enclosingDeclaration: Node, flags: TypeFormatFlags, writer: SymbolWriter): void;
isSymbolAccessible(symbol: Symbol, enclosingDeclaration: Node, meaning: SymbolFlags): SymbolAccessibilityResult;
isEntityNameVisible(entityName: EntityName | Expression, enclosingDeclaration: Node): SymbolVisibilityResult;
// Returns the constant value this property access resolves to, or 'undefined' for a non-constant
@@ -1994,6 +2020,7 @@ namespace ts {
members?: SymbolTable; // Class, interface or literal instance members
exports?: SymbolTable; // Module exports
globalExports?: SymbolTable; // Conditional global UMD exports
/* @internal */ id?: number; // Unique id (used to look up SymbolLinks)
/* @internal */ mergeId?: number; // Merge id (used to look up merged symbol)
/* @internal */ parent?: Symbol; // Parent symbol
@@ -2016,7 +2043,9 @@ namespace ts {
exportsChecked?: boolean; // True if exports of external module have been checked
isDeclarationWithCollidingName?: boolean; // True if symbol is block scoped redeclaration
bindingElement?: BindingElement; // Binding element associated with property symbol
exportsSomeValue?: boolean; // true if module exports some value (not just types)
exportsSomeValue?: boolean; // True if module exports some value (not just types)
firstAssignmentChecked?: boolean; // True if first assignment node has been computed
firstAssignment?: Node; // First assignment node (undefined if no assignments)
}
/* @internal */
@@ -2059,7 +2088,7 @@ namespace ts {
isVisible?: boolean; // Is this node visible
generatedName?: string; // Generated name for module, enum, or import declaration
generatedNames?: Map<string>; // Generated names table for source file
assignmentChecks?: Map<boolean>; // Cache of assignment checks
assignmentMap?: Map<boolean>; // Cached map of references assigned within this node
hasReportedStatementInAmbientContext?: boolean; // Cache boolean if we report statements in ambient context
importOnRightSide?: Symbol; // for import declarations - import that appear on the right side
jsxFlags?: JsxFlags; // flags for knowing what kind of element/attributes we're dealing with
@@ -2093,7 +2122,7 @@ namespace ts {
/* @internal */
FreshObjectLiteral = 0x00100000, // Fresh object literal type
/* @internal */
ContainsUndefinedOrNull = 0x00200000, // Type is or contains Undefined or Null type
ContainsUndefinedOrNull = 0x00200000, // Type is or contains undefined or null type
/* @internal */
ContainsObjectLiteral = 0x00400000, // Type is or contains object literal type
/* @internal */
@@ -2102,6 +2131,8 @@ namespace ts {
ThisType = 0x02000000, // This type
ObjectLiteralPatternWithComputedProperties = 0x04000000, // Object literal type implied by binding pattern has computed properties
/* @internal */
Nullable = Undefined | Null,
/* @internal */
Intrinsic = Any | String | Number | Boolean | ESSymbol | Void | Undefined | Null,
/* @internal */
@@ -2285,6 +2316,7 @@ namespace ts {
/* @internal */
export interface TypeMapper {
(t: TypeParameter): Type;
mappedTypes?: Type[]; // Types mapped by this mapper
instantiations?: Type[]; // Cache of instantiations created using this type mapper.
context?: InferenceContext; // The inference context this mapper was created from.
// Only inference mappers have this set (in createInferenceMapper).
@@ -2367,6 +2399,8 @@ namespace ts {
export type PathSubstitutions = Map<string[]>;
export type TsConfigOnlyOptions = RootPaths | PathSubstitutions;
export type CompilerOptionsValue = string | number | boolean | (string | number)[] | TsConfigOnlyOptions;
export interface CompilerOptions {
allowNonTsExtensions?: boolean;
charset?: string;
@@ -2423,6 +2457,8 @@ namespace ts {
allowSyntheticDefaultImports?: boolean;
allowJs?: boolean;
noImplicitUseStrict?: boolean;
strictNullChecks?: boolean;
lib?: string[];
/* @internal */ stripInternal?: boolean;
// Skip checking lib.d.ts to help speed up tests.
@@ -2430,7 +2466,9 @@ namespace ts {
// Do not perform validation of output file name in transpile scenarios
/* @internal */ suppressOutputPathCheck?: boolean;
[option: string]: string | number | boolean | TsConfigOnlyOptions;
list?: string[];
[option: string]: CompilerOptionsValue;
}
export interface TypingOptions {
@@ -2442,7 +2480,6 @@ namespace ts {
export interface DiscoverTypingsInfo {
fileNames: string[]; // The file names that belong to the same project.
cachePath: string; // The path to the typings cache
projectRootPath: string; // The path to the project root directory
safeListPath: string; // The path used to retrieve the safe list
packageNameToTypingLocation: Map<string>; // The map of package names to their cached typing locations
@@ -2516,7 +2553,7 @@ namespace ts {
/* @internal */
export interface CommandLineOptionBase {
name: string;
type: "string" | "number" | "boolean" | "object" | Map<number>; // a value of a primitive type, or an object literal mapping named values to actual values
type: "string" | "number" | "boolean" | "object" | "list" | Map<number | string>; // a value of a primitive type, or an object literal mapping named values to actual values
isFilePath?: boolean; // True if option value is a path or fileName
shortName?: string; // A short mnemonic for convenience - for instance, 'h' can be used in place of 'help'
description?: DiagnosticMessage; // The message describing what the command line switch does
@@ -2532,8 +2569,7 @@ namespace ts {
/* @internal */
export interface CommandLineOptionOfCustomType extends CommandLineOptionBase {
type: Map<number>; // an object literal mapping named values to actual values
error: DiagnosticMessage; // The error given when the argument does not fit a customized 'type'
type: Map<number | string>; // an object literal mapping named values to actual values
}
/* @internal */
@@ -2542,7 +2578,13 @@ namespace ts {
}
/* @internal */
export type CommandLineOption = CommandLineOptionOfCustomType | CommandLineOptionOfPrimitiveType | TsConfigOnlyOption;
export interface CommandLineOptionOfListType extends CommandLineOptionBase {
type: "list";
element: CommandLineOptionOfCustomType | CommandLineOptionOfPrimitiveType;
}
/* @internal */
export type CommandLineOption = CommandLineOptionOfCustomType | CommandLineOptionOfPrimitiveType | TsConfigOnlyOption | CommandLineOptionOfListType;
/* @internal */
export const enum CharacterCodes {
+21 -8
View File
@@ -407,10 +407,6 @@ namespace ts {
return createTextSpanFromBounds(pos, errorNode.end);
}
export function isExternalModule(file: SourceFile): boolean {
return file.externalModuleIndicator !== undefined;
}
export function isExternalOrCommonJsModule(file: SourceFile): boolean {
return (file.externalModuleIndicator || file.commonJsModuleIndicator) !== undefined;
}
@@ -515,6 +511,7 @@ namespace ts {
case SyntaxKind.StringKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.UndefinedKeyword:
return true;
case SyntaxKind.VoidKeyword:
return node.parent.kind !== SyntaxKind.VoidExpression;
@@ -956,6 +953,16 @@ namespace ts {
return node.kind === SyntaxKind.ElementAccessExpression;
}
export function isJSXTagName(node: Node) {
const parent = node.parent;
if (parent.kind === SyntaxKind.JsxOpeningElement ||
parent.kind === SyntaxKind.JsxSelfClosingElement ||
parent.kind === SyntaxKind.JsxClosingElement) {
return (<JsxOpeningLikeElement>parent).tagName === node;
}
return false;
}
export function isExpression(node: Node): boolean {
switch (node.kind) {
case SyntaxKind.SuperKeyword:
@@ -972,6 +979,7 @@ namespace ts {
case SyntaxKind.TaggedTemplateExpression:
case SyntaxKind.AsExpression:
case SyntaxKind.TypeAssertionExpression:
case SyntaxKind.NonNullExpression:
case SyntaxKind.ParenthesizedExpression:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ClassExpression:
@@ -996,9 +1004,9 @@ namespace ts {
while (node.parent.kind === SyntaxKind.QualifiedName) {
node = node.parent;
}
return node.parent.kind === SyntaxKind.TypeQuery;
return node.parent.kind === SyntaxKind.TypeQuery || isJSXTagName(node);
case SyntaxKind.Identifier:
if (node.parent.kind === SyntaxKind.TypeQuery) {
if (node.parent.kind === SyntaxKind.TypeQuery || isJSXTagName(node)) {
return true;
}
// fall through
@@ -1109,6 +1117,9 @@ namespace ts {
/// Given a BinaryExpression, returns SpecialPropertyAssignmentKind for the various kinds of property
/// assignments we treat as special in the binder
export function getSpecialPropertyAssignmentKind(expression: Node): SpecialPropertyAssignmentKind {
if (!isInJavaScriptFile(expression)) {
return SpecialPropertyAssignmentKind.None;
}
if (expression.kind !== SyntaxKind.BinaryExpression) {
return SpecialPropertyAssignmentKind.None;
}
@@ -1475,6 +1486,7 @@ namespace ts {
// export default ...
export function isAliasSymbolDeclaration(node: Node): boolean {
return node.kind === SyntaxKind.ImportEqualsDeclaration ||
node.kind === SyntaxKind.GlobalModuleExportDeclaration ||
node.kind === SyntaxKind.ImportClause && !!(<ImportClause>node).name ||
node.kind === SyntaxKind.NamespaceImport ||
node.kind === SyntaxKind.ImportSpecifier ||
@@ -2110,10 +2122,10 @@ namespace ts {
return combinePaths(newDirPath, sourceFilePath);
}
export function writeFile(host: EmitHost, diagnostics: DiagnosticCollection, fileName: string, data: string, writeByteOrderMark: boolean) {
export function writeFile(host: EmitHost, diagnostics: DiagnosticCollection, fileName: string, data: string, writeByteOrderMark: boolean, sourceFiles?: SourceFile[]) {
host.writeFile(fileName, data, writeByteOrderMark, hostErrorMessage => {
diagnostics.add(createCompilerDiagnostic(Diagnostics.Could_not_write_file_0_Colon_1, fileName, hostErrorMessage));
});
}, sourceFiles);
}
export function getLineOfLocalPosition(currentSourceFile: SourceFile, pos: number) {
@@ -2406,6 +2418,7 @@ namespace ts {
case SyntaxKind.ElementAccessExpression:
case SyntaxKind.NewExpression:
case SyntaxKind.CallExpression:
case SyntaxKind.NonNullExpression:
case SyntaxKind.JsxElement:
case SyntaxKind.JsxSelfClosingElement:
case SyntaxKind.TaggedTemplateExpression:
+1 -1
View File
@@ -88,7 +88,7 @@ class CompilerBaselineRunner extends RunnerBase {
toBeCompiled = [];
otherFiles = [];
if (/require\(/.test(lastUnit.content) || /reference\spath/.test(lastUnit.content)) {
if (testCaseContent.settings["noImplicitReferences"] || /require\(/.test(lastUnit.content) || /reference\spath/.test(lastUnit.content)) {
toBeCompiled.push({ unitName: this.makeUnitName(lastUnit.name, rootDir), content: lastUnit.content });
units.forEach(unit => {
if (unit.name !== lastUnit.name) {
+1 -1
View File
@@ -1414,7 +1414,7 @@ namespace FourSlash {
return;
}
const incrementalSourceFile = this.languageService.getSourceFile(this.activeFile.fileName);
const incrementalSourceFile = this.languageService.getNonBoundSourceFile(this.activeFile.fileName);
Utils.assertInvariants(incrementalSourceFile, /*parent:*/ undefined);
const incrementalSyntaxDiagnostics = incrementalSourceFile.parseDiagnostics;
+3 -2
View File
@@ -876,7 +876,7 @@ namespace Harness {
useCaseSensitiveFileNames: () => useCaseSensitiveFileNames,
getNewLine: () => newLine,
fileExists: fileName => getSourceFile(fileName, ts.ScriptTarget.ES5) !== undefined,
readFile: (fileName: string): string => { throw new Error("NotYetImplemented"); }
readFile: (fileName: string): string => { return Harness.IO.readFile(fileName); }
};
}
@@ -896,7 +896,8 @@ namespace Harness {
{ name: "fileName", type: "string" },
{ name: "libFiles", type: "string" },
{ name: "noErrorTruncation", type: "boolean" },
{ name: "suppressOutputPathCheck", type: "boolean" }
{ name: "suppressOutputPathCheck", type: "boolean" },
{ name: "noImplicitReferences", type: "boolean" }
];
let optionsIndex: ts.Map<ts.CommandLineOption>;
+1 -1
View File
@@ -423,7 +423,7 @@ namespace Harness.LanguageService {
getProgram(): ts.Program {
throw new Error("Program can not be marshaled across the shim layer.");
}
getSourceFile(fileName: string): ts.SourceFile {
getNonBoundSourceFile(fileName: string): ts.SourceFile {
throw new Error("SourceFile can not be marshaled across the shim layer.");
}
dispose(): void { this.shim.dispose({}); }
+4 -6
View File
@@ -31,22 +31,20 @@ namespace RWC {
let otherFiles: Harness.Compiler.TestFile[] = [];
let compilerResult: Harness.Compiler.CompilerResult;
let compilerOptions: ts.CompilerOptions;
let baselineOpts: Harness.Baseline.BaselineOptions = {
const baselineOpts: Harness.Baseline.BaselineOptions = {
Subfolder: "rwc",
Baselinefolder: "internal/baselines"
};
let baseName = /(.*)\/(.*).json/.exec(ts.normalizeSlashes(jsonPath))[2];
const baseName = /(.*)\/(.*).json/.exec(ts.normalizeSlashes(jsonPath))[2];
let currentDirectory: string;
let useCustomLibraryFile: boolean;
after(() => {
// Mocha holds onto the closure environment of the describe callback even after the test is done.
// Therefore we have to clean out large objects after the test is done.
inputFiles = undefined;
otherFiles = undefined;
inputFiles = [];
otherFiles = [];
compilerResult = undefined;
compilerOptions = undefined;
baselineOpts = undefined;
baseName = undefined;
currentDirectory = undefined;
// useCustomLibraryFile is a flag specified in the json object to indicate whether to use built/local/lib.d.ts
// or to use lib.d.ts inside the json object. If the flag is true, use the lib.d.ts inside json file
+24 -24
View File
@@ -304,13 +304,13 @@ interface String {
* Matches a string with a regular expression, and returns an array containing the results of that search.
* @param regexp A variable name or string literal containing the regular expression pattern and flags.
*/
match(regexp: string): RegExpMatchArray;
match(regexp: string): RegExpMatchArray | null;
/**
* Matches a string with a regular expression, and returns an array containing the results of that search.
* @param regexp A regular expression object that contains the regular expression pattern and applicable flags.
*/
match(regexp: RegExp): RegExpMatchArray;
match(regexp: RegExp): RegExpMatchArray | null;
/**
* Replaces text in a string, using a regular expression or search string.
@@ -813,7 +813,7 @@ interface RegExp {
* Executes a search on a string using a regular expression pattern, and returns an array containing the results of that search.
* @param string The String object or string literal on which to perform the search.
*/
exec(string: string): RegExpExecArray;
exec(string: string): RegExpExecArray | null;
/**
* Returns a Boolean value that indicates whether or not a pattern exists in a searched string.
@@ -836,7 +836,7 @@ interface RegExp {
lastIndex: number;
// Non-standard extensions
compile(): RegExp;
compile(): this;
}
interface RegExpConstructor {
@@ -1108,7 +1108,7 @@ interface Array<T> {
/**
* Removes the last element from an array and returns it.
*/
pop(): T;
pop(): T | undefined;
/**
* Combines two or more arrays.
* @param items Additional items to add to the end of array1.
@@ -1126,7 +1126,7 @@ interface Array<T> {
/**
* Removes the first element from an array and returns it.
*/
shift(): T;
shift(): T | undefined;
/**
* Returns a section of an array.
* @param start The beginning of the specified portion of the array.
@@ -1519,7 +1519,7 @@ interface Int8Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
/**
* Returns the index of the first element in the array where predicate is true, and undefined
@@ -1530,7 +1530,7 @@ interface Int8Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number) => boolean, thisArg?: any): number | undefined;
/**
* Performs the specified action for each element in an array.
@@ -1792,7 +1792,7 @@ interface Uint8Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
/**
* Returns the index of the first element in the array where predicate is true, and undefined
@@ -1803,7 +1803,7 @@ interface Uint8Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number) => boolean, thisArg?: any): number | undefined;
/**
* Performs the specified action for each element in an array.
@@ -2066,7 +2066,7 @@ interface Uint8ClampedArray {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
/**
* Returns the index of the first element in the array where predicate is true, and undefined
@@ -2077,7 +2077,7 @@ interface Uint8ClampedArray {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number) => boolean, thisArg?: any): number | undefined;
/**
* Performs the specified action for each element in an array.
@@ -2339,7 +2339,7 @@ interface Int16Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
/**
* Returns the index of the first element in the array where predicate is true, and undefined
@@ -2350,7 +2350,7 @@ interface Int16Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number) => boolean, thisArg?: any): number | undefined;
/**
* Performs the specified action for each element in an array.
@@ -2613,7 +2613,7 @@ interface Uint16Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
/**
* Returns the index of the first element in the array where predicate is true, and undefined
@@ -2624,7 +2624,7 @@ interface Uint16Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number) => boolean, thisArg?: any): number | undefined;
/**
* Performs the specified action for each element in an array.
@@ -2886,7 +2886,7 @@ interface Int32Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
/**
* Returns the index of the first element in the array where predicate is true, and undefined
@@ -2897,7 +2897,7 @@ interface Int32Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number) => boolean, thisArg?: any): number | undefined;
/**
* Performs the specified action for each element in an array.
@@ -3159,7 +3159,7 @@ interface Uint32Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
/**
* Returns the index of the first element in the array where predicate is true, and undefined
@@ -3170,7 +3170,7 @@ interface Uint32Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number) => boolean, thisArg?: any): number | undefined;
/**
* Performs the specified action for each element in an array.
@@ -3432,7 +3432,7 @@ interface Float32Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
/**
* Returns the index of the first element in the array where predicate is true, and undefined
@@ -3443,7 +3443,7 @@ interface Float32Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number) => boolean, thisArg?: any): number | undefined;
/**
* Performs the specified action for each element in an array.
@@ -3706,7 +3706,7 @@ interface Float64Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number;
find(predicate: (value: number, index: number, obj: Array<number>) => boolean, thisArg?: any): number | undefined;
/**
* Returns the index of the first element in the array where predicate is true, and undefined
@@ -3717,7 +3717,7 @@ interface Float64Array {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: number) => boolean, thisArg?: any): number;
findIndex(predicate: (value: number) => boolean, thisArg?: any): number | undefined;
/**
* Performs the specified action for each element in an array.
+8 -8
View File
@@ -34,7 +34,7 @@ interface SymbolConstructor {
* Otherwise, returns a undefined.
* @param sym Symbol to find the key for.
*/
keyFor(sym: symbol): string;
keyFor(sym: symbol): string | undefined;
// Well-known Symbols
@@ -320,7 +320,7 @@ interface Array<T> {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
find(predicate: (value: T, index: number, obj: Array<T>) => boolean, thisArg?: any): T;
find(predicate: (value: T, index: number, obj: Array<T>) => boolean, thisArg?: any): T | undefined;
/**
* Returns the index of the first element in the array where predicate is true, and undefined
@@ -331,7 +331,7 @@ interface Array<T> {
* @param thisArg If provided, it will be used as the this value for each invocation of
* predicate. If it is not provided, undefined is used instead.
*/
findIndex(predicate: (value: T) => boolean, thisArg?: any): number;
findIndex(predicate: (value: T) => boolean, thisArg?: any): number | undefined;
/**
* Returns the this object after filling the section identified by start and end with value
@@ -407,7 +407,7 @@ interface String {
* If there is no element at that position, the result is undefined.
* If a valid UTF-16 surrogate pair does not begin at pos, the result is the code unit at pos.
*/
codePointAt(pos: number): number;
codePointAt(pos: number): number | undefined;
/**
* Returns true if searchString appears as a substring of the result of converting this
@@ -453,7 +453,7 @@ interface String {
* Matches a string an object that supports being matched against, and returns an array containing the results of that search.
* @param matcher An object that supports being matched against.
*/
match(matcher: { [Symbol.match](string: string): RegExpMatchArray; }): RegExpMatchArray;
match(matcher: { [Symbol.match](string: string): RegExpMatchArray | null; }): RegExpMatchArray | null;
/**
* Replaces text in a string, using an object that supports replacement within a string.
@@ -723,7 +723,7 @@ interface RegExp {
* that search.
* @param string A string to search within.
*/
[Symbol.match](string: string): RegExpMatchArray;
[Symbol.match](string: string): RegExpMatchArray | null;
/**
* Replaces text in a string, using this regular expression.
@@ -800,7 +800,7 @@ interface Map<K, V> {
delete(key: K): boolean;
entries(): IterableIterator<[K, V]>;
forEach(callbackfn: (value: V, index: K, map: Map<K, V>) => void, thisArg?: any): void;
get(key: K): V;
get(key: K): V | undefined;
has(key: K): boolean;
keys(): IterableIterator<K>;
set(key: K, value?: V): Map<K, V>;
@@ -821,7 +821,7 @@ declare var Map: MapConstructor;
interface WeakMap<K, V> {
clear(): void;
delete(key: K): boolean;
get(key: K): V;
get(key: K): V | undefined;
has(key: K): boolean;
set(key: K, value?: V): WeakMap<K, V>;
readonly [Symbol.toStringTag]: "WeakMap";
+1 -1
View File
@@ -613,7 +613,7 @@ namespace ts.server {
throw new Error("SourceFile objects are not serializable through the server protocol.");
}
getSourceFile(fileName: string): SourceFile {
getNonBoundSourceFile(fileName: string): SourceFile {
throw new Error("SourceFile objects are not serializable through the server protocol.");
}
+4 -7
View File
@@ -1006,9 +1006,7 @@ namespace ts.server {
info.setFormatOptions(this.getFormatCodeOptions());
this.filenameToScriptInfo[fileName] = info;
if (!info.isOpen) {
info.fileWatcher = this.host.watchFile(
toPath(fileName, fileName, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)),
_ => { this.watchedFileChanged(fileName); });
info.fileWatcher = this.host.watchFile(fileName, _ => { this.watchedFileChanged(fileName); });
}
}
}
@@ -1227,9 +1225,7 @@ namespace ts.server {
}
}
project.finishGraph();
project.projectFileWatcher = this.host.watchFile(
toPath(configFilename, configFilename, createGetCanonicalFileName(sys.useCaseSensitiveFileNames)),
_ => this.watchedProjectConfigFileChanged(project));
project.projectFileWatcher = this.host.watchFile(configFilename, _ => this.watchedProjectConfigFileChanged(project));
this.log("Add recursive watcher for: " + ts.getDirectoryPath(configFilename));
project.directoryWatcher = this.host.watchDirectory(
ts.getDirectoryPath(configFilename),
@@ -1317,6 +1313,7 @@ namespace ts.server {
else {
const defaultOpts = ts.getDefaultCompilerOptions();
defaultOpts.allowNonTsExtensions = true;
defaultOpts.allowJs = true;
this.setCompilerOptions(defaultOpts);
}
this.languageService = ts.createLanguageService(this.host, this.documentRegistry);
@@ -1329,7 +1326,7 @@ namespace ts.server {
}
isExternalModule(filename: string): boolean {
const sourceFile = this.languageService.getSourceFile(filename);
const sourceFile = this.languageService.getNonBoundSourceFile(filename);
return ts.isExternalModule(sourceFile);
}
+11 -3
View File
@@ -72,12 +72,20 @@ namespace ts.formatting {
if (line === 0) {
return [];
}
// get the span for the previous\current line
// After the enter key, the cursor is now at a new line. The new line may or may not contain non-whitespace characters.
// If the new line has only whitespaces, we won't want to format this line, because that would remove the indentation as
// trailing whitespaces. So the end of the formatting span should be the later one between:
// 1. the end of the previous line
// 2. the last non-whitespace character in the current line
let endOfFormatSpan = getEndLinePosition(line, sourceFile);
while (isWhiteSpace(sourceFile.text.charCodeAt(endOfFormatSpan)) && !isLineBreak(sourceFile.text.charCodeAt(endOfFormatSpan))) {
endOfFormatSpan--;
}
let span = {
// get start position for the previous line
pos: getStartPositionOfLine(line - 1, sourceFile),
// get end position for the current line (end value is exclusive so add 1 to the result)
end: getEndLinePosition(line, sourceFile) + 1
// end value is exclusive so add 1 to the result
end: endOfFormatSpan + 1
}
return formatSpan(span, sourceFile, options, rulesProvider, FormattingRequestKind.FormatOnEnter);
}
-2
View File
@@ -30,7 +30,6 @@ namespace ts.JsTyping {
/**
* @param host is the object providing I/O related operations.
* @param fileNames are the file names that belong to the same project
* @param cachePath is the path to the typings cache
* @param projectRootPath is the path to the project root directory
* @param safeListPath is the path used to retrieve the safe list
* @param packageNameToTypingLocation is the map of package names to their cached typing locations
@@ -40,7 +39,6 @@ namespace ts.JsTyping {
export function discoverTypings(
host: TypingResolutionHost,
fileNames: string[],
cachePath: Path,
projectRootPath: Path,
safeListPath: Path,
packageNameToTypingLocation: Map<string>,
+208
View File
@@ -3,6 +3,12 @@
/* @internal */
namespace ts.NavigationBar {
export function getNavigationBarItems(sourceFile: SourceFile, compilerOptions: CompilerOptions): ts.NavigationBarItem[] {
// TODO: Handle JS files differently in 'navbar' calls for now, but ideally we should unify
// the 'navbar' and 'navto' logic for TypeScript and JavaScript.
if (isSourceFileJavaScript(sourceFile)) {
return getJsNavigationBarItems(sourceFile, compilerOptions);
}
// If the source file has any child items, then it included in the tree
// and takes lexical ownership of all other top-level items.
let hasGlobalNode = false;
@@ -594,4 +600,206 @@ namespace ts.NavigationBar {
return getTextOfNodeFromSourceText(sourceFile.text, node);
}
}
export function getJsNavigationBarItems(sourceFile: SourceFile, compilerOptions: CompilerOptions): NavigationBarItem[] {
const anonFnText = "<function>";
const anonClassText = "<class>";
let indent = 0;
let rootName = isExternalModule(sourceFile) ?
"\"" + escapeString(getBaseFileName(removeFileExtension(normalizePath(sourceFile.fileName)))) + "\""
: "<global>";
let sourceFileItem = getNavBarItem(rootName, ScriptElementKind.moduleElement, [getNodeSpan(sourceFile)]);
let topItem = sourceFileItem;
// Walk the whole file, because we want to also find function expressions - which may be in variable initializer,
// call arguments, expressions, etc...
forEachChild(sourceFile, visitNode);
function visitNode(node: Node) {
const newItem = createNavBarItem(node);
if (newItem) {
topItem.childItems.push(newItem);
}
// Add a level if traversing into a container
if (newItem && (isFunctionLike(node) || isClassLike(node))) {
const lastTop = topItem;
indent++;
topItem = newItem;
forEachChild(node, visitNode);
topItem = lastTop;
indent--;
// If the last item added was an anonymous function expression, and it had no children, discard it.
if (newItem && newItem.text === anonFnText && newItem.childItems.length === 0) {
topItem.childItems.pop();
}
}
else {
forEachChild(node, visitNode);
}
}
function createNavBarItem(node: Node) : NavigationBarItem {
switch (node.kind) {
case SyntaxKind.VariableDeclaration:
// Only add to the navbar if at the top-level of the file
// Note: "const" and "let" are also SyntaxKind.VariableDeclarations
if(node.parent/*VariableDeclarationList*/.parent/*VariableStatement*/
.parent/*SourceFile*/.kind !== SyntaxKind.SourceFile) {
return undefined;
}
// If it is initialized with a function expression, handle it when we reach the function expression node
const varDecl = node as VariableDeclaration;
if (varDecl.initializer && (varDecl.initializer.kind === SyntaxKind.FunctionExpression ||
varDecl.initializer.kind === SyntaxKind.ArrowFunction ||
varDecl.initializer.kind === SyntaxKind.ClassExpression)) {
return undefined;
}
// Fall through
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.ClassDeclaration:
case SyntaxKind.Constructor:
case SyntaxKind.GetAccessor:
case SyntaxKind.SetAccessor:
// "export default function().." looks just like a regular function/class declaration, except with the 'default' flag
const name = node.flags && (node.flags & NodeFlags.Default) && !(node as (Declaration)).name ? "default" :
node.kind === SyntaxKind.Constructor ? "constructor" :
declarationNameToString((node as (Declaration)).name);
return getNavBarItem(name, getScriptKindForElementKind(node.kind), [getNodeSpan(node)]);
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
case SyntaxKind.ClassExpression:
return getDefineModuleItem(node) || getFunctionOrClassExpressionItem(node);
case SyntaxKind.MethodDeclaration:
const methodDecl = node as MethodDeclaration;
return getNavBarItem(declarationNameToString(methodDecl.name),
ScriptElementKind.memberFunctionElement,
[getNodeSpan(node)]);
case SyntaxKind.ExportAssignment:
// e.g. "export default <expr>"
return getNavBarItem("default", ScriptElementKind.variableElement, [getNodeSpan(node)]);
case SyntaxKind.ImportClause: // e.g. 'def' in: import def from 'mod' (in ImportDeclaration)
if (!(node as ImportClause).name) {
// No default import (this node is still a parent of named & namespace imports, which are handled below)
return undefined;
}
// fall through
case SyntaxKind.ImportSpecifier: // e.g. 'id' in: import {id} from 'mod' (in NamedImports, in ImportClause)
case SyntaxKind.NamespaceImport: // e.g. '* as ns' in: import * as ns from 'mod' (in ImportClause)
case SyntaxKind.ExportSpecifier: // e.g. 'a' or 'b' in: export {a, foo as b} from 'mod'
// Export specifiers are only interesting if they are reexports from another module, or renamed, else they are already globals
if (node.kind === SyntaxKind.ExportSpecifier) {
if (!(node.parent.parent as ExportDeclaration).moduleSpecifier && !(node as ExportSpecifier).propertyName) {
return undefined;
}
}
const decl = node as (ImportSpecifier | ImportClause | NamespaceImport | ExportSpecifier);
if (!decl.name) {
return undefined;
}
const declName = declarationNameToString(decl.name);
return getNavBarItem(declName, ScriptElementKind.constElement, [getNodeSpan(node)]);
default:
return undefined;
}
}
function getNavBarItem(text: string, kind: string, spans: TextSpan[], kindModifiers = ScriptElementKindModifier.none): NavigationBarItem {
return {
text, kind, kindModifiers, spans, childItems: [], indent, bolded: false, grayed: false
}
}
function getDefineModuleItem(node: Node): NavigationBarItem {
if (node.kind !== SyntaxKind.FunctionExpression && node.kind !== SyntaxKind.ArrowFunction) {
return undefined;
}
// No match if this is not a call expression to an identifier named 'define'
if (node.parent.kind !== SyntaxKind.CallExpression) {
return undefined;
}
const callExpr = node.parent as CallExpression;
if (callExpr.expression.kind !== SyntaxKind.Identifier || callExpr.expression.getText() !== 'define') {
return undefined;
}
// Return a module of either the given text in the first argument, or of the source file path
let defaultName = node.getSourceFile().fileName;
if (callExpr.arguments[0].kind === SyntaxKind.StringLiteral) {
defaultName = ((callExpr.arguments[0]) as StringLiteral).text;
}
return getNavBarItem(defaultName, ScriptElementKind.moduleElement, [getNodeSpan(node.parent)]);
}
function getFunctionOrClassExpressionItem(node: Node): NavigationBarItem {
if (node.kind !== SyntaxKind.FunctionExpression &&
node.kind !== SyntaxKind.ArrowFunction &&
node.kind !== SyntaxKind.ClassExpression) {
return undefined;
}
const fnExpr = node as FunctionExpression | ArrowFunction | ClassExpression;
let fnName: string;
if (fnExpr.name && getFullWidth(fnExpr.name) > 0) {
// The expression has an identifier, so use that as the name
fnName = declarationNameToString(fnExpr.name);
}
else {
// See if it is a var initializer. If so, use the var name.
if (fnExpr.parent.kind === SyntaxKind.VariableDeclaration) {
fnName = declarationNameToString((fnExpr.parent as VariableDeclaration).name);
}
// See if it is of the form "<expr> = function(){...}". If so, use the text from the left-hand side.
else if (fnExpr.parent.kind === SyntaxKind.BinaryExpression &&
(fnExpr.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) {
fnName = (fnExpr.parent as BinaryExpression).left.getText();
if (fnName.length > 20) {
fnName = fnName.substring(0, 17) + "...";
}
}
// See if it is a property assignment, and if so use the property name
else if (fnExpr.parent.kind === SyntaxKind.PropertyAssignment &&
(fnExpr.parent as PropertyAssignment).name) {
fnName = (fnExpr.parent as PropertyAssignment).name.getText();
}
else {
fnName = node.kind === SyntaxKind.ClassExpression ? anonClassText : anonFnText;
}
}
const scriptKind = node.kind === SyntaxKind.ClassExpression ? ScriptElementKind.classElement : ScriptElementKind.functionElement;
return getNavBarItem(fnName, scriptKind, [getNodeSpan(node)]);
}
function getNodeSpan(node: Node) {
return node.kind === SyntaxKind.SourceFile
? createTextSpanFromBounds(node.getFullStart(), node.getEnd())
: createTextSpanFromBounds(node.getStart(), node.getEnd());
}
function getScriptKindForElementKind(kind: SyntaxKind) {
switch (kind) {
case SyntaxKind.VariableDeclaration:
return ScriptElementKind.variableElement;
case SyntaxKind.FunctionDeclaration:
return ScriptElementKind.functionElement;
case SyntaxKind.ClassDeclaration:
return ScriptElementKind.classElement;
case SyntaxKind.Constructor:
return ScriptElementKind.constructorImplementationElement;
case SyntaxKind.GetAccessor:
return ScriptElementKind.memberGetAccessorElement;
case SyntaxKind.SetAccessor:
return ScriptElementKind.memberSetAccessorElement;
default:
return "unknown";
}
}
return sourceFileItem.childItems;
}
}
+115 -48
View File
@@ -1112,7 +1112,7 @@ namespace ts {
getProgram(): Program;
getSourceFile(fileName: string): SourceFile;
/* @internal */ getNonBoundSourceFile(fileName: string): SourceFile;
dispose(): void;
}
@@ -2147,8 +2147,23 @@ namespace ts {
export function preProcessFile(sourceText: string, readImportFiles = true, detectJavaScriptImports = false): PreProcessedFileInfo {
const referencedFiles: FileReference[] = [];
const importedFiles: FileReference[] = [];
let ambientExternalModules: string[];
let ambientExternalModules: { ref: FileReference, depth: number }[];
let isNoDefaultLib = false;
let braceNesting = 0;
// assume that text represent an external module if it contains at least one top level import/export
// ambient modules that are found inside external modules are interpreted as module augmentations
let externalModule = false;
function nextToken() {
const token = scanner.scan();
if (token === SyntaxKind.OpenBraceToken) {
braceNesting++;
}
else if (token === SyntaxKind.CloseBraceToken) {
braceNesting--;
}
return token;
}
function processTripleSlashDirectives(): void {
const commentRanges = getLeadingCommentRanges(sourceText, 0);
@@ -2165,21 +2180,33 @@ namespace ts {
});
}
function getFileReference() {
const file = scanner.getTokenValue();
const pos = scanner.getTokenPos();
return {
fileName: file,
pos: pos,
end: pos + file.length
};
}
function recordAmbientExternalModule(): void {
if (!ambientExternalModules) {
ambientExternalModules = [];
}
ambientExternalModules.push(scanner.getTokenValue());
ambientExternalModules.push({ ref: getFileReference(), depth: braceNesting });
}
function recordModuleName() {
const importPath = scanner.getTokenValue();
const pos = scanner.getTokenPos();
importedFiles.push({
fileName: importPath,
pos: pos,
end: pos + importPath.length
});
importedFiles.push(getFileReference());
markAsExternalModuleIfTopLevel();
}
function markAsExternalModuleIfTopLevel() {
if (braceNesting === 0) {
externalModule = true;
}
}
/**
@@ -2189,9 +2216,9 @@ namespace ts {
let token = scanner.getToken();
if (token === SyntaxKind.DeclareKeyword) {
// declare module "mod"
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.ModuleKeyword) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.StringLiteral) {
recordAmbientExternalModule();
}
@@ -2208,7 +2235,8 @@ namespace ts {
function tryConsumeImport(): boolean {
let token = scanner.getToken();
if (token === SyntaxKind.ImportKeyword) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.StringLiteral) {
// import "mod";
recordModuleName();
@@ -2216,9 +2244,9 @@ namespace ts {
}
else {
if (token === SyntaxKind.Identifier || isKeyword(token)) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.FromKeyword) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.StringLiteral) {
// import d from "mod";
recordModuleName();
@@ -2232,7 +2260,7 @@ namespace ts {
}
else if (token === SyntaxKind.CommaToken) {
// consume comma and keep going
token = scanner.scan();
token = nextToken();
}
else {
// unknown syntax
@@ -2241,17 +2269,17 @@ namespace ts {
}
if (token === SyntaxKind.OpenBraceToken) {
token = scanner.scan();
token = nextToken();
// consume "{ a as B, c, d as D}" clauses
// make sure that it stops on EOF
while (token !== SyntaxKind.CloseBraceToken && token !== SyntaxKind.EndOfFileToken) {
token = scanner.scan();
token = nextToken();
}
if (token === SyntaxKind.CloseBraceToken) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.FromKeyword) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.StringLiteral) {
// import {a as A} from "mod";
// import d, {a, b as B} from "mod"
@@ -2261,13 +2289,13 @@ namespace ts {
}
}
else if (token === SyntaxKind.AsteriskToken) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.AsKeyword) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.Identifier || isKeyword(token)) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.FromKeyword) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.StringLiteral) {
// import * as NS from "mod"
// import d, * as NS from "mod"
@@ -2288,19 +2316,20 @@ namespace ts {
function tryConsumeExport(): boolean {
let token = scanner.getToken();
if (token === SyntaxKind.ExportKeyword) {
token = scanner.scan();
markAsExternalModuleIfTopLevel();
token = nextToken();
if (token === SyntaxKind.OpenBraceToken) {
token = scanner.scan();
token = nextToken();
// consume "{ a as B, c, d as D}" clauses
// make sure it stops on EOF
while (token !== SyntaxKind.CloseBraceToken && token !== SyntaxKind.EndOfFileToken) {
token = scanner.scan();
token = nextToken();
}
if (token === SyntaxKind.CloseBraceToken) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.FromKeyword) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.StringLiteral) {
// export {a as A} from "mod";
// export {a, b as B} from "mod"
@@ -2310,9 +2339,9 @@ namespace ts {
}
}
else if (token === SyntaxKind.AsteriskToken) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.FromKeyword) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.StringLiteral) {
// export * from "mod"
recordModuleName();
@@ -2320,9 +2349,9 @@ namespace ts {
}
}
else if (token === SyntaxKind.ImportKeyword) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.Identifier || isKeyword(token)) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.EqualsToken) {
if (tryConsumeRequireCall(/*skipCurrentToken*/ true)) {
return true;
@@ -2338,11 +2367,11 @@ namespace ts {
}
function tryConsumeRequireCall(skipCurrentToken: boolean): boolean {
let token = skipCurrentToken ? scanner.scan() : scanner.getToken();
let token = skipCurrentToken ? nextToken() : scanner.getToken();
if (token === SyntaxKind.RequireKeyword) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.OpenParenToken) {
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.StringLiteral) {
// require("mod");
recordModuleName();
@@ -2356,17 +2385,17 @@ namespace ts {
function tryConsumeDefine(): boolean {
let token = scanner.getToken();
if (token === SyntaxKind.Identifier && scanner.getTokenValue() === "define") {
token = scanner.scan();
token = nextToken();
if (token !== SyntaxKind.OpenParenToken) {
return true;
}
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.StringLiteral) {
// looks like define ("modname", ... - skip string literal and comma
token = scanner.scan();
token = nextToken();
if (token === SyntaxKind.CommaToken) {
token = scanner.scan();
token = nextToken();
}
else {
// unexpected token
@@ -2380,7 +2409,7 @@ namespace ts {
}
// skip open bracket
token = scanner.scan();
token = nextToken();
let i = 0;
// scan until ']' or EOF
while (token !== SyntaxKind.CloseBracketToken && token !== SyntaxKind.EndOfFileToken) {
@@ -2390,7 +2419,7 @@ namespace ts {
i++;
}
token = scanner.scan();
token = nextToken();
}
return true;
@@ -2400,7 +2429,7 @@ namespace ts {
function processImports(): void {
scanner.setText(sourceText);
scanner.scan();
nextToken();
// Look for:
// import "mod";
// import d from "mod"
@@ -2427,7 +2456,7 @@ namespace ts {
continue;
}
else {
scanner.scan();
nextToken();
}
}
@@ -2438,7 +2467,34 @@ namespace ts {
processImports();
}
processTripleSlashDirectives();
return { referencedFiles, importedFiles, isLibFile: isNoDefaultLib, ambientExternalModules };
if (externalModule) {
// for external modules module all nested ambient modules are augmentations
if (ambientExternalModules) {
// move all detected ambient modules to imported files since they need to be resolved
for (const decl of ambientExternalModules) {
importedFiles.push(decl.ref);
}
}
return { referencedFiles, importedFiles, isLibFile: isNoDefaultLib, ambientExternalModules: undefined };
}
else {
// for global scripts ambient modules still can have augmentations - look for ambient modules with depth > 0
let ambientModuleNames: string[];
if (ambientExternalModules) {
for (const decl of ambientExternalModules) {
if (decl.depth === 0) {
if (!ambientModuleNames) {
ambientModuleNames = [];
}
ambientModuleNames.push(decl.ref.fileName);
}
else {
importedFiles.push(decl.ref);
}
}
}
return { referencedFiles, importedFiles, isLibFile: isNoDefaultLib, ambientExternalModules: ambientModuleNames };
}
}
/// Helpers
@@ -3448,7 +3504,18 @@ namespace ts {
// We don't want to complete using the type acquired by the shape
// of the binding pattern; we are only interested in types acquired
// through type declaration or inference.
if (rootDeclaration.initializer || rootDeclaration.type) {
// Also proceed if rootDeclaration is parameter and if its containing function expression\arrow function is contextually typed -
// type of parameter will flow in from the contextual type of the function
let canGetType = !!(rootDeclaration.initializer || rootDeclaration.type);
if (!canGetType && rootDeclaration.kind === SyntaxKind.Parameter) {
if (isExpression(rootDeclaration.parent)) {
canGetType = !!typeChecker.getContextualType(<Expression>rootDeclaration.parent);
}
else if (rootDeclaration.parent.kind === SyntaxKind.MethodDeclaration || rootDeclaration.parent.kind === SyntaxKind.SetAccessor) {
canGetType = isExpression(rootDeclaration.parent.parent) && !!typeChecker.getContextualType(<Expression>rootDeclaration.parent.parent);
}
}
if (canGetType) {
typeForObject = typeChecker.getTypeAtLocation(objectLikeContainer);
existingMembers = (<BindingPattern>objectLikeContainer).elements;
}
@@ -6461,7 +6528,7 @@ namespace ts {
}
/// Syntactic features
function getSourceFile(fileName: string): SourceFile {
function getNonBoundSourceFile(fileName: string): SourceFile {
return syntaxTreeCache.getCurrentSourceFile(fileName);
}
@@ -7549,7 +7616,7 @@ namespace ts {
getFormattingEditsAfterKeystroke,
getDocCommentTemplateAtPosition,
getEmitOutput,
getSourceFile,
getNonBoundSourceFile,
getProgram
};
}
-1
View File
@@ -994,7 +994,6 @@ namespace ts {
return ts.JsTyping.discoverTypings(
this.host,
info.fileNames,
toPath(info.cachePath, info.cachePath, getCanonicalFileName),
toPath(info.projectRootPath, info.projectRootPath, getCanonicalFileName),
toPath(info.safeListPath, info.safeListPath, getCanonicalFileName),
info.packageNameToTypingLocation,