Merge remote-tracking branch 'upstream/master' into async-es2018

This commit is contained in:
Kagami Sascha Rosylight
2018-09-06 09:55:41 +09:00
1042 changed files with 126058 additions and 95996 deletions
+3 -1
View File
@@ -74,4 +74,6 @@ tests/cases/user/*/**/*.d.ts
!tests/cases/user/bignumber.js/
!tests/cases/user/discord.js/
tests/baselines/reference/dt
.failed-tests
.failed-tests
TEST-results.xml
package-lock.json
+1
View File
@@ -0,0 +1 @@
package-lock=false
+57 -35
View File
@@ -24,10 +24,9 @@ const baselineAccept = require("./scripts/build/baselineAccept");
const cmdLineOptions = require("./scripts/build/options");
const exec = require("./scripts/build/exec");
const browserify = require("./scripts/build/browserify");
const debounce = require("./scripts/build/debounce");
const prepend = require("./scripts/build/prepend");
const { removeSourceMaps } = require("./scripts/build/sourcemaps");
const { CancelSource, CancelError } = require("./scripts/build/cancellation");
const { CancellationTokenSource, CancelError, delay, Semaphore } = require("prex");
const { libraryTargets, generateLibs } = require("./scripts/build/lib");
const { runConsoleTests, cleanTestDirs, writeTestConfigFile, refBaseline, localBaseline, refRwcBaseline, localRwcBaseline } = require("./scripts/build/tests");
@@ -534,57 +533,80 @@ gulp.task(
["watch-diagnostics", "watch-lib"].concat(useCompilerDeps),
() => project.watch(tsserverProject, { typescript: useCompiler }));
gulp.task(
"watch-local",
/*help*/ false,
["watch-lib", "watch-tsc", "watch-services", "watch-server"]);
gulp.task(
"watch-runner",
/*help*/ false,
useCompilerDeps,
() => project.watch(testRunnerProject, { typescript: useCompiler }));
const watchPatterns = [
runJs,
typescriptDts,
tsserverlibraryDts
];
gulp.task(
"watch-local",
"Watches for changes to projects in src/ (but does not execute tests).",
["watch-lib", "watch-tsc", "watch-services", "watch-server", "watch-runner", "watch-lssl"]);
gulp.task(
"watch",
"Watches for changes to the build inputs for built/local/run.js, then executes runtests-parallel.",
"Watches for changes to the build inputs for built/local/run.js, then runs tests.",
["build-rules", "watch-runner", "watch-services", "watch-lssl"],
() => {
/** @type {CancelSource | undefined} */
let runTestsSource;
const sem = new Semaphore(1);
const fn = debounce(() => {
runTests().catch(error => {
if (error instanceof CancelError) {
log.warn("Operation was canceled");
}
else {
log.error(error);
}
});
}, /*timeout*/ 100, { max: 500 });
gulp.watch(watchPatterns, () => project.wait().then(fn));
gulp.watch([runJs, typescriptDts, tsserverlibraryDts], () => {
runTests();
});
// NOTE: gulp.watch is far too slow when watching tests/cases/**/* as it first enumerates *every* file
const testFilePattern = /(\.ts|[\\/]tsconfig\.json)$/;
fs.watch("tests/cases", { recursive: true }, (_, file) => {
if (testFilePattern.test(file)) project.wait().then(fn);
if (testFilePattern.test(file)) runTests();
});
function runTests() {
if (runTestsSource) runTestsSource.cancel();
runTestsSource = new CancelSource();
return cmdLineOptions.tests || cmdLineOptions.failed
? runConsoleTests(runJs, "mocha-fivemat-progress-reporter", /*runInParallel*/ false, /*watchMode*/ true, runTestsSource.token)
: runConsoleTests(runJs, "min", /*runInParallel*/ true, /*watchMode*/ true, runTestsSource.token);
}
async function runTests() {
try {
// Ensure only one instance of the test runner is running at any given time.
if (sem.count > 0) {
await sem.wait();
try {
// Wait for any concurrent recompilations to complete...
try {
await delay(100);
while (project.hasRemainingWork()) {
await project.waitForWorkToComplete();
await delay(500);
}
}
catch (e) {
if (e instanceof CancelError) return;
throw e;
}
// cancel any pending or active test run if a new recompilation is triggered
const source = new CancellationTokenSource();
project.waitForWorkToStart().then(() => {
source.cancel();
});
if (cmdLineOptions.tests || cmdLineOptions.failed) {
await runConsoleTests(runJs, "mocha-fivemat-progress-reporter", /*runInParallel*/ false, /*watchMode*/ true, source.token);
}
else {
await runConsoleTests(runJs, "min", /*runInParallel*/ true, /*watchMode*/ true, source.token);
}
}
finally {
sem.release();
}
}
}
catch (e) {
if (e instanceof CancelError) {
log.warn("Operation was canceled");
}
else {
log.error(e);
}
}
};
});
gulp.task("clean-built", /*help*/ false, [`clean:${diagnosticInformationMapTs}`], () => del(["built"]));
+2 -2
View File
@@ -49,8 +49,8 @@
"A_namespace_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged_2434": "Eine Namespacedeklaration darf nicht vor der Klasse oder Funktion positioniert werden, mit der sie zusammengeführt wird.",
"A_namespace_declaration_is_only_allowed_in_a_namespace_or_module_1235": "Eine Namespacedeklaration ist nur in einem Namespace oder Modul zulässig.",
"A_namespace_style_import_cannot_be_called_or_constructed_and_will_cause_a_failure_at_runtime_7038": "Ein Import im Namespacestil kann nicht aufgerufen oder erstellt werden und verursacht zur Laufzeit einen Fehler.",
"A_non_dry_build_would_build_project_0_6357": "Bei einem Build mit dem Flag \"-dry\" würde das Projekt \"{0}\" erstellt.",
"A_non_dry_build_would_delete_the_following_files_Colon_0_6356": "Bei einem Build mit dem Flag \"-dry\" würden die folgenden Dateien gelöscht: {0}",
"A_non_dry_build_would_build_project_0_6357": "Bei einem Build ohne das Flag \"-dry\" würde das Projekt \"{0}\" erstellt.",
"A_non_dry_build_would_delete_the_following_files_Colon_0_6356": "Bei einem Build ohne das Flag \"-dry\" würden die folgenden Dateien gelöscht: {0}",
"A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation_2371": "Ein Parameterinitialisierer ist nur in einer Funktions- oder Konstruktorimplementierung zulässig.",
"A_parameter_property_cannot_be_declared_using_a_rest_parameter_1317": "Eine Parametereigenschaft darf nicht mithilfe eines rest-Parameters deklariert werden.",
"A_parameter_property_is_only_allowed_in_a_constructor_implementation_2369": "Eine Parametereigenschaft ist nur in einer Konstruktorimplementierung zulässig.",
+147 -15
View File
@@ -267,6 +267,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_label_is_not_allowed_here_1344" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA['A label is not allowed here.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_member_initializer_in_a_enum_declaration_cannot_reference_members_declared_after_it_including_memb_2651" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A member initializer in a enum declaration cannot reference members declared after it, including members defined in other enums.]]></Val>
@@ -645,6 +651,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Add_default_import_0_to_existing_import_declaration_from_1_90033" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Add default import '{0}' to existing import declaration from "{1}"]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Add_definite_assignment_assertion_to_property_0_95020" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Add definite assignment assertion to property '{0}']]></Val>
@@ -777,6 +789,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";All_type_parameters_are_unused_6205" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[All type parameters are unused]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";All_variables_are_unused_6199" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[All variables are unused.]]></Val>
@@ -849,6 +867,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";An_arrow_function_cannot_have_a_this_parameter_2730" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[An arrow function cannot have a 'this' parameter.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";An_async_function_or_method_in_ES5_SlashES3_requires_the_Promise_constructor_Make_sure_you_have_a_de_2705" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[An async function or method in ES5/ES3 requires the 'Promise' constructor. Make sure you have a declaration for the 'Promise' constructor or include 'ES2015' in your `--lib` option.]]></Val>
@@ -921,6 +945,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";An_expression_of_type_void_cannot_be_tested_for_truthiness_1345" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[An expression of type 'void' cannot be tested for truthiness]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive_1198" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[An extended Unicode escape value must be between 0x0 and 0x10FFFF inclusive.]]></Val>
@@ -1341,6 +1371,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Cannot_find_module_0_Consider_using_resolveJsonModule_to_import_module_with_json_extension_2732" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Cannot find module '{0}'. Consider using '--resolveJsonModule' to import module with '.json' extension]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Cannot_find_name_0_2304" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Cannot find name '{0}'.]]></Val>
@@ -1749,6 +1785,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Conversion_of_type_0_to_type_1_may_be_a_mistake_because_neither_type_sufficiently_overlaps_with_the__2352" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Conversion of type '{0}' to type '{1}' may be a mistake because neither type sufficiently overlaps with the other. If this was intentional, convert the expression to 'unknown' first.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Convert_0_to_mapped_object_type_95055" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert '{0}' to mapped object type]]></Val>
@@ -1767,6 +1809,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Convert_all_to_async_functions_95066" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert all to async functions]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Convert_all_to_default_imports_95035" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert all to default imports]]></Val>
@@ -1821,6 +1869,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Convert_to_async_function_95065" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert to async function]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Convert_to_default_import_95013" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Convert to default import]]></Val>
@@ -2855,7 +2909,7 @@
</Item>
<Item ItemId=";If_the_0_package_actually_exposes_this_module_consider_sending_a_pull_request_to_amend_https_Colon_S_7040" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[If the '{0}' package actually exposes this module, consider sending a pull request to amend 'https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/{0}`]]></Val>
<Val><![CDATA[If the '{0}' package actually exposes this module, consider sending a pull request to amend 'https://github.com/DefinitelyTyped/DefinitelyTyped/tree/master/types/{1}`]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
@@ -2895,6 +2949,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Implicit_conversion_of_a_symbol_to_a_string_will_fail_at_runtime_Consider_wrapping_this_expression_i_2731" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Implicit conversion of a 'symbol' to a 'string' will fail at runtime. Consider wrapping this expression in 'String(...)'.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Import_0_from_module_1_90013" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Import '{0}' from module "{1}"]]></Val>
@@ -2925,6 +2985,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Import_default_0_from_module_1_90032" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Import default '{0}' from module "{1}"]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Import_emit_helpers_from_tslib_6139" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Import emit helpers from 'tslib'.]]></Val>
@@ -3531,6 +3597,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Module_0_was_resolved_to_1_but_resolveJsonModule_is_not_used_7042" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Module '{0}' was resolved to '{1}', but '--resolveJsonModule' is not used.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Module_Resolution_Options_6174" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Module Resolution Options]]></Val>
@@ -3615,6 +3687,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";No_overload_expects_0_arguments_but_overloads_do_exist_that_expect_either_1_or_2_arguments_2575" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[No overload expects {0} arguments, but overloads do exist that expect either {1} or {2} arguments.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Non_abstract_class_0_does_not_implement_inherited_abstract_member_1_from_class_2_2515" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Non-abstract class '{0}' does not implement inherited abstract member '{1}' from class '{2}'.]]></Val>
@@ -3831,6 +3909,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Option_resolveJsonModule_can_only_be_specified_when_module_code_generation_is_commonjs_5071" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Option '--resolveJsonModule' can only be specified when module code generation is 'commonjs'.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Option_resolveJsonModule_cannot_be_specified_without_node_module_resolution_strategy_5070" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Option '--resolveJsonModule' cannot be specified without 'node' module resolution strategy.]]></Val>
@@ -4245,6 +4329,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Property_0_is_a_static_member_of_type_1_2576" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Property '{0}' is a static member of type '{1}']]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Property_0_is_declared_but_its_value_is_never_read_6138" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Property '{0}' is declared but its value is never read.]]></Val>
@@ -4521,6 +4611,18 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Remove_template_tag_90011" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Remove template tag]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Remove_type_parameters_90012" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Remove type parameters]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Remove_unreachable_code_95050" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Remove unreachable code]]></Val>
@@ -4539,12 +4641,24 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Replace_all_unused_infer_with_unknown_90031" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Replace all unused 'infer' with 'unknown']]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Replace_import_with_0_95015" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Replace import with '{0}'.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Replace_infer_0_with_unknown_90030" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Replace 'infer {0}' with 'unknown']]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Report_error_when_not_all_code_paths_in_function_return_a_value_6075" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Report error when not all code paths in function return a value.]]></Val>
@@ -4671,6 +4785,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Return_type_annotation_circularly_references_itself_2577" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Return type annotation circularly references itself.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Return_type_of_call_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1_4046" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Return type of call signature from exported interface has or is using name '{0}' from private module '{1}'.]]></Val>
@@ -5169,6 +5289,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";The_containing_arrow_function_captures_the_global_value_of_this_which_implicitly_has_type_any_7041" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[The containing arrow function captures the global value of 'this' which implicitly has type 'any'.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";The_containing_function_or_module_body_is_too_large_for_control_flow_analysis_2563" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[The containing function or module body is too large for control flow analysis.]]></Val>
@@ -5409,6 +5535,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";The_type_of_a_function_declaration_must_match_the_function_s_signature_8030" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[The type of a function declaration must match the function's signature.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";The_type_returned_by_the_next_method_of_an_async_iterator_must_be_a_promise_for_a_type_with_a_value__2547" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[The type returned by the 'next()' method of an async iterator must be a promise for a type with a 'value' property.]]></Val>
@@ -5451,6 +5583,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";This_may_be_converted_to_an_async_function_80006" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[This may be converted to an async function.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";This_syntax_requires_an_imported_helper_but_module_0_cannot_be_found_2354" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[This syntax requires an imported helper but module '{0}' cannot be found.]]></Val>
@@ -5475,9 +5613,9 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Try_npm_install_types_Slash_0_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_mod_7035" ItemType="0" PsrId="306" Leaf="true">
<Item ItemId=";Try_npm_install_types_Slash_1_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_mod_7035" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Try `npm install @types/{0}` if it exists or add a new declaration (.d.ts) file containing `declare module '{0}';`]]></Val>
<Val><![CDATA[Try `npm install @types/{1}` if it exists or add a new declaration (.d.ts) file containing `declare module '{0}';`]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
@@ -5499,12 +5637,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Type_0_cannot_be_converted_to_type_1_2352" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Type '{0}' cannot be converted to type '{1}'.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Type_0_cannot_be_used_as_an_index_type_2538" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Type '{0}' cannot be used as an index type.]]></Val>
@@ -6141,6 +6273,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";_0_is_declared_here_2728" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA['{0}' is declared here.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";_0_is_not_a_valid_meta_property_for_keyword_1_Did_you_mean_2_17012" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA['{0}' is not a valid meta-property for keyword '{1}'. Did you mean '{2}'?]]></Val>
@@ -6279,12 +6417,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";_0_was_declared_here_2728" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA['{0}' was declared here.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";_0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type_7010" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA['{0}', which lacks return-type annotation, implicitly has an '{1}' return type.]]></Val>
+3078 -2611
View File
File diff suppressed because it is too large Load Diff
+32 -4
View File
@@ -51,10 +51,13 @@ interface DOMStringList {
interface DOMTokenList {
[Symbol.iterator](): IterableIterator<string>;
entries(): IterableIterator<[number, string]>;
keys(): IterableIterator<number>;
values(): IterableIterator<string>;
}
interface DataTransferItemList {
[Symbol.iterator](): IterableIterator<File>;
[Symbol.iterator](): IterableIterator<DataTransferItem>;
}
interface FileList {
@@ -87,9 +90,10 @@ interface HTMLCollectionBase {
interface HTMLCollectionOf<T extends Element> {
[Symbol.iterator](): IterableIterator<T>;
entries(): IterableIterator<[number, T]>;
keys(): IterableIterator<number>;
values(): IterableIterator<T>;
}
interface HTMLFormElement {
[Symbol.iterator](): IterableIterator<Element>;
}
interface HTMLSelectElement {
@@ -167,10 +171,34 @@ interface PluginArray {
interface RTCStatsReport extends ReadonlyMap<string, any> {
}
interface SVGLengthList {
[Symbol.iterator](): IterableIterator<SVGLength>;
}
interface SVGNumberList {
[Symbol.iterator](): IterableIterator<SVGNumber>;
}
interface SVGStringList {
[Symbol.iterator](): IterableIterator<string>;
}
interface SourceBufferList {
[Symbol.iterator](): IterableIterator<SourceBuffer>;
}
interface SpeechGrammarList {
[Symbol.iterator](): IterableIterator<SpeechGrammar>;
}
interface SpeechRecognitionResult {
[Symbol.iterator](): IterableIterator<SpeechRecognitionAlternative>;
}
interface SpeechRecognitionResultList {
[Symbol.iterator](): IterableIterator<SpeechRecognitionResult>;
}
interface StyleSheetList {
[Symbol.iterator](): IterableIterator<StyleSheet>;
}
+4 -4
View File
@@ -1145,15 +1145,15 @@ interface Array<T> {
* Returns a string representation of an array. The elements are converted to string using their toLocalString methods.
*/
toLocaleString(): string;
/**
* Removes the last element from an array and returns it.
*/
pop(): T | undefined;
/**
* Appends new elements to an array, and returns the new length of the array.
* @param items New elements of the Array.
*/
push(...items: T[]): number;
/**
* Removes the last element from an array and returns it.
*/
pop(): T | undefined;
/**
* Combines two or more arrays.
* @param items Additional items to add to the end of array1.
+467 -81
View File
@@ -27,6 +27,33 @@ interface AddEventListenerOptions extends EventListenerOptions {
passive?: boolean;
}
interface AesCbcParams extends Algorithm {
iv: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer;
}
interface AesCtrParams extends Algorithm {
counter: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer;
length: number;
}
interface AesDerivedKeyParams extends Algorithm {
length: number;
}
interface AesGcmParams extends Algorithm {
additionalData?: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer;
iv: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer;
tagLength?: number;
}
interface AesKeyAlgorithm extends KeyAlgorithm {
length: number;
}
interface AesKeyGenParams extends Algorithm {
length: number;
}
interface Algorithm {
name: string;
}
@@ -53,6 +80,15 @@ interface CloseEventInit extends EventInit {
wasClean?: boolean;
}
interface CryptoKeyPair {
privateKey?: CryptoKey;
publicKey?: CryptoKey;
}
interface CustomEventInit<T = any> extends EventInit {
detail?: T;
}
interface DOMMatrix2DInit {
a?: number;
b?: number;
@@ -103,6 +139,22 @@ interface DOMRectInit {
y?: number;
}
interface EcKeyGenParams extends Algorithm {
namedCurve: NamedCurve;
}
interface EcKeyImportParams extends Algorithm {
namedCurve: NamedCurve;
}
interface EcdhKeyDeriveParams extends Algorithm {
public: CryptoKey;
}
interface EcdsaParams extends Algorithm {
hash: HashAlgorithmIdentifier;
}
interface ErrorEventInit extends EventInit {
colno?: number;
error?: any;
@@ -129,12 +181,12 @@ interface ExtendableMessageEventInit extends ExtendableEventInit {
lastEventId?: string;
origin?: string;
ports?: MessagePort[];
source?: Client | ServiceWorker | MessagePort;
source?: Client | ServiceWorker | MessagePort | null;
}
interface FetchEventInit extends ExtendableEventInit {
clientId?: string;
preloadResponse: Promise<any>;
preloadResponse?: Promise<any>;
request: Request;
resultingClientId?: string;
targetClientId?: string;
@@ -148,6 +200,16 @@ interface GetNotificationOptions {
tag?: string;
}
interface HmacImportParams extends Algorithm {
hash: HashAlgorithmIdentifier;
length?: number;
}
interface HmacKeyGenParams extends Algorithm {
hash: HashAlgorithmIdentifier;
length?: number;
}
interface IDBIndexParameters {
multiEntry?: boolean;
unique?: boolean;
@@ -155,7 +217,7 @@ interface IDBIndexParameters {
interface IDBObjectStoreParameters {
autoIncrement?: boolean;
keyPath?: string | string[];
keyPath?: string | string[] | null;
}
interface IDBVersionChangeEventInit extends EventInit {
@@ -163,17 +225,37 @@ interface IDBVersionChangeEventInit extends EventInit {
oldVersion?: number;
}
interface JsonWebKey {
alg?: string;
crv?: string;
d?: string;
dp?: string;
dq?: string;
e?: string;
ext?: boolean;
k?: string;
key_ops?: string[];
kty?: string;
n?: string;
oth?: RsaOtherPrimesInfo[];
p?: string;
q?: string;
qi?: string;
use?: string;
x?: string;
y?: string;
}
interface KeyAlgorithm {
name: string;
}
interface MessageEventInit extends EventInit {
channel?: string;
data?: any;
lastEventId?: string;
origin?: string;
ports?: MessagePort[];
source?: object | null;
source?: MessageEventSource | null;
}
interface NavigationPreloadState {
@@ -209,6 +291,12 @@ interface NotificationOptions {
vibrate?: VibratePattern;
}
interface Pbkdf2Params extends Algorithm {
hash: HashAlgorithmIdentifier;
iterations: number;
salt: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer;
}
interface PerformanceObserverInit {
buffered?: boolean;
entryTypes: string[];
@@ -241,7 +329,7 @@ interface PushSubscriptionJSON {
}
interface PushSubscriptionOptionsInit {
applicationServerKey?: BufferSource | string;
applicationServerKey?: BufferSource | string | null;
userVisibleOnly?: boolean;
}
@@ -263,7 +351,7 @@ interface RequestInit {
redirect?: RequestRedirect;
referrer?: string;
referrerPolicy?: ReferrerPolicy;
signal?: object | null;
signal?: AbortSignal | null;
window?: any;
}
@@ -273,6 +361,33 @@ interface ResponseInit {
statusText?: string;
}
interface RsaHashedImportParams extends Algorithm {
hash: HashAlgorithmIdentifier;
}
interface RsaHashedKeyGenParams extends RsaKeyGenParams {
hash: HashAlgorithmIdentifier;
}
interface RsaKeyGenParams extends Algorithm {
modulusLength: number;
publicExponent: BigInteger;
}
interface RsaOaepParams extends Algorithm {
label?: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer;
}
interface RsaOtherPrimesInfo {
d?: string;
r?: string;
t?: string;
}
interface RsaPssParams extends Algorithm {
saltLength: number;
}
interface StorageEstimate {
quota?: number;
usage?: number;
@@ -296,6 +411,45 @@ interface EventListener {
(evt: Event): void;
}
interface AbortController {
/**
* Returns the AbortSignal object associated with this object.
*/
readonly signal: AbortSignal;
/**
* Invoking this method will set this object's AbortSignal's aborted flag and
* signal to any observers that the associated activity is to be aborted.
*/
abort(): void;
}
declare var AbortController: {
prototype: AbortController;
new(): AbortController;
};
interface AbortSignalEventMap {
"abort": ProgressEvent;
}
interface AbortSignal extends EventTarget {
/**
* Returns true if this AbortSignal's AbortController has signaled to abort, and false
* otherwise.
*/
readonly aborted: boolean;
onabort: ((this: AbortSignal, ev: ProgressEvent) => any) | null;
addEventListener<K extends keyof AbortSignalEventMap>(type: K, listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof AbortSignalEventMap>(type: K, listener: (this: AbortSignal, ev: AbortSignalEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}
declare var AbortSignal: {
prototype: AbortSignal;
new(): AbortSignal;
};
interface AbstractWorkerEventMap {
"error": ErrorEvent;
}
@@ -401,11 +555,52 @@ declare var CacheStorage: {
new(): CacheStorage;
};
interface CanvasGradient {
/**
* Adds a color stop with the given color to the gradient at the given offset. 0.0 is the offset
* at one end of the gradient, 1.0 is the offset at the other end.
* Throws an "IndexSizeError" DOMException if the offset
* is out of range. Throws a "SyntaxError" DOMException if
* the color cannot be parsed.
*/
addColorStop(offset: number, color: string): void;
}
declare var CanvasGradient: {
prototype: CanvasGradient;
new(): CanvasGradient;
};
interface CanvasPath {
arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, anticlockwise?: boolean): void;
arcTo(x1: number, y1: number, x2: number, y2: number, radius: number): void;
bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): void;
closePath(): void;
ellipse(x: number, y: number, radiusX: number, radiusY: number, rotation: number, startAngle: number, endAngle: number, anticlockwise?: boolean): void;
lineTo(x: number, y: number): void;
moveTo(x: number, y: number): void;
quadraticCurveTo(cpx: number, cpy: number, x: number, y: number): void;
rect(x: number, y: number, w: number, h: number): void;
}
interface CanvasPattern {
/**
* Sets the transformation matrix that will be used when rendering the pattern during a fill or
* stroke painting operation.
*/
setTransform(transform?: DOMMatrix2DInit): void;
}
declare var CanvasPattern: {
prototype: CanvasPattern;
new(): CanvasPattern;
};
interface Client {
readonly id: string;
readonly type: ClientTypes;
readonly url: string;
postMessage(message: any, transfer?: any[]): void;
postMessage(message: any, transfer?: Transferable[]): void;
}
declare var Client: {
@@ -463,10 +658,8 @@ interface Console {
info(message?: any, ...optionalParams: any[]): void;
log(message?: any, ...optionalParams: any[]): void;
markTimeline(label?: string): void;
msIsIndependentlyComposed(element: object): boolean;
profile(reportName?: string): void;
profileEnd(): void;
select(element: object): void;
profileEnd(reportName?: string): void;
table(...tabularData: any[]): void;
time(label?: string): void;
timeEnd(label?: string): void;
@@ -482,11 +675,21 @@ declare var Console: {
new(): Console;
};
interface Crypto {
readonly subtle: SubtleCrypto;
getRandomValues<T extends Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | null>(array: T): T;
}
declare var Crypto: {
prototype: Crypto;
new(): Crypto;
};
interface CryptoKey {
readonly algorithm: KeyAlgorithm;
readonly extractable: boolean;
readonly type: string;
readonly usages: string[];
readonly type: KeyType;
readonly usages: KeyUsage[];
}
declare var CryptoKey: {
@@ -494,6 +697,20 @@ declare var CryptoKey: {
new(): CryptoKey;
};
interface CustomEvent<T = any> extends Event {
/**
* Returns any custom data event was created with.
* Typically used for synthetic events.
*/
readonly detail: T;
initCustomEvent(typeArg: string, canBubbleArg: boolean, cancelableArg: boolean, detailArg: T): void;
}
declare var CustomEvent: {
prototype: CustomEvent;
new<T>(typeArg: string, eventInitDict?: CustomEventInit<T>): CustomEvent<T>;
};
interface DOMException {
readonly code: number;
readonly message: string;
@@ -754,7 +971,7 @@ interface DedicatedWorkerGlobalScopeEventMap extends WorkerGlobalScopeEventMap {
interface DedicatedWorkerGlobalScope extends WorkerGlobalScope {
onmessage: ((this: DedicatedWorkerGlobalScope, ev: MessageEvent) => any) | null;
close(): void;
postMessage(message: any, transfer?: any[]): void;
postMessage(message: any, transfer?: Transferable[]): void;
addEventListener<K extends keyof DedicatedWorkerGlobalScopeEventMap>(type: K, listener: (this: DedicatedWorkerGlobalScope, ev: DedicatedWorkerGlobalScopeEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof DedicatedWorkerGlobalScopeEventMap>(type: K, listener: (this: DedicatedWorkerGlobalScope, ev: DedicatedWorkerGlobalScopeEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
@@ -791,32 +1008,65 @@ interface ErrorEvent extends Event {
readonly filename: string;
readonly lineno: number;
readonly message: string;
initErrorEvent(typeArg: string, canBubbleArg: boolean, cancelableArg: boolean, messageArg: string, filenameArg: string, linenoArg: number): void;
}
declare var ErrorEvent: {
prototype: ErrorEvent;
new(typeArg: string, eventInitDict?: ErrorEventInit): ErrorEvent;
new(type: string, eventInitDict?: ErrorEventInit): ErrorEvent;
};
interface Event {
/**
* Returns true or false depending on how event was initialized. True if event goes through its target's ancestors in reverse tree order, and false otherwise.
*/
readonly bubbles: boolean;
cancelBubble: boolean;
readonly cancelable: boolean;
/**
* Returns true or false depending on how event was initialized. True if event invokes listeners past a ShadowRoot node that is the root of its target, and false otherwise.
*/
readonly composed: boolean;
/**
* Returns the object whose event listener's callback is currently being
* invoked.
*/
readonly currentTarget: EventTarget | null;
readonly defaultPrevented: boolean;
readonly eventPhase: number;
/**
* Returns true if event was dispatched by the user agent, and
* false otherwise.
*/
readonly isTrusted: boolean;
returnValue: boolean;
readonly srcElement: object | null;
/**
* Returns the object to which event is dispatched (its target).
*/
readonly target: EventTarget | null;
/**
* Returns the event's timestamp as the number of milliseconds measured relative to
* the time origin.
*/
readonly timeStamp: number;
/**
* Returns the type of event, e.g.
* "click", "hashchange", or
* "submit".
*/
readonly type: string;
deepPath(): EventTarget[];
composedPath(): EventTarget[];
initEvent(type: string, bubbles?: boolean, cancelable?: boolean): void;
preventDefault(): void;
/**
* Invoking this method prevents event from reaching
* any registered event listeners after the current one finishes running and, when dispatched in a tree, also prevents event from reaching any
* other objects.
*/
stopImmediatePropagation(): void;
/**
* When dispatched in a tree, invoking this method prevents event from reaching any objects other than the current object.
*/
stopPropagation(): void;
readonly AT_TARGET: number;
readonly BUBBLING_PHASE: number;
@@ -826,7 +1076,7 @@ interface Event {
declare var Event: {
prototype: Event;
new(typeArg: string, eventInitDict?: EventInit): Event;
new(type: string, eventInitDict?: EventInit): Event;
readonly AT_TARGET: number;
readonly BUBBLING_PHASE: number;
readonly CAPTURING_PHASE: number;
@@ -860,9 +1110,26 @@ interface EventSourceInit {
}
interface EventTarget {
/**
* Appends an event listener for events whose type attribute value is type. The callback argument sets the callback that will be invoked when the event is dispatched.
* The options argument sets listener-specific options. For compatibility this can be a
* boolean, in which case the method behaves exactly as if the value was specified as options's capture.
* When set to true, options's capture prevents callback from being invoked when the event's eventPhase attribute value is BUBBLING_PHASE. When false (or not present), callback will not be invoked when event's eventPhase attribute value is CAPTURING_PHASE. Either way, callback will be invoked if event's eventPhase attribute value is AT_TARGET.
* When set to true, options's passive indicates that the callback will not cancel the event by invoking preventDefault(). This is used to enable performance optimizations described in §2.8 Observing event listeners.
* When set to true, options's once indicates that the callback will only be invoked once after which the event listener will
* be removed.
* The event listener is appended to target's event listener list and is not appended if it has the same type, callback, and capture.
*/
addEventListener(type: string, listener: EventListenerOrEventListenerObject | null, options?: boolean | AddEventListenerOptions): void;
dispatchEvent(evt: Event): boolean;
removeEventListener(type: string, listener?: EventListenerOrEventListenerObject | null, options?: EventListenerOptions | boolean): void;
/**
* Dispatches a synthetic event event to target and returns true
* if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise.
*/
dispatchEvent(event: Event): boolean;
/**
* Removes the event listener in target's event listener list with the same type, callback, and options.
*/
removeEventListener(type: string, callback: EventListenerOrEventListenerObject | null, options?: EventListenerOptions | boolean): void;
}
declare var EventTarget: {
@@ -992,11 +1259,11 @@ interface FormData {
declare var FormData: {
prototype: FormData;
new(form?: object): FormData;
new(): FormData;
};
interface GlobalFetch {
fetch(input?: Request | string, init?: RequestInit): Promise<Response>;
fetch(input: RequestInfo, init?: RequestInit): Promise<Response>;
}
interface Headers {
@@ -1061,13 +1328,13 @@ interface IDBCursor {
* Delete the record pointed at by the cursor with a new value.
* If successful, request's result will be undefined.
*/
delete(): IDBRequest;
delete(): IDBRequest<undefined>;
/**
* Updated the record pointed at by the cursor with a new value.
* Throws a "DataError" DOMException if the effective object store uses in-line keys and the key would have changed.
* If successful, request's result will be the record's key.
*/
update(value: any): IDBRequest;
update(value: any): IDBRequest<IDBValidKey>;
}
declare var IDBCursor: {
@@ -1189,40 +1456,40 @@ interface IDBIndex {
* If successful, request's result will be the
* count.
*/
count(key?: IDBValidKey | IDBKeyRange): IDBRequest;
count(key?: IDBValidKey | IDBKeyRange): IDBRequest<number>;
/**
* Retrieves the value of the first record matching the
* given key or key range in query.
* If successful, request's result will be the value, or undefined if there was no matching record.
*/
get(key: IDBValidKey | IDBKeyRange): IDBRequest;
get(key: IDBValidKey | IDBKeyRange): IDBRequest<any | undefined>;
/**
* Retrieves the values of the records matching the given key or key range in query (up to count if given).
* If successful, request's result will be an Array of the values.
*/
getAll(query?: IDBValidKey | IDBKeyRange, count?: number): IDBRequest;
getAll(query?: IDBValidKey | IDBKeyRange, count?: number): IDBRequest<any[]>;
/**
* Retrieves the keys of records matching the given key or key range in query (up to count if given).
* If successful, request's result will be an Array of the keys.
*/
getAllKeys(query?: IDBValidKey | IDBKeyRange, count?: number): IDBRequest;
getAllKeys(query?: IDBValidKey | IDBKeyRange, count?: number): IDBRequest<IDBValidKey[]>;
/**
* Retrieves the key of the first record matching the
* given key or key range in query.
* If successful, request's result will be the key, or undefined if there was no matching record.
*/
getKey(key: IDBValidKey | IDBKeyRange): IDBRequest;
getKey(key: IDBValidKey | IDBKeyRange): IDBRequest<IDBValidKey | undefined>;
/**
* Opens a cursor over the records matching query,
* ordered by direction. If query is null, all records in index are matched.
* If successful, request's result will be an IDBCursorWithValue, or null if there were no matching records.
*/
openCursor(range?: IDBValidKey | IDBKeyRange, direction?: IDBCursorDirection): IDBRequest;
openCursor(range?: IDBValidKey | IDBKeyRange, direction?: IDBCursorDirection): IDBRequest<IDBCursorWithValue | null>;
/**
* Opens a cursor with key only flag set over the records matching query, ordered by direction. If query is null, all records in index are matched.
* If successful, request's result will be an IDBCursor, or null if there were no matching records.
*/
openKeyCursor(range?: IDBValidKey | IDBKeyRange, direction?: IDBCursorDirection): IDBRequest;
openKeyCursor(range?: IDBValidKey | IDBKeyRange, direction?: IDBCursorDirection): IDBRequest<IDBCursor | null>;
}
declare var IDBIndex: {
@@ -1301,19 +1568,19 @@ interface IDBObjectStore {
* Returns the associated transaction.
*/
readonly transaction: IDBTransaction;
add(value: any, key?: IDBValidKey | IDBKeyRange): IDBRequest;
add(value: any, key?: IDBValidKey | IDBKeyRange): IDBRequest<IDBValidKey>;
/**
* Deletes all records in store.
* If successful, request's result will
* be undefined.
*/
clear(): IDBRequest;
clear(): IDBRequest<undefined>;
/**
* Retrieves the number of records matching the
* given key or key range in query.
* If successful, request's result will be the count.
*/
count(key?: IDBValidKey | IDBKeyRange): IDBRequest;
count(key?: IDBValidKey | IDBKeyRange): IDBRequest<number>;
/**
* Creates a new index in store with the given name, keyPath and options and returns a new IDBIndex. If the keyPath and options define constraints that cannot be
* satisfied with the data already in store the upgrade
@@ -1328,7 +1595,7 @@ interface IDBObjectStore {
* If successful, request's result will
* be undefined.
*/
delete(key: IDBValidKey | IDBKeyRange): IDBRequest;
delete(key: IDBValidKey | IDBKeyRange): IDBRequest<undefined>;
/**
* Deletes the index in store with the given name.
* Throws an "InvalidStateError" DOMException if not called within an upgrade
@@ -1340,41 +1607,41 @@ interface IDBObjectStore {
* given key or key range in query.
* If successful, request's result will be the value, or undefined if there was no matching record.
*/
get(query: IDBValidKey | IDBKeyRange): IDBRequest;
get(query: IDBValidKey | IDBKeyRange): IDBRequest<any | undefined>;
/**
* Retrieves the values of the records matching the
* given key or key range in query (up to count if given).
* If successful, request's result will
* be an Array of the values.
*/
getAll(query?: IDBValidKey | IDBKeyRange, count?: number): IDBRequest;
getAll(query?: IDBValidKey | IDBKeyRange, count?: number): IDBRequest<any[]>;
/**
* Retrieves the keys of records matching the
* given key or key range in query (up to count if given).
* If successful, request's result will
* be an Array of the keys.
*/
getAllKeys(query?: IDBValidKey | IDBKeyRange, count?: number): IDBRequest;
getAllKeys(query?: IDBValidKey | IDBKeyRange, count?: number): IDBRequest<IDBValidKey[]>;
/**
* Retrieves the key of the first record matching the
* given key or key range in query.
* If successful, request's result will be the key, or undefined if there was no matching record.
*/
getKey(query: IDBValidKey | IDBKeyRange): IDBRequest;
getKey(query: IDBValidKey | IDBKeyRange): IDBRequest<IDBValidKey | undefined>;
index(name: string): IDBIndex;
/**
* Opens a cursor over the records matching query,
* ordered by direction. If query is null, all records in store are matched.
* If successful, request's result will be an IDBCursorWithValue pointing at the first matching record, or null if there were no matching records.
*/
openCursor(range?: IDBValidKey | IDBKeyRange, direction?: IDBCursorDirection): IDBRequest;
openCursor(range?: IDBValidKey | IDBKeyRange, direction?: IDBCursorDirection): IDBRequest<IDBCursorWithValue | null>;
/**
* Opens a cursor with key only flag set over the records matching query, ordered by direction. If query is null, all records in store are matched.
* If successful, request's result will be an IDBCursor pointing at the first matching record, or
* null if there were no matching records.
*/
openKeyCursor(query?: IDBValidKey | IDBKeyRange, direction?: IDBCursorDirection): IDBRequest;
put(value: any, key?: IDBValidKey | IDBKeyRange): IDBRequest;
openKeyCursor(query?: IDBValidKey | IDBKeyRange, direction?: IDBCursorDirection): IDBRequest<IDBCursor | null>;
put(value: any, key?: IDBValidKey | IDBKeyRange): IDBRequest<IDBValidKey>;
}
declare var IDBObjectStore: {
@@ -1387,7 +1654,7 @@ interface IDBOpenDBRequestEventMap extends IDBRequestEventMap {
"upgradeneeded": IDBVersionChangeEvent;
}
interface IDBOpenDBRequest extends IDBRequest {
interface IDBOpenDBRequest extends IDBRequest<IDBDatabase> {
onblocked: ((this: IDBOpenDBRequest, ev: Event) => any) | null;
onupgradeneeded: ((this: IDBOpenDBRequest, ev: IDBVersionChangeEvent) => any) | null;
addEventListener<K extends keyof IDBOpenDBRequestEventMap>(type: K, listener: (this: IDBOpenDBRequest, ev: IDBOpenDBRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
@@ -1406,14 +1673,14 @@ interface IDBRequestEventMap {
"success": Event;
}
interface IDBRequest extends EventTarget {
interface IDBRequest<T = any> extends EventTarget {
/**
* When a request is completed, returns the error (a DOMException), or null if the request succeeded. Throws
* a "InvalidStateError" DOMException if the request is still pending.
*/
readonly error: DOMException | null;
onerror: ((this: IDBRequest, ev: Event) => any) | null;
onsuccess: ((this: IDBRequest, ev: Event) => any) | null;
onerror: ((this: IDBRequest<T>, ev: Event) => any) | null;
onsuccess: ((this: IDBRequest<T>, ev: Event) => any) | null;
/**
* Returns "pending" until a request is complete,
* then returns "done".
@@ -1424,7 +1691,7 @@ interface IDBRequest extends EventTarget {
* or undefined if the request failed. Throws a
* "InvalidStateError" DOMException if the request is still pending.
*/
readonly result: any;
readonly result: T;
/**
* Returns the IDBObjectStore, IDBIndex, or IDBCursor the request was made against, or null if is was an open
* request.
@@ -1435,9 +1702,9 @@ interface IDBRequest extends EventTarget {
* If this as an open request, then it returns an upgrade transaction while it is running, or null otherwise.
*/
readonly transaction: IDBTransaction | null;
addEventListener<K extends keyof IDBRequestEventMap>(type: K, listener: (this: IDBRequest, ev: IDBRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener<K extends keyof IDBRequestEventMap>(type: K, listener: (this: IDBRequest<T>, ev: IDBRequestEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof IDBRequestEventMap>(type: K, listener: (this: IDBRequest, ev: IDBRequestEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener<K extends keyof IDBRequestEventMap>(type: K, listener: (this: IDBRequest<T>, ev: IDBRequestEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
}
@@ -1508,11 +1775,27 @@ declare var IDBVersionChangeEvent: {
};
interface ImageBitmap {
/**
* Returns the intrinsic height of the image, in CSS
* pixels.
*/
readonly height: number;
/**
* Returns the intrinsic width of the image, in CSS
* pixels.
*/
readonly width: number;
/**
* Releases imageBitmap's underlying bitmap data.
*/
close(): void;
}
declare var ImageBitmap: {
prototype: ImageBitmap;
new(): ImageBitmap;
};
interface ImageBitmapOptions {
colorSpaceConversion?: "none" | "default";
imageOrientation?: "none" | "flipY";
@@ -1523,6 +1806,17 @@ interface ImageBitmapOptions {
}
interface ImageData {
/**
* Returns the one-dimensional array containing the data in RGBA order, as integers in the
* range 0 to 255.
*/
readonly data: Uint8ClampedArray;
/**
* Returns the actual dimensions of the data in the ImageData object, in
* pixels.
*/
readonly height: number;
readonly width: number;
}
declare var ImageData: {
@@ -1542,11 +1836,31 @@ declare var MessageChannel: {
};
interface MessageEvent extends Event {
/**
* Returns the data of the message.
*/
readonly data: any;
/**
* Returns the last event ID string, for
* server-sent events.
*/
readonly lastEventId: string;
/**
* Returns the origin of the message, for server-sent events and
* cross-document messaging.
*/
readonly origin: string;
/**
* Returns the MessagePort array sent with the message, for cross-document
* messaging and channel messaging.
*/
readonly ports: ReadonlyArray<MessagePort>;
readonly source: MessageEventSource;
initMessageEvent(type: string, bubbles: boolean, cancelable: boolean, data: any, origin: string, lastEventId: string, source: object): void;
/**
* Returns the WindowProxy of the source window, for cross-document
* messaging, and the MessagePort being attached, in the connect event fired at
* SharedWorkerGlobalScope objects.
*/
readonly source: MessageEventSource | null;
}
declare var MessageEvent: {
@@ -1573,7 +1887,7 @@ interface MessagePort extends EventTarget {
* transfer contains duplicate objects or port, or if message
* could not be cloned.
*/
postMessage(message: any, transfer?: any[]): void;
postMessage(message: any, transfer?: Transferable[]): void;
/**
* Begins dispatching messages received on the port.
*/
@@ -1680,6 +1994,15 @@ declare var NotificationEvent: {
new(type: string, eventInitDict: NotificationEventInit): NotificationEvent;
};
interface Path2D extends CanvasPath {
addPath(path: Path2D, transform?: DOMMatrix2DInit): void;
}
declare var Path2D: {
prototype: Path2D;
new(path?: Path2D | string): Path2D;
};
interface PerformanceEventMap {
"resourcetimingbufferfull": Event;
}
@@ -1798,7 +2121,7 @@ declare var ProgressEvent: {
};
interface PromiseRejectionEvent extends Event {
readonly promise: PromiseLike<any>;
readonly promise: Promise<any>;
readonly reason: any;
}
@@ -1968,7 +2291,7 @@ interface Request extends Body {
* Returns the signal associated with request, which is an AbortSignal object indicating whether or not request has been aborted, and its abort
* event handler.
*/
readonly signal: object;
readonly signal: AbortSignal;
/**
* Returns the URL of request as a string.
*/
@@ -2008,7 +2331,7 @@ interface ServiceWorker extends EventTarget, AbstractWorker {
onstatechange: ((this: ServiceWorker, ev: Event) => any) | null;
readonly scriptURL: string;
readonly state: ServiceWorkerState;
postMessage(message: any, transfer?: any[]): void;
postMessage(message: any, transfer?: Transferable[]): void;
addEventListener<K extends keyof ServiceWorkerEventMap>(type: K, listener: (this: ServiceWorker, ev: ServiceWorkerEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
removeEventListener<K extends keyof ServiceWorkerEventMap>(type: K, listener: (this: ServiceWorker, ev: ServiceWorkerEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
@@ -2124,6 +2447,32 @@ declare var StorageManager: {
new(): StorageManager;
};
interface SubtleCrypto {
decrypt(algorithm: string | RsaOaepParams | AesCtrParams | AesCbcParams | AesCmacParams | AesGcmParams | AesCfbParams, key: CryptoKey, data: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer): PromiseLike<ArrayBuffer>;
deriveBits(algorithm: string | EcdhKeyDeriveParams | DhKeyDeriveParams | ConcatParams | HkdfCtrParams | Pbkdf2Params, baseKey: CryptoKey, length: number): PromiseLike<ArrayBuffer>;
deriveKey(algorithm: string | EcdhKeyDeriveParams | DhKeyDeriveParams | ConcatParams | HkdfCtrParams | Pbkdf2Params, baseKey: CryptoKey, derivedKeyType: string | AesDerivedKeyParams | HmacImportParams | ConcatParams | HkdfCtrParams | Pbkdf2Params, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKey>;
digest(algorithm: string | Algorithm, data: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer): PromiseLike<ArrayBuffer>;
encrypt(algorithm: string | RsaOaepParams | AesCtrParams | AesCbcParams | AesCmacParams | AesGcmParams | AesCfbParams, key: CryptoKey, data: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer): PromiseLike<ArrayBuffer>;
exportKey(format: "jwk", key: CryptoKey): PromiseLike<JsonWebKey>;
exportKey(format: "raw" | "pkcs8" | "spki", key: CryptoKey): PromiseLike<ArrayBuffer>;
exportKey(format: string, key: CryptoKey): PromiseLike<JsonWebKey | ArrayBuffer>;
generateKey(algorithm: string, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKeyPair | CryptoKey>;
generateKey(algorithm: RsaHashedKeyGenParams | EcKeyGenParams | DhKeyGenParams, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKeyPair>;
generateKey(algorithm: AesKeyGenParams | HmacKeyGenParams | Pbkdf2Params, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKey>;
importKey(format: "jwk", keyData: JsonWebKey, algorithm: string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams | AesKeyAlgorithm, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKey>;
importKey(format: "raw" | "pkcs8" | "spki", keyData: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer, algorithm: string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams | AesKeyAlgorithm, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKey>;
importKey(format: string, keyData: JsonWebKey | Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer, algorithm: string | RsaHashedImportParams | EcKeyImportParams | HmacImportParams | DhImportKeyParams | AesKeyAlgorithm, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKey>;
sign(algorithm: string | RsaPssParams | EcdsaParams | AesCmacParams, key: CryptoKey, data: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer): PromiseLike<ArrayBuffer>;
unwrapKey(format: string, wrappedKey: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer, unwrappingKey: CryptoKey, unwrapAlgorithm: string | Algorithm, unwrappedKeyAlgorithm: string | Algorithm, extractable: boolean, keyUsages: string[]): PromiseLike<CryptoKey>;
verify(algorithm: string | RsaPssParams | EcdsaParams | AesCmacParams, key: CryptoKey, signature: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer, data: Int8Array | Int16Array | Int32Array | Uint8Array | Uint16Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array | DataView | ArrayBuffer): PromiseLike<boolean>;
wrapKey(format: string, key: CryptoKey, wrappingKey: CryptoKey, wrapAlgorithm: string | Algorithm): PromiseLike<ArrayBuffer>;
}
declare var SubtleCrypto: {
prototype: SubtleCrypto;
new(): SubtleCrypto;
};
interface SyncEvent extends ExtendableEvent {
readonly lastChance: boolean;
readonly tag: string;
@@ -2313,13 +2662,31 @@ interface WindowConsole {
readonly console: Console;
}
interface WindowOrWorkerGlobalScope {
readonly caches: CacheStorage;
readonly crypto: Crypto;
readonly indexedDB: IDBFactory;
readonly origin: string;
readonly performance: Performance;
atob(data: string): string;
btoa(data: string): string;
clearInterval(handle?: number): void;
clearTimeout(handle?: number): void;
createImageBitmap(image: ImageBitmapSource): Promise<ImageBitmap>;
createImageBitmap(image: ImageBitmapSource, sx: number, sy: number, sw: number, sh: number): Promise<ImageBitmap>;
fetch(input: RequestInfo, init?: RequestInit): Promise<Response>;
queueMicrotask(callback: Function): void;
setInterval(handler: TimerHandler, timeout?: number, ...arguments: any[]): number;
setTimeout(handler: TimerHandler, timeout?: number, ...arguments: any[]): number;
}
interface WorkerEventMap extends AbstractWorkerEventMap {
"message": MessageEvent;
}
interface Worker extends EventTarget, AbstractWorker {
onmessage: ((this: Worker, ev: MessageEvent) => any) | null;
postMessage(message: any, transfer?: any[]): void;
postMessage(message: any, transfer?: Transferable[]): void;
terminate(): void;
addEventListener<K extends keyof WorkerEventMap>(type: K, listener: (this: Worker, ev: WorkerEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
@@ -2336,15 +2703,13 @@ interface WorkerGlobalScopeEventMap {
"error": ErrorEvent;
}
interface WorkerGlobalScope extends EventTarget, WorkerUtils, WindowConsole, GlobalFetch {
interface WorkerGlobalScope extends EventTarget, WorkerUtils, WindowConsole, GlobalFetch, WindowOrWorkerGlobalScope {
readonly caches: CacheStorage;
readonly isSecureContext: boolean;
readonly location: WorkerLocation;
onerror: ((this: WorkerGlobalScope, ev: ErrorEvent) => any) | null;
readonly performance: Performance;
readonly self: WorkerGlobalScope;
createImageBitmap(image: ImageBitmap | ImageData | Blob, options?: ImageBitmapOptions): Promise<ImageBitmap>;
createImageBitmap(image: ImageBitmap | ImageData | Blob, sx: number, sy: number, sw: number, sh: number, options?: ImageBitmapOptions): Promise<ImageBitmap>;
msWriteProfilerMark(profilerMarkName: string): void;
addEventListener<K extends keyof WorkerGlobalScopeEventMap>(type: K, listener: (this: WorkerGlobalScope, ev: WorkerGlobalScopeEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
@@ -2388,13 +2753,7 @@ interface WorkerUtils extends WindowBase64 {
readonly indexedDB: IDBFactory;
readonly msIndexedDB: IDBFactory;
readonly navigator: WorkerNavigator;
clearImmediate(handle: number): void;
clearInterval(handle: number): void;
clearTimeout(handle: number): void;
importScripts(...urls: string[]): void;
setImmediate(handler: any, ...args: any[]): number;
setInterval(handler: any, timeout?: any, ...args: any[]): number;
setTimeout(handler: any, timeout?: any, ...args: any[]): number;
}
interface XMLHttpRequestEventMap extends XMLHttpRequestEventTargetEventMap {
@@ -2478,7 +2837,7 @@ interface XMLHttpRequest extends XMLHttpRequestEventTarget {
* Initiates the request. The optional argument provides the request body. The argument is ignored if request method is GET or HEAD.
* Throws an "InvalidStateError" DOMException if either state is not opened or the send() flag is set.
*/
send(body?: object | BodyInit): void;
send(body?: BodyInit | null): void;
/**
* Combines a header in author request headers.
* Throws an "InvalidStateError" DOMException if either state is not opened or the send() flag is set.
@@ -2560,31 +2919,47 @@ interface PerformanceObserverCallback {
declare var onmessage: ((this: DedicatedWorkerGlobalScope, ev: MessageEvent) => any) | null;
declare function close(): void;
declare function postMessage(message: any, transfer?: any[]): void;
declare function dispatchEvent(evt: Event): boolean;
declare function postMessage(message: any, transfer?: Transferable[]): void;
/**
* Dispatches a synthetic event event to target and returns true
* if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise.
*/
declare function dispatchEvent(event: Event): boolean;
declare var caches: CacheStorage;
declare var isSecureContext: boolean;
declare var location: WorkerLocation;
declare var onerror: ((this: DedicatedWorkerGlobalScope, ev: ErrorEvent) => any) | null;
declare var performance: Performance;
declare var self: WorkerGlobalScope;
declare function createImageBitmap(image: ImageBitmap | ImageData | Blob, options?: ImageBitmapOptions): Promise<ImageBitmap>;
declare function createImageBitmap(image: ImageBitmap | ImageData | Blob, sx: number, sy: number, sw: number, sh: number, options?: ImageBitmapOptions): Promise<ImageBitmap>;
declare function msWriteProfilerMark(profilerMarkName: string): void;
declare function dispatchEvent(evt: Event): boolean;
/**
* Dispatches a synthetic event event to target and returns true
* if either event's cancelable attribute value is false or its preventDefault() method was not invoked, and false otherwise.
*/
declare function dispatchEvent(event: Event): boolean;
declare var indexedDB: IDBFactory;
declare var msIndexedDB: IDBFactory;
declare var navigator: WorkerNavigator;
declare function clearImmediate(handle: number): void;
declare function clearInterval(handle: number): void;
declare function clearTimeout(handle: number): void;
declare function setImmediate(handler: any, ...args: any[]): number;
declare function setInterval(handler: any, timeout?: any, ...args: any[]): number;
declare function setTimeout(handler: any, timeout?: any, ...args: any[]): number;
declare function importScripts(...urls: string[]): void;
declare function atob(encodedString: string): string;
declare function btoa(rawString: string): string;
declare var console: Console;
declare function fetch(input?: Request | string, init?: RequestInit): Promise<Response>;
declare function fetch(input: RequestInfo, init?: RequestInit): Promise<Response>;
declare var caches: CacheStorage;
declare var crypto: Crypto;
declare var indexedDB: IDBFactory;
declare var origin: string;
declare var performance: Performance;
declare function atob(data: string): string;
declare function btoa(data: string): string;
declare function clearInterval(handle?: number): void;
declare function clearTimeout(handle?: number): void;
declare function createImageBitmap(image: ImageBitmapSource): Promise<ImageBitmap>;
declare function createImageBitmap(image: ImageBitmapSource, sx: number, sy: number, sw: number, sh: number): Promise<ImageBitmap>;
declare function fetch(input: RequestInfo, init?: RequestInit): Promise<Response>;
declare function queueMicrotask(callback: Function): void;
declare function setInterval(handler: TimerHandler, timeout?: number, ...arguments: any[]): number;
declare function setTimeout(handler: TimerHandler, timeout?: number, ...arguments: any[]): number;
declare function addEventListener<K extends keyof DedicatedWorkerGlobalScopeEventMap>(type: K, listener: (this: DedicatedWorkerGlobalScope, ev: DedicatedWorkerGlobalScopeEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
declare function addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
declare function removeEventListener<K extends keyof DedicatedWorkerGlobalScopeEventMap>(type: K, listener: (this: DedicatedWorkerGlobalScope, ev: DedicatedWorkerGlobalScopeEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
@@ -2594,19 +2969,30 @@ type HeadersInit = Headers | string[][] | Record<string, string>;
type BodyInit = Blob | BufferSource | FormData | URLSearchParams | ReadableStream | string;
type RequestInfo = Request | string;
type DOMHighResTimeStamp = number;
type CanvasImageSource = ImageBitmap;
type MessageEventSource = MessagePort | ServiceWorker;
type ImageBitmapSource = CanvasImageSource | Blob | ImageData;
type TimerHandler = string | Function;
type PerformanceEntryList = PerformanceEntry[];
type PushMessageDataInit = BufferSource | string;
type VibratePattern = number | number[];
type AlgorithmIdentifier = string | Algorithm;
type HashAlgorithmIdentifier = AlgorithmIdentifier;
type BigInteger = Uint8Array;
type NamedCurve = string;
type BufferSource = ArrayBufferView | ArrayBuffer;
type DOMTimeStamp = number;
type FormDataEntryValue = File | string;
type IDBValidKey = number | string | Date | BufferSource | IDBArrayKey;
type MessageEventSource = object | MessagePort | ServiceWorker;
type Transferable = ArrayBuffer | MessagePort | ImageBitmap;
type BinaryType = "blob" | "arraybuffer";
type ClientTypes = "window" | "worker" | "sharedworker" | "all";
type IDBCursorDirection = "next" | "nextunique" | "prev" | "prevunique";
type IDBRequestReadyState = "pending" | "done";
type IDBTransactionMode = "readonly" | "readwrite" | "versionchange";
type KeyFormat = "raw" | "spki" | "pkcs8" | "jwk";
type KeyType = "public" | "private" | "secret";
type KeyUsage = "encrypt" | "decrypt" | "sign" | "verify" | "deriveKey" | "deriveBits" | "wrapKey" | "unwrapKey";
type NotificationDirection = "auto" | "ltr" | "rtl";
type NotificationPermission = "default" | "denied" | "granted";
type PushEncryptionKeyName = "p256dh" | "auth";
@@ -2620,6 +3006,6 @@ type RequestRedirect = "follow" | "error" | "manual";
type ResponseType = "basic" | "cors" | "default" | "error" | "opaque" | "opaqueredirect";
type ServiceWorkerState = "installing" | "installed" | "activating" | "activated" | "redundant";
type ServiceWorkerUpdateViaCache = "imports" | "all" | "none";
type VisibilityState = "hidden" | "visible" | "prerender" | "unloaded";
type VisibilityState = "hidden" | "visible" | "prerender";
type WorkerType = "classic" | "module";
type XMLHttpRequestResponseType = "" | "arraybuffer" | "blob" | "document" | "json" | "text";
type XMLHttpRequestResponseType = "" | "arraybuffer" | "blob" | "document" | "json" | "text";
+26 -1
View File
@@ -519,7 +519,7 @@ declare namespace ts.server.protocol {
/**
* Errorcodes we want to get the fixes for.
*/
errorCodes?: ReadonlyArray<number>;
errorCodes: ReadonlyArray<number>;
}
interface GetCombinedCodeFixRequestArgs {
scope: GetCombinedCodeFixScope;
@@ -591,6 +591,12 @@ declare namespace ts.server.protocol {
interface DefinitionRequest extends FileLocationRequest {
command: CommandTypes.Definition;
}
interface DefinitionAndBoundSpanRequest extends FileLocationRequest {
readonly command: CommandTypes.DefinitionAndBoundSpan;
}
interface DefinitionAndBoundSpanResponse extends Response {
readonly body: DefinitionInfoAndBoundSpan;
}
/**
* Go to type request; value of command field is
* "typeDefinition". Return response giving the file locations that
@@ -1879,6 +1885,25 @@ declare namespace ts.server.protocol {
*/
openFiles: string[];
}
type LargeFileReferencedEventName = "largeFileReferenced";
interface LargeFileReferencedEvent extends Event {
event: LargeFileReferencedEventName;
body: LargeFileReferencedEventBody;
}
interface LargeFileReferencedEventBody {
/**
* name of the large file being loaded
*/
file: string;
/**
* size of the file
*/
fileSize: number;
/**
* max file size allowed on the server
*/
maxFileSize: number;
}
/**
* Arguments for reload request.
*/
+1 -1
View File
@@ -49,7 +49,7 @@
"A_namespace_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged_2434": "Uma declaração de namespace não pode estar localizada antes de uma classe ou função com a qual ela é mesclada.",
"A_namespace_declaration_is_only_allowed_in_a_namespace_or_module_1235": "Uma declaração de namespace só é permitida e um namespace ou módulo.",
"A_namespace_style_import_cannot_be_called_or_constructed_and_will_cause_a_failure_at_runtime_7038": "Uma importação de estilo do namespace não pode ser chamada nem construída e causará uma falha no tempo de execução.",
"A_non_dry_build_would_build_project_0_6357": "Um build não -dry compilaria o projeto '{0}'",
"A_non_dry_build_would_build_project_0_6357": "Um build não -dry criaria o projeto '{0}'",
"A_non_dry_build_would_delete_the_following_files_Colon_0_6356": "Um build não -dry excluiria os seguintes arquivos: {0}",
"A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation_2371": "Um inicializador de parâmetro só é permitido em uma implementação de função ou de construtor.",
"A_parameter_property_cannot_be_declared_using_a_rest_parameter_1317": "Uma propriedade de parâmetro não pode ser declarada usando um parâmetro rest.",
+2580 -1537
View File
File diff suppressed because it is too large Load Diff
+4949 -2943
View File
File diff suppressed because it is too large Load Diff
+1571 -6942
View File
File diff suppressed because it is too large Load Diff
+14777 -10435
View File
File diff suppressed because it is too large Load Diff
+138 -44
View File
@@ -13,9 +13,8 @@ See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
declare namespace ts {
const versionMajorMinor = "3.0";
const versionMajorMinor = "3.1";
/** The version of the TypeScript compiler release */
const version: string;
}
@@ -369,20 +368,21 @@ declare namespace ts {
JSDocAugmentsTag = 293,
JSDocClassTag = 294,
JSDocCallbackTag = 295,
JSDocParameterTag = 296,
JSDocReturnTag = 297,
JSDocThisTag = 298,
JSDocTypeTag = 299,
JSDocTemplateTag = 300,
JSDocTypedefTag = 301,
JSDocPropertyTag = 302,
SyntaxList = 303,
NotEmittedStatement = 304,
PartiallyEmittedExpression = 305,
CommaListExpression = 306,
MergeDeclarationMarker = 307,
EndOfDeclarationMarker = 308,
Count = 309,
JSDocEnumTag = 296,
JSDocParameterTag = 297,
JSDocReturnTag = 298,
JSDocThisTag = 299,
JSDocTypeTag = 300,
JSDocTemplateTag = 301,
JSDocTypedefTag = 302,
JSDocPropertyTag = 303,
SyntaxList = 304,
NotEmittedStatement = 305,
PartiallyEmittedExpression = 306,
CommaListExpression = 307,
MergeDeclarationMarker = 308,
EndOfDeclarationMarker = 309,
Count = 310,
FirstAssignment = 58,
LastAssignment = 70,
FirstCompoundAssignment = 59,
@@ -409,9 +409,9 @@ declare namespace ts {
LastBinaryOperator = 70,
FirstNode = 146,
FirstJSDocNode = 281,
LastJSDocNode = 302,
LastJSDocNode = 303,
FirstJSDocTagNode = 292,
LastJSDocTagNode = 302
LastJSDocTagNode = 303
}
enum NodeFlags {
None = 0,
@@ -480,7 +480,7 @@ declare namespace ts {
}
interface JSDocContainer {
}
type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | LabeledStatement | ExpressionStatement | VariableStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | EndOfFileToken;
type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | LabeledStatement | ExpressionStatement | VariableStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | ExportDeclaration | EndOfFileToken;
type HasType = SignatureDeclaration | VariableDeclaration | ParameterDeclaration | PropertySignature | PropertyDeclaration | TypePredicateNode | ParenthesizedTypeNode | TypeOperatorNode | MappedTypeNode | AssertionExpression | TypeAliasDeclaration | JSDocTypeExpression | JSDocNonNullableType | JSDocNullableType | JSDocOptionalType | JSDocVariadicType;
type HasInitializer = HasExpressionInitializer | ForStatement | ForInStatement | ForOfStatement | JsxAttribute;
type HasExpressionInitializer = VariableDeclaration | ParameterDeclaration | BindingElement | PropertySignature | PropertyDeclaration | PropertyAssignment | EnumMember;
@@ -546,8 +546,9 @@ declare namespace ts {
}
interface TypeParameterDeclaration extends NamedDeclaration {
kind: SyntaxKind.TypeParameter;
parent: DeclarationWithTypeParameters | InferTypeNode;
parent: DeclarationWithTypeParameterChildren | InferTypeNode;
name: Identifier;
/** Note: Consider calling `getEffectiveConstraintOfTypeParameter` */
constraint?: TypeNode;
default?: TypeNode;
expression?: Expression;
@@ -617,6 +618,7 @@ declare namespace ts {
_objectLiteralBrandBrand: any;
name?: PropertyName;
}
/** Unlike ObjectLiteralElement, excludes JSXAttribute and JSXSpreadAttribute. */
type ObjectLiteralElementLike = PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment | MethodDeclaration | AccessorDeclaration;
interface PropertyAssignment extends ObjectLiteralElement, JSDocContainer {
parent: ObjectLiteralExpression;
@@ -750,7 +752,7 @@ declare namespace ts {
}
interface TypePredicateNode extends TypeNode {
kind: SyntaxKind.TypePredicate;
parent: SignatureDeclaration;
parent: SignatureDeclaration | JSDocTypeExpression;
parameterName: Identifier | ThisTypeNode;
type: TypeNode;
}
@@ -1318,7 +1320,8 @@ declare namespace ts {
block: Block;
}
type ObjectTypeDeclaration = ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode;
type DeclarationWithTypeParameters = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag | JSDocTypedefTag | JSDocCallbackTag | JSDocSignature;
type DeclarationWithTypeParameters = DeclarationWithTypeParameterChildren | JSDocTypedefTag | JSDocCallbackTag | JSDocSignature;
type DeclarationWithTypeParameterChildren = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag;
interface ClassLikeDeclarationBase extends NamedDeclaration, JSDocContainer {
kind: SyntaxKind.ClassDeclaration | SyntaxKind.ClassExpression;
name?: Identifier;
@@ -1437,7 +1440,7 @@ declare namespace ts {
kind: SyntaxKind.NamespaceExportDeclaration;
name: Identifier;
}
interface ExportDeclaration extends DeclarationStatement {
interface ExportDeclaration extends DeclarationStatement, JSDocContainer {
kind: SyntaxKind.ExportDeclaration;
parent: SourceFile | ModuleBlock;
/** Will not be assigned in the case of `export * from "foo";` */
@@ -1556,12 +1559,17 @@ declare namespace ts {
interface JSDocClassTag extends JSDocTag {
kind: SyntaxKind.JSDocClassTag;
}
interface JSDocEnumTag extends JSDocTag {
kind: SyntaxKind.JSDocEnumTag;
typeExpression?: JSDocTypeExpression;
}
interface JSDocThisTag extends JSDocTag {
kind: SyntaxKind.JSDocThisTag;
typeExpression?: JSDocTypeExpression;
}
interface JSDocTemplateTag extends JSDocTag {
kind: SyntaxKind.JSDocTemplateTag;
constraint: TypeNode | undefined;
typeParameters: NodeArray<TypeParameterDeclaration>;
}
interface JSDocReturnTag extends JSDocTag {
@@ -1902,7 +1910,7 @@ declare namespace ts {
*/
getExportSymbolOfSymbol(symbol: Symbol): Symbol;
getPropertySymbolOfDestructuringAssignment(location: Identifier): Symbol | undefined;
getTypeAtLocation(node: Node): Type | undefined;
getTypeAtLocation(node: Node): Type;
getTypeFromTypeNode(node: TypeNode): Type;
signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): string;
typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string;
@@ -1934,9 +1942,6 @@ declare namespace ts {
getAmbientModules(): Symbol[];
tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined;
getApparentType(type: Type): Type;
getSuggestionForNonexistentProperty(name: Identifier | string, containingType: Type): string | undefined;
getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
getSuggestionForNonexistentModule(node: Identifier, target: Symbol): string | undefined;
getBaseConstraintOfType(type: Type): Type | undefined;
getDefaultFromTypeParameter(type: Type): Type | undefined;
/**
@@ -2052,6 +2057,7 @@ declare namespace ts {
Optional = 16777216,
Transient = 33554432,
JSContainer = 67108864,
ModuleExports = 134217728,
Enum = 384,
Variable = 3,
Value = 67216319,
@@ -2079,8 +2085,6 @@ declare namespace ts {
AliasExcludes = 2097152,
ModuleMember = 2623475,
ExportHasLocal = 944,
HasExports = 1955,
HasMembers = 6240,
BlockScoped = 418,
PropertyOrAccessor = 98308,
ClassMember = 106500
@@ -2110,7 +2114,8 @@ declare namespace ts {
Computed = "__computed",
Resolving = "__resolving__",
ExportEquals = "export=",
Default = "default"
Default = "default",
This = "this"
}
/**
* This represents a string whose leading underscore have been escaped by adding extra leading underscores.
@@ -2228,6 +2233,7 @@ declare namespace ts {
ReverseMapped = 2048,
JsxAttributes = 4096,
MarkerType = 8192,
JSLiteral = 16384,
ClassOrInterface = 3
}
interface ObjectType extends Type {
@@ -2486,6 +2492,7 @@ declare namespace ts {
strictFunctionTypes?: boolean;
strictNullChecks?: boolean;
strictPropertyInitialization?: boolean;
stripInternal?: boolean;
suppressExcessPropertyErrors?: boolean;
suppressImplicitAnyIndexErrors?: boolean;
target?: ScriptTarget;
@@ -2587,7 +2594,7 @@ declare namespace ts {
}
interface UpToDateHost {
fileExists(fileName: string): boolean;
getModifiedTime(fileName: string): Date;
getModifiedTime(fileName: string): Date | undefined;
getUnchangedTime?(fileName: string): Date | undefined;
getLastStatus?(fileName: string): UpToDateStatus | undefined;
setLastStatus?(fileName: string, status: UpToDateStatus): void;
@@ -2691,7 +2698,7 @@ declare namespace ts {
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
getEnvironmentVariable?(name: string): string | undefined;
createHash?(data: string): string;
getModifiedTime?(fileName: string): Date;
getModifiedTime?(fileName: string): Date | undefined;
setModifiedTime?(fileName: string, date: Date): void;
deleteFile?(fileName: string): void;
}
@@ -3028,7 +3035,7 @@ declare namespace ts {
getCurrentDirectory(): string;
getDirectories(path: string): string[];
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
getModifiedTime?(path: string): Date;
getModifiedTime?(path: string): Date | undefined;
setModifiedTime?(path: string, time: Date): void;
deleteFile?(path: string): void;
/**
@@ -3186,6 +3193,8 @@ declare namespace ts {
* @returns The original parse tree node if found; otherwise, undefined.
*/
function getParseTreeNode<T extends Node>(node: Node | undefined, nodeTest?: (node: Node) => node is T): T | undefined;
/** Add an extra underscore to identifiers that start with two underscores to avoid issues with magic names like '__proto__' */
function escapeLeadingUnderscores(identifier: string): __String;
/**
* Remove extra underscore from escaped identifier text content.
*
@@ -3222,6 +3231,8 @@ declare namespace ts {
function getJSDocAugmentsTag(node: Node): JSDocAugmentsTag | undefined;
/** Gets the JSDoc class tag for the node if present */
function getJSDocClassTag(node: Node): JSDocClassTag | undefined;
/** Gets the JSDoc enum tag for the node if present */
function getJSDocEnumTag(node: Node): JSDocEnumTag | undefined;
/** Gets the JSDoc this tag for the node if present */
function getJSDocThisTag(node: Node): JSDocThisTag | undefined;
/** Gets the JSDoc return tag for the node if present */
@@ -3243,16 +3254,22 @@ declare namespace ts {
*/
function getJSDocType(node: Node): TypeNode | undefined;
/**
* Gets the return type node for the node if provided via JSDoc's return tag.
* Gets the return type node for the node if provided via JSDoc return tag or type tag.
*
* @remarks `getJSDocReturnTag` just gets the whole JSDoc tag. This function
* gets the type from inside the braces.
* gets the type from inside the braces, after the fat arrow, etc.
*/
function getJSDocReturnType(node: Node): TypeNode | undefined;
/** Get all JSDoc tags related to a node, including those on parent nodes. */
function getJSDocTags(node: Node): ReadonlyArray<JSDocTag>;
/** Gets all JSDoc tags of a specified kind, or undefined if not present. */
function getAllJSDocTagsOfKind(node: Node, kind: SyntaxKind): ReadonlyArray<JSDocTag>;
/**
* Gets the effective type parameters. If the node was parsed in a
* JavaScript file, gets the type parameters from the `@template` tag from JSDoc.
*/
function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): ReadonlyArray<TypeParameterDeclaration>;
function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined;
}
declare namespace ts {
function isNumericLiteral(node: Node): node is NumericLiteral;
@@ -3409,6 +3426,7 @@ declare namespace ts {
function isJSDoc(node: Node): node is JSDoc;
function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag;
function isJSDocClassTag(node: Node): node is JSDocClassTag;
function isJSDocEnumTag(node: Node): node is JSDocEnumTag;
function isJSDocThisTag(node: Node): node is JSDocThisTag;
function isJSDocParameterTag(node: Node): node is JSDocParameterTag;
function isJSDocReturnTag(node: Node): node is JSDocReturnTag;
@@ -3732,9 +3750,9 @@ declare namespace ts {
function updateCall(node: CallExpression, expression: Expression, typeArguments: ReadonlyArray<TypeNode> | undefined, argumentsArray: ReadonlyArray<Expression>): CallExpression;
function createNew(expression: Expression, typeArguments: ReadonlyArray<TypeNode> | undefined, argumentsArray: ReadonlyArray<Expression> | undefined): NewExpression;
function updateNew(node: NewExpression, expression: Expression, typeArguments: ReadonlyArray<TypeNode> | undefined, argumentsArray: ReadonlyArray<Expression> | undefined): NewExpression;
function createTaggedTemplate(tag: Expression, template: TemplateLiteral): TaggedTemplateExpression;
/** @deprecated */ function createTaggedTemplate(tag: Expression, template: TemplateLiteral): TaggedTemplateExpression;
function createTaggedTemplate(tag: Expression, typeArguments: ReadonlyArray<TypeNode> | undefined, template: TemplateLiteral): TaggedTemplateExpression;
function updateTaggedTemplate(node: TaggedTemplateExpression, tag: Expression, template: TemplateLiteral): TaggedTemplateExpression;
/** @deprecated */ function updateTaggedTemplate(node: TaggedTemplateExpression, tag: Expression, template: TemplateLiteral): TaggedTemplateExpression;
function updateTaggedTemplate(node: TaggedTemplateExpression, tag: Expression, typeArguments: ReadonlyArray<TypeNode> | undefined, template: TemplateLiteral): TaggedTemplateExpression;
function createTypeAssertion(type: TypeNode, expression: Expression): TypeAssertion;
function updateTypeAssertion(node: TypeAssertion, type: TypeNode, expression: Expression): TypeAssertion;
@@ -3743,7 +3761,6 @@ declare namespace ts {
function createFunctionExpression(modifiers: ReadonlyArray<Modifier> | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration> | undefined, type: TypeNode | undefined, body: Block): FunctionExpression;
function updateFunctionExpression(node: FunctionExpression, modifiers: ReadonlyArray<Modifier> | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, body: Block): FunctionExpression;
function createArrowFunction(modifiers: ReadonlyArray<Modifier> | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody): ArrowFunction;
/** @deprecated */ function updateArrowFunction(node: ArrowFunction, modifiers: ReadonlyArray<Modifier> | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, body: ConciseBody): ArrowFunction;
function updateArrowFunction(node: ArrowFunction, modifiers: ReadonlyArray<Modifier> | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, equalsGreaterThanToken: Token<SyntaxKind.EqualsGreaterThanToken>, body: ConciseBody): ArrowFunction;
function createDelete(expression: Expression): DeleteExpression;
function updateDelete(node: DeleteExpression, expression: Expression): DeleteExpression;
@@ -3759,9 +3776,8 @@ declare namespace ts {
function updatePostfix(node: PostfixUnaryExpression, operand: Expression): PostfixUnaryExpression;
function createBinary(left: Expression, operator: BinaryOperator | BinaryOperatorToken, right: Expression): BinaryExpression;
function updateBinary(node: BinaryExpression, left: Expression, right: Expression, operator?: BinaryOperator | BinaryOperatorToken): BinaryExpression;
function createConditional(condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression;
/** @deprecated */ function createConditional(condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression;
function createConditional(condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression;
/** @deprecated */ function updateConditional(node: ConditionalExpression, condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression;
function updateConditional(node: ConditionalExpression, condition: Expression, questionToken: Token<SyntaxKind.QuestionToken>, whenTrue: Expression, colonToken: Token<SyntaxKind.ColonToken>, whenFalse: Expression): ConditionalExpression;
function createTemplateExpression(head: TemplateHead, templateSpans: ReadonlyArray<TemplateSpan>): TemplateExpression;
function updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: ReadonlyArray<TemplateSpan>): TemplateExpression;
@@ -4155,10 +4171,14 @@ declare namespace ts {
* @returns A 'Program' object.
*/
function createProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): Program;
interface ResolveProjectReferencePathHost {
fileExists(fileName: string): boolean;
}
/**
* Returns the target config filename of a project reference
* Returns the target config filename of a project reference.
* Note: The file might not exist.
*/
function resolveProjectReferencePath(host: CompilerHost | UpToDateHost, ref: ProjectReference): ResolvedConfigFileName;
function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName;
}
declare namespace ts {
interface EmitOutput {
@@ -4577,6 +4597,80 @@ declare namespace ts {
function getAllProjectOutputs(project: ParsedCommandLine): ReadonlyArray<string>;
function formatUpToDateStatus<T>(configFileName: string, status: UpToDateStatus, relName: (fileName: string) => string, formatMessage: (message: DiagnosticMessage, ...args: string[]) => T): T | undefined;
}
declare namespace ts.server {
type ActionSet = "action::set";
type ActionInvalidate = "action::invalidate";
type ActionPackageInstalled = "action::packageInstalled";
type EventTypesRegistry = "event::typesRegistry";
type EventBeginInstallTypes = "event::beginInstallTypes";
type EventEndInstallTypes = "event::endInstallTypes";
type EventInitializationFailed = "event::initializationFailed";
interface SortedReadonlyArray<T> extends ReadonlyArray<T> {
" __sortedArrayBrand": any;
}
interface TypingInstallerResponse {
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
}
interface TypingInstallerRequestWithProjectName {
readonly projectName: string;
}
interface DiscoverTypings extends TypingInstallerRequestWithProjectName {
readonly fileNames: string[];
readonly projectRootPath: Path;
readonly compilerOptions: CompilerOptions;
readonly typeAcquisition: TypeAcquisition;
readonly unresolvedImports: SortedReadonlyArray<string>;
readonly cachePath?: string;
readonly kind: "discover";
}
interface CloseProject extends TypingInstallerRequestWithProjectName {
readonly kind: "closeProject";
}
interface TypesRegistryRequest {
readonly kind: "typesRegistry";
}
interface InstallPackageRequest extends TypingInstallerRequestWithProjectName {
readonly kind: "installPackage";
readonly fileName: Path;
readonly packageName: string;
readonly projectRootPath: Path;
}
interface PackageInstalledResponse extends ProjectResponse {
readonly kind: ActionPackageInstalled;
readonly success: boolean;
readonly message: string;
}
interface InitializationFailedResponse extends TypingInstallerResponse {
readonly kind: EventInitializationFailed;
readonly message: string;
}
interface ProjectResponse extends TypingInstallerResponse {
readonly projectName: string;
}
interface InvalidateCachedTypings extends ProjectResponse {
readonly kind: ActionInvalidate;
}
interface InstallTypes extends ProjectResponse {
readonly kind: EventBeginInstallTypes | EventEndInstallTypes;
readonly eventId: number;
readonly typingsInstallerVersion: string;
readonly packagesToInstall: ReadonlyArray<string>;
}
interface BeginInstallTypes extends InstallTypes {
readonly kind: EventBeginInstallTypes;
}
interface EndInstallTypes extends InstallTypes {
readonly kind: EventEndInstallTypes;
readonly installSuccess: boolean;
}
interface SetTypings extends ProjectResponse {
readonly typeAcquisition: TypeAcquisition;
readonly compilerOptions: CompilerOptions;
readonly typings: string[];
readonly unresolvedImports: SortedReadonlyArray<string>;
readonly kind: ActionSet;
}
}
declare namespace ts {
interface Node {
getSourceFile(): SourceFile;
@@ -5581,5 +5675,5 @@ declare namespace ts {
*/
function transform<T extends Node>(source: T | T[], transformers: TransformerFactory<T>[], compilerOptions?: CompilerOptions): TransformationResult<T>;
}
//# sourceMappingURL=typescriptServices.d.ts.map
export = ts
export = ts;
+4470 -2653
View File
File diff suppressed because it is too large Load Diff
+136 -43
View File
@@ -13,9 +13,8 @@ See the Apache Version 2.0 License for specific language governing permissions
and limitations under the License.
***************************************************************************** */
declare namespace ts {
const versionMajorMinor = "3.0";
const versionMajorMinor = "3.1";
/** The version of the TypeScript compiler release */
const version: string;
}
@@ -369,20 +368,21 @@ declare namespace ts {
JSDocAugmentsTag = 293,
JSDocClassTag = 294,
JSDocCallbackTag = 295,
JSDocParameterTag = 296,
JSDocReturnTag = 297,
JSDocThisTag = 298,
JSDocTypeTag = 299,
JSDocTemplateTag = 300,
JSDocTypedefTag = 301,
JSDocPropertyTag = 302,
SyntaxList = 303,
NotEmittedStatement = 304,
PartiallyEmittedExpression = 305,
CommaListExpression = 306,
MergeDeclarationMarker = 307,
EndOfDeclarationMarker = 308,
Count = 309,
JSDocEnumTag = 296,
JSDocParameterTag = 297,
JSDocReturnTag = 298,
JSDocThisTag = 299,
JSDocTypeTag = 300,
JSDocTemplateTag = 301,
JSDocTypedefTag = 302,
JSDocPropertyTag = 303,
SyntaxList = 304,
NotEmittedStatement = 305,
PartiallyEmittedExpression = 306,
CommaListExpression = 307,
MergeDeclarationMarker = 308,
EndOfDeclarationMarker = 309,
Count = 310,
FirstAssignment = 58,
LastAssignment = 70,
FirstCompoundAssignment = 59,
@@ -409,9 +409,9 @@ declare namespace ts {
LastBinaryOperator = 70,
FirstNode = 146,
FirstJSDocNode = 281,
LastJSDocNode = 302,
LastJSDocNode = 303,
FirstJSDocTagNode = 292,
LastJSDocTagNode = 302
LastJSDocTagNode = 303
}
enum NodeFlags {
None = 0,
@@ -480,7 +480,7 @@ declare namespace ts {
}
interface JSDocContainer {
}
type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | LabeledStatement | ExpressionStatement | VariableStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | EndOfFileToken;
type HasJSDoc = ParameterDeclaration | CallSignatureDeclaration | ConstructSignatureDeclaration | MethodSignature | PropertySignature | ArrowFunction | ParenthesizedExpression | SpreadAssignment | ShorthandPropertyAssignment | PropertyAssignment | FunctionExpression | LabeledStatement | ExpressionStatement | VariableStatement | FunctionDeclaration | ConstructorDeclaration | MethodDeclaration | PropertyDeclaration | AccessorDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | EnumMember | EnumDeclaration | ModuleDeclaration | ImportEqualsDeclaration | IndexSignatureDeclaration | FunctionTypeNode | ConstructorTypeNode | JSDocFunctionType | ExportDeclaration | EndOfFileToken;
type HasType = SignatureDeclaration | VariableDeclaration | ParameterDeclaration | PropertySignature | PropertyDeclaration | TypePredicateNode | ParenthesizedTypeNode | TypeOperatorNode | MappedTypeNode | AssertionExpression | TypeAliasDeclaration | JSDocTypeExpression | JSDocNonNullableType | JSDocNullableType | JSDocOptionalType | JSDocVariadicType;
type HasInitializer = HasExpressionInitializer | ForStatement | ForInStatement | ForOfStatement | JsxAttribute;
type HasExpressionInitializer = VariableDeclaration | ParameterDeclaration | BindingElement | PropertySignature | PropertyDeclaration | PropertyAssignment | EnumMember;
@@ -546,8 +546,9 @@ declare namespace ts {
}
interface TypeParameterDeclaration extends NamedDeclaration {
kind: SyntaxKind.TypeParameter;
parent: DeclarationWithTypeParameters | InferTypeNode;
parent: DeclarationWithTypeParameterChildren | InferTypeNode;
name: Identifier;
/** Note: Consider calling `getEffectiveConstraintOfTypeParameter` */
constraint?: TypeNode;
default?: TypeNode;
expression?: Expression;
@@ -617,6 +618,7 @@ declare namespace ts {
_objectLiteralBrandBrand: any;
name?: PropertyName;
}
/** Unlike ObjectLiteralElement, excludes JSXAttribute and JSXSpreadAttribute. */
type ObjectLiteralElementLike = PropertyAssignment | ShorthandPropertyAssignment | SpreadAssignment | MethodDeclaration | AccessorDeclaration;
interface PropertyAssignment extends ObjectLiteralElement, JSDocContainer {
parent: ObjectLiteralExpression;
@@ -750,7 +752,7 @@ declare namespace ts {
}
interface TypePredicateNode extends TypeNode {
kind: SyntaxKind.TypePredicate;
parent: SignatureDeclaration;
parent: SignatureDeclaration | JSDocTypeExpression;
parameterName: Identifier | ThisTypeNode;
type: TypeNode;
}
@@ -1318,7 +1320,8 @@ declare namespace ts {
block: Block;
}
type ObjectTypeDeclaration = ClassLikeDeclaration | InterfaceDeclaration | TypeLiteralNode;
type DeclarationWithTypeParameters = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag | JSDocTypedefTag | JSDocCallbackTag | JSDocSignature;
type DeclarationWithTypeParameters = DeclarationWithTypeParameterChildren | JSDocTypedefTag | JSDocCallbackTag | JSDocSignature;
type DeclarationWithTypeParameterChildren = SignatureDeclaration | ClassLikeDeclaration | InterfaceDeclaration | TypeAliasDeclaration | JSDocTemplateTag;
interface ClassLikeDeclarationBase extends NamedDeclaration, JSDocContainer {
kind: SyntaxKind.ClassDeclaration | SyntaxKind.ClassExpression;
name?: Identifier;
@@ -1437,7 +1440,7 @@ declare namespace ts {
kind: SyntaxKind.NamespaceExportDeclaration;
name: Identifier;
}
interface ExportDeclaration extends DeclarationStatement {
interface ExportDeclaration extends DeclarationStatement, JSDocContainer {
kind: SyntaxKind.ExportDeclaration;
parent: SourceFile | ModuleBlock;
/** Will not be assigned in the case of `export * from "foo";` */
@@ -1556,12 +1559,17 @@ declare namespace ts {
interface JSDocClassTag extends JSDocTag {
kind: SyntaxKind.JSDocClassTag;
}
interface JSDocEnumTag extends JSDocTag {
kind: SyntaxKind.JSDocEnumTag;
typeExpression?: JSDocTypeExpression;
}
interface JSDocThisTag extends JSDocTag {
kind: SyntaxKind.JSDocThisTag;
typeExpression?: JSDocTypeExpression;
}
interface JSDocTemplateTag extends JSDocTag {
kind: SyntaxKind.JSDocTemplateTag;
constraint: TypeNode | undefined;
typeParameters: NodeArray<TypeParameterDeclaration>;
}
interface JSDocReturnTag extends JSDocTag {
@@ -1902,7 +1910,7 @@ declare namespace ts {
*/
getExportSymbolOfSymbol(symbol: Symbol): Symbol;
getPropertySymbolOfDestructuringAssignment(location: Identifier): Symbol | undefined;
getTypeAtLocation(node: Node): Type | undefined;
getTypeAtLocation(node: Node): Type;
getTypeFromTypeNode(node: TypeNode): Type;
signatureToString(signature: Signature, enclosingDeclaration?: Node, flags?: TypeFormatFlags, kind?: SignatureKind): string;
typeToString(type: Type, enclosingDeclaration?: Node, flags?: TypeFormatFlags): string;
@@ -1934,9 +1942,6 @@ declare namespace ts {
getAmbientModules(): Symbol[];
tryGetMemberInModuleExports(memberName: string, moduleSymbol: Symbol): Symbol | undefined;
getApparentType(type: Type): Type;
getSuggestionForNonexistentProperty(name: Identifier | string, containingType: Type): string | undefined;
getSuggestionForNonexistentSymbol(location: Node, name: string, meaning: SymbolFlags): string | undefined;
getSuggestionForNonexistentModule(node: Identifier, target: Symbol): string | undefined;
getBaseConstraintOfType(type: Type): Type | undefined;
getDefaultFromTypeParameter(type: Type): Type | undefined;
/**
@@ -2052,6 +2057,7 @@ declare namespace ts {
Optional = 16777216,
Transient = 33554432,
JSContainer = 67108864,
ModuleExports = 134217728,
Enum = 384,
Variable = 3,
Value = 67216319,
@@ -2079,8 +2085,6 @@ declare namespace ts {
AliasExcludes = 2097152,
ModuleMember = 2623475,
ExportHasLocal = 944,
HasExports = 1955,
HasMembers = 6240,
BlockScoped = 418,
PropertyOrAccessor = 98308,
ClassMember = 106500
@@ -2110,7 +2114,8 @@ declare namespace ts {
Computed = "__computed",
Resolving = "__resolving__",
ExportEquals = "export=",
Default = "default"
Default = "default",
This = "this"
}
/**
* This represents a string whose leading underscore have been escaped by adding extra leading underscores.
@@ -2228,6 +2233,7 @@ declare namespace ts {
ReverseMapped = 2048,
JsxAttributes = 4096,
MarkerType = 8192,
JSLiteral = 16384,
ClassOrInterface = 3
}
interface ObjectType extends Type {
@@ -2486,6 +2492,7 @@ declare namespace ts {
strictFunctionTypes?: boolean;
strictNullChecks?: boolean;
strictPropertyInitialization?: boolean;
stripInternal?: boolean;
suppressExcessPropertyErrors?: boolean;
suppressImplicitAnyIndexErrors?: boolean;
target?: ScriptTarget;
@@ -2587,7 +2594,7 @@ declare namespace ts {
}
interface UpToDateHost {
fileExists(fileName: string): boolean;
getModifiedTime(fileName: string): Date;
getModifiedTime(fileName: string): Date | undefined;
getUnchangedTime?(fileName: string): Date | undefined;
getLastStatus?(fileName: string): UpToDateStatus | undefined;
setLastStatus?(fileName: string, status: UpToDateStatus): void;
@@ -2691,7 +2698,7 @@ declare namespace ts {
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
getEnvironmentVariable?(name: string): string | undefined;
createHash?(data: string): string;
getModifiedTime?(fileName: string): Date;
getModifiedTime?(fileName: string): Date | undefined;
setModifiedTime?(fileName: string, date: Date): void;
deleteFile?(fileName: string): void;
}
@@ -3028,7 +3035,7 @@ declare namespace ts {
getCurrentDirectory(): string;
getDirectories(path: string): string[];
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
getModifiedTime?(path: string): Date;
getModifiedTime?(path: string): Date | undefined;
setModifiedTime?(path: string, time: Date): void;
deleteFile?(path: string): void;
/**
@@ -3186,6 +3193,8 @@ declare namespace ts {
* @returns The original parse tree node if found; otherwise, undefined.
*/
function getParseTreeNode<T extends Node>(node: Node | undefined, nodeTest?: (node: Node) => node is T): T | undefined;
/** Add an extra underscore to identifiers that start with two underscores to avoid issues with magic names like '__proto__' */
function escapeLeadingUnderscores(identifier: string): __String;
/**
* Remove extra underscore from escaped identifier text content.
*
@@ -3222,6 +3231,8 @@ declare namespace ts {
function getJSDocAugmentsTag(node: Node): JSDocAugmentsTag | undefined;
/** Gets the JSDoc class tag for the node if present */
function getJSDocClassTag(node: Node): JSDocClassTag | undefined;
/** Gets the JSDoc enum tag for the node if present */
function getJSDocEnumTag(node: Node): JSDocEnumTag | undefined;
/** Gets the JSDoc this tag for the node if present */
function getJSDocThisTag(node: Node): JSDocThisTag | undefined;
/** Gets the JSDoc return tag for the node if present */
@@ -3243,16 +3254,22 @@ declare namespace ts {
*/
function getJSDocType(node: Node): TypeNode | undefined;
/**
* Gets the return type node for the node if provided via JSDoc's return tag.
* Gets the return type node for the node if provided via JSDoc return tag or type tag.
*
* @remarks `getJSDocReturnTag` just gets the whole JSDoc tag. This function
* gets the type from inside the braces.
* gets the type from inside the braces, after the fat arrow, etc.
*/
function getJSDocReturnType(node: Node): TypeNode | undefined;
/** Get all JSDoc tags related to a node, including those on parent nodes. */
function getJSDocTags(node: Node): ReadonlyArray<JSDocTag>;
/** Gets all JSDoc tags of a specified kind, or undefined if not present. */
function getAllJSDocTagsOfKind(node: Node, kind: SyntaxKind): ReadonlyArray<JSDocTag>;
/**
* Gets the effective type parameters. If the node was parsed in a
* JavaScript file, gets the type parameters from the `@template` tag from JSDoc.
*/
function getEffectiveTypeParameterDeclarations(node: DeclarationWithTypeParameters): ReadonlyArray<TypeParameterDeclaration>;
function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined;
}
declare namespace ts {
function isNumericLiteral(node: Node): node is NumericLiteral;
@@ -3409,6 +3426,7 @@ declare namespace ts {
function isJSDoc(node: Node): node is JSDoc;
function isJSDocAugmentsTag(node: Node): node is JSDocAugmentsTag;
function isJSDocClassTag(node: Node): node is JSDocClassTag;
function isJSDocEnumTag(node: Node): node is JSDocEnumTag;
function isJSDocThisTag(node: Node): node is JSDocThisTag;
function isJSDocParameterTag(node: Node): node is JSDocParameterTag;
function isJSDocReturnTag(node: Node): node is JSDocReturnTag;
@@ -3732,9 +3750,9 @@ declare namespace ts {
function updateCall(node: CallExpression, expression: Expression, typeArguments: ReadonlyArray<TypeNode> | undefined, argumentsArray: ReadonlyArray<Expression>): CallExpression;
function createNew(expression: Expression, typeArguments: ReadonlyArray<TypeNode> | undefined, argumentsArray: ReadonlyArray<Expression> | undefined): NewExpression;
function updateNew(node: NewExpression, expression: Expression, typeArguments: ReadonlyArray<TypeNode> | undefined, argumentsArray: ReadonlyArray<Expression> | undefined): NewExpression;
function createTaggedTemplate(tag: Expression, template: TemplateLiteral): TaggedTemplateExpression;
/** @deprecated */ function createTaggedTemplate(tag: Expression, template: TemplateLiteral): TaggedTemplateExpression;
function createTaggedTemplate(tag: Expression, typeArguments: ReadonlyArray<TypeNode> | undefined, template: TemplateLiteral): TaggedTemplateExpression;
function updateTaggedTemplate(node: TaggedTemplateExpression, tag: Expression, template: TemplateLiteral): TaggedTemplateExpression;
/** @deprecated */ function updateTaggedTemplate(node: TaggedTemplateExpression, tag: Expression, template: TemplateLiteral): TaggedTemplateExpression;
function updateTaggedTemplate(node: TaggedTemplateExpression, tag: Expression, typeArguments: ReadonlyArray<TypeNode> | undefined, template: TemplateLiteral): TaggedTemplateExpression;
function createTypeAssertion(type: TypeNode, expression: Expression): TypeAssertion;
function updateTypeAssertion(node: TypeAssertion, type: TypeNode, expression: Expression): TypeAssertion;
@@ -3743,7 +3761,6 @@ declare namespace ts {
function createFunctionExpression(modifiers: ReadonlyArray<Modifier> | undefined, asteriskToken: AsteriskToken | undefined, name: string | Identifier | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration> | undefined, type: TypeNode | undefined, body: Block): FunctionExpression;
function updateFunctionExpression(node: FunctionExpression, modifiers: ReadonlyArray<Modifier> | undefined, asteriskToken: AsteriskToken | undefined, name: Identifier | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, body: Block): FunctionExpression;
function createArrowFunction(modifiers: ReadonlyArray<Modifier> | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, equalsGreaterThanToken: EqualsGreaterThanToken | undefined, body: ConciseBody): ArrowFunction;
/** @deprecated */ function updateArrowFunction(node: ArrowFunction, modifiers: ReadonlyArray<Modifier> | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, body: ConciseBody): ArrowFunction;
function updateArrowFunction(node: ArrowFunction, modifiers: ReadonlyArray<Modifier> | undefined, typeParameters: ReadonlyArray<TypeParameterDeclaration> | undefined, parameters: ReadonlyArray<ParameterDeclaration>, type: TypeNode | undefined, equalsGreaterThanToken: Token<SyntaxKind.EqualsGreaterThanToken>, body: ConciseBody): ArrowFunction;
function createDelete(expression: Expression): DeleteExpression;
function updateDelete(node: DeleteExpression, expression: Expression): DeleteExpression;
@@ -3759,9 +3776,8 @@ declare namespace ts {
function updatePostfix(node: PostfixUnaryExpression, operand: Expression): PostfixUnaryExpression;
function createBinary(left: Expression, operator: BinaryOperator | BinaryOperatorToken, right: Expression): BinaryExpression;
function updateBinary(node: BinaryExpression, left: Expression, right: Expression, operator?: BinaryOperator | BinaryOperatorToken): BinaryExpression;
function createConditional(condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression;
/** @deprecated */ function createConditional(condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression;
function createConditional(condition: Expression, questionToken: QuestionToken, whenTrue: Expression, colonToken: ColonToken, whenFalse: Expression): ConditionalExpression;
/** @deprecated */ function updateConditional(node: ConditionalExpression, condition: Expression, whenTrue: Expression, whenFalse: Expression): ConditionalExpression;
function updateConditional(node: ConditionalExpression, condition: Expression, questionToken: Token<SyntaxKind.QuestionToken>, whenTrue: Expression, colonToken: Token<SyntaxKind.ColonToken>, whenFalse: Expression): ConditionalExpression;
function createTemplateExpression(head: TemplateHead, templateSpans: ReadonlyArray<TemplateSpan>): TemplateExpression;
function updateTemplateExpression(node: TemplateExpression, head: TemplateHead, templateSpans: ReadonlyArray<TemplateSpan>): TemplateExpression;
@@ -4155,10 +4171,14 @@ declare namespace ts {
* @returns A 'Program' object.
*/
function createProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): Program;
interface ResolveProjectReferencePathHost {
fileExists(fileName: string): boolean;
}
/**
* Returns the target config filename of a project reference
* Returns the target config filename of a project reference.
* Note: The file might not exist.
*/
function resolveProjectReferencePath(host: CompilerHost | UpToDateHost, ref: ProjectReference): ResolvedConfigFileName;
function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName;
}
declare namespace ts {
interface EmitOutput {
@@ -4577,6 +4597,80 @@ declare namespace ts {
function getAllProjectOutputs(project: ParsedCommandLine): ReadonlyArray<string>;
function formatUpToDateStatus<T>(configFileName: string, status: UpToDateStatus, relName: (fileName: string) => string, formatMessage: (message: DiagnosticMessage, ...args: string[]) => T): T | undefined;
}
declare namespace ts.server {
type ActionSet = "action::set";
type ActionInvalidate = "action::invalidate";
type ActionPackageInstalled = "action::packageInstalled";
type EventTypesRegistry = "event::typesRegistry";
type EventBeginInstallTypes = "event::beginInstallTypes";
type EventEndInstallTypes = "event::endInstallTypes";
type EventInitializationFailed = "event::initializationFailed";
interface SortedReadonlyArray<T> extends ReadonlyArray<T> {
" __sortedArrayBrand": any;
}
interface TypingInstallerResponse {
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
}
interface TypingInstallerRequestWithProjectName {
readonly projectName: string;
}
interface DiscoverTypings extends TypingInstallerRequestWithProjectName {
readonly fileNames: string[];
readonly projectRootPath: Path;
readonly compilerOptions: CompilerOptions;
readonly typeAcquisition: TypeAcquisition;
readonly unresolvedImports: SortedReadonlyArray<string>;
readonly cachePath?: string;
readonly kind: "discover";
}
interface CloseProject extends TypingInstallerRequestWithProjectName {
readonly kind: "closeProject";
}
interface TypesRegistryRequest {
readonly kind: "typesRegistry";
}
interface InstallPackageRequest extends TypingInstallerRequestWithProjectName {
readonly kind: "installPackage";
readonly fileName: Path;
readonly packageName: string;
readonly projectRootPath: Path;
}
interface PackageInstalledResponse extends ProjectResponse {
readonly kind: ActionPackageInstalled;
readonly success: boolean;
readonly message: string;
}
interface InitializationFailedResponse extends TypingInstallerResponse {
readonly kind: EventInitializationFailed;
readonly message: string;
}
interface ProjectResponse extends TypingInstallerResponse {
readonly projectName: string;
}
interface InvalidateCachedTypings extends ProjectResponse {
readonly kind: ActionInvalidate;
}
interface InstallTypes extends ProjectResponse {
readonly kind: EventBeginInstallTypes | EventEndInstallTypes;
readonly eventId: number;
readonly typingsInstallerVersion: string;
readonly packagesToInstall: ReadonlyArray<string>;
}
interface BeginInstallTypes extends InstallTypes {
readonly kind: EventBeginInstallTypes;
}
interface EndInstallTypes extends InstallTypes {
readonly kind: EventEndInstallTypes;
readonly installSuccess: boolean;
}
interface SetTypings extends ProjectResponse {
readonly typeAcquisition: TypeAcquisition;
readonly compilerOptions: CompilerOptions;
readonly typings: string[];
readonly unresolvedImports: SortedReadonlyArray<string>;
readonly kind: ActionSet;
}
}
declare namespace ts {
interface Node {
getSourceFile(): SourceFile;
@@ -5581,4 +5675,3 @@ declare namespace ts {
*/
function transform<T extends Node>(source: T | T[], transformers: TransformerFactory<T>[], compilerOptions?: CompilerOptions): TransformationResult<T>;
}
//# sourceMappingURL=typescriptServices.d.ts.map
+4470 -2653
View File
File diff suppressed because it is too large Load Diff
+2907 -1764
View File
File diff suppressed because it is too large Load Diff
-6281
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -81,6 +81,7 @@
"mocha": "latest",
"mocha-fivemat-progress-reporter": "latest",
"plugin-error": "latest",
"prex": "^0.4.3",
"q": "latest",
"remove-internal": "^2.9.2",
"run-sequence": "latest",
-71
View File
@@ -1,71 +0,0 @@
// @ts-check
const symSource = Symbol("CancelToken.source");
const symToken = Symbol("CancelSource.token");
const symCancellationRequested = Symbol("CancelSource.cancellationRequested");
const symCancellationCallbacks = Symbol("CancelSource.cancellationCallbacks");
class CancelSource {
constructor() {
this[symCancellationRequested] = false;
this[symCancellationCallbacks] = [];
}
/** @type {CancelToken} */
get token() {
return this[symToken] || (this[symToken] = new CancelToken(this));
}
cancel() {
if (!this[symCancellationRequested]) {
this[symCancellationRequested] = true;
for (const callback of this[symCancellationCallbacks]) {
callback();
}
}
}
}
exports.CancelSource = CancelSource;
class CancelToken {
/**
* @param {CancelSource} source
*/
constructor(source) {
if (source[symToken]) return source[symToken];
this[symSource] = source;
}
/** @type {boolean} */
get cancellationRequested() {
return this[symSource][symCancellationRequested];
}
/**
* @param {() => void} callback
*/
subscribe(callback) {
const source = this[symSource];
if (source[symCancellationRequested]) {
callback();
return;
}
source[symCancellationCallbacks].push(callback);
return {
unsubscribe() {
const index = source[symCancellationCallbacks].indexOf(callback);
if (index !== -1) source[symCancellationCallbacks].splice(index, 1);
}
};
}
}
exports.CancelToken = CancelToken;
class CancelError extends Error {
constructor(message = "Operation was canceled") {
super(message);
this.name = "CancelError";
}
}
exports.CancelError = CancelError;
+17 -12
View File
@@ -3,7 +3,7 @@ const cp = require("child_process");
const log = require("fancy-log"); // was `require("gulp-util").log (see https://github.com/gulpjs/gulp-util)
const isWin = /^win/.test(process.platform);
const chalk = require("./chalk");
const { CancelToken, CancelError } = require("./cancellation");
const { CancellationToken, CancelError } = require("prex");
module.exports = exec;
@@ -15,31 +15,36 @@ module.exports = exec;
*
* @typedef ExecOptions
* @property {boolean} [ignoreExitCode]
* @property {CancelToken} [cancelToken]
* @property {import("prex").CancellationToken} [cancelToken]
*/
function exec(cmd, args, options = {}) {
return /**@type {Promise<{exitCode: number}>}*/(new Promise((resolve, reject) => {
log(`> ${chalk.green(cmd)} ${args.join(" ")}`);
const { ignoreExitCode, cancelToken = CancellationToken.none } = options;
cancelToken.throwIfCancellationRequested();
// TODO (weswig): Update child_process types to add windowsVerbatimArguments to the type definition
const subshellFlag = isWin ? "/c" : "-c";
const command = isWin ? [possiblyQuote(cmd), ...args] : [`${cmd} ${args.join(" ")}`];
const ex = cp.spawn(isWin ? "cmd" : "/bin/sh", [subshellFlag, ...command], { stdio: "inherit", windowsVerbatimArguments: true });
const subscription = options.cancelToken && options.cancelToken.subscribe(() => {
ex.kill("SIGINT");
ex.kill("SIGTERM");
log(`> ${chalk.green(cmd)} ${args.join(" ")}`);
const proc = cp.spawn(isWin ? "cmd" : "/bin/sh", [subshellFlag, ...command], { stdio: "inherit", windowsVerbatimArguments: true });
const registration = cancelToken.register(() => {
log(`${chalk.red("killing")} '${chalk.green(cmd)} ${args.join(" ")}'...`);
proc.kill("SIGINT");
proc.kill("SIGTERM");
reject(new CancelError());
});
ex.on("exit", exitCode => {
subscription && subscription.unsubscribe();
if (exitCode === 0 || options.ignoreExitCode) {
proc.on("exit", exitCode => {
registration.unregister();
if (exitCode === 0 || ignoreExitCode) {
resolve({ exitCode });
}
else {
reject(new Error(`Process exited with code: ${exitCode}`));
}
});
ex.on("error", error => {
subscription && subscription.unsubscribe();
proc.on("error", error => {
registration.unregister();
reject(error);
});
}));
@@ -140,7 +140,7 @@ function diagnosticFromJson(json, host) {
category: json.category,
code: json.code,
source: json.source,
relatedInformation: json.relatedInformation && json.relatedInformation.map(diagnosticRelatedInformationFromJson, host)
relatedInformation: json.relatedInformation && json.relatedInformation.map(json => diagnosticRelatedInformationFromJson(json, host))
});
}
exports.diagnosticFromJson = diagnosticFromJson;
@@ -169,7 +169,9 @@ function diagnosticRelatedInformationFromJson(json, host) {
file: json.file && sourceFileFromJson(json.file, host),
start: json.start,
length: json.length,
messageText: json.messageText
messageText: json.messageText,
category: json.category,
code: json.code
};
}
exports.diagnosticRelatedInformationFromJson = diagnosticRelatedInformationFromJson;
+56 -23
View File
@@ -3,6 +3,8 @@ const path = require("path");
const fs = require("fs");
const gulp = require("./gulp");
const gulpif = require("gulp-if");
const log = require("fancy-log"); // was `require("gulp-util").log (see https://github.com/gulpjs/gulp-util)
const chalk = require("./chalk");
const sourcemaps = require("gulp-sourcemaps");
const merge2 = require("merge2");
const tsc = require("gulp-typescript");
@@ -12,7 +14,12 @@ const ts = require("../../lib/typescript");
const del = require("del");
const needsUpdate = require("./needsUpdate");
const mkdirp = require("./mkdirp");
const prettyTime = require("pretty-hrtime");
const { reportDiagnostics } = require("./diagnostics");
const { CountdownEvent, ManualResetEvent } = require("prex");
const workStartedEvent = new ManualResetEvent();
const countdown = new CountdownEvent(0);
class CompilationGulp extends gulp.Gulp {
/**
@@ -20,15 +27,39 @@ class CompilationGulp extends gulp.Gulp {
*/
fork(verbose) {
const child = new ForkedGulp(this.tasks);
if (verbose) {
child.on("task_start", e => gulp.emit("task_start", e));
child.on("task_stop", e => gulp.emit("task_stop", e));
child.on("task_err", e => gulp.emit("task_err", e));
child.on("task_not_found", e => gulp.emit("task_not_found", e));
child.on("task_recursion", e => gulp.emit("task_recursion", e));
}
child.on("task_start", e => {
if (countdown.remainingCount === 0) {
countdown.reset(1);
workStartedEvent.set();
workStartedEvent.reset();
}
else {
countdown.add();
}
if (verbose) {
log('Starting', `'${chalk.cyan(e.task)}' ${chalk.gray(`(${countdown.remainingCount} remaining)`)}...`);
}
});
child.on("task_stop", e => {
countdown.signal();
if (verbose) {
log('Finished', `'${chalk.cyan(e.task)}' after ${chalk.magenta(prettyTime(/** @type {*}*/(e).hrDuration))} ${chalk.gray(`(${countdown.remainingCount} remaining)`)}`);
}
});
child.on("task_err", e => {
countdown.signal();
if (verbose) {
log(`'${chalk.cyan(e.task)}' ${chalk.red("errored after")} ${chalk.magenta(prettyTime(/** @type {*}*/(e).hrDuration))} ${chalk.gray(`(${countdown.remainingCount} remaining)`)}`);
log(e.err ? e.err.stack : e.message);
}
});
return child;
}
// @ts-ignore
start() {
throw new Error("Not supported, use fork.");
}
}
class ForkedGulp extends gulp.Gulp {
@@ -211,24 +242,26 @@ exports.flatten = flatten;
/**
* Returns a Promise that resolves when all pending build tasks have completed
* @param {import("prex").CancellationToken} [token]
*/
function wait() {
return new Promise(resolve => {
if (compilationGulp.allDone()) {
resolve();
}
else {
const onDone = () => {
compilationGulp.removeListener("onDone", onDone);
compilationGulp.removeListener("err", onDone);
resolve();
};
compilationGulp.on("stop", onDone);
compilationGulp.on("err", onDone);
}
});
function waitForWorkToComplete(token) {
return countdown.wait(token);
}
exports.wait = wait;
exports.waitForWorkToComplete = waitForWorkToComplete;
/**
* Returns a Promise that resolves when all pending build tasks have completed
* @param {import("prex").CancellationToken} [token]
*/
function waitForWorkToStart(token) {
return workStartedEvent.wait(token);
}
exports.waitForWorkToStart = waitForWorkToStart;
function getRemainingWork() {
return countdown.remainingCount > 0;
}
exports.hasRemainingWork = getRemainingWork;
/**
* Resolve a TypeScript specifier into a fully-qualified module specifier and any requisite dependencies.
+4 -2
View File
@@ -8,6 +8,7 @@ const mkdirP = require("./mkdirp");
const cmdLineOptions = require("./options");
const exec = require("./exec");
const log = require("fancy-log"); // was `require("gulp-util").log (see https://github.com/gulpjs/gulp-util)
const { CancellationToken } = require("prex");
const mochaJs = require.resolve("mocha/bin/_mocha");
exports.localBaseline = "tests/baselines/local/";
@@ -21,9 +22,9 @@ exports.localTest262Baseline = "internal/baselines/test262/local";
* @param {string} defaultReporter
* @param {boolean} runInParallel
* @param {boolean} watchMode
* @param {InstanceType<typeof import("./cancellation").CancelToken>} [cancelToken]
* @param {import("prex").CancellationToken} [cancelToken]
*/
async function runConsoleTests(runJs, defaultReporter, runInParallel, watchMode, cancelToken) {
async function runConsoleTests(runJs, defaultReporter, runInParallel, watchMode, cancelToken = CancellationToken.none) {
let testTimeout = cmdLineOptions.timeout;
let tests = cmdLineOptions.tests;
const lintFlag = cmdLineOptions.lint;
@@ -37,6 +38,7 @@ async function runConsoleTests(runJs, defaultReporter, runInParallel, watchMode,
const keepFailed = cmdLineOptions.keepFailed;
if (!cmdLineOptions.dirty) {
await cleanTestDirs();
cancelToken.throwIfCancellationRequested();
}
if (fs.existsSync(testConfigFile)) {
+2 -2
View File
@@ -55,13 +55,13 @@ function main(): void {
function updateTsFile(tsFilePath: string, tsFileContents: string, majorMinor: string, patch: string, nightlyPatch: string): string {
const majorMinorRgx = /export const versionMajorMinor = "(\d+\.\d+)"/;
const majorMinorMatch = majorMinorRgx.exec(tsFileContents);
assert(majorMinorMatch !== null, `The file seems to no longer have a string matching '${majorMinorRgx}'.`);
assert(majorMinorMatch !== null, `The file '${tsFilePath}' seems to no longer have a string matching '${majorMinorRgx}'.`);
const parsedMajorMinor = majorMinorMatch![1];
assert(parsedMajorMinor === majorMinor, `versionMajorMinor does not match. ${tsFilePath}: '${parsedMajorMinor}'; package.json: '${majorMinor}'`);
const versionRgx = /export const version = `\$\{versionMajorMinor\}\.(\d)(-dev)?`;/;
const patchMatch = versionRgx.exec(tsFileContents);
assert(patchMatch !== null, "The file seems to no longer have a string matching " + versionRgx.toString());
assert(patchMatch !== null, `The file '${tsFilePath}' seems to no longer have a string matching '${versionRgx.toString()}'.`);
const parsedPatch = patchMatch![1];
if (parsedPatch !== patch) {
throw new Error(`patch does not match. ${tsFilePath}: '${parsedPatch}; package.json: '${patch}'`);
+3
View File
@@ -46,6 +46,9 @@ class FailedTestsReporter extends Mocha.reporters.Base {
}
const newOptions = Object.assign({}, options, { reporterOptions: reporterOptions.reporterOptions || {} });
if (reporterOptions.reporter === "xunit") {
newOptions.reporterOptions.output = "TEST-results.xml";
}
this.reporter = new reporter(runner, newOptions);
}
+1 -1
View File
@@ -16,7 +16,7 @@ function padNum(number: number) {
}
const userName = process.env.GH_USERNAME;
const reviewers = ["weswigham", "sandersn", "mhegazy"]
const reviewers = ["weswigham", "sandersn", "RyanCavanaugh"]
const now = new Date();
const branchName = `user-update-${now.getFullYear()}${padNum(now.getMonth())}${padNum(now.getDay())}`;
const remoteUrl = `https://${process.argv[2]}@github.com/${userName}/TypeScript.git`;
+1
View File
@@ -2,6 +2,7 @@
"extends": "../tsconfig-base",
"compilerOptions": {
"outDir": "../../built/local/",
"rootDir": ".",
"composite": false,
"declaration": false,
"declarationMap": false,
+33 -29
View File
@@ -236,8 +236,9 @@ namespace ts {
if (symbolFlags & SymbolFlags.Value) {
const { valueDeclaration } = symbol;
if (!valueDeclaration ||
(isAssignmentDeclaration(valueDeclaration) && !isAssignmentDeclaration(node)) ||
(valueDeclaration.kind !== node.kind && isEffectiveModuleDeclaration(valueDeclaration))) {
// other kinds of value declarations take precedence over modules
// other kinds of value declarations take precedence over modules and assignment declarations
symbol.valueDeclaration = node;
}
}
@@ -259,7 +260,7 @@ namespace ts {
if (name.kind === SyntaxKind.ComputedPropertyName) {
const nameExpression = name.expression;
// treat computed property names where expression is string/numeric literal as just string/numeric literal
if (isStringOrNumericLiteral(nameExpression)) {
if (isStringOrNumericLiteralLike(nameExpression)) {
return escapeLeadingUnderscores(nameExpression.text);
}
@@ -373,7 +374,8 @@ namespace ts {
// prototype symbols like methods.
symbolTable.set(name, symbol = createSymbol(SymbolFlags.None, name));
}
else {
else if (!(includes & SymbolFlags.Variable && symbol.flags & SymbolFlags.JSContainer)) {
// JSContainers are allowed to merge with variables, no matter what other flags they have.
if (isNamedDeclaration(node)) {
node.name.parent = node;
}
@@ -723,6 +725,7 @@ namespace ts {
case SyntaxKind.Identifier:
case SyntaxKind.ThisKeyword:
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
return isNarrowableReference(expr);
case SyntaxKind.CallExpression:
return hasNarrowableArgument(<CallExpression>expr);
@@ -737,10 +740,11 @@ namespace ts {
}
function isNarrowableReference(expr: Expression): boolean {
return expr.kind === SyntaxKind.Identifier ||
expr.kind === SyntaxKind.ThisKeyword ||
expr.kind === SyntaxKind.SuperKeyword ||
expr.kind === SyntaxKind.PropertyAccessExpression && isNarrowableReference((<PropertyAccessExpression>expr).expression);
return expr.kind === SyntaxKind.Identifier || expr.kind === SyntaxKind.ThisKeyword || expr.kind === SyntaxKind.SuperKeyword ||
isPropertyAccessExpression(expr) && isNarrowableReference(expr.expression) ||
isElementAccessExpression(expr) && expr.argumentExpression &&
(isStringLiteral(expr.argumentExpression) || isNumericLiteral(expr.argumentExpression)) &&
isNarrowableReference(expr.expression);
}
function hasNarrowableArgument(expr: CallExpression) {
@@ -1727,10 +1731,6 @@ namespace ts {
}
}
function bindBlockScopedVariableDeclaration(node: Declaration) {
bindBlockScopedDeclaration(node, SymbolFlags.BlockScopedVariable, SymbolFlags.BlockScopedVariableExcludes);
}
function delayedBindJSDocTypedefTag() {
if (!delayedTypeAliases) {
return;
@@ -2066,6 +2066,7 @@ namespace ts {
}
return checkStrictModeIdentifier(<Identifier>node);
case SyntaxKind.PropertyAccessExpression:
case SyntaxKind.ElementAccessExpression:
if (currentFlow && isNarrowableReference(<Expression>node)) {
node.flowNode = currentFlow;
}
@@ -2075,8 +2076,8 @@ namespace ts {
if (isInJavaScriptFile(node) &&
file.commonJsModuleIndicator &&
isModuleExportsPropertyAccessExpression(node as PropertyAccessExpression) &&
!lookupSymbolForNameWorker(container, "module" as __String)) {
declareSymbol(container.locals!, /*parent*/ undefined, (node as PropertyAccessExpression).expression as Identifier,
!lookupSymbolForNameWorker(blockScopeContainer, "module" as __String)) {
declareSymbol(file.locals!, /*parent*/ undefined, (node as PropertyAccessExpression).expression as Identifier,
SymbolFlags.FunctionScopedVariable | SymbolFlags.ModuleExports, SymbolFlags.FunctionScopedVariableExcludes);
}
break;
@@ -2477,6 +2478,11 @@ namespace ts {
function bindSpecialPropertyAssignment(node: BinaryExpression) {
const lhs = node.left as PropertyAccessEntityNameExpression;
// Class declarations in Typescript do not allow property declarations
const parentSymbol = lookupSymbolForPropertyAccess(lhs.expression);
if (!isInJavaScriptFile(node) && !isFunctionSymbol(parentSymbol)) {
return;
}
// Fix up parent pointers since we're going to use these nodes before we bind into them
node.left.parent = node;
node.right.parent = node;
@@ -2502,11 +2508,10 @@ namespace ts {
function bindPropertyAssignment(name: EntityNameExpression, propertyAccess: PropertyAccessEntityNameExpression, isPrototypeProperty: boolean) {
let namespaceSymbol = lookupSymbolForPropertyAccess(name);
const isToplevelNamespaceableInitializer = isBinaryExpression(propertyAccess.parent)
? getParentOfBinaryExpression(propertyAccess.parent).parent.kind === SyntaxKind.SourceFile &&
!!getJavascriptInitializer(getInitializerOfBinaryExpression(propertyAccess.parent), isPrototypeAccess(propertyAccess.parent.left))
const isToplevel = isBinaryExpression(propertyAccess.parent)
? getParentOfBinaryExpression(propertyAccess.parent).parent.kind === SyntaxKind.SourceFile
: propertyAccess.parent.parent.kind === SyntaxKind.SourceFile;
if (!isPrototypeProperty && (!namespaceSymbol || !(namespaceSymbol.flags & SymbolFlags.Namespace)) && isToplevelNamespaceableInitializer) {
if (!isPrototypeProperty && (!namespaceSymbol || !(namespaceSymbol.flags & SymbolFlags.Namespace)) && isToplevel) {
// make symbols or add declarations for intermediate containers
const flags = SymbolFlags.Module | SymbolFlags.JSContainer;
const excludeFlags = SymbolFlags.ValueModuleExcludes & ~SymbolFlags.JSContainer;
@@ -2529,12 +2534,10 @@ namespace ts {
(namespaceSymbol.members || (namespaceSymbol.members = createSymbolTable())) :
(namespaceSymbol.exports || (namespaceSymbol.exports = createSymbolTable()));
// Declare the method/property
const jsContainerFlag = isToplevelNamespaceableInitializer ? SymbolFlags.JSContainer : 0;
const isMethod = isFunctionLikeDeclaration(getAssignedJavascriptInitializer(propertyAccess)!);
const symbolFlags = (isMethod ? SymbolFlags.Method : SymbolFlags.Property) | jsContainerFlag;
const symbolExcludes = (isMethod ? SymbolFlags.MethodExcludes : SymbolFlags.PropertyExcludes) & ~jsContainerFlag;
declareSymbol(symbolTable, namespaceSymbol, propertyAccess, symbolFlags, symbolExcludes);
const includes = isMethod ? SymbolFlags.Method : SymbolFlags.Property;
const excludes = isMethod ? SymbolFlags.MethodExcludes : SymbolFlags.PropertyExcludes;
declareSymbol(symbolTable, namespaceSymbol, propertyAccess, includes | SymbolFlags.JSContainer, excludes & ~SymbolFlags.JSContainer);
}
/**
@@ -2565,7 +2568,7 @@ namespace ts {
return false;
}
function getParentOfBinaryExpression(expr: BinaryExpression) {
function getParentOfBinaryExpression(expr: Node) {
while (isBinaryExpression(expr.parent)) {
expr = expr.parent;
}
@@ -2652,8 +2655,11 @@ namespace ts {
}
if (!isBindingPattern(node.name)) {
const isEnum = !!getJSDocEnumTag(node);
const enumFlags = (isEnum ? SymbolFlags.RegularEnum : SymbolFlags.None);
const enumExcludes = (isEnum ? SymbolFlags.RegularEnumExcludes : SymbolFlags.None);
if (isBlockOrCatchScoped(node)) {
bindBlockScopedVariableDeclaration(node);
bindBlockScopedDeclaration(node, SymbolFlags.BlockScopedVariable | enumFlags, SymbolFlags.BlockScopedVariableExcludes | enumExcludes);
}
else if (isParameterDeclaration(node)) {
// It is safe to walk up parent chain to find whether the node is a destructuring parameter declaration
@@ -2668,7 +2674,7 @@ namespace ts {
declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.ParameterExcludes);
}
else {
declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable, SymbolFlags.FunctionScopedVariableExcludes);
declareSymbolAndAddToSymbolTable(node, SymbolFlags.FunctionScopedVariable | enumFlags, SymbolFlags.FunctionScopedVariableExcludes | enumExcludes);
}
}
}
@@ -2796,9 +2802,7 @@ namespace ts {
// report error on class declarations
node.kind === SyntaxKind.ClassDeclaration ||
// report error on instantiated modules or const-enums only modules if preserveConstEnums is set
(node.kind === SyntaxKind.ModuleDeclaration && shouldReportErrorOnModuleDeclaration(<ModuleDeclaration>node)) ||
// report error on regular enums and const enums if preserveConstEnums is set
(isEnumDeclaration(node) && (!isEnumConst(node) || options.preserveConstEnums));
(node.kind === SyntaxKind.ModuleDeclaration && shouldReportErrorOnModuleDeclaration(<ModuleDeclaration>node));
if (reportError) {
currentFlow = reportedUnreachableFlow;
@@ -2843,7 +2847,7 @@ namespace ts {
// As opposed to a pure declaration like an `interface`
function isExecutableStatement(s: Statement): boolean {
// Don't remove statements that can validly be used before they appear.
return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) &&
return !isFunctionDeclaration(s) && !isPurelyTypeDeclaration(s) && !isEnumDeclaration(s) &&
// `var x;` may declare a variable used above
!(isVariableStatement(s) && !(getCombinedNodeFlags(s) & (NodeFlags.Let | NodeFlags.Const)) && s.declarationList.declarations.some(d => !d.initializer));
}
+2 -1
View File
@@ -65,7 +65,8 @@ namespace ts {
}
state.changedFilesSet = createMap<true>();
const useOldState = BuilderState.canReuseOldState(state.referencedMap, oldState);
const canCopySemanticDiagnostics = useOldState && oldState!.semanticDiagnosticsPerFile && !!state.semanticDiagnosticsPerFile;
const canCopySemanticDiagnostics = useOldState && oldState!.semanticDiagnosticsPerFile && !!state.semanticDiagnosticsPerFile &&
!compilerOptionsAffectSemanticDiagnostics(compilerOptions, oldState!.program.getCompilerOptions());
if (useOldState) {
// Verify the sanity of old state
if (!oldState!.currentChangedFilePath) {
+1458 -1364
View File
File diff suppressed because it is too large Load Diff
+136 -25
View File
@@ -62,9 +62,7 @@ namespace ts {
/* @internal */
export const libMap = createMapFromEntries(libEntries);
/* @internal */
export const optionDeclarations: CommandLineOption[] = [
// CommandLine only options
const commonOptionsWithBuild: CommandLineOption[] = [
{
name: "help",
shortName: "h",
@@ -78,6 +76,27 @@ namespace ts {
shortName: "?",
type: "boolean"
},
{
name: "preserveWatchOutput",
type: "boolean",
showInSimplifiedHelpView: false,
category: Diagnostics.Command_line_Options,
description: Diagnostics.Whether_to_keep_outdated_console_output_in_watch_mode_instead_of_clearing_the_screen,
},
{
name: "watch",
shortName: "w",
type: "boolean",
showInSimplifiedHelpView: true,
category: Diagnostics.Command_line_Options,
description: Diagnostics.Watch_input_files,
},
];
/* @internal */
export const optionDeclarations: CommandLineOption[] = [
// CommandLine only options
...commonOptionsWithBuild,
{
name: "all",
type: "boolean",
@@ -125,21 +144,6 @@ namespace ts {
category: Diagnostics.Command_line_Options,
description: Diagnostics.Stylize_errors_and_messages_using_color_and_context_experimental
},
{
name: "preserveWatchOutput",
type: "boolean",
showInSimplifiedHelpView: false,
category: Diagnostics.Command_line_Options,
description: Diagnostics.Whether_to_keep_outdated_console_output_in_watch_mode_instead_of_clearing_the_screen,
},
{
name: "watch",
shortName: "w",
type: "boolean",
showInSimplifiedHelpView: true,
category: Diagnostics.Command_line_Options,
description: Diagnostics.Watch_input_files,
},
// Basic
{
@@ -319,13 +323,15 @@ namespace ts {
{
name: "noImplicitAny",
type: "boolean",
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
description: Diagnostics.Raise_error_on_expressions_and_declarations_with_an_implied_any_type,
description: Diagnostics.Raise_error_on_expressions_and_declarations_with_an_implied_any_type
},
{
name: "strictNullChecks",
type: "boolean",
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
description: Diagnostics.Enable_strict_null_checks
@@ -333,6 +339,7 @@ namespace ts {
{
name: "strictFunctionTypes",
type: "boolean",
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
description: Diagnostics.Enable_strict_checking_of_function_types
@@ -340,6 +347,7 @@ namespace ts {
{
name: "strictPropertyInitialization",
type: "boolean",
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
description: Diagnostics.Enable_strict_checking_of_property_initialization_in_classes
@@ -347,6 +355,7 @@ namespace ts {
{
name: "noImplicitThis",
type: "boolean",
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
description: Diagnostics.Raise_error_on_this_expressions_with_an_implied_any_type,
@@ -354,6 +363,7 @@ namespace ts {
{
name: "alwaysStrict",
type: "boolean",
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
description: Diagnostics.Parse_in_strict_mode_and_emit_use_strict_for_each_source_file
@@ -363,6 +373,7 @@ namespace ts {
{
name: "noUnusedLocals",
type: "boolean",
affectsSemanticDiagnostics: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Additional_Checks,
description: Diagnostics.Report_errors_on_unused_locals,
@@ -370,6 +381,7 @@ namespace ts {
{
name: "noUnusedParameters",
type: "boolean",
affectsSemanticDiagnostics: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Additional_Checks,
description: Diagnostics.Report_errors_on_unused_parameters,
@@ -377,6 +389,7 @@ namespace ts {
{
name: "noImplicitReturns",
type: "boolean",
affectsSemanticDiagnostics: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Additional_Checks,
description: Diagnostics.Report_error_when_not_all_code_paths_in_function_return_a_value
@@ -384,6 +397,7 @@ namespace ts {
{
name: "noFallthroughCasesInSwitch",
type: "boolean",
affectsSemanticDiagnostics: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Additional_Checks,
description: Diagnostics.Report_errors_for_fallthrough_cases_in_switch_statement
@@ -455,12 +469,14 @@ namespace ts {
{
name: "allowSyntheticDefaultImports",
type: "boolean",
affectsSemanticDiagnostics: true,
category: Diagnostics.Module_Resolution_Options,
description: Diagnostics.Allow_default_imports_from_modules_with_no_default_export_This_does_not_affect_code_emit_just_typechecking
},
{
name: "esModuleInterop",
type: "boolean",
affectsSemanticDiagnostics: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Module_Resolution_Options,
description: Diagnostics.Enables_emit_interoperability_between_CommonJS_and_ES_Modules_via_creation_of_namespace_objects_for_all_imports_Implies_allowSyntheticDefaultImports
@@ -640,6 +656,7 @@ namespace ts {
{
name: "noImplicitUseStrict",
type: "boolean",
affectsSemanticDiagnostics: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Do_not_emit_use_strict_directives_in_module_output
},
@@ -678,24 +695,28 @@ namespace ts {
{
name: "allowUnusedLabels",
type: "boolean",
affectsSemanticDiagnostics: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Do_not_report_errors_on_unused_labels
},
{
name: "allowUnreachableCode",
type: "boolean",
affectsSemanticDiagnostics: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Do_not_report_errors_on_unreachable_code
},
{
name: "suppressExcessPropertyErrors",
type: "boolean",
affectsSemanticDiagnostics: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Suppress_excess_property_checks_for_object_literals,
},
{
name: "suppressImplicitAnyIndexErrors",
type: "boolean",
affectsSemanticDiagnostics: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Suppress_noImplicitAny_errors_for_indexing_objects_lacking_index_signatures,
},
@@ -714,6 +735,7 @@ namespace ts {
{
name: "noStrictGenericChecks",
type: "boolean",
affectsSemanticDiagnostics: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Disable_strict_checking_of_generic_signatures_in_function_types,
},
@@ -736,6 +758,38 @@ namespace ts {
}
];
/* @internal */
export const buildOpts: CommandLineOption[] = [
...commonOptionsWithBuild,
{
name: "verbose",
shortName: "v",
category: Diagnostics.Command_line_Options,
description: Diagnostics.Enable_verbose_logging,
type: "boolean"
},
{
name: "dry",
shortName: "d",
category: Diagnostics.Command_line_Options,
description: Diagnostics.Show_what_would_be_built_or_deleted_if_specified_with_clean,
type: "boolean"
},
{
name: "force",
shortName: "f",
category: Diagnostics.Command_line_Options,
description: Diagnostics.Build_all_projects_including_those_that_appear_to_be_up_to_date,
type: "boolean"
},
{
name: "clean",
category: Diagnostics.Command_line_Options,
description: Diagnostics.Delete_the_outputs_of_all_projects,
type: "boolean"
}
];
/* @internal */
export const typeAcquisitionDeclarations: CommandLineOption[] = [
{
@@ -797,10 +851,11 @@ namespace ts {
}
function getOptionNameMap(): OptionNameMap {
if (optionNameMapCache) {
return optionNameMapCache;
}
return optionNameMapCache || (optionNameMapCache = createOptionNameMap(optionDeclarations));
}
/*@internal*/
export function createOptionNameMap(optionDeclarations: ReadonlyArray<CommandLineOption>): OptionNameMap {
const optionNameMap = createMap<CommandLineOption>();
const shortOptionNames = createMap<string>();
forEach(optionDeclarations, option => {
@@ -810,8 +865,7 @@ namespace ts {
}
});
optionNameMapCache = { optionNameMap, shortOptionNames };
return optionNameMapCache;
return { optionNameMap, shortOptionNames };
}
/* @internal */
@@ -961,7 +1015,12 @@ namespace ts {
}
/** @internal */
export function getOptionFromName(optionName: string, allowShort = false): CommandLineOption | undefined {
export function getOptionFromName(optionName: string, allowShort?: boolean): CommandLineOption | undefined {
return getOptionDeclarationFromName(getOptionNameMap, optionName, allowShort);
}
/*@internal*/
export function getOptionDeclarationFromName(getOptionNameMap: () => OptionNameMap, optionName: string, allowShort = false): CommandLineOption | undefined {
optionName = optionName.toLowerCase();
const { optionNameMap, shortOptionNames } = getOptionNameMap();
// Try to translate short option names to their full equivalents.
@@ -974,6 +1033,58 @@ namespace ts {
return optionNameMap.get(optionName);
}
/*@internal*/
export interface ParsedBuildCommand {
buildOptions: BuildOptions;
projects: string[];
errors: ReadonlyArray<Diagnostic>;
}
/*@internal*/
export function parseBuildCommand(args: string[]): ParsedBuildCommand {
let buildOptionNameMap: OptionNameMap | undefined;
const returnBuildOptionNameMap = () => (buildOptionNameMap || (buildOptionNameMap = createOptionNameMap(buildOpts)));
const buildOptions: BuildOptions = {};
const projects: string[] = [];
let errors: Diagnostic[] | undefined;
for (const arg of args) {
if (arg.charCodeAt(0) === CharacterCodes.minus) {
const opt = getOptionDeclarationFromName(returnBuildOptionNameMap, arg.slice(arg.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true);
if (opt) {
buildOptions[opt.name as keyof BuildOptions] = true;
}
else {
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Unknown_build_option_0, arg));
}
}
else {
// Not a flag, parse as filename
projects.push(arg);
}
}
if (projects.length === 0) {
// tsc -b invoked with no extra arguments; act as if invoked with "tsc -b ."
projects.push(".");
}
// Nonsensical combinations
if (buildOptions.clean && buildOptions.force) {
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force"));
}
if (buildOptions.clean && buildOptions.verbose) {
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "verbose"));
}
if (buildOptions.clean && buildOptions.watch) {
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "watch"));
}
if (buildOptions.watch && buildOptions.dry) {
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "dry"));
}
return { buildOptions, projects, errors: errors || emptyArray };
}
function getDiagnosticText(_message: DiagnosticMessage, ..._args: any[]): string {
const diagnostic = createCompilerDiagnostic.apply(undefined, arguments);
+4 -10
View File
@@ -789,11 +789,8 @@ namespace ts {
* @param comparer An optional `Comparer` used to sort entries before comparison, though the
* result will remain in the original order in `array`.
*/
export function deduplicate<T>(array: ReadonlyArray<T>, equalityComparer?: EqualityComparer<T>, comparer?: Comparer<T>): T[];
export function deduplicate<T>(array: ReadonlyArray<T> | undefined, equalityComparer?: EqualityComparer<T>, comparer?: Comparer<T>): T[] | undefined;
export function deduplicate<T>(array: ReadonlyArray<T> | undefined, equalityComparer: EqualityComparer<T>, comparer?: Comparer<T>): T[] | undefined {
return !array ? undefined :
array.length === 0 ? [] :
export function deduplicate<T>(array: ReadonlyArray<T>, equalityComparer: EqualityComparer<T>, comparer?: Comparer<T>): T[] {
return array.length === 0 ? [] :
array.length === 1 ? array.slice() :
comparer ? deduplicateRelational(array, equalityComparer, comparer) :
deduplicateEquality(array, equalityComparer);
@@ -802,10 +799,7 @@ namespace ts {
/**
* Deduplicates an array that has already been sorted.
*/
function deduplicateSorted<T>(array: ReadonlyArray<T>, comparer: EqualityComparer<T> | Comparer<T>): T[];
function deduplicateSorted<T>(array: ReadonlyArray<T> | undefined, comparer: EqualityComparer<T> | Comparer<T>): T[] | undefined;
function deduplicateSorted<T>(array: ReadonlyArray<T> | undefined, comparer: EqualityComparer<T> | Comparer<T>): T[] | undefined {
if (!array) return undefined;
function deduplicateSorted<T>(array: ReadonlyArray<T>, comparer: EqualityComparer<T> | Comparer<T>): T[] {
if (array.length === 0) return [];
let last = array[0];
@@ -1272,7 +1266,7 @@ namespace ts {
if (!left || !right) return false;
for (const key in left) {
if (hasOwnProperty.call(left, key)) {
if (!hasOwnProperty.call(right, key) === undefined) return false;
if (!hasOwnProperty.call(right, key)) return false;
if (!equalityComparer(left[key], right[key])) return false;
}
}
+54 -5
View File
@@ -987,6 +987,26 @@
"category": "Error",
"code": 1344
},
"An expression of type 'void' cannot be tested for truthiness": {
"category": "Error",
"code": 1345
},
"This parameter is not allowed with 'use strict' directive.": {
"category": "Error",
"code": 1346
},
"'use strict' directive cannot be used with non-simple parameter list.": {
"category": "Error",
"code": 1347
},
"Non-simple parameter declared here.": {
"category": "Error",
"code": 1348
},
"'use strict' directive used here.": {
"category": "Error",
"code": 1349
},
"Duplicate identifier '{0}'.": {
"category": "Error",
@@ -1960,10 +1980,6 @@
"category": "Error",
"code": 2549
},
"Generic type instantiation is excessively deep and possibly infinite.": {
"category": "Error",
"code": 2550
},
"Property '{0}' does not exist on type '{1}'. Did you mean '{2}'?": {
"category": "Error",
"code": 2551
@@ -2064,6 +2080,14 @@
"category": "Error",
"code": 2575
},
"Property '{0}' is a static member of type '{1}'": {
"category": "Error",
"code": 2576
},
"Return type annotation circularly references itself.": {
"category": "Error",
"code": 2577
},
"JSX element attributes type '{0}' may not be a union type.": {
"category": "Error",
"code": 2600
@@ -2429,6 +2453,10 @@
"category": "Error",
"code": 2732
},
"Index '{0}' is out-of-bounds in tuple of length {1}.": {
"category": "Error",
"code": 2733
},
"Import declaration '{0}' is using private name '{1}'.": {
"category": "Error",
@@ -2888,6 +2916,11 @@
"category": "Error",
"code": 5071
},
"Unknown build option '{0}'.": {
"category": "Error",
"code": 5072
},
"Generates a sourcemap for each corresponding '.d.ts' file.": {
"category": "Message",
@@ -3929,6 +3962,10 @@
"category": "Error",
"code": 7041
},
"Module '{0}' was resolved to '{1}', but '--resolveJsonModule' is not used.": {
"category": "Error",
"code": 7042
},
"You cannot rename this element.": {
"category": "Error",
"code": 8000
@@ -4171,7 +4208,10 @@
"category": "Suggestion",
"code": 80005
},
"This may be converted to an async function.": {
"category": "Suggestion",
"code": 80006
},
"Add missing 'super()' call": {
"category": "Message",
"code": 90001
@@ -4544,6 +4584,7 @@
"category": "Message",
"code": 95062
},
"Add missing enum member '{0}'": {
"category": "Message",
"code": 95063
@@ -4551,5 +4592,13 @@
"Add all missing imports": {
"category": "Message",
"code": 95064
},
"Convert to async function":{
"category": "Message",
"code": 95065
},
"Convert all to async functions": {
"category": "Message",
"code": 95066
}
}
+7 -3
View File
@@ -2593,14 +2593,14 @@ namespace ts {
}
function emitSyntheticTripleSlashReferencesIfNeeded(node: Bundle) {
emitTripleSlashDirectives(!!node.hasNoDefaultLib, node.syntheticFileReferences || [], node.syntheticTypeReferences || []);
emitTripleSlashDirectives(!!node.hasNoDefaultLib, node.syntheticFileReferences || [], node.syntheticTypeReferences || [], node.syntheticLibReferences || []);
}
function emitTripleSlashDirectivesIfNeeded(node: SourceFile) {
if (node.isDeclarationFile) emitTripleSlashDirectives(node.hasNoDefaultLib, node.referencedFiles, node.typeReferenceDirectives);
if (node.isDeclarationFile) emitTripleSlashDirectives(node.hasNoDefaultLib, node.referencedFiles, node.typeReferenceDirectives, node.libReferenceDirectives);
}
function emitTripleSlashDirectives(hasNoDefaultLib: boolean, files: ReadonlyArray<FileReference>, types: ReadonlyArray<FileReference>) {
function emitTripleSlashDirectives(hasNoDefaultLib: boolean, files: ReadonlyArray<FileReference>, types: ReadonlyArray<FileReference>, libs: ReadonlyArray<FileReference>) {
if (hasNoDefaultLib) {
write(`/// <reference no-default-lib="true"/>`);
writeLine();
@@ -2628,6 +2628,10 @@ namespace ts {
write(`/// <reference types="${directive.fileName}" />`);
writeLine();
}
for (const directive of libs) {
write(`/// <reference lib="${directive.fileName}" />`);
writeLine();
}
}
function emitSourceFileWorker(node: SourceFile) {
+22 -13
View File
@@ -3894,6 +3894,20 @@ namespace ts {
return statementOffset;
}
export function findUseStrictPrologue(statements: ReadonlyArray<Statement>): Statement | undefined {
for (const statement of statements) {
if (isPrologueDirective(statement)) {
if (isUseStrictPrologue(statement)) {
return statement;
}
}
else {
break;
}
}
return undefined;
}
export function startsWithUseStrict(statements: ReadonlyArray<Statement>) {
const firstStatement = firstOrUndefined(statements);
return firstStatement !== undefined
@@ -3907,18 +3921,7 @@ namespace ts {
* @param statements An array of statements
*/
export function ensureUseStrict(statements: NodeArray<Statement>): NodeArray<Statement> {
let foundUseStrict = false;
for (const statement of statements) {
if (isPrologueDirective(statement)) {
if (isUseStrictPrologue(statement as ExpressionStatement)) {
foundUseStrict = true;
break;
}
}
else {
break;
}
}
const foundUseStrict = findUseStrictPrologue(statements);
if (!foundUseStrict) {
return setTextRange(
@@ -4709,7 +4712,7 @@ namespace ts {
/**
* Gets the property name of a BindingOrAssignmentElement
*/
export function getPropertyNameOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement) {
export function getPropertyNameOfBindingOrAssignmentElement(bindingElement: BindingOrAssignmentElement): PropertyName | undefined {
switch (bindingElement.kind) {
case SyntaxKind.BindingElement:
// `a` in `let { a: b } = ...`
@@ -4754,6 +4757,12 @@ namespace ts {
Debug.fail("Invalid property name for binding element.");
}
function isStringOrNumericLiteral(node: Node): node is StringLiteral | NumericLiteral {
const kind = node.kind;
return kind === SyntaxKind.StringLiteral
|| kind === SyntaxKind.NumericLiteral;
}
/**
* Gets the elements of a BindingOrAssignmentPattern
*/
+49 -45
View File
@@ -29,6 +29,15 @@ namespace ts {
path: string;
extension: Extension;
packageId: PackageId | undefined;
/**
* When the resolved is not created from cache, the value is
* - string if original Path if it is symbolic link to the resolved path
* - undefined if path is not a symbolic link
* When the resolved is created using value from cache of ResolvedModuleWithFailedLookupLocations, the value is:
* - string if original Path if it is symbolic link to the resolved path
* - true if path is not a symbolic link - this indicates that the originalPath calculation is already done and needs to be skipped
*/
originalPath?: string | true;
}
/** Result of trying to resolve a module at a file. Needs to have 'packageId' added later. */
@@ -62,9 +71,9 @@ namespace ts {
return { fileName: resolved.path, packageId: resolved.packageId };
}
function createResolvedModuleWithFailedLookupLocations(resolved: Resolved | undefined, originalPath: string | undefined, isExternalLibraryImport: boolean, failedLookupLocations: string[]): ResolvedModuleWithFailedLookupLocations {
function createResolvedModuleWithFailedLookupLocations(resolved: Resolved | undefined, isExternalLibraryImport: boolean, failedLookupLocations: string[]): ResolvedModuleWithFailedLookupLocations {
return {
resolvedModule: resolved && { resolvedFileName: resolved.path, originalPath, extension: resolved.extension, isExternalLibraryImport, packageId: resolved.packageId },
resolvedModule: resolved && { resolvedFileName: resolved.path, originalPath: resolved.originalPath === true ? undefined : resolved.originalPath, extension: resolved.extension, isExternalLibraryImport, packageId: resolved.packageId },
failedLookupLocations
};
}
@@ -362,9 +371,7 @@ namespace ts {
}
function getOrCreateCacheForModuleName(nonRelativeModuleName: string): PerModuleNameCache {
if (isExternalModuleNameRelative(nonRelativeModuleName)) {
return undefined!; // TODO: GH#18217
}
Debug.assert(!isExternalModuleNameRelative(nonRelativeModuleName));
let perModuleNameCache = moduleNameToDirectoryMap.get(nonRelativeModuleName);
if (!perModuleNameCache) {
perModuleNameCache = createPerModuleNameCache();
@@ -401,46 +408,47 @@ namespace ts {
}
directoryPathMap.set(path, result);
const resolvedFileName = result.resolvedModule && result.resolvedModule.resolvedFileName;
const resolvedFileName = result.resolvedModule &&
(result.resolvedModule.originalPath || result.resolvedModule.resolvedFileName);
// find common prefix between directory and resolved file name
// this common prefix should be the shorted path that has the same resolution
// this common prefix should be the shortest path that has the same resolution
// directory: /a/b/c/d/e
// resolvedFileName: /a/b/foo.d.ts
const commonPrefix = getCommonPrefix(path, resolvedFileName);
// commonPrefix: /a/b
// for failed lookups cache the result for every directory up to root
const commonPrefix = resolvedFileName && getCommonPrefix(path, resolvedFileName);
let current = path;
while (true) {
while (current !== commonPrefix) {
const parent = getDirectoryPath(current);
if (parent === current || directoryPathMap.has(parent)) {
break;
}
directoryPathMap.set(parent, result);
current = parent;
if (current === commonPrefix) {
break;
}
}
}
function getCommonPrefix(directory: Path, resolution: string | undefined) {
if (resolution === undefined) {
return undefined;
}
function getCommonPrefix(directory: Path, resolution: string) {
const resolutionDirectory = toPath(getDirectoryPath(resolution), currentDirectory, getCanonicalFileName);
// find first position where directory and resolution differs
let i = 0;
while (i < Math.min(directory.length, resolutionDirectory.length) && directory.charCodeAt(i) === resolutionDirectory.charCodeAt(i)) {
const limit = Math.min(directory.length, resolutionDirectory.length);
while (i < limit && directory.charCodeAt(i) === resolutionDirectory.charCodeAt(i)) {
i++;
}
// find last directory separator before position i
const sep = directory.lastIndexOf(directorySeparator, i);
if (sep < 0) {
if (i === directory.length && (resolutionDirectory.length === i || resolutionDirectory[i] === directorySeparator)) {
return directory;
}
const rootLength = getRootLength(directory);
if (i < rootLength) {
return undefined;
}
return directory.substr(0, sep);
const sep = directory.lastIndexOf(directorySeparator, i - 1);
if (sep === -1) {
return undefined;
}
return directory.substr(0, Math.max(sep, rootLength));
}
}
}
@@ -492,10 +500,9 @@ namespace ts {
if (perFolderCache) {
perFolderCache.set(moduleName, result);
// put result in per-module name cache
const perModuleNameCache = cache!.getOrCreateCacheForModuleName(moduleName);
if (perModuleNameCache) {
perModuleNameCache.set(containingDirectory, result);
if (!isExternalModuleNameRelative(moduleName)) {
// put result in per-module name cache
cache!.getOrCreateCacheForModuleName(moduleName).set(containingDirectory, result);
}
}
}
@@ -753,16 +760,16 @@ namespace ts {
tryResolve(Extensions.JavaScript) ||
(compilerOptions.resolveJsonModule ? tryResolve(Extensions.Json) : undefined));
if (result && result.value) {
const { resolved, originalPath, isExternalLibraryImport } = result.value;
return createResolvedModuleWithFailedLookupLocations(resolved, originalPath, isExternalLibraryImport, failedLookupLocations);
const { resolved, isExternalLibraryImport } = result.value;
return createResolvedModuleWithFailedLookupLocations(resolved, isExternalLibraryImport, failedLookupLocations);
}
return { resolvedModule: undefined, failedLookupLocations };
function tryResolve(extensions: Extensions): SearchResult<{ resolved: Resolved, originalPath?: string, isExternalLibraryImport: boolean }> {
function tryResolve(extensions: Extensions): SearchResult<{ resolved: Resolved, isExternalLibraryImport: boolean }> {
const loader: ResolutionKindSpecificLoader = (extensions, candidate, failedLookupLocations, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/ true);
const resolved = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loader, failedLookupLocations, state);
if (resolved) {
return toSearchResult({ resolved, isExternalLibraryImport: false });
return toSearchResult({ resolved, isExternalLibraryImport: stringContains(resolved.path, nodeModulesPathPart) });
}
if (!isExternalModuleNameRelative(moduleName)) {
@@ -773,17 +780,13 @@ namespace ts {
if (!resolved) return undefined;
let resolvedValue = resolved.value;
let originalPath: string | undefined;
if (!compilerOptions.preserveSymlinks && resolvedValue) {
originalPath = resolvedValue.path;
if (!compilerOptions.preserveSymlinks && resolvedValue && !resolvedValue.originalPath) {
const path = realPath(resolvedValue.path, host, traceEnabled);
if (path === originalPath) {
originalPath = undefined;
}
resolvedValue = { ...resolvedValue, path };
const originalPath = path === resolvedValue.path ? undefined : resolvedValue.path;
resolvedValue = { ...resolvedValue, path, originalPath };
}
// For node_modules lookups, get the real path so that multiple accesses to an `npm link`-ed module do not create duplicate files.
return { value: resolvedValue && { resolved: resolvedValue, originalPath, isExternalLibraryImport: true } };
return { value: resolvedValue && { resolved: resolvedValue, isExternalLibraryImport: true } };
}
else {
const { path: candidate, parts } = normalizePathAndParts(combinePaths(containingDirectory, moduleName));
@@ -840,7 +843,8 @@ namespace ts {
return loadNodeModuleFromDirectory(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, considerPackageJson);
}
const nodeModulesPathPart = "/node_modules/";
/*@internal*/
export const nodeModulesPathPart = "/node_modules/";
/**
* This will be called on the successfully resolved path from `loadModuleFromFile`.
@@ -1233,7 +1237,7 @@ namespace ts {
trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory);
}
failedLookupLocations.push(...result.failedLookupLocations);
return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId } };
return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, originalPath: result.resolvedModule.originalPath || true, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId } };
}
}
@@ -1245,16 +1249,16 @@ namespace ts {
const resolved = tryResolve(Extensions.TypeScript) || tryResolve(Extensions.JavaScript);
// No originalPath because classic resolution doesn't resolve realPath
return createResolvedModuleWithFailedLookupLocations(resolved && resolved.value, /*originalPath*/ undefined, /*isExternalLibraryImport*/ false, failedLookupLocations);
return createResolvedModuleWithFailedLookupLocations(resolved && resolved.value, /*isExternalLibraryImport*/ false, failedLookupLocations);
function tryResolve(extensions: Extensions): SearchResult<Resolved> {
const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, failedLookupLocations, state);
if (resolvedUsingSettings) {
return { value: resolvedUsingSettings };
}
const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName);
if (!isExternalModuleNameRelative(moduleName)) {
const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName);
// Climb up parent directories looking for a module.
const resolved = forEachAncestorDirectory(containingDirectory, directory => {
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, directory, traceEnabled, host, failedLookupLocations);
@@ -1292,7 +1296,7 @@ namespace ts {
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled };
const failedLookupLocations: string[] = [];
const resolved = loadModuleFromNodeModulesOneLevel(Extensions.DtsOnly, moduleName, globalCache, failedLookupLocations, state);
return createResolvedModuleWithFailedLookupLocations(resolved, /*originalPath*/ undefined, /*isExternalLibraryImport*/ true, failedLookupLocations);
return createResolvedModuleWithFailedLookupLocations(resolved, /*isExternalLibraryImport*/ true, failedLookupLocations);
}
/**
+131 -146
View File
@@ -1,8 +1,52 @@
// Used by importFixes, getEditsForFileRename, and declaration emit to synthesize import module specifiers.
/* @internal */
namespace ts.moduleSpecifiers {
export interface ModuleSpecifierPreferences {
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
const enum RelativePreference { Relative, NonRelative, Auto }
// See UserPreferences#importPathEnding
const enum Ending { Minimal, Index, JsExtension }
// Processed preferences
interface Preferences {
readonly relativePreference: RelativePreference;
readonly ending: Ending;
}
function getPreferences({ importModuleSpecifierPreference, importModuleSpecifierEnding }: UserPreferences, compilerOptions: CompilerOptions, importingSourceFile: SourceFile): Preferences {
return {
relativePreference: importModuleSpecifierPreference === "relative" ? RelativePreference.Relative : importModuleSpecifierPreference === "non-relative" ? RelativePreference.NonRelative : RelativePreference.Auto,
ending: getEnding(),
};
function getEnding(): Ending {
switch (importModuleSpecifierEnding) {
case "minimal": return Ending.Minimal;
case "index": return Ending.Index;
case "js": return Ending.JsExtension;
default: return usesJsExtensionOnImports(importingSourceFile) ? Ending.JsExtension
: getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeJs ? Ending.Index : Ending.Minimal;
}
}
}
function getPreferencesForUpdate(compilerOptions: CompilerOptions, oldImportSpecifier: string): Preferences {
return {
relativePreference: isExternalModuleNameRelative(oldImportSpecifier) ? RelativePreference.Relative : RelativePreference.NonRelative,
ending: hasJavaScriptOrJsonFileExtension(oldImportSpecifier) ? Ending.JsExtension
: getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeJs || endsWith(oldImportSpecifier, "index") ? Ending.Index : Ending.Minimal,
};
}
export function updateModuleSpecifier(
compilerOptions: CompilerOptions,
importingSourceFileName: Path,
toFileName: string,
host: ModuleSpecifierResolutionHost,
files: ReadonlyArray<SourceFile>,
redirectTargetsMap: RedirectTargetsMap,
oldImportSpecifier: string,
): string | undefined {
const res = getModuleSpecifierWorker(compilerOptions, importingSourceFileName, toFileName, host, files, redirectTargetsMap, getPreferencesForUpdate(compilerOptions, oldImportSpecifier));
if (res === oldImportSpecifier) return undefined;
return res;
}
// Note: importingSourceFile is just for usesJsExtensionOnImports
@@ -13,148 +57,98 @@ namespace ts.moduleSpecifiers {
toFileName: string,
host: ModuleSpecifierResolutionHost,
files: ReadonlyArray<SourceFile>,
preferences: ModuleSpecifierPreferences = {},
preferences: UserPreferences = {},
redirectTargetsMap: RedirectTargetsMap,
): string {
const info = getInfo(compilerOptions, importingSourceFile, importingSourceFileName, host);
const modulePaths = getAllModulePaths(files, importingSourceFileName, toFileName, info.getCanonicalFileName, host, redirectTargetsMap);
return firstDefined(modulePaths, moduleFileName => getGlobalModuleSpecifier(moduleFileName, info, host, compilerOptions)) ||
first(getLocalModuleSpecifiers(toFileName, info, compilerOptions, preferences));
return getModuleSpecifierWorker(compilerOptions, importingSourceFileName, toFileName, host, files, redirectTargetsMap, getPreferences(preferences, compilerOptions, importingSourceFile));
}
export function getModuleSpecifierForDeclarationFile(
moduleSymbol: Symbol,
function getModuleSpecifierWorker(
compilerOptions: CompilerOptions,
importingSourceFile: SourceFile,
importingSourceFileName: Path,
toFileName: string,
host: ModuleSpecifierResolutionHost,
files: ReadonlyArray<SourceFile>,
preferences: ModuleSpecifierPreferences,
redirectTargetsMap: RedirectTargetsMap,
preferences: Preferences
): string {
return first(first(getModuleSpecifiers(moduleSymbol, compilerOptions, importingSourceFile, host, files, preferences, redirectTargetsMap)));
const info = getInfo(importingSourceFileName, host);
const modulePaths = getAllModulePaths(files, importingSourceFileName, toFileName, info.getCanonicalFileName, host, redirectTargetsMap);
return firstDefined(modulePaths, moduleFileName => tryGetModuleNameAsNodeModule(moduleFileName, info, host, compilerOptions)) ||
getLocalModuleSpecifier(toFileName, info, compilerOptions, preferences);
}
// For each symlink/original for a module, returns a list of ways to import that file.
// Returns an import for each symlink and for the realpath.
export function getModuleSpecifiers(
moduleSymbol: Symbol,
compilerOptions: CompilerOptions,
importingSourceFile: SourceFile,
host: ModuleSpecifierResolutionHost,
files: ReadonlyArray<SourceFile>,
preferences: ModuleSpecifierPreferences,
userPreferences: UserPreferences,
redirectTargetsMap: RedirectTargetsMap,
): ReadonlyArray<ReadonlyArray<string>> {
): ReadonlyArray<string> {
const ambient = tryGetModuleNameFromAmbientModule(moduleSymbol);
if (ambient) return [[ambient]];
if (ambient) return [ambient];
const info = getInfo(compilerOptions, importingSourceFile, importingSourceFile.path, host);
if (!files) {
return Debug.fail("Files list must be present to resolve symlinks in specifier resolution");
}
const moduleSourceFile = getSourceFileOfNode(moduleSymbol.valueDeclaration);
const info = getInfo(importingSourceFile.path, host);
const moduleSourceFile = getSourceFileOfNode(moduleSymbol.valueDeclaration || getNonAugmentationDeclaration(moduleSymbol));
const modulePaths = getAllModulePaths(files, importingSourceFile.path, moduleSourceFile.fileName, info.getCanonicalFileName, host, redirectTargetsMap);
const global = mapDefined(modulePaths, moduleFileName => getGlobalModuleSpecifier(moduleFileName, info, host, compilerOptions));
return global.length ? global.map(g => [g]) : modulePaths.map(moduleFileName =>
getLocalModuleSpecifiers(moduleFileName, info, compilerOptions, preferences));
const preferences = getPreferences(userPreferences, compilerOptions, importingSourceFile);
const global = mapDefined(modulePaths, moduleFileName => tryGetModuleNameAsNodeModule(moduleFileName, info, host, compilerOptions));
return global.length ? global : modulePaths.map(moduleFileName => getLocalModuleSpecifier(moduleFileName, info, compilerOptions, preferences));
}
interface Info {
readonly moduleResolutionKind: ModuleResolutionKind;
readonly addJsExtension: boolean;
readonly getCanonicalFileName: GetCanonicalFileName;
readonly sourceDirectory: Path;
}
// importingSourceFileName is separate because getEditsForFileRename may need to specify an updated path
function getInfo(compilerOptions: CompilerOptions, importingSourceFile: SourceFile, importingSourceFileName: Path, host: ModuleSpecifierResolutionHost): Info {
const moduleResolutionKind = getEmitModuleResolutionKind(compilerOptions);
const addJsExtension = usesJsExtensionOnImports(importingSourceFile);
function getInfo(importingSourceFileName: Path, host: ModuleSpecifierResolutionHost): Info {
const getCanonicalFileName = createGetCanonicalFileName(host.useCaseSensitiveFileNames ? host.useCaseSensitiveFileNames() : true);
const sourceDirectory = getDirectoryPath(importingSourceFileName);
return { moduleResolutionKind, addJsExtension, getCanonicalFileName, sourceDirectory };
return { getCanonicalFileName, sourceDirectory };
}
function getGlobalModuleSpecifier(
moduleFileName: string,
{ addJsExtension, getCanonicalFileName, sourceDirectory }: Info,
host: ModuleSpecifierResolutionHost,
compilerOptions: CompilerOptions,
) {
return tryGetModuleNameFromTypeRoots(compilerOptions, host, getCanonicalFileName, moduleFileName, addJsExtension)
|| tryGetModuleNameAsNodeModule(compilerOptions, moduleFileName, host, getCanonicalFileName, sourceDirectory);
}
function getLocalModuleSpecifiers(
moduleFileName: string,
{ moduleResolutionKind, addJsExtension, getCanonicalFileName, sourceDirectory }: Info,
compilerOptions: CompilerOptions,
preferences: ModuleSpecifierPreferences,
): ReadonlyArray<string> {
function getLocalModuleSpecifier(moduleFileName: string, { getCanonicalFileName, sourceDirectory }: Info, compilerOptions: CompilerOptions, { ending, relativePreference }: Preferences): string {
const { baseUrl, paths, rootDirs } = compilerOptions;
const relativePath = rootDirs && tryGetModuleNameFromRootDirs(rootDirs, moduleFileName, sourceDirectory, getCanonicalFileName) ||
removeExtensionAndIndexPostFix(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), moduleResolutionKind, addJsExtension);
if (!baseUrl || preferences.importModuleSpecifierPreference === "relative") {
return [relativePath];
removeExtensionAndIndexPostFix(ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, moduleFileName, getCanonicalFileName)), ending, compilerOptions);
if (!baseUrl || relativePreference === RelativePreference.Relative) {
return relativePath;
}
const relativeToBaseUrl = getRelativePathIfInDirectory(moduleFileName, baseUrl, getCanonicalFileName);
if (!relativeToBaseUrl) {
return [relativePath];
return relativePath;
}
const importRelativeToBaseUrl = removeExtensionAndIndexPostFix(relativeToBaseUrl, moduleResolutionKind, addJsExtension);
if (paths) {
const fromPaths = tryGetModuleNameFromPaths(removeFileExtension(relativeToBaseUrl), importRelativeToBaseUrl, paths);
if (fromPaths) {
return [fromPaths];
}
const importRelativeToBaseUrl = removeExtensionAndIndexPostFix(relativeToBaseUrl, ending, compilerOptions);
const fromPaths = paths && tryGetModuleNameFromPaths(removeFileExtension(relativeToBaseUrl), importRelativeToBaseUrl, paths);
const nonRelative = fromPaths === undefined ? importRelativeToBaseUrl : fromPaths;
if (relativePreference === RelativePreference.NonRelative) {
return nonRelative;
}
if (preferences.importModuleSpecifierPreference === "non-relative") {
return [importRelativeToBaseUrl];
if (relativePreference !== RelativePreference.Auto) Debug.assertNever(relativePreference);
// Prefer a relative import over a baseUrl import if it has fewer components.
return isPathRelativeToParent(nonRelative) || countPathComponents(relativePath) < countPathComponents(nonRelative) ? relativePath : nonRelative;
}
function countPathComponents(path: string): number {
let count = 0;
for (let i = startsWith(path, "./") ? 2 : 0; i < path.length; i++) {
if (path.charCodeAt(i) === CharacterCodes.slash) count++;
}
if (preferences.importModuleSpecifierPreference !== undefined) Debug.assertNever(preferences.importModuleSpecifierPreference);
if (isPathRelativeToParent(relativeToBaseUrl)) {
return [relativePath];
}
/*
Prefer a relative import over a baseUrl import if it doesn't traverse up to baseUrl.
Suppose we have:
baseUrl = /base
sourceDirectory = /base/a/b
moduleFileName = /base/foo/bar
Then:
relativePath = ../../foo/bar
getRelativePathNParents(relativePath) = 2
pathFromSourceToBaseUrl = ../../
getRelativePathNParents(pathFromSourceToBaseUrl) = 2
2 < 2 = false
In this case we should prefer using the baseUrl path "/a/b" instead of the relative path "../../foo/bar".
Suppose we have:
baseUrl = /base
sourceDirectory = /base/foo/a
moduleFileName = /base/foo/bar
Then:
relativePath = ../a
getRelativePathNParents(relativePath) = 1
pathFromSourceToBaseUrl = ../../
getRelativePathNParents(pathFromSourceToBaseUrl) = 2
1 < 2 = true
In this case we should prefer using the relative path "../a" instead of the baseUrl path "foo/a".
*/
const pathFromSourceToBaseUrl = ensurePathIsNonModuleName(getRelativePathFromDirectory(sourceDirectory, baseUrl, getCanonicalFileName));
const relativeFirst = getRelativePathNParents(relativePath) < getRelativePathNParents(pathFromSourceToBaseUrl);
return relativeFirst ? [relativePath, importRelativeToBaseUrl] : [importRelativeToBaseUrl, relativePath];
return count;
}
function usesJsExtensionOnImports({ imports }: SourceFile): boolean {
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? fileExtensionIs(text, Extension.Js) : undefined) || false;
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? hasJavaScriptOrJsonFileExtension(text) : undefined) || false;
}
function stringsEqual(a: string, b: string, getCanonicalFileName: GetCanonicalFileName): boolean {
@@ -222,18 +216,11 @@ namespace ts.moduleSpecifiers {
return result;
}
function getRelativePathNParents(relativePath: string): number {
const components = getPathComponents(relativePath);
if (components[0] || components.length === 1) return 0;
for (let i = 1; i < components.length; i++) {
if (components[i] !== "..") return i - 1;
}
return components.length - 1;
}
function tryGetModuleNameFromAmbientModule(moduleSymbol: Symbol): string | undefined {
const decl = moduleSymbol.valueDeclaration;
if (isModuleDeclaration(decl) && isStringLiteral(decl.name)) {
const decl = find(moduleSymbol.declarations,
d => isNonGlobalAmbientModule(d) && (!isExternalModuleAugmentation(d) || !isExternalModuleNameRelative(getTextOfIdentifierOrLiteral(d.name)))
) as (ModuleDeclaration & { name: StringLiteral }) | undefined;
if (decl) {
return decl.name.text;
}
}
@@ -271,37 +258,8 @@ namespace ts.moduleSpecifiers {
return removeFileExtension(relativePath);
}
function tryGetModuleNameFromTypeRoots(
options: CompilerOptions,
host: GetEffectiveTypeRootsHost,
getCanonicalFileName: (file: string) => string,
moduleFileName: string,
addJsExtension: boolean,
): string | undefined {
const roots = getEffectiveTypeRoots(options, host);
return firstDefined(roots, unNormalizedTypeRoot => {
const typeRoot = toPath(unNormalizedTypeRoot, /*basePath*/ undefined, getCanonicalFileName);
if (startsWith(moduleFileName, typeRoot)) {
// For a type definition, we can strip `/index` even with classic resolution.
return removeExtensionAndIndexPostFix(moduleFileName.substring(typeRoot.length + 1), ModuleResolutionKind.NodeJs, addJsExtension);
}
});
}
function tryGetModuleNameAsNodeModule(
options: CompilerOptions,
moduleFileName: string,
host: ModuleSpecifierResolutionHost,
getCanonicalFileName: (file: string) => string,
sourceDirectory: Path,
): string | undefined {
if (getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs) {
// nothing to do here
return undefined;
}
function tryGetModuleNameAsNodeModule(moduleFileName: string, { getCanonicalFileName, sourceDirectory }: Info, host: ModuleSpecifierResolutionHost, options: CompilerOptions): string | undefined {
const parts: NodeModulePathParts = getNodeModulePathParts(moduleFileName)!;
if (!parts) {
return undefined;
}
@@ -313,8 +271,12 @@ namespace ts.moduleSpecifiers {
// Get a path that's relative to node_modules or the importing file's path
// if node_modules folder is in this folder or any of its parent folders, no need to keep it.
if (!startsWith(sourceDirectory, getCanonicalFileName(moduleSpecifier.substring(0, parts.topLevelNodeModulesIndex)))) return undefined;
// If the module was found in @types, get the actual Node package name
return getPackageNameFromAtTypesDirectory(moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1));
const nodeModulesDirectoryName = moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1);
const packageName = getPackageNameFromAtTypesDirectory(nodeModulesDirectoryName);
// For classic resolution, only allow importing from node_modules/@types, not other node_modules
return getEmitModuleResolutionKind(options) !== ModuleResolutionKind.NodeJs && packageName === nodeModulesDirectoryName ? undefined : packageName;
function getDirectoryOrExtensionlessFileName(path: string): string {
// If the file is the main module, it can be imported by the package name
@@ -389,7 +351,7 @@ namespace ts.moduleSpecifiers {
partEnd = fullPath.indexOf("/", partStart + 1);
switch (state) {
case States.BeforeNodeModules:
if (fullPath.indexOf("/node_modules/", partStart) === partStart) {
if (fullPath.indexOf(nodeModulesPathPart, partStart) === partStart) {
topLevelNodeModulesIndex = partStart;
topLevelPackageNameIndex = partEnd;
state = States.NodeModules;
@@ -406,7 +368,7 @@ namespace ts.moduleSpecifiers {
}
break;
case States.PackageContent:
if (fullPath.indexOf("/node_modules/", partStart) === partStart) {
if (fullPath.indexOf(nodeModulesPathPart, partStart) === partStart) {
state = States.NodeModules;
}
else {
@@ -428,13 +390,36 @@ namespace ts.moduleSpecifiers {
});
}
function removeExtensionAndIndexPostFix(fileName: string, moduleResolutionKind: ModuleResolutionKind, addJsExtension: boolean): string {
function removeExtensionAndIndexPostFix(fileName: string, ending: Ending, options: CompilerOptions): string {
if (fileExtensionIs(fileName, Extension.Json)) return fileName;
const noExtension = removeFileExtension(fileName);
return addJsExtension
? noExtension + ".js"
: moduleResolutionKind === ModuleResolutionKind.NodeJs
? removeSuffix(noExtension, "/index")
: noExtension;
switch (ending) {
case Ending.Minimal:
return removeSuffix(noExtension, "/index");
case Ending.Index:
return noExtension;
case Ending.JsExtension:
return noExtension + getJavaScriptExtensionForFile(fileName, options);
default:
return Debug.assertNever(ending);
}
}
function getJavaScriptExtensionForFile(fileName: string, options: CompilerOptions): Extension {
const ext = extensionFromPath(fileName);
switch (ext) {
case Extension.Ts:
case Extension.Dts:
return Extension.Js;
case Extension.Tsx:
return options.jsx === JsxEmit.Preserve ? Extension.Jsx : Extension.Js;
case Extension.Js:
case Extension.Jsx:
case Extension.Json:
return ext;
default:
return Debug.assertNever(ext);
}
}
function getRelativePathIfInDirectory(path: string, directoryPath: string, getCanonicalFileName: GetCanonicalFileName): string | undefined {
+39 -14
View File
@@ -86,6 +86,7 @@ namespace ts {
visitNodes(cbNode, cbNodes, node.modifiers) ||
visitNode(cbNode, (<ShorthandPropertyAssignment>node).name) ||
visitNode(cbNode, (<ShorthandPropertyAssignment>node).questionToken) ||
visitNode(cbNode, (<ShorthandPropertyAssignment>node).exclamationToken) ||
visitNode(cbNode, (<ShorthandPropertyAssignment>node).equalsToken) ||
visitNode(cbNode, (<ShorthandPropertyAssignment>node).objectAssignmentInitializer);
case SyntaxKind.SpreadAssignment:
@@ -156,6 +157,7 @@ namespace ts {
visitNode(cbNode, (<FunctionLikeDeclaration>node).asteriskToken) ||
visitNode(cbNode, (<FunctionLikeDeclaration>node).name) ||
visitNode(cbNode, (<FunctionLikeDeclaration>node).questionToken) ||
visitNode(cbNode, (<FunctionLikeDeclaration>node).exclamationToken) ||
visitNodes(cbNode, cbNodes, (<FunctionLikeDeclaration>node).typeParameters) ||
visitNodes(cbNode, cbNodes, (<FunctionLikeDeclaration>node).parameters) ||
visitNode(cbNode, (<FunctionLikeDeclaration>node).type) ||
@@ -475,7 +477,7 @@ namespace ts {
case SyntaxKind.JSDocAugmentsTag:
return visitNode(cbNode, (<JSDocAugmentsTag>node).class);
case SyntaxKind.JSDocTemplateTag:
return visitNodes(cbNode, cbNodes, (<JSDocTemplateTag>node).typeParameters);
return visitNode(cbNode, (<JSDocTemplateTag>node).constraint) || visitNodes(cbNode, cbNodes, (<JSDocTemplateTag>node).typeParameters);
case SyntaxKind.JSDocTypedefTag:
if ((node as JSDocTypedefTag).typeExpression &&
(node as JSDocTypedefTag).typeExpression!.kind === SyntaxKind.JSDocTypeExpression) {
@@ -515,7 +517,7 @@ namespace ts {
performance.mark("beforeParse");
let result: SourceFile;
if (languageVersion === ScriptTarget.JSON) {
result = Parser.parseJsonText(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes);
result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, ScriptKind.JSON);
}
else {
result = Parser.parseSourceFile(fileName, sourceText, languageVersion, /*syntaxCursor*/ undefined, setParentNodes, scriptKind);
@@ -689,8 +691,12 @@ namespace ts {
if (scriptKind === ScriptKind.JSON) {
const result = parseJsonText(fileName, sourceText, languageVersion, syntaxCursor, setParentNodes);
convertToObjectWorker(result, result.parseDiagnostics, /*returnValue*/ false, /*knownRootOptions*/ undefined, /*jsonConversionNotifier*/ undefined);
result.referencedFiles = emptyArray;
result.typeReferenceDirectives = emptyArray;
result.libReferenceDirectives = emptyArray;
result.amdDependencies = emptyArray;
result.hasNoDefaultLib = false;
result.pragmas = emptyMap;
return result;
}
@@ -2373,8 +2379,10 @@ namespace ts {
}
function parseJSDocType(): TypeNode {
scanner.setInJSDocType(true);
const dotdotdot = parseOptionalToken(SyntaxKind.DotDotDotToken);
let type = parseType();
let type = parseTypeOrTypePredicate();
scanner.setInJSDocType(false);
if (dotdotdot) {
const variadic = createNode(SyntaxKind.JSDocVariadicType, dotdotdot.pos) as JSDocVariadicType;
variadic.type = type;
@@ -4465,7 +4473,7 @@ namespace ts {
}
else {
const argument = allowInAnd(parseExpression);
if (isStringOrNumericLiteral(argument)) {
if (isStringOrNumericLiteralLike(argument)) {
argument.text = internIdentifier(argument.text);
}
indexedAccess.argumentExpression = argument;
@@ -4707,8 +4715,10 @@ namespace ts {
const asteriskToken = parseOptionalToken(SyntaxKind.AsteriskToken);
const tokenIsIdentifier = isIdentifier();
node.name = parsePropertyName();
// Disallowing of optional property assignments happens in the grammar checker.
// Disallowing of optional property assignments and definite assignment assertion happens in the grammar checker.
(<MethodDeclaration>node).questionToken = parseOptionalToken(SyntaxKind.QuestionToken);
(<MethodDeclaration>node).exclamationToken = parseOptionalToken(SyntaxKind.ExclamationToken);
if (asteriskToken || token() === SyntaxKind.OpenParenToken || token() === SyntaxKind.LessThanToken) {
return parseMethodDeclaration(<MethodDeclaration>node, asteriskToken);
}
@@ -6507,6 +6517,25 @@ namespace ts {
}
}
function skipWhitespaceOrAsterisk(): void {
if (token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
if (lookAhead(isNextNonwhitespaceTokenEndOfFile)) {
return; // Don't skip whitespace prior to EoF (or end of comment) - that shouldn't be included in any node's range
}
}
let precedingLineBreak = scanner.hasPrecedingLineBreak();
while ((precedingLineBreak && token() === SyntaxKind.AsteriskToken) || token() === SyntaxKind.WhitespaceTrivia || token() === SyntaxKind.NewLineTrivia) {
if (token() === SyntaxKind.NewLineTrivia) {
precedingLineBreak = true;
}
else if (token() === SyntaxKind.AsteriskToken) {
precedingLineBreak = false;
}
nextJSDocToken();
}
}
function parseTag(indent: number) {
Debug.assert(token() === SyntaxKind.AtToken);
const atToken = <AtToken>createNode(SyntaxKind.AtToken, scanner.getTokenPos());
@@ -6514,7 +6543,7 @@ namespace ts {
nextJSDocToken();
const tagName = parseJSDocIdentifierName();
skipWhitespace();
skipWhitespaceOrAsterisk();
let tag: JSDocTag | undefined;
switch (tagName.escapedText) {
@@ -6658,7 +6687,7 @@ namespace ts {
}
function tryParseTypeExpression(): JSDocTypeExpression | undefined {
skipWhitespace();
skipWhitespaceOrAsterisk();
return token() === SyntaxKind.OpenBraceToken ? parseJSDocTypeExpression() : undefined;
}
@@ -6698,7 +6727,7 @@ namespace ts {
function parseParameterOrPropertyTag(atToken: AtToken, tagName: Identifier, target: PropertyLikeParse, indent: number | undefined): JSDocParameterTag | JSDocPropertyTag {
let typeExpression = tryParseTypeExpression();
let isNameFirst = !typeExpression;
skipWhitespace();
skipWhitespaceOrAsterisk();
const { name, isBracketed } = parseBracketNameInPropertyAndParamTag();
skipWhitespace();
@@ -6833,7 +6862,7 @@ namespace ts {
function parseTypedefTag(atToken: AtToken, tagName: Identifier, indent: number): JSDocTypedefTag {
const typeExpression = tryParseTypeExpression();
skipWhitespace();
skipWhitespaceOrAsterisk();
const typedefTag = <JSDocTypedefTag>createNode(SyntaxKind.JSDocTypedefTag, atToken.pos);
typedefTag.atToken = atToken;
@@ -7049,13 +7078,10 @@ namespace ts {
typeParameters.push(typeParameter);
} while (parseOptionalJsdoc(SyntaxKind.CommaToken));
if (constraint) {
first(typeParameters).constraint = constraint.type;
}
const result = <JSDocTemplateTag>createNode(SyntaxKind.JSDocTemplateTag, atToken.pos);
result.atToken = atToken;
result.tagName = tagName;
result.constraint = constraint;
result.typeParameters = createNodeArray(typeParameters, typeParametersPos);
finishNode(result);
return result;
@@ -7738,7 +7764,6 @@ namespace ts {
}
}
/*@internal*/
type PragmaDiagnosticReporter = (pos: number, length: number, message: DiagnosticMessage) => void;
/*@internal*/
+58 -63
View File
@@ -67,19 +67,24 @@ namespace ts {
}
export function createCompilerHost(options: CompilerOptions, setParentNodes?: boolean): CompilerHost {
return createCompilerHostWorker(options, setParentNodes);
}
/*@internal*/
// TODO(shkamat): update this after reworking ts build API
export function createCompilerHostWorker(options: CompilerOptions, setParentNodes?: boolean, system = sys): CompilerHost {
const existingDirectories = createMap<boolean>();
function getCanonicalFileName(fileName: string): string {
// if underlying system can distinguish between two files whose names differs only in cases then file name already in canonical form.
// otherwise use toLowerCase as a canonical form.
return sys.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
return system.useCaseSensitiveFileNames ? fileName : fileName.toLowerCase();
}
function getSourceFile(fileName: string, languageVersion: ScriptTarget, onError?: (message: string) => void): SourceFile | undefined {
let text: string | undefined;
try {
performance.mark("beforeIORead");
text = sys.readFile(fileName, options.charset);
text = system.readFile(fileName, options.charset);
performance.mark("afterIORead");
performance.measure("I/O Read", "beforeIORead", "afterIORead");
}
@@ -97,7 +102,7 @@ namespace ts {
if (existingDirectories.has(directoryPath)) {
return true;
}
if (sys.directoryExists(directoryPath)) {
if (system.directoryExists(directoryPath)) {
existingDirectories.set(directoryPath, true);
return true;
}
@@ -108,7 +113,7 @@ namespace ts {
if (directoryPath.length > getRootLength(directoryPath) && !directoryExists(directoryPath)) {
const parentDirectory = getDirectoryPath(directoryPath);
ensureDirectoriesExist(parentDirectory);
sys.createDirectory(directoryPath);
system.createDirectory(directoryPath);
}
}
@@ -119,8 +124,8 @@ namespace ts {
outputFingerprints = createMap<OutputFingerprint>();
}
const hash = sys.createHash!(data); // TODO: GH#18217
const mtimeBefore = sys.getModifiedTime!(fileName); // TODO: GH#18217
const hash = system.createHash!(data); // TODO: GH#18217
const mtimeBefore = system.getModifiedTime!(fileName); // TODO: GH#18217
if (mtimeBefore) {
const fingerprint = outputFingerprints.get(fileName);
@@ -133,9 +138,9 @@ namespace ts {
}
}
sys.writeFile(fileName, data, writeByteOrderMark);
system.writeFile(fileName, data, writeByteOrderMark);
const mtimeAfter = sys.getModifiedTime!(fileName) || missingFileModifiedTime; // TODO: GH#18217
const mtimeAfter = system.getModifiedTime!(fileName) || missingFileModifiedTime; // TODO: GH#18217
outputFingerprints.set(fileName, {
hash,
@@ -149,11 +154,11 @@ namespace ts {
performance.mark("beforeIOWrite");
ensureDirectoriesExist(getDirectoryPath(normalizePath(fileName)));
if (isWatchSet(options) && sys.createHash && sys.getModifiedTime) {
if (isWatchSet(options) && system.createHash && system.getModifiedTime) {
writeFileIfUpdated(fileName, data, writeByteOrderMark);
}
else {
sys.writeFile(fileName, data, writeByteOrderMark);
system.writeFile(fileName, data, writeByteOrderMark);
}
performance.mark("afterIOWrite");
@@ -167,32 +172,29 @@ namespace ts {
}
function getDefaultLibLocation(): string {
return getDirectoryPath(normalizePath(sys.getExecutingFilePath()));
return getDirectoryPath(normalizePath(system.getExecutingFilePath()));
}
const newLine = getNewLineCharacter(options);
const realpath = sys.realpath && ((path: string) => sys.realpath!(path));
const newLine = getNewLineCharacter(options, () => system.newLine);
const realpath = system.realpath && ((path: string) => system.realpath!(path));
return {
getSourceFile,
getDefaultLibLocation,
getDefaultLibFileName: options => combinePaths(getDefaultLibLocation(), getDefaultLibFileName(options)),
writeFile,
getCurrentDirectory: memoize(() => sys.getCurrentDirectory()),
useCaseSensitiveFileNames: () => sys.useCaseSensitiveFileNames,
getCurrentDirectory: memoize(() => system.getCurrentDirectory()),
useCaseSensitiveFileNames: () => system.useCaseSensitiveFileNames,
getCanonicalFileName,
getNewLine: () => newLine,
fileExists: fileName => sys.fileExists(fileName),
readFile: fileName => sys.readFile(fileName),
trace: (s: string) => sys.write(s + newLine),
directoryExists: directoryName => sys.directoryExists(directoryName),
getEnvironmentVariable: name => sys.getEnvironmentVariable ? sys.getEnvironmentVariable(name) : "",
getDirectories: (path: string) => sys.getDirectories(path),
fileExists: fileName => system.fileExists(fileName),
readFile: fileName => system.readFile(fileName),
trace: (s: string) => system.write(s + newLine),
directoryExists: directoryName => system.directoryExists(directoryName),
getEnvironmentVariable: name => system.getEnvironmentVariable ? system.getEnvironmentVariable(name) : "",
getDirectories: (path: string) => system.getDirectories(path),
realpath,
readDirectory: (path, extensions, include, exclude, depth) => sys.readDirectory(path, extensions, include, exclude, depth),
getModifiedTime: sys.getModifiedTime && (path => sys.getModifiedTime!(path)),
setModifiedTime: sys.setModifiedTime && ((path, date) => sys.setModifiedTime!(path, date)),
deleteFile: sys.deleteFile && (path => sys.deleteFile!(path))
readDirectory: (path, extensions, include, exclude, depth) => system.readDirectory(path, extensions, include, exclude, depth)
};
}
@@ -951,8 +953,11 @@ namespace ts {
// If we change our policy of rechecking failed lookups on each program create,
// we should adjust the value returned here.
function moduleNameResolvesToAmbientModuleInNonModifiedFile(moduleName: string, oldProgramState: OldProgramState): boolean {
if (!oldProgramState.program) {
return false;
}
const resolutionToFile = getResolvedModule(oldProgramState.oldSourceFile!, moduleName); // TODO: GH#18217
const resolvedFile = resolutionToFile && oldProgramState.program && oldProgramState.program.getSourceFile(resolutionToFile.resolvedFileName);
const resolvedFile = resolutionToFile && oldProgramState.program.getSourceFile(resolutionToFile.resolvedFileName);
if (resolutionToFile && resolvedFile && !resolvedFile.externalModuleIndicator) {
// In the old program, we resolved to an ambient module that was in the same
// place as we expected to find an actual module file.
@@ -960,16 +965,11 @@ namespace ts {
// because the normal module resolution algorithm will find this anyway.
return false;
}
const ambientModule = oldProgramState.program && oldProgramState.program.getTypeChecker().tryFindAmbientModuleWithoutAugmentations(moduleName);
if (!(ambientModule && ambientModule.declarations)) {
return false;
}
// at least one of declarations should come from non-modified source file
const firstUnmodifiedFile = forEach(ambientModule.declarations, d => {
const f = getSourceFileOfNode(d);
return !contains(oldProgramState.modifiedFilePaths, f.path) && f;
});
const firstUnmodifiedFile = oldProgramState.program.getSourceFiles().find(
f => !contains(oldProgramState.modifiedFilePaths, f.path) && contains(f.ambientModuleNames, moduleName)
);
if (!firstUnmodifiedFile) {
return false;
@@ -1237,6 +1237,7 @@ namespace ts {
getSourceFile: program.getSourceFile,
getSourceFileByPath: program.getSourceFileByPath,
getSourceFiles: program.getSourceFiles,
getLibFileFromReference: program.getLibFileFromReference,
isSourceFileFromExternalLibrary,
writeFile: writeFileCallback || (
(fileName, data, writeByteOrderMark, onError, sourceFiles) => host.writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles)),
@@ -1256,8 +1257,6 @@ namespace ts {
}
function getProjectReferences() {
if (!resolvedProjectReferences) return;
return resolvedProjectReferences;
}
@@ -1476,10 +1475,7 @@ namespace ts {
function getSemanticDiagnosticsForFileNoCache(sourceFile: SourceFile, cancellationToken: CancellationToken): Diagnostic[] | undefined {
return runWithCancellationToken(() => {
// If skipLibCheck is enabled, skip reporting errors if file is a declaration file.
// If skipDefaultLibCheck is enabled, skip reporting errors if file contains a
// '/// <reference no-default-lib="true"/>' directive.
if (options.skipLibCheck && sourceFile.isDeclarationFile || options.skipDefaultLibCheck && sourceFile.hasNoDefaultLib) {
if (skipTypeChecking(sourceFile, options)) {
return emptyArray;
}
@@ -2321,27 +2317,20 @@ namespace ts {
}
function computeCommonSourceDirectory(sourceFiles: SourceFile[]): string {
const fileNames: string[] = [];
for (const file of sourceFiles) {
if (!file.isDeclarationFile) {
fileNames.push(file.fileName);
}
}
const fileNames = mapDefined(sourceFiles, file => file.isDeclarationFile ? undefined : file.fileName);
return computeCommonSourceDirectoryOfFilenames(fileNames, currentDirectory, getCanonicalFileName);
}
function checkSourceFilesBelongToPath(sourceFiles: SourceFile[], rootDirectory: string): boolean {
function checkSourceFilesBelongToPath(sourceFiles: ReadonlyArray<SourceFile>, rootDirectory: string): boolean {
let allFilesBelongToPath = true;
if (sourceFiles) {
const absoluteRootDirectoryPath = host.getCanonicalFileName(getNormalizedAbsolutePath(rootDirectory, currentDirectory));
const absoluteRootDirectoryPath = host.getCanonicalFileName(getNormalizedAbsolutePath(rootDirectory, currentDirectory));
for (const sourceFile of sourceFiles) {
if (!sourceFile.isDeclarationFile) {
const absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory));
if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, sourceFile.fileName, rootDirectory));
allFilesBelongToPath = false;
}
for (const sourceFile of sourceFiles) {
if (!sourceFile.isDeclarationFile) {
const absoluteSourceFilePath = host.getCanonicalFileName(getNormalizedAbsolutePath(sourceFile.fileName, currentDirectory));
if (absoluteSourceFilePath.indexOf(absoluteRootDirectoryPath) !== 0) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_under_rootDir_1_rootDir_is_expected_to_contain_all_source_files, sourceFile.fileName, rootDirectory));
allFilesBelongToPath = false;
}
}
}
@@ -2441,12 +2430,14 @@ namespace ts {
}
// List of collected files is complete; validate exhautiveness if this is a project with a file list
if (options.composite && rootNames.length < files.length) {
const normalizedRootNames = rootNames.map(r => normalizePath(r).toLowerCase());
const sourceFiles = files.filter(f => !f.isDeclarationFile).map(f => normalizePath(f.path).toLowerCase());
for (const file of sourceFiles) {
if (normalizedRootNames.every(r => r !== file)) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_in_project_file_list_Projects_must_list_all_files_or_use_an_include_pattern, file));
if (options.composite) {
const sourceFiles = files.filter(f => !f.isDeclarationFile);
if (rootNames.length < sourceFiles.length) {
const normalizedRootNames = rootNames.map(r => normalizePath(r).toLowerCase());
for (const file of sourceFiles.map(f => normalizePath(f.path).toLowerCase())) {
if (normalizedRootNames.indexOf(file) === -1) {
programDiagnostics.add(createCompilerDiagnostic(Diagnostics.File_0_is_not_in_project_file_list_Projects_must_list_all_files_or_use_an_include_pattern, file));
}
}
}
}
@@ -2852,7 +2843,6 @@ namespace ts {
switch (extension) {
case Extension.Ts:
case Extension.Dts:
case Extension.Json: // Since module is resolved to json file only when --resolveJsonModule, we dont need further check
// These are always allowed.
return undefined;
case Extension.Tsx:
@@ -2861,6 +2851,8 @@ namespace ts {
return needJsx() || needAllowJs();
case Extension.Js:
return needAllowJs();
case Extension.Json:
return needResolveJsonModule();
}
function needJsx() {
@@ -2869,6 +2861,9 @@ namespace ts {
function needAllowJs() {
return options.allowJs || !getStrictOptionValue(options, "noImplicitAny") ? undefined : Diagnostics.Could_not_find_a_declaration_file_for_module_0_1_implicitly_has_an_any_type;
}
function needResolveJsonModule() {
return options.resolveJsonModule ? undefined : Diagnostics.Module_0_was_resolved_to_1_but_resolveJsonModule_is_not_used;
}
}
function getModuleNames({ imports, moduleAugmentations }: SourceFile): string[] {
+1 -1
View File
@@ -419,7 +419,7 @@ namespace ts {
function getDirectoryToWatchFromFailedLookupLocationDirectory(dir: string, dirPath: Path) {
// If directory path contains node module, get the most parent node_modules directory for watching
while (stringContains(dirPath, "/node_modules/")) {
while (stringContains(dirPath, nodeModulesPathPart)) {
dir = getDirectoryPath(dir);
dirPath = getDirectoryPath(dirPath);
}
+35
View File
@@ -42,6 +42,8 @@ namespace ts {
setScriptTarget(scriptTarget: ScriptTarget): void;
setLanguageVariant(variant: LanguageVariant): void;
setTextPos(textPos: number): void;
/* @internal */
setInJSDocType(inType: boolean): void;
// Invokes the provided callback then unconditionally restores the scanner to the state it
// was in immediately prior to invoking the callback. The result of invoking the callback
// is returned from this function.
@@ -824,6 +826,8 @@ namespace ts {
let tokenValue!: string;
let tokenFlags: TokenFlags;
let inJSDocType = 0;
setText(text, start, length);
return {
@@ -854,6 +858,7 @@ namespace ts {
setLanguageVariant,
setOnError,
setTextPos,
setInJSDocType,
tryScan,
lookAhead,
scanRange,
@@ -1350,6 +1355,7 @@ namespace ts {
function scan(): SyntaxKind {
startPos = pos;
tokenFlags = 0;
let asteriskSeen = false;
while (true) {
tokenPos = pos;
if (pos >= end) {
@@ -1390,6 +1396,24 @@ namespace ts {
case CharacterCodes.verticalTab:
case CharacterCodes.formFeed:
case CharacterCodes.space:
case CharacterCodes.nonBreakingSpace:
case CharacterCodes.ogham:
case CharacterCodes.enQuad:
case CharacterCodes.emQuad:
case CharacterCodes.enSpace:
case CharacterCodes.emSpace:
case CharacterCodes.threePerEmSpace:
case CharacterCodes.fourPerEmSpace:
case CharacterCodes.sixPerEmSpace:
case CharacterCodes.figureSpace:
case CharacterCodes.punctuationSpace:
case CharacterCodes.thinSpace:
case CharacterCodes.hairSpace:
case CharacterCodes.zeroWidthSpace:
case CharacterCodes.narrowNoBreakSpace:
case CharacterCodes.mathematicalSpace:
case CharacterCodes.ideographicSpace:
case CharacterCodes.byteOrderMark:
if (skipTrivia) {
pos++;
continue;
@@ -1447,6 +1471,11 @@ namespace ts {
return pos += 2, token = SyntaxKind.AsteriskAsteriskToken;
}
pos++;
if (inJSDocType && !asteriskSeen && (tokenFlags & TokenFlags.PrecedingLineBreak)) {
// decoration at the start of a JSDoc comment line
asteriskSeen = true;
continue;
}
return token = SyntaxKind.AsteriskToken;
case CharacterCodes.plus:
if (text.charCodeAt(pos + 1) === CharacterCodes.plus) {
@@ -1933,6 +1962,7 @@ namespace ts {
function scanJSDocToken(): JsDocSyntaxKind {
startPos = tokenPos = pos;
tokenFlags = 0;
if (pos >= end) {
return token = SyntaxKind.EndOfFileToken;
}
@@ -1952,6 +1982,7 @@ namespace ts {
return token = SyntaxKind.AtToken;
case CharacterCodes.lineFeed:
case CharacterCodes.carriageReturn:
tokenFlags |= TokenFlags.PrecedingLineBreak;
return token = SyntaxKind.NewLineTrivia;
case CharacterCodes.asterisk:
return token = SyntaxKind.AsteriskToken;
@@ -2076,5 +2107,9 @@ namespace ts {
tokenValue = undefined!;
tokenFlags = 0;
}
function setInJSDocType(inType: boolean) {
inJSDocType += inType ? 1 : -1;
}
}
}
+1 -2
View File
@@ -756,8 +756,7 @@ namespace ts {
if (recursive) {
return watchDirectoryRecursively(directoryName, callback);
}
watchDirectory(directoryName, callback);
return undefined!; // TODO: GH#18217
return watchDirectory(directoryName, callback);
};
}
+44 -9
View File
@@ -33,7 +33,7 @@ namespace ts {
let needsScopeFixMarker = false;
let resultHasScopeMarker = false;
let enclosingDeclaration: Node;
let necessaryTypeRefernces: Map<true> | undefined;
let necessaryTypeReferences: Map<true> | undefined;
let lateMarkedStatements: LateVisibilityPaintedStatement[] | undefined;
let lateStatementReplacementMap: Map<VisitResult<LateVisibilityPaintedStatement>>;
let suppressNewDiagnosticContexts: boolean;
@@ -53,6 +53,7 @@ namespace ts {
let currentSourceFile: SourceFile;
let refs: Map<SourceFile>;
let libs: Map<boolean>;
const resolver = context.getEmitResolver();
const options = context.getCompilerOptions();
const newLine = getNewLineCharacter(options);
@@ -63,9 +64,9 @@ namespace ts {
if (!typeReferenceDirectives) {
return;
}
necessaryTypeRefernces = necessaryTypeRefernces || createMap<true>();
necessaryTypeReferences = necessaryTypeReferences || createMap<true>();
for (const ref of typeReferenceDirectives) {
necessaryTypeRefernces.set(ref, true);
necessaryTypeReferences.set(ref, true);
}
}
@@ -163,6 +164,7 @@ namespace ts {
if (node.kind === SyntaxKind.Bundle) {
isBundledEmit = true;
refs = createMap<SourceFile>();
libs = createMap<boolean>();
let hasNoDefaultLib = false;
const bundle = createBundle(map(node.sourceFiles,
sourceFile => {
@@ -177,6 +179,7 @@ namespace ts {
needsScopeFixMarker = false;
resultHasScopeMarker = false;
collectReferences(sourceFile, refs);
collectLibs(sourceFile, libs);
if (isExternalModule(sourceFile)) {
resultHasExternalModuleIndicator = false; // unused in external module bundle emit (all external modules are within module blocks, therefore are known to be modules)
needsDeclare = false;
@@ -200,6 +203,7 @@ namespace ts {
}));
bundle.syntheticFileReferences = [];
bundle.syntheticTypeReferences = getFileReferencesForUsedTypeReferences();
bundle.syntheticLibReferences = getLibReferences();
bundle.hasNoDefaultLib = hasNoDefaultLib;
const outputFilePath = getDirectoryPath(normalizeSlashes(getOutputPathsFor(node, host, /*forceDtsPaths*/ true).declarationFilePath!));
const referenceVisitor = mapReferencesIntoArray(bundle.syntheticFileReferences as FileReference[], outputFilePath);
@@ -219,8 +223,9 @@ namespace ts {
suppressNewDiagnosticContexts = false;
lateMarkedStatements = undefined;
lateStatementReplacementMap = createMap();
necessaryTypeRefernces = undefined;
necessaryTypeReferences = undefined;
refs = collectReferences(currentSourceFile, createMap());
libs = collectLibs(currentSourceFile, createMap());
const references: FileReference[] = [];
const outputFilePath = getDirectoryPath(normalizeSlashes(getOutputPathsFor(node, host, /*forceDtsPaths*/ true).declarationFilePath!));
const referenceVisitor = mapReferencesIntoArray(references, outputFilePath);
@@ -231,12 +236,16 @@ namespace ts {
if (isExternalModule(node) && (!resultHasExternalModuleIndicator || (needsScopeFixMarker && !resultHasScopeMarker))) {
combinedStatements = setTextRange(createNodeArray([...combinedStatements, createExportDeclaration(/*decorators*/ undefined, /*modifiers*/ undefined, createNamedExports([]), /*moduleSpecifier*/ undefined)]), combinedStatements);
}
const updated = updateSourceFileNode(node, combinedStatements, /*isDeclarationFile*/ true, references, getFileReferencesForUsedTypeReferences(), node.hasNoDefaultLib);
const updated = updateSourceFileNode(node, combinedStatements, /*isDeclarationFile*/ true, references, getFileReferencesForUsedTypeReferences(), node.hasNoDefaultLib, getLibReferences());
updated.exportedModulesFromDeclarationEmit = exportedModulesFromDeclarationEmit;
return updated;
function getLibReferences() {
return map(arrayFrom(libs.keys()), lib => ({ fileName: lib, pos: -1, end: -1 }));
}
function getFileReferencesForUsedTypeReferences() {
return necessaryTypeRefernces ? mapDefined(arrayFrom(necessaryTypeRefernces.keys()), getFileReferenceForTypeName) : [];
return necessaryTypeReferences ? mapDefined(arrayFrom(necessaryTypeReferences.keys()), getFileReferenceForTypeName) : [];
}
function getFileReferenceForTypeName(typeName: string): FileReference | undefined {
@@ -297,6 +306,16 @@ namespace ts {
return ret;
}
function collectLibs(sourceFile: SourceFile, ret: Map<boolean>) {
forEach(sourceFile.libReferenceDirectives, ref => {
const lib = host.getLibFileFromReference(ref);
if (lib) {
ret.set(ref.fileName.toLocaleLowerCase(), true);
}
});
return ret;
}
function filterBindingPatternInitializers(name: BindingName) {
if (name.kind === SyntaxKind.Identifier) {
return name;
@@ -952,7 +971,7 @@ namespace ts {
}
case SyntaxKind.FunctionDeclaration: {
// Generators lose their generator-ness, excepting their return type
return cleanup(updateFunctionDeclaration(
const clean = cleanup(updateFunctionDeclaration(
input,
/*decorators*/ undefined,
ensureModifiers(input, isPrivate),
@@ -963,6 +982,21 @@ namespace ts {
ensureType(input, input.type),
/*body*/ undefined
));
if (clean && resolver.isJSContainerFunctionDeclaration(input)) {
const declarations = mapDefined(resolver.getPropertiesOfContainerFunction(input), p => {
if (!isPropertyAccessExpression(p.valueDeclaration)) {
return undefined;
}
const type = resolver.createTypeOfDeclaration(p.valueDeclaration, enclosingDeclaration, declarationEmitNodeBuilderFlags, symbolTracker);
const varDecl = createVariableDeclaration(unescapeLeadingUnderscores(p.escapedName), type, /*initializer*/ undefined);
return createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList([varDecl]));
});
const namespaceDecl = createModuleDeclaration(/*decorators*/ undefined, ensureModifiers(input, isPrivate), input.name!, createModuleBlock(declarations), NodeFlags.Namespace);
return [clean, namespaceDecl];
}
else {
return clean;
}
}
case SyntaxKind.ModuleDeclaration: {
needsDeclare = false;
@@ -1290,12 +1324,13 @@ namespace ts {
}
type CanHaveLiteralInitializer = VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration;
function canHaveLiteralInitializer(node: Node): node is CanHaveLiteralInitializer {
function canHaveLiteralInitializer(node: Node): boolean {
switch (node.kind) {
case SyntaxKind.VariableDeclaration:
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
return !hasModifier(node, ModifierFlags.Private);
case SyntaxKind.Parameter:
case SyntaxKind.VariableDeclaration:
return true;
}
return false;
+1 -1
View File
@@ -447,7 +447,7 @@ namespace ts {
const argumentExpression = ensureIdentifier(flattenContext, visitNode(propertyName.expression, flattenContext.visitor), /*reuseIdentifierExpressions*/ false, /*location*/ propertyName);
return createElementAccess(value, argumentExpression);
}
else if (isStringOrNumericLiteral(propertyName)) {
else if (isStringOrNumericLiteralLike(propertyName)) {
const argumentExpression = getSynthesizedClone(propertyName);
argumentExpression.text = argumentExpression.text;
return createElementAccess(value, argumentExpression);
+14 -6
View File
@@ -2060,14 +2060,11 @@ namespace ts {
setTextRange(declarationList, node);
setCommentRange(declarationList, node);
// If the first or last declaration is a binding pattern, we need to modify
// the source map range for the declaration list.
if (node.transformFlags & TransformFlags.ContainsBindingPattern
&& (isBindingPattern(node.declarations[0].name) || isBindingPattern(last(node.declarations).name))) {
// If the first or last declaration is a binding pattern, we need to modify
// the source map range for the declaration list.
const firstDeclaration = firstOrUndefined(declarations);
if (firstDeclaration) {
setSourceMapRange(declarationList, createRange(firstDeclaration.pos, last(declarations).end));
}
setSourceMapRange(declarationList, getRangeUnion(declarations));
}
return declarationList;
@@ -2075,6 +2072,17 @@ namespace ts {
return visitEachChild(node, visitor, context);
}
function getRangeUnion(declarations: ReadonlyArray<Node>): TextRange {
// declarations may not be sorted by position.
// pos should be the minimum* position over all nodes (that's not -1), end should be the maximum end over all nodes.
let pos = -1, end = -1;
for (const node of declarations) {
pos = pos === -1 ? node.pos : node.pos === -1 ? pos : Math.min(pos, node.pos);
end = Math.max(end, node.end);
}
return createRange(pos, end);
}
/**
* Gets a value indicating whether we should emit an explicit initializer for a variable
* declaration in a `let` declaration list.
+415 -407
View File
File diff suppressed because it is too large Load Diff
+48 -25
View File
@@ -759,6 +759,7 @@ namespace ts {
kind: SyntaxKind.TypeParameter;
parent: DeclarationWithTypeParameterChildren | InferTypeNode;
name: Identifier;
/** Note: Consider calling `getEffectiveConstraintOfTypeParameter` */
constraint?: TypeNode;
default?: TypeNode;
@@ -882,6 +883,7 @@ namespace ts {
kind: SyntaxKind.ShorthandPropertyAssignment;
name: Identifier;
questionToken?: QuestionToken;
exclamationToken?: ExclamationToken;
// used when ObjectLiteralExpression is used in ObjectAssignmentPattern
// it is grammar error to appear in actual object initializer
equalsToken?: Token<SyntaxKind.EqualsToken>;
@@ -940,6 +942,7 @@ namespace ts {
asteriskToken?: AsteriskToken;
questionToken?: QuestionToken;
exclamationToken?: ExclamationToken;
body?: Block | Expression;
}
@@ -1081,7 +1084,7 @@ namespace ts {
export interface TypePredicateNode extends TypeNode {
kind: SyntaxKind.TypePredicate;
parent: SignatureDeclaration;
parent: SignatureDeclaration | JSDocTypeExpression;
parameterName: Identifier | ThisTypeNode;
type: TypeNode;
}
@@ -2363,6 +2366,7 @@ namespace ts {
export interface JSDocTemplateTag extends JSDocTag {
kind: SyntaxKind.JSDocTemplateTag;
constraint: TypeNode | undefined;
typeParameters: NodeArray<TypeParameterDeclaration>;
}
@@ -2630,7 +2634,7 @@ namespace ts {
/* @internal */ ambientModuleNames: ReadonlyArray<string>;
/* @internal */ checkJsDirective?: CheckJsDirective;
/* @internal */ version: string;
/* @internal */ pragmas: PragmaMap;
/* @internal */ pragmas: ReadonlyPragmaMap;
/* @internal */ localJsxNamespace?: __String;
/* @internal */ localJsxFactory?: EntityName;
@@ -2646,6 +2650,7 @@ namespace ts {
sourceFiles: ReadonlyArray<SourceFile>;
/* @internal */ syntheticFileReferences?: ReadonlyArray<FileReference>;
/* @internal */ syntheticTypeReferences?: ReadonlyArray<FileReference>;
/* @internal */ syntheticLibReferences?: ReadonlyArray<FileReference>;
/* @internal */ hasNoDefaultLib?: boolean;
}
@@ -2909,6 +2914,8 @@ namespace ts {
getBaseTypes(type: InterfaceType): BaseType[];
getBaseTypeOfLiteralType(type: Type): Type;
getWidenedType(type: Type): Type;
/* @internal */
getPromisedTypeOfPromise(promise: Type, errorNode?: Node): Type | undefined;
getReturnTypeOfSignature(signature: Signature): Type;
/**
* Gets the type of a parameter at a given position in a signature.
@@ -2973,6 +2980,7 @@ namespace ts {
getAugmentedPropertiesOfType(type: Type): Symbol[];
getRootSymbols(symbol: Symbol): Symbol[];
getContextualType(node: Expression): Type | undefined;
/* @internal */ getContextualTypeForObjectLiteralElement(element: ObjectLiteralElementLike): Type | undefined;
/* @internal */ getContextualTypeForArgumentAtIndex(call: CallLikeExpression, argIndex: number): Type | undefined;
/* @internal */ getContextualTypeForJsxAttribute(attribute: JsxAttribute | JsxSpreadAttribute): Type | undefined;
/* @internal */ isContextSensitive(node: Expression | MethodDeclaration | ObjectLiteralElementLike | JsxAttributeLike): boolean;
@@ -3091,6 +3099,10 @@ namespace ts {
*/
/* @internal */ getAccessibleSymbolChain(symbol: Symbol, enclosingDeclaration: Node | undefined, meaning: SymbolFlags, useOnlyExternalAliasing: boolean): Symbol[] | undefined;
/* @internal */ getTypePredicateOfSignature(signature: Signature): TypePredicate;
/**
* An external module with an 'export =' declaration resolves to the target of the 'export =' declaration,
* and an external module with no 'export =' declaration resolves to the module itself.
*/
/* @internal */ resolveExternalModuleSymbol(symbol: Symbol): Symbol;
/** @param node A location where we might consider accessing `this`. Not necessarily a ThisExpression. */
/* @internal */ tryGetThisTypeAt(node: Node): Type | undefined;
@@ -3108,6 +3120,8 @@ namespace ts {
* and the operation is cancelled, then it should be discarded, otherwise it is safe to keep.
*/
runWithCancellationToken<T>(token: CancellationToken, cb: (checker: TypeChecker) => T): T;
/* @internal */ getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol: Symbol): ReadonlyArray<TypeParameter> | undefined;
}
/* @internal */
@@ -3368,7 +3382,9 @@ namespace ts {
isImplementationOfOverload(node: FunctionLike): boolean | undefined;
isRequiredInitializedParameter(node: ParameterDeclaration): boolean;
isOptionalUninitializedParameterProperty(node: ParameterDeclaration): boolean;
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined;
isJSContainerFunctionDeclaration(node: FunctionDeclaration): boolean;
getPropertiesOfContainerFunction(node: Declaration): Symbol[];
createTypeOfDeclaration(declaration: AccessorDeclaration | VariableLikeDeclaration | PropertyAccessExpression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker, addUndefined?: boolean): TypeNode | undefined;
createReturnTypeOfSignatureDeclaration(signatureDeclaration: SignatureDeclaration, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
createTypeOfExpression(expr: Expression, enclosingDeclaration: Node, flags: NodeBuilderFlags, tracker: SymbolTracker): TypeNode | undefined;
createLiteralConstValue(node: VariableDeclaration | PropertyDeclaration | PropertySignature | ParameterDeclaration): Expression;
@@ -3427,8 +3443,8 @@ namespace ts {
Enum = RegularEnum | ConstEnum,
Variable = FunctionScopedVariable | BlockScopedVariable,
Value = Variable | Property | EnumMember | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor | JSContainer,
Type = Class | Interface | Enum | EnumMember | TypeLiteral | ObjectLiteral | TypeParameter | TypeAlias | JSContainer,
Value = Variable | Property | EnumMember | ObjectLiteral | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor | JSContainer,
Type = Class | Interface | Enum | EnumMember | TypeLiteral | TypeParameter | TypeAlias | JSContainer,
Namespace = ValueModule | NamespaceModule | Enum,
Module = ValueModule | NamespaceModule,
Accessor = GetAccessor | SetAccessor,
@@ -3449,7 +3465,7 @@ namespace ts {
InterfaceExcludes = Type & ~(Interface | Class),
RegularEnumExcludes = (Value | Type) & ~(RegularEnum | ValueModule), // regular enums merge only with regular enums and modules
ConstEnumExcludes = (Value | Type) & ~ConstEnum, // const enums merge only with const enums
ValueModuleExcludes = Value & ~(Function | Class | RegularEnum | ValueModule),
ValueModuleExcludes = Value & ~(Function | Class | RegularEnum | ValueModule | JSContainer),
NamespaceModuleExcludes = 0,
MethodExcludes = Value & ~Method,
GetAccessorExcludes = Value & ~SetAccessor,
@@ -3666,6 +3682,7 @@ namespace ts {
superCall?: SuperCall; // Cached first super-call found in the constructor. Used in checking whether super is called before this-accessing
switchTypes?: Type[]; // Cached array of switch case expression types
jsxNamespace?: Symbol | false; // Resolved jsx namespace symbol for this node
contextFreeType?: Type; // Cached context-free type used by the first pass of inference; used when a function's return is partially contextually sensitive
}
export const enum TypeFlags {
@@ -3943,6 +3960,7 @@ namespace ts {
constraintType?: Type;
templateType?: Type;
modifiersType?: Type;
resolvedApparentType?: Type;
}
export interface EvolvingArrayType extends ObjectType {
@@ -4159,9 +4177,8 @@ namespace ts {
/* @internal */
export const enum InferenceFlags {
None = 0, // No special inference behaviors
InferUnionTypes = 1 << 0, // Infer union types for disjoint candidates (otherwise unknownType)
NoDefault = 1 << 1, // Infer unknownType for no inferences (otherwise anyType or emptyObjectType)
AnyDefault = 1 << 2, // Infer anyType for no inferences (otherwise emptyObjectType)
NoDefault = 1 << 0, // Infer unknownType for no inferences (otherwise anyType or emptyObjectType)
AnyDefault = 1 << 1, // Infer anyType for no inferences (otherwise emptyObjectType)
}
/**
@@ -4540,6 +4557,8 @@ namespace ts {
isCommandLineOnly?: boolean;
showInSimplifiedHelpView?: boolean;
category?: DiagnosticMessage;
strictFlag?: true; // true if the option is one of the flag under strict
affectsSemanticDiagnostics?: true; // true if option affects semantic diagnostics
}
/* @internal */
@@ -4705,15 +4724,6 @@ namespace ts {
verticalTab = 0x0B, // \v
}
export interface UpToDateHost {
fileExists(fileName: string): boolean;
getModifiedTime(fileName: string): Date | undefined;
getUnchangedTime?(fileName: string): Date | undefined;
getLastStatus?(fileName: string): UpToDateStatus | undefined;
setLastStatus?(fileName: string, status: UpToDateStatus): void;
parseConfigFile?(configFilePath: ResolvedConfigFileName): ParsedCommandLine | undefined;
}
export interface ModuleResolutionHost {
// TODO: GH#18217 Optional methods frequently used as non-optional
@@ -4844,10 +4854,6 @@ namespace ts {
/* @internal */ hasInvalidatedResolution?: HasInvalidatedResolution;
/* @internal */ hasChangedAutomaticTypeDirectiveNames?: boolean;
createHash?(data: string): string;
getModifiedTime?(fileName: string): Date | undefined;
setModifiedTime?(fileName: string, date: Date): void;
deleteFile?(fileName: string): void;
}
/* @internal */
@@ -5064,6 +5070,7 @@ namespace ts {
/* @internal */
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
getLibFileFromReference(ref: FileReference): SourceFile | undefined;
getCommonSourceDirectory(): string;
getCanonicalFileName(fileName: string): string;
@@ -5331,7 +5338,6 @@ namespace ts {
useCaseSensitiveFileNames?(): boolean;
fileExists?(path: string): boolean;
readFile?(path: string): string | undefined;
getSourceFiles?(): ReadonlyArray<SourceFile>; // Used for cached resolutions to find symlinks without traversing the fs (again)
}
// Note: this used to be deprecated in our public API, but is still used internally
@@ -5344,7 +5350,7 @@ namespace ts {
reportInaccessibleThisError?(): void;
reportPrivateInBaseOfClassExpression?(propertyName: string): void;
reportInaccessibleUniqueSymbolError?(): void;
moduleResolverHost?: ModuleSpecifierResolutionHost;
moduleResolverHost?: EmitHost;
trackReferencedAmbientModule?(decl: ModuleDeclaration, symbol: Symbol): void;
trackExternalModuleSymbolOfImportTypeNode?(symbol: Symbol): void;
}
@@ -5583,15 +5589,32 @@ namespace ts {
/* @internal */
export type PragmaPsuedoMapEntry = {[K in keyof PragmaPsuedoMap]: {name: K, args: PragmaPsuedoMap[K]}}[keyof PragmaPsuedoMap];
/* @internal */
export interface ReadonlyPragmaMap extends ReadonlyMap<PragmaPsuedoMap[keyof PragmaPsuedoMap] | PragmaPsuedoMap[keyof PragmaPsuedoMap][]> {
get<TKey extends keyof PragmaPsuedoMap>(key: TKey): PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][];
forEach(action: <TKey extends keyof PragmaPsuedoMap>(value: PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][], key: TKey) => void): void;
}
/**
* A strongly-typed es6 map of pragma entries, the values of which are either a single argument
* value (if only one was found), or an array of multiple argument values if the pragma is present
* in multiple places
*/
/* @internal */
export interface PragmaMap extends Map<PragmaPsuedoMap[keyof PragmaPsuedoMap] | PragmaPsuedoMap[keyof PragmaPsuedoMap][]> {
export interface PragmaMap extends Map<PragmaPsuedoMap[keyof PragmaPsuedoMap] | PragmaPsuedoMap[keyof PragmaPsuedoMap][]>, ReadonlyPragmaMap {
set<TKey extends keyof PragmaPsuedoMap>(key: TKey, value: PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][]): this;
get<TKey extends keyof PragmaPsuedoMap>(key: TKey): PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][];
forEach(action: <TKey extends keyof PragmaPsuedoMap>(value: PragmaPsuedoMap[TKey] | PragmaPsuedoMap[TKey][], key: TKey) => void): void;
}
export interface UserPreferences {
readonly disableSuggestions?: boolean;
readonly quotePreference?: "double" | "single";
readonly includeCompletionsForModuleExports?: boolean;
readonly includeCompletionsWithInsertText?: boolean;
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
/** Determines whether we import `foo/index.ts` as "foo", "foo/index", or "foo/index.js" */
readonly importModuleSpecifierEnding?: "minimal" | "index" | "js";
readonly allowTextChangesInNewFiles?: boolean;
}
}
+190 -74
View File
@@ -16,7 +16,7 @@ namespace ts {
namespace ts {
export const emptyArray: never[] = [] as never[];
export const resolvingEmptyArray: never[] = [] as never[];
export const emptyMap: ReadonlyMap<never> = createMap<never>();
export const emptyMap = createMap<never>() as ReadonlyMap<never> & ReadonlyPragmaMap;
export const emptyUnderscoreEscapedMap: ReadonlyUnderscoreEscapedMap<never> = emptyMap as ReadonlyUnderscoreEscapedMap<never>;
export const externalHelpersModuleNameText = "tslib";
@@ -490,12 +490,23 @@ namespace ts {
return getTextOfNodeFromSourceText(sourceFile.text, node, includeTrivia);
}
function isJSDocTypeExpressionOrChild(node: Node): boolean {
return node.kind === SyntaxKind.JSDocTypeExpression || (node.parent && isJSDocTypeExpressionOrChild(node.parent));
}
export function getTextOfNodeFromSourceText(sourceText: string, node: Node, includeTrivia = false): string {
if (nodeIsMissing(node)) {
return "";
}
return sourceText.substring(includeTrivia ? node.pos : skipTrivia(sourceText, node.pos), node.end);
let text = sourceText.substring(includeTrivia ? node.pos : skipTrivia(sourceText, node.pos), node.end);
if (isJSDocTypeExpressionOrChild(node)) {
// strip space + asterisk at line start
text = text.replace(/(^|\r?\n|\r)\s*\*\s*/g, "$1");
}
return text;
}
export function getTextOfNode(node: Node, includeTrivia = false): string {
@@ -638,6 +649,10 @@ namespace ts {
return false;
}
export function getNonAugmentationDeclaration(symbol: Symbol) {
return find(symbol.declarations, d => !isExternalModuleAugmentation(d) && !(isModuleDeclaration(d) && isGlobalScopeAugmentation(d)));
}
export function isEffectiveExternalModule(node: SourceFile, compilerOptions: CompilerOptions) {
return isExternalModule(node) || compilerOptions.isolatedModules || ((getEmitModuleKind(compilerOptions) === ModuleKind.CommonJS) && !!node.commonJsModuleIndicator);
}
@@ -767,9 +782,9 @@ namespace ts {
case SyntaxKind.NumericLiteral:
return escapeLeadingUnderscores(name.text);
case SyntaxKind.ComputedPropertyName:
return isStringOrNumericLiteral(name.expression) ? escapeLeadingUnderscores(name.expression.text) : undefined!; // TODO: GH#18217 Almost all uses of this assume the result to be defined!
return isStringOrNumericLiteralLike(name.expression) ? escapeLeadingUnderscores(name.expression.text) : undefined!; // TODO: GH#18217 Almost all uses of this assume the result to be defined!
default:
Debug.assertNever(name);
return Debug.assertNever(name);
}
}
@@ -907,6 +922,10 @@ namespace ts {
return !!(getCombinedModifierFlags(node) & ModifierFlags.Const);
}
export function isDeclarationReadonly(declaration: Declaration): boolean {
return !!(getCombinedModifierFlags(declaration) & ModifierFlags.Readonly && !isParameterPropertyDeclaration(declaration));
}
export function isVarConst(node: VariableDeclaration | VariableDeclarationList): boolean {
return !!(getCombinedNodeFlags(node) & NodeFlags.Const);
}
@@ -1016,6 +1035,8 @@ namespace ts {
return !isExpressionWithTypeArgumentsInClassExtendsClause(parent);
case SyntaxKind.TypeParameter:
return node === (<TypeParameterDeclaration>parent).constraint;
case SyntaxKind.JSDocTemplateTag:
return node === (<JSDocTemplateTag>parent).constraint;
case SyntaxKind.PropertyDeclaration:
case SyntaxKind.PropertySignature:
case SyntaxKind.Parameter:
@@ -1719,12 +1740,15 @@ namespace ts {
}
export function getDeclarationOfJSInitializer(node: Node): Node | undefined {
if (!isInJavaScriptFile(node) || !node.parent) {
if (!node.parent) {
return undefined;
}
let name: Expression | BindingName | undefined;
let decl: Node | undefined;
if (isVariableDeclaration(node.parent) && node.parent.initializer === node) {
if (!isInJavaScriptFile(node) && !isVarConst(node.parent)) {
return undefined;
}
name = node.parent.name;
decl = node.parent;
}
@@ -1753,6 +1777,10 @@ namespace ts {
return decl;
}
export function isAssignmentDeclaration(decl: Declaration) {
return isBinaryExpression(decl) || isPropertyAccessExpression(decl) || isIdentifier(decl);
}
/** Get the initializer, taking into account defaulted Javascript initializers */
export function getEffectiveInitializer(node: HasExpressionInitializer) {
if (isInJavaScriptFile(node) && node.initializer &&
@@ -1886,8 +1914,12 @@ namespace ts {
/// Given a BinaryExpression, returns SpecialPropertyAssignmentKind for the various kinds of property
/// assignments we treat as special in the binder
export function getSpecialPropertyAssignmentKind(expr: BinaryExpression): SpecialPropertyAssignmentKind {
if (!isInJavaScriptFile(expr) ||
expr.operatorToken.kind !== SyntaxKind.EqualsToken ||
const special = getSpecialPropertyAssignmentKindWorker(expr);
return special === SpecialPropertyAssignmentKind.Property || isInJavaScriptFile(expr) ? special : SpecialPropertyAssignmentKind.None;
}
function getSpecialPropertyAssignmentKindWorker(expr: BinaryExpression): SpecialPropertyAssignmentKind {
if (expr.operatorToken.kind !== SyntaxKind.EqualsToken ||
!isPropertyAccessExpression(expr.left)) {
return SpecialPropertyAssignmentKind.None;
}
@@ -1948,6 +1980,14 @@ namespace ts {
!!getJSDocTypeTag(expr.parent);
}
export function isFunctionSymbol(symbol: Symbol | undefined) {
if (!symbol || !symbol.valueDeclaration) {
return false;
}
const decl = symbol.valueDeclaration;
return decl.kind === SyntaxKind.FunctionDeclaration || isVariableDeclaration(decl) && decl.initializer && isFunctionLike(decl.initializer);
}
export function importFromModuleSpecifier(node: StringLiteralLike): AnyValidImportOrReExport {
return tryGetImportFromModuleSpecifier(node) || Debug.fail(Debug.showSyntaxKind(node.parent));
}
@@ -2091,6 +2131,10 @@ namespace ts {
result = addRange(result, getJSDocParameterTags(node as ParameterDeclaration));
break;
}
if (node.kind === SyntaxKind.TypeParameter) {
result = addRange(result, getJSDocTypeParameterTags(node as TypeParameterDeclaration));
break;
}
node = getNextJSDocCommentLocation(node);
}
return result || emptyArray;
@@ -2310,6 +2354,13 @@ namespace ts {
return node;
}
function skipParenthesesUp(node: Node): Node {
while (node.kind === SyntaxKind.ParenthesizedExpression) {
node = node.parent;
}
return node;
}
// a node is delete target iff. it is PropertyAccessExpression/ElementAccessExpression with parentheses skipped
export function isDeleteTarget(node: Node): boolean {
if (node.kind !== SyntaxKind.PropertyAccessExpression && node.kind !== SyntaxKind.ElementAccessExpression) {
@@ -2348,7 +2399,10 @@ namespace ts {
}
else {
const binExp = name.parent.parent;
return isBinaryExpression(binExp) && getSpecialPropertyAssignmentKind(binExp) !== SpecialPropertyAssignmentKind.None && getNameOfDeclaration(binExp) === name;
return isBinaryExpression(binExp) &&
getSpecialPropertyAssignmentKind(binExp) !== SpecialPropertyAssignmentKind.None &&
(binExp.left.symbol || binExp.symbol) &&
getNameOfDeclaration(binExp) === name;
}
}
default:
@@ -2560,10 +2614,8 @@ namespace ts {
return false;
}
export function isStringOrNumericLiteral(node: Node): node is StringLiteral | NumericLiteral {
const kind = node.kind;
return kind === SyntaxKind.StringLiteral
|| kind === SyntaxKind.NumericLiteral;
export function isStringOrNumericLiteralLike(node: Node): node is StringLiteralLike | NumericLiteral {
return isStringLiteralLike(node) || isNumericLiteral(node);
}
/**
@@ -2580,7 +2632,7 @@ namespace ts {
export function isDynamicName(name: DeclarationName): boolean {
return name.kind === SyntaxKind.ComputedPropertyName &&
!isStringOrNumericLiteral(name.expression) &&
!isStringOrNumericLiteralLike(name.expression) &&
!isWellKnownSymbolSyntactically(name.expression);
}
@@ -2593,24 +2645,25 @@ namespace ts {
return isPropertyAccessExpression(node) && isESSymbolIdentifier(node.expression);
}
export function getPropertyNameForPropertyNameNode(name: DeclarationName): __String | undefined {
if (name.kind === SyntaxKind.Identifier) {
return name.escapedText;
export function getPropertyNameForPropertyNameNode(name: PropertyName): __String | undefined {
switch (name.kind) {
case SyntaxKind.Identifier:
return name.escapedText;
case SyntaxKind.StringLiteral:
case SyntaxKind.NumericLiteral:
return escapeLeadingUnderscores(name.text);
case SyntaxKind.ComputedPropertyName:
const nameExpression = name.expression;
if (isWellKnownSymbolSyntactically(nameExpression)) {
return getPropertyNameForKnownSymbolName(idText((<PropertyAccessExpression>nameExpression).name));
}
else if (isStringOrNumericLiteralLike(nameExpression)) {
return escapeLeadingUnderscores(nameExpression.text);
}
return undefined;
default:
return Debug.assertNever(name);
}
if (name.kind === SyntaxKind.StringLiteral || name.kind === SyntaxKind.NumericLiteral) {
return escapeLeadingUnderscores(name.text);
}
if (name.kind === SyntaxKind.ComputedPropertyName) {
const nameExpression = name.expression;
if (isWellKnownSymbolSyntactically(nameExpression)) {
return getPropertyNameForKnownSymbolName(idText((<PropertyAccessExpression>nameExpression).name));
}
else if (nameExpression.kind === SyntaxKind.StringLiteral || nameExpression.kind === SyntaxKind.NumericLiteral) {
return escapeLeadingUnderscores((<LiteralExpression>nameExpression).text);
}
}
return undefined;
}
export type PropertyNameLiteral = Identifier | StringLiteralLike | NumericLiteral;
@@ -3183,16 +3236,7 @@ namespace ts {
}
export function getDeclarationEmitOutputFilePath(fileName: string, host: EmitHost) {
// TODO: GH#25810 following should work but makes the build break:
// return getDeclarationEmitOutputFilePathWorker(fileName, host.getCompilerOptions(), host.getCurrentDirectory(), host.getCommonSourceDirectory(), f => host.getCanonicalFileName(f));
const options = host.getCompilerOptions();
const outputDir = options.declarationDir || options.outDir; // Prefer declaration folder if specified
const path = outputDir
? getSourceFilePathInNewDir(fileName, host, outputDir)
: fileName;
return removeFileExtension(path) + Extension.Dts;
return getDeclarationEmitOutputFilePathWorker(fileName, host.getCompilerOptions(), host.getCurrentDirectory(), host.getCommonSourceDirectory(), f => host.getCanonicalFileName(f));
}
export function getDeclarationEmitOutputFilePathWorker(fileName: string, options: CompilerOptions, currentDirectory: string, commonSourceDirectory: string, getCanonicalFileName: GetCanonicalFileName): string {
@@ -3325,17 +3369,17 @@ namespace ts {
}
}
else {
forEach(declarations, (member: Declaration) => {
if ((member.kind === SyntaxKind.GetAccessor || member.kind === SyntaxKind.SetAccessor)
forEach(declarations, member => {
if (isAccessor(member)
&& hasModifier(member, ModifierFlags.Static) === hasModifier(accessor, ModifierFlags.Static)) {
const memberName = getPropertyNameForPropertyNameNode((member as NamedDeclaration).name!);
const memberName = getPropertyNameForPropertyNameNode(member.name);
const accessorName = getPropertyNameForPropertyNameNode(accessor.name);
if (memberName === accessorName) {
if (!firstAccessor) {
firstAccessor = <AccessorDeclaration>member;
firstAccessor = member;
}
else if (!secondAccessor) {
secondAccessor = <AccessorDeclaration>member;
secondAccessor = member;
}
if (member.kind === SyntaxKind.GetAccessor && !getAccessor) {
@@ -3362,7 +3406,9 @@ namespace ts {
* parsed in a JavaScript file, gets the type annotation from JSDoc.
*/
export function getEffectiveTypeAnnotationNode(node: Node): TypeNode | undefined {
return (node as HasType).type || (isInJavaScriptFile(node) ? getJSDocType(node) : undefined);
const type = (node as HasType).type;
if (type || !isInJavaScriptFile(node)) return type;
return isJSDocPropertyLikeTag(node) ? node.typeExpression && node.typeExpression.type : getJSDocType(node);
}
export function getTypeAnnotationNode(node: Node): TypeNode | undefined {
@@ -3374,10 +3420,9 @@ namespace ts {
* JavaScript file, gets the return type annotation from JSDoc.
*/
export function getEffectiveReturnTypeNode(node: SignatureDeclaration | JSDocSignature): TypeNode | undefined {
if (isJSDocSignature(node)) {
return node.type && node.type.typeExpression && node.type.typeExpression.type;
}
return node.type || (isInJavaScriptFile(node) ? getJSDocReturnType(node) : undefined);
return isJSDocSignature(node) ?
node.type && node.type.typeExpression && node.type.typeExpression.type :
node.type || (isInJavaScriptFile(node) ? getJSDocReturnType(node) : undefined);
}
export function getJSDocTypeParameterDeclarations(node: DeclarationWithTypeParameters): ReadonlyArray<TypeParameterDeclaration> {
@@ -3721,7 +3766,7 @@ namespace ts {
return false;
}
export function isExpressionWithTypeArgumentsInClassExtendsClause(node: Node): boolean {
export function isExpressionWithTypeArgumentsInClassExtendsClause(node: Node): node is ExpressionWithTypeArguments {
return tryGetClassExtendingExpressionWithTypeArguments(node) !== undefined;
}
@@ -4015,7 +4060,8 @@ namespace ts {
* @param pos The start position.
* @param end The end position.
*/
export function createRange(pos: number, end: number): TextRange {
export function createRange(pos: number, end: number = pos): TextRange {
Debug.assert(end >= pos || end === -1);
return { pos, end };
}
@@ -4191,22 +4237,48 @@ namespace ts {
if (!parent) return AccessKind.Read;
switch (parent.kind) {
case SyntaxKind.ParenthesizedExpression:
return accessKind(parent);
case SyntaxKind.PostfixUnaryExpression:
case SyntaxKind.PrefixUnaryExpression:
const { operator } = parent as PrefixUnaryExpression | PostfixUnaryExpression;
return operator === SyntaxKind.PlusPlusToken || operator === SyntaxKind.MinusMinusToken ? writeOrReadWrite() : AccessKind.Read;
case SyntaxKind.BinaryExpression:
const { left, operatorToken } = parent as BinaryExpression;
return left === node && isAssignmentOperator(operatorToken.kind) ? writeOrReadWrite() : AccessKind.Read;
return left === node && isAssignmentOperator(operatorToken.kind) ?
operatorToken.kind === SyntaxKind.EqualsToken ? AccessKind.Write : writeOrReadWrite()
: AccessKind.Read;
case SyntaxKind.PropertyAccessExpression:
return (parent as PropertyAccessExpression).name !== node ? AccessKind.Read : accessKind(parent);
case SyntaxKind.PropertyAssignment: {
const parentAccess = accessKind(parent.parent);
// In `({ x: varname }) = { x: 1 }`, the left `x` is a read, the right `x` is a write.
return node === (parent as PropertyAssignment).name ? reverseAccessKind(parentAccess) : parentAccess;
}
case SyntaxKind.ShorthandPropertyAssignment:
// Assume it's the local variable being accessed, since we don't check public properties for --noUnusedLocals.
return node === (parent as ShorthandPropertyAssignment).objectAssignmentInitializer ? AccessKind.Read : accessKind(parent.parent);
case SyntaxKind.ArrayLiteralExpression:
return accessKind(parent);
default:
return AccessKind.Read;
}
function writeOrReadWrite(): AccessKind {
// If grandparent is not an ExpressionStatement, this is used as an expression in addition to having a side effect.
return parent.parent && parent.parent.kind === SyntaxKind.ExpressionStatement ? AccessKind.Write : AccessKind.ReadWrite;
return parent.parent && skipParenthesesUp(parent.parent).kind === SyntaxKind.ExpressionStatement ? AccessKind.Write : AccessKind.ReadWrite;
}
}
function reverseAccessKind(a: AccessKind): AccessKind {
switch (a) {
case AccessKind.Read:
return AccessKind.Write;
case AccessKind.Write:
return AccessKind.Read;
case AccessKind.ReadWrite:
return AccessKind.ReadWrite;
default:
return Debug.assertNever(a);
}
}
@@ -4453,12 +4525,6 @@ namespace ts {
return { start, length };
}
/* @internal */
export function createTextRange(pos: number, end: number = pos): TextRange {
Debug.assert(end >= pos);
return { pos, end };
}
export function createTextSpanFromBounds(start: number, end: number) {
return createTextSpan(start, end - start);
}
@@ -4836,13 +4902,13 @@ namespace ts {
if (isDeclaration(hostNode)) {
return getDeclarationIdentifier(hostNode);
}
// Covers remaining cases
// Covers remaining cases (returning undefined if none match).
switch (hostNode.kind) {
case SyntaxKind.VariableStatement:
if (hostNode.declarationList && hostNode.declarationList.declarations[0]) {
return getDeclarationIdentifier(hostNode.declarationList.declarations[0]);
}
return undefined;
break;
case SyntaxKind.ExpressionStatement:
const expr = hostNode.expression;
switch (expr.kind) {
@@ -4854,9 +4920,7 @@ namespace ts {
return arg;
}
}
return undefined;
case SyntaxKind.EndOfFileToken:
return undefined;
break;
case SyntaxKind.ParenthesizedExpression: {
return getDeclarationIdentifier(hostNode.expression);
}
@@ -4864,10 +4928,8 @@ namespace ts {
if (isDeclaration(hostNode.statement) || isExpression(hostNode.statement)) {
return getDeclarationIdentifier(hostNode.statement);
}
return undefined;
break;
}
default:
Debug.assertNever(hostNode, "Found typedef tag attached to node which it should not be!");
}
}
@@ -4946,15 +5008,14 @@ namespace ts {
/**
* Gets the JSDoc parameter tags for the node if present.
*
* @remarks Returns any JSDoc param tag that matches the provided
* @remarks Returns any JSDoc param tag whose name matches the provided
* parameter, whether a param tag on a containing function
* expression, or a param tag on a variable declaration whose
* initializer is the containing function. The tags closest to the
* node are returned first, so in the previous example, the param
* tag on the containing function expression would be first.
*
* Does not return tags for binding patterns, because JSDoc matches
* parameters by name and binding patterns do not have a name.
* For binding patterns, parameter tags are matched by position.
*/
export function getJSDocParameterTags(param: ParameterDeclaration): ReadonlyArray<JSDocParameterTag> {
if (param.name) {
@@ -4975,6 +5036,22 @@ namespace ts {
return emptyArray;
}
/**
* Gets the JSDoc type parameter tags for the node if present.
*
* @remarks Returns any JSDoc template tag whose names match the provided
* parameter, whether a template tag on a containing function
* expression, or a template tag on a variable declaration whose
* initializer is the containing function. The tags closest to the
* node are returned first, so in the previous example, the template
* tag on the containing function expression would be first.
*/
export function getJSDocTypeParameterTags(param: TypeParameterDeclaration): ReadonlyArray<JSDocTemplateTag> {
const name = param.name.escapedText;
return getJSDocTags(param.parent).filter((tag): tag is JSDocTemplateTag =>
isJSDocTemplateTag(tag) && tag.typeParameters.some(tp => tp.name.escapedText === name));
}
/**
* Return true if the node has JSDoc parameter tags.
*
@@ -5103,7 +5180,27 @@ namespace ts {
Debug.assert(node.parent.kind === SyntaxKind.JSDocComment);
return flatMap(node.parent.tags, tag => isJSDocTemplateTag(tag) ? tag.typeParameters : undefined) as ReadonlyArray<TypeParameterDeclaration>;
}
return node.typeParameters || (isInJavaScriptFile(node) ? getJSDocTypeParameterDeclarations(node) : emptyArray);
if (node.typeParameters) {
return node.typeParameters;
}
if (isInJavaScriptFile(node)) {
const decls = getJSDocTypeParameterDeclarations(node);
if (decls.length) {
return decls;
}
const typeTag = getJSDocType(node);
if (typeTag && isFunctionTypeNode(typeTag) && typeTag.typeParameters) {
return typeTag.typeParameters;
}
}
return emptyArray;
}
export function getEffectiveConstraintOfTypeParameter(node: TypeParameterDeclaration): TypeNode | undefined {
return node.constraint ? node.constraint
: isJSDocTemplateTag(node.parent) && node === node.parent.typeParameters[0]
? node.parent.constraint
: undefined;
}
}
@@ -6967,6 +7064,15 @@ namespace ts {
return compilerOptions[flag] === undefined ? !!compilerOptions.strict : !!compilerOptions[flag];
}
export function compilerOptionsAffectSemanticDiagnostics(newOptions: CompilerOptions, oldOptions: CompilerOptions) {
if (oldOptions === newOptions) {
return false;
}
return optionDeclarations.some(option => (!!option.strictFlag && getStrictOptionValue(newOptions, option.name as StrictOptionName) !== getStrictOptionValue(oldOptions, option.name as StrictOptionName)) ||
(!!option.affectsSemanticDiagnostics && !newOptions[option.name] !== !oldOptions[option.name]));
}
export function hasZeroOrOneAsteriskCharacter(str: string): boolean {
let seenAsterisk = false;
for (let i = 0; i < str.length; i++) {
@@ -7260,8 +7366,6 @@ namespace ts {
if (pathComponents.length === 0) return "";
const root = pathComponents[0] && ensureTrailingDirectorySeparator(pathComponents[0]);
if (pathComponents.length === 1) return root;
return root + pathComponents.slice(1).join(directorySeparator);
}
@@ -7865,6 +7969,7 @@ namespace ts {
/** Must have ".d.ts" first because if ".ts" goes first, that will be detected as the extension instead of ".d.ts". */
export const supportedTypescriptExtensionsForExtractExtension: ReadonlyArray<Extension> = [Extension.Dts, Extension.Ts, Extension.Tsx];
export const supportedJavascriptExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx];
export const supportedJavaScriptAndJsonExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx, Extension.Json];
const allSupportedExtensions: ReadonlyArray<Extension> = [...supportedTypeScriptExtensions, ...supportedJavascriptExtensions];
export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: ReadonlyArray<FileExtensionInfo>): ReadonlyArray<string> {
@@ -7890,6 +7995,10 @@ namespace ts {
return some(supportedJavascriptExtensions, extension => fileExtensionIs(fileName, extension));
}
export function hasJavaScriptOrJsonFileExtension(fileName: string): boolean {
return supportedJavaScriptAndJsonExtensions.some(ext => fileExtensionIs(fileName, ext));
}
export function hasTypeScriptFileExtension(fileName: string): boolean {
return some(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension));
}
@@ -8213,4 +8322,11 @@ namespace ts {
// Include the `<>`
return { pos: typeParameters.pos - 1, end: typeParameters.end + 1 };
}
export function skipTypeChecking(sourceFile: SourceFile, options: CompilerOptions) {
// If skipLibCheck is enabled, skip reporting errors if file is a declaration file.
// If skipDefaultLibCheck is enabled, skip reporting errors if file contains a
// '/// <reference no-default-lib="true"/>' directive.
return options.skipLibCheck && sourceFile.isDeclarationFile || options.skipDefaultLibCheck && sourceFile.hasNoDefaultLib;
}
}
+35 -26
View File
@@ -27,12 +27,6 @@ namespace ts {
};
}
/** @internal */
export const nonClearingMessageCodes: number[] = [
Diagnostics.Found_1_error_Watching_for_file_changes.code,
Diagnostics.Found_0_errors_Watching_for_file_changes.code
];
/**
* @returns Whether the screen was cleared.
*/
@@ -41,7 +35,7 @@ namespace ts {
!options.preserveWatchOutput &&
!options.extendedDiagnostics &&
!options.diagnostics &&
!contains(nonClearingMessageCodes, diagnostic.code)) {
contains(screenStartingMessageCodes, diagnostic.code)) {
system.clearScreen();
return true;
}
@@ -174,6 +168,17 @@ namespace ts {
const noopFileWatcher: FileWatcher = { close: noop };
export function createWatchHost(system = sys, reportWatchStatus?: WatchStatusReporter): WatchHost {
const onWatchStatusChange = reportWatchStatus || createWatchStatusReporter(system);
return {
onWatchStatusChange,
watchFile: system.watchFile ? ((path, callback, pollingInterval) => system.watchFile!(path, callback, pollingInterval)) : () => noopFileWatcher,
watchDirectory: system.watchDirectory ? ((path, callback, recursive) => system.watchDirectory!(path, callback, recursive)) : () => noopFileWatcher,
setTimeout: system.setTimeout ? ((callback, ms, ...args: any[]) => system.setTimeout!.call(system, callback, ms, ...args)) : noop,
clearTimeout: system.clearTimeout ? (timeoutId => system.clearTimeout!(timeoutId)) : noop
};
}
/**
* Creates the watch compiler host that can be extended with config file or root file names and options host
*/
@@ -183,9 +188,10 @@ namespace ts {
}
let host: DirectoryStructureHost = system;
host; // tslint:disable-line no-unused-expression (TODO: `host` is unused!)
const useCaseSensitiveFileNames = () => system.useCaseSensitiveFileNames;
const writeFileName = (s: string) => system.write(s + system.newLine);
const onWatchStatusChange = reportWatchStatus || createWatchStatusReporter(system);
const { onWatchStatusChange, watchFile, watchDirectory, setTimeout, clearTimeout } = createWatchHost(system, reportWatchStatus);
return {
useCaseSensitiveFileNames,
getNewLine: () => system.newLine,
@@ -199,10 +205,10 @@ namespace ts {
readDirectory: (path, extensions, exclude, include, depth) => system.readDirectory(path, extensions, exclude, include, depth),
realpath: system.realpath && (path => system.realpath!(path)),
getEnvironmentVariable: system.getEnvironmentVariable && (name => system.getEnvironmentVariable(name)),
watchFile: system.watchFile ? ((path, callback, pollingInterval) => system.watchFile!(path, callback, pollingInterval)) : () => noopFileWatcher,
watchDirectory: system.watchDirectory ? ((path, callback, recursive) => system.watchDirectory!(path, callback, recursive)) : () => noopFileWatcher,
setTimeout: system.setTimeout ? ((callback, ms, ...args: any[]) => system.setTimeout!.call(system, callback, ms, ...args)) : noop,
clearTimeout: system.clearTimeout ? (timeoutId => system.clearTimeout!(timeoutId)) : noop,
watchFile,
watchDirectory,
setTimeout,
clearTimeout,
trace: s => system.write(s),
onWatchStatusChange,
createDirectory: path => system.createDirectory(path),
@@ -223,10 +229,10 @@ namespace ts {
const reportSummary = (errorCount: number) => {
if (errorCount === 1) {
onWatchStatusChange(createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes, errorCount), newLine, compilerOptions);
onWatchStatusChange!(createCompilerDiagnostic(Diagnostics.Found_1_error_Watching_for_file_changes, errorCount), newLine, compilerOptions);
}
else {
onWatchStatusChange(createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errorCount, errorCount), newLine, compilerOptions);
onWatchStatusChange!(createCompilerDiagnostic(Diagnostics.Found_0_errors_Watching_for_file_changes, errorCount, errorCount), newLine, compilerOptions);
}
};
@@ -269,7 +275,21 @@ namespace ts {
export type WatchStatusReporter = (diagnostic: Diagnostic, newLine: string, options: CompilerOptions) => void;
/** Create the program with rootNames and options, if they are undefined, oldProgram and new configFile diagnostics create new program */
export type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) => T;
export interface WatchCompilerHost<T extends BuilderProgram> {
/** Host that has watch functionality used in --watch mode */
export interface WatchHost {
/** If provided, called with Diagnostic message that informs about change in watch status */
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
/** Used to watch changes in source files, missing files needed to update the program or config file */
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
/** If provided, will be used to reset existing delayed compilation */
clearTimeout?(timeoutId: any): void;
}
export interface WatchCompilerHost<T extends BuilderProgram> extends WatchHost {
// TODO: GH#18217 Optional methods are frequently asserted
/**
@@ -278,8 +298,6 @@ namespace ts {
createProgram: CreateProgram<T>;
/** If provided, callback to invoke after every new program creation */
afterProgramCreate?(program: T): void;
/** If provided, called with Diagnostic message that informs about change in watch status */
onWatchStatusChange?(diagnostic: Diagnostic, newLine: string, options: CompilerOptions): void;
// Only for testing
/*@internal*/
@@ -322,15 +340,6 @@ namespace ts {
resolveModuleNames?(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModule[];
/** If provided, used to resolve type reference directives, otherwise typescript's default resolution */
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
/** Used to watch changes in source files, missing files needed to update the program or config file */
watchFile(path: string, callback: FileWatcherCallback, pollingInterval?: number): FileWatcher;
/** Used to watch resolved module's failed lookup locations, config file specs, type roots where auto type reference directives are added */
watchDirectory(path: string, callback: DirectoryWatcherCallback, recursive?: boolean): FileWatcher;
/** If provided, will be used to set delayed compilation, so that multiple changes in short span are compiled together */
setTimeout?(callback: (...args: any[]) => void, ms: number, ...args: any[]): any;
/** If provided, will be used to reset existing delayed compilation */
clearTimeout?(timeoutId: any): void;
}
/** Internal interface used to wire emit through same host */
+36
View File
@@ -374,5 +374,41 @@ namespace fakes {
return parsed;
}
}
export class SolutionBuilderHost extends CompilerHost implements ts.SolutionBuilderHost {
diagnostics: ts.Diagnostic[] = [];
reportDiagnostic(diagnostic: ts.Diagnostic) {
this.diagnostics.push(diagnostic);
}
reportSolutionBuilderStatus(diagnostic: ts.Diagnostic) {
this.diagnostics.push(diagnostic);
}
clearDiagnostics() {
this.diagnostics.length = 0;
}
assertDiagnosticMessages(...expected: ts.DiagnosticMessage[]) {
const actual = this.diagnostics.slice();
if (actual.length !== expected.length) {
assert.fail<any>(actual, expected, `Diagnostic arrays did not match - got\r\n${actual.map(a => " " + a.messageText).join("\r\n")}\r\nexpected\r\n${expected.map(e => " " + e.message).join("\r\n")}`);
}
for (let i = 0; i < actual.length; i++) {
if (actual[i].code !== expected[i].code) {
assert.fail(actual[i].messageText, expected[i].message, `Mismatched error code - expected diagnostic ${i} "${actual[i].messageText}" to match ${expected[i].message}`);
}
}
}
printDiagnostics(header = "== Diagnostics ==") {
const out = ts.createDiagnosticReporter(ts.sys);
ts.sys.write(header + "\r\n");
for (const d of this.diagnostics) {
out(d);
}
}
}
}
+161 -132
View File
@@ -50,10 +50,8 @@ namespace FourSlash {
data?: {};
}
export interface Range {
export interface Range extends ts.TextRange {
fileName: string;
pos: number;
end: number;
marker?: Marker;
}
@@ -870,8 +868,7 @@ namespace FourSlash {
const actualByName = ts.createMap<ts.CompletionEntry>();
for (const entry of actualCompletions.entries) {
if (actualByName.has(entry.name)) {
// TODO: GH#23587
if (entry.name !== "undefined" && entry.name !== "require") this.raiseError(`Duplicate (${actualCompletions.entries.filter(a => a.name === entry.name).length}) completions for ${entry.name}`);
this.raiseError(`Duplicate (${actualCompletions.entries.filter(a => a.name === entry.name).length}) completions for ${entry.name}`);
}
else {
actualByName.set(entry.name, entry);
@@ -911,8 +908,8 @@ namespace FourSlash {
}
private verifyCompletionEntry(actual: ts.CompletionEntry, expected: FourSlashInterface.ExpectedCompletionEntry) {
const { insertText, replacementSpan, hasAction, isRecommended, kind, text, documentation, sourceDisplay } = typeof expected === "string"
? { insertText: undefined, replacementSpan: undefined, hasAction: undefined, isRecommended: undefined, kind: undefined, text: undefined, documentation: undefined, sourceDisplay: undefined }
const { insertText, replacementSpan, hasAction, isRecommended, kind, text, documentation, source, sourceDisplay } = typeof expected === "string"
? { insertText: undefined, replacementSpan: undefined, hasAction: undefined, isRecommended: undefined, kind: undefined, text: undefined, documentation: undefined, source: undefined, sourceDisplay: undefined }
: expected;
if (actual.insertText !== insertText) {
@@ -930,6 +927,7 @@ namespace FourSlash {
assert.equal(actual.hasAction, hasAction);
assert.equal(actual.isRecommended, isRecommended);
assert.equal(actual.source, source);
if (text) {
const actualDetails = this.getCompletionEntryDetails(actual.name, actual.source)!;
@@ -1103,7 +1101,7 @@ namespace FourSlash {
return node;
}
private verifyRange(desc: string, expected: Range, actual: ts.Node) {
private verifyRange(desc: string, expected: ts.TextRange, actual: ts.Node) {
const actualStart = actual.getStart();
const actualEnd = actual.getEnd();
if (actualStart !== expected.pos || actualEnd !== expected.end) {
@@ -1639,11 +1637,7 @@ Actual: ${stringify(fullActual)}`);
baselineFile = baselineFile.replace(ts.Extension.Ts, ".baseline");
}
Harness.Baseline.runBaseline(
baselineFile,
() => {
return this.baselineCurrentFileLocations(pos => this.getBreakpointStatementLocation(pos)!);
});
Harness.Baseline.runBaseline(baselineFile, this.baselineCurrentFileLocations(pos => this.getBreakpointStatementLocation(pos)!));
}
private getEmitFiles(): ReadonlyArray<FourSlashFile> {
@@ -1674,66 +1668,58 @@ Actual: ${stringify(fullActual)}`);
for (const { name, text } of outputFiles) {
const fromTestFile = this.getFileContent(name);
if (fromTestFile !== text) {
this.raiseError("Emit output is not as expected: " + showTextDiff(fromTestFile, text));
this.raiseError(`Emit output for ${name} is not as expected: ${showTextDiff(fromTestFile, text)}`);
}
}
}
public baselineGetEmitOutput(): void {
Harness.Baseline.runBaseline(
ts.Debug.assertDefined(this.testData.globalOptions[MetadataOptionNames.baselineFile]),
() => {
let resultString = "";
// Loop through all the emittedFiles and emit them one by one
for (const emitFile of this.getEmitFiles()) {
const emitOutput = this.languageService.getEmitOutput(emitFile.fileName);
// Print emitOutputStatus in readable format
resultString += "EmitSkipped: " + emitOutput.emitSkipped + Harness.IO.newLine();
let resultString = "";
// Loop through all the emittedFiles and emit them one by one
for (const emitFile of this.getEmitFiles()) {
const emitOutput = this.languageService.getEmitOutput(emitFile.fileName);
// Print emitOutputStatus in readable format
resultString += "EmitSkipped: " + emitOutput.emitSkipped + Harness.IO.newLine();
if (emitOutput.emitSkipped) {
resultString += "Diagnostics:" + Harness.IO.newLine();
const diagnostics = ts.getPreEmitDiagnostics(this.languageService.getProgram()!); // TODO: GH#18217
for (const diagnostic of diagnostics) {
if (!ts.isString(diagnostic.messageText)) {
let chainedMessage: ts.DiagnosticMessageChain | undefined = diagnostic.messageText;
let indentation = " ";
while (chainedMessage) {
resultString += indentation + chainedMessage.messageText + Harness.IO.newLine();
chainedMessage = chainedMessage.next;
indentation = indentation + " ";
}
}
else {
resultString += " " + diagnostic.messageText + Harness.IO.newLine();
}
if (emitOutput.emitSkipped) {
resultString += "Diagnostics:" + Harness.IO.newLine();
const diagnostics = ts.getPreEmitDiagnostics(this.languageService.getProgram()!); // TODO: GH#18217
for (const diagnostic of diagnostics) {
if (!ts.isString(diagnostic.messageText)) {
let chainedMessage: ts.DiagnosticMessageChain | undefined = diagnostic.messageText;
let indentation = " ";
while (chainedMessage) {
resultString += indentation + chainedMessage.messageText + Harness.IO.newLine();
chainedMessage = chainedMessage.next;
indentation = indentation + " ";
}
}
for (const outputFile of emitOutput.outputFiles) {
const fileName = "FileName : " + outputFile.name + Harness.IO.newLine();
resultString = resultString + Harness.IO.newLine() + fileName + outputFile.text;
else {
resultString += " " + diagnostic.messageText + Harness.IO.newLine();
}
resultString += Harness.IO.newLine();
}
}
return resultString;
});
for (const outputFile of emitOutput.outputFiles) {
const fileName = "FileName : " + outputFile.name + Harness.IO.newLine();
resultString = resultString + Harness.IO.newLine() + fileName + outputFile.text;
}
resultString += Harness.IO.newLine();
}
Harness.Baseline.runBaseline(ts.Debug.assertDefined(this.testData.globalOptions[MetadataOptionNames.baselineFile]), resultString);
}
public baselineQuickInfo() {
let baselineFile = this.testData.globalOptions[MetadataOptionNames.baselineFile];
if (!baselineFile) {
baselineFile = ts.getBaseFileName(this.activeFile.fileName).replace(ts.Extension.Ts, ".baseline");
}
const baselineFile = this.testData.globalOptions[MetadataOptionNames.baselineFile] ||
ts.getBaseFileName(this.activeFile.fileName).replace(ts.Extension.Ts, ".baseline");
Harness.Baseline.runBaseline(
baselineFile,
() => stringify(
stringify(
this.testData.markers.map(marker => ({
marker,
quickInfo: this.languageService.getQuickInfoAtPosition(marker.fileName, marker.position)
}))
));
}))));
}
public printBreakpointLocation(pos: number) {
@@ -1967,18 +1953,11 @@ Actual: ${stringify(fullActual)}`);
* May be negative.
*/
private applyEdits(fileName: string, edits: ReadonlyArray<ts.TextChange>, isFormattingEdit: boolean): number {
// We get back a set of edits, but langSvc.editScript only accepts one at a time. Use this to keep track
// of the incremental offset from each edit to the next. We assume these edit ranges don't overlap
// Copy this so we don't ruin someone else's copy
edits = JSON.parse(JSON.stringify(edits));
// Get a snapshot of the content of the file so we can make sure any formatting edits didn't destroy non-whitespace characters
const oldContent = this.getFileContent(fileName);
let runningOffset = 0;
for (let i = 0; i < edits.length; i++) {
const edit = edits[i];
forEachTextChange(edits, edit => {
const offsetStart = edit.span.start;
const offsetEnd = offsetStart + edit.span.length;
this.editScriptAndUpdateMarkers(fileName, offsetStart, offsetEnd, edit.newText);
@@ -1994,14 +1973,7 @@ Actual: ${stringify(fullActual)}`);
}
}
runningOffset += editDelta;
// Update positions of any future edits affected by this change
for (let j = i + 1; j < edits.length; j++) {
if (edits[j].span.start >= edits[i].span.start) {
edits[j].span.start += editDelta;
}
}
}
});
if (isFormattingEdit) {
const newContent = this.getFileContent(fileName);
@@ -2043,30 +2015,14 @@ Actual: ${stringify(fullActual)}`);
this.languageServiceAdapterHost.editScript(fileName, editStart, editEnd, newText);
for (const marker of this.testData.markers) {
if (marker.fileName === fileName) {
marker.position = updatePosition(marker.position);
marker.position = updatePosition(marker.position, editStart, editEnd, newText);
}
}
for (const range of this.testData.ranges) {
if (range.fileName === fileName) {
range.pos = updatePosition(range.pos);
range.end = updatePosition(range.end);
}
}
function updatePosition(position: number) {
if (position > editStart) {
if (position < editEnd) {
// Inside the edit - mark it as invalidated (?)
return -1;
}
else {
// Move marker back/forward by the appropriate amount
return position + (editStart - editEnd) + newText.length;
}
}
else {
return position;
range.pos = updatePosition(range.pos, editStart, editEnd, newText);
range.end = updatePosition(range.end, editStart, editEnd, newText);
}
}
}
@@ -2347,10 +2303,7 @@ Actual: ${stringify(fullActual)}`);
public baselineCurrentFileNameOrDottedNameSpans() {
Harness.Baseline.runBaseline(
this.testData.globalOptions[MetadataOptionNames.baselineFile],
() => {
return this.baselineCurrentFileLocations(pos =>
this.getNameOrDottedNameSpan(pos)!);
});
this.baselineCurrentFileLocations(pos => this.getNameOrDottedNameSpan(pos)!));
}
public printNameOrDottedNameSpans(pos: number) {
@@ -2500,22 +2453,24 @@ Actual: ${stringify(fullActual)}`);
this.applyCodeActions(codeActions);
this.verifyNewContent(options, ts.flatMap(codeActions, a => a.changes.map(c => c.fileName)));
this.verifyNewContentAfterChange(options, ts.flatMap(codeActions, a => a.changes.map(c => c.fileName)));
}
public verifyRangeIs(expectedText: string, includeWhiteSpace?: boolean) {
this.verifyTextMatches(this.rangeText(this.getOnlyRange()), !!includeWhiteSpace, expectedText);
}
private getOnlyRange() {
const ranges = this.getRanges();
if (ranges.length !== 1) {
this.raiseError("Exactly one range should be specified in the testfile.");
}
return ts.first(ranges);
}
const actualText = this.rangeText(ranges[0]);
const result = includeWhiteSpace
? actualText === expectedText
: this.removeWhitespace(actualText) === this.removeWhitespace(expectedText);
if (!result) {
private verifyTextMatches(actualText: string, includeWhitespace: boolean, expectedText: string) {
const removeWhitespace = (s: string): string => includeWhitespace ? s : this.removeWhitespace(s);
if (removeWhitespace(actualText) !== removeWhitespace(expectedText)) {
this.raiseError(`Actual range text doesn't match expected text.\n${showTextDiff(expectedText, actualText)}`);
}
}
@@ -2582,33 +2537,68 @@ Actual: ${stringify(fullActual)}`);
const action = actions[index];
assert.equal(action.description, options.description);
assert.deepEqual(action.commands, options.commands);
for (const change of action.changes) {
this.applyEdits(change.fileName, change.textChanges, /*isFormattingEdit*/ false);
if (options.applyChanges) {
for (const change of action.changes) {
this.applyEdits(change.fileName, change.textChanges, /*isFormattingEdit*/ false);
}
this.verifyNewContentAfterChange(options, action.changes.map(c => c.fileName));
}
else {
this.verifyNewContent(options, action.changes);
}
this.verifyNewContent(options, action.changes.map(c => c.fileName));
}
private verifyNewContent(options: FourSlashInterface.NewContentOptions, changedFiles: ReadonlyArray<string>) {
const assertedChangedFiles = !options.newFileContent || typeof options.newFileContent === "string"
private verifyNewContent({ newFileContent, newRangeContent }: FourSlashInterface.NewContentOptions, changes: ReadonlyArray<ts.FileTextChanges>): void {
if (newRangeContent !== undefined) {
assert(newFileContent === undefined);
assert(changes.length === 1, "Affected 0 or more than 1 file, must use 'newFileContent' instead of 'newRangeContent'");
const change = ts.first(changes);
assert(change.fileName = this.activeFile.fileName);
const newText = ts.textChanges.applyChanges(this.getFileContent(this.activeFile.fileName), change.textChanges);
const newRange = updateTextRangeForTextChanges(this.getOnlyRange(), change.textChanges);
const actualText = newText.slice(newRange.pos, newRange.end);
this.verifyTextMatches(actualText, /*includeWhitespace*/ true, newRangeContent);
}
else {
if (newFileContent === undefined) throw ts.Debug.fail();
if (typeof newFileContent !== "object") newFileContent = { [this.activeFile.fileName]: newFileContent };
for (const change of changes) {
const expectedNewContent = newFileContent[change.fileName];
if (expectedNewContent === undefined) {
ts.Debug.fail(`Did not expect a change in ${change.fileName}`);
}
const oldText = this.tryGetFileContent(change.fileName);
ts.Debug.assert(!!change.isNewFile === (oldText === undefined));
const newContent = change.isNewFile ? ts.first(change.textChanges).newText : ts.textChanges.applyChanges(oldText!, change.textChanges);
assert.equal(newContent, expectedNewContent);
}
for (const newFileName in newFileContent) {
ts.Debug.assert(changes.some(c => c.fileName === newFileName), "No change in file", () => newFileName);
}
}
}
private verifyNewContentAfterChange({ newFileContent, newRangeContent }: FourSlashInterface.NewContentOptions, changedFiles: ReadonlyArray<string>) {
const assertedChangedFiles = !newFileContent || typeof newFileContent === "string"
? [this.activeFile.fileName]
: ts.getOwnKeys(options.newFileContent);
: ts.getOwnKeys(newFileContent);
assert.deepEqual(assertedChangedFiles, changedFiles);
if (options.newFileContent !== undefined) {
assert(!options.newRangeContent);
if (typeof options.newFileContent === "string") {
this.verifyCurrentFileContent(options.newFileContent);
if (newFileContent !== undefined) {
assert(!newRangeContent);
if (typeof newFileContent === "string") {
this.verifyCurrentFileContent(newFileContent);
}
else {
for (const fileName in options.newFileContent) {
this.verifyFileContent(fileName, options.newFileContent[fileName]);
for (const fileName in newFileContent) {
this.verifyFileContent(fileName, newFileContent[fileName]);
}
}
}
else {
this.verifyRangeIs(options.newRangeContent!, /*includeWhitespace*/ true);
this.verifyRangeIs(newRangeContent!, /*includeWhitespace*/ true);
}
}
@@ -2985,7 +2975,7 @@ Actual: ${stringify(fullActual)}`);
}
public verifyApplicableRefactorAvailableAtMarker(negative: boolean, markerName: string) {
const isAvailable = this.getApplicableRefactors(this.getMarkerByName(markerName).position).length > 0;
const isAvailable = this.getApplicableRefactors(this.getMarkerByName(markerName)).length > 0;
if (negative && isAvailable) {
this.raiseError(`verifyApplicableRefactorAvailableAtMarker failed - expected no refactor at marker ${markerName} but found some.`);
}
@@ -3002,7 +2992,7 @@ Actual: ${stringify(fullActual)}`);
}
public verifyRefactorAvailable(negative: boolean, name: string, actionName?: string) {
let refactors = this.getApplicableRefactors(this.getSelection());
let refactors = this.getApplicableRefactorsAtSelection();
refactors = refactors.filter(r => r.name === name && (actionName === undefined || r.actions.some(a => a.name === actionName)));
const isAvailable = refactors.length > 0;
@@ -3022,11 +3012,11 @@ Actual: ${stringify(fullActual)}`);
}
public verifyRefactorsAvailable(names: ReadonlyArray<string>): void {
assert.deepEqual(unique(this.getApplicableRefactors(this.getSelection()), r => r.name), names);
assert.deepEqual(unique(this.getApplicableRefactorsAtSelection(), r => r.name), names);
}
public verifyRefactor({ name, actionName, refactors }: FourSlashInterface.VerifyRefactorOptions) {
const actualRefactors = this.getApplicableRefactors(this.getSelection()).filter(r => r.name === name && r.actions.some(a => a.name === actionName));
const actualRefactors = this.getApplicableRefactorsAtSelection().filter(r => r.name === name && r.actions.some(a => a.name === actionName));
this.assertObjectsEqual(actualRefactors, refactors);
}
@@ -3047,7 +3037,7 @@ Actual: ${stringify(fullActual)}`);
public applyRefactor({ refactorName, actionName, actionDescription, newContent: newContentWithRenameMarker }: FourSlashInterface.ApplyRefactorOptions) {
const range = this.getSelection();
const refactors = this.getApplicableRefactors(range);
const refactors = this.getApplicableRefactorsAtSelection();
const refactorsWithName = refactors.filter(r => r.name === refactorName);
if (refactorsWithName.length === 0) {
this.raiseError(`The expected refactor: ${refactorName} is not available at the marker location.\nAvailable refactors: ${refactors.map(r => r.name)}`);
@@ -3125,8 +3115,8 @@ Actual: ${stringify(fullActual)}`);
const action = ts.first(refactor.actions);
assert(action.name === "Move to a new file" && action.description === "Move to a new file");
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, this.formatCodeSettings, range, refactor.name, action.name, options.preferences || ts.emptyOptions)!;
this.testNewFileContents(editInfo.edits, options.newFileContents, "move to new file");
const editInfo = this.languageService.getEditsForRefactor(range.fileName, this.formatCodeSettings, range, refactor.name, action.name, options.preferences || ts.emptyOptions)!;
this.verifyNewContent({ newFileContent: options.newFileContents }, editInfo.edits);
}
private testNewFileContents(edits: ReadonlyArray<ts.FileTextChanges>, newFileContents: { [fileName: string]: string }, description: string): void {
@@ -3165,21 +3155,21 @@ Actual: ${stringify(fullActual)}`);
formattingOptions?: ts.FormatCodeSettings) {
formattingOptions = formattingOptions || this.formatCodeSettings;
const markerPos = this.getMarkerByName(markerName).position;
const marker = this.getMarkerByName(markerName);
const applicableRefactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, markerPos, ts.emptyOptions);
const applicableRefactors = this.languageService.getApplicableRefactors(this.activeFile.fileName, marker.position, ts.emptyOptions);
const applicableRefactorToApply = ts.find(applicableRefactors, refactor => refactor.name === refactorNameToApply);
if (!applicableRefactorToApply) {
this.raiseError(`The expected refactor: ${refactorNameToApply} is not available at the marker location.`);
}
const editInfo = this.languageService.getEditsForRefactor(this.activeFile.fileName, formattingOptions, markerPos, refactorNameToApply, actionName, ts.emptyOptions)!;
const editInfo = this.languageService.getEditsForRefactor(marker.fileName, formattingOptions, marker.position, refactorNameToApply, actionName, ts.emptyOptions)!;
for (const edit of editInfo.edits) {
this.applyEdits(edit.fileName, edit.textChanges, /*isFormattingEdit*/ false);
}
const actualContent = this.getFileContent(this.activeFile.fileName);
const actualContent = this.getFileContent(marker.fileName);
if (actualContent !== expectedContent) {
this.raiseError(`verifyFileAfterApplyingRefactors failed:\n${showTextDiff(expectedContent, actualContent)}`);
@@ -3381,9 +3371,45 @@ Actual: ${stringify(fullActual)}`);
test(renameKeys(newFileContents, key => pathUpdater(key) || key), "with file moved");
}
private getApplicableRefactors(positionOrRange: number | ts.TextRange, preferences = ts.emptyOptions): ReadonlyArray<ts.ApplicableRefactorInfo> {
return this.languageService.getApplicableRefactors(this.activeFile.fileName, positionOrRange, preferences) || ts.emptyArray;
private getApplicableRefactorsAtSelection() {
return this.getApplicableRefactorsWorker(this.getSelection(), this.activeFile.fileName);
}
private getApplicableRefactors(rangeOrMarker: Range | Marker, preferences = ts.emptyOptions): ReadonlyArray<ts.ApplicableRefactorInfo> {
return this.getApplicableRefactorsWorker("position" in rangeOrMarker ? rangeOrMarker.position : rangeOrMarker, rangeOrMarker.fileName, preferences);
}
private getApplicableRefactorsWorker(positionOrRange: number | ts.TextRange, fileName: string, preferences = ts.emptyOptions): ReadonlyArray<ts.ApplicableRefactorInfo> {
return this.languageService.getApplicableRefactors(fileName, positionOrRange, preferences) || ts.emptyArray;
}
}
function updateTextRangeForTextChanges({ pos, end }: ts.TextRange, textChanges: ReadonlyArray<ts.TextChange>): ts.TextRange {
forEachTextChange(textChanges, change => {
const update = (p: number): number => updatePosition(p, change.span.start, ts.textSpanEnd(change.span), change.newText);
pos = update(pos);
end = update(end);
});
return { pos, end };
}
/** Apply each textChange in order, updating future changes to account for the text offset of previous changes. */
function forEachTextChange(changes: ReadonlyArray<ts.TextChange>, cb: (change: ts.TextChange) => void): void {
// Copy this so we don't ruin someone else's copy
changes = JSON.parse(JSON.stringify(changes));
for (let i = 0; i < changes.length; i++) {
const change = changes[i];
cb(change);
const changeDelta = change.newText.length - change.span.length;
for (let j = i + 1; j < changes.length; j++) {
if (changes[j].span.start >= change.span.start) {
changes[j].span.start += changeDelta;
}
}
}
}
function updatePosition(position: number, editStart: number, editEnd: number, { length }: string): number {
// If inside the edit, return -1 to mark as invalid
return position <= editStart ? position : position < editEnd ? -1 : position + length - + (editEnd - editStart);
}
function renameKeys<T>(obj: { readonly [key: string]: T }, renameKey: (key: string) => string): { readonly [key: string]: T } {
@@ -4764,6 +4790,7 @@ namespace FourSlashInterface {
export type ExpectedCompletionEntry = string | {
readonly name: string,
readonly source?: string,
readonly insertText?: string,
readonly replacementSpan?: FourSlash.Range,
readonly hasAction?: boolean, // If not specified, will assert that this is false.
@@ -4848,10 +4875,12 @@ namespace FourSlashInterface {
}
export interface VerifyCodeFixOptions extends NewContentOptions {
description: string;
errorCode?: number;
index?: number;
preferences?: ts.UserPreferences;
readonly description: string;
readonly errorCode?: number;
readonly index?: number;
readonly preferences?: ts.UserPreferences;
readonly applyChanges?: boolean;
readonly commands?: ReadonlyArray<ts.CodeActionCommand>;
}
export interface VerifyCodeFixAvailableOptions {
+54 -77
View File
@@ -1483,17 +1483,12 @@ namespace Harness {
}
export function doErrorBaseline(baselinePath: string, inputFiles: ReadonlyArray<TestFile>, errors: ReadonlyArray<ts.Diagnostic>, pretty?: boolean) {
Baseline.runBaseline(baselinePath.replace(/\.tsx?$/, ".errors.txt"), (): string | null => {
if (!errors || (errors.length === 0)) {
/* tslint:disable:no-null-keyword */
return null;
/* tslint:enable:no-null-keyword */
}
return getErrorBaseline(inputFiles, errors, pretty);
});
Baseline.runBaseline(baselinePath.replace(/\.tsx?$/, ".errors.txt"),
// tslint:disable-next-line no-null-keyword
!errors || (errors.length === 0) ? null : getErrorBaseline(inputFiles, errors, pretty));
}
export function doTypeAndSymbolBaseline(baselinePath: string, program: ts.Program, allFiles: {unitName: string, content: string}[], opts?: Baseline.BaselineOptions, multifile?: boolean, skipTypeBaselines?: boolean, skipSymbolBaselines?: boolean) {
export function doTypeAndSymbolBaseline(baselinePath: string, program: ts.Program, allFiles: {unitName: string, content: string}[], opts?: Baseline.BaselineOptions, multifile?: boolean, skipTypeBaselines?: boolean, skipSymbolBaselines?: boolean, hasErrorBaseline?: boolean) {
// The full walker simulates the types that you would get from doing a full
// compile. The pull walker simulates the types you get when you just do
// a type query for a random node (like how the LS would do it). Most of the
@@ -1509,7 +1504,7 @@ namespace Harness {
// These types are equivalent, but depend on what order the compiler observed
// certain parts of the program.
const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true);
const fullWalker = new TypeWriterWalker(program, /*fullTypeCheck*/ true, !!hasErrorBaseline);
// Produce baselines. The first gives the types for all expressions.
// The second gives symbols for all identifiers.
@@ -1552,7 +1547,7 @@ namespace Harness {
if (!multifile) {
const fullBaseLine = generateBaseLine(isSymbolBaseLine, isSymbolBaseLine ? skipSymbolBaselines : skipTypeBaselines);
Baseline.runBaseline(outputFileName + fullExtension, () => fullBaseLine, opts);
Baseline.runBaseline(outputFileName + fullExtension, fullBaseLine, opts);
}
else {
Baseline.runMultifileBaseline(outputFileName, fullExtension, () => {
@@ -1637,22 +1632,21 @@ namespace Harness {
throw new Error("Number of sourcemap files should be same as js files.");
}
Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ".js.map"), () => {
if ((options.noEmitOnError && result.diagnostics.length !== 0) || result.maps.size === 0) {
// We need to return null here or the runBaseLine will actually create a empty file.
// Baselining isn't required here because there is no output.
/* tslint:disable:no-null-keyword */
return null;
/* tslint:enable:no-null-keyword */
}
let sourceMapCode = "";
let sourceMapCode: string | null;
if ((options.noEmitOnError && result.diagnostics.length !== 0) || result.maps.size === 0) {
// We need to return null here or the runBaseLine will actually create a empty file.
// Baselining isn't required here because there is no output.
/* tslint:disable:no-null-keyword */
sourceMapCode = null;
/* tslint:enable:no-null-keyword */
}
else {
sourceMapCode = "";
result.maps.forEach(sourceMap => {
sourceMapCode += fileOutput(sourceMap, harnessSettings);
});
return sourceMapCode;
});
}
Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ".js.map"), sourceMapCode);
}
}
@@ -1662,49 +1656,40 @@ namespace Harness {
}
// check js output
Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ts.Extension.Js), () => {
let tsCode = "";
const tsSources = otherFiles.concat(toBeCompiled);
if (tsSources.length > 1) {
tsCode += "//// [" + header + "] ////\r\n\r\n";
}
for (let i = 0; i < tsSources.length; i++) {
tsCode += "//// [" + ts.getBaseFileName(tsSources[i].unitName) + "]\r\n";
tsCode += tsSources[i].content + (i < (tsSources.length - 1) ? "\r\n" : "");
}
let tsCode = "";
const tsSources = otherFiles.concat(toBeCompiled);
if (tsSources.length > 1) {
tsCode += "//// [" + header + "] ////\r\n\r\n";
}
for (let i = 0; i < tsSources.length; i++) {
tsCode += "//// [" + ts.getBaseFileName(tsSources[i].unitName) + "]\r\n";
tsCode += tsSources[i].content + (i < (tsSources.length - 1) ? "\r\n" : "");
}
let jsCode = "";
result.js.forEach(file => {
jsCode += fileOutput(file, harnessSettings);
});
if (result.dts.size > 0) {
jsCode += "\r\n\r\n";
result.dts.forEach(declFile => {
jsCode += fileOutput(declFile, harnessSettings);
});
}
const declFileContext = prepareDeclarationCompilationContext(
toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined
);
const declFileCompilationResult = compileDeclarationFiles(declFileContext, result.symlinks);
if (declFileCompilationResult && declFileCompilationResult.declResult.diagnostics.length) {
jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n";
jsCode += "\r\n\r\n";
jsCode += getErrorBaseline(tsConfigFiles.concat(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.diagnostics);
}
if (jsCode.length > 0) {
return tsCode + "\r\n\r\n" + jsCode;
}
else {
/* tslint:disable:no-null-keyword */
return null;
/* tslint:enable:no-null-keyword */
}
let jsCode = "";
result.js.forEach(file => {
jsCode += fileOutput(file, harnessSettings);
});
if (result.dts.size > 0) {
jsCode += "\r\n\r\n";
result.dts.forEach(declFile => {
jsCode += fileOutput(declFile, harnessSettings);
});
}
const declFileContext = prepareDeclarationCompilationContext(
toBeCompiled, otherFiles, result, harnessSettings, options, /*currentDirectory*/ undefined
);
const declFileCompilationResult = compileDeclarationFiles(declFileContext, result.symlinks);
if (declFileCompilationResult && declFileCompilationResult.declResult.diagnostics.length) {
jsCode += "\r\n\r\n//// [DtsFileErrors]\r\n";
jsCode += "\r\n\r\n";
jsCode += getErrorBaseline(tsConfigFiles.concat(declFileCompilationResult.declInputFiles, declFileCompilationResult.declOtherFiles), declFileCompilationResult.declResult.diagnostics);
}
Baseline.runBaseline(baselinePath.replace(/\.tsx?/, ts.Extension.Js), jsCode.length > 0 ? tsCode + "\r\n\r\n" + jsCode : null); // tslint:disable-line no-null-keyword
}
function fileOutput(file: documents.TextDocument, harnessSettings: TestCaseParser.CompilerSettings): string {
@@ -2027,16 +2012,6 @@ namespace Harness {
}
const fileCache: { [idx: string]: boolean } = {};
function generateActual(generateContent: () => string | null): string | null {
const actual = generateContent();
if (actual === undefined) {
throw new Error("The generated content was \"undefined\". Return \"null\" if no baselining is required.\"");
}
return actual;
}
function compareToBaseline(actual: string | null, relativeFileName: string, opts: BaselineOptions | undefined) {
// actual is now either undefined (the generator had an error), null (no file requested),
@@ -2100,9 +2075,11 @@ namespace Harness {
}
}
export function runBaseline(relativeFileName: string, generateContent: () => string | null, opts?: BaselineOptions): void {
export function runBaseline(relativeFileName: string, actual: string | null, opts?: BaselineOptions): void {
const actualFileName = localPath(relativeFileName, opts && opts.Baselinefolder, opts && opts.Subfolder);
const actual = generateActual(generateContent);
if (actual === undefined) {
throw new Error("The generated content was \"undefined\". Return \"null\" if no baselining is required.\"");
}
const comparison = compareToBaseline(actual, relativeFileName, opts);
writeComparison(comparison.expected, comparison.actual, relativeFileName, actualFileName);
}
+46 -2
View File
@@ -25,7 +25,7 @@ class TypeWriterWalker {
private checker: ts.TypeChecker;
constructor(private program: ts.Program, fullTypeCheck: boolean) {
constructor(private program: ts.Program, fullTypeCheck: boolean, private hadErrorBaseline: boolean) {
// Consider getting both the diagnostics checker and the non-diagnostics checker to verify
// they are consistent.
this.checker = fullTypeCheck
@@ -69,6 +69,26 @@ class TypeWriterWalker {
}
}
private isImportStatementName(node: ts.Node) {
if (ts.isImportSpecifier(node.parent) && (node.parent.name === node || node.parent.propertyName === node)) return true;
if (ts.isImportClause(node.parent) && node.parent.name === node) return true;
if (ts.isImportEqualsDeclaration(node.parent) && node.parent.name === node) return true;
return false;
}
private isExportStatementName(node: ts.Node) {
if (ts.isExportAssignment(node.parent) && node.parent.expression === node) return true;
if (ts.isExportSpecifier(node.parent) && (node.parent.name === node || node.parent.propertyName === node)) return true;
return false;
}
private isIntrinsicJsxTag(node: ts.Node) {
const p = node.parent;
if (!(ts.isJsxOpeningElement(p) || ts.isJsxClosingElement(p) || ts.isJsxSelfClosingElement(p))) return false;
if (p.tagName !== node) return false;
return ts.isIntrinsicJsxName(node.getText());
}
private writeTypeOrSymbol(node: ts.Node, isSymbolWalk: boolean): TypeWriterResult | undefined {
const actualPos = ts.skipTrivia(this.currentSourceFile.text, node.pos);
const lineAndCharacter = this.currentSourceFile.getLineAndCharacterOfPosition(actualPos);
@@ -85,7 +105,31 @@ class TypeWriterWalker {
// let type = this.checker.getTypeAtLocation(node);
let type = ts.isExpressionWithTypeArgumentsInClassExtendsClause(node.parent) ? this.checker.getTypeAtLocation(node.parent) : undefined;
if (!type || type.flags & ts.TypeFlags.Any) type = this.checker.getTypeAtLocation(node);
const typeString = this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.AllowUniqueESSymbolType);
const typeString =
// Distinguish `errorType`s from `any`s; but only if the file has no errors.
// Additionally,
// * the LHS of a qualified name
// * a binding pattern name
// * labels
// * the "global" in "declare global"
// * the "target" in "new.target"
// * names in import statements
// * type-only names in export statements
// * and intrinsic jsx tag names
// return `error`s via `getTypeAtLocation`
// But this is generally expected, so we don't call those out, either
(!this.hadErrorBaseline &&
type.flags & ts.TypeFlags.Any &&
!ts.isBindingElement(node.parent) &&
!ts.isPropertyAccessOrQualifiedName(node.parent) &&
!ts.isLabelName(node) &&
!(ts.isModuleDeclaration(node.parent) && ts.isGlobalScopeAugmentation(node.parent)) &&
!ts.isMetaProperty(node.parent) &&
!this.isImportStatementName(node) &&
!this.isExportStatementName(node) &&
!this.isIntrinsicJsxTag(node)) ?
(type as ts.IntrinsicType).intrinsicName :
this.checker.typeToString(type, node.parent, ts.TypeFormatFlags.NoTruncation | ts.TypeFormatFlags.AllowUniqueESSymbolType);
return {
line: lineAndCharacter.line,
syntaxKind: node.kind,
+11 -3
View File
@@ -620,14 +620,14 @@ interface Array<T> {}`
}
}
removeFile(filePath: string) {
deleteFile(filePath: string) {
const path = this.toFullPath(filePath);
const currentEntry = this.fs.get(path) as FsFile;
Debug.assert(isFsFile(currentEntry));
this.removeFileOrFolder(currentEntry, returnFalse);
}
removeFolder(folderPath: string, recursive?: boolean) {
deleteFolder(folderPath: string, recursive?: boolean) {
const path = this.toFullPath(folderPath);
const currentEntry = this.fs.get(path) as FsFolder;
Debug.assert(isFsFolder(currentEntry));
@@ -635,7 +635,7 @@ interface Array<T> {}`
const subEntries = currentEntry.entries.slice();
subEntries.forEach(fsEntry => {
if (isFsFolder(fsEntry)) {
this.removeFolder(fsEntry.fullPath, recursive);
this.deleteFolder(fsEntry.fullPath, recursive);
}
else {
this.removeFileOrFolder(fsEntry, returnFalse);
@@ -766,6 +766,14 @@ interface Array<T> {}`
return (fsEntry && fsEntry.modifiedTime)!; // TODO: GH#18217
}
setModifiedTime(s: string, date: Date) {
const path = this.toFullPath(s);
const fsEntry = this.fs.get(path);
if (fsEntry) {
fsEntry.modifiedTime = date;
}
}
readFile(s: string): string | undefined {
const fsEntry = this.getRealFile(this.toFullPath(s));
return fsEntry ? fsEntry.content : undefined;
+10
View File
@@ -1378,6 +1378,16 @@ type Extract<T, U> = T extends U ? T : never;
*/
type NonNullable<T> = T extends null | undefined ? never : T;
/**
* Obtain the parameters of a function type in a tuple
*/
type Parameters<T extends (...args: any[]) => any> = T extends (...args: infer P) => any ? P : never;
/**
* Obtain the parameters of a constructor function type in a tuple
*/
type ConstructorParameters<T extends new (...args: any[]) => any> = T extends new (...args: infer P) => any ? P : never;
/**
* Obtain the return type of a function type
*/
+2 -2
View File
@@ -11,7 +11,7 @@ interface ReadonlyArray<T> {
* thisArg is omitted, undefined is used as the this value.
*/
flatMap<U, This = undefined> (
callback: (this: This, value: T, index: number, array: T[]) => U|U[],
callback: (this: This, value: T, index: number, array: T[]) => U|ReadonlyArray<U>,
thisArg?: This
): U[]
@@ -125,7 +125,7 @@ interface Array<T> {
* thisArg is omitted, undefined is used as the this value.
*/
flatMap<U, This = undefined> (
callback: (this: This, value: T, index: number, array: T[]) => U|U[],
callback: (this: This, value: T, index: number, array: T[]) => U|ReadonlyArray<U>,
thisArg?: This
): U[]
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+193 -107
View File
@@ -5,6 +5,8 @@ namespace ts.server {
// tslint:disable variable-name
export const ProjectsUpdatedInBackgroundEvent = "projectsUpdatedInBackground";
export const SurveyReady = "surveyReady";
export const LargeFileReferencedEvent = "largeFileReferenced";
export const ConfigFileDiagEvent = "configFileDiag";
export const ProjectLanguageServiceStateEvent = "projectLanguageServiceState";
export const ProjectInfoTelemetryEvent = "projectInfo";
@@ -16,6 +18,16 @@ namespace ts.server {
data: { openFiles: string[]; };
}
export interface SurveyReady {
eventName: typeof SurveyReady;
data: { surveyId: string; };
}
export interface LargeFileReferencedEvent {
eventName: typeof LargeFileReferencedEvent;
data: { file: string; fileSize: number; maxFileSize: number; };
}
export interface ConfigFileDiagEvent {
eventName: typeof ConfigFileDiagEvent;
data: { triggerFile: string, configFileName: string, diagnostics: ReadonlyArray<Diagnostic> };
@@ -92,7 +104,7 @@ namespace ts.server {
readonly checkJs: boolean;
}
export type ProjectServiceEvent = ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
export type ProjectServiceEvent = LargeFileReferencedEvent | SurveyReady | ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
export type ProjectServiceEventHandler = (event: ProjectServiceEvent) => void;
@@ -212,9 +224,15 @@ namespace ts.server {
}
}
/*@internal*/
export function convertUserPreferences(preferences: protocol.UserPreferences): UserPreferences {
const { lazyConfiguredProjectsFromExternalProject, ...userPreferences } = preferences;
return userPreferences;
}
export interface HostConfiguration {
formatCodeOptions: FormatCodeSettings;
preferences: UserPreferences;
preferences: protocol.UserPreferences;
hostInfo: string;
extraFileExtensions?: FileExtensionInfo[];
}
@@ -344,6 +362,12 @@ namespace ts.server {
return project.dirty && project.updateGraph();
}
function setProjectOptionsUsed(project: ConfiguredProject | ExternalProject) {
if (project.projectKind === ProjectKind.Configured) {
(project as ConfiguredProject).projectOptions = true;
}
}
export class ProjectService {
/*@internal*/
@@ -444,6 +468,9 @@ namespace ts.server {
/** Tracks projects that we have already sent telemetry for. */
private readonly seenProjects = createMap<true>();
/** Tracks projects that we have already sent survey events for. */
private readonly seenSurveyProjects = createMap<true>();
/*@internal*/
readonly watchFactory: WatchFactory<WatchType, Project>;
@@ -645,6 +672,27 @@ namespace ts.server {
this.eventHandler(event);
}
/* @internal */
sendSurveyReadyEvent(surveyId: string) {
if (!this.eventHandler) {
return;
}
this.eventHandler({ eventName: SurveyReady, data: { surveyId } });
}
/* @internal */
sendLargeFileReferencedEvent(file: string, fileSize: number) {
if (!this.eventHandler) {
return;
}
const event: LargeFileReferencedEvent = {
eventName: LargeFileReferencedEvent,
data: { file, fileSize, maxFileSize }
};
this.eventHandler(event);
}
/* @internal */
delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(project: Project) {
this.delayUpdateProjectGraph(project);
@@ -777,7 +825,7 @@ namespace ts.server {
return info && info.getFormatCodeSettings() || this.hostConfiguration.formatCodeOptions;
}
getPreferences(file: NormalizedPath): UserPreferences {
getPreferences(file: NormalizedPath): protocol.UserPreferences {
const info = this.getScriptInfoForNormalizedPath(file);
return info && info.getPreferences() || this.hostConfiguration.preferences;
}
@@ -786,7 +834,7 @@ namespace ts.server {
return this.hostConfiguration.formatCodeOptions;
}
getHostPreferences(): UserPreferences {
getHostPreferences(): protocol.UserPreferences {
return this.hostConfiguration.preferences;
}
@@ -1385,47 +1433,6 @@ namespace ts.server {
return findProjectByName(projectFileName, this.externalProjects);
}
private convertConfigFileContentToProjectOptions(configFilename: string, cachedDirectoryStructureHost: CachedDirectoryStructureHost) {
configFilename = normalizePath(configFilename);
const configFileContent = this.host.readFile(configFilename)!; // TODO: GH#18217
const result = parseJsonText(configFilename, configFileContent);
if (!result.endOfFileToken) {
result.endOfFileToken = <EndOfFileToken>{ kind: SyntaxKind.EndOfFileToken };
}
const errors = result.parseDiagnostics as Diagnostic[];
const parsedCommandLine = parseJsonSourceFileConfigFileContent(
result,
cachedDirectoryStructureHost,
getDirectoryPath(configFilename),
/*existingOptions*/ {},
configFilename,
/*resolutionStack*/[],
this.hostConfiguration.extraFileExtensions);
if (parsedCommandLine.errors.length) {
errors.push(...parsedCommandLine.errors);
}
Debug.assert(!!parsedCommandLine.fileNames);
const projectOptions: ProjectOptions = {
files: parsedCommandLine.fileNames,
compilerOptions: parsedCommandLine.options,
configHasExtendsProperty: parsedCommandLine.raw.extends !== undefined,
configHasFilesProperty: parsedCommandLine.raw.files !== undefined,
configHasIncludeProperty: parsedCommandLine.raw.include !== undefined,
configHasExcludeProperty: parsedCommandLine.raw.exclude !== undefined,
wildcardDirectories: createMapFromTemplate(parsedCommandLine.wildcardDirectories!), // TODO: GH#18217
typeAcquisition: parsedCommandLine.typeAcquisition,
compileOnSave: parsedCommandLine.compileOnSave,
projectReferences: parsedCommandLine.projectReferences
};
return { projectOptions, configFileErrors: errors, configFileSpecs: parsedCommandLine.configFileSpecs };
}
/** Get a filename if the language service exceeds the maximum allowed program size; otherwise returns undefined. */
private getFilenameForExceededTotalSizeLimitForNonTsFiles<T>(name: string, options: CompilerOptions | undefined, fileNames: T[], propertyReader: FilePropertyReader<T>): string | undefined {
if (options && options.disableSizeLimit || !this.host.getFileSize) {
@@ -1482,24 +1489,42 @@ namespace ts.server {
options.compileOnSave === undefined ? true : options.compileOnSave);
project.excludedFiles = excludedFiles;
this.addFilesToNonInferredProjectAndUpdateGraph(project, files, externalFilePropertyReader, typeAcquisition);
this.addFilesToNonInferredProject(project, files, externalFilePropertyReader, typeAcquisition);
this.externalProjects.push(project);
this.sendProjectTelemetry(projectFileName, project);
return project;
}
private sendProjectTelemetry(projectKey: string, project: ExternalProject | ConfiguredProject, projectOptions?: ProjectOptions): void {
if (this.seenProjects.has(projectKey)) {
/*@internal*/
sendSurveyReady(project: ExternalProject | ConfiguredProject): void {
if (this.seenSurveyProjects.has(project.projectName)) {
return;
}
this.seenProjects.set(projectKey, true);
if (project.getCompilerOptions().checkJs !== undefined) {
const name = "checkJs";
this.logger.info(`Survey ${name} is ready`);
this.sendSurveyReadyEvent(name);
this.seenSurveyProjects.set(project.projectName, true);
}
}
/*@internal*/
sendProjectTelemetry(project: ExternalProject | ConfiguredProject): void {
if (this.seenProjects.has(project.projectName)) {
setProjectOptionsUsed(project);
return;
}
this.seenProjects.set(project.projectName, true);
if (!this.eventHandler || !this.host.createSHA256Hash) {
setProjectOptionsUsed(project);
return;
}
const projectOptions = project.projectKind === ProjectKind.Configured ? (project as ConfiguredProject).projectOptions as ProjectOptions : undefined;
setProjectOptionsUsed(project);
const data: ProjectInfoTelemetryEventData = {
projectId: this.host.createSHA256Hash(projectKey),
projectId: this.host.createSHA256Hash(project.projectName),
fileStats: countEachFileTypes(project.getScriptInfos()),
compilerOptions: convertCompilerOptionsForTelemetry(project.getCompilationSettings()),
typeAcquisition: convertTypeAcquisition(project.getTypeAcquisition()),
@@ -1520,8 +1545,7 @@ namespace ts.server {
return "other";
}
const configFilePath = project instanceof ConfiguredProject ? project.getConfigFilePath() : undefined!; // TODO: GH#18217
return getBaseConfigFileName(configFilePath) || "other";
return getBaseConfigFileName(project.getConfigFilePath()) || "other";
}
function convertTypeAcquisition({ enable, include, exclude }: TypeAcquisition): ProjectInfoTypeAcquisitionData {
@@ -1533,30 +1557,19 @@ namespace ts.server {
}
}
private addFilesToNonInferredProjectAndUpdateGraph<T>(project: ConfiguredProject | ExternalProject, files: T[], propertyReader: FilePropertyReader<T>, typeAcquisition: TypeAcquisition): void {
private addFilesToNonInferredProject<T>(project: ConfiguredProject | ExternalProject, files: T[], propertyReader: FilePropertyReader<T>, typeAcquisition: TypeAcquisition): void {
this.updateNonInferredProjectFiles(project, files, propertyReader);
project.setTypeAcquisition(typeAcquisition);
// This doesnt need scheduling since its either creation or reload of the project
project.updateGraph();
}
private createConfiguredProject(configFileName: NormalizedPath) {
const cachedDirectoryStructureHost = createCachedDirectoryStructureHost(this.host, this.host.getCurrentDirectory(), this.host.useCaseSensitiveFileNames)!; // TODO: GH#18217
const { projectOptions, configFileErrors, configFileSpecs } = this.convertConfigFileContentToProjectOptions(configFileName, cachedDirectoryStructureHost);
this.logger.info(`Opened configuration file ${configFileName}`);
const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles(configFileName, projectOptions.compilerOptions, projectOptions.files!, fileNamePropertyReader); // TODO: GH#18217
const project = new ConfiguredProject(
configFileName,
this,
this.documentRegistry,
projectOptions.configHasFilesProperty,
projectOptions.compilerOptions!, // TODO: GH#18217
lastFileExceededProgramSize,
projectOptions.compileOnSave === undefined ? false : projectOptions.compileOnSave,
cachedDirectoryStructureHost,
projectOptions.projectReferences);
project.configFileSpecs = configFileSpecs;
cachedDirectoryStructureHost);
// TODO: We probably should also watch the configFiles that are extended
project.configFileWatcher = this.watchFactory.watchFile(
this.host,
@@ -1566,19 +1579,89 @@ namespace ts.server {
WatchType.ConfigFilePath,
project
);
if (!lastFileExceededProgramSize) {
project.watchWildcards(projectOptions.wildcardDirectories!); // TODO: GH#18217
}
project.setProjectErrors(configFileErrors);
const filesToAdd = projectOptions.files!.concat(project.getExternalFiles());
this.addFilesToNonInferredProjectAndUpdateGraph(project, filesToAdd, fileNamePropertyReader, projectOptions.typeAcquisition!); // TODO: GH#18217
this.configuredProjects.set(project.canonicalConfigFilePath, project);
this.setConfigFileExistenceByNewConfiguredProject(project);
this.sendProjectTelemetry(configFileName, project, projectOptions);
return project;
}
/* @internal */
private createConfiguredProjectWithDelayLoad(configFileName: NormalizedPath) {
const project = this.createConfiguredProject(configFileName);
project.pendingReload = ConfigFileProgramReloadLevel.Full;
return project;
}
/* @internal */
private createAndLoadConfiguredProject(configFileName: NormalizedPath) {
const project = this.createConfiguredProject(configFileName);
this.loadConfiguredProject(project);
return project;
}
/* @internal */
private createLoadAndUpdateConfiguredProject(configFileName: NormalizedPath) {
const project = this.createAndLoadConfiguredProject(configFileName);
project.updateGraph();
return project;
}
/**
* Read the config file of the project, and update the project root file names.
*/
/* @internal */
private loadConfiguredProject(project: ConfiguredProject) {
// Read updated contents from disk
const configFilename = normalizePath(project.getConfigFilePath());
const configFileContent = this.host.readFile(configFilename)!; // TODO: GH#18217
const result = parseJsonText(configFilename, configFileContent);
if (!result.endOfFileToken) {
result.endOfFileToken = <EndOfFileToken>{ kind: SyntaxKind.EndOfFileToken };
}
const configFileErrors = result.parseDiagnostics as Diagnostic[];
const parsedCommandLine = parseJsonSourceFileConfigFileContent(
result,
project.getCachedDirectoryStructureHost(),
getDirectoryPath(configFilename),
/*existingOptions*/ {},
configFilename,
/*resolutionStack*/[],
this.hostConfiguration.extraFileExtensions);
if (parsedCommandLine.errors.length) {
configFileErrors.push(...parsedCommandLine.errors);
}
Debug.assert(!!parsedCommandLine.fileNames);
const compilerOptions = parsedCommandLine.options;
// Update the project
if (!project.projectOptions) {
project.projectOptions = {
configHasExtendsProperty: parsedCommandLine.raw.extends !== undefined,
configHasFilesProperty: parsedCommandLine.raw.files !== undefined,
configHasIncludeProperty: parsedCommandLine.raw.include !== undefined,
configHasExcludeProperty: parsedCommandLine.raw.exclude !== undefined
};
}
project.configFileSpecs = parsedCommandLine.configFileSpecs;
project.setProjectErrors(configFileErrors);
project.updateReferences(parsedCommandLine.projectReferences);
const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles(project.canonicalConfigFilePath, compilerOptions, parsedCommandLine.fileNames, fileNamePropertyReader);
if (lastFileExceededProgramSize) {
project.disableLanguageService(lastFileExceededProgramSize);
project.stopWatchingWildCards();
}
else {
project.enableLanguageService();
project.watchWildcards(createMapFromTemplate(parsedCommandLine.wildcardDirectories!)); // TODO: GH#18217
}
project.enablePluginsWithOptions(compilerOptions);
const filesToAdd = parsedCommandLine.fileNames.concat(project.getExternalFiles());
this.updateRootAndOptionsOfNonInferredProject(project, filesToAdd, fileNamePropertyReader, compilerOptions, parsedCommandLine.typeAcquisition!, parsedCommandLine.compileOnSave!); // TODO: GH#18217
}
private updateNonInferredProjectFiles<T>(project: ExternalProject | ConfiguredProject, files: T[], propertyReader: FilePropertyReader<T>) {
const projectRootFilesMap = project.getRootFilesMap();
const newRootScriptInfoMap = createMap<ProjectRoot>();
@@ -1637,31 +1720,31 @@ namespace ts.server {
project.markAsDirty();
}
private updateNonInferredProject<T>(project: ExternalProject | ConfiguredProject, newUncheckedFiles: T[], propertyReader: FilePropertyReader<T>, newOptions: CompilerOptions, newTypeAcquisition: TypeAcquisition, compileOnSave: boolean | undefined) {
private updateRootAndOptionsOfNonInferredProject<T>(project: ExternalProject | ConfiguredProject, newUncheckedFiles: T[], propertyReader: FilePropertyReader<T>, newOptions: CompilerOptions, newTypeAcquisition: TypeAcquisition, compileOnSave: boolean | undefined) {
project.setCompilerOptions(newOptions);
// VS only set the CompileOnSaveEnabled option in the request if the option was changed recently
// therefore if it is undefined, it should not be updated.
if (compileOnSave !== undefined) {
project.compileOnSaveEnabled = compileOnSave;
}
this.addFilesToNonInferredProjectAndUpdateGraph(project, newUncheckedFiles, propertyReader, newTypeAcquisition);
this.addFilesToNonInferredProject(project, newUncheckedFiles, propertyReader, newTypeAcquisition);
}
/**
* Reload the file names from config file specs and update the project graph
*/
/*@internal*/
reloadFileNamesOfConfiguredProject(project: ConfiguredProject): boolean {
reloadFileNamesOfConfiguredProject(project: ConfiguredProject) {
const configFileSpecs = project.configFileSpecs!; // TODO: GH#18217
const configFileName = project.getConfigFilePath();
const fileNamesResult = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFileName), project.getCompilationSettings(), project.getCachedDirectoryStructureHost(), this.hostConfiguration.extraFileExtensions);
project.updateErrorOnNoInputFiles(fileNamesResult.fileNames.length !== 0);
this.updateNonInferredProjectFiles(project, fileNamesResult.fileNames, fileNamePropertyReader);
this.updateNonInferredProjectFiles(project, fileNamesResult.fileNames.concat(project.getExternalFiles()), fileNamePropertyReader);
return project.updateGraph();
}
/**
* Read the config file of the project again and update the project
* Read the config file of the project again by clearing the cache and update the project graph
*/
/* @internal */
reloadConfiguredProject(project: ConfiguredProject) {
@@ -1673,23 +1756,10 @@ namespace ts.server {
const configFileName = project.getConfigFilePath();
this.logger.info(`Reloading configured project ${configFileName}`);
// Read updated contents from disk
const { projectOptions, configFileErrors, configFileSpecs } = this.convertConfigFileContentToProjectOptions(configFileName, host);
// Load project from the disk
this.loadConfiguredProject(project);
project.updateGraph();
// Update the project
project.configFileSpecs = configFileSpecs;
project.setProjectErrors(configFileErrors);
project.updateReferences(projectOptions.projectReferences);
const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles(project.canonicalConfigFilePath, projectOptions.compilerOptions, projectOptions.files!, fileNamePropertyReader); // TODO: GH#18217
if (lastFileExceededProgramSize) {
project.disableLanguageService(lastFileExceededProgramSize);
project.stopWatchingWildCards();
}
else {
project.enableLanguageService();
project.watchWildcards(projectOptions.wildcardDirectories!); // TODO: GH#18217
}
this.updateNonInferredProject(project, projectOptions.files!, fileNamePropertyReader, projectOptions.compilerOptions!, projectOptions.typeAcquisition!, projectOptions.compileOnSave!); // TODO: GH#18217
this.sendConfigFileDiagEvent(project, configFileName);
}
@@ -1953,7 +2023,19 @@ namespace ts.server {
this.logger.info("Format host information updated");
}
if (args.preferences) {
const { lazyConfiguredProjectsFromExternalProject } = this.hostConfiguration.preferences;
this.hostConfiguration.preferences = { ...this.hostConfiguration.preferences, ...args.preferences };
if (lazyConfiguredProjectsFromExternalProject && !this.hostConfiguration.preferences.lazyConfiguredProjectsFromExternalProject) {
// Load configured projects for external projects that are pending reload
this.configuredProjects.forEach(project => {
if (project.hasExternalProjectRef() &&
project.pendingReload === ConfigFileProgramReloadLevel.Full &&
!this.pendingProjectUpdates.has(project.getProjectName())) {
this.loadConfiguredProject(project);
project.updateGraph();
}
});
}
}
if (args.extraFileExtensions) {
this.hostConfiguration.extraFileExtensions = args.extraFileExtensions;
@@ -2021,17 +2103,14 @@ namespace ts.server {
// otherwise we create a new one.
const configFileName = this.getConfigFileNameForFile(info);
if (configFileName) {
const project = this.findConfiguredProjectByProjectName(configFileName);
if (!project) {
this.createConfiguredProject(configFileName);
updatedProjects.set(configFileName, true);
}
else if (!updatedProjects.has(configFileName)) {
const project = this.findConfiguredProjectByProjectName(configFileName) || this.createConfiguredProject(configFileName);
if (!updatedProjects.has(configFileName)) {
if (delayReload) {
project.pendingReload = ConfigFileProgramReloadLevel.Full;
this.delayUpdateProjectGraph(project);
}
else {
// reload from the disk
this.reloadConfiguredProject(project);
}
updatedProjects.set(configFileName, true);
@@ -2119,7 +2198,7 @@ namespace ts.server {
const configFileName = this.getConfigFileNameForFile(originalFileInfo);
if (!configFileName) return undefined;
const configuredProject = this.findConfiguredProjectByProjectName(configFileName) || this.createConfiguredProject(configFileName);
const configuredProject = this.findConfiguredProjectByProjectName(configFileName) || this.createAndLoadConfiguredProject(configFileName);
updateProjectIfDirty(configuredProject);
// Keep this configured project as referenced from project
addOriginalConfiguredProject(configuredProject);
@@ -2169,7 +2248,7 @@ namespace ts.server {
if (configFileName) {
project = this.findConfiguredProjectByProjectName(configFileName);
if (!project) {
project = this.createConfiguredProject(configFileName);
project = this.createLoadAndUpdateConfiguredProject(configFileName);
// Send the event only if the project got created as part of this open request and info is part of the project
if (info.isOrphan()) {
// Since the file isnt part of configured project, do not send config file info
@@ -2559,7 +2638,9 @@ namespace ts.server {
externalProject.enableLanguageService();
}
// external project already exists and not config files were added - update the project and return;
this.updateNonInferredProject(externalProject, proj.rootFiles, externalFilePropertyReader, compilerOptions, proj.typeAcquisition, proj.options.compileOnSave);
// The graph update here isnt postponed since any file open operation needs all updated external projects
this.updateRootAndOptionsOfNonInferredProject(externalProject, proj.rootFiles, externalFilePropertyReader, compilerOptions, proj.typeAcquisition, proj.options.compileOnSave);
externalProject.updateGraph();
return;
}
// some config files were added to external project (that previously were not there)
@@ -2606,8 +2687,10 @@ namespace ts.server {
for (const tsconfigFile of tsConfigFiles) {
let project = this.findConfiguredProjectByProjectName(tsconfigFile);
if (!project) {
// errors are stored in the project
project = this.createConfiguredProject(tsconfigFile);
// errors are stored in the project, do not need to update the graph
project = this.getHostPreferences().lazyConfiguredProjectsFromExternalProject ?
this.createConfiguredProjectWithDelayLoad(tsconfigFile) :
this.createLoadAndUpdateConfiguredProject(tsconfigFile);
}
if (project && !contains(exisingConfigFiles, tsconfigFile)) {
// keep project alive even if no documents are opened - its lifetime is bound to the lifetime of containing external project
@@ -2617,8 +2700,11 @@ namespace ts.server {
}
else {
// no config files - remove the item from the collection
// Create external project and update its graph, do not delay update since
// any file open operation needs all updated external projects
this.externalProjectToConfiguredProjectMap.delete(proj.projectFileName);
this.createExternalProject(proj.projectFileName, rootFiles, proj.options, proj.typeAcquisition, excludedFiles);
const project = this.createExternalProject(proj.projectFileName, rootFiles, proj.options, proj.typeAcquisition, excludedFiles);
project.updateGraph();
}
}
+48 -20
View File
@@ -149,6 +149,8 @@ namespace ts.server {
*/
private projectStateVersion = 0;
protected isInitialLoadPending: () => boolean = returnFalse;
/*@internal*/
dirty = false;
@@ -1033,7 +1035,10 @@ namespace ts.server {
/* @internal */
getChangesSinceVersion(lastKnownVersion?: number): ProjectFilesWithTSDiagnostics {
updateProjectIfDirty(this);
// Update the graph only if initial configured project load is not pending
if (!this.isInitialLoadPending()) {
updateProjectIfDirty(this);
}
const info: protocol.ProjectVersionInfo = {
projectName: this.getProjectName(),
@@ -1091,9 +1096,8 @@ namespace ts.server {
this.rootFilesMap.delete(info.path);
}
protected enableGlobalPlugins() {
protected enableGlobalPlugins(options: CompilerOptions) {
const host = this.projectService.host;
const options = this.getCompilationSettings();
if (!host.require) {
this.projectService.logger.info("Plugins were requested but not running in environment that supports 'require'. Nothing will be loaded");
@@ -1244,7 +1248,7 @@ namespace ts.server {
if (!projectRootPath && !projectService.useSingleInferredProject) {
this.canonicalCurrentDirectory = projectService.toCanonicalFileName(this.currentDirectory);
}
this.enableGlobalPlugins();
this.enableGlobalPlugins(this.getCompilerOptions());
}
addRoot(info: ScriptInfo) {
@@ -1316,28 +1320,29 @@ namespace ts.server {
private projectErrors: Diagnostic[] | undefined;
private projectReferences: ReadonlyArray<ProjectReference> | undefined;
/*@internal*/
projectOptions?: ProjectOptions | true;
protected isInitialLoadPending: () => boolean = returnTrue;
/*@internal*/
constructor(configFileName: NormalizedPath,
projectService: ProjectService,
documentRegistry: DocumentRegistry,
hasExplicitListOfFiles: boolean,
compilerOptions: CompilerOptions,
lastFileExceededProgramSize: string | undefined,
public compileOnSaveEnabled: boolean,
cachedDirectoryStructureHost: CachedDirectoryStructureHost,
private projectReferences: ReadonlyArray<ProjectReference> | undefined) {
cachedDirectoryStructureHost: CachedDirectoryStructureHost) {
super(configFileName,
ProjectKind.Configured,
projectService,
documentRegistry,
hasExplicitListOfFiles,
lastFileExceededProgramSize,
compilerOptions,
compileOnSaveEnabled,
/*hasExplicitListOfFiles*/ false,
/*lastFileExceededProgramSize*/ undefined,
/*compilerOptions*/ {},
/*compileOnSaveEnabled*/ false,
cachedDirectoryStructureHost,
getDirectoryPath(configFileName));
this.canonicalConfigFilePath = asNormalizedPath(projectService.toCanonicalFileName(configFileName));
this.enablePlugins();
}
/**
@@ -1345,17 +1350,24 @@ namespace ts.server {
* @returns: true if set of files in the project stays the same and false - otherwise.
*/
updateGraph(): boolean {
this.isInitialLoadPending = returnFalse;
const reloadLevel = this.pendingReload;
this.pendingReload = ConfigFileProgramReloadLevel.None;
let result: boolean;
switch (reloadLevel) {
case ConfigFileProgramReloadLevel.Partial:
return this.projectService.reloadFileNamesOfConfiguredProject(this);
result = this.projectService.reloadFileNamesOfConfiguredProject(this);
break;
case ConfigFileProgramReloadLevel.Full:
this.projectService.reloadConfiguredProject(this);
return true;
result = true;
break;
default:
return super.updateGraph();
result = super.updateGraph();
}
this.projectService.sendProjectTelemetry(this);
this.projectService.sendSurveyReady(this);
return result;
}
/*@internal*/
@@ -1382,8 +1394,12 @@ namespace ts.server {
}
enablePlugins() {
this.enablePluginsWithOptions(this.getCompilerOptions());
}
/*@internal*/
enablePluginsWithOptions(options: CompilerOptions) {
const host = this.projectService.host;
const options = this.getCompilationSettings();
if (!host.require) {
this.projectService.logger.info("Plugins were requested but not running in environment that supports 'require'. Nothing will be loaded");
@@ -1407,7 +1423,7 @@ namespace ts.server {
}
}
this.enableGlobalPlugins();
this.enableGlobalPlugins(options);
}
/**
@@ -1505,6 +1521,11 @@ namespace ts.server {
) || false;
}
/*@internal*/
hasExternalProjectRef() {
return !!this.externalProjectRefCount;
}
getEffectiveTypeRoots() {
return getEffectiveTypeRoots(this.getCompilationSettings(), this.directoryStructureHost) || [];
}
@@ -1547,6 +1568,13 @@ namespace ts.server {
getDirectoryPath(projectFilePath || normalizeSlashes(externalProjectName)));
}
updateGraph() {
const result = super.updateGraph();
this.projectService.sendProjectTelemetry(this);
this.projectService.sendSurveyReady(this);
return result;
}
getExcludedFiles() {
return this.excludedFiles;
}
+35 -1
View File
@@ -1839,7 +1839,7 @@ namespace ts.server.protocol {
* begin with prefix.
*/
export interface CompletionsRequest extends FileLocationRequest {
command: CommandTypes.Completions;
command: CommandTypes.Completions | CommandTypes.CompletionInfo;
arguments: CompletionsRequestArgs;
}
@@ -2436,6 +2436,39 @@ namespace ts.server.protocol {
openFiles: string[];
}
export type SurveyReadyEventName = "surveyReady";
export interface SurveyReadyEvent extends Event {
event: SurveyReadyEventName;
body: SurveyReadyEventBody;
}
export interface SurveyReadyEventBody {
/** Name of the survey. This is an internal machine- and programmer-friendly name */
surveyId: string;
}
export type LargeFileReferencedEventName = "largeFileReferenced";
export interface LargeFileReferencedEvent extends Event {
event: LargeFileReferencedEventName;
body: LargeFileReferencedEventBody;
}
export interface LargeFileReferencedEventBody {
/**
* name of the large file being loaded
*/
file: string;
/**
* size of the file
*/
fileSize: number;
/**
* max file size allowed on the server
*/
maxFileSize: number;
}
/**
* Arguments for reload request.
*/
@@ -2802,6 +2835,7 @@ namespace ts.server.protocol {
readonly includeCompletionsWithInsertText?: boolean;
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
readonly allowTextChangesInNewFiles?: boolean;
readonly lazyConfiguredProjectsFromExternalProject?: boolean;
}
export interface CompilerOptions {
+22 -8
View File
@@ -39,7 +39,7 @@ namespace ts.server {
*/
private pendingReloadFromDisk: boolean;
constructor(private readonly host: ServerHost, private readonly fileName: NormalizedPath, initialVersion?: ScriptInfoVersion) {
constructor(private readonly host: ServerHost, private readonly fileName: NormalizedPath, initialVersion: ScriptInfoVersion | undefined, private readonly info: ScriptInfo) {
this.version = initialVersion || { svc: 0, text: 0 };
}
@@ -164,9 +164,20 @@ namespace ts.server {
private getFileText(tempFileName?: string) {
let text: string;
const getText = () => text === undefined ? (text = this.host.readFile(tempFileName || this.fileName) || "") : text;
const size = this.host.getFileSize ? this.host.getFileSize(tempFileName || this.fileName) : getText().length;
return size > maxFileSize ? "" : getText();
const fileName = tempFileName || this.fileName;
const getText = () => text === undefined ? (text = this.host.readFile(fileName) || "") : text;
// Only non typescript files have size limitation
if (!hasTypeScriptFileExtension(this.fileName)) {
const fileSize = this.host.getFileSize ? this.host.getFileSize(fileName) : getText().length;
if (fileSize > maxFileSize) {
Debug.assert(!!this.info.containingProjects.length);
const service = this.info.containingProjects[0].projectService;
service.logger.info(`Skipped loading contents of large file ${fileName} for info ${this.info.fileName}: fileSize: ${fileSize}`);
this.info.containingProjects[0].projectService.sendLargeFileReferencedEvent(fileName, fileSize);
return "";
}
}
return getText();
}
private switchToScriptVersionCache(): ScriptVersionCache {
@@ -223,7 +234,7 @@ namespace ts.server {
*/
readonly containingProjects: Project[] = [];
private formatSettings: FormatCodeSettings | undefined;
private preferences: UserPreferences | undefined;
private preferences: protocol.UserPreferences | undefined;
/* @internal */
fileWatcher: FileWatcher | undefined;
@@ -248,7 +259,7 @@ namespace ts.server {
initialVersion?: ScriptInfoVersion) {
this.isDynamic = isDynamicFileName(fileName);
this.textStorage = new TextStorage(host, fileName, initialVersion);
this.textStorage = new TextStorage(host, fileName, initialVersion, this);
if (hasMixedContent || this.isDynamic) {
this.textStorage.reload("");
this.realpath = this.path;
@@ -322,7 +333,7 @@ namespace ts.server {
}
getFormatCodeSettings(): FormatCodeSettings | undefined { return this.formatSettings; }
getPreferences(): UserPreferences | undefined { return this.preferences; }
getPreferences(): protocol.UserPreferences | undefined { return this.preferences; }
attachToProject(project: Project): boolean {
const isNew = !this.isAttached(project);
@@ -421,7 +432,7 @@ namespace ts.server {
}
}
setOptions(formatSettings: FormatCodeSettings, preferences: UserPreferences | undefined): void {
setOptions(formatSettings: FormatCodeSettings, preferences: protocol.UserPreferences | undefined): void {
if (formatSettings) {
if (!this.formatSettings) {
this.formatSettings = getDefaultFormatCodeSettings(this.host);
@@ -459,12 +470,15 @@ namespace ts.server {
if (this.isDynamicOrHasMixedContent()) {
this.textStorage.reload("");
this.markContainingProjectsAsDirty();
return true;
}
else {
if (this.textStorage.reloadWithFileText(tempFileName)) {
this.markContainingProjectsAsDirty();
return true;
}
}
return false;
}
/*@internal*/
+12 -9
View File
@@ -266,8 +266,6 @@ namespace ts.server {
getValue: (path: Path) => T,
projects: Projects,
action: (project: Project, value: T) => ReadonlyArray<U> | U | undefined,
comparer?: (a: U, b: U) => number,
areEqual?: (a: U, b: U) => boolean,
): U[] {
const outputs = flatMap(isArray(projects) ? projects : projects.projects, project => action(project, defaultValue));
if (!isArray(projects) && projects.symLinkedProjects) {
@@ -276,10 +274,7 @@ namespace ts.server {
outputs.push(...flatMap(projects, project => action(project, value)));
});
}
return comparer
? sortAndDeduplicate(outputs, comparer, areEqual)
: deduplicate(outputs, areEqual);
return deduplicate(outputs, equateValues);
}
function combineProjectOutputFromEveryProject<T>(projectService: ProjectService, action: (project: Project) => ReadonlyArray<T>, areEqual: (a: T, b: T) => boolean) {
@@ -559,6 +554,10 @@ namespace ts.server {
const { openFiles } = event.data;
this.projectsUpdatedInBackgroundEvent(openFiles);
break;
case LargeFileReferencedEvent:
const { file, fileSize, maxFileSize } = event.data;
this.event<protocol.LargeFileReferencedEventBody>({ file, fileSize, maxFileSize }, "largeFileReferenced");
break;
case ConfigFileDiagEvent:
const { triggerFile, configFileName: configFile, diagnostics } = event.data;
const bakedDiags = map(diagnostics, diagnostic => formatConfigFileDiag(diagnostic, /*includeFileName*/ true));
@@ -568,6 +567,10 @@ namespace ts.server {
diagnostics: bakedDiags
}, "configFileDiag");
break;
case SurveyReady:
const { surveyId } = event.data;
this.event<protocol.SurveyReadyEventBody>({ surveyId }, "surveyReady");
break;
case ProjectLanguageServiceStateEvent: {
const eventName: protocol.ProjectLanguageServiceStateEventName = "projectLanguageServiceState";
this.event<protocol.ProjectLanguageServiceStateEventBody>({
@@ -1419,7 +1422,7 @@ namespace ts.server {
const position = this.getPosition(args, scriptInfo);
const completions = project.getLanguageService().getCompletionsAtPosition(file, position, {
...this.getPreferences(file),
...convertUserPreferences(this.getPreferences(file)),
triggerCharacter: args.triggerCharacter,
includeExternalModuleExports: args.includeExternalModuleExports,
includeInsertTextCompletions: args.includeInsertTextCompletions
@@ -2348,7 +2351,7 @@ namespace ts.server {
return this.projectService.getFormatCodeOptions(file);
}
private getPreferences(file: NormalizedPath): UserPreferences {
private getPreferences(file: NormalizedPath): protocol.UserPreferences {
return this.projectService.getPreferences(file);
}
@@ -2356,7 +2359,7 @@ namespace ts.server {
return this.projectService.getHostFormatCodeOptions();
}
private getHostPreferences(): UserPreferences {
private getHostPreferences(): protocol.UserPreferences {
return this.projectService.getHostPreferences();
}
}
+1 -10
View File
@@ -120,6 +120,7 @@ namespace ts.server {
};
}
/*@internal*/
export interface ProjectOptions {
configHasExtendsProperty: boolean;
/**
@@ -128,16 +129,6 @@ namespace ts.server {
configHasFilesProperty: boolean;
configHasIncludeProperty: boolean;
configHasExcludeProperty: boolean;
projectReferences: ReadonlyArray<ProjectReference> | undefined;
/**
* these fields can be present in the project file
*/
files?: string[];
wildcardDirectories?: Map<WatchDirectoryFlags>;
compilerOptions?: CompilerOptions;
typeAcquisition?: TypeAcquisition;
compileOnSave?: boolean;
}
export function isInferredProjectName(name: string) {
@@ -0,0 +1,549 @@
/* @internal */
namespace ts.codefix {
const fixId = "convertToAsyncFunction";
const errorCodes = [Diagnostics.This_may_be_converted_to_an_async_function.code];
registerCodeFix({
errorCodes,
getCodeActions(context: CodeFixContext) {
const changes = textChanges.ChangeTracker.with(context, (t) => convertToAsyncFunction(t, context.sourceFile, context.span.start, context.program.getTypeChecker(), context));
return [createCodeFixAction(fixId, changes, Diagnostics.Convert_to_async_function, fixId, Diagnostics.Convert_all_to_async_functions)];
},
fixIds: [fixId],
getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, err) => convertToAsyncFunction(changes, err.file, err.start, context.program.getTypeChecker(), context)),
});
/*
custom type to encapsulate information for variable declarations synthesized in the refactor
numberOfUsesOriginal - number of times the variable should be assigned in the refactor
numberOfUsesSynthesized - count of how many times the variable has been assigned so far
At the end of the refactor, numberOfUsesOriginal should === numberOfUsesSynthesized
*/
interface SynthIdentifier {
identifier: Identifier;
types: Type[];
numberOfAssignmentsOriginal: number;
}
interface SymbolAndIdentifier {
identifier: Identifier;
symbol: Symbol;
}
interface Transformer {
checker: TypeChecker;
synthNamesMap: Map<SynthIdentifier>; // keys are the symbol id of the identifier
allVarNames: SymbolAndIdentifier[];
setOfExpressionsToReturn: Map<true>; // keys are the node ids of the expressions
constIdentifiers: Identifier[];
originalTypeMap: Map<Type>; // keys are the node id of the identifier
isInJSFile: boolean;
}
function convertToAsyncFunction(changes: textChanges.ChangeTracker, sourceFile: SourceFile, position: number, checker: TypeChecker, context: CodeFixContextBase): void {
// get the function declaration - returns a promise
const tokenAtPosition = getTokenAtPosition(sourceFile, position);
let functionToConvert: FunctionLikeDeclaration | undefined;
// if the parent of a FunctionLikeDeclaration is a variable declaration, the convertToAsync diagnostic will be reported on the variable name
if (isIdentifier(tokenAtPosition) && isVariableDeclaration(tokenAtPosition.parent) &&
tokenAtPosition.parent.initializer && isFunctionLikeDeclaration(tokenAtPosition.parent.initializer)) {
functionToConvert = tokenAtPosition.parent.initializer;
}
else {
functionToConvert = tryCast(getContainingFunction(getTokenAtPosition(sourceFile, position)), isFunctionLikeDeclaration);
}
if (!functionToConvert) {
return;
}
const synthNamesMap: Map<SynthIdentifier> = createMap();
const originalTypeMap: Map<Type> = createMap();
const allVarNames: SymbolAndIdentifier[] = [];
const isInJSFile = isInJavaScriptFile(functionToConvert);
const setOfExpressionsToReturn = getAllPromiseExpressionsToReturn(functionToConvert, checker);
const functionToConvertRenamed: FunctionLikeDeclaration = renameCollidingVarNames(functionToConvert, checker, synthNamesMap, context, setOfExpressionsToReturn, originalTypeMap, allVarNames);
const constIdentifiers = getConstIdentifiers(synthNamesMap);
const returnStatements = getReturnStatementsWithPromiseHandlers(functionToConvertRenamed);
const transformer = { checker, synthNamesMap, allVarNames, setOfExpressionsToReturn, constIdentifiers, originalTypeMap, isInJSFile };
if (!returnStatements.length) {
return;
}
// add the async keyword
changes.insertModifierBefore(sourceFile, SyntaxKind.AsyncKeyword, functionToConvert);
function startTransformation(node: CallExpression, nodeToReplace: Node) {
const newNodes = transformExpression(node, transformer, node);
changes.replaceNodeWithNodes(sourceFile, nodeToReplace, newNodes);
}
for (const statement of returnStatements) {
if (isCallExpression(statement)) {
startTransformation(statement, statement);
}
else {
forEachChild(statement, function visit(node: Node) {
if (isCallExpression(node)) {
startTransformation(node, statement);
}
else if (!isFunctionLike(node)) {
forEachChild(node, visit);
}
});
}
}
}
// Returns the identifiers that are never reassigned in the refactor
function getConstIdentifiers(synthNamesMap: Map<SynthIdentifier>): Identifier[] {
const constIdentifiers: Identifier[] = [];
synthNamesMap.forEach((val) => {
if (val.numberOfAssignmentsOriginal === 0) {
constIdentifiers.push(val.identifier);
}
});
return constIdentifiers;
}
/*
Finds all of the expressions of promise type that should not be saved in a variable during the refactor
*/
function getAllPromiseExpressionsToReturn(func: FunctionLikeDeclaration, checker: TypeChecker): Map<true> {
if (!func.body) {
return createMap<true>();
}
const setOfExpressionsToReturn: Map<true> = createMap<true>();
forEachChild(func.body, function visit(node: Node) {
if (isPromiseReturningExpression(node, checker, "then")) {
setOfExpressionsToReturn.set(getNodeId(node).toString(), true);
forEach((<CallExpression>node).arguments, visit);
}
else if (isPromiseReturningExpression(node, checker, "catch")) {
setOfExpressionsToReturn.set(getNodeId(node).toString(), true);
// if .catch() is the last call in the chain, move leftward in the chain until we hit something else that should be returned
forEachChild(node, visit);
}
else if (isPromiseReturningExpression(node, checker)) {
setOfExpressionsToReturn.set(getNodeId(node).toString(), true);
// don't recurse here, since we won't refactor any children or arguments of the expression
}
else {
forEachChild(node, visit);
}
});
return setOfExpressionsToReturn;
}
/*
Returns true if node is a promise returning expression
If name is not undefined, node is a promise returning call of name
*/
function isPromiseReturningExpression(node: Node, checker: TypeChecker, name?: string): boolean {
const isNodeExpression = name ? isCallExpression(node) : isExpression(node);
const isExpressionOfName = isNodeExpression && (!name || hasPropertyAccessExpressionWithName(node as CallExpression, name));
const nodeType = isExpressionOfName && checker.getTypeAtLocation(node);
return !!(nodeType && checker.getPromisedTypeOfPromise(nodeType));
}
function declaredInFile(symbol: Symbol, sourceFile: SourceFile): boolean {
return symbol.valueDeclaration && symbol.valueDeclaration.getSourceFile() === sourceFile;
}
/*
Renaming of identifiers may be neccesary as the refactor changes scopes -
This function collects all existing identifier names and names of identifiers that will be created in the refactor.
It then checks for any collisions and renames them through getSynthesizedDeepClone
*/
function renameCollidingVarNames(nodeToRename: FunctionLikeDeclaration, checker: TypeChecker, synthNamesMap: Map<SynthIdentifier>, context: CodeFixContextBase, setOfAllExpressionsToReturn: Map<true>, originalType: Map<Type>, allVarNames: SymbolAndIdentifier[]): FunctionLikeDeclaration {
const identsToRenameMap: Map<Identifier> = createMap(); // key is the symbol id
forEachChild(nodeToRename, function visit(node: Node) {
if (!isIdentifier(node)) {
forEachChild(node, visit);
return;
}
const symbol = checker.getSymbolAtLocation(node);
const isDefinedInFile = symbol && declaredInFile(symbol, context.sourceFile);
if (symbol && isDefinedInFile) {
const type = checker.getTypeAtLocation(node);
const lastCallSignature = getLastCallSignature(type, checker);
const symbolIdString = getSymbolId(symbol).toString();
// if the identifier refers to a function we want to add the new synthesized variable for the declaration (ex. blob in let blob = res(arg))
// Note - the choice of the last call signature is arbitrary
if (lastCallSignature && lastCallSignature.parameters.length && !synthNamesMap.has(symbolIdString)) {
const synthName = getNewNameIfConflict(createIdentifier(lastCallSignature.parameters[0].name), allVarNames);
synthNamesMap.set(symbolIdString, synthName);
allVarNames.push({ identifier: synthName.identifier, symbol });
}
// we only care about identifiers that are parameters and declarations (don't care about other uses)
else if (node.parent && (isParameter(node.parent) || isVariableDeclaration(node.parent))) {
// if the identifier name conflicts with a different identifier that we've already seen
if (allVarNames.some(ident => ident.identifier.text === node.text && ident.symbol !== symbol)) {
const newName = getNewNameIfConflict(node, allVarNames);
identsToRenameMap.set(symbolIdString, newName.identifier);
synthNamesMap.set(symbolIdString, newName);
allVarNames.push({ identifier: newName.identifier, symbol });
}
else {
const identifier = getSynthesizedDeepClone(node);
identsToRenameMap.set(symbolIdString, identifier);
synthNamesMap.set(symbolIdString, { identifier, types: [], numberOfAssignmentsOriginal: allVarNames.filter(elem => elem.identifier.text === node.text).length/*, numberOfAssignmentsSynthesized: 0*/ });
if ((isParameter(node.parent) && isExpressionOrCallOnTypePromise(node.parent.parent)) || isVariableDeclaration(node.parent)) {
allVarNames.push({ identifier, symbol });
}
}
}
}
});
return getSynthesizedDeepCloneWithRenames(nodeToRename, /*includeTrivia*/ true, identsToRenameMap, checker, deepCloneCallback);
function isExpressionOrCallOnTypePromise(child: Node): boolean {
const node = child.parent;
if (isCallExpression(node) || isIdentifier(node) && !setOfAllExpressionsToReturn.get(getNodeId(node).toString())) {
const nodeType = checker.getTypeAtLocation(node);
const isPromise = nodeType && checker.getPromisedTypeOfPromise(nodeType);
return !!isPromise;
}
return false;
}
function deepCloneCallback(node: Node, clone: Node) {
if (isIdentifier(node)) {
const symbol = checker.getSymbolAtLocation(node);
const symboldIdString = symbol && getSymbolId(symbol).toString();
const renameInfo = symbol && synthNamesMap.get(symboldIdString!);
if (renameInfo) {
const type = checker.getTypeAtLocation(node);
if (type) {
originalType.set(getNodeId(clone).toString(), type);
}
}
}
const val = setOfAllExpressionsToReturn.get(getNodeId(node).toString());
if (val !== undefined) {
setOfAllExpressionsToReturn.delete(getNodeId(node).toString());
setOfAllExpressionsToReturn.set(getNodeId(clone).toString(), val);
}
}
}
function getNewNameIfConflict(name: Identifier, allVarNames: SymbolAndIdentifier[]): SynthIdentifier {
const numVarsSameName = allVarNames.filter(elem => elem.identifier.text === name.text).length;
const numberOfAssignmentsOriginal = 0;
const identifier = numVarsSameName === 0 ? name : createIdentifier(name.text + "_" + numVarsSameName);
return { identifier, types: [], numberOfAssignmentsOriginal };
}
// dispatch function to recursively build the refactoring
function transformExpression(node: Expression, transformer: Transformer, outermostParent: CallExpression, prevArgName?: SynthIdentifier): Statement[] {
if (!node) {
return [];
}
const originalType = isIdentifier(node) && transformer.originalTypeMap.get(getNodeId(node).toString());
const nodeType = originalType || transformer.checker.getTypeAtLocation(node);
if (isCallExpression(node) && hasPropertyAccessExpressionWithName(node, "then") && nodeType && !!transformer.checker.getPromisedTypeOfPromise(nodeType)) {
return transformThen(node, transformer, outermostParent, prevArgName);
}
else if (isCallExpression(node) && hasPropertyAccessExpressionWithName(node, "catch") && nodeType && !!transformer.checker.getPromisedTypeOfPromise(nodeType)) {
return transformCatch(node, transformer, prevArgName);
}
else if (isPropertyAccessExpression(node)) {
return transformExpression(node.expression, transformer, outermostParent, prevArgName);
}
else if (nodeType && transformer.checker.getPromisedTypeOfPromise(nodeType)) {
return transformPromiseCall(node, transformer, prevArgName);
}
return [];
}
function transformCatch(node: CallExpression, transformer: Transformer, prevArgName?: SynthIdentifier): Statement[] {
const func = node.arguments[0];
const argName = getArgName(func, transformer);
const shouldReturn = transformer.setOfExpressionsToReturn.get(getNodeId(node).toString());
/*
If there is another call in the chain after the .catch() we are transforming, we will need to save the result of both paths (try block and catch block)
To do this, we will need to synthesize a variable that we were not aware of while we were adding identifiers to the synthNamesMap
We will use the prevArgName and then update the synthNamesMap with a new variable name for the next transformation step
*/
if (prevArgName && !shouldReturn) {
prevArgName.numberOfAssignmentsOriginal = 2; // Try block and catch block
transformer.synthNamesMap.forEach((val, key) => {
if (val.identifier.text === prevArgName.identifier.text) {
transformer.synthNamesMap.set(key, getNewNameIfConflict(prevArgName.identifier, transformer.allVarNames));
}
});
// update the constIdentifiers list
if (transformer.constIdentifiers.some(elem => elem.text === prevArgName.identifier.text)) {
transformer.constIdentifiers.push(getNewNameIfConflict(prevArgName.identifier, transformer.allVarNames).identifier);
}
}
const tryBlock = createBlock(transformExpression(node.expression, transformer, node, prevArgName));
const transformationBody = getTransformationBody(func, prevArgName, argName, node, transformer);
const catchArg = argName.identifier.text.length > 0 ? argName.identifier.text : "e";
const catchClause = createCatchClause(catchArg, createBlock(transformationBody));
/*
In order to avoid an implicit any, we will synthesize a type for the declaration using the unions of the types of both paths (try block and catch block)
*/
let varDeclList;
if (prevArgName && !shouldReturn) {
const typeArray: Type[] = prevArgName.types;
const unionType = transformer.checker.getUnionType(typeArray, UnionReduction.Subtype);
const unionTypeNode = transformer.isInJSFile ? undefined : transformer.checker.typeToTypeNode(unionType);
const varDecl = [createVariableDeclaration(getSynthesizedDeepClone(prevArgName.identifier), unionTypeNode)];
varDeclList = createVariableStatement(/*modifiers*/ undefined, createVariableDeclarationList(varDecl, NodeFlags.Let));
}
const tryStatement = createTry(tryBlock, catchClause, /*finallyBlock*/ undefined);
return varDeclList ? [varDeclList, tryStatement] : [tryStatement];
}
function transformThen(node: CallExpression, transformer: Transformer, outermostParent: CallExpression, prevArgName?: SynthIdentifier): Statement[] {
const [res, rej] = node.arguments;
if (!res) {
return transformExpression(node.expression, transformer, outermostParent);
}
const argNameRes = getArgName(res, transformer);
const transformationBody = getTransformationBody(res, prevArgName, argNameRes, node, transformer);
if (rej) {
const argNameRej = getArgName(rej, transformer);
const tryBlock = createBlock(transformExpression(node.expression, transformer, node, argNameRes).concat(transformationBody));
const transformationBody2 = getTransformationBody(rej, prevArgName, argNameRej, node, transformer);
const catchArg = argNameRej.identifier.text.length > 0 ? argNameRej.identifier.text : "e";
const catchClause = createCatchClause(catchArg, createBlock(transformationBody2));
return [createTry(tryBlock, catchClause, /* finallyBlock */ undefined) as Statement];
}
else {
return transformExpression(node.expression, transformer, node, argNameRes).concat(transformationBody);
}
return [];
}
function getFlagOfIdentifier(node: Identifier, constIdentifiers: Identifier[]): NodeFlags {
const inArr: boolean = constIdentifiers.some(elem => elem.text === node.text);
return inArr ? NodeFlags.Const : NodeFlags.Let;
}
function transformPromiseCall(node: Expression, transformer: Transformer, prevArgName?: SynthIdentifier): Statement[] {
const shouldReturn = transformer.setOfExpressionsToReturn.get(getNodeId(node).toString());
// the identifier is empty when the handler (.then()) ignores the argument - In this situation we do not need to save the result of the promise returning call
const hasPrevArgName = prevArgName && prevArgName.identifier.text.length > 0;
const originalNodeParent = node.original ? node.original.parent : node.parent;
if (hasPrevArgName && !shouldReturn && (!originalNodeParent || isPropertyAccessExpression(originalNodeParent))) {
return createVariableDeclarationOrAssignment(prevArgName!, createAwait(node), transformer).concat(); // hack to make the types match
}
else if (!hasPrevArgName && !shouldReturn && (!originalNodeParent || isPropertyAccessExpression(originalNodeParent))) {
return [createStatement(createAwait(node))];
}
return [createReturn(getSynthesizedDeepClone(node))];
}
function createVariableDeclarationOrAssignment(prevArgName: SynthIdentifier, rightHandSide: Expression, transformer: Transformer): NodeArray<Statement> {
if (prevArgName.types.length < prevArgName.numberOfAssignmentsOriginal) {
return createNodeArray([createStatement(createAssignment(getSynthesizedDeepClone(prevArgName.identifier), rightHandSide))]);
}
return createNodeArray([createVariableStatement(/*modifiers*/ undefined,
(createVariableDeclarationList([createVariableDeclaration(getSynthesizedDeepClone(prevArgName.identifier), /*type*/ undefined, rightHandSide)], getFlagOfIdentifier(prevArgName.identifier, transformer.constIdentifiers))))]);
}
function getTransformationBody(func: Node, prevArgName: SynthIdentifier | undefined, argName: SynthIdentifier, parent: CallExpression, transformer: Transformer): NodeArray<Statement> {
const hasPrevArgName = prevArgName && prevArgName.identifier.text.length > 0;
const hasArgName = argName && argName.identifier.text.length > 0;
const shouldReturn = transformer.setOfExpressionsToReturn.get(getNodeId(parent).toString());
switch (func.kind) {
case SyntaxKind.Identifier:
if (!hasArgName) break;
const synthCall = createCall(getSynthesizedDeepClone(func) as Identifier, /*typeArguments*/ undefined, [argName.identifier]);
if (shouldReturn) {
return createNodeArray([createReturn(synthCall)]);
}
if (!hasPrevArgName) break;
const type = transformer.originalTypeMap.get(getNodeId(func).toString());
const callSignatures = type && transformer.checker.getSignaturesOfType(type, SignatureKind.Call);
const returnType = callSignatures && callSignatures[0].getReturnType();
const varDeclOrAssignment = createVariableDeclarationOrAssignment(prevArgName!, createAwait(synthCall), transformer);
prevArgName!.types.push(returnType!);
return varDeclOrAssignment;
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
// Arrow functions with block bodies { } will enter this control flow
if (isFunctionLikeDeclaration(func) && func.body && isBlock(func.body) && func.body.statements) {
let refactoredStmts: Statement[] = [];
for (const statement of func.body.statements) {
if (getReturnStatementsWithPromiseHandlers(statement).length) {
refactoredStmts = refactoredStmts.concat(getInnerTransformationBody(transformer, [statement], prevArgName));
}
else {
refactoredStmts.push(statement);
}
}
return shouldReturn ? getSynthesizedDeepClones(createNodeArray(refactoredStmts)) :
removeReturns(createNodeArray(refactoredStmts), prevArgName!.identifier, transformer.constIdentifiers);
}
else {
const funcBody = (<ArrowFunction>func).body;
const innerRetStmts = getReturnStatementsWithPromiseHandlers(createReturn(funcBody as Expression));
const innerCbBody = getInnerTransformationBody(transformer, innerRetStmts, prevArgName);
if (innerCbBody.length > 0) {
return createNodeArray(innerCbBody);
}
if (hasPrevArgName && !shouldReturn) {
const type = transformer.checker.getTypeAtLocation(func);
const returnType = getLastCallSignature(type, transformer.checker).getReturnType();
const varDeclOrAssignment = createVariableDeclarationOrAssignment(prevArgName!, getSynthesizedDeepClone(funcBody) as Expression, transformer);
prevArgName!.types.push(returnType);
return varDeclOrAssignment;
}
else {
return createNodeArray([createReturn(getSynthesizedDeepClone(funcBody) as Expression)]);
}
}
break;
}
return createNodeArray([]);
}
function getLastCallSignature(type: Type, checker: TypeChecker): Signature {
const callSignatures = type && checker.getSignaturesOfType(type, SignatureKind.Call);
return callSignatures && callSignatures[callSignatures.length - 1];
}
function removeReturns(stmts: NodeArray<Statement>, prevArgName: Identifier, constIdentifiers: Identifier[]): NodeArray<Statement> {
const ret: Statement[] = [];
for (const stmt of stmts) {
if (isReturnStatement(stmt)) {
if (stmt.expression) {
ret.push(createVariableStatement(/*modifiers*/ undefined,
(createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, stmt.expression)], getFlagOfIdentifier(prevArgName, constIdentifiers)))));
}
}
else {
ret.push(getSynthesizedDeepClone(stmt));
}
}
return createNodeArray(ret);
}
function getInnerTransformationBody(transformer: Transformer, innerRetStmts: Node[], prevArgName?: SynthIdentifier) {
let innerCbBody: Statement[] = [];
for (const stmt of innerRetStmts) {
forEachChild(stmt, function visit(node: Node) {
if (isCallExpression(node)) {
const temp = transformExpression(node, transformer, node, prevArgName);
innerCbBody = innerCbBody.concat(temp);
if (innerCbBody.length > 0) {
return;
}
}
else if (!isFunctionLike(node)) {
forEachChild(node, visit);
}
});
}
return innerCbBody;
}
function hasPropertyAccessExpressionWithName(node: CallExpression, funcName: string): boolean {
if (!isPropertyAccessExpression(node.expression)) {
return false;
}
return node.expression.name.text === funcName;
}
function getArgName(funcNode: Node, transformer: Transformer): SynthIdentifier {
const numberOfAssignmentsOriginal = 0;
const types: Type[] = [];
let name: SynthIdentifier | undefined;
if (isFunctionLikeDeclaration(funcNode)) {
if (funcNode.parameters.length > 0) {
const param = funcNode.parameters[0].name as Identifier;
name = getMapEntryIfExists(param);
}
}
else if (isCallExpression(funcNode) && funcNode.arguments.length > 0 && isIdentifier(funcNode.arguments[0])) {
name = { identifier: funcNode.arguments[0] as Identifier, types, numberOfAssignmentsOriginal };
}
else if (isIdentifier(funcNode)) {
name = getMapEntryIfExists(funcNode);
}
if (!name || name.identifier === undefined || name.identifier.text === "_" || name.identifier.text === "undefined") {
return { identifier: createIdentifier(""), types, numberOfAssignmentsOriginal };
}
return name;
function getMapEntryIfExists(identifier: Identifier): SynthIdentifier {
const originalNode = getOriginalNode(identifier);
const symbol = getSymbol(originalNode);
if (!symbol) {
return { identifier, types, numberOfAssignmentsOriginal };
}
const mapEntry = transformer.synthNamesMap.get(getSymbolId(symbol).toString());
return mapEntry || { identifier, types, numberOfAssignmentsOriginal };
}
function getSymbol(node: Node): Symbol | undefined {
return node.symbol ? node.symbol : transformer.checker.getSymbolAtLocation(node);
}
function getOriginalNode(node: Node): Node {
return node.original ? node.original : node;
}
}
}
+1 -1
View File
@@ -208,7 +208,7 @@ namespace ts.codefix {
return replacement[1];
}
else {
changes.replaceRangeWithText(sourceFile, createTextRange(left.getStart(sourceFile), right.pos), "export default");
changes.replaceRangeWithText(sourceFile, createRange(left.getStart(sourceFile), right.pos), "export default");
return true;
}
}
+66 -67
View File
@@ -12,16 +12,16 @@ namespace ts.codefix {
const info = getInfo(context.sourceFile, context.span.start, context.program.getTypeChecker());
if (!info) return undefined;
if (info.kind === InfoKind.enum) {
if (info.kind === InfoKind.Enum) {
const { token, parentDeclaration } = info;
const changes = textChanges.ChangeTracker.with(context, t => addEnumMemberDeclaration(t, context.program.getTypeChecker(), token, parentDeclaration));
return [createCodeFixAction(fixName, changes, [Diagnostics.Add_missing_enum_member_0, token.text], fixId, Diagnostics.Add_all_missing_members)];
}
const { parentDeclaration, classDeclarationSourceFile, inJs, makeStatic, token, call } = info;
const methodCodeAction = call && getActionForMethodDeclaration(context, classDeclarationSourceFile, parentDeclaration, token, call, makeStatic, inJs, context.preferences);
const addMember = inJs ?
singleElementArray(getActionsForAddMissingMemberInJavaScriptFile(context, classDeclarationSourceFile, parentDeclaration, token.text, makeStatic)) :
getActionsForAddMissingMemberInTypeScriptFile(context, classDeclarationSourceFile, parentDeclaration, token, makeStatic);
const { parentDeclaration, declSourceFile, inJs, makeStatic, token, call } = info;
const methodCodeAction = call && getActionForMethodDeclaration(context, declSourceFile, parentDeclaration, token, call, makeStatic, inJs, context.preferences);
const addMember = inJs && !isInterfaceDeclaration(parentDeclaration) ?
singleElementArray(getActionsForAddMissingMemberInJavaScriptFile(context, declSourceFile, parentDeclaration, token.text, makeStatic)) :
getActionsForAddMissingMemberInTypeScriptFile(context, declSourceFile, parentDeclaration, token, makeStatic);
return concatenate(singleElementArray(methodCodeAction), addMember);
},
fixIds: [fixId],
@@ -30,7 +30,7 @@ namespace ts.codefix {
const checker = program.getTypeChecker();
const seen = createMap<true>();
const classToMembers = new NodeMap<ClassLikeDeclaration, ClassInfo[]>();
const typeDeclToMembers = new NodeMap<ClassOrInterface, ClassOrInterfaceInfo[]>();
return createCombinedCodeActions(textChanges.ChangeTracker.with(context, changes => {
eachDiagnostic(context, errorCodes, diag => {
@@ -39,39 +39,39 @@ namespace ts.codefix {
return;
}
if (info.kind === InfoKind.enum) {
if (info.kind === InfoKind.Enum) {
const { token, parentDeclaration } = info;
addEnumMemberDeclaration(changes, checker, token, parentDeclaration);
}
else {
const { parentDeclaration, token } = info;
const infos = classToMembers.getOrUpdate(parentDeclaration, () => []);
const infos = typeDeclToMembers.getOrUpdate(parentDeclaration, () => []);
if (!infos.some(i => i.token.text === token.text)) infos.push(info);
}
});
classToMembers.forEach((infos, classDeclaration) => {
const superClasses = getAllSuperClasses(classDeclaration, checker);
typeDeclToMembers.forEach((infos, classDeclaration) => {
const supers = getAllSupers(classDeclaration, checker);
for (const info of infos) {
// If some superclass added this property, don't add it again.
if (superClasses.some(superClass => {
const superInfos = classToMembers.get(superClass);
if (supers.some(superClassOrInterface => {
const superInfos = typeDeclToMembers.get(superClassOrInterface);
return !!superInfos && superInfos.some(({ token }) => token.text === info.token.text);
})) continue;
const { parentDeclaration, classDeclarationSourceFile, inJs, makeStatic, token, call } = info;
const { parentDeclaration, declSourceFile, inJs, makeStatic, token, call } = info;
// Always prefer to add a method declaration if possible.
if (call) {
addMethodDeclaration(context, changes, classDeclarationSourceFile, parentDeclaration, token, call, makeStatic, inJs, preferences);
addMethodDeclaration(context, changes, declSourceFile, parentDeclaration, token, call, makeStatic, inJs, preferences);
}
else {
if (inJs) {
addMissingMemberInJs(changes, classDeclarationSourceFile, parentDeclaration, token.text, makeStatic);
if (inJs && !isInterfaceDeclaration(parentDeclaration)) {
addMissingMemberInJs(changes, declSourceFile, parentDeclaration, token.text, makeStatic);
}
else {
const typeNode = getTypeNode(program.getTypeChecker(), parentDeclaration, token);
addPropertyDeclaration(changes, classDeclarationSourceFile, parentDeclaration, token.text, typeNode, makeStatic);
addPropertyDeclaration(changes, declSourceFile, parentDeclaration, token.text, typeNode, makeStatic);
}
}
}
@@ -80,37 +80,35 @@ namespace ts.codefix {
},
});
function getAllSuperClasses(cls: ClassLikeDeclaration | undefined, checker: TypeChecker): ReadonlyArray<ClassLikeDeclaration> {
function getAllSupers(decl: ClassOrInterface | undefined, checker: TypeChecker): ReadonlyArray<ClassOrInterface> {
const res: ClassLikeDeclaration[] = [];
while (cls) {
const superElement = getClassExtendsHeritageElement(cls);
while (decl) {
const superElement = getClassExtendsHeritageElement(decl);
const superSymbol = superElement && checker.getSymbolAtLocation(superElement.expression);
const superDecl = superSymbol && find(superSymbol.declarations, isClassLike);
if (superDecl) { res.push(superDecl); }
cls = superDecl;
decl = superDecl;
}
return res;
}
interface InfoBase {
readonly kind: InfoKind;
type ClassOrInterface = ClassLikeDeclaration | InterfaceDeclaration;
const enum InfoKind { Enum, ClassOrInterface }
interface EnumInfo {
readonly kind: InfoKind.Enum;
readonly token: Identifier;
readonly parentDeclaration: EnumDeclaration | ClassLikeDeclaration;
}
enum InfoKind { enum, class }
interface EnumInfo extends InfoBase {
readonly kind: InfoKind.enum;
readonly parentDeclaration: EnumDeclaration;
}
interface ClassInfo extends InfoBase {
readonly kind: InfoKind.class;
readonly parentDeclaration: ClassLikeDeclaration;
interface ClassOrInterfaceInfo {
readonly kind: InfoKind.ClassOrInterface;
readonly token: Identifier;
readonly parentDeclaration: ClassOrInterface;
readonly makeStatic: boolean;
readonly classDeclarationSourceFile: SourceFile;
readonly declSourceFile: SourceFile;
readonly inJs: boolean;
readonly call: CallExpression | undefined;
}
type Info = EnumInfo | ClassInfo;
type Info = EnumInfo | ClassOrInterfaceInfo;
function getInfo(tokenSourceFile: SourceFile, tokenPos: number, checker: TypeChecker): Info | undefined {
// The identifier of the missing property. eg:
@@ -128,35 +126,36 @@ namespace ts.codefix {
const { symbol } = leftExpressionType;
if (!symbol || !symbol.declarations) return undefined;
const classDeclaration = find(symbol.declarations, isClassLike);
if (classDeclaration) {
const makeStatic = (leftExpressionType as TypeReference).target !== checker.getDeclaredTypeOfSymbol(symbol);
const classDeclarationSourceFile = classDeclaration.getSourceFile();
const inJs = isSourceFileJavaScript(classDeclarationSourceFile);
// Prefer to change the class instead of the interface if they are merged
const classOrInterface = find(symbol.declarations, isClassLike) || find(symbol.declarations, isInterfaceDeclaration);
if (classOrInterface) {
const makeStatic = ((leftExpressionType as TypeReference).target || leftExpressionType) !== checker.getDeclaredTypeOfSymbol(symbol);
const declSourceFile = classOrInterface.getSourceFile();
const inJs = isSourceFileJavaScript(declSourceFile);
const call = tryCast(parent.parent, isCallExpression);
return { kind: InfoKind.class, token, parentDeclaration: classDeclaration, makeStatic, classDeclarationSourceFile, inJs, call };
return { kind: InfoKind.ClassOrInterface, token, parentDeclaration: classOrInterface, makeStatic, declSourceFile, inJs, call };
}
const enumDeclaration = find(symbol.declarations, isEnumDeclaration);
if (enumDeclaration) {
return { kind: InfoKind.enum, token, parentDeclaration: enumDeclaration };
return { kind: InfoKind.Enum, token, parentDeclaration: enumDeclaration };
}
return undefined;
}
function getActionsForAddMissingMemberInJavaScriptFile(context: CodeFixContext, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, tokenName: string, makeStatic: boolean): CodeFixAction | undefined {
const changes = textChanges.ChangeTracker.with(context, t => addMissingMemberInJs(t, classDeclarationSourceFile, classDeclaration, tokenName, makeStatic));
function getActionsForAddMissingMemberInJavaScriptFile(context: CodeFixContext, declSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, tokenName: string, makeStatic: boolean): CodeFixAction | undefined {
const changes = textChanges.ChangeTracker.with(context, t => addMissingMemberInJs(t, declSourceFile, classDeclaration, tokenName, makeStatic));
return changes.length === 0 ? undefined
: createCodeFixAction(fixName, changes, [makeStatic ? Diagnostics.Initialize_static_property_0 : Diagnostics.Initialize_property_0_in_the_constructor, tokenName], fixId, Diagnostics.Add_all_missing_members);
}
function addMissingMemberInJs(changeTracker: textChanges.ChangeTracker, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, tokenName: string, makeStatic: boolean): void {
function addMissingMemberInJs(changeTracker: textChanges.ChangeTracker, declSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, tokenName: string, makeStatic: boolean): void {
if (makeStatic) {
if (classDeclaration.kind === SyntaxKind.ClassExpression) {
return;
}
const className = classDeclaration.name!.getText();
const staticInitialization = initializePropertyToUndefined(createIdentifier(className), tokenName);
changeTracker.insertNodeAfter(classDeclarationSourceFile, classDeclaration, staticInitialization);
changeTracker.insertNodeAfter(declSourceFile, classDeclaration, staticInitialization);
}
else {
const classConstructor = getFirstConstructorWithBody(classDeclaration);
@@ -164,7 +163,7 @@ namespace ts.codefix {
return;
}
const propertyInitialization = initializePropertyToUndefined(createThis(), tokenName);
changeTracker.insertNodeAtConstructorEnd(classDeclarationSourceFile, classConstructor, propertyInitialization);
changeTracker.insertNodeAtConstructorEnd(declSourceFile, classConstructor, propertyInitialization);
}
}
@@ -172,13 +171,13 @@ namespace ts.codefix {
return createStatement(createAssignment(createPropertyAccess(obj, propertyName), createIdentifier("undefined")));
}
function getActionsForAddMissingMemberInTypeScriptFile(context: CodeFixContext, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, token: Identifier, makeStatic: boolean): CodeFixAction[] | undefined {
function getActionsForAddMissingMemberInTypeScriptFile(context: CodeFixContext, declSourceFile: SourceFile, classDeclaration: ClassOrInterface, token: Identifier, makeStatic: boolean): CodeFixAction[] | undefined {
const typeNode = getTypeNode(context.program.getTypeChecker(), classDeclaration, token);
const addProp = createAddPropertyDeclarationAction(context, classDeclarationSourceFile, classDeclaration, makeStatic, token.text, typeNode);
return makeStatic ? [addProp] : [addProp, createAddIndexSignatureAction(context, classDeclarationSourceFile, classDeclaration, token.text, typeNode)];
const addProp = createAddPropertyDeclarationAction(context, declSourceFile, classDeclaration, makeStatic, token.text, typeNode);
return makeStatic ? [addProp] : [addProp, createAddIndexSignatureAction(context, declSourceFile, classDeclaration, token.text, typeNode)];
}
function getTypeNode(checker: TypeChecker, classDeclaration: ClassLikeDeclaration, token: Node) {
function getTypeNode(checker: TypeChecker, classDeclaration: ClassOrInterface, token: Node) {
let typeNode: TypeNode | undefined;
if (token.parent.parent.kind === SyntaxKind.BinaryExpression) {
const binaryExpression = token.parent.parent as BinaryExpression;
@@ -189,12 +188,12 @@ namespace ts.codefix {
return typeNode || createKeywordTypeNode(SyntaxKind.AnyKeyword);
}
function createAddPropertyDeclarationAction(context: CodeFixContext, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, makeStatic: boolean, tokenName: string, typeNode: TypeNode): CodeFixAction {
const changes = textChanges.ChangeTracker.with(context, t => addPropertyDeclaration(t, classDeclarationSourceFile, classDeclaration, tokenName, typeNode, makeStatic));
function createAddPropertyDeclarationAction(context: CodeFixContext, declSourceFile: SourceFile, classDeclaration: ClassOrInterface, makeStatic: boolean, tokenName: string, typeNode: TypeNode): CodeFixAction {
const changes = textChanges.ChangeTracker.with(context, t => addPropertyDeclaration(t, declSourceFile, classDeclaration, tokenName, typeNode, makeStatic));
return createCodeFixAction(fixName, changes, [makeStatic ? Diagnostics.Declare_static_property_0 : Diagnostics.Declare_property_0, tokenName], fixId, Diagnostics.Add_all_missing_members);
}
function addPropertyDeclaration(changeTracker: textChanges.ChangeTracker, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, tokenName: string, typeNode: TypeNode, makeStatic: boolean): void {
function addPropertyDeclaration(changeTracker: textChanges.ChangeTracker, declSourceFile: SourceFile, classDeclaration: ClassOrInterface, tokenName: string, typeNode: TypeNode, makeStatic: boolean): void {
const property = createProperty(
/*decorators*/ undefined,
/*modifiers*/ makeStatic ? [createToken(SyntaxKind.StaticKeyword)] : undefined,
@@ -205,15 +204,15 @@ namespace ts.codefix {
const lastProp = getNodeToInsertPropertyAfter(classDeclaration);
if (lastProp) {
changeTracker.insertNodeAfter(classDeclarationSourceFile, lastProp, property);
changeTracker.insertNodeAfter(declSourceFile, lastProp, property);
}
else {
changeTracker.insertNodeAtClassStart(classDeclarationSourceFile, classDeclaration, property);
changeTracker.insertNodeAtClassStart(declSourceFile, classDeclaration, property);
}
}
// Gets the last of the first run of PropertyDeclarations, or undefined if the class does not start with a PropertyDeclaration.
function getNodeToInsertPropertyAfter(cls: ClassLikeDeclaration): PropertyDeclaration | undefined {
function getNodeToInsertPropertyAfter(cls: ClassOrInterface): PropertyDeclaration | undefined {
let res: PropertyDeclaration | undefined;
for (const member of cls.members) {
if (!isPropertyDeclaration(member)) break;
@@ -222,7 +221,7 @@ namespace ts.codefix {
return res;
}
function createAddIndexSignatureAction(context: CodeFixContext, classDeclarationSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, tokenName: string, typeNode: TypeNode): CodeFixAction {
function createAddIndexSignatureAction(context: CodeFixContext, declSourceFile: SourceFile, classDeclaration: ClassOrInterface, tokenName: string, typeNode: TypeNode): CodeFixAction {
// Index signatures cannot have the static modifier.
const stringTypeNode = createKeywordTypeNode(SyntaxKind.StringKeyword);
const indexingParameter = createParameter(
@@ -239,44 +238,44 @@ namespace ts.codefix {
[indexingParameter],
typeNode);
const changes = textChanges.ChangeTracker.with(context, t => t.insertNodeAtClassStart(classDeclarationSourceFile, classDeclaration, indexSignature));
const changes = textChanges.ChangeTracker.with(context, t => t.insertNodeAtClassStart(declSourceFile, classDeclaration, indexSignature));
// No fixId here because code-fix-all currently only works on adding individual named properties.
return createCodeFixActionNoFixId(fixName, changes, [Diagnostics.Add_index_signature_for_property_0, tokenName]);
}
function getActionForMethodDeclaration(
context: CodeFixContext,
classDeclarationSourceFile: SourceFile,
classDeclaration: ClassLikeDeclaration,
declSourceFile: SourceFile,
classDeclaration: ClassOrInterface,
token: Identifier,
callExpression: CallExpression,
makeStatic: boolean,
inJs: boolean,
preferences: UserPreferences,
): CodeFixAction | undefined {
const changes = textChanges.ChangeTracker.with(context, t => addMethodDeclaration(context, t, classDeclarationSourceFile, classDeclaration, token, callExpression, makeStatic, inJs, preferences));
const changes = textChanges.ChangeTracker.with(context, t => addMethodDeclaration(context, t, declSourceFile, classDeclaration, token, callExpression, makeStatic, inJs, preferences));
return createCodeFixAction(fixName, changes, [makeStatic ? Diagnostics.Declare_static_method_0 : Diagnostics.Declare_method_0, token.text], fixId, Diagnostics.Add_all_missing_members);
}
function addMethodDeclaration(
context: CodeFixContextBase,
changeTracker: textChanges.ChangeTracker,
classDeclarationSourceFile: SourceFile,
classDeclaration: ClassLikeDeclaration,
declSourceFile: SourceFile,
typeDecl: ClassOrInterface,
token: Identifier,
callExpression: CallExpression,
makeStatic: boolean,
inJs: boolean,
preferences: UserPreferences,
): void {
const methodDeclaration = createMethodFromCallExpression(context, callExpression, token.text, inJs, makeStatic, preferences);
const methodDeclaration = createMethodFromCallExpression(context, callExpression, token.text, inJs, makeStatic, preferences, !isInterfaceDeclaration(typeDecl));
const containingMethodDeclaration = getAncestor(callExpression, SyntaxKind.MethodDeclaration);
if (containingMethodDeclaration && containingMethodDeclaration.parent === classDeclaration) {
changeTracker.insertNodeAfter(classDeclarationSourceFile, containingMethodDeclaration, methodDeclaration);
if (containingMethodDeclaration && containingMethodDeclaration.parent === typeDecl) {
changeTracker.insertNodeAfter(declSourceFile, containingMethodDeclaration, methodDeclaration);
}
else {
changeTracker.insertNodeAtClassStart(classDeclarationSourceFile, classDeclaration, methodDeclaration);
changeTracker.insertNodeAtClassStart(declSourceFile, typeDecl, methodDeclaration);
}
}
+11 -14
View File
@@ -112,26 +112,23 @@ namespace ts.codefix {
export function createMethodFromCallExpression(
context: CodeFixContextBase,
{ typeArguments, arguments: args, parent: parent }: CallExpression,
call: CallExpression,
methodName: string,
inJs: boolean,
makeStatic: boolean,
preferences: UserPreferences,
body: boolean,
): MethodDeclaration {
const { typeArguments, arguments: args, parent } = call;
const checker = context.program.getTypeChecker();
const types = map(args,
arg => {
let type = checker.getTypeAtLocation(arg);
if (type === undefined) {
return undefined;
}
// Widen the type so we don't emit nonsense annotations like "function fn(x: 3) {"
type = checker.getBaseTypeOfLiteralType(type);
return checker.typeToTypeNode(type);
});
const types = map(args, arg =>
// Widen the type so we don't emit nonsense annotations like "function fn(x: 3) {"
checker.typeToTypeNode(checker.getBaseTypeOfLiteralType(checker.getTypeAtLocation(arg))));
const names = map(args, arg =>
isIdentifier(arg) ? arg.text :
isPropertyAccessExpression(arg) ? arg.name.text : undefined);
isPropertyAccessExpression(arg) ? arg.name.text : undefined);
const contextualType = checker.getContextualType(call);
const returnType = inJs ? undefined : contextualType && checker.typeToTypeNode(contextualType, call) || createKeywordTypeNode(SyntaxKind.AnyKeyword);
return createMethod(
/*decorators*/ undefined,
/*modifiers*/ makeStatic ? [createToken(SyntaxKind.StaticKeyword)] : undefined,
@@ -141,8 +138,8 @@ namespace ts.codefix {
/*typeParameters*/ inJs ? undefined : map(typeArguments, (_, i) =>
createTypeParameterDeclaration(CharacterCodes.T + typeArguments!.length - 1 <= CharacterCodes.Z ? String.fromCharCode(CharacterCodes.T + i) : `T${i}`)),
/*parameters*/ createDummyParameters(args.length, names, types, /*minArgumentCount*/ undefined, inJs),
/*type*/ inJs ? undefined : createKeywordTypeNode(SyntaxKind.AnyKeyword),
createStubbedMethodBody(preferences));
/*type*/ returnType,
body ? createStubbedMethodBody(preferences) : undefined);
}
function createDummyParameters(argCount: number, names: (string | undefined)[] | undefined, types: (TypeNode | undefined)[] | undefined, minArgumentCount: number | undefined, inJs: boolean): ParameterDeclaration[] {
+43 -25
View File
@@ -163,14 +163,19 @@ namespace ts.codefix {
position: number,
preferences: UserPreferences,
): { readonly moduleSpecifier: string, readonly codeAction: CodeAction } {
const exportInfos = getAllReExportingModules(exportedSymbol, moduleSymbol, symbolName, sourceFile, program.getTypeChecker(), program.getSourceFiles());
const exportInfos = getAllReExportingModules(exportedSymbol, moduleSymbol, symbolName, sourceFile, program.getCompilerOptions(), program.getTypeChecker(), program.getSourceFiles());
Debug.assert(exportInfos.some(info => info.moduleSymbol === moduleSymbol));
// We sort the best codefixes first, so taking `first` is best for completions.
const moduleSpecifier = first(getNewImportInfos(program, sourceFile, position, exportInfos, host, preferences)).moduleSpecifier;
const fix = first(getFixForImport(exportInfos, symbolName, position, program, sourceFile, host, preferences));
return { moduleSpecifier, codeAction: codeActionForFix({ host, formatContext }, sourceFile, symbolName, fix, getQuotePreference(sourceFile, preferences)) };
return { moduleSpecifier, codeAction: codeFixActionToCodeAction(codeActionForFix({ host, formatContext }, sourceFile, symbolName, fix, getQuotePreference(sourceFile, preferences))) };
}
function getAllReExportingModules(exportedSymbol: Symbol, exportingModuleSymbol: Symbol, symbolName: string, sourceFile: SourceFile, checker: TypeChecker, allSourceFiles: ReadonlyArray<SourceFile>): ReadonlyArray<SymbolExportInfo> {
function codeFixActionToCodeAction({ description, changes, commands }: CodeFixAction): CodeAction {
return { description, changes, commands };
}
function getAllReExportingModules(exportedSymbol: Symbol, exportingModuleSymbol: Symbol, symbolName: string, sourceFile: SourceFile, compilerOptions: CompilerOptions, checker: TypeChecker, allSourceFiles: ReadonlyArray<SourceFile>): ReadonlyArray<SymbolExportInfo> {
const result: SymbolExportInfo[] = [];
forEachExternalModule(checker, allSourceFiles, (moduleSymbol, moduleFile) => {
// Don't import from a re-export when looking "up" like to `./index` or `../index`.
@@ -178,10 +183,14 @@ namespace ts.codefix {
return;
}
const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, compilerOptions);
if (defaultInfo && defaultInfo.name === symbolName && skipAlias(defaultInfo.symbol, checker) === exportedSymbol) {
result.push({ moduleSymbol, importKind: defaultInfo.kind, exportedSymbolIsTypeOnly: isTypeOnlySymbol(defaultInfo.symbol) });
}
for (const exported of checker.getExportsOfModule(moduleSymbol)) {
if ((exported.escapedName === InternalSymbolName.Default || exported.name === symbolName) && skipAlias(exported, checker) === exportedSymbol) {
const isDefaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol) === exported;
result.push({ moduleSymbol, importKind: isDefaultExport ? ImportKind.Default : ImportKind.Named, exportedSymbolIsTypeOnly: isTypeOnlySymbol(exported) });
if (exported.name === symbolName && skipAlias(exported, checker) === exportedSymbol) {
result.push({ moduleSymbol, importKind: ImportKind.Named, exportedSymbolIsTypeOnly: isTypeOnlySymbol(exported) });
}
}
});
@@ -274,14 +283,13 @@ namespace ts.codefix {
preferences: UserPreferences,
): ReadonlyArray<FixAddNewImport | FixUseImportType> {
const isJs = isSourceFileJavaScript(sourceFile);
const choicesForEachExportingModule = flatMap<SymbolExportInfo, ReadonlyArray<FixAddNewImport | FixUseImportType>>(moduleSymbols, ({ moduleSymbol, importKind, exportedSymbolIsTypeOnly }) => {
const modulePathsGroups = moduleSpecifiers.getModuleSpecifiers(moduleSymbol, program.getCompilerOptions(), sourceFile, host, program.getSourceFiles(), preferences, program.redirectTargetsMap);
return modulePathsGroups.map(group => group.map((moduleSpecifier): FixAddNewImport | FixUseImportType =>
const choicesForEachExportingModule = flatMap(moduleSymbols, ({ moduleSymbol, importKind, exportedSymbolIsTypeOnly }) =>
moduleSpecifiers.getModuleSpecifiers(moduleSymbol, program.getCompilerOptions(), sourceFile, host, program.getSourceFiles(), preferences, program.redirectTargetsMap)
.map((moduleSpecifier): FixAddNewImport | FixUseImportType =>
// `position` should only be undefined at a missing jsx namespace, in which case we shouldn't be looking for pure types.
exportedSymbolIsTypeOnly && isJs ? { kind: ImportFixKind.ImportType, moduleSpecifier, position: Debug.assertDefined(position) } : { kind: ImportFixKind.AddNew, moduleSpecifier, importKind }));
});
// Sort to keep the shortest paths first, but keep [relativePath, importRelativeToBaseUrl] groups together
return flatten<FixAddNewImport | FixUseImportType>(choicesForEachExportingModule.sort((a, b) => first(a).moduleSpecifier.length - first(b).moduleSpecifier.length));
// Sort to keep the shortest paths first
return choicesForEachExportingModule.sort((a, b) => a.moduleSpecifier.length - b.moduleSpecifier.length);
}
function getFixesForAddImport(
@@ -395,13 +403,9 @@ namespace ts.codefix {
forEachExternalModuleToImportFrom(checker, sourceFile, program.getSourceFiles(), moduleSymbol => {
cancellationToken.throwIfCancellationRequested();
// check the default export
const defaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol);
if (defaultExport) {
const info = getDefaultExportInfo(defaultExport, moduleSymbol, program);
if (info && info.name === symbolName && symbolHasMeaning(info.symbolForMeaning, currentTokenMeaning)) {
addSymbol(moduleSymbol, defaultExport, ImportKind.Default);
}
const defaultInfo = getDefaultLikeExportInfo(moduleSymbol, checker, program.getCompilerOptions());
if (defaultInfo && defaultInfo.name === symbolName && symbolHasMeaning(defaultInfo.symbolForMeaning, currentTokenMeaning)) {
addSymbol(moduleSymbol, defaultInfo.symbol, defaultInfo.kind);
}
// check exports with the same name
@@ -413,9 +417,24 @@ namespace ts.codefix {
return originalSymbolToExportInfos;
}
function getDefaultExportInfo(defaultExport: Symbol, moduleSymbol: Symbol, program: Program): { readonly symbolForMeaning: Symbol, readonly name: string } | undefined {
const checker = program.getTypeChecker();
function getDefaultLikeExportInfo(
moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions,
): { readonly symbol: Symbol, readonly symbolForMeaning: Symbol, readonly name: string, readonly kind: ImportKind.Default | ImportKind.Equals } | undefined {
const exported = getDefaultLikeExportWorker(moduleSymbol, checker);
if (!exported) return undefined;
const { symbol, kind } = exported;
const info = getDefaultExportInfoWorker(symbol, moduleSymbol, checker, compilerOptions);
return info && { symbol, symbolForMeaning: info.symbolForMeaning, name: info.name, kind };
}
function getDefaultLikeExportWorker(moduleSymbol: Symbol, checker: TypeChecker): { readonly symbol: Symbol, readonly kind: ImportKind.Default | ImportKind.Equals } | undefined {
const defaultExport = checker.tryGetMemberInModuleExports(InternalSymbolName.Default, moduleSymbol);
if (defaultExport) return { symbol: defaultExport, kind: ImportKind.Default };
const exportEquals = checker.resolveExternalModuleSymbol(moduleSymbol);
return exportEquals === moduleSymbol ? undefined : { symbol: exportEquals, kind: ImportKind.Equals };
}
function getDefaultExportInfoWorker(defaultExport: Symbol, moduleSymbol: Symbol, checker: TypeChecker, compilerOptions: CompilerOptions): { readonly symbolForMeaning: Symbol, readonly name: string } | undefined {
const localSymbol = getLocalSymbolForExportDefault(defaultExport);
if (localSymbol) return { symbolForMeaning: localSymbol, name: localSymbol.name };
@@ -423,12 +442,11 @@ namespace ts.codefix {
if (name !== undefined) return { symbolForMeaning: defaultExport, name };
if (defaultExport.flags & SymbolFlags.Alias) {
const aliased = checker.getAliasedSymbol(defaultExport);
return getDefaultExportInfo(aliased, Debug.assertDefined(aliased.parent), program);
const aliased = checker.getImmediateAliasedSymbol(defaultExport);
return aliased && getDefaultExportInfoWorker(aliased, Debug.assertDefined(aliased.parent), checker, compilerOptions);
}
else {
const moduleName = moduleSymbolToValidIdentifier(moduleSymbol, program.getCompilerOptions().target!);
return moduleName === undefined ? undefined : { symbolForMeaning: defaultExport, name: moduleName };
return { symbolForMeaning: defaultExport, name: moduleSymbolToValidIdentifier(moduleSymbol, compilerOptions.target!) };
}
}
+11 -9
View File
@@ -534,17 +534,19 @@ namespace ts.codefix {
else if (usageContext.properties && hasCallContext(usageContext.properties.get("push" as __String))) {
return checker.createArrayType(getParameterTypeFromCallContexts(0, usageContext.properties.get("push" as __String)!.callContexts!, /*isRestParameter*/ false, checker)!);
}
else if (usageContext.properties || usageContext.callContexts || usageContext.constructContexts || usageContext.numberIndexContext || usageContext.stringIndexContext) {
else if (usageContext.numberIndexContext) {
return checker.createArrayType(recur(usageContext.numberIndexContext));
}
else if (usageContext.properties || usageContext.callContexts || usageContext.constructContexts || usageContext.stringIndexContext) {
const members = createUnderscoreEscapedMap<Symbol>();
const callSignatures: Signature[] = [];
const constructSignatures: Signature[] = [];
let stringIndexInfo: IndexInfo | undefined;
let numberIndexInfo: IndexInfo | undefined;
if (usageContext.properties) {
usageContext.properties.forEach((context, name) => {
const symbol = checker.createSymbol(SymbolFlags.Property, name);
symbol.type = getTypeFromUsageContext(context, checker) || checker.getAnyType();
symbol.type = recur(context);
members.set(name, symbol);
});
}
@@ -561,19 +563,19 @@ namespace ts.codefix {
}
}
if (usageContext.numberIndexContext) {
numberIndexInfo = checker.createIndexInfo(getTypeFromUsageContext(usageContext.numberIndexContext, checker) || checker.getAnyType(), /*isReadonly*/ false);
}
if (usageContext.stringIndexContext) {
stringIndexInfo = checker.createIndexInfo(getTypeFromUsageContext(usageContext.stringIndexContext, checker) || checker.getAnyType(), /*isReadonly*/ false);
stringIndexInfo = checker.createIndexInfo(recur(usageContext.stringIndexContext), /*isReadonly*/ false);
}
return checker.createAnonymousType(/*symbol*/ undefined!, members, callSignatures, constructSignatures, stringIndexInfo, numberIndexInfo); // TODO: GH#18217
return checker.createAnonymousType(/*symbol*/ undefined!, members, callSignatures, constructSignatures, stringIndexInfo, /*numberIndexInfo*/ undefined); // TODO: GH#18217
}
else {
return undefined;
}
function recur(innerContext: UsageContext): Type {
return getTypeFromUsageContext(innerContext, checker) || checker.getAnyType();
}
}
function getParameterTypeFromCallContexts(parameterIndex: number, callContexts: CallContext[], isRestParameter: boolean, checker: TypeChecker) {
+36 -24
View File
@@ -23,7 +23,8 @@ namespace ts.Completions {
type SymbolOriginInfoMap = (SymbolOriginInfo | undefined)[];
const enum KeywordCompletionFilters {
None,
None, // No keywords
All, // Every possible keyword (TODO: This is never appropriate)
ClassElementKeywords, // Keywords inside class body
InterfaceElementKeywords, // Keywords inside interface body
ConstructorParameterKeywords, // Keywords at constructor parameter
@@ -143,21 +144,13 @@ namespace ts.Completions {
getCompletionEntriesFromSymbols(symbols, entries, location, sourceFile, typeChecker, compilerOptions.target!, log, completionKind, preferences, propertyAccessToConvert, isJsxInitializer, recommendedCompletion, symbolToOriginInfoMap);
}
// TODO add filter for keyword based on type/value/namespace and also location
// Add all keywords if
// - this is not a member completion list (all the keywords)
// - other filters are enabled in required scenario so add those keywords
const isMemberCompletion = isMemberCompletionKind(completionKind);
if (keywordFilters !== KeywordCompletionFilters.None || !isMemberCompletion) {
addRange(entries, getKeywordCompletions(keywordFilters));
}
addRange(entries, getKeywordCompletions(keywordFilters));
for (const literal of literals) {
entries.push(createCompletionEntryForLiteral(literal));
}
return { isGlobalCompletion: isInSnippetScope, isMemberCompletion, isNewIdentifierLocation, entries };
return { isGlobalCompletion: isInSnippetScope, isMemberCompletion: isMemberCompletionKind(completionKind), isNewIdentifierLocation, entries };
}
function isUncheckedFile(sourceFile: SourceFile, compilerOptions: CompilerOptions): boolean {
@@ -271,6 +264,9 @@ namespace ts.Completions {
}
function quote(text: string, preferences: UserPreferences): string {
if (/^\d+$/.test(text)) {
return text;
}
const quoted = JSON.stringify(text);
switch (preferences.quotePreference) {
case undefined:
@@ -402,6 +398,8 @@ namespace ts.Completions {
return stringLiteralCompletionsFromProperties(typeChecker.getTypeFromTypeNode((node.parent.parent as IndexedAccessTypeNode).objectType));
case SyntaxKind.ImportType:
return { kind: StringLiteralCompletionKind.Paths, paths: PathCompletions.getStringLiteralCompletionsFromModuleNames(sourceFile, node, compilerOptions, host, typeChecker) };
case SyntaxKind.UnionType:
return isTypeReferenceNode(node.parent.parent.parent) ? { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(node.parent.parent as UnionTypeNode)), isNewIdentifier: false } : undefined;
default:
return undefined;
}
@@ -1012,6 +1010,7 @@ namespace ts.Completions {
tryGetGlobalSymbols();
symbols = tagSymbols.concat(symbols);
completionKind = CompletionKind.MemberLike;
keywordFilters = KeywordCompletionFilters.None;
}
else if (isStartingCloseTag) {
const tagName = (<JsxElement>contextToken.parent.parent).openingElement.tagName;
@@ -1020,6 +1019,7 @@ namespace ts.Completions {
symbols = [tagSymbol];
}
completionKind = CompletionKind.MemberLike;
keywordFilters = KeywordCompletionFilters.None;
}
else {
// For JavaScript or TypeScript, if we're not after a dot, then just try to get the
@@ -1189,9 +1189,7 @@ namespace ts.Completions {
}
function getGlobalCompletions(): void {
if (tryGetFunctionLikeBodyCompletionContainer(contextToken)) {
keywordFilters = KeywordCompletionFilters.FunctionLikeBodyKeywords;
}
keywordFilters = tryGetFunctionLikeBodyCompletionContainer(contextToken) ? KeywordCompletionFilters.FunctionLikeBodyKeywords : KeywordCompletionFilters.All;
// Get all entities in the current scope.
completionKind = CompletionKind.Global;
@@ -1376,6 +1374,14 @@ namespace ts.Completions {
return;
}
if (resolvedModuleSymbol !== moduleSymbol &&
// Don't add another completion for `export =` of a symbol that's already global.
// So in `declare namespace foo {} declare module "foo" { export = foo; }`, there will just be the global completion for `foo`.
resolvedModuleSymbol.declarations.some(d => !!d.getSourceFile().externalModuleIndicator)) {
symbols.push(resolvedModuleSymbol);
symbolToOriginInfoMap[getSymbolId(resolvedModuleSymbol)] = { kind: SymbolOriginInfoKind.Export, moduleSymbol, isDefaultExport: false };
}
for (let symbol of typeChecker.getExportsOfModule(moduleSymbol)) {
// Don't add a completion for a re-export, only for the original.
// The actual import fix might end up coming from a re-export -- we don't compute that until getting completion details.
@@ -1638,7 +1644,8 @@ namespace ts.Completions {
completionKind = CompletionKind.MemberLike;
// Declaring new property/method/accessor
isNewIdentifierLocation = true;
keywordFilters = isClassLike(decl) ? KeywordCompletionFilters.ClassElementKeywords : KeywordCompletionFilters.InterfaceElementKeywords;
keywordFilters = contextToken.kind === SyntaxKind.AsteriskToken ? KeywordCompletionFilters.None :
isClassLike(decl) ? KeywordCompletionFilters.ClassElementKeywords : KeywordCompletionFilters.InterfaceElementKeywords;
// If you're in an interface you don't want to repeat things from super-interface. So just stop here.
if (!isClassLike(decl)) return GlobalsSearch.Success;
@@ -1676,14 +1683,16 @@ namespace ts.Completions {
*/
function tryGetObjectLikeCompletionContainer(contextToken: Node): ObjectLiteralExpression | ObjectBindingPattern | undefined {
if (contextToken) {
const { parent } = contextToken;
switch (contextToken.kind) {
case SyntaxKind.OpenBraceToken: // const x = { |
case SyntaxKind.CommaToken: // const x = { a: 0, |
const parent = contextToken.parent;
if (isObjectLiteralExpression(parent) || isObjectBindingPattern(parent)) {
return parent;
}
break;
case SyntaxKind.AsteriskToken:
return isMethodDeclaration(parent) ? tryCast(parent.parent, isObjectLiteralExpression) : undefined;
}
}
@@ -1860,10 +1869,8 @@ namespace ts.Completions {
case SyntaxKind.GetKeyword:
case SyntaxKind.SetKeyword:
if (isFromObjectTypeDeclaration(contextToken)) {
return false;
}
// falls through
return !isFromObjectTypeDeclaration(contextToken);
case SyntaxKind.ClassKeyword:
case SyntaxKind.EnumKeyword:
case SyntaxKind.InterfaceKeyword:
@@ -1875,6 +1882,9 @@ namespace ts.Completions {
case SyntaxKind.YieldKeyword:
case SyntaxKind.TypeKeyword: // type htm|
return true;
case SyntaxKind.AsteriskToken:
return isFunctionLike(contextToken.parent) && !isMethodDeclaration(contextToken.parent);
}
// If the previous token is keyword correspoding to class member completion keyword
@@ -2114,8 +2124,10 @@ namespace ts.Completions {
const kind = stringToToken(entry.name)!;
switch (keywordFilter) {
case KeywordCompletionFilters.None:
// "undefined" is a global variable, so don't need a keyword completion for it.
return kind !== SyntaxKind.UndefinedKeyword;
return false;
case KeywordCompletionFilters.All:
return kind === SyntaxKind.AsyncKeyword || !isContextualKeyword(kind) && !isClassMemberCompletionKeyword(kind) || kind === SyntaxKind.DeclareKeyword || kind === SyntaxKind.ModuleKeyword
|| isTypeKeyword(kind) && kind !== SyntaxKind.UndefinedKeyword;
case KeywordCompletionFilters.ClassElementKeywords:
return isClassMemberCompletionKeyword(kind);
case KeywordCompletionFilters.InterfaceElementKeywords:
@@ -2150,7 +2162,7 @@ namespace ts.Completions {
}
function isFunctionLikeBodyKeyword(kind: SyntaxKind) {
return kind === SyntaxKind.AsyncKeyword || !isClassMemberCompletionKeyword(kind);
return kind === SyntaxKind.AsyncKeyword || !isContextualKeyword(kind) && !isClassMemberCompletionKeyword(kind);
}
function keywordForNode(node: Node): SyntaxKind {
@@ -2226,7 +2238,7 @@ namespace ts.Completions {
default:
if (!isFromObjectTypeDeclaration(contextToken)) return undefined;
const isValidKeyword = isClassLike(contextToken.parent.parent) ? isClassMemberCompletionKeyword : isInterfaceOrTypeLiteralCompletionKeyword;
return (isValidKeyword(contextToken.kind) || isIdentifier(contextToken) && isValidKeyword(stringToToken(contextToken.text)!)) // TODO: GH#18217
return (isValidKeyword(contextToken.kind) || contextToken.kind === SyntaxKind.AsteriskToken || isIdentifier(contextToken) && isValidKeyword(stringToToken(contextToken.text)!)) // TODO: GH#18217
? contextToken.parent.parent as ObjectTypeDeclaration : undefined;
}
}
+2 -2
View File
@@ -184,7 +184,7 @@ namespace ts {
const bucket = getBucketForCompilationSettings(key, /*createIfMissing*/ true);
let entry = bucket.get(path);
const scriptTarget = scriptKind === ScriptKind.JSON ? ScriptTarget.JSON : compilationSettings.target;
const scriptTarget = scriptKind === ScriptKind.JSON ? ScriptTarget.JSON : compilationSettings.target || ScriptTarget.ES5;
if (!entry && externalCache) {
const sourceFile = externalCache.getDocument(key, path);
if (sourceFile) {
@@ -199,7 +199,7 @@ namespace ts {
if (!entry) {
// Have never seen this file with these settings. Create a new source file for it.
const sourceFile = createLanguageServiceSourceFile(fileName, scriptSnapshot, scriptTarget!, version, /*setNodeParents*/ false, scriptKind); // TODO: GH#18217
const sourceFile = createLanguageServiceSourceFile(fileName, scriptSnapshot, scriptTarget, version, /*setNodeParents*/ false, scriptKind);
if (externalCache) {
externalCache.setDocument(key, path, sourceFile);
}
+5 -6
View File
@@ -6,7 +6,7 @@ namespace ts {
newFileOrDirPath: string,
host: LanguageServiceHost,
formatContext: formatting.FormatContext,
preferences: UserPreferences,
_preferences: UserPreferences,
sourceMapper: SourceMapper,
): ReadonlyArray<FileTextChanges> {
const useCaseSensitiveFileNames = hostUsesCaseSensitiveFileNames(host);
@@ -15,7 +15,7 @@ namespace ts {
const newToOld = getPathUpdater(newFileOrDirPath, oldFileOrDirPath, getCanonicalFileName, sourceMapper);
return textChanges.ChangeTracker.with({ host, formatContext }, changeTracker => {
updateTsconfigFiles(program, changeTracker, oldToNew, newFileOrDirPath, host.getCurrentDirectory(), useCaseSensitiveFileNames);
updateImports(program, changeTracker, oldToNew, newToOld, host, getCanonicalFileName, preferences);
updateImports(program, changeTracker, oldToNew, newToOld, host, getCanonicalFileName);
});
}
@@ -122,7 +122,6 @@ namespace ts {
newToOld: PathUpdater,
host: LanguageServiceHost,
getCanonicalFileName: GetCanonicalFileName,
preferences: UserPreferences,
): void {
const allFiles = program.getSourceFiles();
for (const sourceFile of allFiles) {
@@ -156,7 +155,7 @@ namespace ts {
// Need an update if the imported file moved, or the importing file moved and was using a relative path.
return toImport !== undefined && (toImport.updated || (importingSourceFileMoved && pathIsRelative(importLiteral.text)))
? moduleSpecifiers.getModuleSpecifier(program.getCompilerOptions(), sourceFile, newImportFromPath, toImport.newFileName, host, allFiles, preferences, program.redirectTargetsMap)
? moduleSpecifiers.updateModuleSpecifier(program.getCompilerOptions(), newImportFromPath, toImport.newFileName, host, allFiles, program.redirectTargetsMap, importLiteral.text)
: undefined;
});
}
@@ -210,7 +209,7 @@ namespace ts {
}
function updateImportsWorker(sourceFile: SourceFile, changeTracker: textChanges.ChangeTracker, updateRef: (refText: string) => string | undefined, updateImport: (importLiteral: StringLiteralLike) => string | undefined) {
for (const ref of sourceFile.referencedFiles) {
for (const ref of sourceFile.referencedFiles || emptyArray) { // TODO: GH#26162
const updated = updateRef(ref.fileName);
if (updated !== undefined && updated !== sourceFile.text.slice(ref.pos, ref.end)) changeTracker.replaceRangeWithText(sourceFile, ref, updated);
}
@@ -222,7 +221,7 @@ namespace ts {
}
function createStringRange(node: StringLiteralLike, sourceFile: SourceFileLike): TextRange {
return createTextRange(node.getStart(sourceFile) + 1, node.end - 1);
return createRange(node.getStart(sourceFile) + 1, node.end - 1);
}
function forEachProperty(objectLiteral: Expression, cb: (property: PropertyAssignment, propertyName: string) => void) {
+36 -4
View File
@@ -29,7 +29,7 @@ namespace ts.GoToDefinition {
const calledDeclaration = tryGetSignatureDeclaration(typeChecker, node);
// Don't go to the component constructor definition for a JSX element, just go to the component definition.
if (calledDeclaration && !(isJsxOpeningLikeElement(node.parent) && isConstructorDeclaration(calledDeclaration))) {
if (calledDeclaration && !(isJsxOpeningLikeElement(node.parent) && isConstructorLike(calledDeclaration))) {
const sigInfo = createDefinitionFromSignatureDeclaration(typeChecker, calledDeclaration);
// For a function, if this is the original function definition, return just sigInfo.
// If this is the original constructor definition, parent is the class.
@@ -136,9 +136,30 @@ namespace ts.GoToDefinition {
}
const symbol = typeChecker.getSymbolAtLocation(node);
const type = symbol && typeChecker.getTypeOfSymbolAtLocation(symbol, node);
return type && flatMap(type.isUnion() && !(type.flags & TypeFlags.Enum) ? type.types : [type], t =>
t.symbol && getDefinitionFromSymbol(typeChecker, t.symbol, node));
if (!symbol) return undefined;
const typeAtLocation = typeChecker.getTypeOfSymbolAtLocation(symbol, node);
const returnType = tryGetReturnTypeOfFunction(symbol, typeAtLocation, typeChecker);
const fromReturnType = returnType && definitionFromType(returnType, typeChecker, node);
// If a function returns 'void' or some other type with no definition, just return the function definition.
return fromReturnType && fromReturnType.length !== 0 ? fromReturnType : definitionFromType(typeAtLocation, typeChecker, node);
}
function definitionFromType(type: Type, checker: TypeChecker, node: Node): DefinitionInfo[] {
return flatMap(type.isUnion() && !(type.flags & TypeFlags.Enum) ? type.types : [type], t =>
t.symbol && getDefinitionFromSymbol(checker, t.symbol, node));
}
function tryGetReturnTypeOfFunction(symbol: Symbol, type: Type, checker: TypeChecker): Type | undefined {
// If the type is just a function's inferred type,
// go-to-type should go to the return type instead, since go-to-definition takes you to the function anyway.
if (type.symbol === symbol ||
// At `const f = () => {}`, the symbol is `f` and the type symbol is at `() => {}`
symbol.valueDeclaration && type.symbol && isVariableDeclaration(symbol.valueDeclaration) && symbol.valueDeclaration.initializer === type.symbol.valueDeclaration as Node) {
const sigs = type.getCallSignatures();
if (sigs.length === 1) return checker.getReturnTypeOfSignature(first(sigs));
}
return undefined;
}
export function getDefinitionAndBoundSpan(program: Program, sourceFile: SourceFile, position: number): DefinitionInfoAndBoundSpan | undefined {
@@ -298,4 +319,15 @@ namespace ts.GoToDefinition {
// Don't go to a function type, go to the value having that type.
return tryCast(signature && signature.declaration, (d): d is SignatureDeclaration => isFunctionLike(d) && !isFunctionTypeNode(d));
}
function isConstructorLike(node: Node): boolean {
switch (node.kind) {
case SyntaxKind.Constructor:
case SyntaxKind.ConstructorType:
case SyntaxKind.ConstructSignature:
return true;
default:
return false;
}
}
}
+1 -1
View File
@@ -367,7 +367,7 @@ namespace ts.JsDoc {
const varStatement = <VariableStatement>commentOwner;
const varDeclarations = varStatement.declarationList.declarations;
const parameters = varDeclarations.length === 1 && varDeclarations[0].initializer
? getParametersFromRightHandSideOfAssignment(varDeclarations[0].initializer!)
? getParametersFromRightHandSideOfAssignment(varDeclarations[0].initializer)
: undefined;
return { commentOwner, parameters };
}
+1 -1
View File
@@ -416,7 +416,7 @@ namespace ts.NavigationBar {
}
const declName = getNameOfDeclaration(<Declaration>node);
if (declName) {
if (declName && isPropertyName(declName)) {
return unescapeLeadingUnderscores(getPropertyNameForPropertyNameNode(declName)!); // TODO: GH#18217
}
switch (node.kind) {
+1 -1
View File
@@ -340,7 +340,7 @@ namespace ts.refactor {
const { name, namedBindings } = importDecl.importClause;
const defaultUnused = !name || isUnused(name);
const namedBindingsUnused = !namedBindings ||
(namedBindings.kind === SyntaxKind.NamespaceImport ? isUnused(namedBindings.name) : namedBindings.elements.every(e => isUnused(e.name)));
(namedBindings.kind === SyntaxKind.NamespaceImport ? isUnused(namedBindings.name) : namedBindings.elements.length !== 0 && namedBindings.elements.every(e => isUnused(e.name)));
if (defaultUnused && namedBindingsUnused) {
changes.delete(sourceFile, importDecl);
}
+1 -1
View File
@@ -29,7 +29,7 @@ namespace ts.Rename {
if (isStringLiteralLike(node) && tryGetImportFromModuleSpecifier(node)) return undefined;
const kind = SymbolDisplay.getSymbolKind(typeChecker, symbol, node);
const specifierName = (isImportOrExportSpecifierName(node) || isStringOrNumericLiteral(node) && node.parent.kind === SyntaxKind.ComputedPropertyName)
const specifierName = (isImportOrExportSpecifierName(node) || isStringOrNumericLiteralLike(node) && node.parent.kind === SyntaxKind.ComputedPropertyName)
? stripQuotes(getTextOfIdentifierOrLiteral(node))
: undefined;
const displayName = specifierName || typeChecker.symbolToString(symbol);
+2 -2
View File
@@ -2142,7 +2142,7 @@ namespace ts {
function initializeNameTable(sourceFile: SourceFile): void {
const nameTable = sourceFile.nameTable = createUnderscoreEscapedMap<number>();
sourceFile.forEachChild(function walk(node) {
if (isIdentifier(node) && node.escapedText || isStringOrNumericLiteral(node) && literalIsName(node)) {
if (isIdentifier(node) && node.escapedText || isStringOrNumericLiteralLike(node) && literalIsName(node)) {
const text = getEscapedTextOfIdentifierOrLiteral(node);
nameTable.set(text, nameTable.get(text) === undefined ? node.pos : -1);
}
@@ -2162,7 +2162,7 @@ namespace ts {
* then we want 'something' to be in the name table. Similarly, if we have
* "a['propname']" then we want to store "propname" in the name table.
*/
function literalIsName(node: StringLiteral | NumericLiteral): boolean {
function literalIsName(node: StringLiteralLike | NumericLiteral): boolean {
return isDeclarationName(node) ||
node.parent.kind === SyntaxKind.ExternalModuleReference ||
isArgumentOfElementAccessExpression(node) ||
+1 -2
View File
@@ -328,7 +328,6 @@ namespace ts {
}
export class LanguageServiceShimHostAdapter implements LanguageServiceHost {
private files: string[];
private loggingEnabled = false;
private tracingEnabled = false;
@@ -408,7 +407,7 @@ namespace ts {
public getScriptFileNames(): string[] {
const encoded = this.shimHost.getScriptFileNames();
return this.files = JSON.parse(encoded);
return JSON.parse(encoded);
}
public getScriptSnapshot(fileName: string): IScriptSnapshot | undefined {
+199 -85
View File
@@ -1,22 +1,23 @@
/* @internal */
namespace ts.SignatureHelp {
const enum ArgumentListKind {
TypeArguments,
CallArguments,
TaggedTemplateArguments,
JSXAttributesArguments
const enum InvocationKind { Call, TypeArgs, Contextual }
interface CallInvocation { readonly kind: InvocationKind.Call; readonly node: CallLikeExpression; }
interface TypeArgsInvocation { readonly kind: InvocationKind.TypeArgs; readonly called: Identifier; }
interface ContextualInvocation {
readonly kind: InvocationKind.Contextual;
readonly signature: Signature;
readonly node: Node; // Just for enclosingDeclaration for printing types
readonly symbol: Symbol;
}
const enum InvocationKind { Call, TypeArgs }
type Invocation = { kind: InvocationKind.Call, node: CallLikeExpression } | { kind: InvocationKind.TypeArgs, called: Expression };
type Invocation = CallInvocation | TypeArgsInvocation | ContextualInvocation;
interface ArgumentListInfo {
kind: ArgumentListKind;
invocation: Invocation;
argumentsSpan: TextSpan;
argumentIndex: number;
readonly isTypeParameterList: boolean;
readonly invocation: Invocation;
readonly argumentsSpan: TextSpan;
readonly argumentIndex: number;
/** argumentCount is the *apparent* number of arguments. */
argumentCount: number;
readonly argumentCount: number;
}
export function getSignatureHelpItems(program: Program, sourceFile: SourceFile, position: number, triggerReason: SignatureHelpTriggerReason | undefined, cancellationToken: CancellationToken): SignatureHelpItems | undefined {
@@ -37,47 +38,63 @@ namespace ts.SignatureHelp {
return undefined;
}
const argumentInfo = getContainingArgumentInfo(startingToken, position, sourceFile);
const argumentInfo = getContainingArgumentInfo(startingToken, position, sourceFile, typeChecker);
if (!argumentInfo) return undefined;
cancellationToken.throwIfCancellationRequested();
// Extra syntactic and semantic filtering of signature help
const candidateInfo = getCandidateInfo(argumentInfo, typeChecker, sourceFile, startingToken, onlyUseSyntacticOwners);
const candidateInfo = getCandidateOrTypeInfo(argumentInfo, typeChecker, sourceFile, startingToken, onlyUseSyntacticOwners);
cancellationToken.throwIfCancellationRequested();
if (!candidateInfo) {
// We didn't have any sig help items produced by the TS compiler. If this is a JS
// file, then see if we can figure out anything better.
if (isSourceFileJavaScript(sourceFile)) {
return createJavaScriptSignatureHelpItems(argumentInfo, program, cancellationToken);
}
return undefined;
return isSourceFileJavaScript(sourceFile) ? createJavaScriptSignatureHelpItems(argumentInfo, program, cancellationToken) : undefined;
}
return typeChecker.runWithCancellationToken(cancellationToken, typeChecker => createSignatureHelpItems(candidateInfo.candidates, candidateInfo.resolvedSignature, argumentInfo, sourceFile, typeChecker));
return typeChecker.runWithCancellationToken(cancellationToken, typeChecker =>
candidateInfo.kind === CandidateOrTypeKind.Candidate
? createSignatureHelpItems(candidateInfo.candidates, candidateInfo.resolvedSignature, argumentInfo, sourceFile, typeChecker)
: createTypeHelpItems(candidateInfo.symbol, argumentInfo, sourceFile, typeChecker));
}
interface CandidateInfo { readonly candidates: ReadonlyArray<Signature>; readonly resolvedSignature: Signature; }
function getCandidateInfo(argumentInfo: ArgumentListInfo, checker: TypeChecker, sourceFile: SourceFile, startingToken: Node, onlyUseSyntacticOwners: boolean): CandidateInfo | undefined {
const { invocation } = argumentInfo;
if (invocation.kind === InvocationKind.Call) {
if (onlyUseSyntacticOwners && !isSyntacticOwner(startingToken, invocation.node, sourceFile)) {
return undefined;
const enum CandidateOrTypeKind { Candidate, Type }
interface CandidateInfo {
readonly kind: CandidateOrTypeKind.Candidate;
readonly candidates: ReadonlyArray<Signature>;
readonly resolvedSignature: Signature;
}
interface TypeInfo {
readonly kind: CandidateOrTypeKind.Type;
readonly symbol: Symbol;
}
function getCandidateOrTypeInfo({ invocation, argumentCount }: ArgumentListInfo, checker: TypeChecker, sourceFile: SourceFile, startingToken: Node, onlyUseSyntacticOwners: boolean): CandidateInfo | TypeInfo | undefined {
switch (invocation.kind) {
case InvocationKind.Call: {
if (onlyUseSyntacticOwners && !isSyntacticOwner(startingToken, invocation.node, sourceFile)) {
return undefined;
}
const candidates: Signature[] = [];
const resolvedSignature = checker.getResolvedSignatureForSignatureHelp(invocation.node, candidates, argumentCount)!; // TODO: GH#18217
return candidates.length === 0 ? undefined : { kind: CandidateOrTypeKind.Candidate, candidates, resolvedSignature };
}
const candidates: Signature[] = [];
const resolvedSignature = checker.getResolvedSignatureForSignatureHelp(invocation.node, candidates, argumentInfo.argumentCount)!; // TODO: GH#18217
return candidates.length === 0 ? undefined : { candidates, resolvedSignature };
}
else if (invocation.kind === InvocationKind.TypeArgs) {
if (onlyUseSyntacticOwners && !lessThanFollowsCalledExpression(startingToken, sourceFile, invocation.called)) {
return undefined;
case InvocationKind.TypeArgs: {
const { called } = invocation;
if (onlyUseSyntacticOwners && !containsPrecedingToken(startingToken, sourceFile, isIdentifier(called) ? called.parent : called)) {
return undefined;
}
const candidates = getPossibleGenericSignatures(called, argumentCount, checker);
if (candidates.length !== 0) return { kind: CandidateOrTypeKind.Candidate, candidates, resolvedSignature: first(candidates) };
const symbol = checker.getSymbolAtLocation(called);
return symbol && { kind: CandidateOrTypeKind.Type, symbol };
}
const candidates = getPossibleGenericSignatures(invocation.called, argumentInfo.argumentCount, checker);
return candidates.length === 0 ? undefined : { candidates, resolvedSignature: first(candidates) };
}
else {
Debug.assertNever(invocation);
case InvocationKind.Contextual:
return { kind: CandidateOrTypeKind.Candidate, candidates: [invocation.signature], resolvedSignature: invocation.signature };
default:
return Debug.assertNever(invocation);
}
}
@@ -92,13 +109,14 @@ namespace ts.SignatureHelp {
return !!containingList && contains(invocationChildren, containingList);
}
case SyntaxKind.LessThanToken:
return lessThanFollowsCalledExpression(startingToken, sourceFile, node.expression);
return containsPrecedingToken(startingToken, sourceFile, node.expression);
default:
return false;
}
}
function createJavaScriptSignatureHelpItems(argumentInfo: ArgumentListInfo, program: Program, cancellationToken: CancellationToken): SignatureHelpItems | undefined {
if (argumentInfo.invocation.kind === InvocationKind.Contextual) return undefined;
// See if we can find some symbol with the call expression name that has call signatures.
const expression = getExpressionFromInvocation(argumentInfo.invocation);
const name = isIdentifier(expression) ? expression.text : isPropertyAccessExpression(expression) ? expression.name.text : undefined;
@@ -113,12 +131,12 @@ namespace ts.SignatureHelp {
}));
}
function lessThanFollowsCalledExpression(startingToken: Node, sourceFile: SourceFile, calledExpression: Expression) {
function containsPrecedingToken(startingToken: Node, sourceFile: SourceFile, container: Node) {
const precedingToken = Debug.assertDefined(
findPrecedingToken(startingToken.getFullStart(), sourceFile, startingToken.parent, /*excludeJsdoc*/ true)
);
return rangeContainsRange(calledExpression, precedingToken);
return rangeContainsRange(container, precedingToken);
}
export interface ArgumentInfoForCompletions {
@@ -128,10 +146,40 @@ namespace ts.SignatureHelp {
}
export function getArgumentInfoForCompletions(node: Node, position: number, sourceFile: SourceFile): ArgumentInfoForCompletions | undefined {
const info = getImmediatelyContainingArgumentInfo(node, position, sourceFile);
return !info || info.kind === ArgumentListKind.TypeArguments || info.invocation.kind === InvocationKind.TypeArgs ? undefined
return !info || info.isTypeParameterList || info.invocation.kind !== InvocationKind.Call ? undefined
: { invocation: info.invocation.node, argumentCount: info.argumentCount, argumentIndex: info.argumentIndex };
}
function getArgumentOrParameterListInfo(node: Node, sourceFile: SourceFile): { readonly list: Node, readonly argumentIndex: number, readonly argumentCount: number, readonly argumentsSpan: TextSpan } | undefined {
const info = getArgumentOrParameterListAndIndex(node, sourceFile);
if (!info) return undefined;
const { list, argumentIndex } = info;
const argumentCount = getArgumentCount(list);
if (argumentIndex !== 0) {
Debug.assertLessThan(argumentIndex, argumentCount);
}
const argumentsSpan = getApplicableSpanForArguments(list, sourceFile);
return { list, argumentIndex, argumentCount, argumentsSpan };
}
function getArgumentOrParameterListAndIndex(node: Node, sourceFile: SourceFile): { readonly list: Node, readonly argumentIndex: number } | undefined {
if (node.kind === SyntaxKind.LessThanToken || node.kind === SyntaxKind.OpenParenToken) {
// Find the list that starts right *after* the < or ( token.
// If the user has just opened a list, consider this item 0.
return { list: getChildListThatStartsWithOpenerToken(node.parent, node, sourceFile), argumentIndex: 0 };
}
else {
// findListItemInfo can return undefined if we are not in parent's argument list
// or type argument list. This includes cases where the cursor is:
// - To the right of the closing parenthesis, non-substitution template, or template tail.
// - Between the type arguments and the arguments (greater than token)
// - On the target of the call (parent.func)
// - On the 'new' keyword in a 'new' expression
const list = findContainingList(node);
return list && { list, argumentIndex: getArgumentIndex(list, node) };
}
}
/**
* Returns relevant information for the argument list and the current argument if we are
* in the argument of an invocation; returns undefined otherwise.
@@ -140,8 +188,6 @@ namespace ts.SignatureHelp {
const { parent } = node;
if (isCallOrNewExpression(parent)) {
const invocation = parent;
let list: Node | undefined;
let argumentIndex: number;
// There are 3 cases to handle:
// 1. The token introduces a list, and should begin a signature help session
@@ -157,32 +203,11 @@ namespace ts.SignatureHelp {
// Case 3:
// foo<T#, U#>(a#, #b#) -> The token is buried inside a list, and should give signature help
// Find out if 'node' is an argument, a type argument, or neither
if (node.kind === SyntaxKind.LessThanToken || node.kind === SyntaxKind.OpenParenToken) {
// Find the list that starts right *after* the < or ( token.
// If the user has just opened a list, consider this item 0.
list = getChildListThatStartsWithOpenerToken(parent, node, sourceFile);
Debug.assert(list !== undefined);
argumentIndex = 0;
}
else {
// findListItemInfo can return undefined if we are not in parent's argument list
// or type argument list. This includes cases where the cursor is:
// - To the right of the closing parenthesis, non-substitution template, or template tail.
// - Between the type arguments and the arguments (greater than token)
// - On the target of the call (parent.func)
// - On the 'new' keyword in a 'new' expression
list = findContainingList(node);
if (!list) return undefined;
argumentIndex = getArgumentIndex(list, node);
}
const kind = parent.typeArguments && parent.typeArguments.pos === list.pos ? ArgumentListKind.TypeArguments : ArgumentListKind.CallArguments;
const argumentCount = getArgumentCount(list);
if (argumentIndex !== 0) {
Debug.assertLessThan(argumentIndex, argumentCount);
}
const argumentsSpan = getApplicableSpanForArguments(list, sourceFile);
return { kind, invocation: { kind: InvocationKind.Call, node: invocation }, argumentsSpan, argumentIndex, argumentCount };
const info = getArgumentOrParameterListInfo(node, sourceFile);
if (!info) return undefined;
const { list, argumentIndex, argumentCount, argumentsSpan } = info;
const isTypeParameterList = !!parent.typeArguments && parent.typeArguments.pos === list.pos;
return { isTypeParameterList, invocation: { kind: InvocationKind.Call, node: invocation }, argumentsSpan, argumentIndex, argumentCount };
}
else if (isNoSubstitutionTemplateLiteral(node) && isTaggedTemplateExpression(parent)) {
// Check if we're actually inside the template;
@@ -190,6 +215,7 @@ namespace ts.SignatureHelp {
if (isInsideTemplateLiteral(node, position, sourceFile)) {
return getArgumentListInfoForTemplate(parent, /*argumentIndex*/ 0, sourceFile);
}
return undefined;
}
else if (isTemplateHead(node) && parent.parent.kind === SyntaxKind.TaggedTemplateExpression) {
const templateExpression = <TemplateExpression>parent;
@@ -223,7 +249,7 @@ namespace ts.SignatureHelp {
const attributeSpanStart = parent.attributes.pos;
const attributeSpanEnd = skipTrivia(sourceFile.text, parent.attributes.end, /*stopAfterLineBreak*/ false);
return {
kind: ArgumentListKind.JSXAttributesArguments,
isTypeParameterList: false,
invocation: { kind: InvocationKind.Call, node: parent },
argumentsSpan: createTextSpan(attributeSpanStart, attributeSpanEnd - attributeSpanStart),
argumentIndex: 0,
@@ -236,11 +262,67 @@ namespace ts.SignatureHelp {
const { called, nTypeArguments } = typeArgInfo;
const invocation: Invocation = { kind: InvocationKind.TypeArgs, called };
const argumentsSpan = createTextSpanFromBounds(called.getStart(sourceFile), node.end);
return { kind: ArgumentListKind.TypeArguments, invocation, argumentsSpan, argumentIndex: nTypeArguments, argumentCount: nTypeArguments + 1 };
return { isTypeParameterList: true, invocation, argumentsSpan, argumentIndex: nTypeArguments, argumentCount: nTypeArguments + 1 };
}
return undefined;
}
}
return undefined;
function getImmediatelyContainingArgumentOrContextualParameterInfo(node: Node, position: number, sourceFile: SourceFile, checker: TypeChecker): ArgumentListInfo | undefined {
return tryGetParameterInfo(node, position, sourceFile, checker) || getImmediatelyContainingArgumentInfo(node, position, sourceFile);
}
function getHighestBinary(b: BinaryExpression): BinaryExpression {
return isBinaryExpression(b.parent) ? getHighestBinary(b.parent) : b;
}
function countBinaryExpressionParameters(b: BinaryExpression): number {
return isBinaryExpression(b.left) ? countBinaryExpressionParameters(b.left) + 1 : 2;
}
function tryGetParameterInfo(startingToken: Node, _position: number, sourceFile: SourceFile, checker: TypeChecker): ArgumentListInfo | undefined {
const info = getContextualSignatureLocationInfo(startingToken, sourceFile, checker);
if (!info) return undefined;
const { contextualType, argumentIndex, argumentCount, argumentsSpan } = info;
const signatures = contextualType.getCallSignatures();
if (signatures.length !== 1) return undefined;
const invocation: ContextualInvocation = { kind: InvocationKind.Contextual, signature: first(signatures), node: startingToken, symbol: chooseBetterSymbol(contextualType.symbol) };
return { isTypeParameterList: false, invocation, argumentsSpan, argumentIndex, argumentCount };
}
interface ContextualSignatureLocationInfo {readonly contextualType: Type; readonly argumentIndex: number; readonly argumentCount: number; readonly argumentsSpan: TextSpan; }
function getContextualSignatureLocationInfo(startingToken: Node, sourceFile: SourceFile, checker: TypeChecker): ContextualSignatureLocationInfo | undefined {
if (startingToken.kind !== SyntaxKind.OpenParenToken && startingToken.kind !== SyntaxKind.CommaToken) return undefined;
const { parent } = startingToken;
switch (parent.kind) {
case SyntaxKind.ParenthesizedExpression:
case SyntaxKind.MethodDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
const info = getArgumentOrParameterListInfo(startingToken, sourceFile);
if (!info) return undefined;
const { argumentIndex, argumentCount, argumentsSpan } = info;
const contextualType = isMethodDeclaration(parent) ? checker.getContextualTypeForObjectLiteralElement(parent) : checker.getContextualType(parent as ParenthesizedExpression | FunctionExpression | ArrowFunction);
return contextualType && { contextualType, argumentIndex, argumentCount, argumentsSpan };
case SyntaxKind.BinaryExpression: {
const highestBinary = getHighestBinary(parent as BinaryExpression);
const contextualType = checker.getContextualType(highestBinary);
const argumentIndex = startingToken.kind === SyntaxKind.OpenParenToken ? 0 : countBinaryExpressionParameters(parent as BinaryExpression) - 1;
const argumentCount = countBinaryExpressionParameters(highestBinary);
return contextualType && { contextualType, argumentIndex, argumentCount, argumentsSpan: createTextSpanFromNode(parent) };
}
default:
return undefined;
}
}
// The type of a function type node has a symbol at that node, but it's better to use the symbol for a parameter or type alias.
function chooseBetterSymbol(s: Symbol): Symbol {
return s.name === InternalSymbolName.Type
? firstDefined(s.declarations, d => isFunctionTypeNode(d) ? d.parent.symbol : undefined) || s
: s;
}
function getArgumentIndex(argumentsList: Node, node: Node) {
@@ -323,7 +405,7 @@ namespace ts.SignatureHelp {
Debug.assertLessThan(argumentIndex, argumentCount);
}
return {
kind: ArgumentListKind.TaggedTemplateArguments,
isTypeParameterList: false,
invocation: { kind: InvocationKind.Call, node: tagExpression },
argumentsSpan: getApplicableSpanForTaggedTemplate(tagExpression, sourceFile),
argumentIndex,
@@ -368,12 +450,12 @@ namespace ts.SignatureHelp {
return createTextSpan(applicableSpanStart, applicableSpanEnd - applicableSpanStart);
}
function getContainingArgumentInfo(node: Node, position: number, sourceFile: SourceFile): ArgumentListInfo | undefined {
function getContainingArgumentInfo(node: Node, position: number, sourceFile: SourceFile, checker: TypeChecker): ArgumentListInfo | undefined {
for (let n = node; !isBlock(n) && !isSourceFile(n); n = n.parent) {
// If the node is not a subspan of its parent, this is a big problem.
// There have been crashes that might be caused by this violation.
Debug.assert(rangeContainsRange(n.parent, n), "Not a subspan", () => `Child: ${Debug.showSyntaxKind(n)}, parent: ${Debug.showSyntaxKind(n.parent)}`);
const argumentInfo = getImmediatelyContainingArgumentInfo(n, position, sourceFile);
const argumentInfo = getImmediatelyContainingArgumentOrContextualParameterInfo(n, position, sourceFile, checker);
if (argumentInfo) {
return argumentInfo;
}
@@ -388,17 +470,24 @@ namespace ts.SignatureHelp {
return children[indexOfOpenerToken + 1];
}
function getExpressionFromInvocation(invocation: Invocation): Expression {
function getExpressionFromInvocation(invocation: CallInvocation | TypeArgsInvocation): Expression {
return invocation.kind === InvocationKind.Call ? getInvokedExpression(invocation.node) : invocation.called;
}
const signatureHelpNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;
function createSignatureHelpItems(candidates: ReadonlyArray<Signature>, resolvedSignature: Signature, argumentListInfo: ArgumentListInfo, sourceFile: SourceFile, typeChecker: TypeChecker): SignatureHelpItems {
const { argumentCount, argumentsSpan: applicableSpan, invocation, argumentIndex } = argumentListInfo;
const isTypeParameterList = argumentListInfo.kind === ArgumentListKind.TypeArguments;
function getEnclosingDeclarationFromInvocation(invocation: Invocation): Node {
return invocation.kind === InvocationKind.Call ? invocation.node : invocation.kind === InvocationKind.TypeArgs ? invocation.called : invocation.node;
}
const enclosingDeclaration = invocation.kind === InvocationKind.Call ? invocation.node : invocation.called;
const callTargetSymbol = typeChecker.getSymbolAtLocation(getExpressionFromInvocation(invocation));
const signatureHelpNodeBuilderFlags = NodeBuilderFlags.OmitParameterModifiers | NodeBuilderFlags.IgnoreErrors | NodeBuilderFlags.UseAliasDefinedOutsideCurrentScope;
function createSignatureHelpItems(
candidates: ReadonlyArray<Signature>,
resolvedSignature: Signature,
{ isTypeParameterList, argumentCount, argumentsSpan: applicableSpan, invocation, argumentIndex }: ArgumentListInfo,
sourceFile: SourceFile,
typeChecker: TypeChecker,
): SignatureHelpItems {
const enclosingDeclaration = getEnclosingDeclarationFromInvocation(invocation);
const callTargetSymbol = invocation.kind === InvocationKind.Contextual ? invocation.symbol : typeChecker.getSymbolAtLocation(getExpressionFromInvocation(invocation));
const callTargetDisplayParts = callTargetSymbol ? symbolToDisplayParts(typeChecker, callTargetSymbol, /*enclosingDeclaration*/ undefined, /*meaning*/ undefined) : emptyArray;
const items = candidates.map(candidateSignature => getSignatureHelpItem(candidateSignature, callTargetDisplayParts, isTypeParameterList, typeChecker, enclosingDeclaration, sourceFile));
@@ -412,11 +501,36 @@ namespace ts.SignatureHelp {
return { items, applicableSpan, selectedItemIndex, argumentIndex, argumentCount };
}
function createTypeHelpItems(
symbol: Symbol,
{ argumentCount, argumentsSpan: applicableSpan, invocation, argumentIndex }: ArgumentListInfo,
sourceFile: SourceFile,
checker: TypeChecker
): SignatureHelpItems | undefined {
const typeParameters = checker.getLocalTypeParametersOfClassOrInterfaceOrTypeAlias(symbol);
if (!typeParameters) return undefined;
const items = [getTypeHelpItem(symbol, typeParameters, checker, getEnclosingDeclarationFromInvocation(invocation), sourceFile)];
return { items, applicableSpan, selectedItemIndex: 0, argumentIndex, argumentCount };
}
function getTypeHelpItem(symbol: Symbol, typeParameters: ReadonlyArray<TypeParameter>, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem {
const typeSymbolDisplay = symbolToDisplayParts(checker, symbol);
const printer = createPrinter({ removeComments: true });
const parameters = typeParameters.map(t => createSignatureHelpParameterForTypeParameter(t, checker, enclosingDeclaration, sourceFile, printer));
const documentation = symbol.getDocumentationComment(checker);
const tags = symbol.getJsDocTags();
const prefixDisplayParts = [...typeSymbolDisplay, punctuationPart(SyntaxKind.LessThanToken)];
return { isVariadic: false, prefixDisplayParts, suffixDisplayParts: [punctuationPart(SyntaxKind.GreaterThanToken)], separatorDisplayParts, parameters, documentation, tags };
}
const separatorDisplayParts: SymbolDisplayPart[] = [punctuationPart(SyntaxKind.CommaToken), spacePart()];
function getSignatureHelpItem(candidateSignature: Signature, callTargetDisplayParts: ReadonlyArray<SymbolDisplayPart>, isTypeParameterList: boolean, checker: TypeChecker, enclosingDeclaration: Node, sourceFile: SourceFile): SignatureHelpItem {
const { isVariadic, parameters, prefix, suffix } = (isTypeParameterList ? itemInfoForTypeParameters : itemInfoForParameters)(candidateSignature, checker, enclosingDeclaration, sourceFile);
const prefixDisplayParts = [...callTargetDisplayParts, ...prefix];
const suffixDisplayParts = [...suffix, ...returnTypeToDisplayParts(candidateSignature, enclosingDeclaration, checker)];
const separatorDisplayParts = [punctuationPart(SyntaxKind.CommaToken), spacePart()];
const documentation = candidateSignature.getDocumentationComment(checker);
const tags = candidateSignature.getJsDocTags();
return { isVariadic, prefixDisplayParts, suffixDisplayParts, separatorDisplayParts, parameters, documentation, tags };
@@ -477,6 +591,6 @@ namespace ts.SignatureHelp {
const param = checker.typeParameterToDeclaration(typeParameter, enclosingDeclaration)!;
printer.writeNode(EmitHint.Unspecified, param, sourceFile, writer);
});
return { name: typeParameter.symbol.name, documentation: emptyArray, displayParts, isOptional: false };
return { name: typeParameter.symbol.name, documentation: typeParameter.symbol.getDocumentationComment(checker), displayParts, isOptional: false };
}
}
+62
View File
@@ -3,6 +3,7 @@ namespace ts {
export function computeSuggestionDiagnostics(sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): DiagnosticWithLocation[] {
program.getSemanticDiagnostics(sourceFile, cancellationToken);
const diags: DiagnosticWithLocation[] = [];
const checker = program.getTypeChecker();
if (sourceFile.commonJsModuleIndicator &&
(programContainsEs6Modules(program) || compilerOptionsIndicateEs6Modules(program.getCompilerOptions())) &&
@@ -68,6 +69,9 @@ namespace ts {
}
}
if (isFunctionLikeDeclaration(node)) {
addConvertToAsyncFunctionDiagnostics(node, checker, diags);
}
node.forEachChild(check);
}
}
@@ -109,7 +113,65 @@ namespace ts {
}
}
function addConvertToAsyncFunctionDiagnostics(node: FunctionLikeDeclaration, checker: TypeChecker, diags: DiagnosticWithLocation[]): void {
if (isAsyncFunction(node) || !node.body) {
return;
}
const functionType = checker.getTypeAtLocation(node);
const callSignatures = checker.getSignaturesOfType(functionType, SignatureKind.Call);
const returnType = callSignatures.length ? checker.getReturnTypeOfSignature(callSignatures[0]) : undefined;
if (!returnType || !checker.getPromisedTypeOfPromise(returnType)) {
return;
}
// collect all the return statements
// check that a property access expression exists in there and that it is a handler
const returnStatements = getReturnStatementsWithPromiseHandlers(node);
if (returnStatements.length > 0) {
diags.push(createDiagnosticForNode(isVariableDeclaration(node.parent) ? node.parent.name : node, Diagnostics.This_may_be_converted_to_an_async_function));
}
}
function getErrorNodeFromCommonJsIndicator(commonJsModuleIndicator: Node): Node {
return isBinaryExpression(commonJsModuleIndicator) ? commonJsModuleIndicator.left : commonJsModuleIndicator;
}
/** @internal */
export function getReturnStatementsWithPromiseHandlers(node: Node): Node[] {
const returnStatements: Node[] = [];
if (isFunctionLike(node)) {
forEachChild(node, visit);
}
else {
visit(node);
}
function visit(child: Node) {
if (isFunctionLike(child)) {
return;
}
if (isReturnStatement(child)) {
forEachChild(child, addHandlers);
}
function addHandlers(returnChild: Node) {
if (isPromiseHandler(returnChild)) {
returnStatements.push(child as ReturnStatement);
}
}
forEachChild(child, visit);
}
return returnStatements;
}
function isPromiseHandler(node: Node): boolean {
return (isCallExpression(node) && isPropertyAccessExpression(node.expression) &&
(node.expression.name.text === "then" || node.expression.name.text === "catch"));
}
}
+2 -1
View File
@@ -611,7 +611,8 @@ namespace ts.SymbolDisplay {
displayParts.push(textPart(allSignatures.length === 2 ? "overload" : "overloads"));
displayParts.push(punctuationPart(SyntaxKind.CloseParenToken));
}
documentation = signature.getDocumentationComment(typeChecker);
const docComment = signature.getDocumentationComment(typeChecker);
documentation = docComment.length === 0 ? undefined : docComment;
tags = signature.getJsDocTags();
}
+11 -11
View File
@@ -291,7 +291,7 @@ namespace ts.textChanges {
}
public insertNodeAt(sourceFile: SourceFile, pos: number, newNode: Node, options: InsertNodeOptions = {}) {
this.replaceRange(sourceFile, createTextRange(pos), newNode, options);
this.replaceRange(sourceFile, createRange(pos), newNode, options);
}
private insertNodesAt(sourceFile: SourceFile, pos: number, newNodes: ReadonlyArray<Node>, options: ReplaceWithMultipleNodesOptions = {}): void {
@@ -334,7 +334,7 @@ namespace ts.textChanges {
}
public insertText(sourceFile: SourceFile, pos: number, text: string): void {
this.replaceRangeWithText(sourceFile, createTextRange(pos), text);
this.replaceRangeWithText(sourceFile, createRange(pos), text);
}
/** Prefer this over replacing a node with another that has a type annotation, as it avoids reformatting the other parts of the node. */
@@ -409,14 +409,14 @@ namespace ts.textChanges {
});
}
public insertNodeAtClassStart(sourceFile: SourceFile, cls: ClassLikeDeclaration, newElement: ClassElement): void {
public insertNodeAtClassStart(sourceFile: SourceFile, cls: ClassLikeDeclaration | InterfaceDeclaration, newElement: ClassElement): void {
const clsStart = cls.getStart(sourceFile);
const indentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn(getLineStartPositionForPosition(clsStart, sourceFile), clsStart, sourceFile, this.formatContext.options)
+ this.formatContext.options.indentSize!;
this.insertNodeAt(sourceFile, cls.members.pos, newElement, { indentation, ...this.getInsertNodeAtClassStartPrefixSuffix(sourceFile, cls) });
}
private getInsertNodeAtClassStartPrefixSuffix(sourceFile: SourceFile, cls: ClassLikeDeclaration): { prefix: string, suffix: string } {
private getInsertNodeAtClassStartPrefixSuffix(sourceFile: SourceFile, cls: ClassLikeDeclaration | InterfaceDeclaration): { prefix: string, suffix: string } {
if (cls.members.length === 0) {
if (addToSeen(this.classesWithNodesInsertedAtStart, getNodeId(cls), cls)) {
// For `class C {\n}`, don't add the trailing "\n"
@@ -456,7 +456,7 @@ namespace ts.textChanges {
// check if previous statement ends with semicolon
// if not - insert semicolon to preserve the code from changing the meaning due to ASI
if (sourceFile.text.charCodeAt(after.end - 1) !== CharacterCodes.semicolon) {
this.replaceRange(sourceFile, createTextRange(after.end), createToken(SyntaxKind.SemicolonToken));
this.replaceRange(sourceFile, createRange(after.end), createToken(SyntaxKind.SemicolonToken));
}
}
const endPosition = getAdjustedEndPosition(sourceFile, after, {});
@@ -595,7 +595,7 @@ namespace ts.textChanges {
// write separator and leading trivia of the next element as suffix
const suffix = `${tokenToString(nextToken.kind)}${sourceFile.text.substring(nextToken.end, containingList[index + 1].getStart(sourceFile))}`;
this.replaceRange(sourceFile, createTextRange(startPos, containingList[index + 1].getStart(sourceFile)), newNode, { prefix, suffix });
this.replaceRange(sourceFile, createRange(startPos, containingList[index + 1].getStart(sourceFile)), newNode, { prefix, suffix });
}
}
else {
@@ -629,7 +629,7 @@ namespace ts.textChanges {
}
if (multilineList) {
// insert separator immediately following the 'after' node to preserve comments in trailing trivia
this.replaceRange(sourceFile, createTextRange(end), createToken(separator));
this.replaceRange(sourceFile, createRange(end), createToken(separator));
// use the same indentation as 'after' item
const indentation = formatting.SmartIndenter.findFirstNonWhitespaceColumn(afterStartLinePosition, afterStart, sourceFile, this.formatContext.options);
// insert element before the line break on the line that contains 'after' element
@@ -637,10 +637,10 @@ namespace ts.textChanges {
if (insertPos !== end && isLineBreak(sourceFile.text.charCodeAt(insertPos - 1))) {
insertPos--;
}
this.replaceRange(sourceFile, createTextRange(insertPos), newNode, { indentation, prefix: this.newLineCharacter });
this.replaceRange(sourceFile, createRange(insertPos), newNode, { indentation, prefix: this.newLineCharacter });
}
else {
this.replaceRange(sourceFile, createTextRange(end), newNode, { prefix: `${tokenToString(separator)} ` });
this.replaceRange(sourceFile, createRange(end), newNode, { prefix: `${tokenToString(separator)} ` });
}
}
return this;
@@ -652,7 +652,7 @@ namespace ts.textChanges {
const [openBraceEnd, closeBraceEnd] = getClassBraceEnds(cls, sourceFile);
// For `class C { }` remove the whitespace inside the braces.
if (positionsAreOnSameLine(openBraceEnd, closeBraceEnd, sourceFile) && openBraceEnd !== closeBraceEnd - 1) {
this.deleteRange(sourceFile, createTextRange(openBraceEnd, closeBraceEnd - 1));
this.deleteRange(sourceFile, createRange(openBraceEnd, closeBraceEnd - 1));
}
});
}
@@ -708,7 +708,7 @@ namespace ts.textChanges {
return skipTrivia(sourceFile.text, getAdjustedStartPosition(sourceFile, node, {}, Position.FullStart), /*stopAfterLineBreak*/ false, /*stopAtComments*/ true);
}
function getClassBraceEnds(cls: ClassLikeDeclaration, sourceFile: SourceFile): [number, number] {
function getClassBraceEnds(cls: ClassLikeDeclaration | InterfaceDeclaration, sourceFile: SourceFile): [number, number] {
return [findChildOfKind(cls, SyntaxKind.OpenBraceToken, sourceFile)!.end, findChildOfKind(cls, SyntaxKind.CloseBraceToken, sourceFile)!.end];
}
+1
View File
@@ -46,6 +46,7 @@
"codefixes/addMissingInvocationForDecorator.ts",
"codefixes/annotateWithTypeFromJSDoc.ts",
"codefixes/convertFunctionToEs6Class.ts",
"codefixes/convertToAsyncFunction.ts",
"codefixes/convertToEs6Module.ts",
"codefixes/correctQualifiedNameToIndexedAccessType.ts",
"codefixes/fixClassIncorrectlyImplementsInterface.ts",
-8
View File
@@ -233,14 +233,6 @@ namespace ts {
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
}
export interface UserPreferences {
readonly disableSuggestions?: boolean;
readonly quotePreference?: "double" | "single";
readonly includeCompletionsForModuleExports?: boolean;
readonly includeCompletionsWithInsertText?: boolean;
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
readonly allowTextChangesInNewFiles?: boolean;
}
/* @internal */
export const emptyOptions = {};
+45 -15
View File
@@ -226,7 +226,7 @@ namespace ts {
export function isJumpStatementTarget(node: Node): node is Identifier & { parent: BreakOrContinueStatement } {
return node.kind === SyntaxKind.Identifier && isBreakOrContinueStatement(node.parent) && node.parent.label === node;
}
}
export function isLabelOfLabeledStatement(node: Node): node is Identifier {
return node.kind === SyntaxKind.Identifier && isLabeledStatement(node.parent) && node.parent.label === node;
@@ -396,7 +396,7 @@ namespace ts {
export function isThis(node: Node): boolean {
switch (node.kind) {
case SyntaxKind.ThisKeyword:
// case SyntaxKind.ThisType: TODO: GH#9267
// case SyntaxKind.ThisType: TODO: GH#9267
return true;
case SyntaxKind.Identifier:
// 'this' as a parameter
@@ -755,7 +755,7 @@ namespace ts {
return result;
function find(n: Node): Node | undefined {
if (isNonWhitespaceToken(n)) {
if (isNonWhitespaceToken(n) && n.kind !== SyntaxKind.EndOfFileToken) {
return n;
}
@@ -786,16 +786,14 @@ namespace ts {
}
}
Debug.assert(startNode !== undefined || n.kind === SyntaxKind.SourceFile || isJSDocCommentContainingNode(n));
Debug.assert(startNode !== undefined || n.kind === SyntaxKind.SourceFile || n.kind === SyntaxKind.EndOfFileToken || isJSDocCommentContainingNode(n));
// Here we know that none of child token nodes embrace the position,
// the only known case is when position is at the end of the file.
// Try to find the rightmost token in the file without filtering.
// Namely we are skipping the check: 'position < node.end'
if (children.length) {
const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length, sourceFile);
return candidate && findRightmostToken(candidate, sourceFile);
}
const candidate = findRightmostChildNodeWithTokens(children, /*exclusiveStartPosition*/ children.length, sourceFile);
return candidate && findRightmostToken(candidate, sourceFile);
}
}
@@ -1048,7 +1046,7 @@ namespace ts {
function nodeHasTokens(n: Node, sourceFile: SourceFileLike): boolean {
// If we have a token or node that has a non-zero width, it must have tokens.
// Note: getWidth() does not take trivia into account.
return n.getWidth(sourceFile) !== 0;
return n.kind === SyntaxKind.EndOfFileToken ? !!(n as EndOfFileToken).jsDoc : n.getWidth(sourceFile) !== 0;
}
export function getNodeModifiers(node: Node): string {
@@ -1165,7 +1163,7 @@ namespace ts {
}
export function createTextRangeFromNode(node: Node, sourceFile: SourceFile): TextRange {
return createTextRange(node.getStart(sourceFile), node.end);
return createRange(node.getStart(sourceFile), node.end);
}
export function createTextSpanFromRange(range: TextRange): TextSpan {
@@ -1173,7 +1171,7 @@ namespace ts {
}
export function createTextRangeFromSpan(span: TextSpan): TextRange {
return createTextRange(span.start, span.start + span.length);
return createRange(span.start, span.start + span.length);
}
export function createTextChangeFromStartLength(start: number, length: number, newText: string): TextChange {
@@ -1187,6 +1185,7 @@ namespace ts {
export const typeKeywords: ReadonlyArray<SyntaxKind> = [
SyntaxKind.AnyKeyword,
SyntaxKind.BooleanKeyword,
SyntaxKind.FalseKeyword,
SyntaxKind.KeyOfKeyword,
SyntaxKind.NeverKeyword,
SyntaxKind.NullKeyword,
@@ -1194,6 +1193,7 @@ namespace ts {
SyntaxKind.ObjectKeyword,
SyntaxKind.StringKeyword,
SyntaxKind.SymbolKeyword,
SyntaxKind.TrueKeyword,
SyntaxKind.VoidKeyword,
SyntaxKind.UndefinedKeyword,
SyntaxKind.UniqueKeyword,
@@ -1232,13 +1232,13 @@ namespace ts {
}
export function skipConstraint(type: Type): Type {
return type.isTypeParameter() ? type.getConstraint()! : type; // TODO: GH#18217
return type.isTypeParameter() ? type.getConstraint() || type : type;
}
export function getNameFromPropertyName(name: PropertyName): string | undefined {
return name.kind === SyntaxKind.ComputedPropertyName
// treat computed property names where expression is string/numeric literal as just string/numeric literal
? isStringOrNumericLiteral(name.expression) ? name.expression.text : undefined
? isStringOrNumericLiteralLike(name.expression) ? name.expression.text : undefined
: getTextOfIdentifierOrLiteral(name);
}
@@ -1654,8 +1654,34 @@ namespace ts {
return clone;
}
function getSynthesizedDeepCloneWorker<T extends Node>(node: T): T {
const visited = visitEachChild(node, getSynthesizedDeepClone, nullTransformationContext);
export function getSynthesizedDeepCloneWithRenames<T extends Node | undefined>(node: T, includeTrivia = true, renameMap?: Map<Identifier>, checker?: TypeChecker, callback?: (originalNode: Node, clone: Node) => any): T {
let clone;
if (node && isIdentifier(node!) && renameMap && checker) {
const symbol = checker.getSymbolAtLocation(node!);
const renameInfo = symbol && renameMap.get(String(getSymbolId(symbol)));
if (renameInfo) {
clone = createIdentifier(renameInfo.text);
}
}
if (!clone) {
clone = node && getSynthesizedDeepCloneWorker(node as NonNullable<T>, renameMap, checker, callback);
}
if (clone && !includeTrivia) suppressLeadingAndTrailingTrivia(clone);
if (callback && node) callback(node!, clone);
return clone as T;
}
function getSynthesizedDeepCloneWorker<T extends Node>(node: T, renameMap?: Map<Identifier>, checker?: TypeChecker, callback?: (originalNode: Node, clone: Node) => any): T {
const visited = (renameMap || checker || callback) ?
visitEachChild(node, wrapper, nullTransformationContext) :
visitEachChild(node, getSynthesizedDeepClone, nullTransformationContext);
if (visited === node) {
// This only happens for leaf nodes - internal nodes always see their children change.
const clone = getSynthesizedClone(node);
@@ -1673,6 +1699,10 @@ namespace ts {
// would have made.
visited.parent = undefined!;
return visited;
function wrapper(node: T) {
return getSynthesizedDeepCloneWithRenames(node, /*includeTrivia*/ true, renameMap, checker, callback);
}
}
export function getSynthesizedDeepClones<T extends Node>(nodes: NodeArray<T>, includeTrivia?: boolean): NodeArray<T>;
+15 -14
View File
@@ -207,24 +207,19 @@ class CompilerTest {
public verifyModuleResolution() {
if (this.options.traceResolution) {
Harness.Baseline.runBaseline(this.justName.replace(/\.tsx?$/, ".trace.json"), () => {
return utils.removeTestPathPrefixes(JSON.stringify(this.result.traces, undefined, 4));
});
Harness.Baseline.runBaseline(this.justName.replace(/\.tsx?$/, ".trace.json"),
utils.removeTestPathPrefixes(JSON.stringify(this.result.traces, undefined, 4)));
}
}
public verifySourceMapRecord() {
if (this.options.sourceMap || this.options.inlineSourceMap || this.options.declarationMap) {
Harness.Baseline.runBaseline(this.justName.replace(/\.tsx?$/, ".sourcemap.txt"), () => {
const record = utils.removeTestPathPrefixes(this.result.getSourceMapRecord()!);
if ((this.options.noEmitOnError && this.result.diagnostics.length !== 0) || record === undefined) {
// Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required.
/* tslint:disable:no-null-keyword */
return null;
/* tslint:enable:no-null-keyword */
}
return record;
});
const record = utils.removeTestPathPrefixes(this.result.getSourceMapRecord()!);
const baseline = (this.options.noEmitOnError && this.result.diagnostics.length !== 0) || record === undefined
// Because of the noEmitOnError option no files are created. We need to return null because baselining isn't required.
? null // tslint:disable-line no-null-keyword
: record;
Harness.Baseline.runBaseline(this.justName.replace(/\.tsx?$/, ".sourcemap.txt"), baseline);
}
}
@@ -258,7 +253,13 @@ class CompilerTest {
Harness.Compiler.doTypeAndSymbolBaseline(
this.justName,
this.result.program!,
this.toBeCompiled.concat(this.otherFiles).filter(file => !!this.result.program!.getSourceFile(file.unitName)));
this.toBeCompiled.concat(this.otherFiles).filter(file => !!this.result.program!.getSourceFile(file.unitName)),
/*opts*/ undefined,
/*multifile*/ undefined,
/*skipTypeBaselines*/ undefined,
/*skipSymbolBaselines*/ undefined,
!!ts.length(this.result.diagnostics)
);
}
private makeUnitName(name: string, root: string) {
+3 -4
View File
@@ -80,9 +80,7 @@ abstract class ExternalCompileRunnerBase extends RunnerBase {
if (install.status !== 0) throw new Error(`NPM Install types for ${directoryName} failed: ${install.stderr.toString()}`);
}
args.push("--noEmit");
Harness.Baseline.runBaseline(`${cls.kind()}/${directoryName}.log`, () => {
return cls.report(cp.spawnSync(`node`, args, { cwd, timeout, shell: true }), cwd);
});
Harness.Baseline.runBaseline(`${cls.kind()}/${directoryName}.log`, cls.report(cp.spawnSync(`node`, args, { cwd, timeout, shell: true }), cwd));
});
});
}
@@ -138,7 +136,8 @@ function compareErrorStrings(a: string[], b: string[]) {
return ts.comparePathsCaseSensitive(errorFileA, errorFileB) ||
ts.compareValues(parseInt(lineNumberStringA), parseInt(lineNumberStringB)) ||
ts.compareValues(parseInt(columnNumberStringA), parseInt(columnNumberStringB)) ||
ts.compareStringsCaseSensitive(remainderA, remainderB);
ts.compareStringsCaseSensitive(remainderA, remainderB) ||
ts.compareStringsCaseSensitive(a.slice(1).join("\n"), b.slice(1).join("\n"));
}
class DefinitelyTypedRunner extends ExternalCompileRunnerBase {
+4 -8
View File
@@ -211,14 +211,12 @@ namespace project {
.map(output => utils.removeTestPathPrefixes(vpath.isAbsolute(output) ? vpath.relative(cwd, output, ignoreCase) : output));
const content = JSON.stringify(resolutionInfo, undefined, " ");
Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + ".json", () => content);
Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + ".json", content);
}
public verifyDiagnostics() {
if (this.compilerResult.errors.length) {
Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + ".errors.txt", () => {
return getErrorsBaseline(this.compilerResult);
});
Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + ".errors.txt", getErrorsBaseline(this.compilerResult));
}
}
@@ -244,7 +242,7 @@ namespace project {
}
const content = utils.removeTestPathPrefixes(output.text, /*retainTrailingDirectorySeparator*/ true);
Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + diskRelativeName, () => content as string | null); // TODO: GH#18217
Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + diskRelativeName, content as string | null); // TODO: GH#18217
}
catch (e) {
errs.push(e);
@@ -271,9 +269,7 @@ namespace project {
if (!this.compilerResult.errors.length && this.testCase.declaration) {
const dTsCompileResult = this.compileDeclarations(this.compilerResult);
if (dTsCompileResult && dTsCompileResult.errors.length) {
Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + ".dts.errors.txt", () => {
return getErrorsBaseline(dTsCompileResult);
});
Harness.Baseline.runBaseline(this.getBaselineFolder(this.compilerResult.moduleKind) + this.testCaseJustName + ".dts.errors.txt", getErrorsBaseline(dTsCompileResult));
}
}
}
+7 -16
View File
@@ -63,21 +63,14 @@ class Test262BaselineRunner extends RunnerBase {
});
it("has the expected emitted code", () => {
Harness.Baseline.runBaseline(testState.filename + ".output.js", () => {
const files = Array.from(testState.compilerResult.js.values()).filter(f => f.file !== Test262BaselineRunner.helpersFilePath);
return Harness.Compiler.collateOutputs(files);
}, Test262BaselineRunner.baselineOptions);
const files = Array.from(testState.compilerResult.js.values()).filter(f => f.file !== Test262BaselineRunner.helpersFilePath);
Harness.Baseline.runBaseline(testState.filename + ".output.js", Harness.Compiler.collateOutputs(files), Test262BaselineRunner.baselineOptions);
});
it("has the expected errors", () => {
Harness.Baseline.runBaseline(testState.filename + ".errors.txt", () => {
const errors = testState.compilerResult.diagnostics;
if (errors.length === 0) {
return null;
}
return Harness.Compiler.getErrorBaseline(testState.inputFiles, errors);
}, Test262BaselineRunner.baselineOptions);
const errors = testState.compilerResult.diagnostics;
const baseline = errors.length === 0 ? null : Harness.Compiler.getErrorBaseline(testState.inputFiles, errors);
Harness.Baseline.runBaseline(testState.filename + ".errors.txt", baseline, Test262BaselineRunner.baselineOptions);
});
it("satisfies invariants", () => {
@@ -86,10 +79,8 @@ class Test262BaselineRunner extends RunnerBase {
});
it("has the expected AST", () => {
Harness.Baseline.runBaseline(testState.filename + ".AST.txt", () => {
const sourceFile = testState.compilerResult.program!.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename))!;
return Utils.sourceFileToJSON(sourceFile);
}, Test262BaselineRunner.baselineOptions);
const sourceFile = testState.compilerResult.program!.getSourceFile(Test262BaselineRunner.getTestFilePath(testState.filename))!;
Harness.Baseline.runBaseline(testState.filename + ".AST.txt", Utils.sourceFileToJSON(sourceFile), Test262BaselineRunner.baselineOptions);
});
});
}
+3
View File
@@ -46,8 +46,10 @@
"unittests/cancellableLanguageServiceOperations.ts",
"unittests/commandLineParsing.ts",
"unittests/compileOnSave.ts",
"unittests/compilerCore.ts",
"unittests/configurationExtension.ts",
"unittests/convertCompilerOptionsFromJson.ts",
"unittests/convertToAsyncFunction.ts",
"unittests/convertToBase64.ts",
"unittests/convertTypeAcquisitionFromJson.ts",
"unittests/customTransforms.ts",
@@ -79,6 +81,7 @@
"unittests/transform.ts",
"unittests/transpile.ts",
"unittests/tsbuild.ts",
"unittests/tsbuildWatchMode.ts",
"unittests/tsconfigParsing.ts",
"unittests/tscWatchMode.ts",
"unittests/versionCache.ts",
@@ -366,4 +366,120 @@ namespace ts {
});
});
});
describe("parseBuildOptions", () => {
function assertParseResult(commandLine: string[], expectedParsedBuildCommand: ParsedBuildCommand) {
const parsed = parseBuildCommand(commandLine);
const parsedBuildOptions = JSON.stringify(parsed.buildOptions);
const expectedBuildOptions = JSON.stringify(expectedParsedBuildCommand.buildOptions);
assert.equal(parsedBuildOptions, expectedBuildOptions);
const parsedErrors = parsed.errors;
const expectedErrors = expectedParsedBuildCommand.errors;
assert.isTrue(parsedErrors.length === expectedErrors.length, `Expected error: ${JSON.stringify(expectedErrors)}. Actual error: ${JSON.stringify(parsedErrors)}.`);
for (let i = 0; i < parsedErrors.length; i++) {
const parsedError = parsedErrors[i];
const expectedError = expectedErrors[i];
assert.equal(parsedError.code, expectedError.code);
assert.equal(parsedError.category, expectedError.category);
assert.equal(parsedError.messageText, expectedError.messageText);
}
const parsedProjects = parsed.projects;
const expectedProjects = expectedParsedBuildCommand.projects;
assert.deepEqual(parsedProjects, expectedProjects, `Expected projects: [${JSON.stringify(expectedProjects)}]. Actual projects: [${JSON.stringify(parsedProjects)}].`);
}
it("parse build without any options ", () => {
// --lib es6 0.ts
assertParseResult([],
{
errors: [],
projects: ["."],
buildOptions: {}
});
});
it("Parse multiple options", () => {
// --lib es5,es2015.symbol.wellknown 0.ts
assertParseResult(["--verbose", "--force", "tests"],
{
errors: [],
projects: ["tests"],
buildOptions: { verbose: true, force: true }
});
});
it("Parse option with invalid option ", () => {
// --lib es5,invalidOption 0.ts
assertParseResult(["--verbose", "--invalidOption"],
{
errors: [{
messageText: "Unknown build option '--invalidOption'.",
category: Diagnostics.Unknown_build_option_0.category,
code: Diagnostics.Unknown_build_option_0.code,
file: undefined,
start: undefined,
length: undefined,
}],
projects: ["."],
buildOptions: { verbose: true }
});
});
it("Parse multiple flags with input projects at the end", () => {
// --lib es5,es2015.symbol.wellknown --target es5 0.ts
assertParseResult(["--force", "--verbose", "src", "tests"],
{
errors: [],
projects: ["src", "tests"],
buildOptions: { force: true, verbose: true }
});
});
it("Parse multiple flags with input projects in the middle", () => {
// --module commonjs --target es5 0.ts --lib es5,es2015.symbol.wellknown
assertParseResult(["--force", "src", "tests", "--verbose"],
{
errors: [],
projects: ["src", "tests"],
buildOptions: { force: true, verbose: true }
});
});
it("Parse multiple flags with input projects in the beginning", () => {
// --module commonjs --target es5 0.ts --lib es5,es2015.symbol.wellknown
assertParseResult(["src", "tests", "--force", "--verbose"],
{
errors: [],
projects: ["src", "tests"],
buildOptions: { force: true, verbose: true }
});
});
describe("Combining options that make no sense together", () => {
function verifyInvalidCombination(flag1: keyof BuildOptions, flag2: keyof BuildOptions) {
it(`--${flag1} and --${flag2} together is invalid`, () => {
// --module commonjs --target es5 0.ts --lib es5,es2015.symbol.wellknown
assertParseResult([`--${flag1}`, `--${flag2}`],
{
errors: [{
messageText: `Options '${flag1}' and '${flag2}' cannot be combined.`,
category: Diagnostics.Options_0_and_1_cannot_be_combined.category,
code: Diagnostics.Options_0_and_1_cannot_be_combined.code,
file: undefined,
start: undefined,
length: undefined,
}],
projects: ["."],
buildOptions: { [flag1]: true, [flag2]: true }
});
});
}
verifyInvalidCombination("clean", "force");
verifyInvalidCombination("clean", "verbose");
verifyInvalidCombination("clean", "watch");
verifyInvalidCombination("watch", "dry");
});
});
}

Some files were not shown because too many files have changed in this diff Show More