Merge branch 'master' of https://github.com/Microsoft/TypeScript into bug/24542-bad-error-message-for-import-ing-an-export

This commit is contained in:
Alexander T
2018-10-18 11:49:58 +03:00
1907 changed files with 86658 additions and 47609 deletions
+1 -1
View File
@@ -16,7 +16,7 @@ Please fill in the *entire* template below.
-->
<!-- Please try to reproduce the issue with `typescript@next`. It may have already been fixed. -->
**TypeScript Version:** 3.1.0-dev.201xxxxx
**TypeScript Version:** 3.2.0-dev.201xxxxx
<!-- Search terms you tried before logging this (so others can find this issue more easily) -->
**Search Terms:**
+1
View File
@@ -20,6 +20,7 @@ branches:
- release-2.8
- release-2.9
- release-3.0
- release-3.1
install:
- npm uninstall typescript --no-save
+1
View File
@@ -0,0 +1 @@
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
+3 -3
View File
@@ -72,7 +72,7 @@ Your pull request should:
* Requests need not be a single commit, but should be a linear sequence of commits (i.e. no merge commits in your PR)
* It is desirable, but not necessary, for the tests to pass at each commit
* Have clear commit messages
* e.g. "Refactor feature", "Fix issue", "Add tests for issue"
* e.g. "Minor refactor in goToTypeDefinition", "Fix iterated type in for-await-of", "Add test for preserveWatchOutput on command line"
* Include adequate tests
* At least one test should fail in the absence of your non-test code changes. If your PR does not match this criteria, please specify why
* Tests should include reasonable permutations of the target fix/change
@@ -104,7 +104,7 @@ To run all tests, invoke the `runtests-parallel` target using jake:
jake runtests-parallel
```
This run will all tests; to run only a specific subset of tests, use:
This will run all tests; to run only a specific subset of tests, use:
```Shell
jake runtests tests=<regex>
@@ -194,6 +194,6 @@ to establish the new baselines as the desired behavior. This will change the fil
## Localization
All strings the user may see are stored in [`diagnosticMessages.json`](./src/compiler/diagnosticMessages.json).
If you make changes to it, run `jake generate-diagnostics` to push them to the `Diagnostic` interface in [`diagnosticInformationMap.generated.ts`](./src/compiler/diagnosticInformationMap.generated.ts).
If you make changes to it, run `jake generate-diagnostics` to push them to the `Diagnostic` interface in `diagnosticInformationMap.generated.ts`.
See [coding guidelines on diagnostic messages](https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines#diagnostic-messages).
+1 -1
View File
@@ -61,7 +61,7 @@ Change to the TypeScript directory:
cd TypeScript
```
Install Jake tools and dev dependencies:
Install [Jake](http://jakejs.com/) tools and dev dependencies:
```bash
npm install -g jake
+1 -1
View File
@@ -286,7 +286,7 @@ function f(s) {
}
```
In the JavaScript output, all type annotations have been erased. In general, TypeScript erases all type information before emiting JavaScript.
In the JavaScript output, all type annotations have been erased. In general, TypeScript erases all type information before emitting JavaScript.
## <a name="1.1"/>1.1 Ambient Declarations
+1 -1
View File
@@ -938,7 +938,7 @@
"Type_of_iterated_elements_of_a_yield_Asterisk_operand_must_either_be_a_valid_promise_or_must_not_con_1322": "Der Typ iterierter Elemente eines \"yield*\"-Operanden muss entweder eine gültige Zusage sein oder darf keinen aufrufbaren \"then\"-Member enthalten.",
"Type_of_yield_operand_in_an_async_generator_must_either_be_a_valid_promise_or_must_not_contain_a_cal_1321": "Der Typ eines \"yield\"-Operanden in einem asynchronen Generator muss entweder eine gültige Zusage sein oder darf keinen aufrufbaren \"then\"-Member enthalten.",
"Type_parameter_0_has_a_circular_constraint_2313": "Der Typparameter \"{0}\" weist eine zirkuläre Einschränkung auf.",
"Type_parameter_0_has_a_circular_default_2716": "Der Typparameter \"{0}\" weist einen zirkulären Standard auf.",
"Type_parameter_0_has_a_circular_default_2716": "Der Typparameter \"{0}\" besitzt einen zirkulären Standardwert.",
"Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1_4008": "Der Typparameter \"{0}\" der Aufrufsignatur aus der exportierten Schnittstelle besitzt oder verwendet den privaten Namen \"{1}\".",
"Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1_4006": "Der Typparameter \"{0}\" der Konstruktorsignatur aus der exportierten Schnittstelle besitzt oder verwendet den privaten Namen \"{1}\".",
"Type_parameter_0_of_exported_class_has_or_is_using_private_name_1_4002": "Der Typparameter \"{0}\" der exportierten Klasse besitzt oder verwendet den privaten Namen \"{1}\".",
+174 -18
View File
@@ -135,9 +135,9 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";A_const_initializer_in_an_ambient_context_must_be_a_string_or_numeric_literal_1254" ItemType="0" PsrId="306" Leaf="true">
<Item ItemId=";A_const_initializer_in_an_ambient_context_must_be_a_string_or_numeric_literal_or_literal_enum_refere_1254" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[A 'const' initializer in an ambient context must be a string or numeric literal.]]></Val>
<Val><![CDATA[A 'const' initializer in an ambient context must be a string or numeric literal or literal enum reference.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
@@ -861,6 +861,18 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";An_argument_for_0_was_not_provided_6210" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[An argument for '{0}' was not provided.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";An_argument_matching_this_binding_pattern_was_not_provided_6211" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[An argument matching this binding pattern was not provided.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";An_arithmetic_operand_must_be_of_type_any_number_or_an_enum_type_2356" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[An arithmetic operand must be of type 'any', 'number' or an enum type.]]></Val>
@@ -1233,6 +1245,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Build_option_0_requires_a_value_of_type_1_5073" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Build option '{0}' requires a value of type {1}.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Building_project_0_6358" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Building project '{0}'...]]></Val>
@@ -1401,6 +1419,36 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Cannot_find_name_0_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_2583" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Cannot find name '{0}'. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Cannot_find_name_0_Do_you_need_to_change_your_target_library_Try_changing_the_lib_compiler_option_to_2584" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Cannot find name '{0}'. Do you need to change your target library? Try changing the `lib` compiler option to include 'dom'.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_a_test_runner_Try_npm_i_types_Slashje_2582" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Cannot find name '{0}'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha`.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_jQuery_Try_npm_i_types_Slashjquery_2581" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Cannot find name '{0}'. Do you need to install type definitions for jQuery? Try `npm i @types/jquery`.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Cannot_find_name_0_Do_you_need_to_install_type_definitions_for_node_Try_npm_i_types_Slashnode_2580" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Cannot find name '{0}'. Do you need to install type definitions for node? Try `npm i @types/node`.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Cannot_find_namespace_0_2503" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Cannot find namespace '{0}'.]]></Val>
@@ -2001,6 +2049,18 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Did_you_mean_to_call_this_expression_6212" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Did you mean to call this expression?]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Did_you_mean_to_use_new_with_this_expression_6213" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Did you mean to use 'new' with this expression?]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Digit_expected_1124" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Digit expected.]]></Val>
@@ -2259,6 +2319,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Enable_strict_bind_call_and_apply_methods_on_functions_6214" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Enable strict 'bind', 'call', and 'apply' methods on functions.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Enable_strict_checking_of_function_types_6186" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Enable strict checking of function types.]]></Val>
@@ -2349,6 +2415,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Enum_type_0_circularly_references_itself_2586" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Enum type '{0}' circularly references itself.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Enum_type_0_has_members_with_initializers_that_are_not_literals_2535" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Enum type '{0}' has members with initializers that are not literals.]]></Val>
@@ -2421,9 +2493,9 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Expected_type_of_0_field_in_package_json_to_be_string_got_1_6105" ItemType="0" PsrId="306" Leaf="true">
<Item ItemId=";Expected_type_of_0_field_in_package_json_to_be_1_got_2_6105" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Expected type of '{0}' field in 'package.json' to be 'string', got '{1}'.]]></Val>
<Val><![CDATA[Expected type of '{0}' field in 'package.json' to be '{1}', got '{2}'.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
@@ -2781,6 +2853,18 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Generate_types_for_0_95067" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Generate types for '{0}']]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Generate_types_for_all_packages_without_types_95068" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Generate types for all packages without types]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Generates_a_sourcemap_for_each_corresponding_d_ts_file_6000" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Generates a sourcemap for each corresponding '.d.ts' file.]]></Val>
@@ -2829,12 +2913,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Generic_type_instantiation_is_excessively_deep_and_possibly_infinite_2550" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Generic type instantiation is excessively deep and possibly infinite.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Getter_and_setter_accessors_do_not_agree_in_visibility_2379" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Getter and setter accessors do not agree in visibility.]]></Val>
@@ -3225,6 +3303,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";It_is_highly_likely_that_you_are_missing_a_semicolon_2734" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[It is highly likely that you are missing a semicolon.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";JSDoc_0_1_does_not_match_the_extends_2_clause_8023" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[JSDoc '@{0} {1}' does not match the 'extends {2}' clause.]]></Val>
@@ -3255,6 +3339,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";JSDoc_type_0_circularly_references_itself_2587" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[JSDoc type '{0}' circularly references itself.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";JSDoc_typedef_tag_should_either_have_a_type_annotation_or_be_followed_by_property_or_member_tags_8021" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[JSDoc '@typedef' tag should either have a type annotation or be followed by '@property' or '@member' tags.]]></Val>
@@ -3705,6 +3795,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Non_simple_parameter_declared_here_1348" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Non-simple parameter declared here.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Not_all_code_paths_return_a_value_7030" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Not all code paths return a value.]]></Val>
@@ -3909,9 +4005,9 @@
</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">
<Item ItemId=";Option_resolveJsonModule_can_only_be_specified_when_module_code_generation_is_commonjs_amd_es2015_or_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>
<Val><![CDATA[Option '--resolveJsonModule' can only be specified when module code generation is 'commonjs', 'amd', 'es2015' or 'esNext'.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
@@ -5025,12 +5121,6 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Skipping_clean_because_not_all_projects_could_be_located_6371" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Skipping clean because not all projects could be located]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Source_Map_Options_6175" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Source Map Options]]></Val>
@@ -5313,6 +5403,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";The_expected_type_comes_from_the_return_type_of_this_signature_6502" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[The expected type comes from the return type of this signature.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";The_expected_type_comes_from_this_index_signature_6501" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[The expected type comes from this index signature.]]></Val>
@@ -5589,6 +5685,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";This_parameter_is_not_allowed_with_use_strict_directive_1346" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[This parameter is not allowed with 'use strict' directive.]]></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>
@@ -6051,6 +6153,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Unknown_build_option_0_5072" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Unknown build option '{0}'.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";Unknown_compiler_option_0_5023" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[Unknown compiler option '{0}'.]]></Val>
@@ -6207,6 +6315,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";You_cannot_rename_a_module_via_a_global_import_8031" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[You cannot rename a module via a global import.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library_8001" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA[You cannot rename elements that are defined in the standard TypeScript library.]]></Val>
@@ -6393,6 +6507,12 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";_0_only_refers_to_a_type_but_is_being_used_as_a_value_here_Do_you_need_to_change_your_target_library_2585" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA['{0}' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";_0_refers_to_a_UMD_global_but_the_current_file_is_a_module_Consider_adding_an_import_instead_2686" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA['{0}' refers to a UMD global, but the current file is a module. Consider adding an import instead.]]></Val>
@@ -6657,12 +6777,36 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";package_json_does_not_have_a_typesVersions_entry_that_matches_version_0_6207" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA['package.json' does not have a 'typesVersions' entry that matches version '{0}'.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";package_json_has_0_field_1_that_references_2_6101" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA['package.json' has '{0}' field '{1}' that references '{2}'.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";package_json_has_a_typesVersions_entry_0_that_is_not_a_valid_semver_range_6209" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA['package.json' has a 'typesVersions' entry '{0}' that is not a valid semver range.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_ma_6208" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA['package.json' has a 'typesVersions' entry '{0}' that matches compiler version '{1}', looking for a pattern to match module name '{2}'.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";package_json_has_a_typesVersions_field_with_version_specific_path_mappings_6206" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA['package.json' has a 'typesVersions' field with version-specific path mappings.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";parameter_modifiers_can_only_be_used_in_a_ts_file_8012" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA['parameter modifiers' can only be used in a .ts file.]]></Val>
@@ -6831,6 +6975,18 @@
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";use_strict_directive_cannot_be_used_with_non_simple_parameter_list_1347" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA['use strict' directive cannot be used with non-simple parameter list.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";use_strict_directive_used_here_1349" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA['use strict' directive used here.]]></Val>
</Str>
<Disp Icon="Str" />
</Item>
<Item ItemId=";with_statements_are_not_allowed_in_an_async_function_block_1300" ItemType="0" PsrId="306" Leaf="true">
<Str Cat="Text">
<Val><![CDATA['with' statements are not allowed in an async function block.]]></Val>
+4 -4
View File
@@ -328,7 +328,7 @@
"Do_not_emit_outputs_if_any_errors_were_reported_6008": "No emitir salidas si se informa de algún error.",
"Do_not_emit_use_strict_directives_in_module_output_6112": "No emitir directivas 'use strict' en la salida del módulo.",
"Do_not_erase_const_enum_declarations_in_generated_code_6007": "No borrar las declaraciones de enumeración const en el código generado.",
"Do_not_generate_custom_helper_functions_like_extends_in_compiled_output_6157": "No generar funciones auxiliares personalizadas como \"__extends\" en la salida compilada.",
"Do_not_generate_custom_helper_functions_like_extends_in_compiled_output_6157": "No generar funciones del asistente personalizadas como \"__extends\" en la salida compilada.",
"Do_not_include_the_default_library_file_lib_d_ts_6158": "No incluir el archivo de biblioteca predeterminado (lib.d.ts).",
"Do_not_report_errors_on_unreachable_code_6077": "No notificar los errores del código inaccesible.",
"Do_not_report_errors_on_unused_labels_6074": "No notificar los errores de las etiquetas no usadas.",
@@ -477,7 +477,7 @@
"Import_declaration_0_is_using_private_name_1_4000": "La declaración de importación '{0}' usa el nombre privado '{1}'.",
"Import_declaration_conflicts_with_local_declaration_of_0_2440": "La declaración de importación está en conflicto con la declaración local de \"{0}\".",
"Import_declarations_in_a_namespace_cannot_reference_a_module_1147": "Las declaraciones de importación de un espacio de nombres no pueden hacer referencia a un módulo.",
"Import_emit_helpers_from_tslib_6139": "Importe elementos auxiliares de emisión de \"tslib\".",
"Import_emit_helpers_from_tslib_6139": "Importe asistentes de emisión de \"tslib\".",
"Import_may_be_converted_to_a_default_import_80003": "La importación puede convertirse a una importación predeterminada.",
"Import_name_cannot_be_0_2438": "El nombre de importación no puede ser \"{0}\".",
"Import_or_export_declaration_in_an_ambient_module_declaration_cannot_reference_module_through_relati_2439": "La declaración de importación o exportación de una declaración de módulo de ambiente no puede hacer referencia al módulo a través de su nombre relativo.",
@@ -892,8 +892,8 @@
"The_variable_declaration_of_a_for_of_statement_cannot_have_an_initializer_1190": "La declaración de variable de una instrucción \"for...of\" no puede tener un inicializador.",
"The_with_statement_is_not_supported_All_symbols_in_a_with_block_will_have_type_any_2410": "No se admite la instrucción 'with'. Todos los símbolos de un bloque 'with' tendrán el tipo 'any'.",
"This_constructor_function_may_be_converted_to_a_class_declaration_80002": "Esta función de constructor puede convertirse en una declaración de clase.",
"This_syntax_requires_an_imported_helper_but_module_0_cannot_be_found_2354": "Esta sintaxis requiere una aplicación auxiliar importada, pero no se puede encontrar el módulo \"{0}\".",
"This_syntax_requires_an_imported_helper_named_1_but_module_0_has_no_exported_member_1_2343": "Esta sintaxis requiere una aplicación auxiliar importada denominada \"{1}\", pero el módulo \"{0}\" no tiene el miembro exportado \"{1}\".",
"This_syntax_requires_an_imported_helper_but_module_0_cannot_be_found_2354": "Esta sintaxis requiere un asistente importado, pero no se puede encontrar el módulo \"{0}\".",
"This_syntax_requires_an_imported_helper_named_1_but_module_0_has_no_exported_member_1_2343": "Esta sintaxis requiere un asistente importado denominado \"{1}\", pero el módulo \"{0}\" no tiene el miembro exportado \"{1}\".",
"Trailing_comma_not_allowed_1009": "No se permite la coma final.",
"Transpile_each_file_as_a_separate_module_similar_to_ts_transpileModule_6153": "Transpilar cada archivo como un módulo aparte (parecido a \"ts.transpileModule\").",
"Try_npm_install_types_Slash_0_if_it_exists_or_add_a_new_declaration_d_ts_file_containing_declare_mod_7035": "Pruebe \"npm install @types/{0}\" si existe o agregue un nuevo archivo de declaración (.d.ts) que incluya \"declare module '{0}';\"",
+8 -8
View File
@@ -68,7 +68,7 @@
"A_rest_parameter_cannot_have_an_initializer_1048": "rest 매개 변수에는 이니셜라이저를 사용할 수 없습니다.",
"A_rest_parameter_must_be_last_in_a_parameter_list_1014": "rest 매개 변수는 매개 변수 목록 마지막에 있어야 합니다.",
"A_rest_parameter_must_be_of_an_array_type_2370": "rest 매개 변수는 배열 형식이어야 합니다.",
"A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma_1013": "rest 매개 변수 또는 바인딩 패턴에 후행 쉼표를 사용할습니다.",
"A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma_1013": "rest 매개 변수 또는 바인딩 패턴에 후행 쉼표가 없을습니다.",
"A_return_statement_can_only_be_used_within_a_function_body_1108": "'return' 문은 함수 본문 내에서만 사용할 수 있습니다.",
"A_series_of_entries_which_re_map_imports_to_lookup_locations_relative_to_the_baseUrl_6167": "가져오기를 'baseUrl'에 상대적인 조회 위치로 다시 매핑하는 일련의 항목입니다.",
"A_set_accessor_cannot_have_a_return_type_annotation_1095": "'set' 접근자에는 반환 형식 주석을 사용할 수 없습니다.",
@@ -232,7 +232,7 @@
"Cannot_invoke_an_object_which_is_possibly_null_2721": "'null'일 수 있는 개체를 호출할 수 없습니다.",
"Cannot_invoke_an_object_which_is_possibly_null_or_undefined_2723": "'null'이거나 '정의되지 않음'일 수 있는 개체를 호출할 수 없습니다.",
"Cannot_invoke_an_object_which_is_possibly_undefined_2722": "'정의되지 않음'일 수 있는 개체를 호출할 수 없습니다.",
"Cannot_prepend_project_0_because_it_does_not_have_outFile_set_6308": "'outFile' 집합이 없기 때문에 '{0}' 프로젝트를 추가할 수 없습니다.",
"Cannot_prepend_project_0_because_it_does_not_have_outFile_set_6308": "'{0}' 프로젝트는 'outFile'이 설정되어 있지 않기 때문에 앞에 추가할 수 없습니다.",
"Cannot_re_export_a_type_when_the_isolatedModules_flag_is_provided_1205": "'--isolatedModules' 플래그가 제공된 경우 형식을 다시 내보낼 수 없습니다.",
"Cannot_read_file_0_Colon_1_5012": "파일 '{0}'을(를) 읽을 수 없습니다. {1}.",
"Cannot_redeclare_block_scoped_variable_0_2451": "블록 범위 변수 '{0}'을(를) 다시 선언할 수 없습니다.",
@@ -274,7 +274,7 @@
"Compile_the_project_given_the_path_to_its_configuration_file_or_to_a_folder_with_a_tsconfig_json_6020": "구성 파일에 대한 경로 또는 'tsconfig.json'이 포함된 폴더에 대한 경로를 고려하여 프로젝트를 컴파일합니다.",
"Compiler_option_0_expects_an_argument_6044": "컴파일러 옵션 '{0}'에는 인수가 필요합니다.",
"Compiler_option_0_requires_a_value_of_type_1_5024": "컴파일러 옵션 '{0}'에 {1} 형식의 값이 필요합니다.",
"Composite_projects_may_not_disable_declaration_emit_6304": "복합 프로젝트는 선언 내보내기를 사용하지 않도록 설정할 수 없습니다.",
"Composite_projects_may_not_disable_declaration_emit_6304": "복합 프로젝트는 선언 내보내기를 비활성화할 수 없습니다.",
"Computed_property_names_are_not_allowed_in_enums_1164": "컴퓨팅된 속성 이름은 열거형에 사용할 수 없습니다.",
"Computed_values_are_not_permitted_in_an_enum_with_string_valued_members_2553": "계산된 값은 문자열 값 멤버가 포함된 열거형에서 허용되지 않습니다.",
"Concatenate_and_emit_output_to_single_file_6001": "출력을 연결하고 단일 파일로 내보냅니다.",
@@ -445,7 +445,7 @@
"Function_overload_must_be_static_2387": "함수 오버로드는 정적이어야 합니다.",
"Function_overload_must_not_be_static_2388": "함수 오버로드는 정적이 아니어야 합니다.",
"Generate_get_and_set_accessors_95046": "'get' 및 'set' 접근자 생성",
"Generates_a_sourcemap_for_each_corresponding_d_ts_file_6000": "해당하는 각 '.d.ts' 파일 sourcemap을 생성합니다.",
"Generates_a_sourcemap_for_each_corresponding_d_ts_file_6000": "해당하는 각 '.d.ts' 파일 sourcemap을 생성합니다.",
"Generates_corresponding_d_ts_file_6002": "해당 '.d.ts' 파일을 생성합니다.",
"Generates_corresponding_map_file_6043": "해당 '.map' 파일을 생성합니다.",
"Generator_implicitly_has_type_0_because_it_does_not_yield_any_values_Consider_supplying_a_return_typ_7025": "생성기는 값을 생성하지 않으므로 암시적으로 '{0}' 형식입니다. 반환 형식을 제공하세요.",
@@ -677,13 +677,13 @@
"Print_names_of_generated_files_part_of_the_compilation_6154": "컴파일의 일부인 생성된 파일의 이름을 인쇄합니다.",
"Print_the_compiler_s_version_6019": "컴파일러 버전을 인쇄합니다.",
"Print_this_message_6017": "이 메시지를 출력합니다.",
"Project_0_can_t_be_built_because_its_dependency_1_has_errors_6363": "'{1}' 종속성에 오류가 있기 때문에 '{0}' 프로젝트를 빌드할 수 없습니다.",
"Project_0_can_t_be_built_because_its_dependency_1_has_errors_6363": "'{0}' 프로젝트는 '{1}' 종속성에 오류가 있기 때문에 빌드할 수 없습니다.",
"Project_0_is_out_of_date_because_its_dependency_1_is_out_of_date_6353": "'{1}' 종속성이 최신 상태가 아니기 때문에 '{0}' 프로젝트가 최신 상태가 아닙니다.",
"Project_0_is_out_of_date_because_oldest_output_1_is_older_than_newest_input_2_6350": "가장 오래된 출력 '{1}'이(가) 최신 입력 '{2}'보다 오래되었기 때문에 '{0}' 프로젝트가 최신 상태가 아닙니다.",
"Project_0_is_out_of_date_because_output_file_1_does_not_exist_6352": "'{1}' 출력 파일이 존재하지 않기 때문에 '{0}' 프로젝트가 최신 상태가 아닙니다.",
"Project_0_is_up_to_date_6361": "'{0}' 프로젝트가 최신 상태입니다.",
"Project_0_is_up_to_date_because_newest_input_1_is_older_than_oldest_output_2_6351": "최신 입력 '{1}'이(가) 가장 오래된 출력 '{2}'보다 오래되었기 때문에 '{0}' 프로젝트가 최신 상태입니다.",
"Project_0_is_up_to_date_with_d_ts_files_from_its_dependencies_6354": "종속성 .d.ts 파일이 있기 때문에 '{0}' 프로젝트가 최신 상태입니다.",
"Project_0_is_up_to_date_with_d_ts_files_from_its_dependencies_6354": "'{0}' 프로젝트는 종속성 .d.ts 파일이 있 최신 상태입니다.",
"Project_references_may_not_form_a_circular_graph_Cycle_detected_Colon_0_6202": "프로젝트 참조는 순환 그래프를 형성할 수 없습니다. 순환이 발견되었습니다. {0}",
"Projects_in_this_build_Colon_0_6355": "이 빌드의 프로젝트: {0}",
"Projects_to_reference_6300": "참조할 프로젝트",
@@ -803,7 +803,7 @@
"Show_what_would_be_built_or_deleted_if_specified_with_clean_6367": "빌드될 항목 표시(또는 '--clean'으로 지정된 경우 삭제될 항목 표시)",
"Signature_0_must_be_a_type_predicate_1224": "'{0}' 시그니처는 형식 조건자여야 합니다.",
"Skip_type_checking_of_declaration_files_6012": "선언 파일 형식 검사를 건너뜁니다.",
"Skipping_build_of_project_0_because_its_dependency_1_has_errors_6362": "'{1}' 종속성에 오류가 있기 때문에 '{0}' 프로젝트 빌드를 건너뜁니다.",
"Skipping_build_of_project_0_because_its_dependency_1_has_errors_6362": "'{0}' 프로젝트의 빌드는 '{1}' 종속성에 오류가 있기 때문에 건너뜁니다.",
"Skipping_clean_because_not_all_projects_could_be_located_6371": "일부 프로젝트를 찾을 수 없으므로 정리를 건너뛰는 중입니다.",
"Source_Map_Options_6175": "소스 맵 옵션",
"Specialized_overload_signature_is_not_assignable_to_any_non_specialized_signature_2382": "특수화된 오버로드 시그니처는 특수화되지 않은 서명에 할당할 수 없습니다.",
@@ -1039,7 +1039,7 @@
"const_declarations_must_be_initialized_1155": "'const' 선언은 초기화해야 합니다.",
"const_enum_member_initializer_was_evaluated_to_a_non_finite_value_2477": "'const' 열거형 멤버 이니셜라이저가 무한 값에 대해 평가되었습니다.",
"const_enum_member_initializer_was_evaluated_to_disallowed_value_NaN_2478": "'const' 열거형 멤버 이니셜라이저가 허용되지 않은 'NaN' 값에 대해 평가되었습니다.",
"const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_im_2475": "'const' 열거형은 속성 또는 인덱스 액세스 식 또는 내보내기 할당 또는 가져오기 선언의 오른쪽 또는 형식 쿼리에서만 사용할 수 있습니다.",
"const_enums_can_only_be_used_in_property_or_index_access_expressions_or_the_right_hand_side_of_an_im_2475": "'const' 열거형은 속성이나 인덱스 액세스 식, 또는 내보내기 할당이나 가져오기 선언의 오른쪽, 또는 형식 쿼리에서만 사용할 수 있습니다.",
"delete_cannot_be_called_on_an_identifier_in_strict_mode_1102": "strict 모드에서는 식별자에 대해 'delete'를 호출할 수 없습니다.",
"delete_this_Project_0_is_up_to_date_because_it_was_previously_built_6360": "이 항목 삭제 - '{0}' 프로젝트는 이전에 빌드되었기 때문에 최신 상태입니다.",
"enum_declarations_can_only_be_used_in_a_ts_file_8015": "'enum 선언'은 .ts 파일에서만 사용할 수 있습니다.",
+2 -2
View File
@@ -27,7 +27,7 @@ interface PromiseConstructor {
/**
* Creates a new Promise.
* @param executor A callback used to initialize the promise. This callback is passed two arguments:
* a resolve callback used resolve the promise with a value or the result of another promise,
* a resolve callback used to resolve the promise with a value or the result of another promise,
* and a reject callback used to reject the promise with a provided reason or error.
*/
new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;
@@ -213,4 +213,4 @@ interface PromiseConstructor {
resolve(): Promise<void>;
}
declare var Promise: PromiseConstructor;
declare var Promise: PromiseConstructor;
+71 -1
View File
@@ -315,6 +315,66 @@ interface FunctionConstructor {
declare const Function: FunctionConstructor;
interface CallableFunction extends Function {
/**
* Calls the function with the specified object as the this value and the elements of specified array as the arguments.
* @param thisArg The object to be used as the this object.
* @param args An array of argument values to be passed to the function.
*/
apply<T, R>(this: (this: T) => R, thisArg: T): R;
apply<T, A extends any[], R>(this: (this: T, ...args: A) => R, thisArg: T, args: A): R;
/**
* Calls the function with the specified object as the this value and the specified rest arguments as the arguments.
* @param thisArg The object to be used as the this object.
* @param args Argument values to be passed to the function.
*/
call<T, A extends any[], R>(this: (this: T, ...args: A) => R, thisArg: T, ...args: A): R;
/**
* For a given function, creates a bound function that has the same body as the original function.
* The this object of the bound function is associated with the specified object, and has the specified initial parameters.
* @param thisArg The object to be used as the this object.
* @param args Arguments to bind to the parameters of the function.
*/
bind<T, A extends any[], R>(this: (this: T, ...args: A) => R, thisArg: T): (...args: A) => R;
bind<T, A0, A extends any[], R>(this: (this: T, arg0: A0, ...args: A) => R, thisArg: T, arg0: A0): (...args: A) => R;
bind<T, A0, A1, A extends any[], R>(this: (this: T, arg0: A0, arg1: A1, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1): (...args: A) => R;
bind<T, A0, A1, A2, A extends any[], R>(this: (this: T, arg0: A0, arg1: A1, arg2: A2, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1, arg2: A2): (...args: A) => R;
bind<T, A0, A1, A2, A3, A extends any[], R>(this: (this: T, arg0: A0, arg1: A1, arg2: A2, arg3: A3, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1, arg2: A2, arg3: A3): (...args: A) => R;
bind<T, AX, R>(this: (this: T, ...args: AX[]) => R, thisArg: T, ...args: AX[]): (...args: AX[]) => R;
}
interface NewableFunction extends Function {
/**
* Calls the function with the specified object as the this value and the elements of specified array as the arguments.
* @param thisArg The object to be used as the this object.
* @param args An array of argument values to be passed to the function.
*/
apply<T>(this: new () => T, thisArg: T): void;
apply<T, A extends any[]>(this: new (...args: A) => T, thisArg: T, args: A): void;
/**
* Calls the function with the specified object as the this value and the specified rest arguments as the arguments.
* @param thisArg The object to be used as the this object.
* @param args Argument values to be passed to the function.
*/
call<T, A extends any[]>(this: new (...args: A) => T, thisArg: T, ...args: A): void;
/**
* For a given function, creates a bound function that has the same body as the original function.
* The this object of the bound function is associated with the specified object, and has the specified initial parameters.
* @param thisArg The object to be used as the this object.
* @param args Arguments to bind to the parameters of the function.
*/
bind<A extends any[], R>(this: new (...args: A) => R, thisArg: any): new (...args: A) => R;
bind<A0, A extends any[], R>(this: new (arg0: A0, ...args: A) => R, thisArg: any, arg0: A0): new (...args: A) => R;
bind<A0, A1, A extends any[], R>(this: new (arg0: A0, arg1: A1, ...args: A) => R, thisArg: any, arg0: A0, arg1: A1): new (...args: A) => R;
bind<A0, A1, A2, A extends any[], R>(this: new (arg0: A0, arg1: A1, arg2: A2, ...args: A) => R, thisArg: any, arg0: A0, arg1: A1, arg2: A2): new (...args: A) => R;
bind<A0, A1, A2, A3, A extends any[], R>(this: new (arg0: A0, arg1: A1, arg2: A2, arg3: A3, ...args: A) => R, thisArg: any, arg0: A0, arg1: A1, arg2: A2, arg3: A3): new (...args: A) => R;
bind<AX, R>(this: new (...args: AX[]) => R, thisArg: any, ...args: AX[]): new (...args: AX[]) => R;
}
interface IArguments {
[index: number]: any;
length: number;
@@ -1370,7 +1430,7 @@ type Readonly<T> = {
};
/**
* From T pick a set of properties K
* From T, pick a set of properties whose keys are in the union K
*/
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
@@ -1398,6 +1458,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
@@ -31,7 +31,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[]
@@ -145,7 +145,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[]
+51 -6
View File
@@ -827,15 +827,17 @@ declare namespace ts.server.protocol {
/**
* Information about the item to be renamed.
*/
interface RenameInfo {
type RenameInfo = RenameInfoSuccess | RenameInfoFailure;
interface RenameInfoSuccess {
/**
* True if item can be renamed.
*/
canRename: boolean;
canRename: true;
/**
* Error message if item can not be renamed.
* File or directory to rename.
* If set, `getEditsForFileRename` should be called instead of `findRenameLocations`.
*/
localizedErrorMessage?: string;
fileToRename?: string;
/**
* Display name of the item to be renamed.
*/
@@ -852,6 +854,15 @@ declare namespace ts.server.protocol {
* Optional modifiers for the kind (such as 'public').
*/
kindModifiers: string;
/** Span of text to rename. */
triggerSpan: TextSpan;
}
interface RenameInfoFailure {
canRename: false;
/**
* Error message if item can not be renamed.
*/
localizedErrorMessage: string;
}
/**
* A group of text spans, all in 'file'.
@@ -860,7 +871,11 @@ declare namespace ts.server.protocol {
/** The file to which the spans apply */
file: string;
/** The text spans in this group */
locs: TextSpan[];
locs: RenameTextSpan[];
}
interface RenameTextSpan extends TextSpan {
readonly prefixText?: string;
readonly suffixText?: string;
}
interface RenameResponseBody {
/**
@@ -1373,7 +1388,7 @@ declare namespace ts.server.protocol {
* begin with prefix.
*/
interface CompletionsRequest extends FileLocationRequest {
command: CommandTypes.Completions;
command: CommandTypes.Completions | CommandTypes.CompletionInfo;
arguments: CompletionsRequestArgs;
}
/**
@@ -1885,6 +1900,35 @@ declare namespace ts.server.protocol {
*/
openFiles: string[];
}
type ProjectLoadingStartEventName = "projectLoadingStart";
interface ProjectLoadingStartEvent extends Event {
event: ProjectLoadingStartEventName;
body: ProjectLoadingStartEventBody;
}
interface ProjectLoadingStartEventBody {
/** name of the project */
projectName: string;
/** reason for loading */
reason: string;
}
type ProjectLoadingFinishEventName = "projectLoadingFinish";
interface ProjectLoadingFinishEvent extends Event {
event: ProjectLoadingFinishEventName;
body: ProjectLoadingFinishEventBody;
}
interface ProjectLoadingFinishEventBody {
/** name of the project */
projectName: string;
}
type SurveyReadyEventName = "surveyReady";
interface SurveyReadyEvent extends Event {
event: SurveyReadyEventName;
body: SurveyReadyEventBody;
}
interface SurveyReadyEventBody {
/** Name of the survey. This is an internal machine- and programmer-friendly name */
surveyId: string;
}
type LargeFileReferencedEventName = "largeFileReferenced";
interface LargeFileReferencedEvent extends Event {
event: LargeFileReferencedEventName;
@@ -2220,6 +2264,7 @@ declare namespace ts.server.protocol {
readonly includeCompletionsWithInsertText?: boolean;
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
readonly allowTextChangesInNewFiles?: boolean;
readonly lazyConfiguredProjectsFromExternalProject?: boolean;
}
interface CompilerOptions {
allowJs?: boolean;
+12 -12
View File
@@ -61,7 +61,7 @@
"A_property_of_an_interface_or_type_literal_whose_type_is_a_unique_symbol_type_must_be_readonly_1330": "Uma propriedade de uma interface ou tipo literal cujo tipo é um tipo de 'unique symbol' deve ser 'readonly'.",
"A_required_parameter_cannot_follow_an_optional_parameter_1016": "Um parâmetro obrigatório não pode seguir um parâmetro opcional.",
"A_rest_element_cannot_contain_a_binding_pattern_2501": "Um elemento rest não pode conter um padrão de associação.",
"A_rest_element_cannot_have_a_property_name_2566": "Um elemento restante não pode ter um nome de propriedade.",
"A_rest_element_cannot_have_a_property_name_2566": "Um elemento rest não pode ter um nome de propriedade.",
"A_rest_element_cannot_have_an_initializer_1186": "Um elemento rest não pode ter um inicializador.",
"A_rest_element_must_be_last_in_a_destructuring_pattern_2462": "Um elemento rest deve ser o último em um padrão de desestruturação.",
"A_rest_parameter_cannot_be_optional_1047": "Um parâmetro rest não pode ser opcional.",
@@ -174,7 +174,7 @@
"An_object_member_cannot_be_declared_optional_1162": "Um membro de objeto não pode ser declarado como opcional.",
"An_overload_signature_cannot_be_declared_as_a_generator_1222": "A assinatura de sobrecarga não pode ser declarada como geradora.",
"An_unary_expression_with_the_0_operator_is_not_allowed_in_the_left_hand_side_of_an_exponentiation_ex_17006": "Uma expressão unária com o operador '{0}' não é permitida no lado esquerdo de uma expressão de exponenciação. Considere delimitar a expressão em parênteses.",
"Annotate_everything_with_types_from_JSDoc_95043": "Anotar tudo com tipos de JSDoc",
"Annotate_everything_with_types_from_JSDoc_95043": "Anotar tudo com tipos do JSDoc",
"Annotate_with_type_from_JSDoc_95009": "Anotar com o tipo do JSDoc",
"Annotate_with_types_from_JSDoc_95010": "Anotar com os tipos do JSDoc",
"Argument_expression_expected_1135": "Expressão de argumento esperada.",
@@ -368,7 +368,7 @@
"Enables_experimental_support_for_ES7_decorators_6065": "Habilita o suporte experimental para decoradores ES7.",
"Enables_experimental_support_for_emitting_type_metadata_for_decorators_6066": "Habilita o suporte experimental para a emissão de tipo de metadados para decoradores.",
"Enum_0_used_before_its_declaration_2450": "A enumeração '{0}' usada antes de sua declaração.",
"Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations_2567": "As declarações de enum apenas podem se mescladas com namespaces ou com outras declarações de enum.",
"Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations_2567": "As declarações enum só podem ser mescladas com namespaces ou com outras declarações enum.",
"Enum_declarations_must_all_be_const_or_non_const_2473": "Declarações de enumeração devem ser const ou não const.",
"Enum_member_expected_1132": "Membro de enumeração esperado.",
"Enum_member_must_have_initializer_1061": "O membro de enumeração deve ter um inicializador.",
@@ -571,7 +571,7 @@
"Module_0_has_already_exported_a_member_named_1_Consider_explicitly_re_exporting_to_resolve_the_ambig_2308": "O módulo {0} já exportou um membro denominado '{1}'. Considere reexportar explicitamente para resolver a ambiguidade.",
"Module_0_has_no_default_export_1192": "O módulo '{0}' não tem padrão de exportação.",
"Module_0_has_no_exported_member_1_2305": "O módulo '{0}' não tem nenhum membro exportado '{1}'.",
"Module_0_has_no_exported_member_1_Did_you_mean_2_2724": "O módulo '{0}' não tem nenhum membro exportado '{1}'. Você quis dizer '{2}'?",
"Module_0_has_no_exported_member_1_Did_you_mean_2_2724": "O módulo '{0}' não tem nenhum membro '{1}' exportado. Você quis dizer '{2}'?",
"Module_0_is_hidden_by_a_local_declaration_with_the_same_name_2437": "O módulo '{0}' está oculto por uma declaração de local com o mesmo nome.",
"Module_0_resolves_to_a_non_module_entity_and_cannot_be_imported_using_this_construct_2497": "O módulo '{0}' resolve para uma entidade sem módulo e não pode ser importado usando este constructo.",
"Module_0_uses_export_and_cannot_be_used_with_export_Asterisk_2498": "O módulo '{0}' usa 'export =' e não pode ser usado com 'export *'.",
@@ -622,7 +622,7 @@
"Option_0_can_only_be_used_when_either_option_inlineSourceMap_or_option_sourceMap_is_provided_5051": "A opção '{0} só pode ser usada quando qualquer uma das opções '--inlineSourceMap' ou '--sourceMap' é fornecida.",
"Option_0_cannot_be_specified_with_option_1_5053": "A opção '{0}' não pode ser especificada com a opção '{1}'.",
"Option_0_cannot_be_specified_without_specifying_option_1_5052": "A opção '{0}' não pode ser especificada sem especificar a opção '{1}'.",
"Option_0_cannot_be_specified_without_specifying_option_1_or_option_2_5069": "A opção '{0}' não pode ser especificada sem especificar a opção '{1}' ou a opção '{2}'.",
"Option_0_cannot_be_specified_without_specifying_option_1_or_option_2_5069": "A opção '{0}' não pode ser especificada sem a especificação da opção '{1}' ou '{2}'.",
"Option_0_should_have_array_of_strings_as_a_value_6103": "A opção '{0}' deve ter matriz de cadeias de um valor.",
"Option_build_must_be_the_first_command_line_argument_6369": "A opção '--build' precisa ser o primeiro argumento da linha de comando.",
"Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES_5047": "A opção 'isolatedModules' só pode ser usada quando nenhuma opção de '--module' for fornecida ou a opção 'target' for 'ES2015' ou superior.",
@@ -686,7 +686,7 @@
"Project_0_is_up_to_date_with_d_ts_files_from_its_dependencies_6354": "O projeto '{0}' está atualizado com os arquivos .d.ts de suas dependências",
"Project_references_may_not_form_a_circular_graph_Cycle_detected_Colon_0_6202": "Referências de projeto não podem formar um gráfico circular. Ciclo detectado: {0}",
"Projects_in_this_build_Colon_0_6355": "Projetos neste build: {0}",
"Projects_to_reference_6300": "Projetos para referência",
"Projects_to_reference_6300": "Projetos a serem referenciados",
"Property_0_does_not_exist_on_const_enum_1_2479": "A propriedade '{0}' não existe na enumeração 'const' '{1}'.",
"Property_0_does_not_exist_on_type_1_2339": "A propriedade '{0}' não existe no tipo '{1}'.",
"Property_0_does_not_exist_on_type_1_Did_you_forget_to_use_await_2570": "A propriedade '{0}' não existe no tipo '{1}'. Você esqueceu de usar 'await'?",
@@ -740,7 +740,7 @@
"Remove_braces_from_arrow_function_95060": "Remover chaves da função de seta",
"Remove_declaration_for_Colon_0_90004": "Remover declaração para: '{0}'",
"Remove_destructuring_90009": "Remover desestruturação",
"Remove_import_from_0_90005": "Remover importação do '{0}'",
"Remove_import_from_0_90005": "Remover importação de '{0}'",
"Remove_unreachable_code_95050": "Remover código inacessível",
"Remove_unused_label_95053": "Remover rótulo não utilizado",
"Remove_variable_statement_90010": "Remover instrução de variável",
@@ -752,7 +752,7 @@
"Report_errors_on_unused_parameters_6135": "Relatar erros nos parâmetros não utilizados.",
"Required_type_parameters_may_not_follow_optional_type_parameters_2706": "Os parâmetros de tipo necessários podem não seguir os parâmetros de tipo opcionais.",
"Resolution_for_module_0_was_found_in_cache_from_location_1_6147": "A resolução para o módulo '{0}' foi encontrada no cache do local '{1}'.",
"Resolve_keyof_to_string_valued_property_names_only_no_numbers_or_symbols_6195": "Resolva 'keyof' para nomes de propriedades com valores de cadeia de caracteres somente (sem números ou símbolos).",
"Resolve_keyof_to_string_valued_property_names_only_no_numbers_or_symbols_6195": "Resolva 'keyof' somente para nomes de propriedades com valores de cadeia de caracteres (sem números nem símbolos).",
"Resolving_from_node_modules_folder_6118": "Resolvendo na pasta node_modules...",
"Resolving_module_0_from_1_6086": "======== Resolvendo módulo '{0}' de '{1}'. ========",
"Resolving_module_name_0_relative_to_base_url_1_2_6094": "Resolvendo nome de módulo '{0}' relativo à URL base '{1}' - '{2}'.",
@@ -803,8 +803,8 @@
"Show_what_would_be_built_or_deleted_if_specified_with_clean_6367": "Mostrar o que seria compilado (ou excluído, se especificado com '--clean')",
"Signature_0_must_be_a_type_predicate_1224": "A assinatura '{0}' deve ser um predicado de tipo.",
"Skip_type_checking_of_declaration_files_6012": "Ignorar a verificação de tipo dos arquivos de declaração.",
"Skipping_build_of_project_0_because_its_dependency_1_has_errors_6362": "Ignorando build do projeto '{0}' porque sua dependência '{1}' tem erros",
"Skipping_clean_because_not_all_projects_could_be_located_6371": "Ignorando a limpeza porque nem todos os projetos foram localizados",
"Skipping_build_of_project_0_because_its_dependency_1_has_errors_6362": "Ignorando o build do projeto '{0}' porque a dependência '{1}' tem erros",
"Skipping_clean_because_not_all_projects_could_be_located_6371": "Ignorando a limpeza porque não foram localizados todos os projetos",
"Source_Map_Options_6175": "Opções do Sourcemap",
"Specialized_overload_signature_is_not_assignable_to_any_non_specialized_signature_2382": "A assinatura de sobrecarga especializada não pode ser atribuída a qualquer assinatura não especializada.",
"Specifier_of_dynamic_import_cannot_be_spread_element_1325": "O especificador de importação dinâmica não pode ser o elemento de difusão.",
@@ -966,7 +966,7 @@
"Unexpected_end_of_text_1126": "Fim inesperado do texto.",
"Unexpected_token_1012": "Token inesperado.",
"Unexpected_token_A_constructor_method_accessor_or_property_was_expected_1068": "Token inesperado. Um construtor, método, acessador ou propriedade era esperado.",
"Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces_1069": "Token inesperado. Um nome de parâmetro de tipo era esperado sem chaves.",
"Unexpected_token_A_type_parameter_name_was_expected_without_curly_braces_1069": "Token inesperado. Era esperado um nome de parâmetro de tipo sem chaves.",
"Unexpected_token_expected_1179": "Token inesperado. '{' esperado.",
"Unknown_compiler_option_0_5023": "Opção do compilador '{0}' desconhecida.",
"Unknown_option_excludes_Did_you_mean_exclude_6114": "Opção desconhecida 'excludes'. Você quis dizer 'exclude'?",
@@ -993,7 +993,7 @@
"Variable_declaration_list_cannot_be_empty_1123": "A lista de declaração de variável não pode estar vazia.",
"Version_0_6029": "Versão {0}",
"Watch_input_files_6005": "Observe os arquivos de entrada.",
"Whether_to_keep_outdated_console_output_in_watch_mode_instead_of_clearing_the_screen_6191": "Se se deve manter a saída de console desatualizada no modo de inspeção, em vez de limpar a tela.",
"Whether_to_keep_outdated_console_output_in_watch_mode_instead_of_clearing_the_screen_6191": "Se é necessário manter a saída de console desatualizada no modo de inspeção, em vez de limpar a tela.",
"You_cannot_rename_elements_that_are_defined_in_the_standard_TypeScript_library_8001": "Não é possível renomear elementos que são definidos na biblioteca TypeScript padrão.",
"You_cannot_rename_this_element_8000": "Você não pode renomear este elemento.",
"_0_accepts_too_few_arguments_to_be_used_as_a_decorator_here_Did_you_mean_to_call_it_first_and_write__1329": "'{0}' aceita muito poucos argumentos para serem usados como um decorador aqui. Você quis dizer para chamá-lo primeiro e gravar '@{0}()'?",
+10 -10
View File
@@ -49,8 +49,8 @@
"A_namespace_declaration_cannot_be_located_prior_to_a_class_or_function_with_which_it_is_merged_2434": "Bir ad alanı bildirimi, birleştirildiği sınıf veya işlevden önce gelemez.",
"A_namespace_declaration_is_only_allowed_in_a_namespace_or_module_1235": "Ad alanı bildirimine yalnızca bir ad alanında veya modülde izin verilir.",
"A_namespace_style_import_cannot_be_called_or_constructed_and_will_cause_a_failure_at_runtime_7038": "Bir ad alanı stili içeri aktarma işlemi çağrılamadığından veya oluşturulamadığından çalışma zamanında hataya yol açacak.",
"A_non_dry_build_would_build_project_0_6357": "non-dry bir derleme '{0}' projesini derler",
"A_non_dry_build_would_delete_the_following_files_Colon_0_6356": "non-dry bir derleme şu dosyaları siler: {0}",
"A_non_dry_build_would_build_project_0_6357": "-dry bayrağı kullanılmayan bir derleme '{0}' projesini derler",
"A_non_dry_build_would_delete_the_following_files_Colon_0_6356": "-dry bayrağı kullanılmayan bir derleme şu dosyaları siler: {0}",
"A_parameter_initializer_is_only_allowed_in_a_function_or_constructor_implementation_2371": "Parametre başlatıcısına yalnızca bir işlevde veya oluşturucu uygulamasında izin verilir.",
"A_parameter_property_cannot_be_declared_using_a_rest_parameter_1317": "Parametre özelliği, rest parametresi kullanılarak bildirilemez.",
"A_parameter_property_is_only_allowed_in_a_constructor_implementation_2369": "Parametre özelliğine yalnızca bir oluşturucu uygulamasında izin verilir.",
@@ -110,7 +110,7 @@
"Add_initializers_to_all_uninitialized_properties_95027": "Tüm başlatılmamış özelliklere başlatıcılar ekle",
"Add_missing_super_call_90001": "Eksik 'super()' çağrısını ekle",
"Add_missing_typeof_95052": "Eksik 'typeof' öğesini ekle",
"Add_or_remove_braces_in_an_arrow_function_95058": "Ok işlevine küme ayracı ekleyin veya kaldırın",
"Add_or_remove_braces_in_an_arrow_function_95058": "Ok işlevine küme ayracı ekle veya kaldır",
"Add_qualifier_to_all_unresolved_variables_matching_a_member_name_95037": "Bir üye adıyla eşleşen tüm çözülmemiş değişkenlere niteleyici ekle",
"Add_to_all_uncalled_decorators_95044": "Çağrılmayan tüm dekoratörlere '()' ekle",
"Add_ts_ignore_to_all_error_messages_95042": "Tüm hata iletilerine '@ts-ignore' ekle",
@@ -122,7 +122,7 @@
"All_declarations_of_0_must_have_identical_modifiers_2687": "Tüm '{0}' bildirimleri aynı değiştiricilere sahip olmalıdır.",
"All_declarations_of_0_must_have_identical_type_parameters_2428": "Tüm '{0}' bildirimleri özdeş tür parametrelerine sahip olmalıdır.",
"All_declarations_of_an_abstract_method_must_be_consecutive_2516": "Soyut metoda ait tüm bildirimler ardışık olmalıdır.",
"All_destructured_elements_are_unused_6198": "Yok edilen öğelerin hiçbiri kullanılmamış.",
"All_destructured_elements_are_unused_6198": "Yapısı bozulan öğelerin hiçbiri kullanılmıyor.",
"All_imports_in_import_declaration_are_unused_6192": "İçeri aktarma bildirimindeki hiçbir içeri aktarma kullanılmadı.",
"All_variables_are_unused_6199": "Hiçbir değişken kullanılmıyor.",
"Allow_default_imports_from_modules_with_no_default_export_This_does_not_affect_code_emit_just_typech_6011": "Varsayılan dışarı aktarmaya sahip olmayan modüllerde varsayılan içeri aktarmalara izin verin. Bu işlem kod üretimini etkilemez, yalnızca tür denetimini etkiler.",
@@ -232,7 +232,7 @@
"Cannot_invoke_an_object_which_is_possibly_null_2721": "Muhtemelen 'null' olan bir nesne çağrılamıyor.",
"Cannot_invoke_an_object_which_is_possibly_null_or_undefined_2723": "Muhtemelen 'null' veya 'undefined' olan bir nesne çağrılamıyor.",
"Cannot_invoke_an_object_which_is_possibly_undefined_2722": "Muhtemelen 'undefined' olan bir nesne çağrılamıyor.",
"Cannot_prepend_project_0_because_it_does_not_have_outFile_set_6308": "'{0}' projesi, 'outFile' kümesi içermediğinden başa eklenemiyor",
"Cannot_prepend_project_0_because_it_does_not_have_outFile_set_6308": "{0}' projesi için 'outFile' ayarlanmadığından başa eklenemiyor",
"Cannot_re_export_a_type_when_the_isolatedModules_flag_is_provided_1205": "'--isolatedModules' bayrağı sağlandığında bir tür yeniden dışarı aktarılamaz.",
"Cannot_read_file_0_Colon_1_5012": "'{0}' dosyası okunamıyor: {1}.",
"Cannot_redeclare_block_scoped_variable_0_2451": "Blok kapsamlı değişken '{0}', yeniden bildirilemiyor.",
@@ -311,7 +311,7 @@
"Decorators_cannot_be_applied_to_multiple_get_Slashset_accessors_of_the_same_name_1207": "Dekoratörler aynı ada sahip birden fazla get/set erişimcisine uygulanamaz.",
"Default_export_of_the_module_has_or_is_using_private_name_0_4082": "Modülün varsayılan dışarı aktarımı '{0}' özel adına sahip veya bu adı kullanıyor.",
"Delete_all_unused_declarations_95024": "Kullanılmayan tüm bildirimleri sil",
"Delete_the_outputs_of_all_projects_6365": "Tüm projelerin çıkışlarını silin",
"Delete_the_outputs_of_all_projects_6365": "Tüm projelerin çıkışlarını sil",
"Deprecated_Use_jsxFactory_instead_Specify_the_object_invoked_for_createElement_when_targeting_react__6084": "[Kullanım Dışı] Bunun yerine '--jsxFactory' kullanın. 'react' JSX gösterimi hedefleniyorsa, createElement için çağrılan nesneyi belirtin",
"Deprecated_Use_outFile_instead_Concatenate_and_emit_output_to_single_file_6170": "[Kullanım Dışı] Bunun yerine '--outFile' kullanın. Çıkışı tek bir dosya olarak birleştirin ve gösterin",
"Deprecated_Use_skipLibCheck_instead_Skip_type_checking_of_default_library_declaration_files_6160": "[Kullanım Dışı] Bunun yerine '--skipLibCheck' kullanın. Varsayılan kitaplık bildirim dosyalarının tür denetimini atlayın.",
@@ -362,13 +362,13 @@
"Enable_strict_checking_of_property_initialization_in_classes_6187": "Sınıflarda sıkı özellik başlatma denetimini etkinleştirin.",
"Enable_strict_null_checks_6113": "Katı null denetimlerini etkinleştir.",
"Enable_tracing_of_the_name_resolution_process_6085": "Ad çözümleme işlemini izlemeyi etkinleştir.",
"Enable_verbose_logging_6366": "Ayrıntılı günlüğe yazmayı etkinleştirin",
"Enable_verbose_logging_6366": "Ayrıntılı günlüğe yazmayı etkinleştir",
"Enables_emit_interoperability_between_CommonJS_and_ES_Modules_via_creation_of_namespace_objects_for__7037": "Tüm içeri aktarma işlemleri için ad alanı nesnelerinin oluşturulması aracılığıyla CommonJS ile ES Modülleri arasında yayımlama birlikte çalışabilirliğine imkan tanır. Şu anlama gelir: 'allowSyntheticDefaultImports'.",
"Enables_experimental_support_for_ES7_async_functions_6068": "Zaman uyumsuz ES7 işlevleri için deneysel desteği etkinleştirir.",
"Enables_experimental_support_for_ES7_decorators_6065": "ES7 dekoratörleri için deneysel desteği etkinleştirir.",
"Enables_experimental_support_for_emitting_type_metadata_for_decorators_6066": "Dekoratörlere tür meta verisi gönderme için deneysel desteği etkinleştirir.",
"Enum_0_used_before_its_declaration_2450": "'{0}' sabit listesi, bildiriminden önce kullanıldı.",
"Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations_2567": "Enum bildirimleri yalnızca ad alanı veya diğer enum bildirimleri ile birleştirilebilir.",
"Enum_declarations_can_only_merge_with_namespace_or_other_enum_declarations_2567": "Sabit listesi bildirimleri yalnızca ad alanı veya diğer sabit listesi bildirimleri ile birleştirilebilir.",
"Enum_declarations_must_all_be_const_or_non_const_2473": "Sabit listesi bildirimlerinin tümü const veya const olmayan değerler olmalıdır.",
"Enum_member_expected_1132": "Sabit listesi üyesi bekleniyor.",
"Enum_member_must_have_initializer_1061": "Sabit listesi üyesi bir başlatıcıya sahip olmalıdır.",
@@ -571,7 +571,7 @@
"Module_0_has_already_exported_a_member_named_1_Consider_explicitly_re_exporting_to_resolve_the_ambig_2308": "{0} modülü, '{1}' adlı bir üyeyi zaten dışarı aktardı. Belirsizliği çözmek için açık olarak yeniden dışarı aktarmayı göz önünde bulundurun.",
"Module_0_has_no_default_export_1192": "'{0}' modülü için varsayılan dışarı aktarma yok.",
"Module_0_has_no_exported_member_1_2305": "'{0}' modülü, dışarı aktarılan '{1}' üyesine sahip değil.",
"Module_0_has_no_exported_member_1_Did_you_mean_2_2724": "'{0}' modülünün dışa aktarılan '{1}' adlı bir üyesi yok. Şunu mu demek istediniz: '{2}'?",
"Module_0_has_no_exported_member_1_Did_you_mean_2_2724": "{0}' modülünün dışarı aktarılan '{1}' adlı bir üyesi yok. Şunu mu demek istediniz: '{2}'?",
"Module_0_is_hidden_by_a_local_declaration_with_the_same_name_2437": "'{0}' modülü, aynı ada sahip bir yerel bildirim tarafından gizleniyor.",
"Module_0_resolves_to_a_non_module_entity_and_cannot_be_imported_using_this_construct_2497": "'{0}' modülü, modül olmayan bir varlığa çözümleniyor ve bu oluşturma ile içeri aktarılamaz.",
"Module_0_uses_export_and_cannot_be_used_with_export_Asterisk_2498": "'{0}' modülü 'export =' kullanıyor ve 'export *' ile birlikte kullanılamaz.",
@@ -737,7 +737,7 @@
"Referenced_project_0_must_have_setting_composite_Colon_true_6306": "Başvurulan proje '{0}' \"composite\": true ayarına sahip olmalıdır.",
"Remove_all_unreachable_code_95051": "Tüm erişilemeyen kodları kaldır",
"Remove_all_unused_labels_95054": "Kullanılmayan tüm etiketleri kaldır",
"Remove_braces_from_arrow_function_95060": "Ok işlevinden köşeli ayraçları kaldırın",
"Remove_braces_from_arrow_function_95060": "Ok işlevinden küme ayraçlarını kaldır",
"Remove_declaration_for_Colon_0_90004": "'{0}' bildirimini kaldır",
"Remove_destructuring_90009": "Yıkmayı kaldır",
"Remove_import_from_0_90005": "'{0}' öğesinden içeri aktarmayı kaldır",
+5117 -3376
View File
File diff suppressed because it is too large Load Diff
+7550 -4534
View File
File diff suppressed because it is too large Load Diff
+197 -280
View File
@@ -14,7 +14,7 @@ and limitations under the License.
***************************************************************************** */
declare namespace ts {
const versionMajorMinor = "3.1";
const versionMajorMinor = "3.2";
/** The version of the TypeScript compiler release */
const version: string;
}
@@ -69,7 +69,8 @@ declare namespace ts {
pos: number;
end: number;
}
type JsDocSyntaxKind = SyntaxKind.EndOfFileToken | SyntaxKind.WhitespaceTrivia | SyntaxKind.AtToken | SyntaxKind.NewLineTrivia | SyntaxKind.AsteriskToken | SyntaxKind.OpenBraceToken | SyntaxKind.CloseBraceToken | SyntaxKind.LessThanToken | SyntaxKind.OpenBracketToken | SyntaxKind.CloseBracketToken | SyntaxKind.EqualsToken | SyntaxKind.CommaToken | SyntaxKind.DotToken | SyntaxKind.Identifier | SyntaxKind.NoSubstitutionTemplateLiteral | SyntaxKind.Unknown;
type JsDocSyntaxKind = SyntaxKind.EndOfFileToken | SyntaxKind.WhitespaceTrivia | SyntaxKind.AtToken | SyntaxKind.NewLineTrivia | SyntaxKind.AsteriskToken | SyntaxKind.OpenBraceToken | SyntaxKind.CloseBraceToken | SyntaxKind.LessThanToken | SyntaxKind.OpenBracketToken | SyntaxKind.CloseBracketToken | SyntaxKind.EqualsToken | SyntaxKind.CommaToken | SyntaxKind.DotToken | SyntaxKind.Identifier | SyntaxKind.NoSubstitutionTemplateLiteral | SyntaxKind.Unknown | KeywordSyntaxKind;
type KeywordSyntaxKind = SyntaxKind.AbstractKeyword | SyntaxKind.AnyKeyword | SyntaxKind.AsKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.BreakKeyword | SyntaxKind.CaseKeyword | SyntaxKind.CatchKeyword | SyntaxKind.ClassKeyword | SyntaxKind.ContinueKeyword | SyntaxKind.ConstKeyword | SyntaxKind.ConstructorKeyword | SyntaxKind.DebuggerKeyword | SyntaxKind.DeclareKeyword | SyntaxKind.DefaultKeyword | SyntaxKind.DeleteKeyword | SyntaxKind.DoKeyword | SyntaxKind.ElseKeyword | SyntaxKind.EnumKeyword | SyntaxKind.ExportKeyword | SyntaxKind.ExtendsKeyword | SyntaxKind.FalseKeyword | SyntaxKind.FinallyKeyword | SyntaxKind.ForKeyword | SyntaxKind.FromKeyword | SyntaxKind.FunctionKeyword | SyntaxKind.GetKeyword | SyntaxKind.IfKeyword | SyntaxKind.ImplementsKeyword | SyntaxKind.ImportKeyword | SyntaxKind.InKeyword | SyntaxKind.InferKeyword | SyntaxKind.InstanceOfKeyword | SyntaxKind.InterfaceKeyword | SyntaxKind.IsKeyword | SyntaxKind.KeyOfKeyword | SyntaxKind.LetKeyword | SyntaxKind.ModuleKeyword | SyntaxKind.NamespaceKeyword | SyntaxKind.NeverKeyword | SyntaxKind.NewKeyword | SyntaxKind.NullKeyword | SyntaxKind.NumberKeyword | SyntaxKind.ObjectKeyword | SyntaxKind.PackageKeyword | SyntaxKind.PrivateKeyword | SyntaxKind.ProtectedKeyword | SyntaxKind.PublicKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.RequireKeyword | SyntaxKind.GlobalKeyword | SyntaxKind.ReturnKeyword | SyntaxKind.SetKeyword | SyntaxKind.StaticKeyword | SyntaxKind.StringKeyword | SyntaxKind.SuperKeyword | SyntaxKind.SwitchKeyword | SyntaxKind.SymbolKeyword | SyntaxKind.ThisKeyword | SyntaxKind.ThrowKeyword | SyntaxKind.TrueKeyword | SyntaxKind.TryKeyword | SyntaxKind.TypeKeyword | SyntaxKind.TypeOfKeyword | SyntaxKind.UndefinedKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.UnknownKeyword | SyntaxKind.VarKeyword | SyntaxKind.VoidKeyword | SyntaxKind.WhileKeyword | SyntaxKind.WithKeyword | SyntaxKind.YieldKeyword | SyntaxKind.AsyncKeyword | SyntaxKind.AwaitKeyword | SyntaxKind.OfKeyword;
type JsxTokenSyntaxKind = SyntaxKind.LessThanSlashToken | SyntaxKind.EndOfFileToken | SyntaxKind.ConflictMarkerTrivia | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.OpenBraceToken | SyntaxKind.LessThanToken;
enum SyntaxKind {
Unknown = 0,
@@ -536,6 +537,7 @@ declare namespace ts {
name?: Identifier | StringLiteral | NumericLiteral;
}
interface ComputedPropertyName extends Node {
parent: Declaration;
kind: SyntaxKind.ComputedPropertyName;
expression: Expression;
}
@@ -632,6 +634,7 @@ declare namespace ts {
kind: SyntaxKind.ShorthandPropertyAssignment;
name: Identifier;
questionToken?: QuestionToken;
exclamationToken?: ExclamationToken;
equalsToken?: Token<SyntaxKind.EqualsToken>;
objectAssignmentInitializer?: Expression;
}
@@ -668,6 +671,7 @@ declare namespace ts {
_functionLikeDeclarationBrand: any;
asteriskToken?: AsteriskToken;
questionToken?: QuestionToken;
exclamationToken?: ExclamationToken;
body?: Block | Expression;
}
type FunctionLikeDeclaration = FunctionDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ConstructorDeclaration | FunctionExpression | ArrowFunction;
@@ -1079,7 +1083,7 @@ declare namespace ts {
}
interface ExpressionWithTypeArguments extends NodeWithTypeArguments {
kind: SyntaxKind.ExpressionWithTypeArguments;
parent: HeritageClause;
parent: HeritageClause | JSDocAugmentsTag;
expression: LeftHandSideExpression;
}
interface NewExpression extends PrimaryExpression, Declaration {
@@ -1808,7 +1812,8 @@ declare namespace ts {
getTypeChecker(): TypeChecker;
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
isSourceFileDefaultLibrary(file: SourceFile): boolean;
getProjectReferences(): (ResolvedProjectReference | undefined)[] | undefined;
getProjectReferences(): ReadonlyArray<ProjectReference> | undefined;
getResolvedProjectReferences(): (ResolvedProjectReference | undefined)[] | undefined;
}
interface ResolvedProjectReference {
commandLine: ParsedCommandLine;
@@ -2056,32 +2061,32 @@ declare namespace ts {
ExportStar = 8388608,
Optional = 16777216,
Transient = 33554432,
JSContainer = 67108864,
Assignment = 67108864,
ModuleExports = 134217728,
Enum = 384,
Variable = 3,
Value = 67216319,
Type = 67901928,
Value = 67220415,
Type = 67897832,
Namespace = 1920,
Module = 1536,
Accessor = 98304,
FunctionScopedVariableExcludes = 67216318,
BlockScopedVariableExcludes = 67216319,
ParameterExcludes = 67216319,
FunctionScopedVariableExcludes = 67220414,
BlockScopedVariableExcludes = 67220415,
ParameterExcludes = 67220415,
PropertyExcludes = 0,
EnumMemberExcludes = 68008959,
FunctionExcludes = 67215791,
FunctionExcludes = 67219887,
ClassExcludes = 68008383,
InterfaceExcludes = 67901832,
InterfaceExcludes = 67897736,
RegularEnumExcludes = 68008191,
ConstEnumExcludes = 68008831,
ValueModuleExcludes = 67215503,
ValueModuleExcludes = 110735,
NamespaceModuleExcludes = 0,
MethodExcludes = 67208127,
GetAccessorExcludes = 67150783,
SetAccessorExcludes = 67183551,
TypeParameterExcludes = 67639784,
TypeAliasExcludes = 67901928,
MethodExcludes = 67212223,
GetAccessorExcludes = 67154879,
SetAccessorExcludes = 67187647,
TypeParameterExcludes = 67635688,
TypeAliasExcludes = 67897832,
AliasExcludes = 2097152,
ModuleMember = 2623475,
ExportHasLocal = 944,
@@ -2490,6 +2495,7 @@ declare namespace ts {
sourceRoot?: string;
strict?: boolean;
strictFunctionTypes?: boolean;
strictBindCallApply?: boolean;
strictNullChecks?: boolean;
strictPropertyInitialization?: boolean;
stripInternal?: boolean;
@@ -2581,7 +2587,6 @@ declare namespace ts {
}
interface ExpandResult {
fileNames: string[];
projectReferences: ReadonlyArray<ProjectReference> | undefined;
wildcardDirectories: MapLike<WatchDirectoryFlags>;
}
interface CreateProgramOptions {
@@ -2592,14 +2597,6 @@ declare namespace ts {
oldProgram?: Program;
configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>;
}
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;
}
interface ModuleResolutionHost {
fileExists(fileName: string): boolean;
readFile(fileName: string): string | undefined;
@@ -2698,9 +2695,6 @@ declare namespace ts {
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
getEnvironmentVariable?(name: string): string | undefined;
createHash?(data: string): string;
getModifiedTime?(fileName: string): Date | undefined;
setModifiedTime?(fileName: string, date: Date): void;
deleteFile?(fileName: string): void;
}
interface SourceMapRange extends TextRange {
source?: SourceMapSource;
@@ -3001,6 +2995,16 @@ declare namespace ts {
Parameters = 1296,
IndexSignatureParameters = 4432
}
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;
}
}
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
declare function clearTimeout(handle: any): void;
@@ -3209,17 +3213,27 @@ declare 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.
*/
function getJSDocParameterTags(param: ParameterDeclaration): ReadonlyArray<JSDocParameterTag>;
/**
* 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.
*/
function getJSDocTypeParameterTags(param: TypeParameterDeclaration): ReadonlyArray<JSDocTemplateTag>;
/**
* Return true if the node has JSDoc parameter tags.
*
@@ -4171,14 +4185,15 @@ declare namespace ts {
* @returns A 'Program' object.
*/
function createProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): Program;
interface ResolveProjectReferencePathHost {
/** @deprecated */ interface ResolveProjectReferencePathHost {
fileExists(fileName: string): boolean;
}
/**
* Returns the target config filename of a project reference.
* Note: The file might not exist.
*/
function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName;
function resolveProjectReferencePath(ref: ProjectReference): ResolvedConfigFileName;
/** @deprecated */ function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName;
}
declare namespace ts {
interface EmitOutput {
@@ -4303,32 +4318,43 @@ declare namespace ts {
* Create the builder to manage semantic diagnostics and cache them
*/
function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): SemanticDiagnosticsBuilderProgram;
function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): SemanticDiagnosticsBuilderProgram;
function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): SemanticDiagnosticsBuilderProgram;
/**
* Create the builder that can handle the changes in program and iterate through changed files
* to emit the those files and manage semantic diagnostics cache as well
*/
function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): EmitAndSemanticDiagnosticsBuilderProgram;
function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): EmitAndSemanticDiagnosticsBuilderProgram;
function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): EmitAndSemanticDiagnosticsBuilderProgram;
/**
* Creates a builder thats just abstraction over program and can be used with watch
*/
function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderProgram;
function createAbstractBuilder(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderProgram;
function createAbstractBuilder(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): BuilderProgram;
}
declare namespace ts {
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 */
type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) => T;
interface WatchCompilerHost<T extends BuilderProgram> {
type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference> | undefined) => T;
/** Host that has watch functionality used in --watch mode */
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;
}
interface WatchCompilerHost<T extends BuilderProgram> extends WatchHost {
/**
* Used to create the program when need for program creation or recreation detected
*/
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;
useCaseSensitiveFileNames(): boolean;
getNewLine(): string;
getCurrentDirectory(): string;
@@ -4361,14 +4387,6 @@ declare 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;
}
/**
* Host to create watch with root files and options
@@ -4378,6 +4396,8 @@ declare namespace ts {
rootFiles: string[];
/** Compiler options */
options: CompilerOptions;
/** Project References */
projectReferences?: ReadonlyArray<ProjectReference>;
}
/**
* Host to create watch with config file
@@ -4412,8 +4432,8 @@ declare namespace ts {
/**
* Create the watch compiler host for either configFile or fileNames and its options
*/
function createWatchCompilerHost<T extends BuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfFilesAndCompilerOptions<T>;
function createWatchCompilerHost<T extends BuilderProgram>(configFileName: string, optionsToExtend: CompilerOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfConfigFile<T>;
function createWatchCompilerHost<T extends BuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, projectReferences?: ReadonlyArray<ProjectReference>): WatchCompilerHostOfFilesAndCompilerOptions<T>;
/**
* Creates the watch from the host for root files and compiler options
*/
@@ -4423,184 +4443,11 @@ declare namespace ts {
*/
function createWatchProgram<T extends BuilderProgram>(host: WatchCompilerHostOfConfigFile<T>): WatchOfConfigFile<T>;
}
declare namespace ts {
interface BuildHost {
verbose(diag: DiagnosticMessage, ...args: string[]): void;
error(diag: DiagnosticMessage, ...args: string[]): void;
errorDiagnostic(diag: Diagnostic): void;
message(diag: DiagnosticMessage, ...args: string[]): void;
}
/**
* A BuildContext tracks what's going on during the course of a build.
*
* Callers may invoke any number of build requests within the same context;
* until the context is reset, each project will only be built at most once.
*
* Example: In a standard setup where project B depends on project A, and both are out of date,
* a failed build of A will result in A remaining out of date. When we try to build
* B, we should immediately bail instead of recomputing A's up-to-date status again.
*
* This also matters for performing fast (i.e. fake) downstream builds of projects
* when their upstream .d.ts files haven't changed content (but have newer timestamps)
*/
interface BuildContext {
options: BuildOptions;
/**
* Map from output file name to its pre-build timestamp
*/
unchangedOutputs: FileMap<Date>;
/**
* Map from config file name to up-to-date status
*/
projectStatus: FileMap<UpToDateStatus>;
invalidatedProjects: FileMap<true>;
queuedProjects: FileMap<true>;
missingRoots: Map<true>;
}
type Mapper = ReturnType<typeof createDependencyMapper>;
interface DependencyGraph {
buildQueue: ResolvedConfigFileName[];
dependencyMap: Mapper;
}
interface BuildOptions {
dry: boolean;
force: boolean;
verbose: boolean;
}
enum UpToDateStatusType {
Unbuildable = 0,
UpToDate = 1,
/**
* The project appears out of date because its upstream inputs are newer than its outputs,
* but all of its outputs are actually newer than the previous identical outputs of its (.d.ts) inputs.
* This means we can Pseudo-build (just touch timestamps), as if we had actually built this project.
*/
UpToDateWithUpstreamTypes = 2,
OutputMissing = 3,
OutOfDateWithSelf = 4,
OutOfDateWithUpstream = 5,
UpstreamOutOfDate = 6,
UpstreamBlocked = 7,
/**
* Projects with no outputs (i.e. "solution" files)
*/
ContainerOnly = 8
}
type UpToDateStatus = Status.Unbuildable | Status.UpToDate | Status.OutputMissing | Status.OutOfDateWithSelf | Status.OutOfDateWithUpstream | Status.UpstreamOutOfDate | Status.UpstreamBlocked | Status.ContainerOnly;
namespace Status {
/**
* The project can't be built at all in its current state. For example,
* its config file cannot be parsed, or it has a syntax error or missing file
*/
interface Unbuildable {
type: UpToDateStatusType.Unbuildable;
reason: string;
}
/**
* This project doesn't have any outputs, so "is it up to date" is a meaningless question.
*/
interface ContainerOnly {
type: UpToDateStatusType.ContainerOnly;
}
/**
* The project is up to date with respect to its inputs.
* We track what the newest input file is.
*/
interface UpToDate {
type: UpToDateStatusType.UpToDate | UpToDateStatusType.UpToDateWithUpstreamTypes;
newestInputFileTime?: Date;
newestInputFileName?: string;
newestDeclarationFileContentChangedTime?: Date;
newestOutputFileTime?: Date;
newestOutputFileName?: string;
oldestOutputFileName?: string;
}
/**
* One or more of the outputs of the project does not exist.
*/
interface OutputMissing {
type: UpToDateStatusType.OutputMissing;
/**
* The name of the first output file that didn't exist
*/
missingOutputFileName: string;
}
/**
* One or more of the project's outputs is older than its newest input.
*/
interface OutOfDateWithSelf {
type: UpToDateStatusType.OutOfDateWithSelf;
outOfDateOutputFileName: string;
newerInputFileName: string;
}
/**
* This project depends on an out-of-date project, so shouldn't be built yet
*/
interface UpstreamOutOfDate {
type: UpToDateStatusType.UpstreamOutOfDate;
upstreamProjectName: string;
}
/**
* This project depends an upstream project with build errors
*/
interface UpstreamBlocked {
type: UpToDateStatusType.UpstreamBlocked;
upstreamProjectName: string;
}
/**
* One or more of the project's outputs is older than the newest output of
* an upstream project.
*/
interface OutOfDateWithUpstream {
type: UpToDateStatusType.OutOfDateWithUpstream;
outOfDateOutputFileName: string;
newerProjectName: string;
}
}
interface FileMap<T> {
setValue(fileName: string, value: T): void;
getValue(fileName: string): T | never;
getValueOrUndefined(fileName: string): T | undefined;
hasKey(fileName: string): boolean;
removeKey(fileName: string): void;
getKeys(): string[];
}
function createDependencyMapper(): {
addReference: (childConfigFileName: ResolvedConfigFileName, parentConfigFileName: ResolvedConfigFileName) => void;
getReferencesTo: (parentConfigFileName: ResolvedConfigFileName) => ResolvedConfigFileName[];
getReferencesOf: (childConfigFileName: ResolvedConfigFileName) => ResolvedConfigFileName[];
getKeys: () => ReadonlyArray<ResolvedConfigFileName>;
};
function createBuildContext(options: BuildOptions): BuildContext;
function performBuild(args: string[], compilerHost: CompilerHost, buildHost: BuildHost, system?: System): number | undefined;
/**
* A SolutionBuilder has an immutable set of rootNames that are the "entry point" projects, but
* can dynamically add/remove other projects based on changes on the rootNames' references
*/
function createSolutionBuilder(compilerHost: CompilerHost, buildHost: BuildHost, rootNames: ReadonlyArray<string>, defaultOptions: BuildOptions, system?: System): {
buildAllProjects: () => ExitStatus;
getUpToDateStatus: (project: ParsedCommandLine | undefined) => UpToDateStatus;
getUpToDateStatusOfFile: (configFileName: ResolvedConfigFileName) => UpToDateStatus;
cleanAllProjects: () => ExitStatus.Success | ExitStatus.DiagnosticsPresent_OutputsSkipped;
resetBuildContext: (opts?: BuildOptions) => void;
getBuildGraph: (configFileNames: ReadonlyArray<string>) => DependencyGraph | undefined;
invalidateProject: (configFileName: string) => void;
buildInvalidatedProjects: () => void;
buildDependentInvalidatedProjects: () => void;
resolveProjectName: (name: string) => ResolvedConfigFileName | undefined;
startWatching: () => void;
};
/**
* Gets the UpToDateStatus for a project
*/
function getUpToDateStatus(host: UpToDateHost, project: ParsedCommandLine | undefined): UpToDateStatus;
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 ActionValueInspected = "action::valueInspected";
type EventTypesRegistry = "event::typesRegistry";
type EventBeginInstallTypes = "event::beginInstallTypes";
type EventEndInstallTypes = "event::endInstallTypes";
@@ -4609,7 +4456,7 @@ declare namespace ts.server {
" __sortedArrayBrand": any;
}
interface TypingInstallerResponse {
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | ActionValueInspected | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
}
interface TypingInstallerRequestWithProjectName {
readonly projectName: string;
@@ -4817,14 +4664,7 @@ declare namespace ts {
getCustomTransformers?(): CustomTransformers | undefined;
isKnownTypesPackageName?(name: string): boolean;
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
}
interface UserPreferences {
readonly disableSuggestions?: boolean;
readonly quotePreference?: "double" | "single";
readonly includeCompletionsForModuleExports?: boolean;
readonly includeCompletionsWithInsertText?: boolean;
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
readonly allowTextChangesInNewFiles?: boolean;
writeFile?(fileName: string, content: string): void;
}
interface LanguageService {
cleanupSemanticCache(): void;
@@ -4882,9 +4722,9 @@ declare namespace ts {
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: ReadonlyArray<number>, formatOptions: FormatCodeSettings, preferences: UserPreferences): ReadonlyArray<CodeFixAction>;
getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions;
applyCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
applyCodeActionCommand(action: CodeActionCommand[]): Promise<ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[]): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult>;
applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
/** @deprecated `fileName` will be ignored */
applyCodeActionCommand(fileName: string, action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
/** @deprecated `fileName` will be ignored */
@@ -5046,9 +4886,16 @@ declare namespace ts {
changes: ReadonlyArray<FileTextChanges>;
commands?: ReadonlyArray<CodeActionCommand>;
}
type CodeActionCommand = InstallPackageAction;
type CodeActionCommand = InstallPackageAction | GenerateTypesAction;
interface InstallPackageAction {
}
interface GenerateTypesAction extends GenerateTypesOptions {
}
interface GenerateTypesOptions {
readonly file: string;
readonly fileToGenerateTypesFor: string;
readonly outputFileName: string;
}
/**
* A set of one or more available refactoring actions, grouped under a parent refactoring.
*/
@@ -5114,6 +4961,8 @@ declare namespace ts {
originalFileName?: string;
}
interface RenameLocation extends DocumentSpan {
readonly prefixText?: string;
readonly suffixText?: string;
}
interface ReferenceEntry extends DocumentSpan {
isWriteAccess: boolean;
@@ -5266,15 +5115,24 @@ declare namespace ts {
documentation?: SymbolDisplayPart[];
tags?: JSDocTagInfo[];
}
interface RenameInfo {
canRename: boolean;
localizedErrorMessage?: string;
type RenameInfo = RenameInfoSuccess | RenameInfoFailure;
interface RenameInfoSuccess {
canRename: true;
/**
* File or directory to rename.
* If set, `getEditsForFileRename` should be called instead of `findRenameLocations`.
*/
fileToRename?: string;
displayName: string;
fullDisplayName: string;
kind: ScriptElementKind;
kindModifiers: string;
triggerSpan: TextSpan;
}
interface RenameInfoFailure {
canRename: false;
localizedErrorMessage: string;
}
interface SignatureHelpParameter {
name: string;
documentation: SymbolDisplayPart[];
@@ -5751,24 +5609,6 @@ declare namespace ts.server {
remove(path: NormalizedPath): void;
}
function createNormalizedPathMap<T>(): NormalizedPathMap<T>;
interface ProjectOptions {
configHasExtendsProperty: boolean;
/**
* true if config file explicitly listed files
*/
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;
}
function isInferredProjectName(name: string): boolean;
function makeInferredProjectName(counter: number): string;
function createSortedArray<T>(): SortedArray<T>;
@@ -6602,15 +6442,17 @@ declare namespace ts.server.protocol {
/**
* Information about the item to be renamed.
*/
interface RenameInfo {
type RenameInfo = RenameInfoSuccess | RenameInfoFailure;
interface RenameInfoSuccess {
/**
* True if item can be renamed.
*/
canRename: boolean;
canRename: true;
/**
* Error message if item can not be renamed.
* File or directory to rename.
* If set, `getEditsForFileRename` should be called instead of `findRenameLocations`.
*/
localizedErrorMessage?: string;
fileToRename?: string;
/**
* Display name of the item to be renamed.
*/
@@ -6627,6 +6469,15 @@ declare namespace ts.server.protocol {
* Optional modifiers for the kind (such as 'public').
*/
kindModifiers: string;
/** Span of text to rename. */
triggerSpan: TextSpan;
}
interface RenameInfoFailure {
canRename: false;
/**
* Error message if item can not be renamed.
*/
localizedErrorMessage: string;
}
/**
* A group of text spans, all in 'file'.
@@ -6635,7 +6486,11 @@ declare namespace ts.server.protocol {
/** The file to which the spans apply */
file: string;
/** The text spans in this group */
locs: TextSpan[];
locs: RenameTextSpan[];
}
interface RenameTextSpan extends TextSpan {
readonly prefixText?: string;
readonly suffixText?: string;
}
interface RenameResponseBody {
/**
@@ -7148,7 +7003,7 @@ declare namespace ts.server.protocol {
* begin with prefix.
*/
interface CompletionsRequest extends FileLocationRequest {
command: CommandTypes.Completions;
command: CommandTypes.Completions | CommandTypes.CompletionInfo;
arguments: CompletionsRequestArgs;
}
/**
@@ -7660,6 +7515,35 @@ declare namespace ts.server.protocol {
*/
openFiles: string[];
}
type ProjectLoadingStartEventName = "projectLoadingStart";
interface ProjectLoadingStartEvent extends Event {
event: ProjectLoadingStartEventName;
body: ProjectLoadingStartEventBody;
}
interface ProjectLoadingStartEventBody {
/** name of the project */
projectName: string;
/** reason for loading */
reason: string;
}
type ProjectLoadingFinishEventName = "projectLoadingFinish";
interface ProjectLoadingFinishEvent extends Event {
event: ProjectLoadingFinishEventName;
body: ProjectLoadingFinishEventBody;
}
interface ProjectLoadingFinishEventBody {
/** name of the project */
projectName: string;
}
type SurveyReadyEventName = "surveyReady";
interface SurveyReadyEvent extends Event {
event: SurveyReadyEventName;
body: SurveyReadyEventBody;
}
interface SurveyReadyEventBody {
/** Name of the survey. This is an internal machine- and programmer-friendly name */
surveyId: string;
}
type LargeFileReferencedEventName = "largeFileReferenced";
interface LargeFileReferencedEvent extends Event {
event: LargeFileReferencedEventName;
@@ -7995,6 +7879,7 @@ declare namespace ts.server.protocol {
readonly includeCompletionsWithInsertText?: boolean;
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
readonly allowTextChangesInNewFiles?: boolean;
readonly lazyConfiguredProjectsFromExternalProject?: boolean;
}
interface CompilerOptions {
allowJs?: boolean;
@@ -8126,14 +8011,14 @@ declare namespace ts.server {
getSnapshot(): IScriptSnapshot;
private ensureRealPath;
getFormatCodeSettings(): FormatCodeSettings | undefined;
getPreferences(): UserPreferences | undefined;
getPreferences(): protocol.UserPreferences | undefined;
attachToProject(project: Project): boolean;
isAttached(project: Project): boolean;
detachFromProject(project: Project): void;
detachAllProjects(): void;
getDefaultProject(): Project;
registerFileUpdate(): void;
setOptions(formatSettings: FormatCodeSettings, preferences: UserPreferences | undefined): void;
setOptions(formatSettings: FormatCodeSettings, preferences: protocol.UserPreferences | undefined): void;
getLatestVersion(): string;
saveTo(fileName: string): void;
reloadFromFile(tempFileName?: NormalizedPath): boolean;
@@ -8238,6 +8123,7 @@ declare namespace ts.server {
* This property is different from projectStructureVersion since in most cases edits don't affect set of files in the project
*/
private projectStateVersion;
protected isInitialLoadPending: () => boolean;
private readonly cancellationToken;
isNonTsProject(): boolean;
isJsOnlyProject(): boolean;
@@ -8261,6 +8147,7 @@ declare namespace ts.server {
useCaseSensitiveFileNames(): boolean;
readDirectory(path: string, extensions?: ReadonlyArray<string>, exclude?: ReadonlyArray<string>, include?: ReadonlyArray<string>, depth?: number): string[];
readFile(fileName: string): string | undefined;
writeFile(fileName: string, content: string): void;
fileExists(file: string): boolean;
resolveModuleNames(moduleNames: string[], containingFile: string, reusedNames?: string[]): ResolvedModuleFull[];
getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string): ResolvedModuleWithFailedLookupLocations | undefined;
@@ -8322,7 +8209,7 @@ declare namespace ts.server {
filesToString(writeProjectFileNames: boolean): string;
setCompilerOptions(compilerOptions: CompilerOptions): void;
protected removeRoot(info: ScriptInfo): void;
protected enableGlobalPlugins(): void;
protected enableGlobalPlugins(options: CompilerOptions): void;
protected enablePlugin(pluginConfigEntry: PluginImport, searchPaths: string[]): void;
/** Starts a new check for diagnostics. Call this if some file has updated that would cause diagnostics to be changed. */
refreshDiagnostics(): void;
@@ -8351,14 +8238,14 @@ declare namespace ts.server {
* Otherwise it will create an InferredProject.
*/
class ConfiguredProject extends Project {
compileOnSaveEnabled: boolean;
private projectReferences;
private typeAcquisition;
private directoriesWatchedForWildcards;
readonly canonicalConfigFilePath: NormalizedPath;
/** Ref count to the project when opened from external project */
private externalProjectRefCount;
private projectErrors;
private projectReferences;
protected isInitialLoadPending: () => boolean;
/**
* If the project has reload from disk pending, it reloads (and then updates graph as part of that) instead of just updating the graph
* @returns: true if set of files in the project stays the same and false - otherwise.
@@ -8391,6 +8278,7 @@ declare namespace ts.server {
compileOnSaveEnabled: boolean;
excludedFiles: ReadonlyArray<NormalizedPath>;
private typeAcquisition;
updateGraph(): boolean;
getExcludedFiles(): ReadonlyArray<NormalizedPath>;
getTypeAcquisition(): TypeAcquisition;
setTypeAcquisition(newTypeAcquisition: TypeAcquisition): void;
@@ -8399,6 +8287,9 @@ declare namespace ts.server {
declare namespace ts.server {
const maxProgramSizeForNonTsFiles: number;
const ProjectsUpdatedInBackgroundEvent = "projectsUpdatedInBackground";
const ProjectLoadingStartEvent = "projectLoadingStart";
const ProjectLoadingFinishEvent = "projectLoadingFinish";
const SurveyReady = "surveyReady";
const LargeFileReferencedEvent = "largeFileReferenced";
const ConfigFileDiagEvent = "configFileDiag";
const ProjectLanguageServiceStateEvent = "projectLanguageServiceState";
@@ -8410,6 +8301,25 @@ declare namespace ts.server {
openFiles: string[];
};
}
interface ProjectLoadingStartEvent {
eventName: typeof ProjectLoadingStartEvent;
data: {
project: Project;
reason: string;
};
}
interface ProjectLoadingFinishEvent {
eventName: typeof ProjectLoadingFinishEvent;
data: {
project: Project;
};
}
interface SurveyReady {
eventName: typeof SurveyReady;
data: {
surveyId: string;
};
}
interface LargeFileReferencedEvent {
eventName: typeof LargeFileReferencedEvent;
data: {
@@ -8488,7 +8398,7 @@ declare namespace ts.server {
interface OpenFileInfo {
readonly checkJs: boolean;
}
type ProjectServiceEvent = LargeFileReferencedEvent | ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
type ProjectServiceEvent = LargeFileReferencedEvent | SurveyReady | ProjectsUpdatedInBackgroundEvent | ProjectLoadingStartEvent | ProjectLoadingFinishEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
type ProjectServiceEventHandler = (event: ProjectServiceEvent) => void;
interface SafeList {
[name: string]: {
@@ -8509,7 +8419,7 @@ declare namespace ts.server {
function convertScriptKindName(scriptKindName: protocol.ScriptKindName): ScriptKind.Unknown | ScriptKind.JS | ScriptKind.JSX | ScriptKind.TS | ScriptKind.TSX;
interface HostConfiguration {
formatCodeOptions: FormatCodeSettings;
preferences: UserPreferences;
preferences: protocol.UserPreferences;
hostInfo: string;
extraFileExtensions?: FileExtensionInfo[];
}
@@ -8538,6 +8448,7 @@ declare namespace ts.server {
* Container of all known scripts
*/
private readonly filenameToScriptInfo;
private readonly scriptInfoInNodeModulesWatchers;
/**
* Contains all the deleted script info's version information so that
* it does not reset when creating script info again
@@ -8586,7 +8497,7 @@ declare namespace ts.server {
private readonly throttledOperations;
private readonly hostConfiguration;
private safelist;
private legacySafelist;
private readonly legacySafelist;
private pendingProjectUpdates;
readonly currentDirectory: NormalizedPath;
readonly toCanonicalFileName: (f: string) => string;
@@ -8607,6 +8518,8 @@ declare namespace ts.server {
readonly syntaxOnly?: boolean;
/** Tracks projects that we have already sent telemetry for. */
private readonly seenProjects;
/** Tracks projects that we have already sent survey events for. */
private readonly seenSurveyProjects;
constructor(opts: ProjectServiceOptions);
toPath(fileName: string): Path;
private loadTypesMap;
@@ -8628,9 +8541,9 @@ declare namespace ts.server {
*/
private ensureProjectStructuresUptoDate;
getFormatCodeOptions(file: NormalizedPath): FormatCodeSettings;
getPreferences(file: NormalizedPath): UserPreferences;
getPreferences(file: NormalizedPath): protocol.UserPreferences;
getHostFormatCodeOptions(): FormatCodeSettings;
getHostPreferences(): UserPreferences;
getHostPreferences(): protocol.UserPreferences;
private onSourceFileChanged;
private handleDeletedFile;
private onConfigChangedForConfiguredProject;
@@ -8692,15 +8605,13 @@ declare namespace ts.server {
private findConfiguredProjectByProjectName;
private getConfiguredProjectByCanonicalConfigFilePath;
private findExternalProjectByProjectName;
private convertConfigFileContentToProjectOptions;
/** Get a filename if the language service exceeds the maximum allowed program size; otherwise returns undefined. */
private getFilenameForExceededTotalSizeLimitForNonTsFiles;
private createExternalProject;
private sendProjectTelemetry;
private addFilesToNonInferredProjectAndUpdateGraph;
private addFilesToNonInferredProject;
private createConfiguredProject;
private updateNonInferredProjectFiles;
private updateNonInferredProject;
private updateRootAndOptionsOfNonInferredProject;
private sendConfigFileDiagEvent;
private getOrCreateInferredProjectForProjectRootPathIfEnabled;
private getOrCreateSingleInferredProjectIfEnabled;
@@ -8708,6 +8619,10 @@ declare namespace ts.server {
private createInferredProject;
getScriptInfo(uncheckedFileName: string): ScriptInfo | undefined;
private watchClosedScriptInfo;
private watchClosedScriptInfoInNodeModules;
private getModifiedTime;
private refreshScriptInfo;
private refreshScriptInfosInDirectory;
private stopWatchingScriptInfo;
private getOrCreateScriptInfoNotOpenedByClientForNormalizedPath;
private getOrCreateScriptInfoOpenedByClientForNormalizedPath;
@@ -8815,6 +8730,7 @@ declare namespace ts.server {
globalPlugins?: ReadonlyArray<string>;
pluginProbeLocations?: ReadonlyArray<string>;
allowLocalPluginLoads?: boolean;
typesMapLocation?: string;
}
class Session implements EventSender {
private readonly gcTimer;
@@ -8837,6 +8753,7 @@ declare namespace ts.server {
private defaultEventHandler;
private projectsUpdatedInBackgroundEvent;
logError(err: Error, cmd: string): void;
private logErrorWorker;
send(msg: protocol.Message): void;
event<T extends object>(body: T, eventName: string): void;
/** @deprecated */
@@ -8881,7 +8798,7 @@ declare namespace ts.server {
private getProjects;
private getDefaultProject;
private getRenameLocations;
private static mapRenameInfo;
private mapRenameInfo;
private toSpanGroups;
private getReferences;
/**
+7657 -4624
View File
File diff suppressed because it is too large Load Diff
+99 -241
View File
@@ -14,7 +14,7 @@ and limitations under the License.
***************************************************************************** */
declare namespace ts {
const versionMajorMinor = "3.1";
const versionMajorMinor = "3.2";
/** The version of the TypeScript compiler release */
const version: string;
}
@@ -69,7 +69,8 @@ declare namespace ts {
pos: number;
end: number;
}
type JsDocSyntaxKind = SyntaxKind.EndOfFileToken | SyntaxKind.WhitespaceTrivia | SyntaxKind.AtToken | SyntaxKind.NewLineTrivia | SyntaxKind.AsteriskToken | SyntaxKind.OpenBraceToken | SyntaxKind.CloseBraceToken | SyntaxKind.LessThanToken | SyntaxKind.OpenBracketToken | SyntaxKind.CloseBracketToken | SyntaxKind.EqualsToken | SyntaxKind.CommaToken | SyntaxKind.DotToken | SyntaxKind.Identifier | SyntaxKind.NoSubstitutionTemplateLiteral | SyntaxKind.Unknown;
type JsDocSyntaxKind = SyntaxKind.EndOfFileToken | SyntaxKind.WhitespaceTrivia | SyntaxKind.AtToken | SyntaxKind.NewLineTrivia | SyntaxKind.AsteriskToken | SyntaxKind.OpenBraceToken | SyntaxKind.CloseBraceToken | SyntaxKind.LessThanToken | SyntaxKind.OpenBracketToken | SyntaxKind.CloseBracketToken | SyntaxKind.EqualsToken | SyntaxKind.CommaToken | SyntaxKind.DotToken | SyntaxKind.Identifier | SyntaxKind.NoSubstitutionTemplateLiteral | SyntaxKind.Unknown | KeywordSyntaxKind;
type KeywordSyntaxKind = SyntaxKind.AbstractKeyword | SyntaxKind.AnyKeyword | SyntaxKind.AsKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.BreakKeyword | SyntaxKind.CaseKeyword | SyntaxKind.CatchKeyword | SyntaxKind.ClassKeyword | SyntaxKind.ContinueKeyword | SyntaxKind.ConstKeyword | SyntaxKind.ConstructorKeyword | SyntaxKind.DebuggerKeyword | SyntaxKind.DeclareKeyword | SyntaxKind.DefaultKeyword | SyntaxKind.DeleteKeyword | SyntaxKind.DoKeyword | SyntaxKind.ElseKeyword | SyntaxKind.EnumKeyword | SyntaxKind.ExportKeyword | SyntaxKind.ExtendsKeyword | SyntaxKind.FalseKeyword | SyntaxKind.FinallyKeyword | SyntaxKind.ForKeyword | SyntaxKind.FromKeyword | SyntaxKind.FunctionKeyword | SyntaxKind.GetKeyword | SyntaxKind.IfKeyword | SyntaxKind.ImplementsKeyword | SyntaxKind.ImportKeyword | SyntaxKind.InKeyword | SyntaxKind.InferKeyword | SyntaxKind.InstanceOfKeyword | SyntaxKind.InterfaceKeyword | SyntaxKind.IsKeyword | SyntaxKind.KeyOfKeyword | SyntaxKind.LetKeyword | SyntaxKind.ModuleKeyword | SyntaxKind.NamespaceKeyword | SyntaxKind.NeverKeyword | SyntaxKind.NewKeyword | SyntaxKind.NullKeyword | SyntaxKind.NumberKeyword | SyntaxKind.ObjectKeyword | SyntaxKind.PackageKeyword | SyntaxKind.PrivateKeyword | SyntaxKind.ProtectedKeyword | SyntaxKind.PublicKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.RequireKeyword | SyntaxKind.GlobalKeyword | SyntaxKind.ReturnKeyword | SyntaxKind.SetKeyword | SyntaxKind.StaticKeyword | SyntaxKind.StringKeyword | SyntaxKind.SuperKeyword | SyntaxKind.SwitchKeyword | SyntaxKind.SymbolKeyword | SyntaxKind.ThisKeyword | SyntaxKind.ThrowKeyword | SyntaxKind.TrueKeyword | SyntaxKind.TryKeyword | SyntaxKind.TypeKeyword | SyntaxKind.TypeOfKeyword | SyntaxKind.UndefinedKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.UnknownKeyword | SyntaxKind.VarKeyword | SyntaxKind.VoidKeyword | SyntaxKind.WhileKeyword | SyntaxKind.WithKeyword | SyntaxKind.YieldKeyword | SyntaxKind.AsyncKeyword | SyntaxKind.AwaitKeyword | SyntaxKind.OfKeyword;
type JsxTokenSyntaxKind = SyntaxKind.LessThanSlashToken | SyntaxKind.EndOfFileToken | SyntaxKind.ConflictMarkerTrivia | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.OpenBraceToken | SyntaxKind.LessThanToken;
enum SyntaxKind {
Unknown = 0,
@@ -536,6 +537,7 @@ declare namespace ts {
name?: Identifier | StringLiteral | NumericLiteral;
}
interface ComputedPropertyName extends Node {
parent: Declaration;
kind: SyntaxKind.ComputedPropertyName;
expression: Expression;
}
@@ -632,6 +634,7 @@ declare namespace ts {
kind: SyntaxKind.ShorthandPropertyAssignment;
name: Identifier;
questionToken?: QuestionToken;
exclamationToken?: ExclamationToken;
equalsToken?: Token<SyntaxKind.EqualsToken>;
objectAssignmentInitializer?: Expression;
}
@@ -668,6 +671,7 @@ declare namespace ts {
_functionLikeDeclarationBrand: any;
asteriskToken?: AsteriskToken;
questionToken?: QuestionToken;
exclamationToken?: ExclamationToken;
body?: Block | Expression;
}
type FunctionLikeDeclaration = FunctionDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ConstructorDeclaration | FunctionExpression | ArrowFunction;
@@ -1079,7 +1083,7 @@ declare namespace ts {
}
interface ExpressionWithTypeArguments extends NodeWithTypeArguments {
kind: SyntaxKind.ExpressionWithTypeArguments;
parent: HeritageClause;
parent: HeritageClause | JSDocAugmentsTag;
expression: LeftHandSideExpression;
}
interface NewExpression extends PrimaryExpression, Declaration {
@@ -1808,7 +1812,8 @@ declare namespace ts {
getTypeChecker(): TypeChecker;
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
isSourceFileDefaultLibrary(file: SourceFile): boolean;
getProjectReferences(): (ResolvedProjectReference | undefined)[] | undefined;
getProjectReferences(): ReadonlyArray<ProjectReference> | undefined;
getResolvedProjectReferences(): (ResolvedProjectReference | undefined)[] | undefined;
}
interface ResolvedProjectReference {
commandLine: ParsedCommandLine;
@@ -2056,32 +2061,32 @@ declare namespace ts {
ExportStar = 8388608,
Optional = 16777216,
Transient = 33554432,
JSContainer = 67108864,
Assignment = 67108864,
ModuleExports = 134217728,
Enum = 384,
Variable = 3,
Value = 67216319,
Type = 67901928,
Value = 67220415,
Type = 67897832,
Namespace = 1920,
Module = 1536,
Accessor = 98304,
FunctionScopedVariableExcludes = 67216318,
BlockScopedVariableExcludes = 67216319,
ParameterExcludes = 67216319,
FunctionScopedVariableExcludes = 67220414,
BlockScopedVariableExcludes = 67220415,
ParameterExcludes = 67220415,
PropertyExcludes = 0,
EnumMemberExcludes = 68008959,
FunctionExcludes = 67215791,
FunctionExcludes = 67219887,
ClassExcludes = 68008383,
InterfaceExcludes = 67901832,
InterfaceExcludes = 67897736,
RegularEnumExcludes = 68008191,
ConstEnumExcludes = 68008831,
ValueModuleExcludes = 67215503,
ValueModuleExcludes = 110735,
NamespaceModuleExcludes = 0,
MethodExcludes = 67208127,
GetAccessorExcludes = 67150783,
SetAccessorExcludes = 67183551,
TypeParameterExcludes = 67639784,
TypeAliasExcludes = 67901928,
MethodExcludes = 67212223,
GetAccessorExcludes = 67154879,
SetAccessorExcludes = 67187647,
TypeParameterExcludes = 67635688,
TypeAliasExcludes = 67897832,
AliasExcludes = 2097152,
ModuleMember = 2623475,
ExportHasLocal = 944,
@@ -2490,6 +2495,7 @@ declare namespace ts {
sourceRoot?: string;
strict?: boolean;
strictFunctionTypes?: boolean;
strictBindCallApply?: boolean;
strictNullChecks?: boolean;
strictPropertyInitialization?: boolean;
stripInternal?: boolean;
@@ -2581,7 +2587,6 @@ declare namespace ts {
}
interface ExpandResult {
fileNames: string[];
projectReferences: ReadonlyArray<ProjectReference> | undefined;
wildcardDirectories: MapLike<WatchDirectoryFlags>;
}
interface CreateProgramOptions {
@@ -2592,14 +2597,6 @@ declare namespace ts {
oldProgram?: Program;
configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>;
}
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;
}
interface ModuleResolutionHost {
fileExists(fileName: string): boolean;
readFile(fileName: string): string | undefined;
@@ -2698,9 +2695,6 @@ declare namespace ts {
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
getEnvironmentVariable?(name: string): string | undefined;
createHash?(data: string): string;
getModifiedTime?(fileName: string): Date | undefined;
setModifiedTime?(fileName: string, date: Date): void;
deleteFile?(fileName: string): void;
}
interface SourceMapRange extends TextRange {
source?: SourceMapSource;
@@ -3001,6 +2995,16 @@ declare namespace ts {
Parameters = 1296,
IndexSignatureParameters = 4432
}
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;
}
}
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
declare function clearTimeout(handle: any): void;
@@ -3209,17 +3213,27 @@ declare 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.
*/
function getJSDocParameterTags(param: ParameterDeclaration): ReadonlyArray<JSDocParameterTag>;
/**
* 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.
*/
function getJSDocTypeParameterTags(param: TypeParameterDeclaration): ReadonlyArray<JSDocTemplateTag>;
/**
* Return true if the node has JSDoc parameter tags.
*
@@ -4171,14 +4185,15 @@ declare namespace ts {
* @returns A 'Program' object.
*/
function createProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): Program;
interface ResolveProjectReferencePathHost {
/** @deprecated */ interface ResolveProjectReferencePathHost {
fileExists(fileName: string): boolean;
}
/**
* Returns the target config filename of a project reference.
* Note: The file might not exist.
*/
function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName;
function resolveProjectReferencePath(ref: ProjectReference): ResolvedConfigFileName;
/** @deprecated */ function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName;
}
declare namespace ts {
interface EmitOutput {
@@ -4303,32 +4318,43 @@ declare namespace ts {
* Create the builder to manage semantic diagnostics and cache them
*/
function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): SemanticDiagnosticsBuilderProgram;
function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): SemanticDiagnosticsBuilderProgram;
function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): SemanticDiagnosticsBuilderProgram;
/**
* Create the builder that can handle the changes in program and iterate through changed files
* to emit the those files and manage semantic diagnostics cache as well
*/
function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): EmitAndSemanticDiagnosticsBuilderProgram;
function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): EmitAndSemanticDiagnosticsBuilderProgram;
function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): EmitAndSemanticDiagnosticsBuilderProgram;
/**
* Creates a builder thats just abstraction over program and can be used with watch
*/
function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderProgram;
function createAbstractBuilder(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderProgram;
function createAbstractBuilder(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): BuilderProgram;
}
declare namespace ts {
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 */
type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) => T;
interface WatchCompilerHost<T extends BuilderProgram> {
type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference> | undefined) => T;
/** Host that has watch functionality used in --watch mode */
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;
}
interface WatchCompilerHost<T extends BuilderProgram> extends WatchHost {
/**
* Used to create the program when need for program creation or recreation detected
*/
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;
useCaseSensitiveFileNames(): boolean;
getNewLine(): string;
getCurrentDirectory(): string;
@@ -4361,14 +4387,6 @@ declare 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;
}
/**
* Host to create watch with root files and options
@@ -4378,6 +4396,8 @@ declare namespace ts {
rootFiles: string[];
/** Compiler options */
options: CompilerOptions;
/** Project References */
projectReferences?: ReadonlyArray<ProjectReference>;
}
/**
* Host to create watch with config file
@@ -4412,8 +4432,8 @@ declare namespace ts {
/**
* Create the watch compiler host for either configFile or fileNames and its options
*/
function createWatchCompilerHost<T extends BuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfFilesAndCompilerOptions<T>;
function createWatchCompilerHost<T extends BuilderProgram>(configFileName: string, optionsToExtend: CompilerOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfConfigFile<T>;
function createWatchCompilerHost<T extends BuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, projectReferences?: ReadonlyArray<ProjectReference>): WatchCompilerHostOfFilesAndCompilerOptions<T>;
/**
* Creates the watch from the host for root files and compiler options
*/
@@ -4423,184 +4443,11 @@ declare namespace ts {
*/
function createWatchProgram<T extends BuilderProgram>(host: WatchCompilerHostOfConfigFile<T>): WatchOfConfigFile<T>;
}
declare namespace ts {
interface BuildHost {
verbose(diag: DiagnosticMessage, ...args: string[]): void;
error(diag: DiagnosticMessage, ...args: string[]): void;
errorDiagnostic(diag: Diagnostic): void;
message(diag: DiagnosticMessage, ...args: string[]): void;
}
/**
* A BuildContext tracks what's going on during the course of a build.
*
* Callers may invoke any number of build requests within the same context;
* until the context is reset, each project will only be built at most once.
*
* Example: In a standard setup where project B depends on project A, and both are out of date,
* a failed build of A will result in A remaining out of date. When we try to build
* B, we should immediately bail instead of recomputing A's up-to-date status again.
*
* This also matters for performing fast (i.e. fake) downstream builds of projects
* when their upstream .d.ts files haven't changed content (but have newer timestamps)
*/
interface BuildContext {
options: BuildOptions;
/**
* Map from output file name to its pre-build timestamp
*/
unchangedOutputs: FileMap<Date>;
/**
* Map from config file name to up-to-date status
*/
projectStatus: FileMap<UpToDateStatus>;
invalidatedProjects: FileMap<true>;
queuedProjects: FileMap<true>;
missingRoots: Map<true>;
}
type Mapper = ReturnType<typeof createDependencyMapper>;
interface DependencyGraph {
buildQueue: ResolvedConfigFileName[];
dependencyMap: Mapper;
}
interface BuildOptions {
dry: boolean;
force: boolean;
verbose: boolean;
}
enum UpToDateStatusType {
Unbuildable = 0,
UpToDate = 1,
/**
* The project appears out of date because its upstream inputs are newer than its outputs,
* but all of its outputs are actually newer than the previous identical outputs of its (.d.ts) inputs.
* This means we can Pseudo-build (just touch timestamps), as if we had actually built this project.
*/
UpToDateWithUpstreamTypes = 2,
OutputMissing = 3,
OutOfDateWithSelf = 4,
OutOfDateWithUpstream = 5,
UpstreamOutOfDate = 6,
UpstreamBlocked = 7,
/**
* Projects with no outputs (i.e. "solution" files)
*/
ContainerOnly = 8
}
type UpToDateStatus = Status.Unbuildable | Status.UpToDate | Status.OutputMissing | Status.OutOfDateWithSelf | Status.OutOfDateWithUpstream | Status.UpstreamOutOfDate | Status.UpstreamBlocked | Status.ContainerOnly;
namespace Status {
/**
* The project can't be built at all in its current state. For example,
* its config file cannot be parsed, or it has a syntax error or missing file
*/
interface Unbuildable {
type: UpToDateStatusType.Unbuildable;
reason: string;
}
/**
* This project doesn't have any outputs, so "is it up to date" is a meaningless question.
*/
interface ContainerOnly {
type: UpToDateStatusType.ContainerOnly;
}
/**
* The project is up to date with respect to its inputs.
* We track what the newest input file is.
*/
interface UpToDate {
type: UpToDateStatusType.UpToDate | UpToDateStatusType.UpToDateWithUpstreamTypes;
newestInputFileTime?: Date;
newestInputFileName?: string;
newestDeclarationFileContentChangedTime?: Date;
newestOutputFileTime?: Date;
newestOutputFileName?: string;
oldestOutputFileName?: string;
}
/**
* One or more of the outputs of the project does not exist.
*/
interface OutputMissing {
type: UpToDateStatusType.OutputMissing;
/**
* The name of the first output file that didn't exist
*/
missingOutputFileName: string;
}
/**
* One or more of the project's outputs is older than its newest input.
*/
interface OutOfDateWithSelf {
type: UpToDateStatusType.OutOfDateWithSelf;
outOfDateOutputFileName: string;
newerInputFileName: string;
}
/**
* This project depends on an out-of-date project, so shouldn't be built yet
*/
interface UpstreamOutOfDate {
type: UpToDateStatusType.UpstreamOutOfDate;
upstreamProjectName: string;
}
/**
* This project depends an upstream project with build errors
*/
interface UpstreamBlocked {
type: UpToDateStatusType.UpstreamBlocked;
upstreamProjectName: string;
}
/**
* One or more of the project's outputs is older than the newest output of
* an upstream project.
*/
interface OutOfDateWithUpstream {
type: UpToDateStatusType.OutOfDateWithUpstream;
outOfDateOutputFileName: string;
newerProjectName: string;
}
}
interface FileMap<T> {
setValue(fileName: string, value: T): void;
getValue(fileName: string): T | never;
getValueOrUndefined(fileName: string): T | undefined;
hasKey(fileName: string): boolean;
removeKey(fileName: string): void;
getKeys(): string[];
}
function createDependencyMapper(): {
addReference: (childConfigFileName: ResolvedConfigFileName, parentConfigFileName: ResolvedConfigFileName) => void;
getReferencesTo: (parentConfigFileName: ResolvedConfigFileName) => ResolvedConfigFileName[];
getReferencesOf: (childConfigFileName: ResolvedConfigFileName) => ResolvedConfigFileName[];
getKeys: () => ReadonlyArray<ResolvedConfigFileName>;
};
function createBuildContext(options: BuildOptions): BuildContext;
function performBuild(args: string[], compilerHost: CompilerHost, buildHost: BuildHost, system?: System): number | undefined;
/**
* A SolutionBuilder has an immutable set of rootNames that are the "entry point" projects, but
* can dynamically add/remove other projects based on changes on the rootNames' references
*/
function createSolutionBuilder(compilerHost: CompilerHost, buildHost: BuildHost, rootNames: ReadonlyArray<string>, defaultOptions: BuildOptions, system?: System): {
buildAllProjects: () => ExitStatus;
getUpToDateStatus: (project: ParsedCommandLine | undefined) => UpToDateStatus;
getUpToDateStatusOfFile: (configFileName: ResolvedConfigFileName) => UpToDateStatus;
cleanAllProjects: () => ExitStatus.Success | ExitStatus.DiagnosticsPresent_OutputsSkipped;
resetBuildContext: (opts?: BuildOptions) => void;
getBuildGraph: (configFileNames: ReadonlyArray<string>) => DependencyGraph | undefined;
invalidateProject: (configFileName: string) => void;
buildInvalidatedProjects: () => void;
buildDependentInvalidatedProjects: () => void;
resolveProjectName: (name: string) => ResolvedConfigFileName | undefined;
startWatching: () => void;
};
/**
* Gets the UpToDateStatus for a project
*/
function getUpToDateStatus(host: UpToDateHost, project: ParsedCommandLine | undefined): UpToDateStatus;
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 ActionValueInspected = "action::valueInspected";
type EventTypesRegistry = "event::typesRegistry";
type EventBeginInstallTypes = "event::beginInstallTypes";
type EventEndInstallTypes = "event::endInstallTypes";
@@ -4609,7 +4456,7 @@ declare namespace ts.server {
" __sortedArrayBrand": any;
}
interface TypingInstallerResponse {
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | ActionValueInspected | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
}
interface TypingInstallerRequestWithProjectName {
readonly projectName: string;
@@ -4817,14 +4664,7 @@ declare namespace ts {
getCustomTransformers?(): CustomTransformers | undefined;
isKnownTypesPackageName?(name: string): boolean;
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
}
interface UserPreferences {
readonly disableSuggestions?: boolean;
readonly quotePreference?: "double" | "single";
readonly includeCompletionsForModuleExports?: boolean;
readonly includeCompletionsWithInsertText?: boolean;
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
readonly allowTextChangesInNewFiles?: boolean;
writeFile?(fileName: string, content: string): void;
}
interface LanguageService {
cleanupSemanticCache(): void;
@@ -4882,9 +4722,9 @@ declare namespace ts {
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: ReadonlyArray<number>, formatOptions: FormatCodeSettings, preferences: UserPreferences): ReadonlyArray<CodeFixAction>;
getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions;
applyCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
applyCodeActionCommand(action: CodeActionCommand[]): Promise<ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[]): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult>;
applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
/** @deprecated `fileName` will be ignored */
applyCodeActionCommand(fileName: string, action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
/** @deprecated `fileName` will be ignored */
@@ -5046,9 +4886,16 @@ declare namespace ts {
changes: ReadonlyArray<FileTextChanges>;
commands?: ReadonlyArray<CodeActionCommand>;
}
type CodeActionCommand = InstallPackageAction;
type CodeActionCommand = InstallPackageAction | GenerateTypesAction;
interface InstallPackageAction {
}
interface GenerateTypesAction extends GenerateTypesOptions {
}
interface GenerateTypesOptions {
readonly file: string;
readonly fileToGenerateTypesFor: string;
readonly outputFileName: string;
}
/**
* A set of one or more available refactoring actions, grouped under a parent refactoring.
*/
@@ -5114,6 +4961,8 @@ declare namespace ts {
originalFileName?: string;
}
interface RenameLocation extends DocumentSpan {
readonly prefixText?: string;
readonly suffixText?: string;
}
interface ReferenceEntry extends DocumentSpan {
isWriteAccess: boolean;
@@ -5266,15 +5115,24 @@ declare namespace ts {
documentation?: SymbolDisplayPart[];
tags?: JSDocTagInfo[];
}
interface RenameInfo {
canRename: boolean;
localizedErrorMessage?: string;
type RenameInfo = RenameInfoSuccess | RenameInfoFailure;
interface RenameInfoSuccess {
canRename: true;
/**
* File or directory to rename.
* If set, `getEditsForFileRename` should be called instead of `findRenameLocations`.
*/
fileToRename?: string;
displayName: string;
fullDisplayName: string;
kind: ScriptElementKind;
kindModifiers: string;
triggerSpan: TextSpan;
}
interface RenameInfoFailure {
canRename: false;
localizedErrorMessage: string;
}
interface SignatureHelpParameter {
name: string;
documentation: SymbolDisplayPart[];
+7227 -4444
View File
File diff suppressed because it is too large Load Diff
+99 -241
View File
@@ -14,7 +14,7 @@ and limitations under the License.
***************************************************************************** */
declare namespace ts {
const versionMajorMinor = "3.1";
const versionMajorMinor = "3.2";
/** The version of the TypeScript compiler release */
const version: string;
}
@@ -69,7 +69,8 @@ declare namespace ts {
pos: number;
end: number;
}
type JsDocSyntaxKind = SyntaxKind.EndOfFileToken | SyntaxKind.WhitespaceTrivia | SyntaxKind.AtToken | SyntaxKind.NewLineTrivia | SyntaxKind.AsteriskToken | SyntaxKind.OpenBraceToken | SyntaxKind.CloseBraceToken | SyntaxKind.LessThanToken | SyntaxKind.OpenBracketToken | SyntaxKind.CloseBracketToken | SyntaxKind.EqualsToken | SyntaxKind.CommaToken | SyntaxKind.DotToken | SyntaxKind.Identifier | SyntaxKind.NoSubstitutionTemplateLiteral | SyntaxKind.Unknown;
type JsDocSyntaxKind = SyntaxKind.EndOfFileToken | SyntaxKind.WhitespaceTrivia | SyntaxKind.AtToken | SyntaxKind.NewLineTrivia | SyntaxKind.AsteriskToken | SyntaxKind.OpenBraceToken | SyntaxKind.CloseBraceToken | SyntaxKind.LessThanToken | SyntaxKind.OpenBracketToken | SyntaxKind.CloseBracketToken | SyntaxKind.EqualsToken | SyntaxKind.CommaToken | SyntaxKind.DotToken | SyntaxKind.Identifier | SyntaxKind.NoSubstitutionTemplateLiteral | SyntaxKind.Unknown | KeywordSyntaxKind;
type KeywordSyntaxKind = SyntaxKind.AbstractKeyword | SyntaxKind.AnyKeyword | SyntaxKind.AsKeyword | SyntaxKind.BooleanKeyword | SyntaxKind.BreakKeyword | SyntaxKind.CaseKeyword | SyntaxKind.CatchKeyword | SyntaxKind.ClassKeyword | SyntaxKind.ContinueKeyword | SyntaxKind.ConstKeyword | SyntaxKind.ConstructorKeyword | SyntaxKind.DebuggerKeyword | SyntaxKind.DeclareKeyword | SyntaxKind.DefaultKeyword | SyntaxKind.DeleteKeyword | SyntaxKind.DoKeyword | SyntaxKind.ElseKeyword | SyntaxKind.EnumKeyword | SyntaxKind.ExportKeyword | SyntaxKind.ExtendsKeyword | SyntaxKind.FalseKeyword | SyntaxKind.FinallyKeyword | SyntaxKind.ForKeyword | SyntaxKind.FromKeyword | SyntaxKind.FunctionKeyword | SyntaxKind.GetKeyword | SyntaxKind.IfKeyword | SyntaxKind.ImplementsKeyword | SyntaxKind.ImportKeyword | SyntaxKind.InKeyword | SyntaxKind.InferKeyword | SyntaxKind.InstanceOfKeyword | SyntaxKind.InterfaceKeyword | SyntaxKind.IsKeyword | SyntaxKind.KeyOfKeyword | SyntaxKind.LetKeyword | SyntaxKind.ModuleKeyword | SyntaxKind.NamespaceKeyword | SyntaxKind.NeverKeyword | SyntaxKind.NewKeyword | SyntaxKind.NullKeyword | SyntaxKind.NumberKeyword | SyntaxKind.ObjectKeyword | SyntaxKind.PackageKeyword | SyntaxKind.PrivateKeyword | SyntaxKind.ProtectedKeyword | SyntaxKind.PublicKeyword | SyntaxKind.ReadonlyKeyword | SyntaxKind.RequireKeyword | SyntaxKind.GlobalKeyword | SyntaxKind.ReturnKeyword | SyntaxKind.SetKeyword | SyntaxKind.StaticKeyword | SyntaxKind.StringKeyword | SyntaxKind.SuperKeyword | SyntaxKind.SwitchKeyword | SyntaxKind.SymbolKeyword | SyntaxKind.ThisKeyword | SyntaxKind.ThrowKeyword | SyntaxKind.TrueKeyword | SyntaxKind.TryKeyword | SyntaxKind.TypeKeyword | SyntaxKind.TypeOfKeyword | SyntaxKind.UndefinedKeyword | SyntaxKind.UniqueKeyword | SyntaxKind.UnknownKeyword | SyntaxKind.VarKeyword | SyntaxKind.VoidKeyword | SyntaxKind.WhileKeyword | SyntaxKind.WithKeyword | SyntaxKind.YieldKeyword | SyntaxKind.AsyncKeyword | SyntaxKind.AwaitKeyword | SyntaxKind.OfKeyword;
type JsxTokenSyntaxKind = SyntaxKind.LessThanSlashToken | SyntaxKind.EndOfFileToken | SyntaxKind.ConflictMarkerTrivia | SyntaxKind.JsxText | SyntaxKind.JsxTextAllWhiteSpaces | SyntaxKind.OpenBraceToken | SyntaxKind.LessThanToken;
enum SyntaxKind {
Unknown = 0,
@@ -536,6 +537,7 @@ declare namespace ts {
name?: Identifier | StringLiteral | NumericLiteral;
}
interface ComputedPropertyName extends Node {
parent: Declaration;
kind: SyntaxKind.ComputedPropertyName;
expression: Expression;
}
@@ -632,6 +634,7 @@ declare namespace ts {
kind: SyntaxKind.ShorthandPropertyAssignment;
name: Identifier;
questionToken?: QuestionToken;
exclamationToken?: ExclamationToken;
equalsToken?: Token<SyntaxKind.EqualsToken>;
objectAssignmentInitializer?: Expression;
}
@@ -668,6 +671,7 @@ declare namespace ts {
_functionLikeDeclarationBrand: any;
asteriskToken?: AsteriskToken;
questionToken?: QuestionToken;
exclamationToken?: ExclamationToken;
body?: Block | Expression;
}
type FunctionLikeDeclaration = FunctionDeclaration | MethodDeclaration | GetAccessorDeclaration | SetAccessorDeclaration | ConstructorDeclaration | FunctionExpression | ArrowFunction;
@@ -1079,7 +1083,7 @@ declare namespace ts {
}
interface ExpressionWithTypeArguments extends NodeWithTypeArguments {
kind: SyntaxKind.ExpressionWithTypeArguments;
parent: HeritageClause;
parent: HeritageClause | JSDocAugmentsTag;
expression: LeftHandSideExpression;
}
interface NewExpression extends PrimaryExpression, Declaration {
@@ -1808,7 +1812,8 @@ declare namespace ts {
getTypeChecker(): TypeChecker;
isSourceFileFromExternalLibrary(file: SourceFile): boolean;
isSourceFileDefaultLibrary(file: SourceFile): boolean;
getProjectReferences(): (ResolvedProjectReference | undefined)[] | undefined;
getProjectReferences(): ReadonlyArray<ProjectReference> | undefined;
getResolvedProjectReferences(): (ResolvedProjectReference | undefined)[] | undefined;
}
interface ResolvedProjectReference {
commandLine: ParsedCommandLine;
@@ -2056,32 +2061,32 @@ declare namespace ts {
ExportStar = 8388608,
Optional = 16777216,
Transient = 33554432,
JSContainer = 67108864,
Assignment = 67108864,
ModuleExports = 134217728,
Enum = 384,
Variable = 3,
Value = 67216319,
Type = 67901928,
Value = 67220415,
Type = 67897832,
Namespace = 1920,
Module = 1536,
Accessor = 98304,
FunctionScopedVariableExcludes = 67216318,
BlockScopedVariableExcludes = 67216319,
ParameterExcludes = 67216319,
FunctionScopedVariableExcludes = 67220414,
BlockScopedVariableExcludes = 67220415,
ParameterExcludes = 67220415,
PropertyExcludes = 0,
EnumMemberExcludes = 68008959,
FunctionExcludes = 67215791,
FunctionExcludes = 67219887,
ClassExcludes = 68008383,
InterfaceExcludes = 67901832,
InterfaceExcludes = 67897736,
RegularEnumExcludes = 68008191,
ConstEnumExcludes = 68008831,
ValueModuleExcludes = 67215503,
ValueModuleExcludes = 110735,
NamespaceModuleExcludes = 0,
MethodExcludes = 67208127,
GetAccessorExcludes = 67150783,
SetAccessorExcludes = 67183551,
TypeParameterExcludes = 67639784,
TypeAliasExcludes = 67901928,
MethodExcludes = 67212223,
GetAccessorExcludes = 67154879,
SetAccessorExcludes = 67187647,
TypeParameterExcludes = 67635688,
TypeAliasExcludes = 67897832,
AliasExcludes = 2097152,
ModuleMember = 2623475,
ExportHasLocal = 944,
@@ -2490,6 +2495,7 @@ declare namespace ts {
sourceRoot?: string;
strict?: boolean;
strictFunctionTypes?: boolean;
strictBindCallApply?: boolean;
strictNullChecks?: boolean;
strictPropertyInitialization?: boolean;
stripInternal?: boolean;
@@ -2581,7 +2587,6 @@ declare namespace ts {
}
interface ExpandResult {
fileNames: string[];
projectReferences: ReadonlyArray<ProjectReference> | undefined;
wildcardDirectories: MapLike<WatchDirectoryFlags>;
}
interface CreateProgramOptions {
@@ -2592,14 +2597,6 @@ declare namespace ts {
oldProgram?: Program;
configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>;
}
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;
}
interface ModuleResolutionHost {
fileExists(fileName: string): boolean;
readFile(fileName: string): string | undefined;
@@ -2698,9 +2695,6 @@ declare namespace ts {
resolveTypeReferenceDirectives?(typeReferenceDirectiveNames: string[], containingFile: string): ResolvedTypeReferenceDirective[];
getEnvironmentVariable?(name: string): string | undefined;
createHash?(data: string): string;
getModifiedTime?(fileName: string): Date | undefined;
setModifiedTime?(fileName: string, date: Date): void;
deleteFile?(fileName: string): void;
}
interface SourceMapRange extends TextRange {
source?: SourceMapSource;
@@ -3001,6 +2995,16 @@ declare namespace ts {
Parameters = 1296,
IndexSignatureParameters = 4432
}
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;
}
}
declare function setTimeout(handler: (...args: any[]) => void, timeout: number): any;
declare function clearTimeout(handle: any): void;
@@ -3209,17 +3213,27 @@ declare 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.
*/
function getJSDocParameterTags(param: ParameterDeclaration): ReadonlyArray<JSDocParameterTag>;
/**
* 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.
*/
function getJSDocTypeParameterTags(param: TypeParameterDeclaration): ReadonlyArray<JSDocTemplateTag>;
/**
* Return true if the node has JSDoc parameter tags.
*
@@ -4171,14 +4185,15 @@ declare namespace ts {
* @returns A 'Program' object.
*/
function createProgram(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): Program;
interface ResolveProjectReferencePathHost {
/** @deprecated */ interface ResolveProjectReferencePathHost {
fileExists(fileName: string): boolean;
}
/**
* Returns the target config filename of a project reference.
* Note: The file might not exist.
*/
function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName;
function resolveProjectReferencePath(ref: ProjectReference): ResolvedConfigFileName;
/** @deprecated */ function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName;
}
declare namespace ts {
interface EmitOutput {
@@ -4303,32 +4318,43 @@ declare namespace ts {
* Create the builder to manage semantic diagnostics and cache them
*/
function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): SemanticDiagnosticsBuilderProgram;
function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): SemanticDiagnosticsBuilderProgram;
function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): SemanticDiagnosticsBuilderProgram;
/**
* Create the builder that can handle the changes in program and iterate through changed files
* to emit the those files and manage semantic diagnostics cache as well
*/
function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): EmitAndSemanticDiagnosticsBuilderProgram;
function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): EmitAndSemanticDiagnosticsBuilderProgram;
function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): EmitAndSemanticDiagnosticsBuilderProgram;
/**
* Creates a builder thats just abstraction over program and can be used with watch
*/
function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderProgram;
function createAbstractBuilder(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderProgram;
function createAbstractBuilder(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): BuilderProgram;
}
declare namespace ts {
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 */
type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) => T;
interface WatchCompilerHost<T extends BuilderProgram> {
type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference> | undefined) => T;
/** Host that has watch functionality used in --watch mode */
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;
}
interface WatchCompilerHost<T extends BuilderProgram> extends WatchHost {
/**
* Used to create the program when need for program creation or recreation detected
*/
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;
useCaseSensitiveFileNames(): boolean;
getNewLine(): string;
getCurrentDirectory(): string;
@@ -4361,14 +4387,6 @@ declare 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;
}
/**
* Host to create watch with root files and options
@@ -4378,6 +4396,8 @@ declare namespace ts {
rootFiles: string[];
/** Compiler options */
options: CompilerOptions;
/** Project References */
projectReferences?: ReadonlyArray<ProjectReference>;
}
/**
* Host to create watch with config file
@@ -4412,8 +4432,8 @@ declare namespace ts {
/**
* Create the watch compiler host for either configFile or fileNames and its options
*/
function createWatchCompilerHost<T extends BuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfFilesAndCompilerOptions<T>;
function createWatchCompilerHost<T extends BuilderProgram>(configFileName: string, optionsToExtend: CompilerOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfConfigFile<T>;
function createWatchCompilerHost<T extends BuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, projectReferences?: ReadonlyArray<ProjectReference>): WatchCompilerHostOfFilesAndCompilerOptions<T>;
/**
* Creates the watch from the host for root files and compiler options
*/
@@ -4423,184 +4443,11 @@ declare namespace ts {
*/
function createWatchProgram<T extends BuilderProgram>(host: WatchCompilerHostOfConfigFile<T>): WatchOfConfigFile<T>;
}
declare namespace ts {
interface BuildHost {
verbose(diag: DiagnosticMessage, ...args: string[]): void;
error(diag: DiagnosticMessage, ...args: string[]): void;
errorDiagnostic(diag: Diagnostic): void;
message(diag: DiagnosticMessage, ...args: string[]): void;
}
/**
* A BuildContext tracks what's going on during the course of a build.
*
* Callers may invoke any number of build requests within the same context;
* until the context is reset, each project will only be built at most once.
*
* Example: In a standard setup where project B depends on project A, and both are out of date,
* a failed build of A will result in A remaining out of date. When we try to build
* B, we should immediately bail instead of recomputing A's up-to-date status again.
*
* This also matters for performing fast (i.e. fake) downstream builds of projects
* when their upstream .d.ts files haven't changed content (but have newer timestamps)
*/
interface BuildContext {
options: BuildOptions;
/**
* Map from output file name to its pre-build timestamp
*/
unchangedOutputs: FileMap<Date>;
/**
* Map from config file name to up-to-date status
*/
projectStatus: FileMap<UpToDateStatus>;
invalidatedProjects: FileMap<true>;
queuedProjects: FileMap<true>;
missingRoots: Map<true>;
}
type Mapper = ReturnType<typeof createDependencyMapper>;
interface DependencyGraph {
buildQueue: ResolvedConfigFileName[];
dependencyMap: Mapper;
}
interface BuildOptions {
dry: boolean;
force: boolean;
verbose: boolean;
}
enum UpToDateStatusType {
Unbuildable = 0,
UpToDate = 1,
/**
* The project appears out of date because its upstream inputs are newer than its outputs,
* but all of its outputs are actually newer than the previous identical outputs of its (.d.ts) inputs.
* This means we can Pseudo-build (just touch timestamps), as if we had actually built this project.
*/
UpToDateWithUpstreamTypes = 2,
OutputMissing = 3,
OutOfDateWithSelf = 4,
OutOfDateWithUpstream = 5,
UpstreamOutOfDate = 6,
UpstreamBlocked = 7,
/**
* Projects with no outputs (i.e. "solution" files)
*/
ContainerOnly = 8
}
type UpToDateStatus = Status.Unbuildable | Status.UpToDate | Status.OutputMissing | Status.OutOfDateWithSelf | Status.OutOfDateWithUpstream | Status.UpstreamOutOfDate | Status.UpstreamBlocked | Status.ContainerOnly;
namespace Status {
/**
* The project can't be built at all in its current state. For example,
* its config file cannot be parsed, or it has a syntax error or missing file
*/
interface Unbuildable {
type: UpToDateStatusType.Unbuildable;
reason: string;
}
/**
* This project doesn't have any outputs, so "is it up to date" is a meaningless question.
*/
interface ContainerOnly {
type: UpToDateStatusType.ContainerOnly;
}
/**
* The project is up to date with respect to its inputs.
* We track what the newest input file is.
*/
interface UpToDate {
type: UpToDateStatusType.UpToDate | UpToDateStatusType.UpToDateWithUpstreamTypes;
newestInputFileTime?: Date;
newestInputFileName?: string;
newestDeclarationFileContentChangedTime?: Date;
newestOutputFileTime?: Date;
newestOutputFileName?: string;
oldestOutputFileName?: string;
}
/**
* One or more of the outputs of the project does not exist.
*/
interface OutputMissing {
type: UpToDateStatusType.OutputMissing;
/**
* The name of the first output file that didn't exist
*/
missingOutputFileName: string;
}
/**
* One or more of the project's outputs is older than its newest input.
*/
interface OutOfDateWithSelf {
type: UpToDateStatusType.OutOfDateWithSelf;
outOfDateOutputFileName: string;
newerInputFileName: string;
}
/**
* This project depends on an out-of-date project, so shouldn't be built yet
*/
interface UpstreamOutOfDate {
type: UpToDateStatusType.UpstreamOutOfDate;
upstreamProjectName: string;
}
/**
* This project depends an upstream project with build errors
*/
interface UpstreamBlocked {
type: UpToDateStatusType.UpstreamBlocked;
upstreamProjectName: string;
}
/**
* One or more of the project's outputs is older than the newest output of
* an upstream project.
*/
interface OutOfDateWithUpstream {
type: UpToDateStatusType.OutOfDateWithUpstream;
outOfDateOutputFileName: string;
newerProjectName: string;
}
}
interface FileMap<T> {
setValue(fileName: string, value: T): void;
getValue(fileName: string): T | never;
getValueOrUndefined(fileName: string): T | undefined;
hasKey(fileName: string): boolean;
removeKey(fileName: string): void;
getKeys(): string[];
}
function createDependencyMapper(): {
addReference: (childConfigFileName: ResolvedConfigFileName, parentConfigFileName: ResolvedConfigFileName) => void;
getReferencesTo: (parentConfigFileName: ResolvedConfigFileName) => ResolvedConfigFileName[];
getReferencesOf: (childConfigFileName: ResolvedConfigFileName) => ResolvedConfigFileName[];
getKeys: () => ReadonlyArray<ResolvedConfigFileName>;
};
function createBuildContext(options: BuildOptions): BuildContext;
function performBuild(args: string[], compilerHost: CompilerHost, buildHost: BuildHost, system?: System): number | undefined;
/**
* A SolutionBuilder has an immutable set of rootNames that are the "entry point" projects, but
* can dynamically add/remove other projects based on changes on the rootNames' references
*/
function createSolutionBuilder(compilerHost: CompilerHost, buildHost: BuildHost, rootNames: ReadonlyArray<string>, defaultOptions: BuildOptions, system?: System): {
buildAllProjects: () => ExitStatus;
getUpToDateStatus: (project: ParsedCommandLine | undefined) => UpToDateStatus;
getUpToDateStatusOfFile: (configFileName: ResolvedConfigFileName) => UpToDateStatus;
cleanAllProjects: () => ExitStatus.Success | ExitStatus.DiagnosticsPresent_OutputsSkipped;
resetBuildContext: (opts?: BuildOptions) => void;
getBuildGraph: (configFileNames: ReadonlyArray<string>) => DependencyGraph | undefined;
invalidateProject: (configFileName: string) => void;
buildInvalidatedProjects: () => void;
buildDependentInvalidatedProjects: () => void;
resolveProjectName: (name: string) => ResolvedConfigFileName | undefined;
startWatching: () => void;
};
/**
* Gets the UpToDateStatus for a project
*/
function getUpToDateStatus(host: UpToDateHost, project: ParsedCommandLine | undefined): UpToDateStatus;
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 ActionValueInspected = "action::valueInspected";
type EventTypesRegistry = "event::typesRegistry";
type EventBeginInstallTypes = "event::beginInstallTypes";
type EventEndInstallTypes = "event::endInstallTypes";
@@ -4609,7 +4456,7 @@ declare namespace ts.server {
" __sortedArrayBrand": any;
}
interface TypingInstallerResponse {
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | ActionValueInspected | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
}
interface TypingInstallerRequestWithProjectName {
readonly projectName: string;
@@ -4817,14 +4664,7 @@ declare namespace ts {
getCustomTransformers?(): CustomTransformers | undefined;
isKnownTypesPackageName?(name: string): boolean;
installPackage?(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult>;
}
interface UserPreferences {
readonly disableSuggestions?: boolean;
readonly quotePreference?: "double" | "single";
readonly includeCompletionsForModuleExports?: boolean;
readonly includeCompletionsWithInsertText?: boolean;
readonly importModuleSpecifierPreference?: "relative" | "non-relative";
readonly allowTextChangesInNewFiles?: boolean;
writeFile?(fileName: string, content: string): void;
}
interface LanguageService {
cleanupSemanticCache(): void;
@@ -4882,9 +4722,9 @@ declare namespace ts {
toLineColumnOffset?(fileName: string, position: number): LineAndCharacter;
getCodeFixesAtPosition(fileName: string, start: number, end: number, errorCodes: ReadonlyArray<number>, formatOptions: FormatCodeSettings, preferences: UserPreferences): ReadonlyArray<CodeFixAction>;
getCombinedCodeFix(scope: CombinedCodeFixScope, fixId: {}, formatOptions: FormatCodeSettings, preferences: UserPreferences): CombinedCodeActions;
applyCodeActionCommand(action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
applyCodeActionCommand(action: CodeActionCommand[]): Promise<ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[]): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand, formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult>;
applyCodeActionCommand(action: CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult[]>;
applyCodeActionCommand(action: CodeActionCommand | CodeActionCommand[], formatSettings?: FormatCodeSettings): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
/** @deprecated `fileName` will be ignored */
applyCodeActionCommand(fileName: string, action: CodeActionCommand): Promise<ApplyCodeActionCommandResult>;
/** @deprecated `fileName` will be ignored */
@@ -5046,9 +4886,16 @@ declare namespace ts {
changes: ReadonlyArray<FileTextChanges>;
commands?: ReadonlyArray<CodeActionCommand>;
}
type CodeActionCommand = InstallPackageAction;
type CodeActionCommand = InstallPackageAction | GenerateTypesAction;
interface InstallPackageAction {
}
interface GenerateTypesAction extends GenerateTypesOptions {
}
interface GenerateTypesOptions {
readonly file: string;
readonly fileToGenerateTypesFor: string;
readonly outputFileName: string;
}
/**
* A set of one or more available refactoring actions, grouped under a parent refactoring.
*/
@@ -5114,6 +4961,8 @@ declare namespace ts {
originalFileName?: string;
}
interface RenameLocation extends DocumentSpan {
readonly prefixText?: string;
readonly suffixText?: string;
}
interface ReferenceEntry extends DocumentSpan {
isWriteAccess: boolean;
@@ -5266,15 +5115,24 @@ declare namespace ts {
documentation?: SymbolDisplayPart[];
tags?: JSDocTagInfo[];
}
interface RenameInfo {
canRename: boolean;
localizedErrorMessage?: string;
type RenameInfo = RenameInfoSuccess | RenameInfoFailure;
interface RenameInfoSuccess {
canRename: true;
/**
* File or directory to rename.
* If set, `getEditsForFileRename` should be called instead of `findRenameLocations`.
*/
fileToRename?: string;
displayName: string;
fullDisplayName: string;
kind: ScriptElementKind;
kindModifiers: string;
triggerSpan: TextSpan;
}
interface RenameInfoFailure {
canRename: false;
localizedErrorMessage: string;
}
interface SignatureHelpParameter {
name: string;
documentation: SymbolDisplayPart[];
+7227 -4444
View File
File diff suppressed because it is too large Load Diff
+5816 -3855
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -68,7 +68,7 @@
"A_rest_parameter_cannot_have_an_initializer_1048": "rest 参数不能具有初始化表达式。",
"A_rest_parameter_must_be_last_in_a_parameter_list_1014": "rest 参数必须是参数列表中的最后一个参数。",
"A_rest_parameter_must_be_of_an_array_type_2370": "rest 参数必须是数组类型。",
"A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma_1013": "Rest 参数或绑定模式可能不具有尾随逗号。",
"A_rest_parameter_or_binding_pattern_may_not_have_a_trailing_comma_1013": "Rest 参数或绑定模式不可带尾随逗号。",
"A_return_statement_can_only_be_used_within_a_function_body_1108": "\"return\" 语句只能在函数体中使用。",
"A_series_of_entries_which_re_map_imports_to_lookup_locations_relative_to_the_baseUrl_6167": "一系列条目,这些条目将重新映射导入内容,以查找与 \"baseUrl\" 有关的位置。",
"A_set_accessor_cannot_have_a_return_type_annotation_1095": "\"set\" 访问器不能具有返回类型批注。",
@@ -161,7 +161,7 @@
"An_index_signature_parameter_cannot_have_an_accessibility_modifier_1018": "索引签名参数不能具有可访问性修饰符。",
"An_index_signature_parameter_cannot_have_an_initializer_1020": "索引签名参数不能具有初始化表达式。",
"An_index_signature_parameter_must_have_a_type_annotation_1022": "索引签名参数必须具有类型批注。",
"An_index_signature_parameter_type_cannot_be_a_type_alias_Consider_writing_0_Colon_1_Colon_2_instead_1336": "索引签名参数类型不能为类型别名。请考虑改编写“[{0}: {1}]:{2}”。",
"An_index_signature_parameter_type_cannot_be_a_type_alias_Consider_writing_0_Colon_1_Colon_2_instead_1336": "索引签名参数类型不能为类型别名。请考虑改编写“[{0}: {1}]:{2}”。",
"An_index_signature_parameter_type_cannot_be_a_union_type_Consider_using_a_mapped_object_type_instead_1337": "索引签名参数类型不能为联合类型。请考虑改用映射的对象类型。",
"An_index_signature_parameter_type_must_be_string_or_number_1023": "索引签名参数类型必须为 \"string\" 或 \"number\"。",
"An_interface_can_only_extend_an_identifier_Slashqualified_name_with_optional_type_arguments_2499": "接口只能扩展具有可选类型参数的标识符/限定名称。",
@@ -628,7 +628,7 @@
"Option_isolatedModules_can_only_be_used_when_either_option_module_is_provided_or_option_target_is_ES_5047": "选项 \"isolatedModules\" 只可在提供了选项 \"--module\" 或者选项 \"target\" 是 \"ES2015\" 或更高版本时使用。",
"Option_paths_cannot_be_used_without_specifying_baseUrl_option_5060": "在未指定 \"--baseUrl\" 选项的情况下,无法使用选项 \"paths\"。",
"Option_project_cannot_be_mixed_with_source_files_on_a_command_line_5042": "选项 \"project\" 在命令行上不能与源文件混合使用。",
"Option_resolveJsonModule_cannot_be_specified_without_node_module_resolution_strategy_5070": "没有 \"node\" 模块解析策略的情况下,无法指定选项 \"-resolveJsonModule\"。",
"Option_resolveJsonModule_cannot_be_specified_without_node_module_resolution_strategy_5070": "没有 \"node\" 模块解析策略的情况下,无法指定选项 \"-resolveJsonModule\"。",
"Options_0_and_1_cannot_be_combined_6370": "选项“{0}”与“{1}”不能组合在一起。",
"Options_Colon_6027": "选项:",
"Output_directory_for_generated_declaration_files_6166": "已生成声明文件的输出目录。",
+3 -2
View File
@@ -1,8 +1,8 @@
{
"name": "typescript",
"author": "Microsoft Corp.",
"homepage": "http://typescriptlang.org/",
"version": "3.1.0",
"homepage": "https://www.typescriptlang.org/",
"version": "3.2.0",
"license": "Apache-2.0",
"description": "TypeScript is a language for application scale JavaScript development",
"keywords": [
@@ -75,6 +75,7 @@
"gulp-typescript": "latest",
"istanbul": "latest",
"jake": "latest",
"lodash": "4.17.10",
"merge2": "latest",
"minimist": "latest",
"mkdirp": "latest",
+312 -8
View File
@@ -4,7 +4,7 @@ const fs = require("fs");
const log = require("fancy-log"); // was `require("gulp-util").log (see https://github.com/gulpjs/gulp-util)
const ts = require("../../lib/typescript");
const { Duplex } = require("stream");
const chalk = require("./chalk");
const chalk = /**@type {*} */(require("chalk"));
const Vinyl = require("vinyl");
/**
@@ -14,7 +14,7 @@ const Vinyl = require("vinyl");
* @param {UpToDateOptions} [options]
*
* @typedef UpToDateOptions
* @property {boolean} [verbose]
* @property {boolean | "minimal"} [verbose]
* @property {(configFilePath: string) => ParsedCommandLine | undefined} [parseProject]
*/
function upToDate(parsedProject, options) {
@@ -47,9 +47,9 @@ function upToDate(parsedProject, options) {
cb();
},
final(cb) {
const status = ts.getUpToDateStatus(upToDateHost, parsedProject);
const status = getUpToDateStatus(upToDateHost, parsedProject);
reportStatus(parsedProject, status, options);
if (status.type !== ts.UpToDateStatusType.UpToDate) {
if (status.type !== UpToDateStatusType.UpToDate) {
for (const input of inputs) duplex.push(input);
}
duplex.push(null);
@@ -88,11 +88,25 @@ function formatMessage(message, ...args) {
/**
* @param {ParsedCommandLine} project
* @param {UpToDateStatus} status
* @param {{verbose?: boolean}} options
* @param {{verbose?: boolean | "minimal"}} options
*/
function reportStatus(project, status, options) {
switch (options.verbose) {
case "minimal":
switch (status.type) {
case UpToDateStatusType.UpToDate:
log.info(`Project '${fileName(project.options.configFilePath)}' is up to date.`);
break;
default:
log.info(`Project '${fileName(project.options.configFilePath)}' is out of date, rebuilding...`);
break;
}
break;
case true:
/**@type {*}*/(ts).formatUpToDateStatus(project.options.configFilePath, status, fileName, formatMessage);
break;
}
if (!options.verbose) return;
ts.formatUpToDateStatus(project.options.configFilePath, status, fileName, formatMessage);
}
/**
@@ -120,12 +134,302 @@ function formatStringFromArgs(text, args, baseIndex = 0) {
return text.replace(/{(\d+)}/g, (_match, index) => args[+index + baseIndex]);
}
const minimumDate = new Date(-8640000000000000);
const maximumDate = new Date(8640000000000000);
const missingFileModifiedTime = new Date(0);
/**
* @typedef {0} UpToDateStatusType.Unbuildable
* @typedef {1} UpToDateStatusType.UpToDate
* @typedef {2} UpToDateStatusType.UpToDateWithUpstreamTypes
* @typedef {3} UpToDateStatusType.OutputMissing
* @typedef {4} UpToDateStatusType.OutOfDateWithSelf
* @typedef {5} UpToDateStatusType.OutOfDateWithUpstream
* @typedef {6} UpToDateStatusType.UpstreamOutOfDate
* @typedef {7} UpToDateStatusType.UpstreamBlocked
* @typedef {8} UpToDateStatusType.ComputingUpstream
* @typedef {9} UpToDateStatusType.ContainerOnly
* @enum {UpToDateStatusType.Unbuildable | UpToDateStatusType.UpToDate | UpToDateStatusType.UpToDateWithUpstreamTypes | UpToDateStatusType.OutputMissing | UpToDateStatusType.OutOfDateWithSelf | UpToDateStatusType.OutOfDateWithUpstream | UpToDateStatusType.UpstreamOutOfDate | UpToDateStatusType.UpstreamBlocked | UpToDateStatusType.ComputingUpstream | UpToDateStatusType.ContainerOnly}
*/
const UpToDateStatusType = {
Unbuildable: /** @type {0} */(0),
UpToDate: /** @type {1} */(1),
UpToDateWithUpstreamTypes: /** @type {2} */(2),
OutputMissing: /** @type {3} */(3),
OutOfDateWithSelf: /** @type {4} */(4),
OutOfDateWithUpstream: /** @type {5} */(5),
UpstreamOutOfDate: /** @type {6} */(6),
UpstreamBlocked: /** @type {7} */(7),
ComputingUpstream: /** @type {8} */(8),
ContainerOnly: /** @type {9} */(9),
};
/**
* @param {Date} date1
* @param {Date} date2
* @returns {Date}
*/
function newer(date1, date2) {
return date2 > date1 ? date2 : date1;
}
/**
* @param {UpToDateHost} host
* @param {ParsedCommandLine | undefined} project
* @returns {UpToDateStatus}
*/
function getUpToDateStatus(host, project) {
if (project === undefined) return { type: UpToDateStatusType.Unbuildable, reason: "File deleted mid-build" };
const prior = host.getLastStatus ? host.getLastStatus(project.options.configFilePath) : undefined;
if (prior !== undefined) {
return prior;
}
const actual = getUpToDateStatusWorker(host, project);
if (host.setLastStatus) {
host.setLastStatus(project.options.configFilePath, actual);
}
return actual;
}
/**
* @param {UpToDateHost} host
* @param {ParsedCommandLine | undefined} project
* @returns {UpToDateStatus}
*/
function getUpToDateStatusWorker(host, project) {
/** @type {string} */
let newestInputFileName = undefined;
let newestInputFileTime = minimumDate;
// Get timestamps of input files
for (const inputFile of project.fileNames) {
if (!host.fileExists(inputFile)) {
return {
type: UpToDateStatusType.Unbuildable,
reason: `${inputFile} does not exist`
};
}
const inputTime = host.getModifiedTime(inputFile) || missingFileModifiedTime;
if (inputTime > newestInputFileTime) {
newestInputFileName = inputFile;
newestInputFileTime = inputTime;
}
}
// Collect the expected outputs of this project
const outputs = /**@type {string[]}*/(/**@type {*}*/(ts).getAllProjectOutputs(project));
if (outputs.length === 0) {
return {
type: UpToDateStatusType.ContainerOnly
};
}
// Now see if all outputs are newer than the newest input
let oldestOutputFileName = "(none)";
let oldestOutputFileTime = maximumDate;
let newestOutputFileName = "(none)";
let newestOutputFileTime = minimumDate;
/** @type {string | undefined} */
let missingOutputFileName;
let newestDeclarationFileContentChangedTime = minimumDate;
let isOutOfDateWithInputs = false;
for (const output of outputs) {
// Output is missing; can stop checking
// Don't immediately return because we can still be upstream-blocked, which is a higher-priority status
if (!host.fileExists(output)) {
missingOutputFileName = output;
break;
}
const outputTime = host.getModifiedTime(output) || missingFileModifiedTime;
if (outputTime < oldestOutputFileTime) {
oldestOutputFileTime = outputTime;
oldestOutputFileName = output;
}
// If an output is older than the newest input, we can stop checking
// Don't immediately return because we can still be upstream-blocked, which is a higher-priority status
if (outputTime < newestInputFileTime) {
isOutOfDateWithInputs = true;
break;
}
if (outputTime > newestOutputFileTime) {
newestOutputFileTime = outputTime;
newestOutputFileName = output;
}
// Keep track of when the most recent time a .d.ts file was changed.
// In addition to file timestamps, we also keep track of when a .d.ts file
// had its file touched but not had its contents changed - this allows us
// to skip a downstream typecheck
if (path.extname(output) === ".d.ts") {
const unchangedTime = host.getUnchangedTime ? host.getUnchangedTime(output) : undefined;
if (unchangedTime !== undefined) {
newestDeclarationFileContentChangedTime = newer(unchangedTime, newestDeclarationFileContentChangedTime);
}
else {
const outputModifiedTime = host.getModifiedTime(output) || missingFileModifiedTime;
newestDeclarationFileContentChangedTime = newer(newestDeclarationFileContentChangedTime, outputModifiedTime);
}
}
}
let pseudoUpToDate = false;
let usesPrepend = false;
/** @type {string | undefined} */
let upstreamChangedProject;
if (project.projectReferences) {
if (host.setLastStatus) host.setLastStatus(project.options.configFilePath, { type: UpToDateStatusType.ComputingUpstream });
for (const ref of project.projectReferences) {
usesPrepend = usesPrepend || !!(ref.prepend);
const resolvedRef = ts.resolveProjectReferencePath(host, ref);
const parsedRef = host.parseConfigFile ? host.parseConfigFile(resolvedRef) : ts.getParsedCommandLineOfConfigFile(resolvedRef, {}, parseConfigHost);
const refStatus = getUpToDateStatus(host, parsedRef);
// Its a circular reference ignore the status of this project
if (refStatus.type === UpToDateStatusType.ComputingUpstream) {
continue;
}
// An upstream project is blocked
if (refStatus.type === UpToDateStatusType.Unbuildable) {
return {
type: UpToDateStatusType.UpstreamBlocked,
upstreamProjectName: ref.path
};
}
// If the upstream project is out of date, then so are we (someone shouldn't have asked, though?)
if (refStatus.type !== UpToDateStatusType.UpToDate) {
return {
type: UpToDateStatusType.UpstreamOutOfDate,
upstreamProjectName: ref.path
};
}
// If the upstream project's newest file is older than our oldest output, we
// can't be out of date because of it
if (refStatus.newestInputFileTime && refStatus.newestInputFileTime <= oldestOutputFileTime) {
continue;
}
// If the upstream project has only change .d.ts files, and we've built
// *after* those files, then we're "psuedo up to date" and eligible for a fast rebuild
if (refStatus.newestDeclarationFileContentChangedTime && refStatus.newestDeclarationFileContentChangedTime <= oldestOutputFileTime) {
pseudoUpToDate = true;
upstreamChangedProject = ref.path;
continue;
}
// We have an output older than an upstream output - we are out of date
return {
type: UpToDateStatusType.OutOfDateWithUpstream,
outOfDateOutputFileName: oldestOutputFileName,
newerProjectName: ref.path
};
}
}
if (missingOutputFileName !== undefined) {
return {
type: UpToDateStatusType.OutputMissing,
missingOutputFileName
};
}
if (isOutOfDateWithInputs) {
return {
type: UpToDateStatusType.OutOfDateWithSelf,
outOfDateOutputFileName: oldestOutputFileName,
newerInputFileName: newestInputFileName
};
}
if (usesPrepend && pseudoUpToDate) {
return {
type: UpToDateStatusType.OutOfDateWithUpstream,
outOfDateOutputFileName: oldestOutputFileName,
newerProjectName: upstreamChangedProject
};
}
// Up to date
return {
type: pseudoUpToDate ? UpToDateStatusType.UpToDateWithUpstreamTypes : UpToDateStatusType.UpToDate,
newestDeclarationFileContentChangedTime,
newestInputFileTime,
newestOutputFileTime,
newestInputFileName,
newestOutputFileName,
oldestOutputFileName
};
}
const parseConfigHost = {
useCaseSensitiveFileNames: true,
getCurrentDirectory: () => process.cwd(),
readDirectory: (file) => fs.readdirSync(file),
fileExists: file => fs.existsSync(file) && fs.statSync(file).isFile(),
readFile: file => fs.readFileSync(file, "utf8"),
onUnRecoverableConfigFileDiagnostic: () => undefined
};
/**
* @typedef {import("vinyl")} File
* @typedef {import("../../lib/typescript").ParsedCommandLine & { options: CompilerOptions }} ParsedCommandLine
* @typedef {import("../../lib/typescript").CompilerOptions & { configFilePath?: string }} CompilerOptions
* @typedef {import("../../lib/typescript").UpToDateHost} UpToDateHost
* @typedef {import("../../lib/typescript").UpToDateStatus} UpToDateStatus
* @typedef {import("../../lib/typescript").DiagnosticMessage} DiagnosticMessage
* @typedef UpToDateHost
* @property {(fileName: string) => boolean} fileExists
* @property {(fileName: string) => Date} getModifiedTime
* @property {(fileName: string) => Date} [getUnchangedTime]
* @property {(configFilePath: string) => ParsedCommandLine | undefined} parseConfigFile
* @property {(configFilePath: string) => UpToDateStatus} [getLastStatus]
* @property {(configFilePath: string, status: UpToDateStatus) => void} [setLastStatus]
*
* @typedef Status.Unbuildable
* @property {UpToDateStatusType.Unbuildable} type
* @property {string} reason
*
* @typedef Status.ContainerOnly
* @property {UpToDateStatusType.ContainerOnly} type
*
* @typedef Status.UpToDate
* @property {UpToDateStatusType.UpToDate | UpToDateStatusType.UpToDateWithUpstreamTypes} type
* @property {Date} [newestInputFileTime]
* @property {string} [newestInputFileName]
* @property {Date} [newestDeclarationFileContentChangedTime]
* @property {Date} [newestOutputFileTime]
* @property {string} [newestOutputFileName]
* @property {string} [oldestOutputFileName]
*
* @typedef Status.OutputMissing
* @property {UpToDateStatusType.OutputMissing} type
* @property {string} missingOutputFileName
*
* @typedef Status.OutOfDateWithSelf
* @property {UpToDateStatusType.OutOfDateWithSelf} type
* @property {string} outOfDateOutputFileName
* @property {string} newerInputFileName
*
* @typedef Status.UpstreamOutOfDate
* @property {UpToDateStatusType.UpstreamOutOfDate} type
* @property {string} upstreamProjectName
*
* @typedef Status.UpstreamBlocked
* @property {UpToDateStatusType.UpstreamBlocked} type
* @property {string} upstreamProjectName
*
* @typedef Status.ComputingUpstream
* @property {UpToDateStatusType.ComputingUpstream} type
*
* @typedef Status.OutOfDateWithUpstream
* @property {UpToDateStatusType.OutOfDateWithUpstream} type
* @property {string} outOfDateOutputFileName
* @property {string} newerProjectName
* @typedef {Status.Unbuildable | Status.ContainerOnly | Status.UpToDate | Status.OutputMissing | Status.OutOfDateWithSelf | Status.UpstreamOutOfDate | Status.UpstreamBlocked | Status.ComputingUpstream | Status.OutOfDateWithUpstream} UpToDateStatus
*/
void 0;
+91 -83
View File
@@ -234,13 +234,17 @@ 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 and assignment declarations
symbol.valueDeclaration = node;
}
setValueDeclaration(symbol, node);
}
}
function setValueDeclaration(symbol: Symbol, node: Declaration): void {
const { valueDeclaration } = symbol;
if (!valueDeclaration ||
(isAssignmentDeclaration(valueDeclaration) && !isAssignmentDeclaration(node)) ||
(valueDeclaration.kind !== node.kind && isEffectiveModuleDeclaration(valueDeclaration))) {
// other kinds of value declarations take precedence over modules and assignment declarations
symbol.valueDeclaration = node;
}
}
@@ -288,7 +292,7 @@ namespace ts {
// module.exports = ...
return InternalSymbolName.ExportEquals;
case SyntaxKind.BinaryExpression:
if (getSpecialPropertyAssignmentKind(node as BinaryExpression) === SpecialPropertyAssignmentKind.ModuleExports) {
if (getAssignmentDeclarationKind(node as BinaryExpression) === AssignmentDeclarationKind.ModuleExports) {
// module.exports = ...
return InternalSymbolName.ExportEquals;
}
@@ -374,8 +378,8 @@ namespace ts {
// prototype symbols like methods.
symbolTable.set(name, symbol = createSymbol(SymbolFlags.None, name));
}
else if (!(includes & SymbolFlags.Variable && symbol.flags & SymbolFlags.JSContainer)) {
// JSContainers are allowed to merge with variables, no matter what other flags they have.
else if (!(includes & SymbolFlags.Variable && symbol.flags & SymbolFlags.Assignment)) {
// Assignment declarations are allowed to merge with variables, no matter what other flags they have.
if (isNamedDeclaration(node)) {
node.name.parent = node;
}
@@ -461,7 +465,7 @@ namespace ts {
// during global merging in the checker. Why? The only case when ambient module is permitted inside another module is module augmentation
// and this case is specially handled. Module augmentations should only be merged with original module definition
// and should never be merged directly with other augmentation, and the latter case would be possible if automatic merge is allowed.
if (isJSDocTypeAlias(node)) Debug.assert(isInJavaScriptFile(node)); // We shouldn't add symbols for JSDoc nodes if not in a JS file.
if (isJSDocTypeAlias(node)) Debug.assert(isInJSFile(node)); // We shouldn't add symbols for JSDoc nodes if not in a JS file.
if ((!isAmbientModule(node) && (hasExportModifier || container.flags & NodeFlags.ExportContext)) || isJSDocTypeAlias(node)) {
if (hasModifier(node, ModifierFlags.Default) && !getDeclarationName(node)) {
return declareSymbol(container.symbol.exports!, container.symbol, node, symbolFlags, symbolExcludes); // No local symbol for an unnamed default!
@@ -636,6 +640,7 @@ namespace ts {
function bindChildrenWorker(node: Node): void {
if (checkUnreachable(node)) {
bindEachChild(node);
bindJSDoc(node);
return;
}
switch (node.kind) {
@@ -1176,7 +1181,6 @@ namespace ts {
}
const preCaseLabel = createBranchLabel();
addAntecedent(preCaseLabel, createFlowSwitchClause(preSwitchCaseFlow!, node.parent, clauseStart, i + 1));
addAntecedent(preCaseLabel, createFlowSwitchClause(preSwitchCaseFlow!, node.parent, clauseStart, i + 1));
addAntecedent(preCaseLabel, fallthroughFlow);
currentFlow = finishFlowLabel(preCaseLabel);
const clause = clauses[i];
@@ -2009,7 +2013,7 @@ namespace ts {
function bindJSDoc(node: Node) {
if (hasJSDocNodes(node)) {
if (isInJavaScriptFile(node)) {
if (isInJSFile(node)) {
for (const j of node.jsDoc!) {
bind(j);
}
@@ -2075,7 +2079,7 @@ namespace ts {
if (isSpecialPropertyDeclaration(node as PropertyAccessExpression)) {
bindSpecialPropertyDeclaration(node as PropertyAccessExpression);
}
if (isInJavaScriptFile(node) &&
if (isInJSFile(node) &&
file.commonJsModuleIndicator &&
isModuleExportsPropertyAccessExpression(node as PropertyAccessExpression) &&
!lookupSymbolForNameWorker(blockScopeContainer, "module" as __String)) {
@@ -2084,27 +2088,27 @@ namespace ts {
}
break;
case SyntaxKind.BinaryExpression:
const specialKind = getSpecialPropertyAssignmentKind(node as BinaryExpression);
const specialKind = getAssignmentDeclarationKind(node as BinaryExpression);
switch (specialKind) {
case SpecialPropertyAssignmentKind.ExportsProperty:
case AssignmentDeclarationKind.ExportsProperty:
bindExportsPropertyAssignment(node as BinaryExpression);
break;
case SpecialPropertyAssignmentKind.ModuleExports:
case AssignmentDeclarationKind.ModuleExports:
bindModuleExportsAssignment(node as BinaryExpression);
break;
case SpecialPropertyAssignmentKind.PrototypeProperty:
case AssignmentDeclarationKind.PrototypeProperty:
bindPrototypePropertyAssignment((node as BinaryExpression).left as PropertyAccessEntityNameExpression, node);
break;
case SpecialPropertyAssignmentKind.Prototype:
case AssignmentDeclarationKind.Prototype:
bindPrototypeAssignment(node as BinaryExpression);
break;
case SpecialPropertyAssignmentKind.ThisProperty:
case AssignmentDeclarationKind.ThisProperty:
bindThisPropertyAssignment(node as BinaryExpression);
break;
case SpecialPropertyAssignmentKind.Property:
case AssignmentDeclarationKind.Property:
bindSpecialPropertyAssignment(node as BinaryExpression);
break;
case SpecialPropertyAssignmentKind.None:
case AssignmentDeclarationKind.None:
// Nothing to do
break;
default:
@@ -2184,7 +2188,7 @@ namespace ts {
return bindFunctionExpression(<FunctionExpression>node);
case SyntaxKind.CallExpression:
if (isInJavaScriptFile(node)) {
if (isInJSFile(node)) {
bindCallExpression(<CallExpression>node);
}
break;
@@ -2286,14 +2290,19 @@ namespace ts {
bindAnonymousDeclaration(node, SymbolFlags.Alias, getDeclarationName(node)!);
}
else {
const flags = node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(node)
const flags = exportAssignmentIsAlias(node)
// An export default clause with an EntityNameExpression or a class expression exports all meanings of that identifier or expression;
? SymbolFlags.Alias
// An export default clause with any other expression exports a value
: SymbolFlags.Property;
// If there is an `export default x;` alias declaration, can't `export default` anything else.
// (In contrast, you can still have `export default function f() {}` and `export default interface I {}`.)
declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.All);
const symbol = declareSymbol(container.symbol.exports, container.symbol, node, flags, SymbolFlags.All);
if (node.isExportEquals) {
// Will be an error later, since the module already has other exports. Just make sure this has a valueDeclaration set.
setValueDeclaration(symbol, node);
}
}
}
@@ -2301,27 +2310,17 @@ namespace ts {
if (node.modifiers && node.modifiers.length) {
file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Modifiers_cannot_appear_here));
}
if (node.parent.kind !== SyntaxKind.SourceFile) {
file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Global_module_exports_may_only_appear_at_top_level));
return;
const diag = !isSourceFile(node.parent) ? Diagnostics.Global_module_exports_may_only_appear_at_top_level
: !isExternalModule(node.parent) ? Diagnostics.Global_module_exports_may_only_appear_in_module_files
: !node.parent.isDeclarationFile ? Diagnostics.Global_module_exports_may_only_appear_in_declaration_files
: undefined;
if (diag) {
file.bindDiagnostics.push(createDiagnosticForNode(node, diag));
}
else {
const parent = node.parent as SourceFile;
if (!isExternalModule(parent)) {
file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Global_module_exports_may_only_appear_in_module_files));
return;
}
if (!parent.isDeclarationFile) {
file.bindDiagnostics.push(createDiagnosticForNode(node, Diagnostics.Global_module_exports_may_only_appear_in_declaration_files));
return;
}
file.symbol.globalExports = file.symbol.globalExports || createSymbolTable();
declareSymbol(file.symbol.globalExports, file.symbol, node, SymbolFlags.Alias, SymbolFlags.AliasExcludes);
}
file.symbol.globalExports = file.symbol.globalExports || createSymbolTable();
declareSymbol(file.symbol.globalExports, file.symbol, node, SymbolFlags.Alias, SymbolFlags.AliasExcludes);
}
function bindExportDeclaration(node: ExportDeclaration) {
@@ -2361,7 +2360,7 @@ namespace ts {
const lhs = node.left as PropertyAccessEntityNameExpression;
const symbol = forEachIdentifierInEntityName(lhs.expression, /*parent*/ undefined, (id, symbol) => {
if (symbol) {
addDeclarationToSymbol(symbol, id, SymbolFlags.Module | SymbolFlags.JSContainer);
addDeclarationToSymbol(symbol, id, SymbolFlags.Module | SymbolFlags.Assignment);
}
return symbol;
});
@@ -2394,7 +2393,7 @@ namespace ts {
}
function bindThisPropertyAssignment(node: BinaryExpression | PropertyAccessExpression) {
Debug.assert(isInJavaScriptFile(node));
Debug.assert(isInJSFile(node));
const thisContainer = getThisContainer(node, /*includeArrowFunctions*/ false);
switch (thisContainer.kind) {
case SyntaxKind.FunctionDeclaration:
@@ -2456,7 +2455,7 @@ namespace ts {
node.left.parent = node;
node.right.parent = node;
const lhs = node.left as PropertyAccessEntityNameExpression;
bindPropertyAssignment(lhs, lhs, /*isPrototypeProperty*/ false);
bindPropertyAssignment(lhs.expression, lhs, /*isPrototypeProperty*/ false);
}
/**
@@ -2482,7 +2481,7 @@ namespace ts {
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)) {
if (!isInJSFile(node) && !isFunctionSymbol(parentSymbol)) {
return;
}
// Fix up parent pointers since we're going to use these nodes before we bind into them
@@ -2513,21 +2512,23 @@ namespace ts {
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)) && isToplevel) {
if (isToplevel && !isPrototypeProperty && (!namespaceSymbol || !(namespaceSymbol.flags & SymbolFlags.Namespace))) {
// make symbols or add declarations for intermediate containers
const flags = SymbolFlags.Module | SymbolFlags.JSContainer;
const excludeFlags = SymbolFlags.ValueModuleExcludes & ~SymbolFlags.JSContainer;
const flags = SymbolFlags.Module | SymbolFlags.Assignment;
const excludeFlags = SymbolFlags.ValueModuleExcludes & ~SymbolFlags.Assignment;
namespaceSymbol = forEachIdentifierInEntityName(propertyAccess.expression, namespaceSymbol, (id, symbol, parent) => {
if (symbol) {
addDeclarationToSymbol(symbol, id, flags);
return symbol;
}
else {
return declareSymbol(parent ? parent.exports! : container.locals!, parent, id, flags, excludeFlags);
const table = parent ? parent.exports! :
file.jsGlobalAugmentations || (file.jsGlobalAugmentations = createSymbolTable());
return declareSymbol(table, parent, id, flags, excludeFlags);
}
});
}
if (!namespaceSymbol || !isJavascriptContainer(namespaceSymbol)) {
if (!namespaceSymbol || !isExpandoSymbol(namespaceSymbol)) {
return;
}
@@ -2536,14 +2537,14 @@ namespace ts {
(namespaceSymbol.members || (namespaceSymbol.members = createSymbolTable())) :
(namespaceSymbol.exports || (namespaceSymbol.exports = createSymbolTable()));
const isMethod = isFunctionLikeDeclaration(getAssignedJavascriptInitializer(propertyAccess)!);
const isMethod = isFunctionLikeDeclaration(getAssignedExpandoInitializer(propertyAccess)!);
const includes = isMethod ? SymbolFlags.Method : SymbolFlags.Property;
const excludes = isMethod ? SymbolFlags.MethodExcludes : SymbolFlags.PropertyExcludes;
declareSymbol(symbolTable, namespaceSymbol, propertyAccess, includes | SymbolFlags.JSContainer, excludes & ~SymbolFlags.JSContainer);
declareSymbol(symbolTable, namespaceSymbol, propertyAccess, includes | SymbolFlags.Assignment, excludes & ~SymbolFlags.Assignment);
}
/**
* Javascript containers are:
* Javascript expando values are:
* - Functions
* - classes
* - namespaces
@@ -2552,7 +2553,7 @@ namespace ts {
* - with empty object literals
* - with non-empty object literals if assigned to the prototype property
*/
function isJavascriptContainer(symbol: Symbol): boolean {
function isExpandoSymbol(symbol: Symbol): boolean {
if (symbol.flags & (SymbolFlags.Function | SymbolFlags.Class | SymbolFlags.NamespaceModule)) {
return true;
}
@@ -2565,7 +2566,7 @@ namespace ts {
init = init && getRightMostAssignedExpression(init);
if (init) {
const isPrototypeAssignment = isPrototypeAccess(isVariableDeclaration(node) ? node.name : isBinaryExpression(node) ? node.left : node);
return !!getJavascriptInitializer(isBinaryExpression(init) && init.operatorToken.kind === SyntaxKind.BarBarToken ? init.right : init, isPrototypeAssignment);
return !!getExpandoInitializer(isBinaryExpression(init) && init.operatorToken.kind === SyntaxKind.BarBarToken ? init.right : init, isPrototypeAssignment);
}
return false;
}
@@ -2657,7 +2658,7 @@ namespace ts {
}
if (!isBindingPattern(node.name)) {
const isEnum = !!getJSDocEnumTag(node);
const isEnum = isInJSFile(node) && !!getJSDocEnumTag(node);
const enumFlags = (isEnum ? SymbolFlags.RegularEnum : SymbolFlags.None);
const enumExcludes = (isEnum ? SymbolFlags.RegularEnumExcludes : SymbolFlags.None);
if (isBlockOrCatchScoped(node)) {
@@ -2892,6 +2893,9 @@ namespace ts {
if (local) {
return local.exportSymbol || local;
}
if (isSourceFile(container) && container.jsGlobalAugmentations && container.jsGlobalAugmentations.has(name)) {
return container.jsGlobalAugmentations.get(name);
}
return container.symbol && container.symbol.exports && container.symbol.exports.get(name);
}
@@ -2996,7 +3000,7 @@ namespace ts {
transformFlags |= TransformFlags.AssertTypeScript;
}
if (subtreeFlags & TransformFlags.ContainsSpread
if (subtreeFlags & TransformFlags.ContainsRestOrSpread
|| (expression.transformFlags & (TransformFlags.Super | TransformFlags.ContainsSuper))) {
// If the this node contains a SpreadExpression, or is a super call, then it is an ES6
// node.
@@ -3027,7 +3031,7 @@ namespace ts {
if (node.typeArguments) {
transformFlags |= TransformFlags.AssertTypeScript;
}
if (subtreeFlags & TransformFlags.ContainsSpread) {
if (subtreeFlags & TransformFlags.ContainsRestOrSpread) {
// If the this node contains a SpreadElementExpression then it is an ES6
// node.
transformFlags |= TransformFlags.AssertES2015;
@@ -3070,18 +3074,18 @@ namespace ts {
// syntax.
if (node.questionToken
|| node.type
|| subtreeFlags & TransformFlags.ContainsDecorators
|| (subtreeFlags & TransformFlags.ContainsTypeScriptClassSyntax && some(node.decorators))
|| isThisIdentifier(name)) {
transformFlags |= TransformFlags.AssertTypeScript;
}
// If a parameter has an accessibility modifier, then it is TypeScript syntax.
if (hasModifier(node, ModifierFlags.ParameterPropertyModifier)) {
transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsParameterPropertyAssignments;
transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsTypeScriptClassSyntax;
}
// parameters with object rest destructuring are ES Next syntax
if (subtreeFlags & TransformFlags.ContainsObjectRest) {
if (subtreeFlags & TransformFlags.ContainsObjectRestOrSpread) {
transformFlags |= TransformFlags.AssertESNext;
}
@@ -3134,7 +3138,7 @@ namespace ts {
// TypeScript syntax.
// An exported declaration may be TypeScript syntax, but is handled by the visitor
// for a namespace declaration.
if ((subtreeFlags & TransformFlags.TypeScriptClassSyntaxMask)
if ((subtreeFlags & TransformFlags.ContainsTypeScriptClassSyntax)
|| node.typeParameters) {
transformFlags |= TransformFlags.AssertTypeScript;
}
@@ -3156,7 +3160,7 @@ namespace ts {
// A class with a parameter property assignment, property initializer, or decorator is
// TypeScript syntax.
if (subtreeFlags & TransformFlags.TypeScriptClassSyntaxMask
if (subtreeFlags & TransformFlags.ContainsTypeScriptClassSyntax
|| node.typeParameters) {
transformFlags |= TransformFlags.AssertTypeScript;
}
@@ -3233,7 +3237,7 @@ namespace ts {
}
// function declarations with object rest destructuring are ES Next syntax
if (subtreeFlags & TransformFlags.ContainsObjectRest) {
if (subtreeFlags & TransformFlags.ContainsObjectRestOrSpread) {
transformFlags |= TransformFlags.AssertESNext;
}
@@ -3257,7 +3261,7 @@ namespace ts {
}
// function declarations with object rest destructuring are ES Next syntax
if (subtreeFlags & TransformFlags.ContainsObjectRest) {
if (subtreeFlags & TransformFlags.ContainsObjectRestOrSpread) {
transformFlags |= TransformFlags.AssertESNext;
}
@@ -3288,7 +3292,7 @@ namespace ts {
}
// function declarations with object rest destructuring are ES Next syntax
if (subtreeFlags & TransformFlags.ContainsObjectRest) {
if (subtreeFlags & TransformFlags.ContainsObjectRestOrSpread) {
transformFlags |= TransformFlags.AssertESNext;
}
@@ -3303,7 +3307,7 @@ namespace ts {
// If the PropertyDeclaration has an initializer or a computed name, we need to inform its ancestor
// so that it handle the transformation.
if (node.initializer || isComputedPropertyName(node.name)) {
transformFlags |= TransformFlags.ContainsPropertyInitializer;
transformFlags |= TransformFlags.ContainsTypeScriptClassSyntax;
}
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
@@ -3337,7 +3341,7 @@ namespace ts {
}
// function declarations with object rest destructuring are ES Next syntax
if (subtreeFlags & TransformFlags.ContainsObjectRest) {
if (subtreeFlags & TransformFlags.ContainsObjectRestOrSpread) {
transformFlags |= TransformFlags.AssertESNext;
}
@@ -3379,7 +3383,7 @@ namespace ts {
}
// function expressions with object rest destructuring are ES Next syntax
if (subtreeFlags & TransformFlags.ContainsObjectRest) {
if (subtreeFlags & TransformFlags.ContainsObjectRestOrSpread) {
transformFlags |= TransformFlags.AssertESNext;
}
@@ -3420,7 +3424,7 @@ namespace ts {
}
// arrow functions with object rest destructuring are ES Next syntax
if (subtreeFlags & TransformFlags.ContainsObjectRest) {
if (subtreeFlags & TransformFlags.ContainsObjectRestOrSpread) {
transformFlags |= TransformFlags.AssertESNext;
}
@@ -3440,7 +3444,9 @@ namespace ts {
// ES6 syntax, and requires a lexical `this` binding.
if (transformFlags & TransformFlags.Super) {
transformFlags ^= TransformFlags.Super;
transformFlags |= TransformFlags.ContainsSuper;
// super inside of an async function requires hoisting the super access (ES2017).
// same for super inside of an async generator, which is ESNext.
transformFlags |= TransformFlags.ContainsSuper | TransformFlags.ContainsES2017 | TransformFlags.ContainsESNext;
}
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
@@ -3456,7 +3462,9 @@ namespace ts {
// ES6 syntax, and requires a lexical `this` binding.
if (expressionFlags & TransformFlags.Super) {
transformFlags &= ~TransformFlags.Super;
transformFlags |= TransformFlags.ContainsSuper;
// super inside of an async function requires hoisting the super access (ES2017).
// same for super inside of an async generator, which is ESNext.
transformFlags |= TransformFlags.ContainsSuper | TransformFlags.ContainsES2017 | TransformFlags.ContainsESNext;
}
node.transformFlags = transformFlags | TransformFlags.HasComputedFlags;
@@ -3468,7 +3476,7 @@ namespace ts {
transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern;
// A VariableDeclaration containing ObjectRest is ESNext syntax
if (subtreeFlags & TransformFlags.ContainsObjectRest) {
if (subtreeFlags & TransformFlags.ContainsObjectRestOrSpread) {
transformFlags |= TransformFlags.AssertESNext;
}
@@ -3717,11 +3725,11 @@ namespace ts {
break;
case SyntaxKind.SpreadElement:
transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsSpread;
transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsRestOrSpread;
break;
case SyntaxKind.SpreadAssignment:
transformFlags |= TransformFlags.AssertESNext | TransformFlags.ContainsObjectSpread;
transformFlags |= TransformFlags.AssertESNext | TransformFlags.ContainsObjectRestOrSpread;
break;
case SyntaxKind.SuperKeyword:
@@ -3737,8 +3745,8 @@ namespace ts {
case SyntaxKind.ObjectBindingPattern:
transformFlags |= TransformFlags.AssertES2015 | TransformFlags.ContainsBindingPattern;
if (subtreeFlags & TransformFlags.ContainsRest) {
transformFlags |= TransformFlags.AssertESNext | TransformFlags.ContainsObjectRest;
if (subtreeFlags & TransformFlags.ContainsRestOrSpread) {
transformFlags |= TransformFlags.AssertESNext | TransformFlags.ContainsObjectRestOrSpread;
}
excludeFlags = TransformFlags.BindingPatternExcludes;
break;
@@ -3751,13 +3759,13 @@ namespace ts {
case SyntaxKind.BindingElement:
transformFlags |= TransformFlags.AssertES2015;
if ((<BindingElement>node).dotDotDotToken) {
transformFlags |= TransformFlags.ContainsRest;
transformFlags |= TransformFlags.ContainsRestOrSpread;
}
break;
case SyntaxKind.Decorator:
// This node is TypeScript syntax, and marks its container as also being TypeScript syntax.
transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsDecorators;
transformFlags |= TransformFlags.AssertTypeScript | TransformFlags.ContainsTypeScriptClassSyntax;
break;
case SyntaxKind.ObjectLiteralExpression:
@@ -3774,7 +3782,7 @@ namespace ts {
transformFlags |= TransformFlags.ContainsLexicalThis;
}
if (subtreeFlags & TransformFlags.ContainsObjectSpread) {
if (subtreeFlags & TransformFlags.ContainsObjectRestOrSpread) {
// If an ObjectLiteralExpression contains a spread element, then it
// is an ES next node.
transformFlags |= TransformFlags.AssertESNext;
@@ -3785,7 +3793,7 @@ namespace ts {
case SyntaxKind.ArrayLiteralExpression:
case SyntaxKind.NewExpression:
excludeFlags = TransformFlags.ArrayLiteralOrCallOrNewExcludes;
if (subtreeFlags & TransformFlags.ContainsSpread) {
if (subtreeFlags & TransformFlags.ContainsRestOrSpread) {
// If the this node contains a SpreadExpression, then it is an ES6
// node.
transformFlags |= TransformFlags.AssertES2015;
+18 -11
View File
@@ -294,7 +294,7 @@ namespace ts {
configFileParsingDiagnostics: ReadonlyArray<Diagnostic>;
}
export function getBuilderCreationParameters(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: BuilderProgram | CompilerHost, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderCreationParameters {
export function getBuilderCreationParameters(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: BuilderProgram | CompilerHost, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): BuilderCreationParameters {
let host: BuilderProgramHost;
let newProgram: Program;
let oldProgram: BuilderProgram;
@@ -307,7 +307,14 @@ namespace ts {
}
else if (isArray(newProgramOrRootNames)) {
oldProgram = configFileParsingDiagnosticsOrOldProgram as BuilderProgram;
newProgram = createProgram(newProgramOrRootNames, hostOrOptions as CompilerOptions, oldProgramOrHost as CompilerHost, oldProgram && oldProgram.getProgram(), configFileParsingDiagnostics);
newProgram = createProgram({
rootNames: newProgramOrRootNames,
options: hostOrOptions as CompilerOptions,
host: oldProgramOrHost as CompilerHost,
oldProgram: oldProgram && oldProgram.getProgram(),
configFileParsingDiagnostics,
projectReferences
});
host = oldProgramOrHost as CompilerHost;
}
else {
@@ -623,9 +630,9 @@ namespace ts {
* Create the builder to manage semantic diagnostics and cache them
*/
export function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): SemanticDiagnosticsBuilderProgram;
export function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): SemanticDiagnosticsBuilderProgram;
export function createSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
return createBuilderProgram(BuilderProgramKind.SemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics));
export function createSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): SemanticDiagnosticsBuilderProgram;
export function createSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>) {
return createBuilderProgram(BuilderProgramKind.SemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences));
}
/**
@@ -633,18 +640,18 @@ namespace ts {
* to emit the those files and manage semantic diagnostics cache as well
*/
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): EmitAndSemanticDiagnosticsBuilderProgram;
export function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): EmitAndSemanticDiagnosticsBuilderProgram;
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>) {
return createBuilderProgram(BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics));
export function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): EmitAndSemanticDiagnosticsBuilderProgram;
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>) {
return createBuilderProgram(BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences));
}
/**
* Creates a builder thats just abstraction over program and can be used with watch
*/
export function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderProgram;
export function createAbstractBuilder(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderProgram;
export function createAbstractBuilder(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | BuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): BuilderProgram {
const { newProgram: program } = getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics);
export function createAbstractBuilder(rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): BuilderProgram;
export function createAbstractBuilder(newProgramOrRootNames: Program | ReadonlyArray<string> | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | BuilderProgram, configFileParsingDiagnosticsOrOldProgram?: ReadonlyArray<Diagnostic> | BuilderProgram, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference>): BuilderProgram {
const { newProgram: program } = getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences);
return {
// Only return program, all other methods are not implemented
getProgram: () => program,
+41 -3
View File
@@ -88,7 +88,7 @@ namespace ts.BuilderState {
function getReferencedFileFromImportedModuleSymbol(symbol: Symbol) {
if (symbol.declarations && symbol.declarations[0]) {
const declarationSourceFile = getSourceFileOfNode(symbol.declarations[0]);
return declarationSourceFile && declarationSourceFile.path;
return declarationSourceFile && declarationSourceFile.resolvedPath;
}
}
@@ -100,6 +100,13 @@ namespace ts.BuilderState {
return symbol && getReferencedFileFromImportedModuleSymbol(symbol);
}
/**
* Gets the path to reference file from file name, it could be resolvedPath if present otherwise path
*/
function getReferencedFileFromFileName(program: Program, fileName: string, sourceFileDirectory: Path, getCanonicalFileName: GetCanonicalFileName): Path {
return toPath(program.getProjectReferenceRedirect(fileName) || fileName, sourceFileDirectory, getCanonicalFileName);
}
/**
* Gets the referenced files for a file from the program with values for the keys as referenced file's path to be true
*/
@@ -123,7 +130,7 @@ namespace ts.BuilderState {
// Handle triple slash references
if (sourceFile.referencedFiles && sourceFile.referencedFiles.length > 0) {
for (const referencedFile of sourceFile.referencedFiles) {
const referencedPath = toPath(referencedFile.fileName, sourceFileDirectory, getCanonicalFileName);
const referencedPath = getReferencedFileFromFileName(program, referencedFile.fileName, sourceFileDirectory, getCanonicalFileName);
addReferencedFile(referencedPath);
}
}
@@ -136,13 +143,44 @@ namespace ts.BuilderState {
}
const fileName = resolvedTypeReferenceDirective.resolvedFileName!; // TODO: GH#18217
const typeFilePath = toPath(fileName, sourceFileDirectory, getCanonicalFileName);
const typeFilePath = getReferencedFileFromFileName(program, fileName, sourceFileDirectory, getCanonicalFileName);
addReferencedFile(typeFilePath);
});
}
// Add module augmentation as references
if (sourceFile.moduleAugmentations.length) {
const checker = program.getTypeChecker();
for (const moduleName of sourceFile.moduleAugmentations) {
if (!isStringLiteral(moduleName)) { continue; }
const symbol = checker.getSymbolAtLocation(moduleName);
if (!symbol) { continue; }
// Add any file other than our own as reference
addReferenceFromAmbientModule(symbol);
}
}
// From ambient modules
for (const ambientModule of program.getTypeChecker().getAmbientModules()) {
if (ambientModule.declarations.length > 1) {
addReferenceFromAmbientModule(ambientModule);
}
}
return referencedFiles;
function addReferenceFromAmbientModule(symbol: Symbol) {
// Add any file other than our own as reference
for (const declaration of symbol.declarations) {
const declarationSourceFile = getSourceFileOfNode(declaration);
if (declarationSourceFile &&
declarationSourceFile !== sourceFile) {
addReferencedFile(declarationSourceFile.resolvedPath);
}
}
}
function addReferencedFile(referencedPath: Path) {
if (!referencedFiles) {
referencedFiles = createMap<true>();
+1311 -1182
View File
File diff suppressed because it is too large Load Diff
+191 -94
View File
@@ -62,7 +62,8 @@ namespace ts {
/* @internal */
export const libMap = createMapFromEntries(libEntries);
const commonOptionsWithBuild: CommandLineOption[] = [
/* @internal */
export const commonOptionsWithBuild: CommandLineOption[] = [
{
name: "help",
shortName: "h",
@@ -76,6 +77,14 @@ namespace ts {
shortName: "?",
type: "boolean"
},
{
name: "watch",
shortName: "w",
type: "boolean",
showInSimplifiedHelpView: true,
category: Diagnostics.Command_line_Options,
description: Diagnostics.Watch_input_files,
},
{
name: "preserveWatchOutput",
type: "boolean",
@@ -84,12 +93,23 @@ namespace ts {
description: Diagnostics.Whether_to_keep_outdated_console_output_in_watch_mode_instead_of_clearing_the_screen,
},
{
name: "watch",
shortName: "w",
name: "listFiles",
type: "boolean",
showInSimplifiedHelpView: true,
category: Diagnostics.Command_line_Options,
description: Diagnostics.Watch_input_files,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Print_names_of_files_part_of_the_compilation
},
{
name: "listEmittedFiles",
type: "boolean",
category: Diagnostics.Advanced_Options,
description: Diagnostics.Print_names_of_generated_files_part_of_the_compilation
},
{
name: "traceResolution",
type: "boolean",
category: Diagnostics.Advanced_Options,
description: Diagnostics.Enable_tracing_of_the_name_resolution_process
},
];
@@ -159,6 +179,8 @@ namespace ts {
es2018: ScriptTarget.ES2018,
esnext: ScriptTarget.ESNext,
}),
affectsSourceFile: true,
affectsModuleResolution: true,
paramType: Diagnostics.VERSION,
showInSimplifiedHelpView: true,
category: Diagnostics.Basic_Options,
@@ -177,6 +199,7 @@ namespace ts {
es2015: ModuleKind.ES2015,
esnext: ModuleKind.ESNext
}),
affectsModuleResolution: true,
paramType: Diagnostics.KIND,
showInSimplifiedHelpView: true,
category: Diagnostics.Basic_Options,
@@ -189,6 +212,7 @@ namespace ts {
name: "lib",
type: libMap
},
affectsModuleResolution: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Basic_Options,
description: Diagnostics.Specify_library_files_to_be_included_in_the_compilation
@@ -196,6 +220,7 @@ namespace ts {
{
name: "allowJs",
type: "boolean",
affectsModuleResolution: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Basic_Options,
description: Diagnostics.Allow_javascript_files_to_be_compiled
@@ -213,6 +238,7 @@ namespace ts {
"react-native": JsxEmit.ReactNative,
"react": JsxEmit.React
}),
affectsSourceFile: true,
paramType: Diagnostics.KIND,
showInSimplifiedHelpView: true,
category: Diagnostics.Basic_Options,
@@ -323,6 +349,7 @@ namespace ts {
{
name: "noImplicitAny",
type: "boolean",
affectsSemanticDiagnostics: true,
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
@@ -331,6 +358,7 @@ namespace ts {
{
name: "strictNullChecks",
type: "boolean",
affectsSemanticDiagnostics: true,
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
@@ -339,14 +367,24 @@ namespace ts {
{
name: "strictFunctionTypes",
type: "boolean",
affectsSemanticDiagnostics: true,
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
description: Diagnostics.Enable_strict_checking_of_function_types
},
{
name: "strictBindCallApply",
type: "boolean",
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
description: Diagnostics.Enable_strict_bind_call_and_apply_methods_on_functions
},
{
name: "strictPropertyInitialization",
type: "boolean",
affectsSemanticDiagnostics: true,
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
@@ -355,6 +393,7 @@ namespace ts {
{
name: "noImplicitThis",
type: "boolean",
affectsSemanticDiagnostics: true,
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
@@ -363,6 +402,7 @@ namespace ts {
{
name: "alwaysStrict",
type: "boolean",
affectsSourceFile: true,
strictFlag: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Strict_Type_Checking_Options,
@@ -397,6 +437,7 @@ namespace ts {
{
name: "noFallthroughCasesInSwitch",
type: "boolean",
affectsBindDiagnostics: true,
affectsSemanticDiagnostics: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Additional_Checks,
@@ -410,6 +451,7 @@ namespace ts {
node: ModuleResolutionKind.NodeJs,
classic: ModuleResolutionKind.Classic,
}),
affectsModuleResolution: true,
paramType: Diagnostics.STRATEGY,
category: Diagnostics.Module_Resolution_Options,
description: Diagnostics.Specify_module_resolution_strategy_Colon_node_Node_js_or_classic_TypeScript_pre_1_6,
@@ -417,6 +459,7 @@ namespace ts {
{
name: "baseUrl",
type: "string",
affectsModuleResolution: true,
isFilePath: true,
category: Diagnostics.Module_Resolution_Options,
description: Diagnostics.Base_directory_to_resolve_non_absolute_module_names
@@ -426,6 +469,7 @@ namespace ts {
// use type = object to copy the value as-is
name: "paths",
type: "object",
affectsModuleResolution: true,
isTSConfigOnly: true,
category: Diagnostics.Module_Resolution_Options,
description: Diagnostics.A_series_of_entries_which_re_map_imports_to_lookup_locations_relative_to_the_baseUrl
@@ -441,6 +485,7 @@ namespace ts {
type: "string",
isFilePath: true
},
affectsModuleResolution: true,
category: Diagnostics.Module_Resolution_Options,
description: Diagnostics.List_of_root_folders_whose_combined_content_represents_the_structure_of_the_project_at_runtime
},
@@ -452,6 +497,7 @@ namespace ts {
type: "string",
isFilePath: true
},
affectsModuleResolution: true,
category: Diagnostics.Module_Resolution_Options,
description: Diagnostics.List_of_folders_to_include_type_definitions_from
},
@@ -462,6 +508,7 @@ namespace ts {
name: "types",
type: "string"
},
affectsModuleResolution: true,
showInSimplifiedHelpView: true,
category: Diagnostics.Module_Resolution_Options,
description: Diagnostics.Type_declaration_files_to_be_included_in_compilation
@@ -549,30 +596,12 @@ namespace ts {
category: Diagnostics.Advanced_Options,
description: Diagnostics.Show_verbose_diagnostic_information
},
{
name: "traceResolution",
type: "boolean",
category: Diagnostics.Advanced_Options,
description: Diagnostics.Enable_tracing_of_the_name_resolution_process
},
{
name: "resolveJsonModule",
type: "boolean",
category: Diagnostics.Advanced_Options,
description: Diagnostics.Include_modules_imported_with_json_extension
},
{
name: "listFiles",
type: "boolean",
category: Diagnostics.Advanced_Options,
description: Diagnostics.Print_names_of_files_part_of_the_compilation
},
{
name: "listEmittedFiles",
type: "boolean",
category: Diagnostics.Advanced_Options,
description: Diagnostics.Print_names_of_generated_files_part_of_the_compilation
},
{
name: "out",
@@ -632,12 +661,14 @@ namespace ts {
{
name: "noLib",
type: "boolean",
affectsModuleResolution: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Do_not_include_the_default_library_file_lib_d_ts
},
{
name: "noResolve",
type: "boolean",
affectsModuleResolution: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Do_not_add_triple_slash_references_or_imported_modules_to_the_list_of_compiled_files
},
@@ -650,6 +681,7 @@ namespace ts {
{
name: "disableSizeLimit",
type: "boolean",
affectsSourceFile: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Disable_size_limitations_on_JavaScript_projects
},
@@ -695,6 +727,7 @@ namespace ts {
{
name: "allowUnusedLabels",
type: "boolean",
affectsBindDiagnostics: true,
affectsSemanticDiagnostics: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Do_not_report_errors_on_unused_labels
@@ -702,6 +735,7 @@ namespace ts {
{
name: "allowUnreachableCode",
type: "boolean",
affectsBindDiagnostics: true,
affectsSemanticDiagnostics: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.Do_not_report_errors_on_unreachable_code
@@ -729,6 +763,7 @@ namespace ts {
{
name: "maxNodeModuleJsDepth",
type: "number",
// TODO: GH#27108 affectsModuleResolution: true,
category: Diagnostics.Advanced_Options,
description: Diagnostics.The_maximum_dependency_depth_to_search_under_node_modules_and_load_JavaScript_files
},
@@ -758,6 +793,18 @@ namespace ts {
}
];
/* @internal */
export const semanticDiagnosticsOptionDeclarations: ReadonlyArray<CommandLineOption> =
optionDeclarations.filter(option => !!option.affectsSemanticDiagnostics);
/* @internal */
export const moduleResolutionOptionDeclarations: ReadonlyArray<CommandLineOption> =
optionDeclarations.filter(option => !!option.affectsModuleResolution);
/* @internal */
export const sourceFileAffectingCompilerOptions: ReadonlyArray<CommandLineOption> = optionDeclarations.filter(option =>
!!option.affectsSourceFile || !!option.affectsModuleResolution || !!option.affectsBindDiagnostics);
/* @internal */
export const buildOpts: CommandLineOption[] = [
...commonOptionsWithBuild,
@@ -903,17 +950,27 @@ namespace ts {
}
}
export function parseCommandLine(commandLine: ReadonlyArray<string>, readFile?: (path: string) => string | undefined): ParsedCommandLine {
const options: CompilerOptions = {};
/* @internal */
export interface OptionsBase {
[option: string]: CompilerOptionsValue | undefined;
}
/** Tuple with error messages for 'unknown compiler option', 'option requires type' */
type ParseCommandLineWorkerDiagnostics = [DiagnosticMessage, DiagnosticMessage];
function parseCommandLineWorker(
getOptionNameMap: () => OptionNameMap,
[unknownOptionDiagnostic, optionTypeMismatchDiagnostic]: ParseCommandLineWorkerDiagnostics,
commandLine: ReadonlyArray<string>,
readFile?: (path: string) => string | undefined) {
const options = {} as OptionsBase;
const fileNames: string[] = [];
const projectReferences: ProjectReference[] | undefined = undefined;
const errors: Diagnostic[] = [];
parseStrings(commandLine);
return {
options,
fileNames,
projectReferences,
errors
};
@@ -926,7 +983,7 @@ namespace ts {
parseResponseFile(s.slice(1));
}
else if (s.charCodeAt(0) === CharacterCodes.minus) {
const opt = getOptionFromName(s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true);
const opt = getOptionDeclarationFromName(getOptionNameMap, s.slice(s.charCodeAt(1) === CharacterCodes.minus ? 2 : 1), /*allowShort*/ true);
if (opt) {
if (opt.isTSConfigOnly) {
errors.push(createCompilerDiagnostic(Diagnostics.Option_0_can_only_be_specified_in_tsconfig_json_file, opt.name));
@@ -934,7 +991,7 @@ namespace ts {
else {
// Check to see if no argument was provided (e.g. "--locale" is the last command-line argument).
if (!args[i] && opt.type !== "boolean") {
errors.push(createCompilerDiagnostic(Diagnostics.Compiler_option_0_expects_an_argument, opt.name));
errors.push(createCompilerDiagnostic(optionTypeMismatchDiagnostic, opt.name));
}
switch (opt.type) {
@@ -956,7 +1013,7 @@ namespace ts {
i++;
break;
case "list":
const result = parseListTypeOption(<CommandLineOptionOfListType>opt, args[i], errors);
const result = parseListTypeOption(opt, args[i], errors);
options[opt.name] = result || [];
if (result) {
i++;
@@ -971,7 +1028,7 @@ namespace ts {
}
}
else {
errors.push(createCompilerDiagnostic(Diagnostics.Unknown_compiler_option_0, s));
errors.push(createCompilerDiagnostic(unknownOptionDiagnostic, s));
}
}
else {
@@ -1014,13 +1071,19 @@ namespace ts {
}
}
export function parseCommandLine(commandLine: ReadonlyArray<string>, readFile?: (path: string) => string | undefined): ParsedCommandLine {
return parseCommandLineWorker(getOptionNameMap, [
Diagnostics.Unknown_compiler_option_0,
Diagnostics.Compiler_option_0_expects_an_argument
], commandLine, readFile);
}
/** @internal */
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 {
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.
@@ -1044,25 +1107,11 @@ namespace ts {
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);
}
}
const { options, fileNames: projects, errors } = parseCommandLineWorker(returnBuildOptionNameMap, [
Diagnostics.Unknown_build_option_0,
Diagnostics.Build_option_0_requires_a_value_of_type_1
], args);
const buildOptions = options as BuildOptions;
if (projects.length === 0) {
// tsc -b invoked with no extra arguments; act as if invoked with "tsc -b ."
@@ -1071,19 +1120,19 @@ namespace ts {
// Nonsensical combinations
if (buildOptions.clean && buildOptions.force) {
(errors || (errors = [])).push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "clean", "force"));
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"));
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"));
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"));
errors.push(createCompilerDiagnostic(Diagnostics.Options_0_and_1_cannot_be_combined, "watch", "dry"));
}
return { buildOptions, projects, errors: errors || emptyArray };
return { buildOptions, projects, errors };
}
function getDiagnosticText(_message: DiagnosticMessage, ..._args: any[]): string {
@@ -1480,7 +1529,12 @@ namespace ts {
elements: NodeArray<Expression>,
elementOption: CommandLineOption | undefined
): any[] | void {
return (returnValue ? elements.map : elements.forEach).call(elements, (element: Expression) => convertPropertyValueToJson(element, elementOption));
if (!returnValue) {
return elements.forEach(element => convertPropertyValueToJson(element, elementOption));
}
// Filter out invalid values
return filter(elements.map(element => convertPropertyValueToJson(element, elementOption)), v => v !== undefined);
}
function convertPropertyValueToJson(valueExpression: Expression, option: CommandLineOption | undefined): any {
@@ -1613,7 +1667,7 @@ namespace ts {
return undefined;
}
else if (optionDefinition.type === "list") {
return getCustomTypeMapOfCommandLineOption((<CommandLineOptionOfListType>optionDefinition).element);
return getCustomTypeMapOfCommandLineOption(optionDefinition.element);
}
else {
return (<CommandLineOptionOfCustomType>optionDefinition).type;
@@ -1677,7 +1731,7 @@ namespace ts {
case "object":
return {};
default:
return (option as CommandLineOptionOfCustomType).type.keys().next().value;
return option.type.keys().next().value;
}
}
@@ -1825,7 +1879,8 @@ namespace ts {
const options = extend(existingOptions, parsedConfig.options || {});
options.configFilePath = configFileName && normalizeSlashes(configFileName);
setConfigFileInOptions(options, sourceFile);
const { fileNames, wildcardDirectories, spec, projectReferences } = getFileNames();
let projectReferences: ProjectReference[] | undefined;
const { fileNames, wildcardDirectories, spec } = getFileNames();
return {
options,
fileNames,
@@ -1843,8 +1898,22 @@ namespace ts {
if (hasProperty(raw, "files") && !isNullOrUndefined(raw.files)) {
if (isArray(raw.files)) {
filesSpecs = <ReadonlyArray<string>>raw.files;
if (filesSpecs.length === 0) {
createCompilerDiagnosticOnlyIfJson(Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json");
const hasReferences = hasProperty(raw, "references") && !isNullOrUndefined(raw.references);
const hasZeroOrNoReferences = !hasReferences || raw.references.length === 0;
const hasExtends = hasProperty(raw, "extends");
if (filesSpecs.length === 0 && hasZeroOrNoReferences && !hasExtends) {
if (sourceFile) {
const fileName = configFileName || "tsconfig.json";
const diagnosticMessage = Diagnostics.The_files_list_in_config_file_0_is_empty;
const nodeValue = firstDefined(getTsConfigPropArray(sourceFile, "files"), property => property.initializer);
const error = nodeValue
? createDiagnosticForNodeInSourceFile(sourceFile, nodeValue, diagnosticMessage, fileName)
: createCompilerDiagnostic(diagnosticMessage, fileName);
errors.push(error);
}
else {
createCompilerDiagnosticOnlyIfJson(Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json");
}
}
}
else {
@@ -1885,19 +1954,18 @@ namespace ts {
}
const result = matchFileNames(filesSpecs, includeSpecs, excludeSpecs, configFileName ? directoryOfCombinedPath(configFileName, basePath) : basePath, options, host, errors, extraFileExtensions, sourceFile);
if (result.fileNames.length === 0 && !hasProperty(raw, "files") && resolutionStack.length === 0 && !hasProperty(raw, "references")) {
if (shouldReportNoInputFiles(result, canJsonReportNoInutFiles(raw), resolutionStack)) {
errors.push(getErrorForNoInputFiles(result.spec, configFileName));
}
if (hasProperty(raw, "references") && !isNullOrUndefined(raw.references)) {
if (isArray(raw.references)) {
const references: ProjectReference[] = [];
for (const ref of raw.references) {
if (typeof ref.path !== "string") {
createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "reference.path", "string");
}
else {
references.push({
(projectReferences || (projectReferences = [])).push({
path: getNormalizedAbsolutePath(ref.path, basePath),
originalPath: ref.path,
prepend: ref.prepend,
@@ -1905,7 +1973,6 @@ namespace ts {
});
}
}
result.projectReferences = references;
}
else {
createCompilerDiagnosticOnlyIfJson(Diagnostics.Compiler_option_0_requires_a_value_of_type_1, "references", "Array");
@@ -1922,13 +1989,11 @@ namespace ts {
}
}
/*@internal*/
export function isErrorNoInputFiles(error: Diagnostic) {
function isErrorNoInputFiles(error: Diagnostic) {
return error.code === Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2.code;
}
/*@internal*/
export function getErrorForNoInputFiles({ includeSpecs, excludeSpecs }: ConfigFileSpecs, configFileName: string | undefined) {
function getErrorForNoInputFiles({ includeSpecs, excludeSpecs }: ConfigFileSpecs, configFileName: string | undefined) {
return createCompilerDiagnostic(
Diagnostics.No_inputs_were_found_in_config_file_0_Specified_include_paths_were_1_and_exclude_paths_were_2,
configFileName || "tsconfig.json",
@@ -1936,6 +2001,27 @@ namespace ts {
JSON.stringify(excludeSpecs || []));
}
function shouldReportNoInputFiles(result: ExpandResult, canJsonReportNoInutFiles: boolean, resolutionStack?: Path[]) {
return result.fileNames.length === 0 && canJsonReportNoInutFiles && (!resolutionStack || resolutionStack.length === 0);
}
/*@internal*/
export function canJsonReportNoInutFiles(raw: any) {
return !hasProperty(raw, "files") && !hasProperty(raw, "references");
}
/*@internal*/
export function updateErrorForNoInputFiles(result: ExpandResult, configFileName: string, configFileSpecs: ConfigFileSpecs, configParseDiagnostics: Diagnostic[], canJsonReportNoInutFiles: boolean) {
const existingErrors = configParseDiagnostics.length;
if (shouldReportNoInputFiles(result, canJsonReportNoInutFiles)) {
configParseDiagnostics.push(getErrorForNoInputFiles(configFileSpecs, configFileName));
}
else {
filterMutate(configParseDiagnostics, error => !isErrorNoInputFiles(error));
}
return existingErrors !== configParseDiagnostics.length;
}
interface ParsedTsconfig {
raw: any;
options?: CompilerOptions;
@@ -1978,7 +2064,7 @@ namespace ts {
if (ownConfig.extendedConfigPath) {
// copy the resolution stack so it is never reused between branches in potential diamond-problem scenarios.
resolutionStack = resolutionStack.concat([resolvedPath]);
const extendedConfig = getExtendedConfig(sourceFile!, ownConfig.extendedConfigPath, host, basePath, resolutionStack, errors);
const extendedConfig = getExtendedConfig(sourceFile, ownConfig.extendedConfigPath, host, basePath, resolutionStack, errors);
if (extendedConfig && isSuccessfulParsedTsconfig(extendedConfig)) {
const baseRaw = extendedConfig.raw;
const raw = ownConfig.raw;
@@ -2067,11 +2153,6 @@ namespace ts {
createDiagnosticForNodeInSourceFile(sourceFile, valueNode, message, arg0)
);
return;
case "files":
if ((<ReadonlyArray<string>>value).length === 0) {
errors.push(createDiagnosticForNodeInSourceFile(sourceFile, valueNode, Diagnostics.The_files_list_in_config_file_0_is_empty, configFileName || "tsconfig.json"));
}
return;
}
},
onSetUnknownOptionKeyValueInRoot(key: string, keyNode: PropertyName, _value: CompilerOptionsValue, _valueNode: Expression) {
@@ -2081,6 +2162,7 @@ namespace ts {
}
};
const json = convertToObjectWorker(sourceFile, errors, /*returnValue*/ true, getTsconfigRootOptionsMap(), optionsIterator);
if (!typeAcquisition) {
if (typingOptionstypeAcquisition) {
typeAcquisition = (typingOptionstypeAcquisition.enableAutoDiscovery !== undefined) ?
@@ -2123,7 +2205,7 @@ namespace ts {
}
function getExtendedConfig(
sourceFile: TsConfigSourceFile,
sourceFile: TsConfigSourceFile | undefined,
extendedConfigPath: string,
host: ParseConfigHost,
basePath: string,
@@ -2132,7 +2214,7 @@ namespace ts {
): ParsedTsconfig | undefined {
const extendedResult = readJsonConfigFile(extendedConfigPath, path => host.readFile(path));
if (sourceFile) {
(sourceFile.extendedSourceFiles || (sourceFile.extendedSourceFiles = [])).push(extendedResult.fileName);
sourceFile.extendedSourceFiles = [extendedResult.fileName];
}
if (extendedResult.parseDiagnostics.length) {
errors.push(...extendedResult.parseDiagnostics);
@@ -2142,8 +2224,8 @@ namespace ts {
const extendedDirname = getDirectoryPath(extendedConfigPath);
const extendedConfig = parseConfig(/*json*/ undefined, extendedResult, host, extendedDirname,
getBaseFileName(extendedConfigPath), resolutionStack, errors);
if (sourceFile) {
sourceFile.extendedSourceFiles!.push(...extendedResult.extendedSourceFiles!);
if (sourceFile && extendedResult.extendedSourceFiles) {
sourceFile.extendedSourceFiles!.push(...extendedResult.extendedSourceFiles);
}
if (isSuccessfulParsedTsconfig(extendedConfig)) {
@@ -2256,7 +2338,7 @@ namespace ts {
function normalizeOptionValue(option: CommandLineOption, basePath: string, value: any): CompilerOptionsValue {
if (isNullOrUndefined(value)) return undefined;
if (option.type === "list") {
const listOption = <CommandLineOptionOfListType>option;
const listOption = option;
if (listOption.element.isFilePath || !isString(listOption.element.type)) {
return <CompilerOptionsValue>filter(map(value, v => normalizeOptionValue(listOption.element, basePath, v)), v => !!v);
}
@@ -2398,7 +2480,7 @@ namespace ts {
// new entries in these paths.
const wildcardDirectories = getWildcardDirectories(validatedIncludeSpecs, validatedExcludeSpecs, basePath, host.useCaseSensitiveFileNames);
const spec: ConfigFileSpecs = { filesSpecs, referencesSpecs: undefined, includeSpecs, excludeSpecs, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories };
const spec: ConfigFileSpecs = { filesSpecs, includeSpecs, excludeSpecs, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories };
return getFileNamesFromConfigSpecs(spec, basePath, options, host, extraFileExtensions);
}
@@ -2427,11 +2509,16 @@ namespace ts {
// via wildcard, and to handle extension priority.
const wildcardFileMap = createMap<string>();
// Wildcard paths of json files (provided via the "includes" array in tsconfig.json) are stored in a
// file map with a possibly case insensitive key. We use this map to store paths matched
// via wildcard of *.json kind
const wildCardJsonFileMap = createMap<string>();
const { filesSpecs, validatedIncludeSpecs, validatedExcludeSpecs, wildcardDirectories } = spec;
// Rather than requery this for each file and filespec, we query the supported extensions
// once and store it on the expansion context.
const supportedExtensions = getSupportedExtensions(options, extraFileExtensions);
const supportedExtensionsWithJsonIfResolveJsonModule = getSuppoertedExtensionsWithJsonIfResolveJsonModule(options, supportedExtensions);
// Literal files are always included verbatim. An "include" or "exclude" specification cannot
// remove a literal file.
@@ -2442,8 +2529,25 @@ namespace ts {
}
}
let jsonOnlyIncludeRegexes: ReadonlyArray<RegExp> | undefined;
if (validatedIncludeSpecs && validatedIncludeSpecs.length > 0) {
for (const file of host.readDirectory(basePath, supportedExtensions, validatedExcludeSpecs, validatedIncludeSpecs, /*depth*/ undefined)) {
for (const file of host.readDirectory(basePath, supportedExtensionsWithJsonIfResolveJsonModule, validatedExcludeSpecs, validatedIncludeSpecs, /*depth*/ undefined)) {
if (fileExtensionIs(file, Extension.Json)) {
// Valid only if *.json specified
if (!jsonOnlyIncludeRegexes) {
const includes = validatedIncludeSpecs.filter(s => endsWith(s, Extension.Json));
const includeFilePatterns = map(getRegularExpressionsForWildcards(includes, basePath, "files"), pattern => `^${pattern}$`);
jsonOnlyIncludeRegexes = includeFilePatterns ? includeFilePatterns.map(pattern => getRegexFromPattern(pattern, host.useCaseSensitiveFileNames)) : emptyArray;
}
const includeIndex = findIndex(jsonOnlyIncludeRegexes, re => re.test(file));
if (includeIndex !== -1) {
const key = keyMapper(file);
if (!literalFileMap.has(key) && !wildCardJsonFileMap.has(key)) {
wildCardJsonFileMap.set(key, file);
}
}
continue;
}
// If we have already included a literal or wildcard path with a
// higher priority extension, we should skip this file.
//
@@ -2469,16 +2573,9 @@ namespace ts {
const literalFiles = arrayFrom(literalFileMap.values());
const wildcardFiles = arrayFrom(wildcardFileMap.values());
const projectReferences = spec.referencesSpecs && spec.referencesSpecs.map((r): ProjectReference => {
return {
...r,
path: getNormalizedAbsolutePath(r.path, basePath)
};
});
return {
fileNames: literalFiles.concat(wildcardFiles),
projectReferences,
fileNames: literalFiles.concat(wildcardFiles, arrayFrom(wildCardJsonFileMap.values())),
wildcardDirectories,
spec
};
@@ -2648,7 +2745,7 @@ namespace ts {
case "boolean":
return typeof value === "boolean" ? value : "";
case "list":
const elementType = (option as CommandLineOptionOfListType).element;
const elementType = option.element;
return isArray(value) ? value.map(v => getOptionValueWithEmptyStrings(v, elementType)) : "";
default:
return forEachEntry(option.type, (optionEnumValue, optionStringValue) => {
+2 -2
View File
@@ -220,7 +220,7 @@ namespace ts {
}
if (extendedDiagnostics) {
performance.mark("beginEmitBodyWithDetachedCommetns");
performance.mark("beginEmitBodyWithDetachedComments");
}
if (!skipTrailingComments) {
@@ -231,7 +231,7 @@ namespace ts {
}
if (extendedDiagnostics) {
performance.measure("commentTime", "beginEmitBodyWithDetachedCommetns");
performance.measure("commentTime", "beginEmitBodyWithDetachedComments");
}
}
+16 -6
View File
@@ -1,7 +1,7 @@
namespace ts {
// WARNING: The script `configureNightly.ts` uses a regexp to parse out these values.
// If changing the text in this section, be sure to test `configureNightly` too.
export const versionMajorMinor = "3.1";
export const versionMajorMinor = "3.2";
/** The version of the TypeScript compiler release */
export const version = `${versionMajorMinor}.0-dev`;
}
@@ -65,6 +65,7 @@ namespace ts {
/* @internal */
namespace ts {
export const emptyArray: never[] = [] as never[];
/** Create a MapLike with good performance. */
function createDictionaryObject<T>(): MapLike<T> {
@@ -841,7 +842,7 @@ namespace ts {
return deduplicateSorted(sort(array, comparer), equalityComparer || comparer);
}
export function arrayIsEqualTo<T>(array1: ReadonlyArray<T> | undefined, array2: ReadonlyArray<T> | undefined, equalityComparer: (a: T, b: T) => boolean = equateValues): boolean {
export function arrayIsEqualTo<T>(array1: ReadonlyArray<T> | undefined, array2: ReadonlyArray<T> | undefined, equalityComparer: (a: T, b: T, index: number) => boolean = equateValues): boolean {
if (!array1 || !array2) {
return array1 === array2;
}
@@ -851,7 +852,7 @@ namespace ts {
}
for (let i = 0; i < array1.length; i++) {
if (!equalityComparer(array1[i], array2[i])) {
if (!equalityComparer(array1[i], array2[i], i)) {
return false;
}
}
@@ -1408,9 +1409,12 @@ namespace ts {
/**
* Tests whether a value is string
*/
export function isString(text: any): text is string {
export function isString(text: unknown): text is string {
return typeof text === "string";
}
export function isNumber(x: unknown): x is number {
return typeof x === "number";
}
export function tryCast<TOut extends TIn, TIn = any>(value: TIn | undefined, test: (value: TIn) => value is TOut): TOut | undefined;
export function tryCast<T>(value: T, test: (value: T) => boolean): T | undefined;
@@ -1533,6 +1537,7 @@ namespace ts {
* Every function should be assignable to this, but this should not be assignable to every function.
*/
export type AnyFunction = (...args: never[]) => void;
export type AnyConstructor = new (...args: unknown[]) => unknown;
export namespace Debug {
export let currentAssertionLevel = AssertionLevel.None;
@@ -1597,8 +1602,9 @@ namespace ts {
return value;
}
export function assertNever(member: never, message?: string, stackCrawlMark?: AnyFunction): never {
return fail(message || `Illegal value: ${member}`, stackCrawlMark || assertNever);
export function assertNever(member: never, message = "Illegal value:", stackCrawlMark?: AnyFunction): never {
const detail = "kind" in member && "pos" in member ? "SyntaxKind: " + showSyntaxKind(member as Node) : JSON.stringify(member);
return fail(`${message} ${detail}`, stackCrawlMark || assertNever);
}
export function getFunctionName(func: AnyFunction) {
@@ -2124,4 +2130,8 @@ namespace ts {
deleted(oldItems[oldIndex++]);
}
}
export function fill<T>(length: number, cb: (index: number) => T): T[] {
return new Array(length).fill(0).map((_, i) => cb(i));
}
}
+96 -13
View File
@@ -2088,6 +2088,38 @@
"category": "Error",
"code": 2577
},
"Cannot find name '{0}'. Do you need to install type definitions for node? Try `npm i @types/node`.": {
"category": "Error",
"code": 2580
},
"Cannot find name '{0}'. Do you need to install type definitions for jQuery? Try `npm i @types/jquery`.": {
"category": "Error",
"code": 2581
},
"Cannot find name '{0}'. Do you need to install type definitions for a test runner? Try `npm i @types/jest` or `npm i @types/mocha`.": {
"category": "Error",
"code": 2582
},
"Cannot find name '{0}'. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.": {
"category": "Error",
"code": 2583
},
"Cannot find name '{0}'. Do you need to change your target library? Try changing the `lib` compiler option to include 'dom'.": {
"category": "Error",
"code": 2584
},
"'{0}' only refers to a type, but is being used as a value here. Do you need to change your target library? Try changing the `lib` compiler option to es2015 or later.": {
"category": "Error",
"code": 2585
},
"Enum type '{0}' circularly references itself.": {
"category": "Error",
"code": 2586
},
"JSDoc type '{0}' circularly references itself.": {
"category": "Error",
"code": 2587
},
"JSX element attributes type '{0}' may not be a union type.": {
"category": "Error",
"code": 2600
@@ -2453,9 +2485,9 @@
"category": "Error",
"code": 2732
},
"Index '{0}' is out-of-bounds in tuple of length {1}.": {
"It is highly likely that you are missing a semicolon.": {
"category": "Error",
"code": 2733
"code": 2734
},
"Import declaration '{0}' is using private name '{1}'.": {
@@ -2920,7 +2952,10 @@
"category": "Error",
"code": 5072
},
"Build option '{0}' requires a value of type {1}.": {
"category": "Error",
"code": 5073
},
"Generates a sourcemap for each corresponding '.d.ts' file.": {
"category": "Message",
@@ -3294,7 +3329,7 @@
"category": "Message",
"code": 6104
},
"Expected type of '{0}' field in 'package.json' to be 'string', got '{1}'.": {
"Expected type of '{0}' field in 'package.json' to be '{1}', got '{2}'.": {
"category": "Message",
"code": 6105
},
@@ -3692,6 +3727,42 @@
"category": "Error",
"code": 6205
},
"'package.json' has a 'typesVersions' field with version-specific path mappings.": {
"category": "Message",
"code": 6206
},
"'package.json' does not have a 'typesVersions' entry that matches version '{0}'.": {
"category": "Message",
"code": 6207
},
"'package.json' has a 'typesVersions' entry '{0}' that matches compiler version '{1}', looking for a pattern to match module name '{2}'.": {
"category": "Message",
"code": 6208
},
"'package.json' has a 'typesVersions' entry '{0}' that is not a valid semver range.": {
"category": "Message",
"code": 6209
},
"An argument for '{0}' was not provided.": {
"category": "Message",
"code": 6210
},
"An argument matching this binding pattern was not provided.": {
"category": "Message",
"code": 6211
},
"Did you mean to call this expression?": {
"category": "Message",
"code": 6212
},
"Did you mean to use 'new' with this expression?": {
"category": "Message",
"code": 6213
},
"Enable strict 'bind', 'call', and 'apply' methods on functions.": {
"category": "Message",
"code": 6214
},
"Projects to reference": {
"category": "Message",
@@ -3814,10 +3885,6 @@
"category": "Error",
"code": 6370
},
"Skipping clean because not all projects could be located": {
"category": "Error",
"code": 6371
},
"The expected type comes from property '{0}' which is declared here on type '{1}'": {
"category": "Message",
@@ -3827,6 +3894,10 @@
"category": "Message",
"code": 6501
},
"The expected type comes from the return type of this signature.": {
"category": "Message",
"code": 6502
},
"Variable '{0}' implicitly has an '{1}' type.": {
"category": "Error",
@@ -4086,6 +4157,10 @@
"category": "Error",
"code": 8030
},
"You cannot rename a module via a global import.": {
"category": "Error",
"code": 8031
},
"Only identifiers/qualified-names with optional type arguments are currently supported in a class 'extends' clause.": {
"category": "Error",
"code": 9002
@@ -4584,7 +4659,7 @@
"category": "Message",
"code": 95062
},
"Add missing enum member '{0}'": {
"category": "Message",
"code": 95063
@@ -4593,12 +4668,20 @@
"category": "Message",
"code": 95064
},
"Convert to async function":{
"Convert to async function": {
"category": "Message",
"code": 95065
"code": 95065
},
"Convert all to async functions": {
"category": "Message",
"code": 95066
"category": "Message",
"code": 95066
},
"Generate types for '{0}'": {
"category": "Message",
"code": 95067
},
"Generate types for all packages without types": {
"category": "Message",
"code": 95068
}
}
+43 -31
View File
@@ -41,20 +41,25 @@ namespace ts {
export function getOutputPathsFor(sourceFile: SourceFile | Bundle, host: EmitHost, forceDtsPaths: boolean): EmitFileNames {
const options = host.getCompilerOptions();
if (sourceFile.kind === SyntaxKind.Bundle) {
const jsFilePath = options.outFile || options.out!;
const sourceMapFilePath = getSourceMapFilePath(jsFilePath, options);
const declarationFilePath = (forceDtsPaths || getEmitDeclarations(options)) ? removeFileExtension(jsFilePath) + Extension.Dts : undefined;
const declarationMapPath = getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined;
const outPath = options.outFile || options.out!;
const jsFilePath = options.emitDeclarationOnly ? undefined : outPath;
const sourceMapFilePath = jsFilePath && getSourceMapFilePath(jsFilePath, options);
const declarationFilePath = (forceDtsPaths || getEmitDeclarations(options)) ? removeFileExtension(outPath) + Extension.Dts : undefined;
const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined;
const bundleInfoPath = options.references && jsFilePath ? (removeFileExtension(jsFilePath) + infoExtension) : undefined;
return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, bundleInfoPath };
}
else {
const jsFilePath = getOwnEmitOutputFilePath(sourceFile.fileName, host, getOutputExtension(sourceFile, options));
const sourceMapFilePath = isJsonSourceFile(sourceFile) ? undefined : getSourceMapFilePath(jsFilePath, options);
const ownOutputFilePath = getOwnEmitOutputFilePath(sourceFile.fileName, host, getOutputExtension(sourceFile, options));
// If json file emits to the same location skip writing it, if emitDeclarationOnly skip writing it
const isJsonEmittedToSameLocation = isJsonSourceFile(sourceFile) &&
comparePaths(sourceFile.fileName, ownOutputFilePath, host.getCurrentDirectory(), !host.useCaseSensitiveFileNames()) === Comparison.EqualTo;
const jsFilePath = options.emitDeclarationOnly || isJsonEmittedToSameLocation ? undefined : ownOutputFilePath;
const sourceMapFilePath = !jsFilePath || isJsonSourceFile(sourceFile) ? undefined : getSourceMapFilePath(jsFilePath, options);
// For legacy reasons (ie, we have baselines capturing the behavior), js files don't report a .d.ts output path - this would only matter if `declaration` and `allowJs` were both on, which is currently an error
const isJs = isSourceFileJavaScript(sourceFile);
const isJs = isSourceFileJS(sourceFile);
const declarationFilePath = ((forceDtsPaths || getEmitDeclarations(options)) && !isJs) ? getDeclarationEmitOutputFilePath(sourceFile.fileName, host) : undefined;
const declarationMapPath = getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined;
const declarationMapPath = declarationFilePath && getAreDeclarationMapsEnabled(options) ? declarationFilePath + ".map" : undefined;
return { jsFilePath, sourceMapFilePath, declarationFilePath, declarationMapPath, bundleInfoPath: undefined };
}
}
@@ -80,7 +85,7 @@ namespace ts {
}
if (options.jsx === JsxEmit.Preserve) {
if (isSourceFileJavaScript(sourceFile)) {
if (isSourceFileJS(sourceFile)) {
if (fileExtensionIs(sourceFile.fileName, Extension.Jsx)) {
return Extension.Jsx;
}
@@ -135,27 +140,33 @@ namespace ts {
if (!emitSkipped && emittedFilesList) {
if (!emitOnlyDtsFiles) {
emittedFilesList.push(jsFilePath);
}
if (sourceMapFilePath) {
emittedFilesList.push(sourceMapFilePath);
if (jsFilePath) {
emittedFilesList.push(jsFilePath);
}
if (sourceMapFilePath) {
emittedFilesList.push(sourceMapFilePath);
}
if (bundleInfoPath) {
emittedFilesList.push(bundleInfoPath);
}
}
if (declarationFilePath) {
emittedFilesList.push(declarationFilePath);
}
if (bundleInfoPath) {
emittedFilesList.push(bundleInfoPath);
if (declarationMapPath) {
emittedFilesList.push(declarationMapPath);
}
}
}
function emitJsFileOrBundle(sourceFileOrBundle: SourceFile | Bundle, jsFilePath: string, sourceMapFilePath: string | undefined, bundleInfoPath: string | undefined) {
// Make sure not to write js file and source map file if any of them cannot be written
if (host.isEmitBlocked(jsFilePath) || compilerOptions.noEmit || compilerOptions.emitDeclarationOnly) {
emitSkipped = true;
function emitJsFileOrBundle(sourceFileOrBundle: SourceFile | Bundle, jsFilePath: string | undefined, sourceMapFilePath: string | undefined, bundleInfoPath: string | undefined) {
if (emitOnlyDtsFiles || !jsFilePath) {
return;
}
if (emitOnlyDtsFiles) {
// Make sure not to write js file and source map file if any of them cannot be written
if ((jsFilePath && host.isEmitBlocked(jsFilePath)) || compilerOptions.noEmit) {
emitSkipped = true;
return;
}
// Transform the source files
@@ -187,12 +198,12 @@ namespace ts {
}
function emitDeclarationFileOrBundle(sourceFileOrBundle: SourceFile | Bundle, declarationFilePath: string | undefined, declarationMapPath: string | undefined) {
if (!(declarationFilePath && !isInJavaScriptFile(sourceFileOrBundle))) {
if (!(declarationFilePath && !isInJSFile(sourceFileOrBundle))) {
return;
}
const sourceFiles = isSourceFile(sourceFileOrBundle) ? [sourceFileOrBundle] : sourceFileOrBundle.sourceFiles;
// Setup and perform the transformation to retrieve declarations from the input files
const nonJsFiles = filter(sourceFiles, isSourceFileNotJavaScript);
const nonJsFiles = filter(sourceFiles, isSourceFileNotJS);
const inputListOrBundle = (compilerOptions.outFile || compilerOptions.out) ? [createBundle(nonJsFiles, !isSourceFile(sourceFileOrBundle) ? sourceFileOrBundle.prepends : undefined)] : nonJsFiles;
if (emitOnlyDtsFiles && !getEmitDeclarations(compilerOptions)) {
// Checker wont collect the linked aliases since thats only done when declaration is enabled.
@@ -1015,7 +1026,7 @@ namespace ts {
writeLines(helper.text);
}
else {
writeLines(helper.text(makeFileLevelOptmiisticUniqueName));
writeLines(helper.text(makeFileLevelOptimisticUniqueName));
}
helpersEmitted = true;
}
@@ -1041,7 +1052,7 @@ namespace ts {
// SyntaxKind.TemplateMiddle
// SyntaxKind.TemplateTail
function emitLiteral(node: LiteralLikeNode) {
const text = getLiteralTextOfNode(node);
const text = getLiteralTextOfNode(node, printerOptions.neverAsciiEscape);
if ((printerOptions.sourceMap || printerOptions.inlineSourceMap)
&& (node.kind === SyntaxKind.StringLiteral || isTemplateLiteralKind(node.kind))) {
writeLiteral(text);
@@ -1532,7 +1543,7 @@ namespace ts {
expression = skipPartiallyEmittedExpressions(expression);
if (isNumericLiteral(expression)) {
// check if numeric literal is a decimal literal that was originally written with a dot
const text = getLiteralTextOfNode(<LiteralExpression>expression);
const text = getLiteralTextOfNode(<LiteralExpression>expression, /*neverAsciiEscape*/ true);
return !expression.numericLiteralFlags
&& !stringContains(text, tokenToString(SyntaxKind.DotToken)!);
}
@@ -2818,7 +2829,8 @@ namespace ts {
const parameter = singleOrUndefined(parameters);
return parameter
&& parameter.pos === parentNode.pos // may not have parsed tokens between parent and parameter
&& !(isArrowFunction(parentNode) && parentNode.type) // arrow function may not have return type annotation
&& isArrowFunction(parentNode) // only arrow functions may have simple arrow head
&& !parentNode.type // arrow function may not have return type annotation
&& !some(parentNode.decorators) // parent may not have decorators
&& !some(parentNode.modifiers) // parent may not have modifiers
&& !some(parentNode.typeParameters) // parent may not have type parameters
@@ -3305,20 +3317,20 @@ namespace ts {
return getSourceTextOfNodeFromSourceFile(currentSourceFile, node, includeTrivia);
}
function getLiteralTextOfNode(node: LiteralLikeNode): string {
function getLiteralTextOfNode(node: LiteralLikeNode, neverAsciiEscape: boolean | undefined): string {
if (node.kind === SyntaxKind.StringLiteral && (<StringLiteral>node).textSourceNode) {
const textSourceNode = (<StringLiteral>node).textSourceNode!;
if (isIdentifier(textSourceNode)) {
return getEmitFlags(node) & EmitFlags.NoAsciiEscaping ?
return neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ?
`"${escapeString(getTextOfNode(textSourceNode))}"` :
`"${escapeNonAsciiString(getTextOfNode(textSourceNode))}"`;
}
else {
return getLiteralTextOfNode(textSourceNode);
return getLiteralTextOfNode(textSourceNode, neverAsciiEscape);
}
}
return getLiteralText(node, currentSourceFile);
return getLiteralText(node, currentSourceFile, neverAsciiEscape);
}
/**
@@ -3587,7 +3599,7 @@ namespace ts {
}
}
function makeFileLevelOptmiisticUniqueName(name: string) {
function makeFileLevelOptimisticUniqueName(name: string) {
return makeUniqueName(name, isFileLevelUniqueName, /*optimistic*/ true);
}
+1 -1
View File
@@ -235,7 +235,7 @@ namespace ts {
// Modifiers
export function createModifier<T extends Modifier["kind"]>(kind: T) {
export function createModifier<T extends Modifier["kind"]>(kind: T): Token<T> {
return createToken(kind);
}
+159
View File
@@ -0,0 +1,159 @@
/* @internal */
namespace ts {
export interface InspectValueOptions {
readonly fileNameToRequire: string;
}
export const enum ValueKind { Const, Array, FunctionOrClass, Object }
export interface ValueInfoBase {
readonly name: string;
}
export type ValueInfo = ValueInfoSimple | ValueInfoArray | ValueInfoFunctionOrClass | ValueInfoObject;
export interface ValueInfoSimple extends ValueInfoBase {
readonly kind: ValueKind.Const;
readonly typeName: string;
readonly comment?: string | undefined;
}
export interface ValueInfoFunctionOrClass extends ValueInfoBase {
readonly kind: ValueKind.FunctionOrClass;
readonly source: string | number; // For a native function, this is the length.
readonly prototypeMembers: ReadonlyArray<ValueInfo>;
readonly namespaceMembers: ReadonlyArray<ValueInfo>;
}
export interface ValueInfoArray extends ValueInfoBase {
readonly kind: ValueKind.Array;
readonly inner: ValueInfo;
}
export interface ValueInfoObject extends ValueInfoBase {
readonly kind: ValueKind.Object;
readonly members: ReadonlyArray<ValueInfo>;
}
export function inspectModule(fileNameToRequire: string): ValueInfo {
return inspectValue(removeFileExtension(getBaseFileName(fileNameToRequire)), tryRequire(fileNameToRequire));
}
export function inspectValue(name: string, value: unknown): ValueInfo {
return getValueInfo(name, value, getRecurser());
}
type Recurser = <T>(obj: unknown, name: string, cbOk: () => T, cbFail: (isCircularReference: boolean, keyStack: ReadonlyArray<string>) => T) => T;
function getRecurser(): Recurser {
const seen = new Set<unknown>();
const nameStack: string[] = [];
return (obj, name, cbOk, cbFail) => {
if (seen.has(obj) || nameStack.length > 4) {
return cbFail(seen.has(obj), nameStack);
}
seen.add(obj);
nameStack.push(name);
const res = cbOk();
nameStack.pop();
seen.delete(obj);
return res;
};
}
function getValueInfo(name: string, value: unknown, recurser: Recurser): ValueInfo {
return recurser(value, name,
(): ValueInfo => {
if (typeof value === "function") return getFunctionOrClassInfo(value as AnyFunction, name, recurser);
if (typeof value === "object") {
const builtin = getBuiltinType(name, value as object, recurser);
if (builtin !== undefined) return builtin;
const entries = getEntriesOfObject(value as object);
return { kind: ValueKind.Object, name, members: flatMap(entries, ({ key, value }) => getValueInfo(key, value, recurser)) };
}
return { kind: ValueKind.Const, name, typeName: isNullOrUndefined(value) ? "any" : typeof value };
},
(isCircularReference, keyStack) => anyValue(name, ` ${isCircularReference ? "Circular reference" : "Too-deep object hierarchy"} from ${keyStack.join(".")}`));
}
function getFunctionOrClassInfo(fn: AnyFunction, name: string, recurser: Recurser): ValueInfoFunctionOrClass {
const prototypeMembers = getPrototypeMembers(fn, recurser);
const namespaceMembers = flatMap(getEntriesOfObject(fn), ({ key, value }) => getValueInfo(key, value, recurser));
const toString = cast(Function.prototype.toString.call(fn), isString);
const source = stringContains(toString, "{ [native code] }") ? getFunctionLength(fn) : toString;
return { kind: ValueKind.FunctionOrClass, name, source, namespaceMembers, prototypeMembers };
}
const builtins: () => ReadonlyMap<AnyConstructor> = memoize(() => {
const map = createMap<AnyConstructor>();
for (const { key, value } of getEntriesOfObject(global)) {
if (typeof value === "function" && typeof value.prototype === "object" && value !== Object) {
map.set(key, value as AnyConstructor);
}
}
return map;
});
function getBuiltinType(name: string, value: object, recurser: Recurser): ValueInfo | undefined {
return isArray(value)
? { name, kind: ValueKind.Array, inner: value.length && getValueInfo("element", first(value), recurser) || anyValue(name) }
: forEachEntry(builtins(), (builtin, builtinName): ValueInfo | undefined =>
value instanceof builtin ? { kind: ValueKind.Const, name, typeName: builtinName } : undefined);
}
function getPrototypeMembers(fn: AnyFunction, recurser: Recurser): ReadonlyArray<ValueInfo> {
const prototype = fn.prototype as unknown;
// tslint:disable-next-line no-unnecessary-type-assertion (TODO: update LKG and it will really be unnecessary)
return typeof prototype !== "object" || prototype === null ? emptyArray : mapDefined(getEntriesOfObject(prototype as object), ({ key, value }) =>
key === "constructor" ? undefined : getValueInfo(key, value, recurser));
}
const ignoredProperties: ReadonlySet<string> = new Set(["arguments", "caller", "constructor", "eval", "super_"]);
const reservedFunctionProperties: ReadonlySet<string> = new Set(Object.getOwnPropertyNames(noop));
interface ObjectEntry { readonly key: string; readonly value: unknown; }
function getEntriesOfObject(obj: object): ReadonlyArray<ObjectEntry> {
const seen = createMap<true>();
const entries: ObjectEntry[] = [];
let chain = obj;
while (!isNullOrUndefined(chain) && chain !== Object.prototype && chain !== Function.prototype) {
for (const key of Object.getOwnPropertyNames(chain)) {
if (!isJsPrivate(key) &&
!ignoredProperties.has(key) &&
(typeof obj !== "function" || !reservedFunctionProperties.has(key)) &&
// Don't add property from a higher prototype if it already exists in a lower one
addToSeen(seen, key)) {
const value = safeGetPropertyOfObject(chain, key);
// Don't repeat "toString" that matches signature from Object.prototype
if (!(key === "toString" && typeof value === "function" && value.length === 0)) {
entries.push({ key, value });
}
}
}
chain = Object.getPrototypeOf(chain);
}
return entries.sort((e1, e2) => compareStringsCaseSensitive(e1.key, e2.key));
}
function getFunctionLength(fn: AnyFunction): number {
return tryCast(safeGetPropertyOfObject(fn, "length"), isNumber) || 0;
}
function safeGetPropertyOfObject(obj: object, key: string): unknown {
const desc = Object.getOwnPropertyDescriptor(obj, key);
return desc && desc.value;
}
function isNullOrUndefined(value: unknown): value is null | undefined {
return value == null; // tslint:disable-line
}
function anyValue(name: string, comment?: string): ValueInfo {
return { kind: ValueKind.Const, name, typeName: "any", comment };
}
export function isJsPrivate(name: string): boolean {
return name.startsWith("_");
}
function tryRequire(fileNameToRequire: string): unknown {
try {
return require(fileNameToRequire);
}
catch {
return undefined;
}
}
}
+357 -242
View File
@@ -24,6 +24,13 @@ namespace ts {
return withPackageId(/*packageId*/ undefined, r);
}
function removeIgnoredPackageId(r: Resolved | undefined): PathAndExtension | undefined {
if (r) {
Debug.assert(r.packageId === undefined);
return { path: r.path, ext: r.extension };
}
}
/** Result of trying to resolve a module. */
interface Resolved {
path: string;
@@ -67,7 +74,7 @@ namespace ts {
if (!resolved) {
return undefined;
}
Debug.assert(extensionIsTypeScript(resolved.extension));
Debug.assert(extensionIsTS(resolved.extension));
return { fileName: resolved.path, packageId: resolved.packageId };
}
@@ -82,12 +89,14 @@ namespace ts {
host: ModuleResolutionHost;
compilerOptions: CompilerOptions;
traceEnabled: boolean;
failedLookupLocations: Push<string>;
}
/** Just the fields that we use for module resolution. */
interface PackageJsonPathFields {
typings?: string;
types?: string;
typesVersions?: MapLike<MapLike<string[]>>;
main?: string;
}
@@ -96,48 +105,111 @@ namespace ts {
version?: string;
}
/** Reads from "main" or "types"/"typings" depending on `extensions`. */
function tryReadPackageJsonFields(readTypes: boolean, jsonContent: PackageJsonPathFields, baseDirectory: string, state: ModuleResolutionState): string | undefined {
return readTypes ? tryReadFromField("typings") || tryReadFromField("types") : tryReadFromField("main");
type MatchingKeys<TRecord, TMatch, K extends keyof TRecord = keyof TRecord> = K extends (TRecord[K] extends TMatch ? K : never) ? K : never;
function tryReadFromField(fieldName: "typings" | "types" | "main"): string | undefined {
if (!hasProperty(jsonContent, fieldName)) {
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_does_not_have_a_0_field, fieldName);
}
return;
}
const fileName = jsonContent[fieldName];
if (!isString(fileName)) {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_string_got_1, fieldName, typeof fileName);
}
return;
}
const path = normalizePath(combinePaths(baseDirectory, fileName));
function readPackageJsonField<TMatch, K extends MatchingKeys<PackageJson, string | undefined>>(jsonContent: PackageJson, fieldName: K, typeOfTag: "string", state: ModuleResolutionState): PackageJson[K] | undefined;
function readPackageJsonField<K extends MatchingKeys<PackageJson, object | undefined>>(jsonContent: PackageJson, fieldName: K, typeOfTag: "object", state: ModuleResolutionState): PackageJson[K] | undefined;
function readPackageJsonField<K extends keyof PackageJson>(jsonContent: PackageJson, fieldName: K, typeOfTag: "string" | "object", state: ModuleResolutionState): PackageJson[K] | undefined {
if (!hasProperty(jsonContent, fieldName)) {
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, fileName, path);
trace(state.host, Diagnostics.package_json_does_not_have_a_0_field, fieldName);
}
return path;
return;
}
const value = jsonContent[fieldName];
if (typeof value !== typeOfTag || value === null) {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, fieldName, typeOfTag, value === null ? "null" : typeof value);
}
return;
}
return value;
}
/* @internal */
export function readJson(path: string, host: { readFile(fileName: string): string | undefined }): object {
try {
const jsonText = host.readFile(path);
if (!jsonText) return {};
const result = parseConfigFileTextToJson(path, jsonText);
if (result.error) {
return {};
}
return result.config;
function readPackageJsonPathField<K extends "typings" | "types" | "main">(jsonContent: PackageJson, fieldName: K, baseDirectory: string, state: ModuleResolutionState): PackageJson[K] | undefined {
const fileName = readPackageJsonField(jsonContent, fieldName, "string", state);
if (fileName === undefined) return;
const path = normalizePath(combinePaths(baseDirectory, fileName));
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_has_0_field_1_that_references_2, fieldName, fileName, path);
}
catch (e) {
// gracefully handle if readFile fails or returns not JSON
return {};
return path;
}
function readPackageJsonTypesFields(jsonContent: PackageJson, baseDirectory: string, state: ModuleResolutionState) {
return readPackageJsonPathField(jsonContent, "typings", baseDirectory, state)
|| readPackageJsonPathField(jsonContent, "types", baseDirectory, state);
}
function readPackageJsonMainField(jsonContent: PackageJson, baseDirectory: string, state: ModuleResolutionState) {
return readPackageJsonPathField(jsonContent, "main", baseDirectory, state);
}
function readPackageJsonTypesVersionsField(jsonContent: PackageJson, state: ModuleResolutionState) {
const typesVersions = readPackageJsonField(jsonContent, "typesVersions", "object", state);
if (typesVersions === undefined) return;
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_has_a_typesVersions_field_with_version_specific_path_mappings);
}
return typesVersions;
}
interface VersionPaths {
version: string;
paths: MapLike<string[]>;
}
function readPackageJsonTypesVersionPaths(jsonContent: PackageJson, state: ModuleResolutionState): VersionPaths | undefined {
const typesVersions = readPackageJsonTypesVersionsField(jsonContent, state);
if (typesVersions === undefined) return;
if (state.traceEnabled) {
for (const key in typesVersions) {
if (hasProperty(typesVersions, key) && !VersionRange.tryParse(key)) {
trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_is_not_a_valid_semver_range, key);
}
}
}
const result = getPackageJsonTypesVersionsPaths(typesVersions);
if (!result) {
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_does_not_have_a_typesVersions_entry_that_matches_version_0, versionMajorMinor);
}
return;
}
const { version: bestVersionKey, paths: bestVersionPaths } = result;
if (typeof bestVersionPaths !== "object") {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Expected_type_of_0_field_in_package_json_to_be_1_got_2, `typesVersions['${bestVersionKey}']`, "object", typeof bestVersionPaths);
}
return;
}
return result;
}
let typeScriptVersion: Version | undefined;
/* @internal */
export function getPackageJsonTypesVersionsPaths(typesVersions: MapLike<MapLike<string[]>>) {
if (!typeScriptVersion) typeScriptVersion = new Version(version);
for (const key in typesVersions) {
if (!hasProperty(typesVersions, key)) continue;
const keyRange = VersionRange.tryParse(key);
if (keyRange === undefined) {
continue;
}
// return the first entry whose range matches the current compiler version.
if (keyRange.test(typeScriptVersion)) {
return { version: key, paths: typesVersions[key] };
}
}
}
@@ -188,7 +260,8 @@ namespace ts {
*/
export function resolveTypeReferenceDirective(typeReferenceDirectiveName: string, containingFile: string | undefined, options: CompilerOptions, host: ModuleResolutionHost): ResolvedTypeReferenceDirectiveWithFailedLookupLocations {
const traceEnabled = isTraceEnabled(options, host);
const moduleResolutionState: ModuleResolutionState = { compilerOptions: options, host, traceEnabled };
const failedLookupLocations: string[] = [];
const moduleResolutionState: ModuleResolutionState = { compilerOptions: options, host, traceEnabled, failedLookupLocations };
const typeRoots = getEffectiveTypeRoots(options, host);
if (traceEnabled) {
@@ -210,8 +283,6 @@ namespace ts {
}
}
const failedLookupLocations: string[] = [];
let resolved = primaryLookup();
let primary = true;
if (!resolved) {
@@ -247,7 +318,7 @@ namespace ts {
trace(host, Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, candidateDirectory);
}
return resolvedTypeScriptOnly(
loadNodeModuleFromDirectory(Extensions.DtsOnly, candidate, failedLookupLocations,
loadNodeModuleFromDirectory(Extensions.DtsOnly, candidate,
!directoryExists, moduleResolutionState));
});
}
@@ -266,7 +337,14 @@ namespace ts {
if (traceEnabled) {
trace(host, Diagnostics.Looking_up_in_node_modules_folder_initial_location_0, initialLocationForSecondaryLookup);
}
const result = loadModuleFromNodeModules(Extensions.DtsOnly, typeReferenceDirectiveName, initialLocationForSecondaryLookup, failedLookupLocations, moduleResolutionState, /*cache*/ undefined);
let result: SearchResult<Resolved> | undefined;
if (!isExternalModuleNameRelative(typeReferenceDirectiveName)) {
result = loadModuleFromNearestNodeModulesDirectory(Extensions.DtsOnly, typeReferenceDirectiveName, initialLocationForSecondaryLookup, moduleResolutionState, /*cache*/ undefined);
}
else {
const { path: candidate } = normalizePathAndParts(combinePaths(initialLocationForSecondaryLookup, typeReferenceDirectiveName));
result = toSearchResult(nodeLoadModuleByRelativeName(Extensions.DtsOnly, candidate, /*onlyRecordFailures*/ false, moduleResolutionState, /*considerPackageJson*/ true));
}
const resolvedFile = resolvedTypeScriptOnly(result && result.value);
if (!resolvedFile && traceEnabled) {
trace(host, Diagnostics.Type_reference_directive_0_was_not_resolved, typeReferenceDirectiveName);
@@ -304,14 +382,19 @@ namespace ts {
if (host.directoryExists(root)) {
for (const typeDirectivePath of host.getDirectories(root)) {
const normalized = normalizePath(typeDirectivePath);
const packageJsonPath = pathToPackageJson(combinePaths(root, normalized));
const packageJsonPath = combinePaths(root, normalized, "package.json");
// `types-publisher` sometimes creates packages with `"typings": null` for packages that don't provide their own types.
// See `createNotNeededPackageJSON` in the types-publisher` repo.
// tslint:disable-next-line:no-null-keyword
const isNotNeededPackage = host.fileExists(packageJsonPath) && (readJson(packageJsonPath, host) as PackageJson).typings === null;
if (!isNotNeededPackage) {
// Return just the type directive names
result.push(getBaseFileName(normalized));
const baseFileName = getBaseFileName(normalized);
// At this stage, skip results with leading dot.
if (baseFileName.charCodeAt(0) !== CharacterCodes.dot) {
// Return just the type directive names
result.push(baseFileName);
}
}
}
}
@@ -527,7 +610,7 @@ namespace ts {
* 'typings' entry or file 'index' with some supported extension
* - Classic loader will only try to interpret '/a/b/c' as file.
*/
type ResolutionKindSpecificLoader = (extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState) => Resolved | undefined;
type ResolutionKindSpecificLoader = (extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState) => Resolved | undefined;
/**
* Any module resolution kind can be augmented with optional settings: 'baseUrl', 'paths' and 'rootDirs' - they are used to
@@ -590,18 +673,18 @@ namespace ts {
* entries in 'rootDirs', use them to build absolute path out of (*) and try to resolve module from this location.
*/
function tryLoadModuleUsingOptionalResolutionSettings(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
state: ModuleResolutionState): Resolved | undefined {
if (!isExternalModuleNameRelative(moduleName)) {
return tryLoadModuleUsingBaseUrl(extensions, moduleName, loader, failedLookupLocations, state);
return tryLoadModuleUsingBaseUrl(extensions, moduleName, loader, state);
}
else {
return tryLoadModuleUsingRootDirs(extensions, moduleName, containingDirectory, loader, failedLookupLocations, state);
return tryLoadModuleUsingRootDirs(extensions, moduleName, containingDirectory, loader, state);
}
}
function tryLoadModuleUsingRootDirs(extensions: Extensions, moduleName: string, containingDirectory: string, loader: ResolutionKindSpecificLoader,
failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
state: ModuleResolutionState): Resolved | undefined {
if (!state.compilerOptions.rootDirs) {
return undefined;
@@ -646,7 +729,7 @@ namespace ts {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Loading_0_from_the_root_dir_1_candidate_location_2, suffix, matchedNormalizedPrefix, candidate);
}
const resolvedFileName = loader(extensions, candidate, failedLookupLocations, !directoryProbablyExists(containingDirectory, state.host), state);
const resolvedFileName = loader(extensions, candidate, !directoryProbablyExists(containingDirectory, state.host), state);
if (resolvedFileName) {
return resolvedFileName;
}
@@ -665,7 +748,7 @@ namespace ts {
trace(state.host, Diagnostics.Loading_0_from_the_root_dir_1_candidate_location_2, suffix, rootDir, candidate);
}
const baseDirectory = getDirectoryPath(candidate);
const resolvedFileName = loader(extensions, candidate, failedLookupLocations, !directoryProbablyExists(baseDirectory, state.host), state);
const resolvedFileName = loader(extensions, candidate, !directoryProbablyExists(baseDirectory, state.host), state);
if (resolvedFileName) {
return resolvedFileName;
}
@@ -677,60 +760,28 @@ namespace ts {
return undefined;
}
function tryLoadModuleUsingBaseUrl(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
if (!state.compilerOptions.baseUrl) {
function tryLoadModuleUsingBaseUrl(extensions: Extensions, moduleName: string, loader: ResolutionKindSpecificLoader, state: ModuleResolutionState): Resolved | undefined {
const { baseUrl, paths } = state.compilerOptions;
if (!baseUrl) {
return undefined;
}
if (state.traceEnabled) {
trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, state.compilerOptions.baseUrl, moduleName);
trace(state.host, Diagnostics.baseUrl_option_is_set_to_0_using_this_value_to_resolve_non_relative_module_name_1, baseUrl, moduleName);
}
// string is for exact match
let matchedPattern: Pattern | string | undefined;
if (state.compilerOptions.paths) {
if (paths) {
if (state.traceEnabled) {
trace(state.host, Diagnostics.paths_option_is_specified_looking_for_a_pattern_to_match_module_name_0, moduleName);
}
matchedPattern = matchPatternOrExact(getOwnKeys(state.compilerOptions.paths), moduleName);
}
if (matchedPattern) {
const matchedStar = isString(matchedPattern) ? undefined : matchedText(matchedPattern, moduleName);
const matchedPatternText = isString(matchedPattern) ? matchedPattern : patternText(matchedPattern);
if (state.traceEnabled) {
trace(state.host, Diagnostics.Module_name_0_matched_pattern_1, moduleName, matchedPatternText);
const resolved = tryLoadModuleUsingPaths(extensions, moduleName, baseUrl, paths, loader, /*onlyRecordFailures*/ false, state);
if (resolved) {
return resolved.value;
}
return forEach(state.compilerOptions.paths![matchedPatternText], subst => {
const path = matchedStar ? subst.replace("*", matchedStar) : subst;
const candidate = normalizePath(combinePaths(state.compilerOptions.baseUrl!, path));
if (state.traceEnabled) {
trace(state.host, Diagnostics.Trying_substitution_0_candidate_module_location_Colon_1, subst, path);
}
// A path mapping may have an extension, in contrast to an import, which should omit it.
const extension = tryGetExtensionFromPath(candidate);
if (extension !== undefined) {
const path = tryFile(candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state);
if (path !== undefined) {
return noPackageId({ path, ext: extension });
}
}
return loader(extensions, candidate, failedLookupLocations, !directoryProbablyExists(getDirectoryPath(candidate), state.host), state);
});
}
else {
const candidate = normalizePath(combinePaths(state.compilerOptions.baseUrl, moduleName));
if (state.traceEnabled) {
trace(state.host, Diagnostics.Resolving_module_name_0_relative_to_base_url_1_2, moduleName, state.compilerOptions.baseUrl, candidate);
}
return loader(extensions, candidate, failedLookupLocations, !directoryProbablyExists(getDirectoryPath(candidate), state.host), state);
const candidate = normalizePath(combinePaths(baseUrl, moduleName));
if (state.traceEnabled) {
trace(state.host, Diagnostics.Resolving_module_name_0_relative_to_base_url_1_2, moduleName, baseUrl, candidate);
}
}
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache): ResolvedModuleWithFailedLookupLocations {
return nodeModuleNameResolverWorker(moduleName, getDirectoryPath(containingFile), compilerOptions, host, cache, /*jsOnly*/ false);
return loader(extensions, candidate, !directoryProbablyExists(getDirectoryPath(candidate), state.host), state);
}
/**
@@ -739,20 +790,33 @@ namespace ts {
* Throws an error if the module can't be resolved.
*/
/* @internal */
export function resolveJavaScriptModule(moduleName: string, initialDir: string, host: ModuleResolutionHost): string {
const { resolvedModule, failedLookupLocations } =
nodeModuleNameResolverWorker(moduleName, initialDir, { moduleResolution: ModuleResolutionKind.NodeJs, allowJs: true }, host, /*cache*/ undefined, /*jsOnly*/ true);
export function resolveJSModule(moduleName: string, initialDir: string, host: ModuleResolutionHost): string {
const { resolvedModule, failedLookupLocations } = tryResolveJSModuleWorker(moduleName, initialDir, host);
if (!resolvedModule) {
throw new Error(`Could not resolve JS module '${moduleName}' starting at '${initialDir}'. Looked in: ${failedLookupLocations.join(", ")}`);
}
return resolvedModule.resolvedFileName;
}
/* @internal */
export function tryResolveJSModule(moduleName: string, initialDir: string, host: ModuleResolutionHost): string | undefined {
const { resolvedModule } = tryResolveJSModuleWorker(moduleName, initialDir, host);
return resolvedModule && resolvedModule.resolvedFileName;
}
function tryResolveJSModuleWorker(moduleName: string, initialDir: string, host: ModuleResolutionHost): ResolvedModuleWithFailedLookupLocations {
return nodeModuleNameResolverWorker(moduleName, initialDir, { moduleResolution: ModuleResolutionKind.NodeJs, allowJs: true }, host, /*cache*/ undefined, /*jsOnly*/ true);
}
export function nodeModuleNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: ModuleResolutionCache): ResolvedModuleWithFailedLookupLocations {
return nodeModuleNameResolverWorker(moduleName, getDirectoryPath(containingFile), compilerOptions, host, cache, /*jsOnly*/ false);
}
function nodeModuleNameResolverWorker(moduleName: string, containingDirectory: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache: ModuleResolutionCache | undefined, jsOnly: boolean): ResolvedModuleWithFailedLookupLocations {
const traceEnabled = isTraceEnabled(compilerOptions, host);
const failedLookupLocations: string[] = [];
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled };
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations };
const result = jsOnly ?
tryResolve(Extensions.JavaScript) :
@@ -766,8 +830,8 @@ namespace ts {
return { resolvedModule: undefined, failedLookupLocations };
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);
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => nodeLoadModuleByRelativeName(extensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ true);
const resolved = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loader, state);
if (resolved) {
return toSearchResult({ resolved, isExternalLibraryImport: stringContains(resolved.path, nodeModulesPathPart) });
}
@@ -776,7 +840,7 @@ namespace ts {
if (traceEnabled) {
trace(host, Diagnostics.Loading_module_0_from_node_modules_folder_target_file_type_1, moduleName, Extensions[extensions]);
}
const resolved = loadModuleFromNodeModules(extensions, moduleName, containingDirectory, failedLookupLocations, state, cache);
const resolved = loadModuleFromNearestNodeModulesDirectory(extensions, moduleName, containingDirectory, state, cache);
if (!resolved) return undefined;
let resolvedValue = resolved.value;
@@ -790,7 +854,7 @@ namespace ts {
}
else {
const { path: candidate, parts } = normalizePathAndParts(combinePaths(containingDirectory, moduleName));
const resolved = nodeLoadModuleByRelativeName(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state, /*considerPackageJson*/ true);
const resolved = nodeLoadModuleByRelativeName(extensions, candidate, /*onlyRecordFailures*/ false, state, /*considerPackageJson*/ true);
// Treat explicit "node_modules" import as an external library import.
return resolved && toSearchResult({ resolved, isExternalLibraryImport: contains(parts, "node_modules") });
}
@@ -810,7 +874,7 @@ namespace ts {
return real;
}
function nodeLoadModuleByRelativeName(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson: boolean): Resolved | undefined {
function nodeLoadModuleByRelativeName(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson: boolean): Resolved | undefined {
if (state.traceEnabled) {
trace(state.host, Diagnostics.Loading_module_as_file_Slash_folder_candidate_module_location_0_target_file_type_1, candidate, Extensions[extensions]);
}
@@ -824,10 +888,11 @@ namespace ts {
onlyRecordFailures = true;
}
}
const resolvedFromFile = loadModuleFromFile(extensions, candidate, failedLookupLocations, onlyRecordFailures, state);
const resolvedFromFile = loadModuleFromFile(extensions, candidate, onlyRecordFailures, state);
if (resolvedFromFile) {
const nm = considerPackageJson ? parseNodeModuleFromPath(resolvedFromFile) : undefined;
const packageId = nm && getPackageJsonInfo(nm.packageDirectory, nm.subModuleName, failedLookupLocations, /*onlyRecordFailures*/ false, state).packageId;
const packageInfo = nm && getPackageJsonInfo(nm.packageDirectory, nm.subModuleName, /*onlyRecordFailures*/ false, state);
const packageId = packageInfo && packageInfo.packageId;
return withPackageId(packageId, resolvedFromFile);
}
}
@@ -840,7 +905,7 @@ namespace ts {
onlyRecordFailures = true;
}
}
return loadNodeModuleFromDirectory(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, considerPackageJson);
return loadNodeModuleFromDirectory(extensions, candidate, onlyRecordFailures, state, considerPackageJson);
}
/*@internal*/
@@ -886,52 +951,46 @@ namespace ts {
if (endsWith(path, ".d.ts")) {
return path;
}
if (endsWith(path, "/index")) {
if (path === "index" || endsWith(path, "/index")) {
return path + ".d.ts";
}
return path + "/index.d.ts";
}
/* @internal */
export function directoryProbablyExists(directoryName: string, host: { directoryExists?: (directoryName: string) => boolean }): boolean {
// if host does not support 'directoryExists' assume that directory will exist
return !host.directoryExists || host.directoryExists(directoryName);
}
function loadModuleFromFileNoPackageId(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
return noPackageId(loadModuleFromFile(extensions, candidate, failedLookupLocations, onlyRecordFailures, state));
function loadModuleFromFileNoPackageId(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): Resolved | undefined {
return noPackageId(loadModuleFromFile(extensions, candidate, onlyRecordFailures, state));
}
/**
* @param {boolean} onlyRecordFailures - if true then function won't try to actually load files but instead record all attempts as failures. This flag is necessary
* in cases when we know upfront that all load attempts will fail (because containing folder does not exists) however we still need to record all failed lookup locations.
*/
function loadModuleFromFile(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
function loadModuleFromFile(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
if (extensions === Extensions.Json) {
const extensionLess = tryRemoveExtension(candidate, Extension.Json);
return extensionLess === undefined ? undefined : tryAddingExtensions(extensionLess, extensions, failedLookupLocations, onlyRecordFailures, state);
return extensionLess === undefined ? undefined : tryAddingExtensions(extensionLess, extensions, onlyRecordFailures, state);
}
// First, try adding an extension. An import of "foo" could be matched by a file "foo.ts", or "foo.js" by "foo.js.ts"
const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, failedLookupLocations, onlyRecordFailures, state);
const resolvedByAddingExtension = tryAddingExtensions(candidate, extensions, onlyRecordFailures, state);
if (resolvedByAddingExtension) {
return resolvedByAddingExtension;
}
// If that didn't work, try stripping a ".js" or ".jsx" extension and replacing it with a TypeScript one;
// e.g. "./foo.js" can be matched by "./foo.ts" or "./foo.d.ts"
if (hasJavaScriptFileExtension(candidate)) {
if (hasJSFileExtension(candidate)) {
const extensionless = removeFileExtension(candidate);
if (state.traceEnabled) {
const extension = candidate.substring(extensionless.length);
trace(state.host, Diagnostics.File_name_0_has_a_1_extension_stripping_it, candidate, extension);
}
return tryAddingExtensions(extensionless, extensions, failedLookupLocations, onlyRecordFailures, state);
return tryAddingExtensions(extensionless, extensions, onlyRecordFailures, state);
}
}
/** Try to return an existing file that adds one of the `extensions` to `candidate`. */
function tryAddingExtensions(candidate: string, extensions: Extensions, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
function tryAddingExtensions(candidate: string, extensions: Extensions, onlyRecordFailures: boolean, state: ModuleResolutionState): PathAndExtension | undefined {
if (!onlyRecordFailures) {
// check if containing folder exists - if it doesn't then just record failures for all supported extensions without disk probing
const directory = getDirectoryPath(candidate);
@@ -952,13 +1011,13 @@ namespace ts {
}
function tryExtension(ext: Extension): PathAndExtension | undefined {
const path = tryFile(candidate + ext, failedLookupLocations, onlyRecordFailures, state);
const path = tryFile(candidate + ext, onlyRecordFailures, state);
return path === undefined ? undefined : { path, ext };
}
}
/** Return the file if it exists. */
function tryFile(fileName: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined {
function tryFile(fileName: string, onlyRecordFailures: boolean, state: ModuleResolutionState): string | undefined {
if (!onlyRecordFailures) {
if (state.host.fileExists(fileName)) {
if (state.traceEnabled) {
@@ -972,48 +1031,40 @@ namespace ts {
}
}
}
failedLookupLocations.push(fileName);
state.failedLookupLocations.push(fileName);
return undefined;
}
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true) {
const { packageJsonContent, packageId } = considerPackageJson
? getPackageJsonInfo(candidate, "", failedLookupLocations, onlyRecordFailures, state)
: { packageJsonContent: undefined, packageId: undefined };
return withPackageId(packageId, loadNodeModuleFromDirectoryWorker(extensions, candidate, failedLookupLocations, onlyRecordFailures, state, packageJsonContent));
function loadNodeModuleFromDirectory(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, considerPackageJson = true) {
const packageInfo = considerPackageJson ? getPackageJsonInfo(candidate, "", onlyRecordFailures, state) : undefined;
const packageId = packageInfo && packageInfo.packageId;
const packageJsonContent = packageInfo && packageInfo.packageJsonContent;
const versionPaths = packageJsonContent && readPackageJsonTypesVersionPaths(packageJsonContent, state);
return withPackageId(packageId, loadNodeModuleFromDirectoryWorker(extensions, candidate, onlyRecordFailures, state, packageJsonContent, versionPaths));
}
function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, onlyRecordFailures: boolean, state: ModuleResolutionState, packageJsonContent: PackageJsonPathFields | undefined): PathAndExtension | undefined {
const fromPackageJson = packageJsonContent && loadModuleFromPackageJson(packageJsonContent, extensions, candidate, failedLookupLocations, state);
if (fromPackageJson) {
return fromPackageJson;
}
const directoryExists = !onlyRecordFailures && directoryProbablyExists(candidate, state.host);
return loadModuleFromFile(extensions, combinePaths(candidate, "index"), failedLookupLocations, !directoryExists, state);
interface PackageJsonInfo {
packageJsonContent: PackageJsonPathFields | undefined;
packageId: PackageId | undefined;
versionPaths: VersionPaths | undefined;
}
function getPackageJsonInfo(
nodeModuleDirectory: string,
subModuleName: string,
failedLookupLocations: Push<string>,
onlyRecordFailures: boolean,
state: ModuleResolutionState,
): { found: boolean, packageJsonContent: PackageJsonPathFields | undefined, packageId: PackageId | undefined } {
function getPackageJsonInfo(packageDirectory: string, subModuleName: string, onlyRecordFailures: boolean, state: ModuleResolutionState): PackageJsonInfo | undefined {
const { host, traceEnabled } = state;
const directoryExists = !onlyRecordFailures && directoryProbablyExists(nodeModuleDirectory, host);
const packageJsonPath = pathToPackageJson(nodeModuleDirectory);
const directoryExists = !onlyRecordFailures && directoryProbablyExists(packageDirectory, host);
const packageJsonPath = combinePaths(packageDirectory, "package.json");
if (directoryExists && host.fileExists(packageJsonPath)) {
const packageJsonContent = readJson(packageJsonPath, host) as PackageJson;
if (subModuleName === "") { // looking up the root - need to handle types/typings/main redirects for subModuleName
const path = tryReadPackageJsonFields(/*readTypes*/ true, packageJsonContent, nodeModuleDirectory, state);
const path = readPackageJsonTypesFields(packageJsonContent, packageDirectory, state);
if (typeof path === "string") {
subModuleName = addExtensionAndIndex(path.substring(nodeModuleDirectory.length + 1));
subModuleName = addExtensionAndIndex(path.substring(packageDirectory.length + 1));
}
else {
const jsPath = tryReadPackageJsonFields(/*readTypes*/ false, packageJsonContent, nodeModuleDirectory, state);
if (typeof jsPath === "string" && jsPath.length > nodeModuleDirectory.length) {
const potentialSubModule = jsPath.substring(nodeModuleDirectory.length + 1);
subModuleName = (forEach(supportedJavascriptExtensions, extension =>
const jsPath = readPackageJsonMainField(packageJsonContent, packageDirectory, state);
if (typeof jsPath === "string" && jsPath.length > packageDirectory.length) {
const potentialSubModule = jsPath.substring(packageDirectory.length + 1);
subModuleName = (forEach(supportedJSExtensions, extension =>
tryRemoveExtension(potentialSubModule, extension)) || potentialSubModule) + Extension.Dts;
}
else {
@@ -1021,9 +1072,12 @@ namespace ts {
}
}
}
if (!endsWith(subModuleName, Extension.Dts)) {
subModuleName = addExtensionAndIndex(subModuleName);
}
const versionPaths = readPackageJsonTypesVersionPaths(packageJsonContent, state);
const packageId: PackageId | undefined = typeof packageJsonContent.name === "string" && typeof packageJsonContent.version === "string"
? { name: packageJsonContent.name, subModuleName, version: packageJsonContent.version }
: undefined;
@@ -1035,54 +1089,64 @@ namespace ts {
trace(host, Diagnostics.Found_package_json_at_0, packageJsonPath);
}
}
return { found: true, packageJsonContent, packageId };
return { packageJsonContent, packageId, versionPaths };
}
else {
if (directoryExists && traceEnabled) {
trace(host, Diagnostics.File_0_does_not_exist, packageJsonPath);
}
// record package json as one of failed lookup locations - in the future if this file will appear it will invalidate resolution results
failedLookupLocations.push(packageJsonPath);
return { found: false, packageJsonContent: undefined, packageId: undefined };
state.failedLookupLocations.push(packageJsonPath);
}
}
function loadModuleFromPackageJson(jsonContent: PackageJsonPathFields, extensions: Extensions, candidate: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): PathAndExtension | undefined {
let file = tryReadPackageJsonFields(extensions !== Extensions.JavaScript && extensions !== Extensions.Json, jsonContent, candidate, state);
if (!file) {
if (extensions === Extensions.TypeScript) {
function loadNodeModuleFromDirectoryWorker(extensions: Extensions, candidate: string, onlyRecordFailures: boolean, state: ModuleResolutionState, jsonContent: PackageJsonPathFields | undefined, versionPaths: VersionPaths | undefined): PathAndExtension | undefined {
const packageFile = jsonContent && (extensions !== Extensions.JavaScript && extensions !== Extensions.Json
? readPackageJsonTypesFields(jsonContent, candidate, state) ||
// When resolving typescript modules, try resolving using main field as well
file = tryReadPackageJsonFields(/*readTypes*/ false, jsonContent, candidate, state);
if (!file) {
return undefined;
(extensions === Extensions.TypeScript ? readPackageJsonMainField(jsonContent, candidate, state) : undefined)
: readPackageJsonMainField(jsonContent, candidate, state));
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => {
const fromFile = tryFile(candidate, onlyRecordFailures, state);
if (fromFile) {
const resolved = resolvedIfExtensionMatches(extensions, fromFile);
if (resolved) {
return noPackageId(resolved);
}
if (state.traceEnabled) {
trace(state.host, Diagnostics.File_0_has_an_unsupported_extension_so_skipping_it, fromFile);
}
}
else {
return undefined;
}
}
const onlyRecordFailures = !directoryProbablyExists(getDirectoryPath(file), state.host);
const fromFile = tryFile(file, failedLookupLocations, onlyRecordFailures, state);
if (fromFile) {
const resolved = resolvedIfExtensionMatches(extensions, fromFile);
if (resolved) {
return resolved;
}
// Even if extensions is DtsOnly, we can still look up a .ts file as a result of package.json "types"
const nextExtensions = extensions === Extensions.DtsOnly ? Extensions.TypeScript : extensions;
// Don't do package.json lookup recursively, because Node.js' package lookup doesn't.
return nodeLoadModuleByRelativeName(nextExtensions, candidate, onlyRecordFailures, state, /*considerPackageJson*/ false);
};
const onlyRecordFailuresForPackageFile = packageFile ? !directoryProbablyExists(getDirectoryPath(packageFile), state.host) : undefined;
const onlyRecordFailuresForIndex = onlyRecordFailures || !directoryProbablyExists(candidate, state.host);
const indexPath = combinePaths(candidate, "index");
if (versionPaths && (!packageFile || containsPath(candidate, packageFile))) {
const moduleName = getRelativePathFromDirectory(candidate, packageFile || indexPath, /*ignoreCase*/ false);
if (state.traceEnabled) {
trace(state.host, Diagnostics.File_0_has_an_unsupported_extension_so_skipping_it, fromFile);
trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, versionPaths.version, version, moduleName);
}
const result = tryLoadModuleUsingPaths(extensions, moduleName, candidate, versionPaths.paths, loader, onlyRecordFailuresForPackageFile || onlyRecordFailuresForIndex, state);
if (result) {
return removeIgnoredPackageId(result.value);
}
}
// Even if extensions is DtsOnly, we can still look up a .ts file as a result of package.json "types"
const nextExtensions = extensions === Extensions.DtsOnly ? Extensions.TypeScript : extensions;
// Don't do package.json lookup recursively, because Node.js' package lookup doesn't.
const result = nodeLoadModuleByRelativeName(nextExtensions, file, failedLookupLocations, onlyRecordFailures, state, /*considerPackageJson*/ false);
if (result) {
// It won't have a `packageId` set, because we disabled `considerPackageJson`.
Debug.assert(result.packageId === undefined);
return { path: result.path, ext: result.extension };
}
// It won't have a `packageId` set, because we disabled `considerPackageJson`.
const packageFileResult = packageFile && removeIgnoredPackageId(loader(extensions, packageFile, onlyRecordFailuresForPackageFile!, state));
if (packageFileResult) return packageFileResult;
return loadModuleFromFile(extensions, indexPath, onlyRecordFailuresForIndex, state);
}
/** Resolve from an arbitrarily specified file. Return `undefined` if it has an unsupported extension. */
@@ -1105,34 +1169,8 @@ namespace ts {
}
}
function pathToPackageJson(directory: string): string {
return combinePaths(directory, "package.json");
}
function loadModuleFromNodeModulesFolder(extensions: Extensions, moduleName: string, nodeModulesFolder: string, nodeModulesFolderExists: boolean, failedLookupLocations: Push<string>, state: ModuleResolutionState): Resolved | undefined {
const candidate = normalizePath(combinePaths(nodeModulesFolder, moduleName));
// First look for a nested package.json, as in `node_modules/foo/bar/package.json`.
let packageJsonContent: PackageJsonPathFields | undefined;
let packageId: PackageId | undefined;
const packageInfo = getPackageJsonInfo(candidate, "", failedLookupLocations, /*onlyRecordFailures*/ !nodeModulesFolderExists, state);
if (packageInfo.found) {
({ packageJsonContent, packageId } = packageInfo);
}
else {
const { packageName, rest } = getPackageName(moduleName);
if (rest !== "") { // If "rest" is empty, we just did this search above.
const packageRootPath = combinePaths(nodeModulesFolder, packageName);
// Don't use a "types" or "main" from here because we're not loading the root, but a subdirectory -- just here for the packageId.
packageId = getPackageJsonInfo(packageRootPath, rest, failedLookupLocations, !nodeModulesFolderExists, state).packageId;
}
}
const pathAndExtension = loadModuleFromFile(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state) ||
loadNodeModuleFromDirectoryWorker(extensions, candidate, failedLookupLocations, !nodeModulesFolderExists, state, packageJsonContent);
return withPackageId(packageId, pathAndExtension);
}
/* @internal */
export function getPackageName(moduleName: string): { packageName: string, rest: string } {
export function parsePackageName(moduleName: string): { packageName: string, rest: string } {
let idx = moduleName.indexOf(directorySeparator);
if (moduleName[0] === "@") {
idx = moduleName.indexOf(directorySeparator, idx + 1);
@@ -1140,36 +1178,36 @@ namespace ts {
return idx === -1 ? { packageName: moduleName, rest: "" } : { packageName: moduleName.slice(0, idx), rest: moduleName.slice(idx + 1) };
}
function loadModuleFromNodeModules(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, cache: NonRelativeModuleNameResolutionCache | undefined): SearchResult<Resolved> {
return loadModuleFromNodeModulesWorker(extensions, moduleName, directory, failedLookupLocations, state, /*typesOnly*/ false, cache);
}
function loadModuleFromNodeModulesAtTypes(moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState): SearchResult<Resolved> {
// Extensions parameter here doesn't actually matter, because typesOnly ensures we're just doing @types lookup, which is always DtsOnly.
return loadModuleFromNodeModulesWorker(Extensions.DtsOnly, moduleName, directory, failedLookupLocations, state, /*typesOnly*/ true, /*cache*/ undefined);
function loadModuleFromNearestNodeModulesDirectory(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, cache: NonRelativeModuleNameResolutionCache | undefined): SearchResult<Resolved> {
return loadModuleFromNearestNodeModulesDirectoryWorker(extensions, moduleName, directory, state, /*typesScopeOnly*/ false, cache);
}
function loadModuleFromNodeModulesWorker(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, typesOnly: boolean, cache: NonRelativeModuleNameResolutionCache | undefined): SearchResult<Resolved> {
function loadModuleFromNearestNodeModulesDirectoryTypesScope(moduleName: string, directory: string, state: ModuleResolutionState): SearchResult<Resolved> {
// Extensions parameter here doesn't actually matter, because typesOnly ensures we're just doing @types lookup, which is always DtsOnly.
return loadModuleFromNearestNodeModulesDirectoryWorker(Extensions.DtsOnly, moduleName, directory, state, /*typesScopeOnly*/ true, /*cache*/ undefined);
}
function loadModuleFromNearestNodeModulesDirectoryWorker(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, typesScopeOnly: boolean, cache: NonRelativeModuleNameResolutionCache | undefined): SearchResult<Resolved> {
const perModuleNameCache = cache && cache.getOrCreateCacheForModuleName(moduleName);
return forEachAncestorDirectory(normalizeSlashes(directory), ancestorDirectory => {
if (getBaseFileName(ancestorDirectory) !== "node_modules") {
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, ancestorDirectory, state.traceEnabled, state.host, failedLookupLocations);
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, ancestorDirectory, state);
if (resolutionFromCache) {
return resolutionFromCache;
}
return toSearchResult(loadModuleFromNodeModulesOneLevel(extensions, moduleName, ancestorDirectory, failedLookupLocations, state, typesOnly));
return toSearchResult(loadModuleFromImmediateNodeModulesDirectory(extensions, moduleName, ancestorDirectory, state, typesScopeOnly));
}
});
}
/** Load a module from a single node_modules directory, but not from any ancestors' node_modules directories. */
function loadModuleFromNodeModulesOneLevel(extensions: Extensions, moduleName: string, directory: string, failedLookupLocations: Push<string>, state: ModuleResolutionState, typesOnly = false): Resolved | undefined {
function loadModuleFromImmediateNodeModulesDirectory(extensions: Extensions, moduleName: string, directory: string, state: ModuleResolutionState, typesScopeOnly: boolean): Resolved | undefined {
const nodeModulesFolder = combinePaths(directory, "node_modules");
const nodeModulesFolderExists = directoryProbablyExists(nodeModulesFolder, state.host);
if (!nodeModulesFolderExists && state.traceEnabled) {
trace(state.host, Diagnostics.Directory_0_does_not_exist_skipping_all_lookups_in_it, nodeModulesFolder);
}
const packageResult = typesOnly ? undefined : loadModuleFromNodeModulesFolder(extensions, moduleName, nodeModulesFolder, nodeModulesFolderExists, failedLookupLocations, state);
const packageResult = typesScopeOnly ? undefined : loadModuleFromSpecificNodeModulesDirectory(extensions, moduleName, nodeModulesFolder, nodeModulesFolderExists, state);
if (packageResult) {
return packageResult;
}
@@ -1182,7 +1220,84 @@ namespace ts {
}
nodeModulesAtTypesExists = false;
}
return loadModuleFromNodeModulesFolder(Extensions.DtsOnly, mangleScopedPackage(moduleName, state), nodeModulesAtTypes, nodeModulesAtTypesExists, failedLookupLocations, state);
return loadModuleFromSpecificNodeModulesDirectory(Extensions.DtsOnly, mangleScopedPackageNameWithTrace(moduleName, state), nodeModulesAtTypes, nodeModulesAtTypesExists, state);
}
}
function loadModuleFromSpecificNodeModulesDirectory(extensions: Extensions, moduleName: string, nodeModulesDirectory: string, nodeModulesDirectoryExists: boolean, state: ModuleResolutionState): Resolved | undefined {
const candidate = normalizePath(combinePaths(nodeModulesDirectory, moduleName));
// First look for a nested package.json, as in `node_modules/foo/bar/package.json`.
let packageJsonContent: PackageJsonPathFields | undefined;
let packageId: PackageId | undefined;
let versionPaths: VersionPaths | undefined;
const packageInfo = getPackageJsonInfo(candidate, "", !nodeModulesDirectoryExists, state);
if (packageInfo) {
({ packageJsonContent, packageId, versionPaths } = packageInfo);
const fromFile = loadModuleFromFile(extensions, candidate, !nodeModulesDirectoryExists, state);
if (fromFile) {
return noPackageId(fromFile);
}
const fromDirectory = loadNodeModuleFromDirectoryWorker(extensions, candidate, !nodeModulesDirectoryExists, state, packageJsonContent, versionPaths);
return withPackageId(packageId, fromDirectory);
}
const loader: ResolutionKindSpecificLoader = (extensions, candidate, onlyRecordFailures, state) => {
const pathAndExtension =
loadModuleFromFile(extensions, candidate, onlyRecordFailures, state) ||
loadNodeModuleFromDirectoryWorker(extensions, candidate, onlyRecordFailures, state, packageJsonContent, versionPaths);
return withPackageId(packageId, pathAndExtension);
};
const { packageName, rest } = parsePackageName(moduleName);
if (rest !== "") { // If "rest" is empty, we just did this search above.
const packageDirectory = combinePaths(nodeModulesDirectory, packageName);
// Don't use a "types" or "main" from here because we're not loading the root, but a subdirectory -- just here for the packageId and path mappings.
const packageInfo = getPackageJsonInfo(packageDirectory, rest, !nodeModulesDirectoryExists, state);
if (packageInfo) ({ packageId, versionPaths } = packageInfo);
if (versionPaths) {
if (state.traceEnabled) {
trace(state.host, Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2, versionPaths.version, version, rest);
}
const packageDirectoryExists = nodeModulesDirectoryExists && directoryProbablyExists(packageDirectory, state.host);
const fromPaths = tryLoadModuleUsingPaths(extensions, rest, packageDirectory, versionPaths.paths, loader, !packageDirectoryExists, state);
if (fromPaths) {
return fromPaths.value;
}
}
}
return loader(extensions, candidate, !nodeModulesDirectoryExists, state);
}
function tryLoadModuleUsingPaths(extensions: Extensions, moduleName: string, baseDirectory: string, paths: MapLike<string[]>, loader: ResolutionKindSpecificLoader, onlyRecordFailures: boolean, state: ModuleResolutionState): SearchResult<Resolved> {
const matchedPattern = matchPatternOrExact(getOwnKeys(paths), moduleName);
if (matchedPattern) {
const matchedStar = isString(matchedPattern) ? undefined : matchedText(matchedPattern, moduleName);
const matchedPatternText = isString(matchedPattern) ? matchedPattern : patternText(matchedPattern);
if (state.traceEnabled) {
trace(state.host, Diagnostics.Module_name_0_matched_pattern_1, moduleName, matchedPatternText);
}
const resolved = forEach(paths[matchedPatternText], subst => {
const path = matchedStar ? subst.replace("*", matchedStar) : subst;
const candidate = normalizePath(combinePaths(baseDirectory, path));
if (state.traceEnabled) {
trace(state.host, Diagnostics.Trying_substitution_0_candidate_module_location_Colon_1, subst, path);
}
// A path mapping may have an extension, in contrast to an import, which should omit it.
const extension = tryGetExtensionFromPath(candidate);
if (extension !== undefined) {
const path = tryFile(candidate, onlyRecordFailures, state);
if (path !== undefined) {
return noPackageId({ path, ext: extension });
}
}
return loader(extensions, candidate, onlyRecordFailures || !directoryProbablyExists(getDirectoryPath(candidate), state.host), state);
});
return { value: resolved };
}
}
@@ -1190,8 +1305,8 @@ namespace ts {
const mangledScopedPackageSeparator = "__";
/** For a scoped package, we must look in `@types/foo__bar` instead of `@types/@foo/bar`. */
function mangleScopedPackage(packageName: string, state: ModuleResolutionState): string {
const mangled = getMangledNameForScopedPackage(packageName);
function mangleScopedPackageNameWithTrace(packageName: string, state: ModuleResolutionState): string {
const mangled = mangleScopedPackageName(packageName);
if (state.traceEnabled && mangled !== packageName) {
trace(state.host, Diagnostics.Scoped_package_detected_looking_in_0, mangled);
}
@@ -1200,11 +1315,11 @@ namespace ts {
/* @internal */
export function getTypesPackageName(packageName: string): string {
return `@types/${getMangledNameForScopedPackage(packageName)}`;
return `@types/${mangleScopedPackageName(packageName)}`;
}
/* @internal */
export function getMangledNameForScopedPackage(packageName: string): string {
export function mangleScopedPackageName(packageName: string): string {
if (startsWith(packageName, "@")) {
const replaceSlash = packageName.replace(directorySeparator, mangledScopedPackageSeparator);
if (replaceSlash !== packageName) {
@@ -1215,36 +1330,36 @@ namespace ts {
}
/* @internal */
export function getPackageNameFromAtTypesDirectory(mangledName: string): string {
export function getPackageNameFromTypesPackageName(mangledName: string): string {
const withoutAtTypePrefix = removePrefix(mangledName, "@types/");
if (withoutAtTypePrefix !== mangledName) {
return getUnmangledNameForScopedPackage(withoutAtTypePrefix);
return unmangleScopedPackageName(withoutAtTypePrefix);
}
return mangledName;
}
/* @internal */
export function getUnmangledNameForScopedPackage(typesPackageName: string): string {
export function unmangleScopedPackageName(typesPackageName: string): string {
return stringContains(typesPackageName, mangledScopedPackageSeparator) ?
"@" + typesPackageName.replace(mangledScopedPackageSeparator, directorySeparator) :
typesPackageName;
}
function tryFindNonRelativeModuleNameInCache(cache: PerModuleNameCache | undefined, moduleName: string, containingDirectory: string, traceEnabled: boolean, host: ModuleResolutionHost, failedLookupLocations: Push<string>): SearchResult<Resolved> {
function tryFindNonRelativeModuleNameInCache(cache: PerModuleNameCache | undefined, moduleName: string, containingDirectory: string, state: ModuleResolutionState): SearchResult<Resolved> {
const result = cache && cache.get(containingDirectory);
if (result) {
if (traceEnabled) {
trace(host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory);
if (state.traceEnabled) {
trace(state.host, Diagnostics.Resolution_for_module_0_was_found_in_cache_from_location_1, moduleName, containingDirectory);
}
failedLookupLocations.push(...result.failedLookupLocations);
state.failedLookupLocations.push(...result.failedLookupLocations);
return { value: result.resolvedModule && { path: result.resolvedModule.resolvedFileName, originalPath: result.resolvedModule.originalPath || true, extension: result.resolvedModule.extension, packageId: result.resolvedModule.packageId } };
}
}
export function classicNameResolver(moduleName: string, containingFile: string, compilerOptions: CompilerOptions, host: ModuleResolutionHost, cache?: NonRelativeModuleNameResolutionCache): ResolvedModuleWithFailedLookupLocations {
const traceEnabled = isTraceEnabled(compilerOptions, host);
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled };
const failedLookupLocations: string[] = [];
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations };
const containingDirectory = getDirectoryPath(containingFile);
const resolved = tryResolve(Extensions.TypeScript) || tryResolve(Extensions.JavaScript);
@@ -1252,7 +1367,7 @@ namespace ts {
return createResolvedModuleWithFailedLookupLocations(resolved && resolved.value, /*isExternalLibraryImport*/ false, failedLookupLocations);
function tryResolve(extensions: Extensions): SearchResult<Resolved> {
const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, failedLookupLocations, state);
const resolvedUsingSettings = tryLoadModuleUsingOptionalResolutionSettings(extensions, moduleName, containingDirectory, loadModuleFromFileNoPackageId, state);
if (resolvedUsingSettings) {
return { value: resolvedUsingSettings };
}
@@ -1261,24 +1376,24 @@ namespace ts {
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);
const resolutionFromCache = tryFindNonRelativeModuleNameInCache(perModuleNameCache, moduleName, directory, state);
if (resolutionFromCache) {
return resolutionFromCache;
}
const searchName = normalizePath(combinePaths(directory, moduleName));
return toSearchResult(loadModuleFromFileNoPackageId(extensions, searchName, failedLookupLocations, /*onlyRecordFailures*/ false, state));
return toSearchResult(loadModuleFromFileNoPackageId(extensions, searchName, /*onlyRecordFailures*/ false, state));
});
if (resolved) {
return resolved;
}
if (extensions === Extensions.TypeScript) {
// If we didn't find the file normally, look it up in @types.
return loadModuleFromNodeModulesAtTypes(moduleName, containingDirectory, failedLookupLocations, state);
return loadModuleFromNearestNodeModulesDirectoryTypesScope(moduleName, containingDirectory, state);
}
}
else {
const candidate = normalizePath(combinePaths(containingDirectory, moduleName));
return toSearchResult(loadModuleFromFileNoPackageId(extensions, candidate, failedLookupLocations, /*onlyRecordFailures*/ false, state));
return toSearchResult(loadModuleFromFileNoPackageId(extensions, candidate, /*onlyRecordFailures*/ false, state));
}
}
}
@@ -1293,9 +1408,9 @@ namespace ts {
if (traceEnabled) {
trace(host, Diagnostics.Auto_discovery_for_typings_is_enabled_in_project_0_Running_extra_resolution_pass_for_module_1_using_cache_location_2, projectName, moduleName, globalCache);
}
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled };
const failedLookupLocations: string[] = [];
const resolved = loadModuleFromNodeModulesOneLevel(Extensions.DtsOnly, moduleName, globalCache, failedLookupLocations, state);
const state: ModuleResolutionState = { compilerOptions, host, traceEnabled, failedLookupLocations };
const resolved = loadModuleFromImmediateNodeModulesDirectory(Extensions.DtsOnly, moduleName, globalCache, state, /*typesScopeOnly*/ false);
return createResolvedModuleWithFailedLookupLocations(resolved, /*isExternalLibraryImport*/ true, failedLookupLocations);
}
+38 -18
View File
@@ -30,7 +30,7 @@ namespace ts.moduleSpecifiers {
function getPreferencesForUpdate(compilerOptions: CompilerOptions, oldImportSpecifier: string): Preferences {
return {
relativePreference: isExternalModuleNameRelative(oldImportSpecifier) ? RelativePreference.Relative : RelativePreference.NonRelative,
ending: hasJavaScriptOrJsonFileExtension(oldImportSpecifier) ? Ending.JsExtension
ending: hasJSOrJsonFileExtension(oldImportSpecifier) ? Ending.JsExtension
: getEmitModuleResolutionKind(compilerOptions) !== ModuleResolutionKind.NodeJs || endsWith(oldImportSpecifier, "index") ? Ending.Index : Ending.Minimal,
};
}
@@ -148,7 +148,7 @@ namespace ts.moduleSpecifiers {
}
function usesJsExtensionOnImports({ imports }: SourceFile): boolean {
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? hasJavaScriptOrJsonFileExtension(text) : undefined) || false;
return firstDefined(imports, ({ text }) => pathIsRelative(text) ? hasJSOrJsonFileExtension(text) : undefined) || false;
}
function stringsEqual(a: string, b: string, getCanonicalFileName: GetCanonicalFileName): boolean {
@@ -235,7 +235,8 @@ namespace ts.moduleSpecifiers {
const suffix = pattern.substr(indexOfStar + 1);
if (relativeToBaseUrl.length >= prefix.length + suffix.length &&
startsWith(relativeToBaseUrl, prefix) &&
endsWith(relativeToBaseUrl, suffix)) {
endsWith(relativeToBaseUrl, suffix) ||
!suffix && relativeToBaseUrl === removeTrailingDirectorySeparator(prefix)) {
const matchedStar = relativeToBaseUrl.substr(prefix.length, relativeToBaseUrl.length - suffix.length);
return key.replace("*", matchedStar);
}
@@ -259,11 +260,34 @@ namespace ts.moduleSpecifiers {
}
function tryGetModuleNameAsNodeModule(moduleFileName: string, { getCanonicalFileName, sourceDirectory }: Info, host: ModuleSpecifierResolutionHost, options: CompilerOptions): string | undefined {
if (!host.fileExists || !host.readFile) {
return undefined;
}
const parts: NodeModulePathParts = getNodeModulePathParts(moduleFileName)!;
if (!parts) {
return undefined;
}
const packageRootPath = moduleFileName.substring(0, parts.packageRootIndex);
const packageJsonPath = combinePaths(packageRootPath, "package.json");
const packageJsonContent = host.fileExists(packageJsonPath)
? JSON.parse(host.readFile(packageJsonPath)!)
: undefined;
const versionPaths = packageJsonContent && packageJsonContent.typesVersions
? getPackageJsonTypesVersionsPaths(packageJsonContent.typesVersions)
: undefined;
if (versionPaths) {
const subModuleName = moduleFileName.slice(parts.packageRootIndex + 1);
const fromPaths = tryGetModuleNameFromPaths(
removeFileExtension(subModuleName),
removeExtensionAndIndexPostFix(subModuleName, Ending.Minimal, options),
versionPaths.paths
);
if (fromPaths !== undefined) {
moduleFileName = combinePaths(moduleFileName.slice(0, parts.packageRootIndex), fromPaths);
}
}
// Simplify the full file path to something that can be resolved by Node.
// If the module could be imported by a directory name, use that directory's name
@@ -274,23 +298,18 @@ namespace ts.moduleSpecifiers {
// If the module was found in @types, get the actual Node package name
const nodeModulesDirectoryName = moduleSpecifier.substring(parts.topLevelPackageNameIndex + 1);
const packageName = getPackageNameFromAtTypesDirectory(nodeModulesDirectoryName);
const packageName = getPackageNameFromTypesPackageName(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
const packageRootPath = path.substring(0, parts.packageRootIndex);
const packageJsonPath = combinePaths(packageRootPath, "package.json");
if (host.fileExists!(packageJsonPath)) { // TODO: GH#18217
const packageJsonContent = JSON.parse(host.readFile!(packageJsonPath)!);
if (packageJsonContent) {
const mainFileRelative = packageJsonContent.typings || packageJsonContent.types || packageJsonContent.main;
if (mainFileRelative) {
const mainExportFile = toPath(mainFileRelative, packageRootPath, getCanonicalFileName);
if (removeFileExtension(mainExportFile) === removeFileExtension(getCanonicalFileName(path))) {
return packageRootPath;
}
if (packageJsonContent) {
const mainFileRelative = packageJsonContent.typings || packageJsonContent.types || packageJsonContent.main;
if (mainFileRelative) {
const mainExportFile = toPath(mainFileRelative, packageRootPath, getCanonicalFileName);
if (removeFileExtension(mainExportFile) === removeFileExtension(getCanonicalFileName(path))) {
return packageRootPath;
}
}
}
@@ -309,11 +328,12 @@ namespace ts.moduleSpecifiers {
}
function tryGetAnyFileFromPath(host: ModuleSpecifierResolutionHost, path: string) {
if (!host.fileExists) return;
// We check all js, `node` and `json` extensions in addition to TS, since node module resolution would also choose those over the directory
const extensions = getSupportedExtensions({ allowJs: true }, [{ extension: "node", isMixedContent: false }, { extension: "json", isMixedContent: false, scriptKind: ScriptKind.JSON }]);
for (const e of extensions) {
const fullPath = path + e;
if (host.fileExists!(fullPath)) { // TODO: GH#18217
if (host.fileExists(fullPath)) {
return fullPath;
}
}
@@ -399,13 +419,13 @@ namespace ts.moduleSpecifiers {
case Ending.Index:
return noExtension;
case Ending.JsExtension:
return noExtension + getJavaScriptExtensionForFile(fileName, options);
return noExtension + getJSExtensionForFile(fileName, options);
default:
return Debug.assertNever(ending);
}
}
function getJavaScriptExtensionForFile(fileName: string, options: CompilerOptions): Extension {
function getJSExtensionForFile(fileName: string, options: CompilerOptions): Extension {
const ext = extensionFromPath(fileName);
switch (ext) {
case Extension.Ts:
+39 -39
View File
@@ -1482,7 +1482,15 @@ namespace ts {
// which would be a candidate for improved error reporting.
return token() === SyntaxKind.OpenBracketToken || isLiteralPropertyName();
case ParsingContext.ObjectLiteralMembers:
return token() === SyntaxKind.OpenBracketToken || token() === SyntaxKind.AsteriskToken || token() === SyntaxKind.DotDotDotToken || isLiteralPropertyName();
switch (token()) {
case SyntaxKind.OpenBracketToken:
case SyntaxKind.AsteriskToken:
case SyntaxKind.DotDotDotToken:
case SyntaxKind.DotToken: // Not an object literal member, but don't want to close the object (see `tests/cases/fourslash/completionsDotInObjectLiteral.ts`)
return true;
default:
return isLiteralPropertyName();
}
case ParsingContext.RestProperties:
return isLiteralPropertyName();
case ParsingContext.ObjectBindingElements:
@@ -6308,7 +6316,7 @@ namespace ts {
// Parses out a JSDoc type expression.
export function parseJSDocTypeExpression(mayOmitBraces?: boolean): JSDocTypeExpression {
const result = <JSDocTypeExpression>createNode(SyntaxKind.JSDocTypeExpression, scanner.getTokenPos());
const result = <JSDocTypeExpression>createNode(SyntaxKind.JSDocTypeExpression);
const hasBrace = (mayOmitBraces ? parseOptional : parseExpected)(SyntaxKind.OpenBraceToken);
result.type = doInsideOfContext(NodeFlags.JSDoc, parseJSDocType);
@@ -6441,13 +6449,6 @@ namespace ts {
indent += asterisk.length;
}
break;
case SyntaxKind.Identifier:
// Anything else is doc comment text. We just save it. Because it
// wasn't a tag, we can no longer parse a tag on this line until we hit the next
// line break.
pushComment(scanner.getTokenText());
state = JSDocState.SavingComments;
break;
case SyntaxKind.WhitespaceTrivia:
// only collect whitespace if we're already saving comments or have just crossed the comment indent margin
const whitespace = scanner.getTokenText();
@@ -6462,7 +6463,9 @@ namespace ts {
case SyntaxKind.EndOfFileToken:
break loop;
default:
// anything other than whitespace or asterisk at the beginning of the line starts the comment text
// Anything else is doc comment text. We just save it. Because it
// wasn't a tag, we can no longer parse a tag on this line until we hit the next
// line break.
state = JSDocState.SavingComments;
pushComment(scanner.getTokenText());
break;
@@ -6542,7 +6545,7 @@ namespace ts {
atToken.end = scanner.getTextPos();
nextJSDocToken();
const tagName = parseJSDocIdentifierName();
const tagName = parseJSDocIdentifierName(/*message*/ undefined);
skipWhitespaceOrAsterisk();
let tag: JSDocTag | undefined;
@@ -6724,7 +6727,7 @@ namespace ts {
}
}
function parseParameterOrPropertyTag(atToken: AtToken, tagName: Identifier, target: PropertyLikeParse, indent: number | undefined): JSDocParameterTag | JSDocPropertyTag {
function parseParameterOrPropertyTag(atToken: AtToken, tagName: Identifier, target: PropertyLikeParse, indent: number): JSDocParameterTag | JSDocPropertyTag {
let typeExpression = tryParseTypeExpression();
let isNameFirst = !typeExpression;
skipWhitespaceOrAsterisk();
@@ -6739,9 +6742,8 @@ namespace ts {
const result = target === PropertyLikeParse.Property ?
<JSDocPropertyTag>createNode(SyntaxKind.JSDocPropertyTag, atToken.pos) :
<JSDocParameterTag>createNode(SyntaxKind.JSDocParameterTag, atToken.pos);
let comment: string | undefined;
if (indent !== undefined) comment = parseTagComments(indent + scanner.getStartPos() - atToken.pos);
const nestedTypeLiteral = target !== PropertyLikeParse.CallbackParameter && parseNestedTypeLiteral(typeExpression, name, target);
const comment = parseTagComments(indent + scanner.getStartPos() - atToken.pos);
const nestedTypeLiteral = target !== PropertyLikeParse.CallbackParameter && parseNestedTypeLiteral(typeExpression, name, target, indent);
if (nestedTypeLiteral) {
typeExpression = nestedTypeLiteral;
isNameFirst = true;
@@ -6756,14 +6758,14 @@ namespace ts {
return finishNode(result);
}
function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression | undefined, name: EntityName, target: PropertyLikeParse) {
function parseNestedTypeLiteral(typeExpression: JSDocTypeExpression | undefined, name: EntityName, target: PropertyLikeParse, indent: number) {
if (typeExpression && isObjectOrObjectArrayTypeReference(typeExpression.type)) {
const typeLiteralExpression = <JSDocTypeExpression>createNode(SyntaxKind.JSDocTypeExpression, scanner.getTokenPos());
let child: JSDocPropertyLikeTag | JSDocTypeTag | false;
let jsdocTypeLiteral: JSDocTypeLiteral;
const start = scanner.getStartPos();
let children: JSDocPropertyLikeTag[] | undefined;
while (child = tryParse(() => parseChildParameterOrPropertyTag(target, name))) {
while (child = tryParse(() => parseChildParameterOrPropertyTag(target, indent, name))) {
if (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) {
children = append(children, child);
}
@@ -6879,7 +6881,7 @@ namespace ts {
let jsdocTypeLiteral: JSDocTypeLiteral | undefined;
let childTypeTag: JSDocTypeTag | undefined;
const start = atToken.pos;
while (child = tryParse(() => parseChildPropertyTag())) {
while (child = tryParse(() => parseChildPropertyTag(indent))) {
if (!jsdocTypeLiteral) {
jsdocTypeLiteral = <JSDocTypeLiteral>createNode(SyntaxKind.JSDocTypeLiteral, start);
}
@@ -6945,7 +6947,7 @@ namespace ts {
const start = scanner.getStartPos();
const jsdocSignature = createNode(SyntaxKind.JSDocSignature, start) as JSDocSignature;
jsdocSignature.parameters = [];
while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter) as JSDocParameterTag)) {
while (child = tryParse(() => parseChildParameterOrPropertyTag(PropertyLikeParse.CallbackParameter, indent) as JSDocParameterTag)) {
jsdocSignature.parameters = append(jsdocSignature.parameters as MutableNodeArray<JSDocParameterTag>, child);
}
const returnTag = tryParse(() => {
@@ -6988,18 +6990,18 @@ namespace ts {
return a.escapedText === b.escapedText;
}
function parseChildPropertyTag() {
return parseChildParameterOrPropertyTag(PropertyLikeParse.Property) as JSDocTypeTag | JSDocPropertyTag | false;
function parseChildPropertyTag(indent: number) {
return parseChildParameterOrPropertyTag(PropertyLikeParse.Property, indent) as JSDocTypeTag | JSDocPropertyTag | false;
}
function parseChildParameterOrPropertyTag(target: PropertyLikeParse, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
function parseChildParameterOrPropertyTag(target: PropertyLikeParse, indent: number, name?: EntityName): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
let canParseTag = true;
let seenAsterisk = false;
while (true) {
switch (nextJSDocToken()) {
case SyntaxKind.AtToken:
if (canParseTag) {
const child = tryParseChildTag(target);
const child = tryParseChildTag(target, indent);
if (child && (child.kind === SyntaxKind.JSDocParameterTag || child.kind === SyntaxKind.JSDocPropertyTag) &&
target !== PropertyLikeParse.CallbackParameter &&
name && (ts.isIdentifier(child.name) || !escapedTextsEqual(name, child.name.left))) {
@@ -7028,7 +7030,7 @@ namespace ts {
}
}
function tryParseChildTag(target: PropertyLikeParse): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
function tryParseChildTag(target: PropertyLikeParse, indent: number): JSDocTypeTag | JSDocPropertyTag | JSDocParameterTag | false {
Debug.assert(token() === SyntaxKind.AtToken);
const atToken = <AtToken>createNode(SyntaxKind.AtToken);
atToken.end = scanner.getTextPos();
@@ -7055,9 +7057,7 @@ namespace ts {
if (!(target & t)) {
return false;
}
const tag = parseParameterOrPropertyTag(atToken, tagName, target, /*indent*/ undefined);
tag.comment = parseTagComments(tag.end - tag.pos);
return tag;
return parseParameterOrPropertyTag(atToken, tagName, target, indent);
}
function parseTemplateTag(atToken: AtToken, tagName: Identifier): JSDocTemplateTag {
@@ -7727,7 +7727,7 @@ namespace ts {
/*@internal*/
export function processCommentPragmas(context: PragmaContext, sourceText: string): void {
const triviaScanner = createScanner(context.languageVersion, /*skipTrivia*/ false, LanguageVariant.Standard, sourceText);
const pragmas: PragmaPsuedoMapEntry[] = [];
const pragmas: PragmaPseudoMapEntry[] = [];
// Keep scanning all the leading trivia in the file until we get to something that
// isn't trivia. Any single line comment will be analyzed to see if it is a
@@ -7782,7 +7782,7 @@ namespace ts {
const referencedFiles = context.referencedFiles;
const typeReferenceDirectives = context.typeReferenceDirectives;
const libReferenceDirectives = context.libReferenceDirectives;
forEach(toArray(entryOrList), (arg: PragmaPsuedoMap["reference"]) => {
forEach(toArray(entryOrList), (arg: PragmaPseudoMap["reference"]) => {
// TODO: GH#18217
if (arg!.arguments["no-default-lib"]) {
context.hasNoDefaultLib = true;
@@ -7805,7 +7805,7 @@ namespace ts {
case "amd-dependency": {
context.amdDependencies = map(
toArray(entryOrList),
(x: PragmaPsuedoMap["amd-dependency"]) => ({ name: x!.arguments.name!, path: x!.arguments.path })); // TODO: GH#18217
(x: PragmaPseudoMap["amd-dependency"]) => ({ name: x!.arguments.name!, path: x!.arguments.path })); // TODO: GH#18217
break;
}
case "amd-module": {
@@ -7815,11 +7815,11 @@ namespace ts {
// TODO: It's probably fine to issue this diagnostic on all instances of the pragma
reportDiagnostic(entry!.range.pos, entry!.range.end - entry!.range.pos, Diagnostics.An_AMD_module_cannot_have_multiple_name_assignments);
}
context.moduleName = (entry as PragmaPsuedoMap["amd-module"])!.arguments.name;
context.moduleName = (entry as PragmaPseudoMap["amd-module"])!.arguments.name;
}
}
else {
context.moduleName = (entryOrList as PragmaPsuedoMap["amd-module"])!.arguments.name;
context.moduleName = (entryOrList as PragmaPseudoMap["amd-module"])!.arguments.name;
}
break;
}
@@ -7855,10 +7855,10 @@ namespace ts {
const tripleSlashXMLCommentStartRegEx = /^\/\/\/\s*<(\S+)\s.*?\/>/im;
const singleLinePragmaRegEx = /^\/\/\/?\s*@(\S+)\s*(.*)\s*$/im;
function extractPragmas(pragmas: PragmaPsuedoMapEntry[], range: CommentRange, text: string) {
function extractPragmas(pragmas: PragmaPseudoMapEntry[], range: CommentRange, text: string) {
const tripleSlash = range.kind === SyntaxKind.SingleLineCommentTrivia && tripleSlashXMLCommentStartRegEx.exec(text);
if (tripleSlash) {
const name = tripleSlash[1].toLowerCase() as keyof PragmaPsuedoMap; // Technically unsafe cast, but we do it so the below check to make it safe typechecks
const name = tripleSlash[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so the below check to make it safe typechecks
const pragma = commentPragmas[name] as PragmaDefinition;
if (!pragma || !(pragma.kind! & PragmaKindFlags.TripleSlashXML)) {
return;
@@ -7885,10 +7885,10 @@ namespace ts {
}
}
}
pragmas.push({ name, args: { arguments: argument, range } } as PragmaPsuedoMapEntry);
pragmas.push({ name, args: { arguments: argument, range } } as PragmaPseudoMapEntry);
}
else {
pragmas.push({ name, args: { arguments: {}, range } } as PragmaPsuedoMapEntry);
pragmas.push({ name, args: { arguments: {}, range } } as PragmaPseudoMapEntry);
}
return;
}
@@ -7907,9 +7907,9 @@ namespace ts {
}
}
function addPragmaForMatch(pragmas: PragmaPsuedoMapEntry[], range: CommentRange, kind: PragmaKindFlags, match: RegExpExecArray) {
function addPragmaForMatch(pragmas: PragmaPseudoMapEntry[], range: CommentRange, kind: PragmaKindFlags, match: RegExpExecArray) {
if (!match) return;
const name = match[1].toLowerCase() as keyof PragmaPsuedoMap; // Technically unsafe cast, but we do it so they below check to make it safe typechecks
const name = match[1].toLowerCase() as keyof PragmaPseudoMap; // Technically unsafe cast, but we do it so they below check to make it safe typechecks
const pragma = commentPragmas[name] as PragmaDefinition;
if (!pragma || !(pragma.kind! & kind)) {
return;
@@ -7917,7 +7917,7 @@ namespace ts {
const args = match[2]; // Split on spaces and match up positionally with definition
const argument = getNamedPragmaArguments(pragma, args);
if (argument === "fail") return; // Missing required argument, fail to parse it
pragmas.push({ name, args: { arguments: argument, range } } as PragmaPsuedoMapEntry);
pragmas.push({ name, args: { arguments: argument, range } } as PragmaPseudoMapEntry);
return;
}
+152 -100
View File
@@ -207,7 +207,7 @@ namespace ts {
...program.getSemanticDiagnostics(sourceFile, cancellationToken)
];
if (program.getCompilerOptions().declaration) {
if (getEmitDeclarations(program.getCompilerOptions())) {
addRange(diagnostics, program.getDeclarationDiagnostics(sourceFile, cancellationToken));
}
@@ -250,7 +250,7 @@ namespace ts {
Blue = "\u001b[94m",
Cyan = "\u001b[96m"
}
const gutterStyleSequence = "\u001b[30;47m";
const gutterStyleSequence = "\u001b[7m";
const gutterSeparator = " ";
const resetEscapeSequence = "\u001b[0m";
const ellipsis = "...";
@@ -442,6 +442,7 @@ namespace ts {
fileExists: (fileName: string) => boolean,
hasInvalidatedResolution: HasInvalidatedResolution,
hasChangedAutomaticTypeDirectiveNames: boolean,
projectReferences: ReadonlyArray<ProjectReference> | undefined
): boolean {
// If we haven't created a program yet or have changed automatic type directives, then it is not up-to-date
if (!program || hasChangedAutomaticTypeDirectiveNames) {
@@ -453,6 +454,11 @@ namespace ts {
return false;
}
// If project references dont match
if (!arrayIsEqualTo(program.getProjectReferences(), projectReferences, projectReferenceUptoDate)) {
return false;
}
// If any file is not up-to-date, then the whole program is not up-to-date
if (program.getSourceFiles().some(sourceFileNotUptoDate)) {
return false;
@@ -477,9 +483,27 @@ namespace ts {
return true;
function sourceFileNotUptoDate(sourceFile: SourceFile): boolean {
return sourceFile.version !== getSourceVersion(sourceFile.path) ||
hasInvalidatedResolution(sourceFile.path);
function sourceFileNotUptoDate(sourceFile: SourceFile) {
return !sourceFileVersionUptoDate(sourceFile) ||
hasInvalidatedResolution(sourceFile.resolvedPath);
}
function sourceFileVersionUptoDate(sourceFile: SourceFile) {
return sourceFile.version === getSourceVersion(sourceFile.resolvedPath);
}
function projectReferenceUptoDate(oldRef: ProjectReference, newRef: ProjectReference, index: number) {
if (!projectReferenceIsEqualTo(oldRef, newRef)) {
return false;
}
const oldResolvedRef = program!.getResolvedProjectReferences()![index];
if (oldResolvedRef) {
// If sourceFile for the oldResolvedRef existed, check the version for uptodate
return sourceFileVersionUptoDate(oldResolvedRef.sourceFile);
}
// In old program, not able to resolve project reference path,
// so if config file doesnt exist, it is uptodate.
return !fileExists(resolveProjectReferencePath(oldRef));
}
}
@@ -490,23 +514,15 @@ namespace ts {
}
/**
* Determined if source file needs to be re-created even if its text hasn't changed
* Determine if source file needs to be re-created even if its text hasn't changed
*/
function shouldProgramCreateNewSourceFiles(program: Program | undefined, newOptions: CompilerOptions) {
// If any of these options change, we can't reuse old source file even if version match
// The change in options like these could result in change in syntax tree change
const oldOptions = program && program.getCompilerOptions();
return oldOptions && (
oldOptions.target !== newOptions.target ||
oldOptions.module !== newOptions.module ||
oldOptions.moduleResolution !== newOptions.moduleResolution ||
oldOptions.noResolve !== newOptions.noResolve ||
oldOptions.jsx !== newOptions.jsx ||
oldOptions.allowJs !== newOptions.allowJs ||
oldOptions.disableSizeLimit !== newOptions.disableSizeLimit ||
oldOptions.baseUrl !== newOptions.baseUrl ||
!equalOwnProperties(oldOptions.paths, newOptions.paths)
);
function shouldProgramCreateNewSourceFiles(program: Program | undefined, newOptions: CompilerOptions): boolean {
if (!program) return false;
// If any compiler options change, we can't reuse old source file even if version match
// The change in options like these could result in change in syntax tree or `sourceFile.bindDiagnostics`.
const oldOptions = program.getCompilerOptions();
return !!sourceFileAffectingCompilerOptions.some(option =>
!isJsonEqual(getCompilerOptionValue(oldOptions, option), getCompilerOptionValue(newOptions, option)));
}
function createCreateProgramOptions(rootNames: ReadonlyArray<string>, options: CompilerOptions, host?: CompilerHost, oldProgram?: Program, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>): CreateProgramOptions {
@@ -594,7 +610,7 @@ namespace ts {
const programDiagnostics = createDiagnosticCollection();
const currentDirectory = host.getCurrentDirectory();
const supportedExtensions = getSupportedExtensions(options);
const supportedExtensionsWithJsonIfResolveJsonModule = options.resolveJsonModule ? [...supportedExtensions, Extension.Json] : undefined;
const supportedExtensionsWithJsonIfResolveJsonModule = getSuppoertedExtensionsWithJsonIfResolveJsonModule(options, supportedExtensions);
// Map storing if there is emit blocking diagnostics for given input
const hasEmitBlockingDiagnostics = createMap<boolean>();
@@ -647,7 +663,7 @@ namespace ts {
// A parallel array to projectReferences storing the results of reading in the referenced tsconfig files
let resolvedProjectReferences: (ResolvedProjectReference | undefined)[] | undefined = projectReferences ? [] : undefined;
const projectReferenceRedirects: Map<string> = createMap();
let projectReferenceRedirects: ParsedCommandLine[] | undefined;
const shouldCreateNewSourceFile = shouldProgramCreateNewSourceFiles(oldProgram, options);
const structuralIsReused = tryReuseStructureFromOldProgram();
@@ -660,11 +676,12 @@ namespace ts {
const parsedRef = parseProjectReferenceConfigFile(ref);
resolvedProjectReferences!.push(parsedRef);
if (parsedRef) {
if (parsedRef.commandLine.options.outFile) {
const dtsOutfile = changeExtension(parsedRef.commandLine.options.outFile, ".d.ts");
const out = parsedRef.commandLine.options.outFile || parsedRef.commandLine.options.out;
if (out) {
const dtsOutfile = changeExtension(out, ".d.ts");
processSourceFile(dtsOutfile, /*isDefaultLib*/ false, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined);
}
addProjectReferenceRedirects(parsedRef.commandLine, projectReferenceRedirects);
addProjectReferenceRedirects(parsedRef.commandLine);
}
}
}
@@ -759,7 +776,9 @@ namespace ts {
isEmittedFile,
getConfigFileParsingDiagnostics,
getResolvedModuleWithFailedLookupLocationsFromCache,
getProjectReferences
getProjectReferences,
getResolvedProjectReferences,
getProjectReferenceRedirect
};
verifyCompilerOptions();
@@ -798,9 +817,9 @@ namespace ts {
// If a rootDir is specified use it as the commonSourceDirectory
commonSourceDirectory = getNormalizedAbsolutePath(options.rootDir, currentDirectory);
}
else if (options.composite) {
else if (options.composite && options.configFilePath) {
// Project compilations never infer their root from the input source paths
commonSourceDirectory = getDirectoryPath(normalizeSlashes(options.configFilePath!)); // TODO: GH#18217
commonSourceDirectory = getDirectoryPath(normalizeSlashes(options.configFilePath));
checkSourceFilesBelongToPath(emittedFiles, commonSourceDirectory);
}
else {
@@ -1007,15 +1026,22 @@ namespace ts {
}
// Check if any referenced project tsconfig files are different
const oldRefs = oldProgram.getProjectReferences();
// If array of references is changed, we cant resue old program
const oldProjectReferences = oldProgram.getProjectReferences();
if (!arrayIsEqualTo(oldProjectReferences!, projectReferences, projectReferenceIsEqualTo)) {
return oldProgram.structureIsReused = StructureIsReused.Not;
}
// Check the json files for the project references
const oldRefs = oldProgram.getResolvedProjectReferences();
if (projectReferences) {
if (!oldRefs) {
return oldProgram.structureIsReused = StructureIsReused.Not;
}
// Resolved project referenced should be array if projectReferences provided are array
Debug.assert(!!oldRefs);
for (let i = 0; i < projectReferences.length; i++) {
const oldRef = oldRefs[i];
const oldRef = oldRefs![i];
const newRef = parseProjectReferenceConfigFile(projectReferences[i]);
if (oldRef) {
const newRef = parseProjectReferenceConfigFile(projectReferences[i]);
if (!newRef || newRef.sourceFile !== oldRef.sourceFile) {
// Resolved project reference has gone missing or changed
return oldProgram.structureIsReused = StructureIsReused.Not;
@@ -1023,16 +1049,15 @@ namespace ts {
}
else {
// A previously-unresolved reference may be resolved now
if (parseProjectReferenceConfigFile(projectReferences[i]) !== undefined) {
if (newRef !== undefined) {
return oldProgram.structureIsReused = StructureIsReused.Not;
}
}
}
}
else {
if (oldRefs) {
return oldProgram.structureIsReused = StructureIsReused.Not;
}
// Resolved project referenced should be undefined if projectReferences is undefined
Debug.assert(!oldRefs);
}
// check if program source files has changed in the way that can affect structure of the program
@@ -1054,7 +1079,7 @@ namespace ts {
for (const oldSourceFile of oldSourceFiles) {
let newSourceFile = host.getSourceFileByPath
? host.getSourceFileByPath(oldSourceFile.fileName, oldSourceFile.resolvedPath || oldSourceFile.path, options.target!, /*onError*/ undefined, shouldCreateNewSourceFile)
? host.getSourceFileByPath(oldSourceFile.fileName, oldSourceFile.resolvedPath, options.target!, /*onError*/ undefined, shouldCreateNewSourceFile)
: host.getSourceFile(oldSourceFile.fileName, options.target!, /*onError*/ undefined, shouldCreateNewSourceFile); // TODO: GH#18217
if (!newSourceFile) {
@@ -1085,7 +1110,11 @@ namespace ts {
fileChanged = newSourceFile !== oldSourceFile;
}
// Since the project references havent changed, its right to set originalFileName and resolvedPath here
newSourceFile.path = oldSourceFile.path;
newSourceFile.originalFileName = oldSourceFile.originalFileName;
newSourceFile.resolvedPath = oldSourceFile.resolvedPath;
newSourceFile.fileName = oldSourceFile.fileName;
filePaths.push(newSourceFile.path);
const packageName = oldProgram.sourceFileToPackageName.get(oldSourceFile.path);
@@ -1162,7 +1191,7 @@ namespace ts {
modifiedFilePaths = modifiedSourceFiles.map(f => f.newFile.path);
// try to verify results of module resolution
for (const { oldFile: oldSourceFile, newFile: newSourceFile } of modifiedSourceFiles) {
const newSourceFilePath = getNormalizedAbsolutePath(newSourceFile.fileName, currentDirectory);
const newSourceFilePath = getNormalizedAbsolutePath(newSourceFile.originalFileName, currentDirectory);
if (resolveModuleNamesWorker) {
const moduleNames = getModuleNames(newSourceFile);
const oldProgramState: OldProgramState = { program: oldProgram, oldSourceFile, modifiedFilePaths };
@@ -1219,7 +1248,14 @@ namespace ts {
fileProcessingDiagnostics.reattachFileDiagnostics(modifiedFile.newFile);
}
resolvedTypeReferenceDirectives = oldProgram.getResolvedTypeReferenceDirectives();
resolvedProjectReferences = oldProgram.getProjectReferences();
resolvedProjectReferences = oldProgram.getResolvedProjectReferences();
if (resolvedProjectReferences) {
resolvedProjectReferences.forEach(ref => {
if (ref) {
addProjectReferenceRedirects(ref.commandLine);
}
});
}
sourceFileToPackageName = oldProgram.sourceFileToPackageName;
redirectTargetsMap = oldProgram.redirectTargetsMap;
@@ -1257,10 +1293,14 @@ namespace ts {
};
}
function getProjectReferences() {
function getResolvedProjectReferences() {
return resolvedProjectReferences;
}
function getProjectReferences() {
return projectReferences;
}
function getPrependNodes(): InputFiles[] {
if (!projectReferences) {
return emptyArray;
@@ -1271,12 +1311,13 @@ namespace ts {
const ref = projectReferences[i];
const resolvedRefOpts = resolvedProjectReferences![i]!.commandLine;
if (ref.prepend && resolvedRefOpts && resolvedRefOpts.options) {
const out = resolvedRefOpts.options.outFile || resolvedRefOpts.options.out;
// Upstream project didn't have outFile set -- skip (error will have been issued earlier)
if (!resolvedRefOpts.options.outFile) continue;
if (!out) continue;
const dtsFilename = changeExtension(resolvedRefOpts.options.outFile, ".d.ts");
const js = host.readFile(resolvedRefOpts.options.outFile) || `/* Input file ${resolvedRefOpts.options.outFile} was missing */\r\n`;
const jsMapPath = resolvedRefOpts.options.outFile + ".map"; // TODO: try to read sourceMappingUrl comment from the file
const dtsFilename = changeExtension(out, ".d.ts");
const js = host.readFile(out) || `/* Input file ${out} was missing */\r\n`;
const jsMapPath = out + ".map"; // TODO: try to read sourceMappingUrl comment from the file
const jsMap = host.readFile(jsMapPath);
const dts = host.readFile(dtsFilename) || `/* Input file ${dtsFilename} was missing */\r\n`;
const dtsMapPath = dtsFilename + ".map";
@@ -1351,7 +1392,7 @@ namespace ts {
...program.getSemanticDiagnostics(sourceFile, cancellationToken)
];
if (diagnostics.length === 0 && program.getCompilerOptions().declaration) {
if (diagnostics.length === 0 && getEmitDeclarations(program.getCompilerOptions())) {
declarationDiagnostics = program.getDeclarationDiagnostics(/*sourceFile*/ undefined, cancellationToken);
}
@@ -1438,9 +1479,9 @@ namespace ts {
function getSyntacticDiagnosticsForFile(sourceFile: SourceFile): ReadonlyArray<DiagnosticWithLocation> {
// For JavaScript files, we report semantic errors for using TypeScript-only
// constructs from within a JavaScript file as syntactic errors.
if (isSourceFileJavaScript(sourceFile)) {
if (isSourceFileJS(sourceFile)) {
if (!sourceFile.additionalSyntacticDiagnostics) {
sourceFile.additionalSyntacticDiagnostics = getJavaScriptSyntacticDiagnosticsForFile(sourceFile);
sourceFile.additionalSyntacticDiagnostics = getJSSyntacticDiagnosticsForFile(sourceFile);
}
return concatenate(sourceFile.additionalSyntacticDiagnostics, sourceFile.parseDiagnostics);
}
@@ -1538,7 +1579,7 @@ namespace ts {
return true;
}
function getJavaScriptSyntacticDiagnosticsForFile(sourceFile: SourceFile): DiagnosticWithLocation[] {
function getJSSyntacticDiagnosticsForFile(sourceFile: SourceFile): DiagnosticWithLocation[] {
return runWithCancellationToken(() => {
const diagnostics: DiagnosticWithLocation[] = [];
let parent: Node = sourceFile;
@@ -1801,7 +1842,7 @@ namespace ts {
return;
}
const isJavaScriptFile = isSourceFileJavaScript(file);
const isJavaScriptFile = isSourceFileJS(file);
const isExternalModuleFile = isExternalModule(file);
// file.imports may not be undefined if there exists dynamic import
@@ -1924,7 +1965,7 @@ namespace ts {
refFile?: SourceFile): SourceFile | undefined {
if (hasExtension(fileName)) {
if (!options.allowNonTsExtensions && !forEach(supportedExtensionsWithJsonIfResolveJsonModule || supportedExtensions, extension => fileExtensionIs(host.getCanonicalFileName(fileName), extension))) {
if (!options.allowNonTsExtensions && !forEach(supportedExtensionsWithJsonIfResolveJsonModule, extension => fileExtensionIs(host.getCanonicalFileName(fileName), extension))) {
if (fail) fail(Diagnostics.File_0_has_unsupported_extension_The_only_supported_extensions_are_1, fileName, "'" + supportedExtensions.join("', '") + "'");
return undefined;
}
@@ -1983,11 +2024,14 @@ namespace ts {
}
}
function createRedirectSourceFile(redirectTarget: SourceFile, unredirected: SourceFile, fileName: string, path: Path): SourceFile {
function createRedirectSourceFile(redirectTarget: SourceFile, unredirected: SourceFile, fileName: string, path: Path, resolvedPath: Path, originalFileName: string): SourceFile {
const redirect: SourceFile = Object.create(redirectTarget);
redirect.fileName = fileName;
redirect.path = path;
redirect.resolvedPath = resolvedPath;
redirect.originalFileName = originalFileName;
redirect.redirectInfo = { redirectTarget, unredirected };
sourceFilesFoundSearchingNodeModules.set(path, currentNodeModulesDepth > 0);
Object.defineProperties(redirect, {
id: {
get(this: SourceFile) { return this.redirectInfo!.redirectTarget.id; },
@@ -2003,6 +2047,7 @@ namespace ts {
// Get source file from normalized fileName
function findSourceFile(fileName: string, path: Path, isDefaultLib: boolean, ignoreNoDefaultLib: boolean, refFile: SourceFile, refPos: number, refEnd: number, packageId: PackageId | undefined): SourceFile | undefined {
const originalFileName = fileName;
if (filesByName.has(path)) {
const file = filesByName.get(path);
// try to check if we've already seen this file but with a different casing in path
@@ -2076,7 +2121,7 @@ namespace ts {
if (fileFromPackageId) {
// Some other SourceFile already exists with this package name and version.
// Instead of creating a duplicate, just redirect to the existing one.
const dupFile = createRedirectSourceFile(fileFromPackageId, file!, fileName, path); // TODO: GH#18217
const dupFile = createRedirectSourceFile(fileFromPackageId, file!, fileName, path, toPath(fileName), originalFileName); // TODO: GH#18217
redirectTargetsMap.add(fileFromPackageId.path, fileName);
filesByName.set(path, dupFile);
sourceFileToPackageName.set(path, packageId.name);
@@ -2099,6 +2144,7 @@ namespace ts {
sourceFilesFoundSearchingNodeModules.set(path, currentNodeModulesDepth > 0);
file.path = path;
file.resolvedPath = toPath(fileName);
file.originalFileName = originalFileName;
if (host.useCaseSensitiveFileNames()) {
const pathLowerCase = path.toLowerCase();
@@ -2136,25 +2182,29 @@ namespace ts {
}
function getProjectReferenceRedirect(fileName: string): string | undefined {
const path = toPath(fileName);
// Ignore dts or any of the non ts files
if (!projectReferenceRedirects || fileExtensionIs(fileName, Extension.Dts) || !fileExtensionIsOneOf(fileName, supportedTSExtensions)) {
return undefined;
}
// If this file is produced by a referenced project, we need to rewrite it to
// look in the output folder of the referenced project rather than the input
const normalized = getNormalizedAbsolutePath(fileName, path);
let result: string | undefined;
projectReferenceRedirects.forEach((v, k) => {
if (result !== undefined) {
return forEach(projectReferenceRedirects, referencedProject => {
// not input file from the referenced project, ignore
if (!contains(referencedProject.fileNames, fileName, isSameFile)) {
return undefined;
}
if (normalized.indexOf(k) === 0) {
result = changeExtension(fileName.replace(k, v), ".d.ts");
}
const out = referencedProject.options.outFile || referencedProject.options.out;
return out ?
changeExtension(out, Extension.Dts) :
getOutputDeclarationFileName(fileName, referencedProject);
});
return result;
}
function processReferencedFiles(file: SourceFile, isDefaultLib: boolean) {
forEach(file.referencedFiles, ref => {
const referencedFileName = resolveTripleslashReference(ref.fileName, file.fileName);
const referencedFileName = resolveTripleslashReference(ref.fileName, file.originalFileName);
processSourceFile(referencedFileName, isDefaultLib, /*ignoreNoDefaultLib*/ false, /*packageId*/ undefined, file, ref.pos, ref.end);
});
}
@@ -2166,7 +2216,7 @@ namespace ts {
return;
}
const resolutions = resolveTypeReferenceDirectiveNamesWorker(typeDirectives, file.fileName);
const resolutions = resolveTypeReferenceDirectiveNamesWorker(typeDirectives, file.originalFileName);
for (let i = 0; i < typeDirectives.length; i++) {
const ref = file.typeReferenceDirectives[i];
@@ -2262,7 +2312,7 @@ namespace ts {
// Because global augmentation doesn't have string literal name, we can check for global augmentation as such.
const moduleNames = getModuleNames(file);
const oldProgramState: OldProgramState = { program: oldProgram, oldSourceFile: oldProgram && oldProgram.getSourceFile(file.fileName), modifiedFilePaths };
const resolutions = resolveModuleNamesReusingOldState(moduleNames, getNormalizedAbsolutePath(file.fileName, currentDirectory), file, oldProgramState);
const resolutions = resolveModuleNamesReusingOldState(moduleNames, getNormalizedAbsolutePath(file.originalFileName, currentDirectory), file, oldProgramState);
Debug.assert(resolutions.length === moduleNames.length);
for (let i = 0; i < moduleNames.length; i++) {
const resolution = resolutions[i];
@@ -2273,7 +2323,7 @@ namespace ts {
}
const isFromNodeModulesSearch = resolution.isExternalLibraryImport;
const isJsFile = !resolutionExtensionIsTypeScriptOrJson(resolution.extension);
const isJsFile = !resolutionExtensionIsTSOrJson(resolution.extension);
const isJsFileFromNodeModules = isFromNodeModulesSearch && isJsFile;
const resolvedFileName = resolution.resolvedFileName;
@@ -2295,7 +2345,7 @@ namespace ts {
&& i < file.imports.length
&& !elideImport
&& !(isJsFile && !options.allowJs)
&& (isInJavaScriptFile(file.imports[i]) || !(file.imports[i].flags & NodeFlags.JSDoc));
&& (isInJSFile(file.imports[i]) || !(file.imports[i].flags & NodeFlags.JSDoc));
if (elideImport) {
modulesWithElidedImports.set(file.path, true);
@@ -2341,7 +2391,7 @@ namespace ts {
function parseProjectReferenceConfigFile(ref: ProjectReference): { commandLine: ParsedCommandLine, sourceFile: SourceFile } | undefined {
// The actual filename (i.e. add "/tsconfig.json" if necessary)
const refPath = resolveProjectReferencePath(host, ref);
const refPath = resolveProjectReferencePath(ref);
// An absolute path pointing to the containing directory of the config file
const basePath = getNormalizedAbsolutePath(getDirectoryPath(refPath), host.getCurrentDirectory());
const sourceFile = host.getSourceFile(refPath, ScriptTarget.JSON) as JsonSourceFile | undefined;
@@ -2353,15 +2403,8 @@ namespace ts {
return { commandLine, sourceFile };
}
function addProjectReferenceRedirects(referencedProject: ParsedCommandLine, target: Map<string>) {
const rootDir = normalizePath(referencedProject.options.rootDir || getDirectoryPath(referencedProject.options.configFilePath!)); // TODO: GH#18217
target.set(rootDir, getDeclarationOutputDirectory(referencedProject));
}
function getDeclarationOutputDirectory(proj: ParsedCommandLine) {
return proj.options.declarationDir ||
proj.options.outDir ||
getDirectoryPath(proj.options.configFilePath!); // TODO: GH#18217
function addProjectReferenceRedirects(referencedProject: ParsedCommandLine) {
(projectReferenceRedirects || (projectReferenceRedirects = [])).push(referencedProject);
}
function verifyCompilerOptions() {
@@ -2370,8 +2413,8 @@ namespace ts {
}
if (options.isolatedModules) {
if (options.declaration) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "declaration", "isolatedModules");
if (getEmitDeclarations(options)) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, getEmitDeclarationOptionName(options), "isolatedModules");
}
if (options.noEmitOnError) {
@@ -2418,9 +2461,10 @@ namespace ts {
createDiagnosticForReference(i, Diagnostics.Referenced_project_0_must_have_setting_composite_Colon_true, ref.path);
}
if (ref.prepend) {
if (resolvedRefOpts.outFile) {
if (!host.fileExists(resolvedRefOpts.outFile)) {
createDiagnosticForReference(i, Diagnostics.Output_file_0_from_project_1_does_not_exist, resolvedRefOpts.outFile, ref.path);
const out = resolvedRefOpts.outFile || resolvedRefOpts.out;
if (out) {
if (!host.fileExists(out)) {
createDiagnosticForReference(i, Diagnostics.Output_file_0_from_project_1_does_not_exist, out, ref.path);
}
}
else {
@@ -2494,8 +2538,8 @@ namespace ts {
}
if (options.declarationDir) {
if (!options.declaration) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "declarationDir", "declaration");
if (!getEmitDeclarations(options)) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "declarationDir", "declaration", "composite");
}
if (options.out || options.outFile) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "declarationDir", options.out ? "out" : "outFile");
@@ -2503,7 +2547,7 @@ namespace ts {
}
if (options.declarationMap && !getEmitDeclarations(options)) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "declarationMap", "declaration");
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "declarationMap", "declaration", "composite");
}
if (options.lib && options.noLib) {
@@ -2536,7 +2580,7 @@ namespace ts {
}
// Cannot specify module gen that isn't amd or system with --out
if (outFile) {
if (outFile && !options.emitDeclarationOnly) {
if (options.module && !(options.module === ModuleKind.AMD || options.module === ModuleKind.System)) {
createDiagnosticForOptionName(Diagnostics.Only_amd_and_system_modules_are_supported_alongside_0, options.out ? "out" : "outFile", "module");
}
@@ -2571,8 +2615,8 @@ namespace ts {
}
}
if (!options.noEmit && options.allowJs && options.declaration) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", "declaration");
if (!options.noEmit && options.allowJs && getEmitDeclarations(options)) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_with_option_1, "allowJs", getEmitDeclarationOptionName(options));
}
if (options.checkJs && !options.allowJs) {
@@ -2580,8 +2624,8 @@ namespace ts {
}
if (options.emitDeclarationOnly) {
if (!options.declaration) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1, "emitDeclarationOnly", "declaration");
if (!getEmitDeclarations(options)) {
createDiagnosticForOptionName(Diagnostics.Option_0_cannot_be_specified_without_specifying_option_1_or_option_2, "emitDeclarationOnly", "declaration", "composite");
}
if (options.noEmit) {
@@ -2794,7 +2838,7 @@ namespace ts {
return containsPath(options.outDir, filePath, currentDirectory, !host.useCaseSensitiveFileNames());
}
if (fileExtensionIsOneOf(filePath, supportedJavascriptExtensions) || fileExtensionIs(filePath, Extension.Dts)) {
if (fileExtensionIsOneOf(filePath, supportedJSExtensions) || fileExtensionIs(filePath, Extension.Dts)) {
// Otherwise just check if sourceFile with the name exists
const filePathWithoutExtension = removeFileExtension(filePath);
return !!getSourceFileByPath((filePathWithoutExtension + Extension.Ts) as Path) ||
@@ -2812,7 +2856,10 @@ namespace ts {
export function parseConfigHostFromCompilerHost(host: CompilerHost): ParseConfigFileHost {
return {
fileExists: f => host.fileExists(f),
readDirectory: (root, extensions, includes, depth?) => host.readDirectory ? host.readDirectory(root, extensions, includes, depth) : [],
readDirectory(root, extensions, excludes, includes, depth) {
Debug.assertDefined(host.readDirectory, "'CompilerHost.readDirectory' must be implemented to correctly process 'projectReferences'");
return host.readDirectory!(root, extensions, excludes, includes, depth);
},
readFile: f => host.readFile(f),
useCaseSensitiveFileNames: host.useCaseSensitiveFileNames(),
getCurrentDirectory: () => host.getCurrentDirectory(),
@@ -2820,20 +2867,25 @@ namespace ts {
};
}
export interface ResolveProjectReferencePathHost {
// For backward compatibility
/** @deprecated */ export interface ResolveProjectReferencePathHost {
fileExists(fileName: string): boolean;
}
/**
* Returns the target config filename of a project reference.
* Note: The file might not exist.
*/
export function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName {
if (!host.fileExists(ref.path)) {
return combinePaths(ref.path, "tsconfig.json") as ResolvedConfigFileName;
}
return ref.path as ResolvedConfigFileName;
export function resolveProjectReferencePath(ref: ProjectReference): ResolvedConfigFileName;
/** @deprecated */ export function resolveProjectReferencePath(host: ResolveProjectReferencePathHost, ref: ProjectReference): ResolvedConfigFileName;
export function resolveProjectReferencePath(hostOrRef: ResolveProjectReferencePathHost | ProjectReference, ref?: ProjectReference): ResolvedConfigFileName {
const passedInRef = ref ? ref : hostOrRef as ProjectReference;
return resolveConfigFileProjectName(passedInRef.path);
}
function getEmitDeclarationOptionName(options: CompilerOptions) {
return options.declaration ? "declaration" : "composite";
}
/* @internal */
/**
* Returns a DiagnosticMessage if we won't include a resolved module due to its extension.
+3 -2
View File
@@ -226,7 +226,7 @@ namespace ts {
// otherwise try to load typings from @types
const globalCache = resolutionHost.getGlobalCache();
if (globalCache !== undefined && !isExternalModuleNameRelative(moduleName) && !(primaryResult.resolvedModule && extensionIsTypeScript(primaryResult.resolvedModule.extension))) {
if (globalCache !== undefined && !isExternalModuleNameRelative(moduleName) && !(primaryResult.resolvedModule && extensionIsTS(primaryResult.resolvedModule.extension))) {
// create different collection of failed lookup locations for second pass
// if it will fail and we've already found something during the first pass - we don't want to pollute its results
const { resolvedModule, failedLookupLocations } = loadModuleFromGlobalCache(moduleName, resolutionHost.projectName, compilerOptions, host, globalCache);
@@ -398,7 +398,8 @@ namespace ts {
function getDirectoryToWatchFailedLookupLocation(failedLookupLocation: string, failedLookupLocationPath: Path): DirectoryOfFailedLookupWatch {
if (isInDirectoryPath(rootPath, failedLookupLocationPath)) {
failedLookupLocation = isRootedDiskPath(failedLookupLocation) ? failedLookupLocation : getNormalizedAbsolutePath(failedLookupLocation, getCurrentDirectory());
// Ensure failed look up is normalized path
failedLookupLocation = isRootedDiskPath(failedLookupLocation) ? normalizePath(failedLookupLocation) : getNormalizedAbsolutePath(failedLookupLocation, getCurrentDirectory());
Debug.assert(failedLookupLocation.length === failedLookupLocationPath.length, `FailedLookup: ${failedLookupLocation} failedLookupLocationPath: ${failedLookupLocationPath}`); // tslint:disable-line
const subDirectoryInRoot = failedLookupLocationPath.indexOf(directorySeparator, rootPath.length + 1);
if (subDirectoryInRoot !== -1) {
+86 -80
View File
@@ -60,81 +60,87 @@ namespace ts {
tryScan<T>(callback: () => T): T;
}
const textToToken = createMapFromTemplate({
"abstract": SyntaxKind.AbstractKeyword,
"any": SyntaxKind.AnyKeyword,
"as": SyntaxKind.AsKeyword,
"boolean": SyntaxKind.BooleanKeyword,
"break": SyntaxKind.BreakKeyword,
"case": SyntaxKind.CaseKeyword,
"catch": SyntaxKind.CatchKeyword,
"class": SyntaxKind.ClassKeyword,
"continue": SyntaxKind.ContinueKeyword,
"const": SyntaxKind.ConstKeyword,
"constructor": SyntaxKind.ConstructorKeyword,
"debugger": SyntaxKind.DebuggerKeyword,
"declare": SyntaxKind.DeclareKeyword,
"default": SyntaxKind.DefaultKeyword,
"delete": SyntaxKind.DeleteKeyword,
"do": SyntaxKind.DoKeyword,
"else": SyntaxKind.ElseKeyword,
"enum": SyntaxKind.EnumKeyword,
"export": SyntaxKind.ExportKeyword,
"extends": SyntaxKind.ExtendsKeyword,
"false": SyntaxKind.FalseKeyword,
"finally": SyntaxKind.FinallyKeyword,
"for": SyntaxKind.ForKeyword,
"from": SyntaxKind.FromKeyword,
"function": SyntaxKind.FunctionKeyword,
"get": SyntaxKind.GetKeyword,
"if": SyntaxKind.IfKeyword,
"implements": SyntaxKind.ImplementsKeyword,
"import": SyntaxKind.ImportKeyword,
"in": SyntaxKind.InKeyword,
"infer": SyntaxKind.InferKeyword,
"instanceof": SyntaxKind.InstanceOfKeyword,
"interface": SyntaxKind.InterfaceKeyword,
"is": SyntaxKind.IsKeyword,
"keyof": SyntaxKind.KeyOfKeyword,
"let": SyntaxKind.LetKeyword,
"module": SyntaxKind.ModuleKeyword,
"namespace": SyntaxKind.NamespaceKeyword,
"never": SyntaxKind.NeverKeyword,
"new": SyntaxKind.NewKeyword,
"null": SyntaxKind.NullKeyword,
"number": SyntaxKind.NumberKeyword,
"object": SyntaxKind.ObjectKeyword,
"package": SyntaxKind.PackageKeyword,
"private": SyntaxKind.PrivateKeyword,
"protected": SyntaxKind.ProtectedKeyword,
"public": SyntaxKind.PublicKeyword,
"readonly": SyntaxKind.ReadonlyKeyword,
"require": SyntaxKind.RequireKeyword,
"global": SyntaxKind.GlobalKeyword,
"return": SyntaxKind.ReturnKeyword,
"set": SyntaxKind.SetKeyword,
"static": SyntaxKind.StaticKeyword,
"string": SyntaxKind.StringKeyword,
"super": SyntaxKind.SuperKeyword,
"switch": SyntaxKind.SwitchKeyword,
"symbol": SyntaxKind.SymbolKeyword,
"this": SyntaxKind.ThisKeyword,
"throw": SyntaxKind.ThrowKeyword,
"true": SyntaxKind.TrueKeyword,
"try": SyntaxKind.TryKeyword,
"type": SyntaxKind.TypeKeyword,
"typeof": SyntaxKind.TypeOfKeyword,
"undefined": SyntaxKind.UndefinedKeyword,
"unique": SyntaxKind.UniqueKeyword,
"unknown": SyntaxKind.UnknownKeyword,
"var": SyntaxKind.VarKeyword,
"void": SyntaxKind.VoidKeyword,
"while": SyntaxKind.WhileKeyword,
"with": SyntaxKind.WithKeyword,
"yield": SyntaxKind.YieldKeyword,
"async": SyntaxKind.AsyncKeyword,
"await": SyntaxKind.AwaitKeyword,
"of": SyntaxKind.OfKeyword,
const textToKeywordObj: MapLike<KeywordSyntaxKind> = {
abstract: SyntaxKind.AbstractKeyword,
any: SyntaxKind.AnyKeyword,
as: SyntaxKind.AsKeyword,
boolean: SyntaxKind.BooleanKeyword,
break: SyntaxKind.BreakKeyword,
case: SyntaxKind.CaseKeyword,
catch: SyntaxKind.CatchKeyword,
class: SyntaxKind.ClassKeyword,
continue: SyntaxKind.ContinueKeyword,
const: SyntaxKind.ConstKeyword,
["" + "constructor"]: SyntaxKind.ConstructorKeyword,
debugger: SyntaxKind.DebuggerKeyword,
declare: SyntaxKind.DeclareKeyword,
default: SyntaxKind.DefaultKeyword,
delete: SyntaxKind.DeleteKeyword,
do: SyntaxKind.DoKeyword,
else: SyntaxKind.ElseKeyword,
enum: SyntaxKind.EnumKeyword,
export: SyntaxKind.ExportKeyword,
extends: SyntaxKind.ExtendsKeyword,
false: SyntaxKind.FalseKeyword,
finally: SyntaxKind.FinallyKeyword,
for: SyntaxKind.ForKeyword,
from: SyntaxKind.FromKeyword,
function: SyntaxKind.FunctionKeyword,
get: SyntaxKind.GetKeyword,
if: SyntaxKind.IfKeyword,
implements: SyntaxKind.ImplementsKeyword,
import: SyntaxKind.ImportKeyword,
in: SyntaxKind.InKeyword,
infer: SyntaxKind.InferKeyword,
instanceof: SyntaxKind.InstanceOfKeyword,
interface: SyntaxKind.InterfaceKeyword,
is: SyntaxKind.IsKeyword,
keyof: SyntaxKind.KeyOfKeyword,
let: SyntaxKind.LetKeyword,
module: SyntaxKind.ModuleKeyword,
namespace: SyntaxKind.NamespaceKeyword,
never: SyntaxKind.NeverKeyword,
new: SyntaxKind.NewKeyword,
null: SyntaxKind.NullKeyword,
number: SyntaxKind.NumberKeyword,
object: SyntaxKind.ObjectKeyword,
package: SyntaxKind.PackageKeyword,
private: SyntaxKind.PrivateKeyword,
protected: SyntaxKind.ProtectedKeyword,
public: SyntaxKind.PublicKeyword,
readonly: SyntaxKind.ReadonlyKeyword,
require: SyntaxKind.RequireKeyword,
global: SyntaxKind.GlobalKeyword,
return: SyntaxKind.ReturnKeyword,
set: SyntaxKind.SetKeyword,
static: SyntaxKind.StaticKeyword,
string: SyntaxKind.StringKeyword,
super: SyntaxKind.SuperKeyword,
switch: SyntaxKind.SwitchKeyword,
symbol: SyntaxKind.SymbolKeyword,
this: SyntaxKind.ThisKeyword,
throw: SyntaxKind.ThrowKeyword,
true: SyntaxKind.TrueKeyword,
try: SyntaxKind.TryKeyword,
type: SyntaxKind.TypeKeyword,
typeof: SyntaxKind.TypeOfKeyword,
undefined: SyntaxKind.UndefinedKeyword,
unique: SyntaxKind.UniqueKeyword,
unknown: SyntaxKind.UnknownKeyword,
var: SyntaxKind.VarKeyword,
void: SyntaxKind.VoidKeyword,
while: SyntaxKind.WhileKeyword,
with: SyntaxKind.WithKeyword,
yield: SyntaxKind.YieldKeyword,
async: SyntaxKind.AsyncKeyword,
await: SyntaxKind.AwaitKeyword,
of: SyntaxKind.OfKeyword,
};
const textToKeyword = createMapFromTemplate(textToKeywordObj);
const textToToken = createMapFromTemplate<SyntaxKind>({
...textToKeywordObj,
"{": SyntaxKind.OpenBraceToken,
"}": SyntaxKind.CloseBraceToken,
"(": SyntaxKind.OpenParenToken,
@@ -1288,15 +1294,15 @@ namespace ts {
return result;
}
function getIdentifierToken(): SyntaxKind {
function getIdentifierToken(): SyntaxKind.Identifier | KeywordSyntaxKind {
// Reserved words are between 2 and 11 characters long and start with a lowercase letter
const len = tokenValue.length;
if (len >= 2 && len <= 11) {
const ch = tokenValue.charCodeAt(0);
if (ch >= CharacterCodes.a && ch <= CharacterCodes.z) {
token = textToToken.get(tokenValue)!;
if (token !== undefined) {
return token;
const keyword = textToKeyword.get(tokenValue);
if (keyword !== undefined) {
return token = keyword;
}
}
}
@@ -2016,7 +2022,7 @@ namespace ts {
pos++;
}
tokenValue = text.substring(tokenPos, pos);
return token = SyntaxKind.Identifier;
return token = getIdentifierToken();
}
else {
return token = SyntaxKind.Unknown;
+391
View File
@@ -0,0 +1,391 @@
/* @internal */
namespace ts {
// https://semver.org/#spec-item-2
// > A normal version number MUST take the form X.Y.Z where X, Y, and Z are non-negative
// > integers, and MUST NOT contain leading zeroes. X is the major version, Y is the minor
// > version, and Z is the patch version. Each element MUST increase numerically.
//
// NOTE: We differ here in that we allow X and X.Y, with missing parts having the default
// value of `0`.
const versionRegExp = /^(0|[1-9]\d*)(?:\.(0|[1-9]\d*)(?:\.(0|[1-9]\d*)(?:\-([a-z0-9-.]+))?(?:\+([a-z0-9-.]+))?)?)?$/i;
// https://semver.org/#spec-item-9
// > A pre-release version MAY be denoted by appending a hyphen and a series of dot separated
// > identifiers immediately following the patch version. Identifiers MUST comprise only ASCII
// > alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty. Numeric identifiers
// > MUST NOT include leading zeroes.
const prereleaseRegExp = /^(?:0|[1-9]\d*|[a-z-][a-z0-9-]*)(?:\.(?:0|[1-9]\d*|[a-z-][a-z0-9-]*))*$/i;
// https://semver.org/#spec-item-10
// > Build metadata MAY be denoted by appending a plus sign and a series of dot separated
// > identifiers immediately following the patch or pre-release version. Identifiers MUST
// > comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty.
const buildRegExp = /^[a-z0-9-]+(?:\.[a-z0-9-]+)*$/i;
// https://semver.org/#spec-item-9
// > Numeric identifiers MUST NOT include leading zeroes.
const numericIdentifierRegExp = /^(0|[1-9]\d*)$/;
/**
* Describes a precise semantic version number, https://semver.org
*/
export class Version {
static readonly zero = new Version(0, 0, 0);
readonly major: number;
readonly minor: number;
readonly patch: number;
readonly prerelease: ReadonlyArray<string>;
readonly build: ReadonlyArray<string>;
constructor(text: string);
constructor(major: number, minor?: number, patch?: number, prerelease?: string, build?: string);
constructor(major: number | string, minor = 0, patch = 0, prerelease = "", build = "") {
if (typeof major === "string") {
const result = Debug.assertDefined(tryParseComponents(major), "Invalid version");
({ major, minor, patch, prerelease, build } = result);
}
Debug.assert(major >= 0, "Invalid argument: major");
Debug.assert(minor >= 0, "Invalid argument: minor");
Debug.assert(patch >= 0, "Invalid argument: patch");
Debug.assert(!prerelease || prereleaseRegExp.test(prerelease), "Invalid argument: prerelease");
Debug.assert(!build || buildRegExp.test(build), "Invalid argument: build");
this.major = major;
this.minor = minor;
this.patch = patch;
this.prerelease = prerelease ? prerelease.split(".") : emptyArray;
this.build = build ? build.split(".") : emptyArray;
}
static tryParse(text: string) {
const result = tryParseComponents(text);
if (!result) return undefined;
const { major, minor, patch, prerelease, build } = result;
return new Version(major, minor, patch, prerelease, build);
}
compareTo(other: Version | undefined) {
// https://semver.org/#spec-item-11
// > Precedence is determined by the first difference when comparing each of these
// > identifiers from left to right as follows: Major, minor, and patch versions are
// > always compared numerically.
//
// https://semver.org/#spec-item-11
// > Precedence for two pre-release versions with the same major, minor, and patch version
// > MUST be determined by comparing each dot separated identifier from left to right until
// > a difference is found [...]
//
// https://semver.org/#spec-item-11
// > Build metadata does not figure into precedence
if (this === other) return Comparison.EqualTo;
if (other === undefined) return Comparison.GreaterThan;
return compareValues(this.major, other.major)
|| compareValues(this.minor, other.minor)
|| compareValues(this.patch, other.patch)
|| comparePrerelaseIdentifiers(this.prerelease, other.prerelease);
}
increment(field: "major" | "minor" | "patch") {
switch (field) {
case "major": return new Version(this.major + 1, 0, 0);
case "minor": return new Version(this.major, this.minor + 1, 0);
case "patch": return new Version(this.major, this.minor, this.patch + 1);
default: return Debug.assertNever(field);
}
}
toString() {
let result = `${this.major}.${this.minor}.${this.patch}`;
if (some(this.prerelease)) result += `-${this.prerelease.join(".")}`;
if (some(this.build)) result += `+${this.build.join(".")}`;
return result;
}
}
function tryParseComponents(text: string) {
const match = versionRegExp.exec(text);
if (!match) return undefined;
const [, major, minor = "0", patch = "0", prerelease = "", build = ""] = match;
if (prerelease && !prereleaseRegExp.test(prerelease)) return undefined;
if (build && !buildRegExp.test(build)) return undefined;
return {
major: parseInt(major, 10),
minor: parseInt(minor, 10),
patch: parseInt(patch, 10),
prerelease,
build
};
}
function comparePrerelaseIdentifiers(left: ReadonlyArray<string>, right: ReadonlyArray<string>) {
// https://semver.org/#spec-item-11
// > When major, minor, and patch are equal, a pre-release version has lower precedence
// > than a normal version.
if (left === right) return Comparison.EqualTo;
if (left.length === 0) return right.length === 0 ? Comparison.EqualTo : Comparison.GreaterThan;
if (right.length === 0) return Comparison.LessThan;
// https://semver.org/#spec-item-11
// > Precedence for two pre-release versions with the same major, minor, and patch version
// > MUST be determined by comparing each dot separated identifier from left to right until
// > a difference is found [...]
const length = Math.min(left.length, right.length);
for (let i = 0; i < length; i++) {
const leftIdentifier = left[i];
const rightIdentifier = right[i];
if (leftIdentifier === rightIdentifier) continue;
const leftIsNumeric = numericIdentifierRegExp.test(leftIdentifier);
const rightIsNumeric = numericIdentifierRegExp.test(rightIdentifier);
if (leftIsNumeric || rightIsNumeric) {
// https://semver.org/#spec-item-11
// > Numeric identifiers always have lower precedence than non-numeric identifiers.
if (leftIsNumeric !== rightIsNumeric) return leftIsNumeric ? Comparison.LessThan : Comparison.GreaterThan;
// https://semver.org/#spec-item-11
// > identifiers consisting of only digits are compared numerically
const result = compareValues(+leftIdentifier, +rightIdentifier);
if (result) return result;
}
else {
// https://semver.org/#spec-item-11
// > identifiers with letters or hyphens are compared lexically in ASCII sort order.
const result = compareStringsCaseSensitive(leftIdentifier, rightIdentifier);
if (result) return result;
}
}
// https://semver.org/#spec-item-11
// > A larger set of pre-release fields has a higher precedence than a smaller set, if all
// > of the preceding identifiers are equal.
return compareValues(left.length, right.length);
}
/**
* Describes a semantic version range, per https://github.com/npm/node-semver#ranges
*/
export class VersionRange {
private _alternatives: ReadonlyArray<ReadonlyArray<Comparator>>;
constructor(spec: string) {
this._alternatives = spec ? Debug.assertDefined(parseRange(spec), "Invalid range spec.") : emptyArray;
}
static tryParse(text: string) {
const sets = parseRange(text);
if (sets) {
const range = new VersionRange("");
range._alternatives = sets;
return range;
}
return undefined;
}
test(version: Version | string) {
if (typeof version === "string") version = new Version(version);
return testDisjunction(version, this._alternatives);
}
toString() {
return formatDisjunction(this._alternatives);
}
}
interface Comparator {
readonly operator: "<" | "<=" | ">" | ">=" | "=";
readonly operand: Version;
}
// https://github.com/npm/node-semver#range-grammar
//
// range-set ::= range ( logical-or range ) *
// range ::= hyphen | simple ( ' ' simple ) * | ''
// logical-or ::= ( ' ' ) * '||' ( ' ' ) *
const logicalOrRegExp = /\s*\|\|\s*/g;
const whitespaceRegExp = /\s+/g;
// https://github.com/npm/node-semver#range-grammar
//
// partial ::= xr ( '.' xr ( '.' xr qualifier ? )? )?
// xr ::= 'x' | 'X' | '*' | nr
// nr ::= '0' | ['1'-'9'] ( ['0'-'9'] ) *
// qualifier ::= ( '-' pre )? ( '+' build )?
// pre ::= parts
// build ::= parts
// parts ::= part ( '.' part ) *
// part ::= nr | [-0-9A-Za-z]+
const partialRegExp = /^([xX*0]|[1-9]\d*)(?:\.([xX*0]|[1-9]\d*)(?:\.([xX*0]|[1-9]\d*)(?:-([a-z0-9-.]+))?(?:\+([a-z0-9-.]+))?)?)?$/i;
// https://github.com/npm/node-semver#range-grammar
//
// hyphen ::= partial ' - ' partial
const hyphenRegExp = /^\s*([a-z0-9-+.*]+)\s+-\s+([a-z0-9-+.*]+)\s*$/i;
// https://github.com/npm/node-semver#range-grammar
//
// simple ::= primitive | partial | tilde | caret
// primitive ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial
// tilde ::= '~' partial
// caret ::= '^' partial
const rangeRegExp = /^\s*(~|\^|<|<=|>|>=|=)?\s*([a-z0-9-+.*]+)$/i;
function parseRange(text: string) {
const alternatives: Comparator[][] = [];
for (const range of text.trim().split(logicalOrRegExp)) {
if (!range) continue;
const comparators: Comparator[] = [];
const match = hyphenRegExp.exec(range);
if (match) {
if (!parseHyphen(match[1], match[2], comparators)) return undefined;
}
else {
for (const simple of range.split(whitespaceRegExp)) {
const match = rangeRegExp.exec(simple);
if (!match || !parseComparator(match[1], match[2], comparators)) return undefined;
}
}
alternatives.push(comparators);
}
return alternatives;
}
function parsePartial(text: string) {
const match = partialRegExp.exec(text);
if (!match) return undefined;
const [, major, minor = "*", patch = "*", prerelease, build] = match;
const version = new Version(
isWildcard(major) ? 0 : parseInt(major, 10),
isWildcard(major) || isWildcard(minor) ? 0 : parseInt(minor, 10),
isWildcard(major) || isWildcard(minor) || isWildcard(patch) ? 0 : parseInt(patch, 10),
prerelease,
build);
return { version, major, minor, patch };
}
function parseHyphen(left: string, right: string, comparators: Comparator[]) {
const leftResult = parsePartial(left);
if (!leftResult) return false;
const rightResult = parsePartial(right);
if (!rightResult) return false;
if (!isWildcard(leftResult.major)) {
comparators.push(createComparator(">=", leftResult.version));
}
if (!isWildcard(rightResult.major)) {
comparators.push(
isWildcard(rightResult.minor) ? createComparator("<", rightResult.version.increment("major")) :
isWildcard(rightResult.patch) ? createComparator("<", rightResult.version.increment("minor")) :
createComparator("<=", rightResult.version));
}
return true;
}
function parseComparator(operator: string, text: string, comparators: Comparator[]) {
const result = parsePartial(text);
if (!result) return false;
const { version, major, minor, patch } = result;
if (!isWildcard(major)) {
switch (operator) {
case "~":
comparators.push(createComparator(">=", version));
comparators.push(createComparator("<", version.increment(
isWildcard(minor) ? "major" :
"minor")));
break;
case "^":
comparators.push(createComparator(">=", version));
comparators.push(createComparator("<", version.increment(
version.major > 0 || isWildcard(minor) ? "major" :
version.minor > 0 || isWildcard(patch) ? "minor" :
"patch")));
break;
case "<":
case ">=":
comparators.push(createComparator(operator, version));
break;
case "<=":
case ">":
comparators.push(
isWildcard(minor) ? createComparator(operator === "<=" ? "<" : ">=", version.increment("major")) :
isWildcard(patch) ? createComparator(operator === "<=" ? "<" : ">=", version.increment("minor")) :
createComparator(operator, version));
break;
case "=":
case undefined:
if (isWildcard(minor) || isWildcard(patch)) {
comparators.push(createComparator(">=", version));
comparators.push(createComparator("<", version.increment(isWildcard(minor) ? "major" : "minor")));
}
else {
comparators.push(createComparator("=", version));
}
break;
default:
// unrecognized
return false;
}
}
else if (operator === "<" || operator === ">") {
comparators.push(createComparator("<", Version.zero));
}
return true;
}
function isWildcard(part: string) {
return part === "*" || part === "x" || part === "X";
}
function createComparator(operator: Comparator["operator"], operand: Version) {
return { operator, operand };
}
function testDisjunction(version: Version, alternatives: ReadonlyArray<ReadonlyArray<Comparator>>) {
// an empty disjunction is treated as "*" (all versions)
if (alternatives.length === 0) return true;
for (const alternative of alternatives) {
if (testAlternative(version, alternative)) return true;
}
return false;
}
function testAlternative(version: Version, comparators: ReadonlyArray<Comparator>) {
for (const comparator of comparators) {
if (!testComparator(version, comparator.operator, comparator.operand)) return false;
}
return true;
}
function testComparator(version: Version, operator: Comparator["operator"], operand: Version) {
const cmp = version.compareTo(operand);
switch (operator) {
case "<": return cmp < 0;
case "<=": return cmp <= 0;
case ">": return cmp > 0;
case ">=": return cmp >= 0;
case "=": return cmp === 0;
default: return Debug.assertNever(operator);
}
}
function formatDisjunction(alternatives: ReadonlyArray<ReadonlyArray<Comparator>>) {
return map(alternatives, formatAlternative).join(" || ") || "*";
}
function formatAlternative(comparators: ReadonlyArray<Comparator>) {
return map(comparators, formatComparator).join(" ");
}
function formatComparator(comparator: Comparator) {
return `${comparator.operator}${comparator.operand}`;
}
}
+14 -28
View File
@@ -36,23 +36,6 @@ namespace ts {
Low = 250
}
function getPriorityValues(highPriorityValue: number): [number, number, number] {
const mediumPriorityValue = highPriorityValue * 2;
const lowPriorityValue = mediumPriorityValue * 4;
return [highPriorityValue, mediumPriorityValue, lowPriorityValue];
}
function pollingInterval(watchPriority: PollingInterval): number {
return pollingIntervalsForPriority[watchPriority];
}
const pollingIntervalsForPriority = getPriorityValues(250);
/* @internal */
export function watchFileUsingPriorityPollingInterval(host: System, fileName: string, callback: FileWatcherCallback, watchPriority: PollingInterval): FileWatcher {
return host.watchFile!(fileName, callback, pollingInterval(watchPriority));
}
/* @internal */
export type HostWatchFile = (fileName: string, callback: FileWatcherCallback, pollingInterval: PollingInterval | undefined) => FileWatcher;
/* @internal */
@@ -317,18 +300,22 @@ namespace ts {
const newTime = modifiedTime.getTime();
if (oldTime !== newTime) {
watchedFile.mtime = modifiedTime;
const eventKind = oldTime === 0
? FileWatcherEventKind.Created
: newTime === 0
? FileWatcherEventKind.Deleted
: FileWatcherEventKind.Changed;
watchedFile.callback(watchedFile.fileName, eventKind);
watchedFile.callback(watchedFile.fileName, getFileWatcherEventKind(oldTime, newTime));
return true;
}
return false;
}
/*@internal*/
export function getFileWatcherEventKind(oldTime: number, newTime: number) {
return oldTime === 0
? FileWatcherEventKind.Created
: newTime === 0
? FileWatcherEventKind.Deleted
: FileWatcherEventKind.Changed;
}
/*@internal*/
export interface RecursiveDirectoryWatcherHost {
watchDirectory: HostWatchDirectory;
@@ -792,11 +779,10 @@ namespace ts {
dirName,
(_eventName: string, relativeFileName) => {
// When files are deleted from disk, the triggered "rename" event would have a relativefileName of "undefined"
const fileName = !isString(relativeFileName)
? undefined! // TODO: GH#18217
: getNormalizedAbsolutePath(relativeFileName, dirName);
if (!isString(relativeFileName)) { return; }
const fileName = getNormalizedAbsolutePath(relativeFileName, dirName);
// Some applications save a working file via rename operations
const callbacks = fileWatcherCallbacks.get(toCanonicalName(fileName));
const callbacks = fileName && fileWatcherCallbacks.get(toCanonicalName(fileName));
if (callbacks) {
for (const fileCallback of callbacks) {
fileCallback(fileName, FileWatcherEventKind.Changed);
@@ -843,7 +829,7 @@ namespace ts {
}
}
type FsWatchCallback = (eventName: "rename" | "change", relativeFileName: string) => void;
type FsWatchCallback = (eventName: "rename" | "change", relativeFileName: string | undefined) => void;
function createFileWatcherCallback(callback: FsWatchCallback): FileWatcherCallback {
return (_fileName, eventKind) => callback(eventKind === FileWatcherEventKind.Changed ? "change" : "rename", "");
+14 -7
View File
@@ -1,11 +1,11 @@
/*@internal*/
namespace ts {
export function getDeclarationDiagnostics(host: EmitHost, resolver: EmitResolver, file: SourceFile | undefined): DiagnosticWithLocation[] | undefined {
if (file && isSourceFileJavaScript(file)) {
if (file && isSourceFileJS(file)) {
return []; // No declaration diagnostics for js for now
}
const compilerOptions = host.getCompilerOptions();
const result = transformNodes(resolver, host, compilerOptions, file ? [file] : filter(host.getSourceFiles(), isSourceFileNotJavaScript), [transformDeclarations], /*allowDtsFiles*/ false);
const result = transformNodes(resolver, host, compilerOptions, file ? [file] : filter(host.getSourceFiles(), isSourceFileNotJS), [transformDeclarations], /*allowDtsFiles*/ false);
return result.diagnostics;
}
@@ -157,7 +157,7 @@ namespace ts {
function transformRoot(node: SourceFile): SourceFile;
function transformRoot(node: SourceFile | Bundle): SourceFile | Bundle;
function transformRoot(node: SourceFile | Bundle) {
if (node.kind === SyntaxKind.SourceFile && (node.isDeclarationFile || isSourceFileJavaScript(node))) {
if (node.kind === SyntaxKind.SourceFile && (node.isDeclarationFile || isSourceFileJS(node))) {
return node;
}
@@ -168,7 +168,7 @@ namespace ts {
let hasNoDefaultLib = false;
const bundle = createBundle(map(node.sourceFiles,
sourceFile => {
if (sourceFile.isDeclarationFile || isSourceFileJavaScript(sourceFile)) return undefined!; // Omit declaration files from bundle results, too // TODO: GH#18217
if (sourceFile.isDeclarationFile || isSourceFileJS(sourceFile)) return undefined!; // Omit declaration files from bundle results, too // TODO: GH#18217
hasNoDefaultLib = hasNoDefaultLib || sourceFile.hasNoDefaultLib;
currentSourceFile = sourceFile;
enclosingDeclaration = sourceFile;
@@ -275,7 +275,7 @@ namespace ts {
else {
if (isBundledEmit && contains((node as Bundle).sourceFiles, file)) return; // Omit references to files which are being merged
const paths = getOutputPathsFor(file, host, /*forceDtsPaths*/ true);
declFileName = paths.declarationFilePath || paths.jsFilePath;
declFileName = paths.declarationFilePath || paths.jsFilePath || file.fileName;
}
if (declFileName) {
@@ -289,6 +289,13 @@ namespace ts {
if (startsWith(fileName, "./") && hasExtension(fileName)) {
fileName = fileName.substring(2);
}
// omit references to files from node_modules (npm may disambiguate module
// references when installing this package, making the path is unreliable).
if (startsWith(fileName, "node_modules/") || fileName.indexOf("/node_modules/") !== -1) {
return;
}
references.push({ pos: -1, end: -1, fileName });
}
};
@@ -296,7 +303,7 @@ namespace ts {
}
function collectReferences(sourceFile: SourceFile, ret: Map<SourceFile>) {
if (noResolve || isSourceFileJavaScript(sourceFile)) return ret;
if (noResolve || isSourceFileJS(sourceFile)) return ret;
forEach(sourceFile.referencedFiles, f => {
const elem = tryResolveScriptReference(host, sourceFile, f);
if (elem) {
@@ -982,7 +989,7 @@ namespace ts {
ensureType(input, input.type),
/*body*/ undefined
));
if (clean && resolver.isJSContainerFunctionDeclaration(input)) {
if (clean && resolver.isExpandoFunctionDeclaration(input)) {
const declarations = mapDefined(resolver.getPropertiesOfContainerFunction(input), p => {
if (!isPropertyAccessExpression(p.valueDeclaration)) {
return undefined;
@@ -434,7 +434,7 @@ namespace ts {
// Heritage clause is written by user so it can always be named
if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
// Class or Interface implemented/extended is inaccessible
diagnosticMessage = (node as ExpressionWithTypeArguments).parent.token === SyntaxKind.ImplementsKeyword ?
diagnosticMessage = isHeritageClause(node.parent) && node.parent.token === SyntaxKind.ImplementsKeyword ?
Diagnostics.Implements_clause_of_exported_class_0_has_or_is_using_private_name_1 :
Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1;
}
@@ -446,7 +446,7 @@ namespace ts {
return {
diagnosticMessage,
errorNode: node,
typeName: getNameOfDeclaration((node as ExpressionWithTypeArguments).parent.parent)
typeName: getNameOfDeclaration(node.parent.parent as Declaration)
};
}
@@ -466,4 +466,4 @@ namespace ts {
};
}
}
}
}
+3 -3
View File
@@ -307,8 +307,8 @@ namespace ts {
if (!getRestIndicatorOfBindingOrAssignmentElement(element)) {
const propertyName = getPropertyNameOfBindingOrAssignmentElement(element)!;
if (flattenContext.level >= FlattenLevel.ObjectRest
&& !(element.transformFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest))
&& !(getTargetOfBindingOrAssignmentElement(element)!.transformFlags & (TransformFlags.ContainsRest | TransformFlags.ContainsObjectRest))
&& !(element.transformFlags & (TransformFlags.ContainsRestOrSpread | TransformFlags.ContainsObjectRestOrSpread))
&& !(getTargetOfBindingOrAssignmentElement(element)!.transformFlags & (TransformFlags.ContainsRestOrSpread | TransformFlags.ContainsObjectRestOrSpread))
&& !isComputedPropertyName(propertyName)) {
bindingElements = append(bindingElements, element);
}
@@ -384,7 +384,7 @@ namespace ts {
if (flattenContext.level >= FlattenLevel.ObjectRest) {
// If an array pattern contains an ObjectRest, we must cache the result so that we
// can perform the ObjectRest destructuring in a different declaration
if (element.transformFlags & TransformFlags.ContainsObjectRest) {
if (element.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
const temp = createTempVariable(/*recordTempVariable*/ undefined);
if (flattenContext.hoistTempVariables) {
flattenContext.context.hoistVariableDeclaration(temp);
+458 -161
View File
@@ -46,10 +46,16 @@ namespace ts {
* so nobody can observe this new value.
*/
interface LoopOutParameter {
flags: LoopOutParameterFlags;
originalName: Identifier;
outParamName: Identifier;
}
const enum LoopOutParameterFlags {
Body = 1 << 0, // Modified in the body of the iteration statement
Initializer = 1 << 1, // Set in the initializer of a ForStatement
}
const enum CopyDirection {
ToOriginal,
ToOutParameter
@@ -129,10 +135,14 @@ namespace ts {
*/
hoistedLocalVariables?: Identifier[];
conditionVariable?: Identifier;
loopParameters: ParameterDeclaration[];
/**
* List of loop out parameters - detailed descripion can be found in the comment to LoopOutParameter
*/
loopOutParameters?: LoopOutParameter[];
loopOutParameters: LoopOutParameter[];
}
const enum SuperCaptureResult {
@@ -347,7 +357,7 @@ namespace ts {
return (node.transformFlags & TransformFlags.ContainsES2015) !== 0
|| convertedLoopState !== undefined
|| (hierarchyFacts & HierarchyFacts.ConstructorWithCapturedSuper && (isStatement(node) || (node.kind === SyntaxKind.Block)))
|| (isIterationStatement(node, /*lookInLabeledStatements*/ false) && shouldConvertIterationStatementBody(node))
|| (isIterationStatement(node, /*lookInLabeledStatements*/ false) && shouldConvertIterationStatement(node))
|| (getEmitFlags(node) & EmitFlags.TypeScriptClassWrapper) !== 0;
}
@@ -646,8 +656,8 @@ namespace ts {
}
}
let returnExpression: Expression = createLiteral(labelMarker);
if (convertedLoopState.loopOutParameters!.length) {
const outParams = convertedLoopState.loopOutParameters!;
if (convertedLoopState.loopOutParameters.length) {
const outParams = convertedLoopState.loopOutParameters;
let expr: Expression | undefined;
for (let i = 0; i < outParams.length; i++) {
const copyExpr = copyOutParameter(outParams[i], CopyDirection.ToOutParameter);
@@ -2610,7 +2620,40 @@ namespace ts {
return visitEachChild(node, visitor, context);
}
function shouldConvertIterationStatementBody(node: IterationStatement): boolean {
interface ForStatementWithConvertibleInitializer extends ForStatement {
initializer: VariableDeclarationList;
}
interface ForStatementWithConvertibleCondition extends ForStatement {
condition: Expression;
}
interface ForStatementWithConvertibleIncrementor extends ForStatement {
incrementor: Expression;
}
function shouldConvertPartOfIterationStatement(node: Node) {
return (resolver.getNodeCheckFlags(node) & NodeCheckFlags.ContainsCapturedBlockScopeBinding) !== 0;
}
function shouldConvertInitializerOfForStatement(node: IterationStatement): node is ForStatementWithConvertibleInitializer {
return isForStatement(node) && !!node.initializer && shouldConvertPartOfIterationStatement(node.initializer);
}
function shouldConvertConditionOfForStatement(node: IterationStatement): node is ForStatementWithConvertibleCondition {
return isForStatement(node) && !!node.condition && shouldConvertPartOfIterationStatement(node.condition);
}
function shouldConvertIncrementorOfForStatement(node: IterationStatement): node is ForStatementWithConvertibleIncrementor {
return isForStatement(node) && !!node.incrementor && shouldConvertPartOfIterationStatement(node.incrementor);
}
function shouldConvertIterationStatement(node: IterationStatement) {
return shouldConvertBodyOfIterationStatement(node)
|| shouldConvertInitializerOfForStatement(node);
}
function shouldConvertBodyOfIterationStatement(node: IterationStatement): boolean {
return (resolver.getNodeCheckFlags(node) & NodeCheckFlags.LoopWithCapturedBlockScopedBinding) !== 0;
}
@@ -2639,7 +2682,7 @@ namespace ts {
}
function convertIterationStatementBodyIfNecessary(node: IterationStatement, outermostLabeledStatement: LabeledStatement | undefined, convert?: LoopConverter): VisitResult<Statement> {
if (!shouldConvertIterationStatementBody(node)) {
if (!shouldConvertIterationStatement(node)) {
let saveAllowedNonLabeledJumps: Jump | undefined;
if (convertedLoopState) {
// we get here if we are trying to emit normal loop loop inside converted loop
@@ -2658,7 +2701,102 @@ namespace ts {
return result;
}
const functionName = createUniqueName("_loop");
const currentState = createConvertedLoopState(node);
const statements: Statement[] = [];
const outerConvertedLoopState = convertedLoopState;
convertedLoopState = currentState;
const initializerFunction = shouldConvertInitializerOfForStatement(node) ? createFunctionForInitializerOfForStatement(node, currentState) : undefined;
const bodyFunction = shouldConvertBodyOfIterationStatement(node) ? createFunctionForBodyOfIterationStatement(node, currentState, outerConvertedLoopState) : undefined;
convertedLoopState = outerConvertedLoopState;
if (initializerFunction) statements.push(initializerFunction.functionDeclaration);
if (bodyFunction) statements.push(bodyFunction.functionDeclaration);
addExtraDeclarationsForConvertedLoop(statements, currentState, outerConvertedLoopState);
if (initializerFunction) {
statements.push(generateCallToConvertedLoopInitializer(initializerFunction.functionName, initializerFunction.containsYield));
}
let loop: Statement;
if (bodyFunction) {
if (convert) {
loop = convert(node, outermostLabeledStatement, bodyFunction.part);
}
else {
const clone = convertIterationStatementCore(node, initializerFunction, createBlock(bodyFunction.part, /*multiLine*/ true));
aggregateTransformFlags(clone);
loop = restoreEnclosingLabel(clone, outermostLabeledStatement, convertedLoopState && resetLabel);
}
}
else {
const clone = convertIterationStatementCore(node, initializerFunction, visitNode(node.statement, visitor, isStatement, liftToBlock));
aggregateTransformFlags(clone);
loop = restoreEnclosingLabel(clone, outermostLabeledStatement, convertedLoopState && resetLabel);
}
statements.push(loop);
return statements;
}
function convertIterationStatementCore(node: IterationStatement, initializerFunction: IterationStatementPartFunction<VariableDeclarationList> | undefined, convertedLoopBody: Statement) {
switch (node.kind) {
case SyntaxKind.ForStatement: return convertForStatement(node as ForStatement, initializerFunction, convertedLoopBody);
case SyntaxKind.ForInStatement: return convertForInStatement(node as ForInStatement, convertedLoopBody);
case SyntaxKind.ForOfStatement: return convertForOfStatement(node as ForOfStatement, convertedLoopBody);
case SyntaxKind.DoStatement: return convertDoStatement(node as DoStatement, convertedLoopBody);
case SyntaxKind.WhileStatement: return convertWhileStatement(node as WhileStatement, convertedLoopBody);
default: return Debug.failBadSyntaxKind(node, "IterationStatement expected");
}
}
function convertForStatement(node: ForStatement, initializerFunction: IterationStatementPartFunction<VariableDeclarationList> | undefined, convertedLoopBody: Statement) {
const shouldConvertCondition = node.condition && shouldConvertPartOfIterationStatement(node.condition);
const shouldConvertIncrementor = shouldConvertCondition || node.incrementor && shouldConvertPartOfIterationStatement(node.incrementor);
return updateFor(
node,
visitNode(initializerFunction ? initializerFunction.part : node.initializer, visitor, isForInitializer),
visitNode(shouldConvertCondition ? undefined : node.condition, visitor, isExpression),
visitNode(shouldConvertIncrementor ? undefined : node.incrementor, visitor, isExpression),
convertedLoopBody
);
}
function convertForOfStatement(node: ForOfStatement, convertedLoopBody: Statement) {
return updateForOf(
node,
/*awaitModifier*/ undefined,
visitNode(node.initializer, visitor, isForInitializer),
visitNode(node.expression, visitor, isExpression),
convertedLoopBody);
}
function convertForInStatement(node: ForInStatement, convertedLoopBody: Statement) {
return updateForIn(
node,
visitNode(node.initializer, visitor, isForInitializer),
visitNode(node.expression, visitor, isExpression),
convertedLoopBody);
}
function convertDoStatement(node: DoStatement, convertedLoopBody: Statement) {
return updateDo(
node,
convertedLoopBody,
visitNode(node.expression, visitor, isExpression));
}
function convertWhileStatement(node: WhileStatement, convertedLoopBody: Statement) {
return updateWhile(
node,
visitNode(node.expression, visitor, isExpression),
convertedLoopBody);
}
function createConvertedLoopState(node: IterationStatement) {
let loopInitializer: VariableDeclarationList | undefined;
switch (node.kind) {
case SyntaxKind.ForStatement:
@@ -2670,74 +2808,311 @@ namespace ts {
}
break;
}
// variables that will be passed to the loop as parameters
const loopParameters: ParameterDeclaration[] = [];
// variables declared in the loop initializer that will be changed inside the loop
const loopOutParameters: LoopOutParameter[] = [];
if (loopInitializer && (getCombinedNodeFlags(loopInitializer) & NodeFlags.BlockScoped)) {
const hasCapturedBindingsInForInitializer = shouldConvertInitializerOfForStatement(node);
for (const decl of loopInitializer.declarations) {
processLoopVariableDeclaration(decl, loopParameters, loopOutParameters);
processLoopVariableDeclaration(node, decl, loopParameters, loopOutParameters, hasCapturedBindingsInForInitializer);
}
}
const outerConvertedLoopState = convertedLoopState;
convertedLoopState = { loopOutParameters };
if (outerConvertedLoopState) {
const currentState: ConvertedLoopState = { loopParameters, loopOutParameters };
if (convertedLoopState) {
// convertedOuterLoopState !== undefined means that this converted loop is nested in another converted loop.
// if outer converted loop has already accumulated some state - pass it through
if (outerConvertedLoopState.argumentsName) {
if (convertedLoopState.argumentsName) {
// outer loop has already used 'arguments' so we've already have some name to alias it
// use the same name in all nested loops
convertedLoopState.argumentsName = outerConvertedLoopState.argumentsName;
currentState.argumentsName = convertedLoopState.argumentsName;
}
if (outerConvertedLoopState.thisName) {
if (convertedLoopState.thisName) {
// outer loop has already used 'this' so we've already have some name to alias it
// use the same name in all nested loops
convertedLoopState.thisName = outerConvertedLoopState.thisName;
currentState.thisName = convertedLoopState.thisName;
}
if (outerConvertedLoopState.hoistedLocalVariables) {
if (convertedLoopState.hoistedLocalVariables) {
// we've already collected some non-block scoped variable declarations in enclosing loop
// use the same storage in nested loop
convertedLoopState.hoistedLocalVariables = outerConvertedLoopState.hoistedLocalVariables;
currentState.hoistedLocalVariables = convertedLoopState.hoistedLocalVariables;
}
}
return currentState;
}
function addExtraDeclarationsForConvertedLoop(statements: Statement[], state: ConvertedLoopState, outerState: ConvertedLoopState | undefined) {
let extraVariableDeclarations: VariableDeclaration[] | undefined;
// propagate state from the inner loop to the outer loop if necessary
if (state.argumentsName) {
// if alias for arguments is set
if (outerState) {
// pass it to outer converted loop
outerState.argumentsName = state.argumentsName;
}
else {
// this is top level converted loop and we need to create an alias for 'arguments' object
(extraVariableDeclarations || (extraVariableDeclarations = [])).push(
createVariableDeclaration(
state.argumentsName,
/*type*/ undefined,
createIdentifier("arguments")
)
);
}
}
if (state.thisName) {
// if alias for this is set
if (outerState) {
// pass it to outer converted loop
outerState.thisName = state.thisName;
}
else {
// this is top level converted loop so we need to create an alias for 'this' here
// NOTE:
// if converted loops were all nested in arrow function then we'll always emit '_this' so convertedLoopState.thisName will not be set.
// If it is set this means that all nested loops are not nested in arrow function and it is safe to capture 'this'.
(extraVariableDeclarations || (extraVariableDeclarations = [])).push(
createVariableDeclaration(
state.thisName,
/*type*/ undefined,
createIdentifier("this")
)
);
}
}
if (state.hoistedLocalVariables) {
// if hoistedLocalVariables !== undefined this means that we've possibly collected some variable declarations to be hoisted later
if (outerState) {
// pass them to outer converted loop
outerState.hoistedLocalVariables = state.hoistedLocalVariables;
}
else {
if (!extraVariableDeclarations) {
extraVariableDeclarations = [];
}
// hoist collected variable declarations
for (const identifier of state.hoistedLocalVariables) {
extraVariableDeclarations.push(createVariableDeclaration(identifier));
}
}
}
// add extra variables to hold out parameters if necessary
if (state.loopOutParameters.length) {
if (!extraVariableDeclarations) {
extraVariableDeclarations = [];
}
for (const outParam of state.loopOutParameters) {
extraVariableDeclarations.push(createVariableDeclaration(outParam.outParamName));
}
}
if (state.conditionVariable) {
if (!extraVariableDeclarations) {
extraVariableDeclarations = [];
}
extraVariableDeclarations.push(createVariableDeclaration(state.conditionVariable, /*type*/ undefined, createFalse()));
}
// create variable statement to hold all introduced variable declarations
if (extraVariableDeclarations) {
statements.push(createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(extraVariableDeclarations)
));
}
}
interface IterationStatementPartFunction<T> {
functionName: Identifier;
functionDeclaration: Statement;
containsYield: boolean;
part: T;
}
function createOutVariable(p: LoopOutParameter) {
return createVariableDeclaration(p.originalName, /*type*/ undefined, p.outParamName);
}
/**
* Creates a `_loop_init` function for a `ForStatement` with a block-scoped initializer
* that is captured in a closure inside of the initializer. The `_loop_init` function is
* used to preserve the per-iteration environment semantics of
* [13.7.4.8 RS: ForBodyEvaluation](https://tc39.github.io/ecma262/#sec-forbodyevaluation).
*/
function createFunctionForInitializerOfForStatement(node: ForStatementWithConvertibleInitializer, currentState: ConvertedLoopState): IterationStatementPartFunction<VariableDeclarationList> {
const functionName = createUniqueName("_loop_init");
const containsYield = (node.initializer.transformFlags & TransformFlags.ContainsYield) !== 0;
let emitFlags = EmitFlags.None;
if (currentState.containsLexicalThis) emitFlags |= EmitFlags.CapturesThis;
if (containsYield && hierarchyFacts & HierarchyFacts.AsyncFunctionBody) emitFlags |= EmitFlags.AsyncFunctionBody;
const statements: Statement[] = [];
statements.push(createVariableStatement(/*modifiers*/ undefined, node.initializer));
copyOutParameters(currentState.loopOutParameters, LoopOutParameterFlags.Initializer, CopyDirection.ToOutParameter, statements);
// This transforms the following ES2015 syntax:
//
// for (let i = (setImmediate(() => console.log(i)), 0); i < 2; i++) {
// // loop body
// }
//
// Into the following ES5 syntax:
//
// var _loop_init_1 = function () {
// var i = (setImmediate(() => console.log(i)), 0);
// out_i_1 = i;
// };
// var out_i_1;
// _loop_init_1();
// for (var i = out_i_1; i < 2; i++) {
// // loop body
// }
//
// Which prevents mutations to `i` in the per-iteration environment of the body
// from affecting the initial value for `i` outside of the per-iteration environment.
const functionDeclaration = createVariableStatement(
/*modifiers*/ undefined,
setEmitFlags(
createVariableDeclarationList([
createVariableDeclaration(
functionName,
/*type*/ undefined,
setEmitFlags(
createFunctionExpression(
/*modifiers*/ undefined,
containsYield ? createToken(SyntaxKind.AsteriskToken) : undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
/*parameters*/ undefined,
/*type*/ undefined,
visitNode(
createBlock(statements, /*multiLine*/ true),
visitor,
isBlock
)
),
emitFlags
)
)
]),
EmitFlags.NoHoisting
)
);
const part = createVariableDeclarationList(map(currentState.loopOutParameters, createOutVariable));
return { functionName, containsYield, functionDeclaration, part };
}
/**
* Creates a `_loop` function for an `IterationStatement` with a block-scoped initializer
* that is captured in a closure inside of the loop body. The `_loop` function is used to
* preserve the per-iteration environment semantics of
* [13.7.4.8 RS: ForBodyEvaluation](https://tc39.github.io/ecma262/#sec-forbodyevaluation).
*/
function createFunctionForBodyOfIterationStatement(node: IterationStatement, currentState: ConvertedLoopState, outerState: ConvertedLoopState | undefined): IterationStatementPartFunction<Statement[]> {
const functionName = createUniqueName("_loop");
startLexicalEnvironment();
let loopBody = visitNode(node.statement, visitor, isStatement, liftToBlock);
const statement = visitNode(node.statement, visitor, isStatement, liftToBlock);
const lexicalEnvironment = endLexicalEnvironment();
const currentState = convertedLoopState;
convertedLoopState = outerConvertedLoopState;
const statements: Statement[] = [];
if (shouldConvertConditionOfForStatement(node) || shouldConvertIncrementorOfForStatement(node)) {
// If a block-scoped variable declared in the initializer of `node` is captured in
// the condition or incrementor, we must move the condition and incrementor into
// the body of the for loop.
//
// This transforms the following ES2015 syntax:
//
// for (let i = 0; setImmediate(() => console.log(i)), i < 2; setImmediate(() => console.log(i)), i++) {
// // loop body
// }
//
// Into the following ES5 syntax:
//
// var _loop_1 = function (i) {
// if (inc_1)
// setImmediate(() => console.log(i)), i++;
// else
// inc_1 = true;
// if (!(setImmediate(() => console.log(i)), i < 2))
// return out_i_1 = i, "break";
// // loop body
// out_i_1 = i;
// }
// var out_i_1, inc_1 = false;
// for (var i = 0;;) {
// var state_1 = _loop_1(i);
// i = out_i_1;
// if (state_1 === "break")
// break;
// }
//
// Which prevents mutations to `i` in the per-iteration environment of the body
// from affecting the value of `i` in the previous per-iteration environment.
//
// Note that the incrementor of a `for` loop is evaluated in a *new* per-iteration
// environment that is carried over to the next iteration of the loop. As a result,
// we must indicate whether this is the first evaluation of the loop body so that
// we only evaluate the incrementor on subsequent evaluations.
if (loopOutParameters.length || lexicalEnvironment) {
const statements = isBlock(loopBody) ? loopBody.statements.slice() : [loopBody];
if (loopOutParameters.length) {
copyOutParameters(loopOutParameters, CopyDirection.ToOutParameter, statements);
currentState.conditionVariable = createUniqueName("inc");
statements.push(createIf(
currentState.conditionVariable,
createStatement(visitNode(node.incrementor, visitor, isExpression)),
createStatement(createAssignment(currentState.conditionVariable, createTrue()))
));
if (shouldConvertConditionOfForStatement(node)) {
statements.push(createIf(
createPrefix(SyntaxKind.ExclamationToken, visitNode(node.condition, visitor, isExpression)),
visitNode(createBreak(), visitor, isStatement)
));
}
addStatementsAfterPrologue(statements, lexicalEnvironment);
loopBody = createBlock(statements, /*multiline*/ true);
}
if (isBlock(loopBody)) {
loopBody.multiLine = true;
if (isBlock(statement)) {
addRange(statements, statement.statements);
}
else {
loopBody = createBlock([loopBody], /*multiline*/ true);
statements.push(statement);
}
copyOutParameters(currentState.loopOutParameters, LoopOutParameterFlags.Body, CopyDirection.ToOutParameter, statements);
addStatementsAfterPrologue(statements, lexicalEnvironment);
const loopBody = createBlock(statements, /*multiLine*/ true);
if (isBlock(statement)) setOriginalNode(loopBody, statement);
const containsYield = (node.statement.transformFlags & TransformFlags.ContainsYield) !== 0;
const isAsyncBlockContainingAwait = containsYield && (hierarchyFacts & HierarchyFacts.AsyncFunctionBody) !== 0;
let loopBodyFlags: EmitFlags = 0;
if (currentState.containsLexicalThis) {
loopBodyFlags |= EmitFlags.CapturesThis;
}
let emitFlags: EmitFlags = 0;
if (currentState.containsLexicalThis) emitFlags |= EmitFlags.CapturesThis;
if (containsYield && (hierarchyFacts & HierarchyFacts.AsyncFunctionBody) !== 0) emitFlags |= EmitFlags.AsyncFunctionBody;
if (isAsyncBlockContainingAwait) {
loopBodyFlags |= EmitFlags.AsyncFunctionBody;
}
// This transforms the following ES2015 syntax (in addition to other variations):
//
// for (let i = 0; i < 2; i++) {
// setImmediate(() => console.log(i));
// }
//
// Into the following ES5 syntax:
//
// var _loop_1 = function (i) {
// setImmediate(() => console.log(i));
// };
// for (var i = 0; i < 2; i++) {
// _loop_1(i);
// }
const convertedLoopVariable =
const functionDeclaration =
createVariableStatement(
/*modifiers*/ undefined,
setEmitFlags(
@@ -2752,11 +3127,11 @@ namespace ts {
containsYield ? createToken(SyntaxKind.AsteriskToken) : undefined,
/*name*/ undefined,
/*typeParameters*/ undefined,
loopParameters,
currentState.loopParameters,
/*type*/ undefined,
<Block>loopBody
loopBody
),
loopBodyFlags
emitFlags
)
)
]
@@ -2765,106 +3140,8 @@ namespace ts {
)
);
const statements: Statement[] = [convertedLoopVariable];
let extraVariableDeclarations: VariableDeclaration[] | undefined;
// propagate state from the inner loop to the outer loop if necessary
if (currentState.argumentsName) {
// if alias for arguments is set
if (outerConvertedLoopState) {
// pass it to outer converted loop
outerConvertedLoopState.argumentsName = currentState.argumentsName;
}
else {
// this is top level converted loop and we need to create an alias for 'arguments' object
(extraVariableDeclarations || (extraVariableDeclarations = [])).push(
createVariableDeclaration(
currentState.argumentsName,
/*type*/ undefined,
createIdentifier("arguments")
)
);
}
}
if (currentState.thisName) {
// if alias for this is set
if (outerConvertedLoopState) {
// pass it to outer converted loop
outerConvertedLoopState.thisName = currentState.thisName;
}
else {
// this is top level converted loop so we need to create an alias for 'this' here
// NOTE:
// if converted loops were all nested in arrow function then we'll always emit '_this' so convertedLoopState.thisName will not be set.
// If it is set this means that all nested loops are not nested in arrow function and it is safe to capture 'this'.
(extraVariableDeclarations || (extraVariableDeclarations = [])).push(
createVariableDeclaration(
currentState.thisName,
/*type*/ undefined,
createIdentifier("this")
)
);
}
}
if (currentState.hoistedLocalVariables) {
// if hoistedLocalVariables !== undefined this means that we've possibly collected some variable declarations to be hoisted later
if (outerConvertedLoopState) {
// pass them to outer converted loop
outerConvertedLoopState.hoistedLocalVariables = currentState.hoistedLocalVariables;
}
else {
if (!extraVariableDeclarations) {
extraVariableDeclarations = [];
}
// hoist collected variable declarations
for (const identifier of currentState.hoistedLocalVariables) {
extraVariableDeclarations.push(createVariableDeclaration(identifier));
}
}
}
// add extra variables to hold out parameters if necessary
if (loopOutParameters.length) {
if (!extraVariableDeclarations) {
extraVariableDeclarations = [];
}
for (const outParam of loopOutParameters) {
extraVariableDeclarations.push(createVariableDeclaration(outParam.outParamName));
}
}
// create variable statement to hold all introduced variable declarations
if (extraVariableDeclarations) {
statements.push(createVariableStatement(
/*modifiers*/ undefined,
createVariableDeclarationList(extraVariableDeclarations)
));
}
const convertedLoopBodyStatements = generateCallToConvertedLoop(functionName, loopParameters, currentState, containsYield);
let loop: Statement;
if (convert) {
loop = convert(node, outermostLabeledStatement, convertedLoopBodyStatements);
}
else {
let clone = getMutableClone(node);
// clean statement part
clone.statement = undefined!;
// visit childnodes to transform initializer/condition/incrementor parts
clone = visitEachChild(clone, visitor, context);
// set loop statement
clone.statement = createBlock(convertedLoopBodyStatements, /*multiline*/ true);
// reset and re-aggregate the transform flags
clone.transformFlags = 0;
aggregateTransformFlags(clone);
loop = restoreEnclosingLabel(clone, outermostLabeledStatement, convertedLoopState && resetLabel);
}
statements.push(loop);
return statements;
const part = generateCallToConvertedLoop(functionName, currentState, outerState, containsYield);
return { functionName, containsYield, functionDeclaration, part };
}
function copyOutParameter(outParam: LoopOutParameter, copyDirection: CopyDirection): BinaryExpression {
@@ -2873,14 +3150,26 @@ namespace ts {
return createBinary(target, SyntaxKind.EqualsToken, source);
}
function copyOutParameters(outParams: LoopOutParameter[], copyDirection: CopyDirection, statements: Statement[]): void {
function copyOutParameters(outParams: LoopOutParameter[], partFlags: LoopOutParameterFlags, copyDirection: CopyDirection, statements: Statement[]): void {
for (const outParam of outParams) {
statements.push(createExpressionStatement(copyOutParameter(outParam, copyDirection)));
if (outParam.flags & partFlags) {
statements.push(createExpressionStatement(copyOutParameter(outParam, copyDirection)));
}
}
}
function generateCallToConvertedLoop(loopFunctionExpressionName: Identifier, parameters: ParameterDeclaration[], state: ConvertedLoopState, isAsyncBlockContainingAwait: boolean): Statement[] {
const outerConvertedLoopState = convertedLoopState;
function generateCallToConvertedLoopInitializer(initFunctionExpressionName: Identifier, containsYield: boolean): Statement {
const call = createCall(initFunctionExpressionName, /*typeArguments*/ undefined, []);
const callResult = containsYield
? createYield(
createToken(SyntaxKind.AsteriskToken),
setEmitFlags(call, EmitFlags.Iterator)
)
: call;
return createStatement(callResult);
}
function generateCallToConvertedLoop(loopFunctionExpressionName: Identifier, state: ConvertedLoopState, outerState: ConvertedLoopState | undefined, containsYield: boolean): Statement[] {
const statements: Statement[] = [];
// loop is considered simple if it does not have any return statements or break\continue that transfer control outside of the loop
@@ -2891,8 +3180,8 @@ namespace ts {
!state.labeledNonLocalBreaks &&
!state.labeledNonLocalContinues;
const call = createCall(loopFunctionExpressionName, /*typeArguments*/ undefined, map(parameters, p => <Identifier>p.name));
const callResult = isAsyncBlockContainingAwait
const call = createCall(loopFunctionExpressionName, /*typeArguments*/ undefined, map(state.loopParameters, p => <Identifier>p.name));
const callResult = containsYield
? createYield(
createToken(SyntaxKind.AsteriskToken),
setEmitFlags(call, EmitFlags.Iterator)
@@ -2900,7 +3189,7 @@ namespace ts {
: call;
if (isSimpleLoop) {
statements.push(createExpressionStatement(callResult));
copyOutParameters(state.loopOutParameters!, CopyDirection.ToOriginal, statements);
copyOutParameters(state.loopOutParameters, LoopOutParameterFlags.Body, CopyDirection.ToOriginal, statements);
}
else {
const loopResultName = createUniqueName("state");
@@ -2911,12 +3200,12 @@ namespace ts {
)
);
statements.push(stateVariable);
copyOutParameters(state.loopOutParameters!, CopyDirection.ToOriginal, statements);
copyOutParameters(state.loopOutParameters, LoopOutParameterFlags.Body, CopyDirection.ToOriginal, statements);
if (state.nonLocalJumps! & Jump.Return) {
let returnStatement: ReturnStatement;
if (outerConvertedLoopState) {
outerConvertedLoopState.nonLocalJumps! |= Jump.Return;
if (outerState) {
outerState.nonLocalJumps! |= Jump.Return;
returnStatement = createReturn(loopResultName);
}
else {
@@ -2949,8 +3238,8 @@ namespace ts {
if (state.labeledNonLocalBreaks || state.labeledNonLocalContinues) {
const caseClauses: CaseClause[] = [];
processLabeledJumps(state.labeledNonLocalBreaks!, /*isBreak*/ true, loopResultName, outerConvertedLoopState, caseClauses);
processLabeledJumps(state.labeledNonLocalContinues!, /*isBreak*/ false, loopResultName, outerConvertedLoopState, caseClauses);
processLabeledJumps(state.labeledNonLocalBreaks!, /*isBreak*/ true, loopResultName, outerState, caseClauses);
processLabeledJumps(state.labeledNonLocalContinues!, /*isBreak*/ false, loopResultName, outerState, caseClauses);
statements.push(
createSwitch(
loopResultName,
@@ -2998,20 +3287,28 @@ namespace ts {
});
}
function processLoopVariableDeclaration(decl: VariableDeclaration | BindingElement, loopParameters: ParameterDeclaration[], loopOutParameters: LoopOutParameter[]) {
function processLoopVariableDeclaration(container: IterationStatement, decl: VariableDeclaration | BindingElement, loopParameters: ParameterDeclaration[], loopOutParameters: LoopOutParameter[], hasCapturedBindingsInForInitializer: boolean) {
const name = decl.name;
if (isBindingPattern(name)) {
for (const element of name.elements) {
if (!isOmittedExpression(element)) {
processLoopVariableDeclaration(element, loopParameters, loopOutParameters);
processLoopVariableDeclaration(container, element, loopParameters, loopOutParameters, hasCapturedBindingsInForInitializer);
}
}
}
else {
loopParameters.push(createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name));
if (resolver.getNodeCheckFlags(decl) & NodeCheckFlags.NeedsLoopOutParameter) {
const checkFlags = resolver.getNodeCheckFlags(decl);
if (checkFlags & NodeCheckFlags.NeedsLoopOutParameter || hasCapturedBindingsInForInitializer) {
const outParamName = createUniqueName("out_" + idText(name));
loopOutParameters.push({ originalName: name, outParamName });
let flags: LoopOutParameterFlags = 0;
if (checkFlags & NodeCheckFlags.NeedsLoopOutParameter) {
flags |= LoopOutParameterFlags.Body;
}
if (isForStatement(container) && container.initializer && resolver.isBindingCapturedByNode(container.initializer, decl)) {
flags |= LoopOutParameterFlags.Initializer;
}
loopOutParameters.push({ flags, originalName: name, outParamName });
}
}
}
@@ -3432,7 +3729,7 @@ namespace ts {
function visitCallExpressionWithPotentialCapturedThisAssignment(node: CallExpression, assignToCapturedThis: boolean): CallExpression | BinaryExpression {
// We are here either because SuperKeyword was used somewhere in the expression, or
// because we contain a SpreadElementExpression.
if (node.transformFlags & TransformFlags.ContainsSpread ||
if (node.transformFlags & TransformFlags.ContainsRestOrSpread ||
node.expression.kind === SyntaxKind.SuperKeyword ||
isSuperProperty(skipOuterExpressions(node.expression))) {
@@ -3442,7 +3739,7 @@ namespace ts {
}
let resultingCall: CallExpression | BinaryExpression;
if (node.transformFlags & TransformFlags.ContainsSpread) {
if (node.transformFlags & TransformFlags.ContainsRestOrSpread) {
// [source]
// f(...a, b)
// x.m(...a, b)
@@ -3505,7 +3802,7 @@ namespace ts {
* @param node A NewExpression node.
*/
function visitNewExpression(node: NewExpression): LeftHandSideExpression {
if (node.transformFlags & TransformFlags.ContainsSpread) {
if (node.transformFlags & TransformFlags.ContainsRestOrSpread) {
// We are here because we contain a SpreadElementExpression.
// [source]
// new C(...a)
@@ -4079,7 +4376,7 @@ namespace ts {
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
}
};
return function (d, b) {
extendStatics(d, b);
+144 -14
View File
@@ -32,6 +32,15 @@ namespace ts {
let enclosingFunctionParameterNames: UnderscoreEscapedMap<true>;
/**
* Keeps track of property names accessed on super (`super.x`) within async functions.
*/
let capturedSuperProperties: UnderscoreEscapedMap<true>;
/** Whether the async function contains an element access on super (`super[x]`). */
let hasSuperElementAccess: boolean;
/** A set of node IDs for generated super accessors (variable statements). */
const substitutedSuperAccessors: boolean[] = [];
// Save the previous transformation hooks.
const previousOnEmitNode = context.onEmitNode;
const previousOnSubstituteNode = context.onSubstituteNode;
@@ -56,7 +65,6 @@ namespace ts {
if ((node.transformFlags & TransformFlags.ContainsES2017) === 0) {
return node;
}
switch (node.kind) {
case SyntaxKind.AsyncKeyword:
// ES2017 async modifier should be elided for targets < ES2017
@@ -77,6 +85,18 @@ namespace ts {
case SyntaxKind.ArrowFunction:
return visitArrowFunction(<ArrowFunction>node);
case SyntaxKind.PropertyAccessExpression:
if (capturedSuperProperties && isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.SuperKeyword) {
capturedSuperProperties.set(node.name.escapedText, true);
}
return visitEachChild(node, visitor, context);
case SyntaxKind.ElementAccessExpression:
if (capturedSuperProperties && (<ElementAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword) {
hasSuperElementAccess = true;
}
return visitEachChild(node, visitor, context);
default:
return visitEachChild(node, visitor, context);
}
@@ -398,6 +418,11 @@ namespace ts {
recordDeclarationName(parameter, enclosingFunctionParameterNames);
}
const savedCapturedSuperProperties = capturedSuperProperties;
const savedHasSuperElementAccess = hasSuperElementAccess;
capturedSuperProperties = createUnderscoreEscapedMap<true>();
hasSuperElementAccess = false;
let result: ConciseBody;
if (!isArrowFunction) {
const statements: Statement[] = [];
@@ -415,18 +440,26 @@ namespace ts {
addStatementsAfterPrologue(statements, endLexicalEnvironment());
// Minor optimization, emit `_super` helper to capture `super` access in an arrow.
// This step isn't needed if we eventually transform this to ES5.
const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 && resolver.getNodeCheckFlags(node) & (NodeCheckFlags.AsyncMethodWithSuperBinding | NodeCheckFlags.AsyncMethodWithSuper);
if (emitSuperHelpers) {
enableSubstitutionForAsyncMethodsWithSuper();
const variableStatement = createSuperAccessVariableStatement(resolver, node, capturedSuperProperties);
substitutedSuperAccessors[getNodeId(variableStatement)] = true;
addStatementsAfterPrologue(statements, [variableStatement]);
}
const block = createBlock(statements, /*multiLine*/ true);
setTextRange(block, node.body);
// Minor optimization, emit `_super` helper to capture `super` access in an arrow.
// This step isn't needed if we eventually transform this to ES5.
if (languageVersion >= ScriptTarget.ES2015) {
if (emitSuperHelpers && hasSuperElementAccess) {
// Emit helpers for super element access expressions (`super[x]`).
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.AsyncMethodWithSuperBinding) {
enableSubstitutionForAsyncMethodsWithSuper();
addEmitHelper(block, advancedAsyncSuperHelper);
}
else if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.AsyncMethodWithSuper) {
enableSubstitutionForAsyncMethodsWithSuper();
addEmitHelper(block, asyncSuperHelper);
}
}
@@ -452,6 +485,8 @@ namespace ts {
}
enclosingFunctionParameterNames = savedEnclosingFunctionParameterNames;
capturedSuperProperties = savedCapturedSuperProperties;
hasSuperElementAccess = savedHasSuperElementAccess;
return result;
}
@@ -493,6 +528,8 @@ namespace ts {
context.enableEmitNotification(SyntaxKind.GetAccessor);
context.enableEmitNotification(SyntaxKind.SetAccessor);
context.enableEmitNotification(SyntaxKind.Constructor);
// We need to be notified when entering the generated accessor arrow functions.
context.enableEmitNotification(SyntaxKind.VariableStatement);
}
}
@@ -516,6 +553,14 @@ namespace ts {
return;
}
}
// Disable substitution in the generated super accessor itself.
else if (enabledSubstitutions && substitutedSuperAccessors[getNodeId(node)]) {
const savedEnclosingSuperContainerFlags = enclosingSuperContainerFlags;
enclosingSuperContainerFlags = 0;
previousOnEmitNode(hint, node, emitCallback);
enclosingSuperContainerFlags = savedEnclosingSuperContainerFlags;
return;
}
previousOnEmitNode(hint, node, emitCallback);
}
@@ -548,8 +593,10 @@ namespace ts {
function substitutePropertyAccessExpression(node: PropertyAccessExpression) {
if (node.expression.kind === SyntaxKind.SuperKeyword) {
return createSuperAccessInAsyncMethod(
createLiteral(idText(node.name)),
return setTextRange(
createPropertyAccess(
createFileLevelUniqueName("_super"),
node.name),
node
);
}
@@ -558,7 +605,7 @@ namespace ts {
function substituteElementAccessExpression(node: ElementAccessExpression) {
if (node.expression.kind === SyntaxKind.SuperKeyword) {
return createSuperAccessInAsyncMethod(
return createSuperElementAccessInAsyncMethod(
node.argumentExpression,
node
);
@@ -593,12 +640,12 @@ namespace ts {
|| kind === SyntaxKind.SetAccessor;
}
function createSuperAccessInAsyncMethod(argumentExpression: Expression, location: TextRange): LeftHandSideExpression {
function createSuperElementAccessInAsyncMethod(argumentExpression: Expression, location: TextRange): LeftHandSideExpression {
if (enclosingSuperContainerFlags & NodeCheckFlags.AsyncMethodWithSuperBinding) {
return setTextRange(
createPropertyAccess(
createCall(
createFileLevelUniqueName("_super"),
createFileLevelUniqueName("_superIndex"),
/*typeArguments*/ undefined,
[argumentExpression]
),
@@ -610,7 +657,7 @@ namespace ts {
else {
return setTextRange(
createCall(
createFileLevelUniqueName("_super"),
createFileLevelUniqueName("_superIndex"),
/*typeArguments*/ undefined,
[argumentExpression]
),
@@ -620,6 +667,89 @@ namespace ts {
}
}
/** Creates a variable named `_super` with accessor properties for the given property names. */
export function createSuperAccessVariableStatement(resolver: EmitResolver, node: FunctionLikeDeclaration, names: UnderscoreEscapedMap<true>) {
// Create a variable declaration with a getter/setter (if binding) definition for each name:
// const _super = Object.create(null, { x: { get: () => super.x, set: (v) => super.x = v }, ... });
const hasBinding = (resolver.getNodeCheckFlags(node) & NodeCheckFlags.AsyncMethodWithSuperBinding) !== 0;
const accessors: PropertyAssignment[] = [];
names.forEach((_, key) => {
const name = unescapeLeadingUnderscores(key);
const getterAndSetter: PropertyAssignment[] = [];
getterAndSetter.push(createPropertyAssignment(
"get",
createArrowFunction(
/* modifiers */ undefined,
/* typeParameters */ undefined,
/* parameters */ [],
/* type */ undefined,
/* equalsGreaterThanToken */ undefined,
createPropertyAccess(
createSuper(),
name
)
)
));
if (hasBinding) {
getterAndSetter.push(
createPropertyAssignment(
"set",
createArrowFunction(
/* modifiers */ undefined,
/* typeParameters */ undefined,
/* parameters */ [
createParameter(
/* decorators */ undefined,
/* modifiers */ undefined,
/* dotDotDotToken */ undefined,
"v",
/* questionToken */ undefined,
/* type */ undefined,
/* initializer */ undefined
)
],
/* type */ undefined,
/* equalsGreaterThanToken */ undefined,
createAssignment(
createPropertyAccess(
createSuper(),
name),
createIdentifier("v")
)
)
)
);
}
accessors.push(
createPropertyAssignment(
name,
createObjectLiteral(getterAndSetter),
)
);
});
return createVariableStatement(
/* modifiers */ undefined,
createVariableDeclarationList(
[
createVariableDeclaration(
createFileLevelUniqueName("_super"),
/* type */ undefined,
createCall(
createPropertyAccess(
createIdentifier("Object"),
"create"
),
/* typeArguments */ undefined,
[
createNull(),
createObjectLiteral(accessors, /* multiline */ true)
]
)
)
],
NodeFlags.Const));
}
const awaiterHelper: EmitHelper = {
name: "typescript:awaiter",
scoped: false,
@@ -667,14 +797,14 @@ namespace ts {
name: "typescript:async-super",
scoped: true,
text: helperString`
const ${"_super"} = name => super[name];`
const ${"_superIndex"} = name => super[name];`
};
export const advancedAsyncSuperHelper: EmitHelper = {
name: "typescript:advanced-async-super",
scoped: true,
text: helperString`
const ${"_super"} = (function (geti, seti) {
const ${"_superIndex"} = (function (geti, seti) {
const cache = Object.create(null);
return name => cache[name] || (cache[name] = { get value() { return geti(name); }, set value(v) { seti(name, v); } });
})(name => super[name], (name, value) => super[name] = value);`
+77 -33
View File
@@ -26,6 +26,13 @@ namespace ts {
let enclosingFunctionFlags: FunctionFlags;
let enclosingSuperContainerFlags: NodeCheckFlags = 0;
/** Keeps track of property names accessed on super (`super.x`) within async functions. */
let capturedSuperProperties: UnderscoreEscapedMap<true>;
/** Whether the async function contains an element access on super (`super[x]`). */
let hasSuperElementAccess: boolean;
/** A set of node IDs for generated super accessors. */
const substitutedSuperAccessors: boolean[] = [];
return chainBundle(transformSourceFile);
function transformSourceFile(node: SourceFile) {
@@ -57,7 +64,6 @@ namespace ts {
if ((node.transformFlags & TransformFlags.ContainsESNext) === 0) {
return node;
}
switch (node.kind) {
case SyntaxKind.AwaitExpression:
return visitAwaitExpression(node as AwaitExpression);
@@ -101,6 +107,16 @@ namespace ts {
return visitParenthesizedExpression(node as ParenthesizedExpression, noDestructuringValue);
case SyntaxKind.CatchClause:
return visitCatchClause(node as CatchClause);
case SyntaxKind.PropertyAccessExpression:
if (capturedSuperProperties && isPropertyAccessExpression(node) && node.expression.kind === SyntaxKind.SuperKeyword) {
capturedSuperProperties.set(node.name.escapedText, true);
}
return visitEachChild(node, visitor, context);
case SyntaxKind.ElementAccessExpression:
if (capturedSuperProperties && (<ElementAccessExpression>node).expression.kind === SyntaxKind.SuperKeyword) {
hasSuperElementAccess = true;
}
return visitEachChild(node, visitor, context);
default:
return visitEachChild(node, visitor, context);
}
@@ -210,7 +226,7 @@ namespace ts {
}
function visitObjectLiteralExpression(node: ObjectLiteralExpression): Expression {
if (node.transformFlags & TransformFlags.ContainsObjectSpread) {
if (node.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
// spread elements emit like so:
// non-spread elements are chunked together into object literals, and then all are passed to __assign:
// { a, ...o, b } => __assign({a}, o, {b});
@@ -250,7 +266,7 @@ namespace ts {
* @param node A BinaryExpression node.
*/
function visitBinaryExpression(node: BinaryExpression, noDestructuringValue: boolean): Expression {
if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.ContainsObjectRest) {
if (isDestructuringAssignment(node) && node.left.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
return flattenDestructuringAssignment(
node,
visitor,
@@ -276,7 +292,7 @@ namespace ts {
*/
function visitVariableDeclaration(node: VariableDeclaration): VisitResult<VariableDeclaration> {
// If we are here it is because the name contains a binding pattern with a rest somewhere in it.
if (isBindingPattern(node.name) && node.name.transformFlags & TransformFlags.ContainsObjectRest) {
if (isBindingPattern(node.name) && node.name.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
return flattenDestructuringBinding(
node,
visitor,
@@ -307,7 +323,7 @@ namespace ts {
* @param node A ForOfStatement.
*/
function visitForOfStatement(node: ForOfStatement, outermostLabeledStatement: LabeledStatement | undefined): VisitResult<Statement> {
if (node.initializer.transformFlags & TransformFlags.ContainsObjectRest) {
if (node.initializer.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
node = transformForOfStatementWithObjectRest(node);
}
if (node.awaitModifier) {
@@ -499,7 +515,7 @@ namespace ts {
}
function visitParameter(node: ParameterDeclaration): ParameterDeclaration {
if (node.transformFlags & TransformFlags.ContainsObjectRest) {
if (node.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
// Binding patterns are converted into a generated name and are
// evaluated inside the function body.
return updateParameter(
@@ -655,41 +671,57 @@ namespace ts {
const statementOffset = addPrologue(statements, node.body!.statements, /*ensureUseStrict*/ false, visitor);
appendObjectRestAssignmentsIfNeeded(statements, node);
statements.push(
createReturn(
createAsyncGeneratorHelper(
context,
createFunctionExpression(
/*modifiers*/ undefined,
createToken(SyntaxKind.AsteriskToken),
node.name && getGeneratedNameForNode(node.name),
/*typeParameters*/ undefined,
/*parameters*/ [],
/*type*/ undefined,
updateBlock(
node.body!,
visitLexicalEnvironment(node.body!.statements, visitor, context, statementOffset)
)
const savedCapturedSuperProperties = capturedSuperProperties;
const savedHasSuperElementAccess = hasSuperElementAccess;
capturedSuperProperties = createUnderscoreEscapedMap<true>();
hasSuperElementAccess = false;
const returnStatement = createReturn(
createAsyncGeneratorHelper(
context,
createFunctionExpression(
/*modifiers*/ undefined,
createToken(SyntaxKind.AsteriskToken),
node.name && getGeneratedNameForNode(node.name),
/*typeParameters*/ undefined,
/*parameters*/ [],
/*type*/ undefined,
updateBlock(
node.body!,
visitLexicalEnvironment(node.body!.statements, visitor, context, statementOffset)
)
)
)
);
// Minor optimization, emit `_super` helper to capture `super` access in an arrow.
// This step isn't needed if we eventually transform this to ES5.
const emitSuperHelpers = languageVersion >= ScriptTarget.ES2015 && resolver.getNodeCheckFlags(node) & (NodeCheckFlags.AsyncMethodWithSuperBinding | NodeCheckFlags.AsyncMethodWithSuper);
if (emitSuperHelpers) {
enableSubstitutionForAsyncMethodsWithSuper();
const variableStatement = createSuperAccessVariableStatement(resolver, node, capturedSuperProperties);
substitutedSuperAccessors[getNodeId(variableStatement)] = true;
addStatementsAfterPrologue(statements, [variableStatement]);
}
statements.push(returnStatement);
addStatementsAfterPrologue(statements, endLexicalEnvironment());
const block = updateBlock(node.body!, statements);
// Minor optimization, emit `_super` helper to capture `super` access in an arrow.
// This step isn't needed if we eventually transform this to ES5.
if (languageVersion >= ScriptTarget.ES2015) {
if (emitSuperHelpers && hasSuperElementAccess) {
if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.AsyncMethodWithSuperBinding) {
enableSubstitutionForAsyncMethodsWithSuper();
addEmitHelper(block, advancedAsyncSuperHelper);
}
else if (resolver.getNodeCheckFlags(node) & NodeCheckFlags.AsyncMethodWithSuper) {
enableSubstitutionForAsyncMethodsWithSuper();
addEmitHelper(block, asyncSuperHelper);
}
}
capturedSuperProperties = savedCapturedSuperProperties;
hasSuperElementAccess = savedHasSuperElementAccess;
return block;
}
@@ -716,7 +748,7 @@ namespace ts {
function appendObjectRestAssignmentsIfNeeded(statements: Statement[] | undefined, node: FunctionLikeDeclaration): Statement[] | undefined {
for (const parameter of node.parameters) {
if (parameter.transformFlags & TransformFlags.ContainsObjectRest) {
if (parameter.transformFlags & TransformFlags.ContainsObjectRestOrSpread) {
const temp = getGeneratedNameForNode(parameter);
const declarations = flattenDestructuringBinding(
parameter,
@@ -758,6 +790,8 @@ namespace ts {
context.enableEmitNotification(SyntaxKind.GetAccessor);
context.enableEmitNotification(SyntaxKind.SetAccessor);
context.enableEmitNotification(SyntaxKind.Constructor);
// We need to be notified when entering the generated accessor arrow functions.
context.enableEmitNotification(SyntaxKind.VariableStatement);
}
}
@@ -781,6 +815,14 @@ namespace ts {
return;
}
}
// Disable substitution in the generated super accessor itself.
else if (enabledSubstitutions && substitutedSuperAccessors[getNodeId(node)]) {
const savedEnclosingSuperContainerFlags = enclosingSuperContainerFlags;
enclosingSuperContainerFlags = 0 as NodeCheckFlags;
previousOnEmitNode(hint, node, emitCallback);
enclosingSuperContainerFlags = savedEnclosingSuperContainerFlags;
return;
}
previousOnEmitNode(hint, node, emitCallback);
}
@@ -813,8 +855,10 @@ namespace ts {
function substitutePropertyAccessExpression(node: PropertyAccessExpression) {
if (node.expression.kind === SyntaxKind.SuperKeyword) {
return createSuperAccessInAsyncMethod(
createLiteral(idText(node.name)),
return setTextRange(
createPropertyAccess(
createFileLevelUniqueName("_super"),
node.name),
node
);
}
@@ -823,7 +867,7 @@ namespace ts {
function substituteElementAccessExpression(node: ElementAccessExpression) {
if (node.expression.kind === SyntaxKind.SuperKeyword) {
return createSuperAccessInAsyncMethod(
return createSuperElementAccessInAsyncMethod(
node.argumentExpression,
node
);
@@ -858,12 +902,12 @@ namespace ts {
|| kind === SyntaxKind.SetAccessor;
}
function createSuperAccessInAsyncMethod(argumentExpression: Expression, location: TextRange): LeftHandSideExpression {
function createSuperElementAccessInAsyncMethod(argumentExpression: Expression, location: TextRange): LeftHandSideExpression {
if (enclosingSuperContainerFlags & NodeCheckFlags.AsyncMethodWithSuperBinding) {
return setTextRange(
createPropertyAccess(
createCall(
createIdentifier("_super"),
createIdentifier("_superIndex"),
/*typeArguments*/ undefined,
[argumentExpression]
),
@@ -875,7 +919,7 @@ namespace ts {
else {
return setTextRange(
createCall(
createIdentifier("_super"),
createIdentifier("_superIndex"),
/*typeArguments*/ undefined,
[argumentExpression]
),
+4 -2
View File
@@ -973,9 +973,11 @@ namespace ts {
// Check if we have property assignment inside class declaration.
// If there is a property assignment, we need to emit constructor whether users define it or not
// If there is no property assignment, we can omit constructor if users do not define it
const hasInstancePropertyWithInitializer = forEach(node.members, isInstanceInitializedProperty);
const hasParameterPropertyAssignments = node.transformFlags & TransformFlags.ContainsParameterPropertyAssignments;
const constructor = getFirstConstructorWithBody(node);
const hasInstancePropertyWithInitializer = forEach(node.members, isInstanceInitializedProperty);
const hasParameterPropertyAssignments = constructor &&
constructor.transformFlags & TransformFlags.ContainsTypeScriptClassSyntax &&
forEach(constructor.parameters, isParameterWithPropertyAssignment);
// If the class does not contain nodes that require a synthesized constructor,
// accept the current constructor if it exists.
+481 -451
View File
File diff suppressed because it is too large Load Diff
+3 -1
View File
@@ -9,6 +9,7 @@
"files": [
"core.ts",
"performance.ts",
"semver.ts",
"types.ts",
"sys.ts",
@@ -51,6 +52,7 @@
"resolutionCache.ts",
"moduleSpecifiers.ts",
"watch.ts",
"tsbuild.ts"
"tsbuild.ts",
"inspectValue.ts",
]
}
+177 -69
View File
@@ -24,7 +24,84 @@ namespace ts {
| SyntaxKind.DotToken
| SyntaxKind.Identifier
| SyntaxKind.NoSubstitutionTemplateLiteral
| SyntaxKind.Unknown;
| SyntaxKind.Unknown
| KeywordSyntaxKind;
export type KeywordSyntaxKind =
| SyntaxKind.AbstractKeyword
| SyntaxKind.AnyKeyword
| SyntaxKind.AsKeyword
| SyntaxKind.BooleanKeyword
| SyntaxKind.BreakKeyword
| SyntaxKind.CaseKeyword
| SyntaxKind.CatchKeyword
| SyntaxKind.ClassKeyword
| SyntaxKind.ContinueKeyword
| SyntaxKind.ConstKeyword
| SyntaxKind.ConstructorKeyword
| SyntaxKind.DebuggerKeyword
| SyntaxKind.DeclareKeyword
| SyntaxKind.DefaultKeyword
| SyntaxKind.DeleteKeyword
| SyntaxKind.DoKeyword
| SyntaxKind.ElseKeyword
| SyntaxKind.EnumKeyword
| SyntaxKind.ExportKeyword
| SyntaxKind.ExtendsKeyword
| SyntaxKind.FalseKeyword
| SyntaxKind.FinallyKeyword
| SyntaxKind.ForKeyword
| SyntaxKind.FromKeyword
| SyntaxKind.FunctionKeyword
| SyntaxKind.GetKeyword
| SyntaxKind.IfKeyword
| SyntaxKind.ImplementsKeyword
| SyntaxKind.ImportKeyword
| SyntaxKind.InKeyword
| SyntaxKind.InferKeyword
| SyntaxKind.InstanceOfKeyword
| SyntaxKind.InterfaceKeyword
| SyntaxKind.IsKeyword
| SyntaxKind.KeyOfKeyword
| SyntaxKind.LetKeyword
| SyntaxKind.ModuleKeyword
| SyntaxKind.NamespaceKeyword
| SyntaxKind.NeverKeyword
| SyntaxKind.NewKeyword
| SyntaxKind.NullKeyword
| SyntaxKind.NumberKeyword
| SyntaxKind.ObjectKeyword
| SyntaxKind.PackageKeyword
| SyntaxKind.PrivateKeyword
| SyntaxKind.ProtectedKeyword
| SyntaxKind.PublicKeyword
| SyntaxKind.ReadonlyKeyword
| SyntaxKind.RequireKeyword
| SyntaxKind.GlobalKeyword
| SyntaxKind.ReturnKeyword
| SyntaxKind.SetKeyword
| SyntaxKind.StaticKeyword
| SyntaxKind.StringKeyword
| SyntaxKind.SuperKeyword
| SyntaxKind.SwitchKeyword
| SyntaxKind.SymbolKeyword
| SyntaxKind.ThisKeyword
| SyntaxKind.ThrowKeyword
| SyntaxKind.TrueKeyword
| SyntaxKind.TryKeyword
| SyntaxKind.TypeKeyword
| SyntaxKind.TypeOfKeyword
| SyntaxKind.UndefinedKeyword
| SyntaxKind.UniqueKeyword
| SyntaxKind.UnknownKeyword
| SyntaxKind.VarKeyword
| SyntaxKind.VoidKeyword
| SyntaxKind.WhileKeyword
| SyntaxKind.WithKeyword
| SyntaxKind.YieldKeyword
| SyntaxKind.AsyncKeyword
| SyntaxKind.AwaitKeyword
| SyntaxKind.OfKeyword;
export type JsxTokenSyntaxKind =
| SyntaxKind.LessThanSlashToken
@@ -1708,7 +1785,7 @@ namespace ts {
export interface ExpressionWithTypeArguments extends NodeWithTypeArguments {
kind: SyntaxKind.ExpressionWithTypeArguments;
parent: HeritageClause;
parent: HeritageClause | JSDocAugmentsTag;
expression: LeftHandSideExpression;
}
@@ -2551,7 +2628,18 @@ namespace ts {
fileName: string;
/* @internal */ path: Path;
text: string;
/** Resolved path can be different from path property,
* when file is included through project reference is mapped to its output instead of source
* in that case resolvedPath = path to output file
* path = input file's path
*/
/* @internal */ resolvedPath: Path;
/** Original file name that can be different from fileName,
* when file is included through project reference is mapped to its output instead of source
* in that case originalFileName = name of input file
* fileName = output file's name
*/
/* @internal */ originalFileName: string;
/**
* If two source files are for the same version of the same package, one will redirect to the other.
@@ -2593,6 +2681,8 @@ namespace ts {
/* @internal */ externalModuleIndicator?: Node;
// The first node that causes this file to be a CommonJS module
/* @internal */ commonJsModuleIndicator?: Node;
// JS identifier-declarations that are intended to merge with globals
/* @internal */ jsGlobalAugmentations?: SymbolTable;
/* @internal */ identifiers: Map<string>; // Map from a string to an interned string
/* @internal */ nodeCount: number;
@@ -2815,7 +2905,9 @@ namespace ts {
/* @internal */ getResolvedModuleWithFailedLookupLocationsFromCache(moduleName: string, containingFile: string): ResolvedModuleWithFailedLookupLocations | undefined;
getProjectReferences(): (ResolvedProjectReference | undefined)[] | undefined;
getProjectReferences(): ReadonlyArray<ProjectReference> | undefined;
getResolvedProjectReferences(): (ResolvedProjectReference | undefined)[] | undefined;
/*@internal*/ getProjectReferenceRedirect(fileName: string): string | undefined;
}
/* @internal */
@@ -2893,7 +2985,7 @@ namespace ts {
}
/* @internal */
export interface TypeCheckerHost {
export interface TypeCheckerHost extends ModuleSpecifierResolutionHost {
getCompilerOptions(): CompilerOptions;
getSourceFiles(): ReadonlyArray<SourceFile>;
@@ -3011,8 +3103,6 @@ namespace ts {
getExportsOfModule(moduleSymbol: Symbol): Symbol[];
/** Unlike `getExportsOfModule`, this includes properties of an `export =` value. */
/* @internal */ getExportsAndPropertiesOfModule(moduleSymbol: Symbol): Symbol[];
getAllAttributesTypeFromJsxOpeningLikeElement(elementNode: JsxOpeningLikeElement): Type | undefined;
getJsxIntrinsicTagNamesAt(location: Node): Symbol[];
isOptionalParameter(node: ParameterDeclaration): boolean;
getAmbientModules(): Symbol[];
@@ -3034,8 +3124,8 @@ namespace ts {
/* @internal */ getStringType(): Type;
/* @internal */ getNumberType(): Type;
/* @internal */ getBooleanType(): Type;
/* @internal */ getFalseType(): Type;
/* @internal */ getTrueType(): Type;
/* @internal */ getFalseType(fresh?: boolean): Type;
/* @internal */ getTrueType(fresh?: boolean): Type;
/* @internal */ getVoidType(): Type;
/* @internal */ getUndefinedType(): Type;
/* @internal */ getNullType(): Type;
@@ -3079,7 +3169,7 @@ namespace ts {
* True if `contextualType` should not be considered for completions because
* e.g. it specifies `kind: "a"` and obj has `kind: "b"`.
*/
/* @internal */ isTypeInvalidDueToUnionDiscriminant(contextualType: Type, obj: ObjectLiteralExpression): boolean;
/* @internal */ isTypeInvalidDueToUnionDiscriminant(contextualType: Type, obj: ObjectLiteralExpression | JsxAttributes): boolean;
/**
* For a union, will include a property if it's defined in *any* of the member types.
* So for `{ a } | { b }`, this will include both `a` and `b`.
@@ -3168,6 +3258,8 @@ namespace ts {
InTypeAlias = 1 << 23, // Writing type in type alias declaration
InInitialEntityName = 1 << 24, // Set when writing the LHS of an entity name or entity name expression
InReverseMappedType = 1 << 25,
/* @internal */ DoNotIncludeSymbolChain = 1 << 26, // Skip looking up and printing an accessible symbol chain
}
// Ensure the shared flags between this and `NodeBuilderFlags` stay in alignment
@@ -3230,6 +3322,9 @@ namespace ts {
// Prefer aliases which are not directly visible
UseAliasDefinedOutsideCurrentScope = 0x00000008,
// Skip building an accessible symbol chain
/* @internal */ DoNotIncludeSymbolChain = 0x00000010,
}
/* @internal */
@@ -3383,7 +3478,7 @@ namespace ts {
isImplementationOfOverload(node: FunctionLike): boolean | undefined;
isRequiredInitializedParameter(node: ParameterDeclaration): boolean;
isOptionalUninitializedParameterProperty(node: ParameterDeclaration): boolean;
isJSContainerFunctionDeclaration(node: FunctionDeclaration): boolean;
isExpandoFunctionDeclaration(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;
@@ -3405,6 +3500,7 @@ namespace ts {
getJsxFactoryEntity(location?: Node): EntityName | undefined;
getAllAccessorDeclarations(declaration: AccessorDeclaration): AllAccessorDeclarations;
getSymbolOfExternalModuleSpecifier(node: StringLiteralLike): Symbol | undefined;
isBindingCapturedByNode(node: Node, decl: VariableDeclaration | BindingElement): boolean;
}
export const enum SymbolFlags {
@@ -3435,7 +3531,7 @@ namespace ts {
ExportStar = 1 << 23, // Export * declaration
Optional = 1 << 24, // Optional property
Transient = 1 << 25, // Transient symbol (created during type check)
JSContainer = 1 << 26, // Contains Javascript special declarations
Assignment = 1 << 26, // Assignment treated as declaration (eg `this.prop = 1`)
ModuleExports = 1 << 27, // Symbol for CommonJS `module` of `module.exports`
/* @internal */
@@ -3444,8 +3540,8 @@ namespace ts {
Enum = RegularEnum | ConstEnum,
Variable = FunctionScopedVariable | BlockScopedVariable,
Value = Variable | Property | EnumMember | ObjectLiteral | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor | JSContainer,
Type = Class | Interface | Enum | EnumMember | TypeLiteral | TypeParameter | TypeAlias | JSContainer,
Value = Variable | Property | EnumMember | ObjectLiteral | Function | Class | Enum | ValueModule | Method | GetAccessor | SetAccessor | Assignment,
Type = Class | Interface | Enum | EnumMember | TypeLiteral | TypeParameter | TypeAlias | Assignment,
Namespace = ValueModule | NamespaceModule | Enum,
Module = ValueModule | NamespaceModule,
Accessor = GetAccessor | SetAccessor,
@@ -3466,7 +3562,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 | JSContainer),
ValueModuleExcludes = Value & ~(Function | Class | RegularEnum | ValueModule | Assignment),
NamespaceModuleExcludes = 0,
MethodExcludes = Value & ~Method,
GetAccessorExcludes = Value & ~SetAccessor,
@@ -3520,6 +3616,7 @@ namespace ts {
type?: Type; // Type of value symbol
uniqueESSymbolType?: Type; // UniqueESSymbol type for a symbol
declaredType?: Type; // Type of class, interface, enum, type alias, or type parameter
resolvedJSDocType?: Type; // Resolved type of a JSDoc type reference
typeParameters?: TypeParameter[]; // Type parameters of type alias (undefined if non-generic)
outerTypeParameters?: TypeParameter[]; // Outer type parameters of anonymous object type
inferredClassType?: Type; // Type of an inferred ES5 class
@@ -3653,22 +3750,23 @@ namespace ts {
EnumValuesComputed = 0x00004000, // Values for enum members have been computed, and any errors have been reported for them.
LexicalModuleMergesWithClass = 0x00008000, // Instantiated lexical module declaration is merged with a previous class declaration.
LoopWithCapturedBlockScopedBinding = 0x00010000, // Loop that contains block scoped variable captured in closure
CapturedBlockScopedBinding = 0x00020000, // Block-scoped binding that is captured in some function
BlockScopedBindingInLoop = 0x00040000, // Block-scoped binding with declaration nested inside iteration statement
ClassWithBodyScopedClassBinding = 0x00080000, // Decorated class that contains a binding to itself inside of the class body.
BodyScopedClassBinding = 0x00100000, // Binding to a decorated class inside of the class's body.
NeedsLoopOutParameter = 0x00200000, // Block scoped binding whose value should be explicitly copied outside of the converted loop
AssignmentsMarked = 0x00400000, // Parameter assignments have been marked
ClassWithConstructorReference = 0x00800000, // Class that contains a binding to its constructor inside of the class body.
ConstructorReferenceInClass = 0x01000000, // Binding to a class constructor inside of the class's body.
ContainsCapturedBlockScopeBinding = 0x00020000, // Part of a loop that contains block scoped variable captured in closure
CapturedBlockScopedBinding = 0x00040000, // Block-scoped binding that is captured in some function
BlockScopedBindingInLoop = 0x00080000, // Block-scoped binding with declaration nested inside iteration statement
ClassWithBodyScopedClassBinding = 0x00100000, // Decorated class that contains a binding to itself inside of the class body.
BodyScopedClassBinding = 0x00200000, // Binding to a decorated class inside of the class's body.
NeedsLoopOutParameter = 0x00400000, // Block scoped binding whose value should be explicitly copied outside of the converted loop
AssignmentsMarked = 0x00800000, // Parameter assignments have been marked
ClassWithConstructorReference = 0x01000000, // Class that contains a binding to its constructor inside of the class body.
ConstructorReferenceInClass = 0x02000000, // Binding to a class constructor inside of the class's body.
}
/* @internal */
export interface NodeLinks {
flags: NodeCheckFlags; // Set of flags specific to Node
resolvedType?: Type; // Cached type of type node
resolvedEnumType?: Type; // Cached constraint type from enum jsdoc tag
resolvedSignature?: Signature; // Cached signature of signature node or call expression
resolvedSignatures?: Map<Signature[]>; // Cached signatures of jsx node
resolvedSymbol?: Symbol; // Cached name resolution result
resolvedIndexInfo?: IndexInfo; // Cached indexing info resolution result
maybeTypePredicate?: boolean; // Cached check whether call expression might reference a type predicate
@@ -3684,6 +3782,8 @@ namespace ts {
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
deferredNodes?: Map<Node>; // Set of nodes whose checking has been deferred
capturedBlockScopeBindings?: Symbol[]; // Block-scoped bindings captured beneath this part of an IterationStatement
}
export const enum TypeFlags {
@@ -3731,7 +3831,7 @@ namespace ts {
Unit = Literal | UniqueESSymbol | Nullable,
StringOrNumberLiteral = StringLiteral | NumberLiteral,
/* @internal */
StringOrNumberLiteralOrUnique = StringOrNumberLiteral | UniqueESSymbol,
StringOrNumberLiteralOrUnique = StringLiteral | NumberLiteral | UniqueESSymbol,
/* @internal */
DefinitelyFalsy = StringLiteral | NumberLiteral | BooleanLiteral | Void | Undefined | Null,
PossiblyFalsy = DefinitelyFalsy | String | Number | Boolean,
@@ -3802,6 +3902,15 @@ namespace ts {
intrinsicName: string; // Name of intrinsic type
}
/* @internal */
export interface FreshableIntrinsicType extends IntrinsicType {
freshType: IntrinsicType; // Fresh version of type
regularType: IntrinsicType; // Regular version of type
}
/* @internal */
export type FreshableType = LiteralType | FreshableIntrinsicType;
// String literal types (TypeFlags.StringLiteral)
// Numeric literal types (TypeFlags.NumberLiteral)
export interface LiteralType extends Type {
@@ -3962,6 +4071,7 @@ namespace ts {
templateType?: Type;
modifiersType?: Type;
resolvedApparentType?: Type;
instantiating?: boolean;
}
export interface EvolvingArrayType extends ObjectType {
@@ -4219,7 +4329,7 @@ namespace ts {
}
/* @internal */
export const enum SpecialPropertyAssignmentKind {
export const enum AssignmentDeclarationKind {
None,
/// exports.name = expr
ExportsProperty,
@@ -4402,6 +4512,7 @@ namespace ts {
sourceRoot?: string;
strict?: boolean;
strictFunctionTypes?: boolean; // Always combine with strict property
strictBindCallApply?: boolean; // Always combine with strict property
strictNullChecks?: boolean; // Always combine with strict property
strictPropertyInitialization?: boolean; // Always combine with strict property
stripInternal?: boolean;
@@ -4516,7 +4627,6 @@ namespace ts {
/* @internal */
export interface ConfigFileSpecs {
filesSpecs: ReadonlyArray<string> | undefined;
referencesSpecs: ReadonlyArray<ProjectReference> | undefined;
/**
* Present to report errors (user specified specs), validatedIncludeSpecs are used for file name matching
*/
@@ -4532,7 +4642,6 @@ namespace ts {
export interface ExpandResult {
fileNames: string[];
projectReferences: ReadonlyArray<ProjectReference> | undefined;
wildcardDirectories: MapLike<WatchDirectoryFlags>;
/* @internal */ spec: ConfigFileSpecs;
}
@@ -4559,6 +4668,9 @@ namespace ts {
showInSimplifiedHelpView?: boolean;
category?: DiagnosticMessage;
strictFlag?: true; // true if the option is one of the flag under strict
affectsSourceFile?: true; // true if we should recreate SourceFiles after this option changes
affectsModuleResolution?: true; // currently same effect as `affectsSourceFile`
affectsBindDiagnostics?: true; // true if this affects binding (currently same effect as `affectsSourceFile`)
affectsSemanticDiagnostics?: true; // true if option affects semantic diagnostics
}
@@ -4878,25 +4990,21 @@ namespace ts {
// Markers
// - Flags used to indicate that a subtree contains a specific transformation.
ContainsDecorators = 1 << 12,
ContainsPropertyInitializer = 1 << 13,
ContainsLexicalThis = 1 << 14,
ContainsCapturedLexicalThis = 1 << 15,
ContainsLexicalThisInComputedPropertyName = 1 << 16,
ContainsDefaultValueAssignments = 1 << 17,
ContainsParameterPropertyAssignments = 1 << 18,
ContainsSpread = 1 << 19,
ContainsObjectSpread = 1 << 20,
ContainsRest = ContainsSpread,
ContainsObjectRest = ContainsObjectSpread,
ContainsComputedPropertyName = 1 << 21,
ContainsBlockScopedBinding = 1 << 22,
ContainsBindingPattern = 1 << 23,
ContainsYield = 1 << 24,
ContainsHoistedDeclarationOrCompletion = 1 << 25,
ContainsDynamicImport = 1 << 26,
Super = 1 << 27,
ContainsSuper = 1 << 28,
ContainsTypeScriptClassSyntax = 1 << 12, // Decorators, Property Initializers, Parameter Property Initializers
ContainsLexicalThis = 1 << 13,
ContainsCapturedLexicalThis = 1 << 14,
ContainsLexicalThisInComputedPropertyName = 1 << 15,
ContainsDefaultValueAssignments = 1 << 16,
ContainsRestOrSpread = 1 << 17,
ContainsObjectRestOrSpread = 1 << 18,
ContainsComputedPropertyName = 1 << 19,
ContainsBlockScopedBinding = 1 << 20,
ContainsBindingPattern = 1 << 21,
ContainsYield = 1 << 22,
ContainsHoistedDeclarationOrCompletion = 1 << 23,
ContainsDynamicImport = 1 << 24,
Super = 1 << 25,
ContainsSuper = 1 << 26,
// Please leave this as 1 << 29.
// It is the maximum bit we can set before we outgrow the size of a v8 small integer (SMI) on an x86 system.
@@ -4920,23 +5028,22 @@ namespace ts {
OuterExpressionExcludes = TypeScript | ES2015 | DestructuringAssignment | Generator | HasComputedFlags,
PropertyAccessExcludes = OuterExpressionExcludes | Super,
NodeExcludes = PropertyAccessExcludes | ContainsSuper,
ArrowFunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRest,
FunctionExcludes = NodeExcludes | ContainsDecorators | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsParameterPropertyAssignments | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRest,
ConstructorExcludes = NodeExcludes | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRest,
MethodOrAccessorExcludes = NodeExcludes | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRest,
ClassExcludes = NodeExcludes | ContainsDecorators | ContainsPropertyInitializer | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsComputedPropertyName | ContainsParameterPropertyAssignments | ContainsLexicalThisInComputedPropertyName,
ModuleExcludes = NodeExcludes | ContainsDecorators | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsHoistedDeclarationOrCompletion,
ArrowFunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread,
FunctionExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsDefaultValueAssignments | ContainsCapturedLexicalThis | ContainsLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread,
ConstructorExcludes = NodeExcludes | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread,
MethodOrAccessorExcludes = NodeExcludes | ContainsDefaultValueAssignments | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsYield | ContainsHoistedDeclarationOrCompletion | ContainsBindingPattern | ContainsObjectRestOrSpread,
ClassExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsComputedPropertyName | ContainsLexicalThisInComputedPropertyName,
ModuleExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsLexicalThis | ContainsCapturedLexicalThis | ContainsBlockScopedBinding | ContainsHoistedDeclarationOrCompletion,
TypeExcludes = ~ContainsTypeScript,
ObjectLiteralExcludes = NodeExcludes | ContainsDecorators | ContainsComputedPropertyName | ContainsLexicalThisInComputedPropertyName | ContainsObjectSpread,
ArrayLiteralOrCallOrNewExcludes = NodeExcludes | ContainsSpread,
VariableDeclarationListExcludes = NodeExcludes | ContainsBindingPattern | ContainsObjectRest,
ObjectLiteralExcludes = NodeExcludes | ContainsTypeScriptClassSyntax | ContainsComputedPropertyName | ContainsLexicalThisInComputedPropertyName | ContainsObjectRestOrSpread,
ArrayLiteralOrCallOrNewExcludes = NodeExcludes | ContainsRestOrSpread,
VariableDeclarationListExcludes = NodeExcludes | ContainsBindingPattern | ContainsObjectRestOrSpread,
ParameterExcludes = NodeExcludes,
CatchClauseExcludes = NodeExcludes | ContainsObjectRest,
BindingPatternExcludes = NodeExcludes | ContainsRest,
CatchClauseExcludes = NodeExcludes | ContainsObjectRestOrSpread,
BindingPatternExcludes = NodeExcludes | ContainsRestOrSpread,
// Masks
// - Additional bitmasks
TypeScriptClassSyntaxMask = ContainsParameterPropertyAssignments | ContainsPropertyInitializer | ContainsDecorators,
ES2015FunctionSyntaxMask = ContainsCapturedLexicalThis | ContainsDefaultValueAssignments,
}
@@ -4954,7 +5061,7 @@ namespace ts {
/* @internal */
export interface EmitNode {
annotatedNodes?: Node[]; // Tracks Parse-tree nodes with EmitNodes for eventual cleanup.
flags: EmitFlags; // Flags that customize emit
flags: EmitFlags; // Flags that customize emit
leadingComments?: SynthesizedComment[]; // Synthesized leading comments
trailingComments?: SynthesizedComment[]; // Synthesized trailing comments
commentRange?: TextRange; // The text range to use when emitting leading or trailing comments
@@ -5314,6 +5421,7 @@ namespace ts {
/*@internal*/ inlineSourceMap?: boolean;
/*@internal*/ extendedDiagnostics?: boolean;
/*@internal*/ onlyPrintJsDocStyle?: boolean;
/*@internal*/ neverAsciiEscape?: boolean;
}
/* @internal */
@@ -5351,7 +5459,7 @@ namespace ts {
reportInaccessibleThisError?(): void;
reportPrivateInBaseOfClassExpression?(propertyName: string): void;
reportInaccessibleUniqueSymbolError?(): void;
moduleResolverHost?: EmitHost;
moduleResolverHost?: ModuleSpecifierResolutionHost & { getSourceFiles(): ReadonlyArray<SourceFile>, getCommonSourceDirectory(): string };
trackReferencedAmbientModule?(decl: ModuleDeclaration, symbol: Symbol): void;
trackExternalModuleSymbolOfImportTypeNode?(symbol: Symbol): void;
}
@@ -5585,15 +5693,15 @@ namespace ts {
type ConcretePragmaSpecs = typeof commentPragmas;
/* @internal */
export type PragmaPsuedoMap = {[K in keyof ConcretePragmaSpecs]?: {arguments: PragmaArgumentType<ConcretePragmaSpecs[K]>, range: CommentRange}};
export type PragmaPseudoMap = {[K in keyof ConcretePragmaSpecs]?: {arguments: PragmaArgumentType<ConcretePragmaSpecs[K]>, range: CommentRange}};
/* @internal */
export type PragmaPsuedoMapEntry = {[K in keyof PragmaPsuedoMap]: {name: K, args: PragmaPsuedoMap[K]}}[keyof PragmaPsuedoMap];
export type PragmaPseudoMapEntry = {[K in keyof PragmaPseudoMap]: {name: K, args: PragmaPseudoMap[K]}}[keyof PragmaPseudoMap];
/* @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;
export interface ReadonlyPragmaMap extends ReadonlyMap<PragmaPseudoMap[keyof PragmaPseudoMap] | PragmaPseudoMap[keyof PragmaPseudoMap][]> {
get<TKey extends keyof PragmaPseudoMap>(key: TKey): PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][];
forEach(action: <TKey extends keyof PragmaPseudoMap>(value: PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][], key: TKey) => void): void;
}
/**
@@ -5602,10 +5710,10 @@ namespace ts {
* in multiple places
*/
/* @internal */
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 PragmaMap extends Map<PragmaPseudoMap[keyof PragmaPseudoMap] | PragmaPseudoMap[keyof PragmaPseudoMap][]>, ReadonlyPragmaMap {
set<TKey extends keyof PragmaPseudoMap>(key: TKey, value: PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][]): this;
get<TKey extends keyof PragmaPseudoMap>(key: TKey): PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][];
forEach(action: <TKey extends keyof PragmaPseudoMap>(value: PragmaPseudoMap[TKey] | PragmaPseudoMap[TKey][], key: TKey) => void): void;
}
export interface UserPreferences {
+172 -125
View File
@@ -14,7 +14,6 @@ namespace ts {
/* @internal */
namespace ts {
export const emptyArray: never[] = [] as never[];
export const resolvingEmptyArray: never[] = [] as never[];
export const emptyMap = createMap<never>() as ReadonlyMap<never> & ReadonlyPragmaMap;
export const emptyUnderscoreEscapedMap: ReadonlyUnderscoreEscapedMap<never> = emptyMap as ReadonlyUnderscoreEscapedMap<never>;
@@ -102,22 +101,8 @@ namespace ts {
}
export function changesAffectModuleResolution(oldOptions: CompilerOptions, newOptions: CompilerOptions): boolean {
return !oldOptions ||
(oldOptions.module !== newOptions.module) ||
(oldOptions.moduleResolution !== newOptions.moduleResolution) ||
(oldOptions.noResolve !== newOptions.noResolve) ||
(oldOptions.target !== newOptions.target) ||
(oldOptions.noLib !== newOptions.noLib) ||
(oldOptions.jsx !== newOptions.jsx) ||
(oldOptions.allowJs !== newOptions.allowJs) ||
(oldOptions.rootDir !== newOptions.rootDir) ||
(oldOptions.configFilePath !== newOptions.configFilePath) ||
(oldOptions.baseUrl !== newOptions.baseUrl) ||
(oldOptions.maxNodeModuleJsDepth !== newOptions.maxNodeModuleJsDepth) ||
!arrayIsEqualTo(oldOptions.lib, newOptions.lib) ||
!arrayIsEqualTo(oldOptions.typeRoots, newOptions.typeRoots) ||
!arrayIsEqualTo(oldOptions.rootDirs, newOptions.rootDirs) ||
!equalOwnProperties(oldOptions.paths, newOptions.paths);
return oldOptions.configFilePath !== newOptions.configFilePath || moduleResolutionOptionDeclarations.some(o =>
!isJsonEqual(getCompilerOptionValue(oldOptions, o), getCompilerOptionValue(newOptions, o)));
}
/**
@@ -250,6 +235,12 @@ namespace ts {
sourceFile.resolvedTypeReferenceDirectiveNames.set(typeReferenceDirectiveName, resolvedTypeReferenceDirective);
}
export function projectReferenceIsEqualTo(oldRef: ProjectReference, newRef: ProjectReference) {
return oldRef.path === newRef.path &&
!oldRef.prepend === !newRef.prepend &&
!oldRef.circular === !newRef.circular;
}
export function moduleResolutionIsEqualTo(oldResolution: ResolvedModuleFull, newResolution: ResolvedModuleFull): boolean {
return oldResolution.isExternalLibraryImport === newResolution.isExternalLibraryImport &&
oldResolution.extension === newResolution.extension &&
@@ -533,14 +524,14 @@ namespace ts {
return emitNode && emitNode.flags || 0;
}
export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile) {
export function getLiteralText(node: LiteralLikeNode, sourceFile: SourceFile, neverAsciiEscape: boolean | undefined) {
// If we don't need to downlevel and we can reach the original source text using
// the node's parent reference, then simply get the text as it was originally written.
if (!nodeIsSynthesized(node) && node.parent && !(isNumericLiteral(node) && node.numericLiteralFlags & TokenFlags.ContainsSeparator)) {
return getSourceTextOfNodeFromSourceFile(sourceFile, node);
}
const escapeText = getEmitFlags(node) & EmitFlags.NoAsciiEscaping ? escapeString : escapeNonAsciiString;
const escapeText = neverAsciiEscape || (getEmitFlags(node) & EmitFlags.NoAsciiEscaping) ? escapeString : escapeNonAsciiString;
// If we can't reach the original source text, use the canonical form if it's a number,
// or a (possibly escaped) quoted form of the original text if it's string-like.
@@ -987,6 +978,7 @@ namespace ts {
case SyntaxKind.StringKeyword:
case SyntaxKind.BooleanKeyword:
case SyntaxKind.SymbolKeyword:
case SyntaxKind.ObjectKeyword:
case SyntaxKind.UndefinedKeyword:
case SyntaxKind.NeverKeyword:
return true;
@@ -1679,15 +1671,15 @@ namespace ts {
return node.kind === SyntaxKind.ImportEqualsDeclaration && (<ImportEqualsDeclaration>node).moduleReference.kind !== SyntaxKind.ExternalModuleReference;
}
export function isSourceFileJavaScript(file: SourceFile): boolean {
return isInJavaScriptFile(file);
export function isSourceFileJS(file: SourceFile): boolean {
return isInJSFile(file);
}
export function isSourceFileNotJavaScript(file: SourceFile): boolean {
return !isInJavaScriptFile(file);
export function isSourceFileNotJS(file: SourceFile): boolean {
return !isInJSFile(file);
}
export function isInJavaScriptFile(node: Node | undefined): boolean {
export function isInJSFile(node: Node | undefined): boolean {
return !!node && !!(node.flags & NodeFlags.JavaScriptFile);
}
@@ -1739,14 +1731,14 @@ namespace ts {
return getSourceTextOfNodeFromSourceFile(sourceFile, str).charCodeAt(0) === CharacterCodes.doubleQuote;
}
export function getDeclarationOfJSInitializer(node: Node): Node | undefined {
export function getDeclarationOfExpando(node: Node): Node | undefined {
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)) {
if (!isInJSFile(node) && !isVarConst(node.parent)) {
return undefined;
}
name = node.parent.name;
@@ -1771,7 +1763,7 @@ namespace ts {
}
}
if (!name || !getJavascriptInitializer(node, isPrototypeAccess(name))) {
if (!name || !getExpandoInitializer(node, isPrototypeAccess(name))) {
return undefined;
}
return decl;
@@ -1783,7 +1775,7 @@ namespace ts {
/** Get the initializer, taking into account defaulted Javascript initializers */
export function getEffectiveInitializer(node: HasExpressionInitializer) {
if (isInJavaScriptFile(node) && node.initializer &&
if (isInJSFile(node) && node.initializer &&
isBinaryExpression(node.initializer) && node.initializer.operatorToken.kind === SyntaxKind.BarBarToken &&
node.name && isEntityNameExpression(node.name) && isSameEntityName(node.name, node.initializer.left)) {
return node.initializer.right;
@@ -1791,26 +1783,26 @@ namespace ts {
return node.initializer;
}
/** Get the declaration initializer when it is container-like (See getJavascriptInitializer). */
export function getDeclaredJavascriptInitializer(node: HasExpressionInitializer) {
/** Get the declaration initializer when it is container-like (See getExpandoInitializer). */
export function getDeclaredExpandoInitializer(node: HasExpressionInitializer) {
const init = getEffectiveInitializer(node);
return init && getJavascriptInitializer(init, isPrototypeAccess(node.name));
return init && getExpandoInitializer(init, isPrototypeAccess(node.name));
}
/**
* Get the assignment 'initializer' -- the righthand side-- when the initializer is container-like (See getJavascriptInitializer).
* Get the assignment 'initializer' -- the righthand side-- when the initializer is container-like (See getExpandoInitializer).
* We treat the right hand side of assignments with container-like initalizers as declarations.
*/
export function getAssignedJavascriptInitializer(node: Node) {
export function getAssignedExpandoInitializer(node: Node) {
if (node && node.parent && isBinaryExpression(node.parent) && node.parent.operatorToken.kind === SyntaxKind.EqualsToken) {
const isPrototypeAssignment = isPrototypeAccess(node.parent.left);
return getJavascriptInitializer(node.parent.right, isPrototypeAssignment) ||
getDefaultedJavascriptInitializer(node.parent.left as EntityNameExpression, node.parent.right, isPrototypeAssignment);
return getExpandoInitializer(node.parent.right, isPrototypeAssignment) ||
getDefaultedExpandoInitializer(node.parent.left as EntityNameExpression, node.parent.right, isPrototypeAssignment);
}
}
/**
* Recognized Javascript container-like initializers are:
* Recognized expando initializers are:
* 1. (function() {})() -- IIFEs
* 2. function() { } -- Function expressions
* 3. class { } -- Class expressions
@@ -1819,7 +1811,7 @@ namespace ts {
*
* This function returns the provided initializer, or undefined if it is not valid.
*/
export function getJavascriptInitializer(initializer: Node, isPrototypeAssignment: boolean): Expression | undefined {
export function getExpandoInitializer(initializer: Node, isPrototypeAssignment: boolean): Expression | undefined {
if (isCallExpression(initializer)) {
const e = skipParentheses(initializer.expression);
return e.kind === SyntaxKind.FunctionExpression || e.kind === SyntaxKind.ArrowFunction ? initializer : undefined;
@@ -1835,29 +1827,29 @@ namespace ts {
}
/**
* A defaulted Javascript initializer matches the pattern
* `Lhs = Lhs || JavascriptInitializer`
* or `var Lhs = Lhs || JavascriptInitializer`
* A defaulted expando initializer matches the pattern
* `Lhs = Lhs || ExpandoInitializer`
* or `var Lhs = Lhs || ExpandoInitializer`
*
* The second Lhs is required to be the same as the first except that it may be prefixed with
* 'window.', 'global.' or 'self.' The second Lhs is otherwise ignored by the binder and checker.
*/
function getDefaultedJavascriptInitializer(name: EntityNameExpression, initializer: Expression, isPrototypeAssignment: boolean) {
const e = isBinaryExpression(initializer) && initializer.operatorToken.kind === SyntaxKind.BarBarToken && getJavascriptInitializer(initializer.right, isPrototypeAssignment);
function getDefaultedExpandoInitializer(name: EntityNameExpression, initializer: Expression, isPrototypeAssignment: boolean) {
const e = isBinaryExpression(initializer) && initializer.operatorToken.kind === SyntaxKind.BarBarToken && getExpandoInitializer(initializer.right, isPrototypeAssignment);
if (e && isSameEntityName(name, (initializer as BinaryExpression).left as EntityNameExpression)) {
return e;
}
}
export function isDefaultedJavascriptInitializer(node: BinaryExpression) {
export function isDefaultedExpandoInitializer(node: BinaryExpression) {
const name = isVariableDeclaration(node.parent) ? node.parent.name :
isBinaryExpression(node.parent) && node.parent.operatorToken.kind === SyntaxKind.EqualsToken ? node.parent.left :
undefined;
return name && getJavascriptInitializer(node.right, isPrototypeAccess(name)) && isEntityNameExpression(name) && isSameEntityName(name, node.left);
return name && getExpandoInitializer(node.right, isPrototypeAccess(name)) && isEntityNameExpression(name) && isSameEntityName(name, node.left);
}
/** Given a Javascript initializer, return the outer name. That is, the lhs of the assignment or the declaration name. */
export function getOuterNameOfJsInitializer(node: Declaration): DeclarationName | undefined {
/** Given an expando initializer, return its declaration name, or the left-hand side of the assignment if it's part of an assignment declaration. */
export function getNameOfExpando(node: Declaration): DeclarationName | undefined {
if (isBinaryExpression(node.parent)) {
const parent = (node.parent.operatorToken.kind === SyntaxKind.BarBarToken && isBinaryExpression(node.parent.parent)) ? node.parent.parent : node.parent;
if (parent.operatorToken.kind === SyntaxKind.EqualsToken && isIdentifier(parent.left)) {
@@ -1913,36 +1905,36 @@ 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 {
const special = getSpecialPropertyAssignmentKindWorker(expr);
return special === SpecialPropertyAssignmentKind.Property || isInJavaScriptFile(expr) ? special : SpecialPropertyAssignmentKind.None;
export function getAssignmentDeclarationKind(expr: BinaryExpression): AssignmentDeclarationKind {
const special = getAssignmentDeclarationKindWorker(expr);
return special === AssignmentDeclarationKind.Property || isInJSFile(expr) ? special : AssignmentDeclarationKind.None;
}
function getSpecialPropertyAssignmentKindWorker(expr: BinaryExpression): SpecialPropertyAssignmentKind {
function getAssignmentDeclarationKindWorker(expr: BinaryExpression): AssignmentDeclarationKind {
if (expr.operatorToken.kind !== SyntaxKind.EqualsToken ||
!isPropertyAccessExpression(expr.left)) {
return SpecialPropertyAssignmentKind.None;
return AssignmentDeclarationKind.None;
}
const lhs = expr.left;
if (isEntityNameExpression(lhs.expression) && lhs.name.escapedText === "prototype" && isObjectLiteralExpression(getInitializerOfBinaryExpression(expr))) {
// F.prototype = { ... }
return SpecialPropertyAssignmentKind.Prototype;
return AssignmentDeclarationKind.Prototype;
}
return getSpecialPropertyAccessKind(lhs);
return getAssignmentDeclarationPropertyAccessKind(lhs);
}
export function getSpecialPropertyAccessKind(lhs: PropertyAccessExpression): SpecialPropertyAssignmentKind {
export function getAssignmentDeclarationPropertyAccessKind(lhs: PropertyAccessExpression): AssignmentDeclarationKind {
if (lhs.expression.kind === SyntaxKind.ThisKeyword) {
return SpecialPropertyAssignmentKind.ThisProperty;
return AssignmentDeclarationKind.ThisProperty;
}
else if (isIdentifier(lhs.expression) && lhs.expression.escapedText === "module" && lhs.name.escapedText === "exports") {
// module.exports = expr
return SpecialPropertyAssignmentKind.ModuleExports;
return AssignmentDeclarationKind.ModuleExports;
}
else if (isEntityNameExpression(lhs.expression)) {
if (isPrototypeAccess(lhs.expression)) {
// F.G....prototype.x = expr
return SpecialPropertyAssignmentKind.PrototypeProperty;
return AssignmentDeclarationKind.PrototypeProperty;
}
let nextToLast = lhs;
@@ -1954,13 +1946,13 @@ namespace ts {
if (id.escapedText === "exports" ||
id.escapedText === "module" && nextToLast.name.escapedText === "exports") {
// exports.name = expr OR module.exports.name = expr
return SpecialPropertyAssignmentKind.ExportsProperty;
return AssignmentDeclarationKind.ExportsProperty;
}
// F.G...x = expr
return SpecialPropertyAssignmentKind.Property;
return AssignmentDeclarationKind.Property;
}
return SpecialPropertyAssignmentKind.None;
return AssignmentDeclarationKind.None;
}
export function getInitializerOfBinaryExpression(expr: BinaryExpression) {
@@ -1971,11 +1963,11 @@ namespace ts {
}
export function isPrototypePropertyAssignment(node: Node): boolean {
return isBinaryExpression(node) && getSpecialPropertyAssignmentKind(node) === SpecialPropertyAssignmentKind.PrototypeProperty;
return isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.PrototypeProperty;
}
export function isSpecialPropertyDeclaration(expr: PropertyAccessExpression): boolean {
return isInJavaScriptFile(expr) &&
return isInJSFile(expr) &&
expr.parent && expr.parent.kind === SyntaxKind.ExpressionStatement &&
!!getJSDocTypeTag(expr.parent);
}
@@ -2083,7 +2075,7 @@ namespace ts {
function getSourceOfDefaultedAssignment(node: Node): Node | undefined {
return isExpressionStatement(node) &&
isBinaryExpression(node.expression) &&
getSpecialPropertyAssignmentKind(node.expression) !== SpecialPropertyAssignmentKind.None &&
getAssignmentDeclarationKind(node.expression) !== AssignmentDeclarationKind.None &&
isBinaryExpression(node.expression.right) &&
node.expression.right.operatorToken.kind === SyntaxKind.BarBarToken
? node.expression.right.right
@@ -2403,7 +2395,7 @@ namespace ts {
else {
const binExp = parent.parent;
return isBinaryExpression(binExp) &&
getSpecialPropertyAssignmentKind(binExp) !== SpecialPropertyAssignmentKind.None &&
getAssignmentDeclarationKind(binExp) !== AssignmentDeclarationKind.None &&
(binExp.left.symbol || binExp.symbol) &&
getNameOfDeclaration(binExp) === name
? binExp
@@ -2472,7 +2464,7 @@ namespace ts {
node.kind === SyntaxKind.ImportSpecifier ||
node.kind === SyntaxKind.ExportSpecifier ||
node.kind === SyntaxKind.ExportAssignment && exportAssignmentIsAlias(<ExportAssignment>node) ||
isBinaryExpression(node) && getSpecialPropertyAssignmentKind(node) === SpecialPropertyAssignmentKind.ModuleExports;
isBinaryExpression(node) && getAssignmentDeclarationKind(node) === AssignmentDeclarationKind.ModuleExports;
}
export function exportAssignmentIsAlias(node: ExportAssignment | BinaryExpression): boolean {
@@ -2481,7 +2473,7 @@ namespace ts {
}
export function getEffectiveBaseTypeNode(node: ClassLikeDeclaration | InterfaceDeclaration) {
if (isInJavaScriptFile(node)) {
if (isInJSFile(node)) {
// Prefer an @augments tag because it may have type parameters.
const tag = getJSDocAugmentsTag(node);
if (tag) {
@@ -3253,7 +3245,7 @@ namespace ts {
}
export interface EmitFileNames {
jsFilePath: string;
jsFilePath: string | undefined;
sourceMapFilePath: string | undefined;
declarationFilePath: string | undefined;
declarationMapPath: string | undefined;
@@ -3274,7 +3266,7 @@ namespace ts {
const isSourceFileFromExternalLibrary = (file: SourceFile) => host.isSourceFileFromExternalLibrary(file);
if (options.outFile || options.out) {
const moduleKind = getEmitModuleKind(options);
const moduleEmitEnabled = moduleKind === ModuleKind.AMD || moduleKind === ModuleKind.System;
const moduleEmitEnabled = options.emitDeclarationOnly || moduleKind === ModuleKind.AMD || moduleKind === ModuleKind.System;
// Can emit only sources that are not declaration file and are either non module code or module with --module or --target es6 specified
return filter(host.getSourceFiles(), sourceFile =>
(moduleEmitEnabled || !isExternalModule(sourceFile)) && sourceFileMayBeEmitted(sourceFile, options, isSourceFileFromExternalLibrary));
@@ -3287,7 +3279,7 @@ namespace ts {
/** Don't call this for `--outFile`, just for `--outDir` or plain emit. `--outFile` needs additional checks. */
export function sourceFileMayBeEmitted(sourceFile: SourceFile, options: CompilerOptions, isSourceFileFromExternalLibrary: (file: SourceFile) => boolean) {
return !(options.noEmitForJsFiles && isSourceFileJavaScript(sourceFile)) && !sourceFile.isDeclarationFile && !isSourceFileFromExternalLibrary(sourceFile);
return !(options.noEmitForJsFiles && isSourceFileJS(sourceFile)) && !sourceFile.isDeclarationFile && !isSourceFileFromExternalLibrary(sourceFile);
}
export function getSourceFilePathInNewDir(fileName: string, host: EmitHost, newDirPath: string): string {
@@ -3411,7 +3403,7 @@ namespace ts {
*/
export function getEffectiveTypeAnnotationNode(node: Node): TypeNode | undefined {
const type = (node as HasType).type;
if (type || !isInJavaScriptFile(node)) return type;
if (type || !isInJSFile(node)) return type;
return isJSDocPropertyLikeTag(node) ? node.typeExpression && node.typeExpression.type : getJSDocType(node);
}
@@ -3426,7 +3418,7 @@ namespace ts {
export function getEffectiveReturnTypeNode(node: SignatureDeclaration | JSDocSignature): TypeNode | undefined {
return isJSDocSignature(node) ?
node.type && node.type.typeExpression && node.type.typeExpression.type :
node.type || (isInJavaScriptFile(node) ? getJSDocReturnType(node) : undefined);
node.type || (isInJSFile(node) ? getJSDocReturnType(node) : undefined);
}
export function getJSDocTypeParameterDeclarations(node: DeclarationWithTypeParameters): ReadonlyArray<TypeParameterDeclaration> {
@@ -3743,11 +3735,20 @@ namespace ts {
/** Get `C` given `N` if `N` is in the position `class C extends N` where `N` is an ExpressionWithTypeArguments. */
export function tryGetClassExtendingExpressionWithTypeArguments(node: Node): ClassLikeDeclaration | undefined {
if (isExpressionWithTypeArguments(node) &&
node.parent.token === SyntaxKind.ExtendsKeyword &&
isClassLike(node.parent.parent)) {
return node.parent.parent;
}
const cls = tryGetClassImplementingOrExtendingExpressionWithTypeArguments(node);
return cls && !cls.isImplements ? cls.class : undefined;
}
export interface ClassImplementingOrExtendingExpressionWithTypeArguments {
readonly class: ClassLikeDeclaration;
readonly isImplements: boolean;
}
export function tryGetClassImplementingOrExtendingExpressionWithTypeArguments(node: Node): ClassImplementingOrExtendingExpressionWithTypeArguments | undefined {
return isExpressionWithTypeArguments(node)
&& isHeritageClause(node.parent)
&& isClassLike(node.parent.parent)
? { class: node.parent.parent, isImplements: node.parent.token === SyntaxKind.ImplementsKeyword }
: undefined;
}
export function isAssignmentExpression(node: Node, excludeCompoundAssignment: true): node is AssignmentExpression<EqualsToken>;
@@ -3774,15 +3775,6 @@ namespace ts {
return tryGetClassExtendingExpressionWithTypeArguments(node) !== undefined;
}
export function isExpressionWithTypeArgumentsInClassImplementsClause(node: Node): node is ExpressionWithTypeArguments {
return node.kind === SyntaxKind.ExpressionWithTypeArguments
&& isEntityNameExpression((node as ExpressionWithTypeArguments).expression)
&& node.parent
&& (<HeritageClause>node.parent).token === SyntaxKind.ImplementsKeyword
&& node.parent.parent
&& isClassLike(node.parent.parent);
}
export function isEntityNameExpression(node: Node): node is EntityNameExpression {
return node.kind === SyntaxKind.Identifier || isPropertyAccessEntityNameExpression(node);
}
@@ -3819,8 +3811,8 @@ namespace ts {
}
/** Return ".ts", ".d.ts", or ".tsx", if that is the extension. */
export function tryExtractTypeScriptExtension(fileName: string): string | undefined {
return find(supportedTypescriptExtensionsForExtractExtension, extension => fileExtensionIs(fileName, extension));
export function tryExtractTSExtension(fileName: string): string | undefined {
return find(supportedTSExtensionsForExtractExtension, extension => fileExtensionIs(fileName, extension));
}
/**
* Replace each instance of non-ascii characters by one, two, three, or four escape sequences
@@ -3974,6 +3966,27 @@ namespace ts {
return getStringFromExpandedCharCodes(expandedCharCodes);
}
export function readJson(path: string, host: { readFile(fileName: string): string | undefined }): object {
try {
const jsonText = host.readFile(path);
if (!jsonText) return {};
const result = parseConfigFileTextToJson(path, jsonText);
if (result.error) {
return {};
}
return result.config;
}
catch (e) {
// gracefully handle if readFile fails or returns not JSON
return {};
}
}
export function directoryProbablyExists(directoryName: string, host: { directoryExists?: (directoryName: string) => boolean }): boolean {
// if host does not support 'directoryExists' assume that directory will exist
return !host.directoryExists || host.directoryExists(directoryName);
}
const carriageReturnLineFeed = "\r\n";
const lineFeed = "\n";
export function getNewLineCharacter(options: CompilerOptions | PrinterOptions, getNewLine?: () => string): string {
@@ -4309,7 +4322,7 @@ namespace ts {
/**
* clears already present map by calling onDeleteExistingValue callback before deleting that key/value
*/
export function clearMap<T>(map: Map<T>, onDeleteValue: (valueInMap: T, key: string) => void) {
export function clearMap<T>(map: { forEach: Map<T>["forEach"]; clear: Map<T>["clear"]; }, onDeleteValue: (valueInMap: T, key: string) => void) {
// Remove all
map.forEach(onDeleteValue);
map.clear();
@@ -4966,11 +4979,11 @@ namespace ts {
}
case SyntaxKind.BinaryExpression: {
const expr = declaration as BinaryExpression;
switch (getSpecialPropertyAssignmentKind(expr)) {
case SpecialPropertyAssignmentKind.ExportsProperty:
case SpecialPropertyAssignmentKind.ThisProperty:
case SpecialPropertyAssignmentKind.Property:
case SpecialPropertyAssignmentKind.PrototypeProperty:
switch (getAssignmentDeclarationKind(expr)) {
case AssignmentDeclarationKind.ExportsProperty:
case AssignmentDeclarationKind.ThisProperty:
case AssignmentDeclarationKind.Property:
case AssignmentDeclarationKind.PrototypeProperty:
return (expr.left as PropertyAccessExpression).name;
default:
return undefined;
@@ -5187,7 +5200,7 @@ namespace ts {
if (node.typeParameters) {
return node.typeParameters;
}
if (isInJavaScriptFile(node)) {
if (isInJSFile(node)) {
const decls = getJSDocTypeParameterDeclarations(node);
if (decls.length) {
return decls;
@@ -6593,7 +6606,7 @@ namespace ts {
/* @internal */
export function isDeclaration(node: Node): node is NamedDeclaration {
if (node.kind === SyntaxKind.TypeParameter) {
return node.parent.kind !== SyntaxKind.JSDocTemplateTag || isInJavaScriptFile(node);
return node.parent.kind !== SyntaxKind.JSDocTemplateTag || isInJSFile(node);
}
return isDeclarationKind(node.kind);
@@ -7065,28 +7078,27 @@ namespace ts {
const moduleKind = getEmitModuleKind(compilerOptions);
return compilerOptions.allowSyntheticDefaultImports !== undefined
? compilerOptions.allowSyntheticDefaultImports
: compilerOptions.esModuleInterop
? moduleKind !== ModuleKind.None && moduleKind < ModuleKind.ES2015
: moduleKind === ModuleKind.System;
: compilerOptions.esModuleInterop ||
moduleKind === ModuleKind.System;
}
export function getEmitDeclarations(compilerOptions: CompilerOptions): boolean {
return !!(compilerOptions.declaration || compilerOptions.composite);
}
export type StrictOptionName = "noImplicitAny" | "noImplicitThis" | "strictNullChecks" | "strictFunctionTypes" | "strictPropertyInitialization" | "alwaysStrict";
export type StrictOptionName = "noImplicitAny" | "noImplicitThis" | "strictNullChecks" | "strictFunctionTypes" | "strictBindCallApply" | "strictPropertyInitialization" | "alwaysStrict";
export function getStrictOptionValue(compilerOptions: CompilerOptions, flag: StrictOptionName): boolean {
return compilerOptions[flag] === undefined ? !!compilerOptions.strict : !!compilerOptions[flag];
}
export function compilerOptionsAffectSemanticDiagnostics(newOptions: CompilerOptions, oldOptions: CompilerOptions) {
if (oldOptions === newOptions) {
return false;
}
export function compilerOptionsAffectSemanticDiagnostics(newOptions: CompilerOptions, oldOptions: CompilerOptions): boolean {
return oldOptions !== newOptions &&
semanticDiagnosticsOptionDeclarations.some(option => !isJsonEqual(getCompilerOptionValue(oldOptions, option), getCompilerOptionValue(newOptions, option)));
}
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 getCompilerOptionValue(options: CompilerOptions, option: CommandLineOption): unknown {
return option.strictFlag ? getStrictOptionValue(options, option.name as StrictOptionName) : options[option.name];
}
export function hasZeroOrOneAsteriskCharacter(str: string): boolean {
@@ -7651,6 +7663,15 @@ namespace ts {
// It may be inefficient (we could just match (/[-[\]{}()*+?.,\\^$|#\s]/g), but this is future
// proof.
const reservedCharacterPattern = /[^\w\s\/]/g;
export function regExpEscape(text: string) {
return text.replace(reservedCharacterPattern, escapeRegExpCharacter);
}
function escapeRegExpCharacter(match: string) {
return "\\" + match;
}
const wildcardCharCodes = [CharacterCodes.asterisk, CharacterCodes.question];
export function hasExtension(fileName: string): boolean {
@@ -7717,7 +7738,7 @@ namespace ts {
return `^(${pattern})${terminator}`;
}
function getRegularExpressionsForWildcards(specs: ReadonlyArray<string> | undefined, basePath: string, usage: "files" | "directories" | "exclude"): string[] | undefined {
export function getRegularExpressionsForWildcards(specs: ReadonlyArray<string> | undefined, basePath: string, usage: "files" | "directories" | "exclude"): string[] | undefined {
if (specs === undefined || specs.length === 0) {
return undefined;
}
@@ -7981,48 +8002,58 @@ namespace ts {
/**
* List of supported extensions in order of file resolution precedence.
*/
export const supportedTypeScriptExtensions: ReadonlyArray<Extension> = [Extension.Ts, Extension.Tsx, Extension.Dts];
export const supportedTSExtensions: ReadonlyArray<Extension> = [Extension.Ts, Extension.Tsx, Extension.Dts];
export const supportedTSExtensionsWithJson: ReadonlyArray<Extension> = [Extension.Ts, Extension.Tsx, Extension.Dts, Extension.Json];
/** 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 const supportedTSExtensionsForExtractExtension: ReadonlyArray<Extension> = [Extension.Dts, Extension.Ts, Extension.Tsx];
export const supportedJSExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx];
export const supportedJSAndJsonExtensions: ReadonlyArray<Extension> = [Extension.Js, Extension.Jsx, Extension.Json];
const allSupportedExtensions: ReadonlyArray<Extension> = [...supportedTSExtensions, ...supportedJSExtensions];
const allSupportedExtensionsWithJson: ReadonlyArray<Extension> = [...supportedTSExtensions, ...supportedJSExtensions, Extension.Json];
export function getSupportedExtensions(options?: CompilerOptions, extraFileExtensions?: ReadonlyArray<FileExtensionInfo>): ReadonlyArray<string> {
const needJsExtensions = options && options.allowJs;
if (!extraFileExtensions || extraFileExtensions.length === 0) {
return needJsExtensions ? allSupportedExtensions : supportedTypeScriptExtensions;
return needJsExtensions ? allSupportedExtensions : supportedTSExtensions;
}
const extensions = [
...needJsExtensions ? allSupportedExtensions : supportedTypeScriptExtensions,
...mapDefined(extraFileExtensions, x => x.scriptKind === ScriptKind.Deferred || needJsExtensions && isJavaScriptLike(x.scriptKind) ? x.extension : undefined)
...needJsExtensions ? allSupportedExtensions : supportedTSExtensions,
...mapDefined(extraFileExtensions, x => x.scriptKind === ScriptKind.Deferred || needJsExtensions && isJSLike(x.scriptKind) ? x.extension : undefined)
];
return deduplicate<string>(extensions, equateStringsCaseSensitive, compareStringsCaseSensitive);
}
function isJavaScriptLike(scriptKind: ScriptKind | undefined): boolean {
export function getSuppoertedExtensionsWithJsonIfResolveJsonModule(options: CompilerOptions | undefined, supportedExtensions: ReadonlyArray<string>): ReadonlyArray<string> {
if (!options || !options.resolveJsonModule) { return supportedExtensions; }
if (supportedExtensions === allSupportedExtensions) { return allSupportedExtensionsWithJson; }
if (supportedExtensions === supportedTSExtensions) { return supportedTSExtensionsWithJson; }
return [...supportedExtensions, Extension.Json];
}
function isJSLike(scriptKind: ScriptKind | undefined): boolean {
return scriptKind === ScriptKind.JS || scriptKind === ScriptKind.JSX;
}
export function hasJavaScriptFileExtension(fileName: string): boolean {
return some(supportedJavascriptExtensions, extension => fileExtensionIs(fileName, extension));
export function hasJSFileExtension(fileName: string): boolean {
return some(supportedJSExtensions, extension => fileExtensionIs(fileName, extension));
}
export function hasJavaScriptOrJsonFileExtension(fileName: string): boolean {
return supportedJavaScriptAndJsonExtensions.some(ext => fileExtensionIs(fileName, ext));
export function hasJSOrJsonFileExtension(fileName: string): boolean {
return supportedJSAndJsonExtensions.some(ext => fileExtensionIs(fileName, ext));
}
export function hasTypeScriptFileExtension(fileName: string): boolean {
return some(supportedTypeScriptExtensions, extension => fileExtensionIs(fileName, extension));
export function hasTSFileExtension(fileName: string): boolean {
return some(supportedTSExtensions, extension => fileExtensionIs(fileName, extension));
}
export function isSupportedSourceFileName(fileName: string, compilerOptions?: CompilerOptions, extraFileExtensions?: ReadonlyArray<FileExtensionInfo>) {
if (!fileName) { return false; }
for (const extension of getSupportedExtensions(compilerOptions, extraFileExtensions)) {
const supportedExtensions = getSupportedExtensions(compilerOptions, extraFileExtensions);
for (const extension of getSuppoertedExtensionsWithJsonIfResolveJsonModule(compilerOptions, supportedExtensions)) {
if (fileExtensionIs(fileName, extension)) {
return true;
}
@@ -8152,12 +8183,12 @@ namespace ts {
}
/** True if an extension is one of the supported TypeScript extensions. */
export function extensionIsTypeScript(ext: Extension): boolean {
export function extensionIsTS(ext: Extension): boolean {
return ext === Extension.Ts || ext === Extension.Tsx || ext === Extension.Dts;
}
export function resolutionExtensionIsTypeScriptOrJson(ext: Extension) {
return extensionIsTypeScript(ext) || ext === Extension.Json;
export function resolutionExtensionIsTSOrJson(ext: Extension) {
return extensionIsTS(ext) || ext === Extension.Json;
}
/**
@@ -8345,4 +8376,20 @@ namespace ts {
// '/// <reference no-default-lib="true"/>' directive.
return options.skipLibCheck && sourceFile.isDeclarationFile || options.skipDefaultLibCheck && sourceFile.hasNoDefaultLib;
}
export function isJsonEqual(a: unknown, b: unknown): boolean {
return a === b || typeof a === "object" && a !== null && typeof b === "object" && b !== null && equalOwnProperties(a as MapLike<unknown>, b as MapLike<unknown>, isJsonEqual);
}
export function getOrUpdate<T>(map: Map<T>, key: string, getDefault: () => T): T {
const got = map.get(key);
if (got === undefined) {
const value = getDefault();
map.set(key, value);
return value;
}
else {
return got;
}
}
}
+24 -21
View File
@@ -101,7 +101,7 @@ namespace ts {
getGlobalDiagnostics(): ReadonlyArray<Diagnostic>;
getSemanticDiagnostics(): ReadonlyArray<Diagnostic>;
getConfigFileParsingDiagnostics(): ReadonlyArray<Diagnostic>;
emit(): EmitResult;
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback): EmitResult;
}
export type ReportEmitErrorSummary = (errorCount: number) => void;
@@ -109,7 +109,7 @@ namespace ts {
/**
* Helper that emit files, report diagnostics and lists emitted and/or source files depending on compiler options
*/
export function emitFilesAndReportErrors(program: ProgramToEmitFilesAndReportErrors, reportDiagnostic: DiagnosticReporter, writeFileName?: (s: string) => void, reportSummary?: ReportEmitErrorSummary) {
export function emitFilesAndReportErrors(program: ProgramToEmitFilesAndReportErrors, reportDiagnostic: DiagnosticReporter, writeFileName?: (s: string) => void, reportSummary?: ReportEmitErrorSummary, writeFile?: WriteFileCallback) {
// First get and report any syntactic errors.
const diagnostics = program.getConfigFileParsingDiagnostics().slice();
const configFileParsingDiagnosticsLength = diagnostics.length;
@@ -128,7 +128,7 @@ namespace ts {
}
// Emit and report any errors we ran into.
const { emittedFiles, emitSkipped, diagnostics: emitDiagnostics } = program.emit();
const { emittedFiles, emitSkipped, diagnostics: emitDiagnostics } = program.emit(/*targetSourceFile*/ undefined, writeFile);
addRange(diagnostics, emitDiagnostics);
if (reportSemanticDiagnostics) {
@@ -263,10 +263,11 @@ namespace ts {
/**
* Creates the watch compiler host from system for compiling root files and options in watch mode
*/
export function createWatchCompilerHostOfFilesAndCompilerOptions<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfFilesAndCompilerOptions<T> {
export function createWatchCompilerHostOfFilesAndCompilerOptions<T extends BuilderProgram = EmitAndSemanticDiagnosticsBuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, projectReferences?: ReadonlyArray<ProjectReference>): WatchCompilerHostOfFilesAndCompilerOptions<T> {
const host = createWatchCompilerHost(system, createProgram, reportDiagnostic || createDiagnosticReporter(system), reportWatchStatus) as WatchCompilerHostOfFilesAndCompilerOptions<T>;
host.rootFiles = rootFiles;
host.options = options;
host.projectReferences = projectReferences;
return host;
}
}
@@ -274,7 +275,7 @@ namespace ts {
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 type CreateProgram<T extends BuilderProgram> = (rootNames: ReadonlyArray<string> | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: T, configFileParsingDiagnostics?: ReadonlyArray<Diagnostic>, projectReferences?: ReadonlyArray<ProjectReference> | undefined) => T;
/** 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 */
@@ -360,6 +361,9 @@ namespace ts {
/** Compiler options */
options: CompilerOptions;
/** Project References */
projectReferences?: ReadonlyArray<ProjectReference>;
}
/**
@@ -413,11 +417,11 @@ namespace ts {
/**
* Create the watch compiler host for either configFile or fileNames and its options
*/
export function createWatchCompilerHost<T extends BuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfFilesAndCompilerOptions<T>;
export function createWatchCompilerHost<T extends BuilderProgram>(configFileName: string, optionsToExtend: CompilerOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfConfigFile<T>;
export function createWatchCompilerHost<T extends BuilderProgram>(rootFilesOrConfigFileName: string | string[], options: CompilerOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter): WatchCompilerHostOfFilesAndCompilerOptions<T> | WatchCompilerHostOfConfigFile<T> {
export function createWatchCompilerHost<T extends BuilderProgram>(rootFiles: string[], options: CompilerOptions, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, projectReferences?: ReadonlyArray<ProjectReference>): WatchCompilerHostOfFilesAndCompilerOptions<T>;
export function createWatchCompilerHost<T extends BuilderProgram>(rootFilesOrConfigFileName: string | string[], options: CompilerOptions | undefined, system: System, createProgram?: CreateProgram<T>, reportDiagnostic?: DiagnosticReporter, reportWatchStatus?: WatchStatusReporter, projectReferences?: ReadonlyArray<ProjectReference>): WatchCompilerHostOfFilesAndCompilerOptions<T> | WatchCompilerHostOfConfigFile<T> {
if (isArray(rootFilesOrConfigFileName)) {
return createWatchCompilerHostOfFilesAndCompilerOptions(rootFilesOrConfigFileName, options!, system, createProgram, reportDiagnostic, reportWatchStatus); // TODO: GH#18217
return createWatchCompilerHostOfFilesAndCompilerOptions(rootFilesOrConfigFileName, options!, system, createProgram, reportDiagnostic, reportWatchStatus, projectReferences); // TODO: GH#18217
}
else {
return createWatchCompilerHostOfConfigFile(rootFilesOrConfigFileName, options, system, createProgram, reportDiagnostic, reportWatchStatus);
@@ -463,9 +467,10 @@ namespace ts {
const getCurrentDirectory = () => currentDirectory;
const readFile: (path: string, encoding?: string) => string | undefined = (path, encoding) => host.readFile(path, encoding);
const { configFileName, optionsToExtend: optionsToExtendForConfigFile = {}, createProgram } = host;
let { rootFiles: rootFileNames, options: compilerOptions } = host;
let { rootFiles: rootFileNames, options: compilerOptions, projectReferences } = host;
let configFileSpecs: ConfigFileSpecs;
let configFileParsingDiagnostics: ReadonlyArray<Diagnostic> | undefined;
let configFileParsingDiagnostics: Diagnostic[] | undefined;
let canConfigFileJsonReportNoInputFiles = false;
let hasChangedConfigFileParsingErrors = false;
const cachedDirectoryStructureHost = configFileName === undefined ? undefined : createCachedDirectoryStructureHost(host, currentDirectory, useCaseSensitiveFileNames);
@@ -542,7 +547,8 @@ namespace ts {
},
maxNumberOfFilesToIterateForInvalidation: host.maxNumberOfFilesToIterateForInvalidation,
getCurrentProgram,
writeLog
writeLog,
readDirectory: (path, extensions, exclude, include, depth?) => directoryStructureHost.readDirectory!(path, extensions, exclude, include, depth),
};
// Cache for the module resolution
const resolutionCache = createResolutionCache(compilerHost, configFileName ?
@@ -589,9 +595,9 @@ namespace ts {
// All resolutions are invalid if user provided resolutions
const hasInvalidatedResolution = resolutionCache.createHasInvalidatedResolution(userProvidedResolution);
if (isProgramUptoDate(getCurrentProgram(), rootFileNames, compilerOptions, getSourceVersion, fileExists, hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames)) {
if (isProgramUptoDate(getCurrentProgram(), rootFileNames, compilerOptions, getSourceVersion, fileExists, hasInvalidatedResolution, hasChangedAutomaticTypeDirectiveNames, projectReferences)) {
if (hasChangedConfigFileParsingErrors) {
builderProgram = createProgram(/*rootNames*/ undefined, /*options*/ undefined, compilerHost, builderProgram, configFileParsingDiagnostics);
builderProgram = createProgram(/*rootNames*/ undefined, /*options*/ undefined, compilerHost, builderProgram, configFileParsingDiagnostics, projectReferences);
hasChangedConfigFileParsingErrors = false;
}
}
@@ -620,7 +626,7 @@ namespace ts {
resolutionCache.startCachingPerDirectoryResolution();
compilerHost.hasInvalidatedResolution = hasInvalidatedResolution;
compilerHost.hasChangedAutomaticTypeDirectiveNames = hasChangedAutomaticTypeDirectiveNames;
builderProgram = createProgram(rootFileNames, compilerOptions, compilerHost, builderProgram, configFileParsingDiagnostics);
builderProgram = createProgram(rootFileNames, compilerOptions, compilerHost, builderProgram, configFileParsingDiagnostics, projectReferences);
resolutionCache.finishCachingPerDirectoryResolution();
// Update watches
@@ -824,12 +830,7 @@ namespace ts {
function reloadFileNamesFromConfigFile() {
writeLog("Reloading new file names and options");
const result = getFileNamesFromConfigSpecs(configFileSpecs, getDirectoryPath(configFileName), compilerOptions, parseConfigFileHost);
if (result.fileNames.length) {
configFileParsingDiagnostics = filter(configFileParsingDiagnostics, error => !isErrorNoInputFiles(error));
hasChangedConfigFileParsingErrors = true;
}
else if (!configFileSpecs.filesSpecs && !some(configFileParsingDiagnostics, isErrorNoInputFiles)) {
configFileParsingDiagnostics = configFileParsingDiagnostics!.concat(getErrorForNoInputFiles(configFileSpecs, configFileName));
if (updateErrorForNoInputFiles(result, configFileName, configFileSpecs, configFileParsingDiagnostics!, canConfigFileJsonReportNoInputFiles)) {
hasChangedConfigFileParsingErrors = true;
}
rootFileNames = result.fileNames;
@@ -861,7 +862,9 @@ namespace ts {
rootFileNames = configFileParseResult.fileNames;
compilerOptions = configFileParseResult.options;
configFileSpecs = configFileParseResult.configFileSpecs!; // TODO: GH#18217
configFileParsingDiagnostics = getConfigFileParsingDiagnostics(configFileParseResult);
projectReferences = configFileParseResult.projectReferences;
configFileParsingDiagnostics = getConfigFileParsingDiagnostics(configFileParseResult).slice();
canConfigFileJsonReportNoInputFiles = canJsonReportNoInutFiles(configFileParseResult.raw);
hasChangedConfigFileParsingErrors = true;
}
+35 -24
View File
@@ -3,12 +3,15 @@ namespace ts.server {
writeMessage(message: string): void;
}
interface RenameEntry extends RenameInfo {
fileName: string;
position: number;
locations: RenameLocation[];
findInStrings: boolean;
findInComments: boolean;
interface RenameEntry {
readonly renameInfo: RenameInfo;
readonly inputs: {
readonly fileName: string;
readonly position: number;
readonly findInStrings: boolean;
readonly findInComments: boolean;
};
readonly locations: RenameLocation[];
}
/* @internal */
@@ -390,33 +393,41 @@ namespace ts.server {
const locations: RenameLocation[] = [];
for (const entry of body.locs) {
const fileName = entry.file;
for (const loc of entry.locs) {
locations.push({ textSpan: this.decodeSpan(loc, fileName), fileName });
for (const { start, end, ...prefixSuffixText } of entry.locs) {
locations.push({ textSpan: this.decodeSpan({ start, end }, fileName), fileName, ...prefixSuffixText });
}
}
return this.lastRenameEntry = {
canRename: body.info.canRename,
displayName: body.info.displayName,
fullDisplayName: body.info.fullDisplayName,
kind: body.info.kind,
kindModifiers: body.info.kindModifiers,
localizedErrorMessage: body.info.localizedErrorMessage,
triggerSpan: createTextSpanFromBounds(position, position),
fileName,
position,
findInStrings: !!findInStrings,
findInComments: !!findInComments,
const renameInfo = body.info.canRename
? identity<RenameInfoSuccess>({
canRename: body.info.canRename,
fileToRename: body.info.fileToRename,
displayName: body.info.displayName,
fullDisplayName: body.info.fullDisplayName,
kind: body.info.kind,
kindModifiers: body.info.kindModifiers,
triggerSpan: createTextSpanFromBounds(position, position),
})
: identity<RenameInfoFailure>({ canRename: false, localizedErrorMessage: body.info.localizedErrorMessage });
this.lastRenameEntry = {
renameInfo,
inputs: {
fileName,
position,
findInStrings: !!findInStrings,
findInComments: !!findInComments,
},
locations,
};
return renameInfo;
}
findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean): RenameLocation[] {
if (!this.lastRenameEntry ||
this.lastRenameEntry.fileName !== fileName ||
this.lastRenameEntry.position !== position ||
this.lastRenameEntry.findInStrings !== findInStrings ||
this.lastRenameEntry.findInComments !== findInComments) {
this.lastRenameEntry.inputs.fileName !== fileName ||
this.lastRenameEntry.inputs.position !== position ||
this.lastRenameEntry.inputs.findInStrings !== findInStrings ||
this.lastRenameEntry.inputs.findInComments !== findInComments) {
this.getRenameInfo(fileName, position, findInStrings, findInComments);
}
+79 -33
View File
@@ -420,12 +420,12 @@ namespace FourSlash {
}
}
public goToEachRange(action: () => void) {
public goToEachRange(action: (range: Range) => void) {
const ranges = this.getRanges();
assert(ranges.length);
for (const range of ranges) {
this.selectRange(range);
action();
action(range);
}
}
@@ -593,7 +593,7 @@ namespace FourSlash {
public verifyNoErrors() {
ts.forEachKey(this.inputFiles, fileName => {
if (!ts.isAnySupportedFileExtension(fileName)
|| !this.getProgram().getCompilerOptions().allowJs && !ts.extensionIsTypeScript(ts.extensionFromPath(fileName))) return;
|| !this.getProgram().getCompilerOptions().allowJs && !ts.extensionIsTS(ts.extensionFromPath(fileName))) return;
const errors = this.getDiagnostics(fileName).filter(e => e.category !== ts.DiagnosticCategory.Suggestion);
if (errors.length) {
this.printErrorLog(/*expectErrors*/ false, errors);
@@ -908,8 +908,8 @@ namespace FourSlash {
}
private verifyCompletionEntry(actual: ts.CompletionEntry, expected: FourSlashInterface.ExpectedCompletionEntry) {
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 }
const { insertText, replacementSpan, hasAction, isRecommended, kind, text, documentation, tags, source, sourceDisplay } = typeof expected === "string"
? { insertText: undefined, replacementSpan: undefined, hasAction: undefined, isRecommended: undefined, kind: undefined, text: undefined, documentation: undefined, tags: undefined, source: undefined, sourceDisplay: undefined }
: expected;
if (actual.insertText !== insertText) {
@@ -929,7 +929,7 @@ namespace FourSlash {
assert.equal(actual.isRecommended, isRecommended);
assert.equal(actual.source, source);
if (text) {
if (text !== undefined) {
const actualDetails = this.getCompletionEntryDetails(actual.name, actual.source)!;
assert.equal(ts.displayPartsToString(actualDetails.displayParts), text);
assert.equal(ts.displayPartsToString(actualDetails.documentation), documentation || "");
@@ -937,9 +937,10 @@ namespace FourSlash {
// assert.equal(actualDetails.kind, actual.kind);
assert.equal(actualDetails.kindModifiers, actual.kindModifiers);
assert.equal(actualDetails.source && ts.displayPartsToString(actualDetails.source), sourceDisplay);
assert.deepEqual(actualDetails.tags, tags);
}
else {
assert(documentation === undefined && sourceDisplay === undefined, "If specifying completion details, should specify 'text'");
assert(documentation === undefined && tags === undefined && sourceDisplay === undefined, "If specifying completion details, should specify 'text'");
}
}
@@ -1363,7 +1364,7 @@ Actual: ${stringify(fullActual)}`);
public verifyQuickInfoDisplayParts(kind: string, kindModifiers: string, textSpan: TextSpan,
displayParts: ts.SymbolDisplayPart[],
documentation: ts.SymbolDisplayPart[],
tags: ts.JSDocTagInfo[]
tags: ts.JSDocTagInfo[] | undefined
) {
const actualQuickInfo = this.languageService.getQuickInfoAtPosition(this.activeFile.fileName, this.currentCaretPosition)!;
@@ -1372,11 +1373,16 @@ Actual: ${stringify(fullActual)}`);
assert.equal(JSON.stringify(actualQuickInfo.textSpan), JSON.stringify(textSpan), this.messageAtLastKnownMarker("QuickInfo textSpan"));
assert.equal(TestState.getDisplayPartsJson(actualQuickInfo.displayParts), TestState.getDisplayPartsJson(displayParts), this.messageAtLastKnownMarker("QuickInfo displayParts"));
assert.equal(TestState.getDisplayPartsJson(actualQuickInfo.documentation), TestState.getDisplayPartsJson(documentation), this.messageAtLastKnownMarker("QuickInfo documentation"));
assert.equal(actualQuickInfo.tags!.length, tags.length, this.messageAtLastKnownMarker("QuickInfo tags"));
ts.zipWith(tags, actualQuickInfo.tags!, (expectedTag, actualTag) => {
assert.equal(expectedTag.name, actualTag.name);
assert.equal(expectedTag.text, actualTag.text, this.messageAtLastKnownMarker("QuickInfo tag " + actualTag.name));
});
if (!actualQuickInfo.tags || !tags) {
assert.equal(actualQuickInfo.tags, tags, this.messageAtLastKnownMarker("QuickInfo tags"));
}
else {
assert.equal(actualQuickInfo.tags.length, tags.length, this.messageAtLastKnownMarker("QuickInfo tags"));
ts.zipWith(tags, actualQuickInfo.tags, (expectedTag, actualTag) => {
assert.equal(expectedTag.name, actualTag.name);
assert.equal(expectedTag.text, actualTag.text, this.messageAtLastKnownMarker("QuickInfo tag " + actualTag.name));
});
}
}
public verifyRangesAreRenameLocations(options?: Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges?: Range[] }) {
@@ -1389,7 +1395,7 @@ Actual: ${stringify(fullActual)}`);
}
}
public verifyRenameLocations(startRanges: ArrayOrSingle<Range>, options: ReadonlyArray<Range> | { findInStrings?: boolean, findInComments?: boolean, ranges: ReadonlyArray<Range> }) {
public verifyRenameLocations(startRanges: ArrayOrSingle<Range>, options: FourSlashInterface.RenameLocationsOptions) {
const { findInStrings = false, findInComments = false, ranges = this.getRanges() } = ts.isArray(options) ? { findInStrings: false, findInComments: false, ranges: options } : options;
for (const startRange of toArray(startRanges)) {
@@ -1406,7 +1412,10 @@ Actual: ${stringify(fullActual)}`);
const sort = (locations: ReadonlyArray<ts.RenameLocation> | undefined) =>
locations && ts.sort(locations, (r1, r2) => ts.compareStringsCaseSensitive(r1.fileName, r2.fileName) || r1.textSpan.start - r2.textSpan.start);
assert.deepEqual(sort(references), sort(ranges.map((r): ts.RenameLocation => ({ fileName: r.fileName, textSpan: ts.createTextSpanFromRange(r) }))));
assert.deepEqual(sort(references), sort(ranges.map((rangeOrOptions): ts.RenameLocation => {
const { range, ...prefixSuffixText } = "range" in rangeOrOptions ? rangeOrOptions : { range: rangeOrOptions };
return { fileName: range.fileName, textSpan: ts.createTextSpanFromRange(range), ...prefixSuffixText };
})));
}
}
@@ -1525,22 +1534,25 @@ Actual: ${stringify(fullActual)}`);
}
}
public verifyRenameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string) {
public verifyRenameInfoSucceeded(displayName: string | undefined, fullDisplayName: string | undefined, kind: string | undefined, kindModifiers: string | undefined, fileToRename: string | undefined, expectedRange: Range | undefined): void {
const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition);
if (!renameInfo.canRename) {
this.raiseError("Rename did not succeed");
throw this.raiseError("Rename did not succeed");
}
this.validate("displayName", displayName, renameInfo.displayName);
this.validate("fullDisplayName", fullDisplayName, renameInfo.fullDisplayName);
this.validate("kind", kind, renameInfo.kind);
this.validate("kindModifiers", kindModifiers, renameInfo.kindModifiers);
this.validate("fileToRename", fileToRename, renameInfo.fileToRename);
if (this.getRanges().length !== 1) {
this.raiseError("Expected a single range to be selected in the test file.");
if (!expectedRange) {
if (this.getRanges().length !== 1) {
this.raiseError("Expected a single range to be selected in the test file.");
}
expectedRange = this.getRanges()[0];
}
const expectedRange = this.getRanges()[0];
if (renameInfo.triggerSpan.start !== expectedRange.pos ||
ts.textSpanEnd(renameInfo.triggerSpan) !== expectedRange.end) {
this.raiseError("Expected triggerSpan [" + expectedRange.pos + "," + expectedRange.end + "). Got [" +
@@ -1551,9 +1563,8 @@ Actual: ${stringify(fullActual)}`);
public verifyRenameInfoFailed(message?: string) {
const renameInfo = this.languageService.getRenameInfo(this.activeFile.fileName, this.currentCaretPosition);
if (renameInfo.canRename) {
this.raiseError("Rename was expected to fail");
throw this.raiseError("Rename was expected to fail");
}
this.validate("error", message, renameInfo.localizedErrorMessage);
}
@@ -2493,9 +2504,7 @@ Actual: ${stringify(fullActual)}`);
const { changes, commands } = this.languageService.getCombinedCodeFix({ type: "file", fileName: this.activeFile.fileName }, fixId, this.formatCodeSettings, ts.emptyOptions);
assert.deepEqual<ReadonlyArray<{}> | undefined>(commands, expectedCommands);
assert(changes.every(c => c.fileName === this.activeFile.fileName), "TODO: support testing codefixes that touch multiple files");
this.applyChanges(changes);
this.verifyCurrentFileContent(newFileContent);
this.verifyNewContent({ newFileContent }, changes);
}
/**
@@ -2507,10 +2516,10 @@ Actual: ${stringify(fullActual)}`);
* @param expectedContents The contents of the file after the fixes are applied.
* @param fileName The file to check. If not supplied, the current open file is used.
*/
public verifyFileAfterCodeFix(expectedContents: string, fileName?: string) {
public verifyFileAfterCodeFix(expectedContents: string, fileName?: string, index?: number) {
fileName = fileName ? fileName : this.activeFile.fileName;
this.applyCodeActions(this.getCodeFixes(fileName));
this.applyCodeActions(this.getCodeFixes(fileName), index);
const actualContents: string = this.getFileContent(fileName);
if (this.removeWhitespace(actualContents) !== this.removeWhitespace(expectedContents)) {
@@ -3380,6 +3389,19 @@ Actual: ${stringify(fullActual)}`);
private getApplicableRefactorsWorker(positionOrRange: number | ts.TextRange, fileName: string, preferences = ts.emptyOptions): ReadonlyArray<ts.ApplicableRefactorInfo> {
return this.languageService.getApplicableRefactors(fileName, positionOrRange, preferences) || ts.emptyArray;
}
public generateTypes(examples: ReadonlyArray<FourSlashInterface.GenerateTypesOptions>): void {
for (const { name = "example", value, output, outputBaseline } of examples) {
const actual = ts.generateTypesForModule(name, value, this.formatCodeSettings);
if (outputBaseline) {
if (actual === undefined) throw ts.Debug.fail();
Harness.Baseline.runBaseline(ts.combinePaths("generateTypes", outputBaseline + ts.Extension.Dts), actual);
}
else {
assert.equal(actual, output, `generateTypes output for ${name} does not match`);
}
}
}
}
function updateTextRangeForTextChanges({ pos, end }: ts.TextRange, textChanges: ReadonlyArray<ts.TextChange>): ts.TextRange {
@@ -3433,7 +3455,7 @@ Actual: ${stringify(fullActual)}`);
// Parse out the files and their metadata
const testData = parseTestData(absoluteBasePath, content, absoluteFileName);
const state = new TestState(absoluteBasePath, testType, testData);
const output = ts.transpileModule(content, { reportDiagnostics: true });
const output = ts.transpileModule(content, { reportDiagnostics: true, compilerOptions: { target: ts.ScriptTarget.ES2015 } });
if (output.diagnostics!.length > 0) {
throw new Error(`Syntax error in ${absoluteBasePath}: ${output.diagnostics![0].messageText}`);
}
@@ -3977,7 +3999,7 @@ namespace FourSlashInterface {
this.state.goToRangeStart(range);
}
public eachRange(action: () => void) {
public eachRange(action: (range: FourSlash.Range) => void) {
this.state.goToEachRange(action);
}
@@ -4366,6 +4388,10 @@ namespace FourSlashInterface {
this.state.verifyRangeAfterCodeFix(expectedText, includeWhiteSpace, errorCode, index);
}
public fileAfterCodeFix(expectedContents: string, fileName?: string, index?: number) {
this.state.verifyFileAfterCodeFix(expectedContents, fileName, index);
}
public codeFixAll(options: VerifyCodeFixAllOptions): void {
this.state.verifyCodeFixAll(options);
}
@@ -4456,15 +4482,15 @@ namespace FourSlashInterface {
this.state.verifySemanticClassifications(classifications);
}
public renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string) {
this.state.verifyRenameInfoSucceeded(displayName, fullDisplayName, kind, kindModifiers);
public renameInfoSucceeded(displayName?: string, fullDisplayName?: string, kind?: string, kindModifiers?: string, fileToRename?: string, expectedRange?: FourSlash.Range) {
this.state.verifyRenameInfoSucceeded(displayName, fullDisplayName, kind, kindModifiers, fileToRename, expectedRange);
}
public renameInfoFailed(message?: string) {
this.state.verifyRenameInfoFailed(message);
}
public renameLocations(startRanges: ArrayOrSingle<FourSlash.Range>, options: FourSlash.Range[] | { findInStrings?: boolean, findInComments?: boolean, ranges: FourSlash.Range[] }) {
public renameLocations(startRanges: ArrayOrSingle<FourSlash.Range>, options: RenameLocationsOptions) {
this.state.verifyRenameLocations(startRanges, options);
}
@@ -4503,6 +4529,18 @@ namespace FourSlashInterface {
public noMoveToNewFile(): void {
this.state.noMoveToNewFile();
}
public generateTypes(...options: GenerateTypesOptions[]): void {
this.state.generateTypes(options);
}
}
export interface GenerateTypesOptions {
readonly name?: string;
readonly value: unknown;
// Exactly one of these should be set:
readonly output?: string;
readonly outputBaseline?: string;
}
export class Edit {
@@ -4799,6 +4837,7 @@ namespace FourSlashInterface {
readonly text: string;
readonly documentation: string;
readonly sourceDisplay?: string;
readonly tags?: ReadonlyArray<ts.JSDocTagInfo>;
};
export interface CompletionsAtOptions extends Partial<ts.UserPreferences> {
triggerCharacter?: ts.CompletionsTriggerCharacter;
@@ -4891,7 +4930,7 @@ namespace FourSlashInterface {
export interface VerifyCodeFixAllOptions {
fixId: string;
fixAllDescription: string;
newFileContent: string;
newFileContent: NewFileContent;
commands: ReadonlyArray<{}>;
}
@@ -4926,4 +4965,11 @@ namespace FourSlashInterface {
readonly newFileContents: { readonly [fileName: string]: string };
readonly preferences?: ts.UserPreferences;
}
export type RenameLocationsOptions = ReadonlyArray<RenameLocationOptions> | {
readonly findInStrings?: boolean;
readonly findInComments?: boolean;
readonly ranges: ReadonlyArray<RenameLocationOptions>;
};
export type RenameLocationOptions = FourSlash.Range | { readonly range: FourSlash.Range, readonly prefixText?: string, readonly suffixText?: string };
}
+1 -1
View File
@@ -1159,7 +1159,7 @@ namespace Harness {
}
// If not a primitive, the possible types are specified in what is effectively a map of options.
case "list":
return ts.parseListTypeOption(<ts.CommandLineOptionOfListType>option, value, errors);
return ts.parseListTypeOption(option, value, errors);
default:
return ts.parseCustomTypeOption(<ts.CommandLineOptionOfCustomType>option, value, errors);
}
+1 -1
View File
@@ -268,7 +268,7 @@ namespace Harness.LanguageService {
getHost(): LanguageServiceAdapterHost { return this.host; }
getLanguageService(): ts.LanguageService { return ts.createLanguageService(this.host); }
getClassifier(): ts.Classifier { return ts.createClassifier(); }
getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { return ts.preProcessFile(fileContents, /* readImportFiles */ true, ts.hasJavaScriptFileExtension(fileName)); }
getPreProcessedFileInfo(fileName: string, fileContents: string): ts.PreProcessedFileInfo { return ts.preProcessFile(fileContents, /* readImportFiles */ true, ts.hasJSFileExtension(fileName)); }
}
/// Shim adapter
+27
View File
@@ -7,6 +7,21 @@ namespace utils {
return text !== undefined ? text.replace(testPathPrefixRegExp, (_, scheme) => scheme || (retainTrailingDirectorySeparator ? "/" : "")) : undefined!; // TODO: GH#18217
}
function createDiagnosticMessageReplacer<R extends (messageArgs: string[], ...args: string[]) => string[]>(diagnosticMessage: ts.DiagnosticMessage, replacer: R) {
const messageParts = diagnosticMessage.message.split(/{\d+}/g);
const regExp = new RegExp(`^(?:${messageParts.map(ts.regExpEscape).join("(.*?)")})$`);
type Args<R> = R extends (messageArgs: string[], ...args: infer A) => string[] ? A : [];
return (text: string, ...args: Args<R>) => text.replace(regExp, (_, ...fixedArgs) => ts.formatStringFromArgs(diagnosticMessage.message, replacer(fixedArgs, ...args)));
}
const replaceTypesVersionsMessage = createDiagnosticMessageReplacer(
ts.Diagnostics.package_json_has_a_typesVersions_entry_0_that_matches_compiler_version_1_looking_for_a_pattern_to_match_module_name_2,
([entry, , moduleName], compilerVersion) => [entry, compilerVersion, moduleName]);
export function sanitizeTraceResolutionLogEntry(text: string) {
return text && removeTestPathPrefixes(replaceTypesVersionsMessage(text, "3.1.0-dev"));
}
/**
* Removes leading indentation from a template literal string.
*/
@@ -82,4 +97,16 @@ namespace utils {
export function addUTF8ByteOrderMark(text: string) {
return getByteOrderMarkLength(text) === 0 ? "\u00EF\u00BB\u00BF" + text : text;
}
export function theory<T extends any[]>(name: string, cb: (...args: T) => void, data: T[]) {
for (const entry of data) {
it(`${name}(${entry.map(formatTheoryDatum).join(", ")})`, () => cb(...entry));
}
}
function formatTheoryDatum(value: any) {
return typeof value === "function" ? value.name || "<anonymous function>" :
value === undefined ? "undefined" :
JSON.stringify(value);
}
}
+11 -3
View File
@@ -4,6 +4,8 @@ namespace ts.TestFSWithWatch {
content: `/// <reference no-default-lib="true"/>
interface Boolean {}
interface Function {}
interface CallableFunction {}
interface NewableFunction {}
interface IArguments {}
interface Number { toExponential: any; }
interface Object {}
@@ -187,9 +189,10 @@ interface Array<T> {}`
}
export function checkArray(caption: string, actual: ReadonlyArray<string>, expected: ReadonlyArray<string>) {
checkMapKeys(caption, arrayToMap(actual, identity), expected);
assert.equal(actual.length, expected.length, `${caption}: incorrect actual number of files, expected:\r\n${expected.join("\r\n")}\r\ngot: ${actual.join("\r\n")}`);
for (const f of expected) {
assert.equal(true, contains(actual, f), `${caption}: expected to find ${f} in ${actual}`);
assert.isTrue(contains(actual, f), `${caption}: expected to find ${f} in ${actual}`);
}
}
@@ -654,7 +657,7 @@ interface Array<T> {}`
invokeWatcherCallbacks(this.watchedDirectoriesRecursive.get(this.toPath(folderFullPath))!, cb => this.directoryCallback(cb, relativePath));
}
invokeFileWatcher(fileFullPath: string, eventKind: FileWatcherEventKind, useFileNameInCallback?: boolean) {
private invokeFileWatcher(fileFullPath: string, eventKind: FileWatcherEventKind, useFileNameInCallback?: boolean) {
invokeWatcherCallbacks(this.watchedFiles.get(this.toPath(fileFullPath))!, ({ cb, fileName }) => cb(useFileNameInCallback ? fileName : fileFullPath, eventKind));
}
@@ -934,7 +937,12 @@ interface Array<T> {}`
const folder = this.fs.get(base) as FsFolder;
Debug.assert(isFsFolder(folder));
this.addFileOrFolderInFolder(folder, file);
if (!this.fs.has(file.path)) {
this.addFileOrFolderInFolder(folder, file);
}
else {
this.modifyFile(path, content);
}
}
write(message: string) {
+3 -3
View File
@@ -21,8 +21,8 @@ namespace vpath {
export import relative = ts.getRelativePathFromDirectory;
export import beneath = ts.containsPath;
export import changeExtension = ts.changeAnyExtension;
export import isTypeScript = ts.hasTypeScriptFileExtension;
export import isJavaScript = ts.hasJavaScriptFileExtension;
export import isTypeScript = ts.hasTSFileExtension;
export import isJavaScript = ts.hasJSFileExtension;
const invalidRootComponentRegExp = /^(?!(\/|\/\/\w+\/|[a-zA-Z]:\/?|)$)/;
const invalidNavigableComponentRegExp = /[:*?"<>|]/;
@@ -133,4 +133,4 @@ namespace vpath {
export function isTsConfigFile(path: string): boolean {
return path.indexOf("tsconfig") !== -1 && path.indexOf("json") !== -1;
}
}
}
+5 -5
View File
@@ -21,13 +21,13 @@ namespace ts.JsTyping {
export interface CachedTyping {
typingLocation: string;
version: Semver;
version: Version;
}
/* @internal */
export function isTypingUpToDate(cachedTyping: CachedTyping, availableTypingVersions: MapLike<string>) {
const availableVersion = Semver.parse(getProperty(availableTypingVersions, `ts${versionMajorMinor}`) || getProperty(availableTypingVersions, "latest")!);
return !availableVersion.greaterThan(cachedTyping.version);
const availableVersion = new Version(getProperty(availableTypingVersions, `ts${versionMajorMinor}`) || getProperty(availableTypingVersions, "latest")!);
return availableVersion.compareTo(cachedTyping.version) <= 0;
}
/* @internal */
@@ -122,7 +122,7 @@ namespace ts.JsTyping {
// Only infer typings for .js and .jsx files
fileNames = mapDefined(fileNames, fileName => {
const path = normalizePath(fileName);
if (hasJavaScriptFileExtension(path)) {
if (hasJSFileExtension(path)) {
return path;
}
});
@@ -218,7 +218,7 @@ namespace ts.JsTyping {
*/
function getTypingNamesFromSourceFileNames(fileNames: string[]) {
const fromFileNames = mapDefined(fileNames, j => {
if (!hasJavaScriptFileExtension(j)) return undefined;
if (!hasJSFileExtension(j)) return undefined;
const inferredTypingName = removeFileExtension(getBaseFileName(j.toLowerCase()));
const cleanedTypingName = removeMinAndVersionNumbers(inferredTypingName);
-61
View File
@@ -1,61 +0,0 @@
/* @internal */
namespace ts {
function stringToInt(str: string): number {
const n = parseInt(str, 10);
if (isNaN(n)) {
throw new Error(`Error in parseInt(${JSON.stringify(str)})`);
}
return n;
}
const isPrereleaseRegex = /^(.*)-next.\d+/;
const prereleaseSemverRegex = /^(\d+)\.(\d+)\.0-next.(\d+)$/;
const semverRegex = /^(\d+)\.(\d+)\.(\d+)$/;
export class Semver {
static parse(semver: string): Semver {
const isPrerelease = isPrereleaseRegex.test(semver);
const result = Semver.tryParse(semver, isPrerelease);
if (!result) {
throw new Error(`Unexpected semver: ${semver} (isPrerelease: ${isPrerelease})`);
}
return result;
}
static fromRaw({ major, minor, patch, isPrerelease }: Semver): Semver {
return new Semver(major, minor, patch, isPrerelease);
}
// This must parse the output of `versionString`.
private static tryParse(semver: string, isPrerelease: boolean): Semver | undefined {
// Per the semver spec <http://semver.org/#spec-item-2>:
// "A normal version number MUST take the form X.Y.Z where X, Y, and Z are non-negative integers, and MUST NOT contain leading zeroes."
const rgx = isPrerelease ? prereleaseSemverRegex : semverRegex;
const match = rgx.exec(semver);
return match ? new Semver(stringToInt(match[1]), stringToInt(match[2]), stringToInt(match[3]), isPrerelease) : undefined;
}
private constructor(
readonly major: number, readonly minor: number, readonly patch: number,
/**
* If true, this is `major.minor.0-next.patch`.
* If false, this is `major.minor.patch`.
*/
readonly isPrerelease: boolean) { }
get versionString(): string {
return this.isPrerelease ? `${this.major}.${this.minor}.0-next.${this.patch}` : `${this.major}.${this.minor}.${this.patch}`;
}
equals(sem: Semver): boolean {
return this.major === sem.major && this.minor === sem.minor && this.patch === sem.patch && this.isPrerelease === sem.isPrerelease;
}
greaterThan(sem: Semver): boolean {
return this.major > sem.major || this.major === sem.major
&& (this.minor > sem.minor || this.minor === sem.minor
&& (!this.isPrerelease && sem.isPrerelease || this.isPrerelease === sem.isPrerelease
&& this.patch > sem.patch));
}
}
}
+1
View File
@@ -4,6 +4,7 @@ namespace ts.server {
export const ActionSet: ActionSet = "action::set";
export const ActionInvalidate: ActionInvalidate = "action::invalidate";
export const ActionPackageInstalled: ActionPackageInstalled = "action::packageInstalled";
export const ActionValueInspected: ActionValueInspected = "action::valueInspected";
export const EventTypesRegistry: EventTypesRegistry = "event::typesRegistry";
export const EventBeginInstallTypes: EventBeginInstallTypes = "event::beginInstallTypes";
export const EventEndInstallTypes: EventEndInstallTypes = "event::endInstallTypes";
+1 -2
View File
@@ -16,7 +16,6 @@
"files": [
"shared.ts",
"types.ts",
"jsTyping.ts",
"semver.ts"
"jsTyping.ts"
]
}
+16 -3
View File
@@ -2,6 +2,7 @@ declare namespace ts.server {
export type ActionSet = "action::set";
export type ActionInvalidate = "action::invalidate";
export type ActionPackageInstalled = "action::packageInstalled";
export type ActionValueInspected = "action::valueInspected";
export type EventTypesRegistry = "event::typesRegistry";
export type EventBeginInstallTypes = "event::beginInstallTypes";
export type EventEndInstallTypes = "event::endInstallTypes";
@@ -12,7 +13,7 @@ declare namespace ts.server {
}
export interface TypingInstallerResponse {
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
readonly kind: ActionSet | ActionInvalidate | EventTypesRegistry | ActionPackageInstalled | ActionValueInspected | EventBeginInstallTypes | EventEndInstallTypes | EventInitializationFailed;
}
export interface TypingInstallerRequestWithProjectName {
@@ -20,7 +21,7 @@ declare namespace ts.server {
}
/* @internal */
export type TypingInstallerRequestUnion = DiscoverTypings | CloseProject | TypesRegistryRequest | InstallPackageRequest;
export type TypingInstallerRequestUnion = DiscoverTypings | CloseProject | TypesRegistryRequest | InstallPackageRequest | InspectValueRequest;
export interface DiscoverTypings extends TypingInstallerRequestWithProjectName {
readonly fileNames: string[];
@@ -47,6 +48,12 @@ declare namespace ts.server {
readonly projectRootPath: Path;
}
/* @internal */
export interface InspectValueRequest {
readonly kind: "inspectValue";
readonly options: InspectValueOptions;
}
/* @internal */
export interface TypesRegistryResponse extends TypingInstallerResponse {
readonly kind: EventTypesRegistry;
@@ -59,6 +66,12 @@ declare namespace ts.server {
readonly message: string;
}
/* @internal */
export interface InspectValueResponse {
readonly kind: ActionValueInspected;
readonly result: ValueInfo;
}
export interface InitializationFailedResponse extends TypingInstallerResponse {
readonly kind: EventInitializationFailed;
readonly message: string;
@@ -106,5 +119,5 @@ declare namespace ts.server {
}
/* @internal */
export type TypingInstallerResponseUnion = SetTypings | InvalidateCachedTypings | TypesRegistryResponse | PackageInstalledResponse | InstallTypes | InitializationFailedResponse;
export type TypingInstallerResponseUnion = SetTypings | InvalidateCachedTypings | TypesRegistryResponse | PackageInstalledResponse | InspectValueResponse | InstallTypes | InitializationFailedResponse;
}
+2 -2
View File
@@ -7,7 +7,7 @@ interface PromiseConstructor {
/**
* Creates a new Promise.
* @param executor A callback used to initialize the promise. This callback is passed two arguments:
* a resolve callback used resolve the promise with a value or the result of another promise,
* a resolve callback used to resolve the promise with a value or the result of another promise,
* and a reject callback used to reject the promise with a provided reason or error.
*/
new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;
@@ -193,4 +193,4 @@ interface PromiseConstructor {
resolve(): Promise<void>;
}
declare var Promise: PromiseConstructor;
declare var Promise: PromiseConstructor;
+61 -1
View File
@@ -295,6 +295,66 @@ interface FunctionConstructor {
declare const Function: FunctionConstructor;
interface CallableFunction extends Function {
/**
* Calls the function with the specified object as the this value and the elements of specified array as the arguments.
* @param thisArg The object to be used as the this object.
* @param args An array of argument values to be passed to the function.
*/
apply<T, R>(this: (this: T) => R, thisArg: T): R;
apply<T, A extends any[], R>(this: (this: T, ...args: A) => R, thisArg: T, args: A): R;
/**
* Calls the function with the specified object as the this value and the specified rest arguments as the arguments.
* @param thisArg The object to be used as the this object.
* @param args Argument values to be passed to the function.
*/
call<T, A extends any[], R>(this: (this: T, ...args: A) => R, thisArg: T, ...args: A): R;
/**
* For a given function, creates a bound function that has the same body as the original function.
* The this object of the bound function is associated with the specified object, and has the specified initial parameters.
* @param thisArg The object to be used as the this object.
* @param args Arguments to bind to the parameters of the function.
*/
bind<T, A extends any[], R>(this: (this: T, ...args: A) => R, thisArg: T): (...args: A) => R;
bind<T, A0, A extends any[], R>(this: (this: T, arg0: A0, ...args: A) => R, thisArg: T, arg0: A0): (...args: A) => R;
bind<T, A0, A1, A extends any[], R>(this: (this: T, arg0: A0, arg1: A1, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1): (...args: A) => R;
bind<T, A0, A1, A2, A extends any[], R>(this: (this: T, arg0: A0, arg1: A1, arg2: A2, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1, arg2: A2): (...args: A) => R;
bind<T, A0, A1, A2, A3, A extends any[], R>(this: (this: T, arg0: A0, arg1: A1, arg2: A2, arg3: A3, ...args: A) => R, thisArg: T, arg0: A0, arg1: A1, arg2: A2, arg3: A3): (...args: A) => R;
bind<T, AX, R>(this: (this: T, ...args: AX[]) => R, thisArg: T, ...args: AX[]): (...args: AX[]) => R;
}
interface NewableFunction extends Function {
/**
* Calls the function with the specified object as the this value and the elements of specified array as the arguments.
* @param thisArg The object to be used as the this object.
* @param args An array of argument values to be passed to the function.
*/
apply<T>(this: new () => T, thisArg: T): void;
apply<T, A extends any[]>(this: new (...args: A) => T, thisArg: T, args: A): void;
/**
* Calls the function with the specified object as the this value and the specified rest arguments as the arguments.
* @param thisArg The object to be used as the this object.
* @param args Argument values to be passed to the function.
*/
call<T, A extends any[]>(this: new (...args: A) => T, thisArg: T, ...args: A): void;
/**
* For a given function, creates a bound function that has the same body as the original function.
* The this object of the bound function is associated with the specified object, and has the specified initial parameters.
* @param thisArg The object to be used as the this object.
* @param args Arguments to bind to the parameters of the function.
*/
bind<A extends any[], R>(this: new (...args: A) => R, thisArg: any): new (...args: A) => R;
bind<A0, A extends any[], R>(this: new (arg0: A0, ...args: A) => R, thisArg: any, arg0: A0): new (...args: A) => R;
bind<A0, A1, A extends any[], R>(this: new (arg0: A0, arg1: A1, ...args: A) => R, thisArg: any, arg0: A0, arg1: A1): new (...args: A) => R;
bind<A0, A1, A2, A extends any[], R>(this: new (arg0: A0, arg1: A1, arg2: A2, ...args: A) => R, thisArg: any, arg0: A0, arg1: A1, arg2: A2): new (...args: A) => R;
bind<A0, A1, A2, A3, A extends any[], R>(this: new (arg0: A0, arg1: A1, arg2: A2, arg3: A3, ...args: A) => R, thisArg: any, arg0: A0, arg1: A1, arg2: A2, arg3: A3): new (...args: A) => R;
bind<AX, R>(this: new (...args: AX[]) => R, thisArg: any, ...args: AX[]): new (...args: AX[]) => R;
}
interface IArguments {
[index: number]: any;
length: number;
@@ -1350,7 +1410,7 @@ type Readonly<T> = {
};
/**
* From T pick a set of properties K
* From T, pick a set of properties whose keys are in the union K
*/
type Pick<T, K extends keyof T> = {
[P in K]: T[P];
File diff suppressed because it is too large Load Diff
+200 -39
View File
@@ -5,6 +5,8 @@ namespace ts.server {
// tslint:disable variable-name
export const ProjectsUpdatedInBackgroundEvent = "projectsUpdatedInBackground";
export const ProjectLoadingStartEvent = "projectLoadingStart";
export const ProjectLoadingFinishEvent = "projectLoadingFinish";
export const SurveyReady = "surveyReady";
export const LargeFileReferencedEvent = "largeFileReferenced";
export const ConfigFileDiagEvent = "configFileDiag";
@@ -18,6 +20,16 @@ namespace ts.server {
data: { openFiles: string[]; };
}
export interface ProjectLoadingStartEvent {
eventName: typeof ProjectLoadingStartEvent;
data: { project: Project; reason: string; };
}
export interface ProjectLoadingFinishEvent {
eventName: typeof ProjectLoadingFinishEvent;
data: { project: Project; };
}
export interface SurveyReady {
eventName: typeof SurveyReady;
data: { surveyId: string; };
@@ -44,6 +56,24 @@ namespace ts.server {
readonly data: ProjectInfoTelemetryEventData;
}
/* __GDPR__
"projectInfo" : {
"${include}": ["${TypeScriptCommonProperties}"],
"projectId": { "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight", "endpoint": "ProjectId" },
"fileStats": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"compilerOptions": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"extends": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"files": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"include": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"exclude": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"compileOnSave": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"typeAcquisition": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"configFileName": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"projectType": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"languageServiceEnabled": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"version": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
export interface ProjectInfoTelemetryEventData {
/** Cryptographically secure hash of project file location. */
readonly projectId: string;
@@ -104,7 +134,15 @@ namespace ts.server {
readonly checkJs: boolean;
}
export type ProjectServiceEvent = LargeFileReferencedEvent | SurveyReady | ProjectsUpdatedInBackgroundEvent | ConfigFileDiagEvent | ProjectLanguageServiceStateEvent | ProjectInfoTelemetryEvent | OpenFileInfoTelemetryEvent;
export type ProjectServiceEvent = LargeFileReferencedEvent |
SurveyReady |
ProjectsUpdatedInBackgroundEvent |
ProjectLoadingStartEvent |
ProjectLoadingFinishEvent |
ConfigFileDiagEvent |
ProjectLanguageServiceStateEvent |
ProjectInfoTelemetryEvent |
OpenFileInfoTelemetryEvent;
export type ProjectServiceEventHandler = (event: ProjectServiceEvent) => void;
@@ -291,7 +329,8 @@ namespace ts.server {
ClosedScriptInfo = "Closed Script info",
ConfigFileForInferredRoot = "Config file for the inferred project root",
FailedLookupLocation = "Directory of Failed lookup locations in module resolution",
TypeRoots = "Type root directory"
TypeRoots = "Type root directory",
NodeModulesForClosedScriptInfo = "node_modules for closed script infos in them",
}
const enum ConfigFileWatcherStatus {
@@ -353,10 +392,18 @@ namespace ts.server {
return !!(infoOrFileName as ScriptInfo).containingProjects;
}
interface ScriptInfoInNodeModulesWatcher extends FileWatcher {
refCount: number;
}
function getDetailWatchInfo(watchType: WatchType, project: Project | undefined) {
return `Project: ${project ? project.getProjectName() : ""} WatchType: ${watchType}`;
}
function isScriptInfoWatchedFromNodeModules(info: ScriptInfo) {
return !info.isScriptOpen() && info.mTime !== undefined;
}
/*@internal*/
export function updateProjectIfDirty(project: Project) {
return project.dirty && project.updateGraph();
@@ -380,6 +427,7 @@ namespace ts.server {
* Container of all known scripts
*/
private readonly filenameToScriptInfo = createMap<ScriptInfo>();
private readonly scriptInfoInNodeModulesWatchers = createMap <ScriptInfoInNodeModulesWatcher>();
/**
* Contains all the deleted script info's version information so that
* it does not reset when creating script info again
@@ -438,7 +486,7 @@ namespace ts.server {
private readonly hostConfiguration: HostConfiguration;
private safelist: SafeList = defaultTypeSafeList;
private legacySafelist: { [key: string]: string } = {};
private readonly legacySafelist = createMap<string>();
private pendingProjectUpdates = createMap<Project>();
/* @internal */
@@ -590,14 +638,14 @@ namespace ts.server {
this.safelist = raw.typesMap;
for (const key in raw.simpleMap) {
if (raw.simpleMap.hasOwnProperty(key)) {
this.legacySafelist[key] = raw.simpleMap[key].toLowerCase();
this.legacySafelist.set(key, raw.simpleMap[key].toLowerCase());
}
}
}
catch (e) {
this.logger.info(`Error loading types map: ${e}`);
this.safelist = defaultTypeSafeList;
this.legacySafelist = {};
this.legacySafelist.clear();
}
}
@@ -693,6 +741,33 @@ namespace ts.server {
this.eventHandler(event);
}
/* @internal */
sendProjectLoadingStartEvent(project: ConfiguredProject, reason: string) {
if (!this.eventHandler) {
return;
}
project.sendLoadingProjectFinish = true;
const event: ProjectLoadingStartEvent = {
eventName: ProjectLoadingStartEvent,
data: { project, reason }
};
this.eventHandler(event);
}
/* @internal */
sendProjectLoadingFinishEvent(project: ConfiguredProject) {
if (!this.eventHandler || !project.sendLoadingProjectFinish) {
return;
}
project.sendLoadingProjectFinish = false;
const event: ProjectLoadingFinishEvent = {
eventName: ProjectLoadingFinishEvent,
data: { project }
};
this.eventHandler(event);
}
/* @internal */
delayUpdateProjectGraphAndEnsureProjectStructureForOpenFiles(project: Project) {
this.delayUpdateProjectGraph(project);
@@ -927,6 +1002,7 @@ namespace ts.server {
else {
this.logConfigFileWatchUpdate(project.getConfigFilePath(), project.canonicalConfigFilePath, configFileExistenceInfo, ConfigFileWatcherStatus.ReloadingInferredRootFiles);
project.pendingReload = ConfigFileProgramReloadLevel.Full;
project.pendingReloadReason = "Change in config file detected";
this.delayUpdateProjectGraph(project);
// As we scheduled the update on configured project graph,
// we would need to schedule the project reload for only the root of inferred projects
@@ -1447,14 +1523,14 @@ namespace ts.server {
for (const f of fileNames) {
const fileName = propertyReader.getFileName(f);
if (hasTypeScriptFileExtension(fileName)) {
if (hasTSFileExtension(fileName)) {
continue;
}
totalNonTsFileSize += this.host.getFileSize(fileName);
if (totalNonTsFileSize > maxProgramSizeForNonTsFiles || totalNonTsFileSize > availableSpace) {
this.logger.info(getExceedLimitMessage({ propertyReader, hasTypeScriptFileExtension, host: this.host }, totalNonTsFileSize));
this.logger.info(getExceedLimitMessage({ propertyReader, hasTSFileExtension, host: this.host }, totalNonTsFileSize));
// Keep the size as zero since it's disabled
return fileName;
}
@@ -1464,14 +1540,14 @@ namespace ts.server {
return;
function getExceedLimitMessage(context: { propertyReader: FilePropertyReader<any>, hasTypeScriptFileExtension: (filename: string) => boolean, host: ServerHost }, totalNonTsFileSize: number) {
function getExceedLimitMessage(context: { propertyReader: FilePropertyReader<any>, hasTSFileExtension: (filename: string) => boolean, host: ServerHost }, totalNonTsFileSize: number) {
const files = getTop5LargestFiles(context);
return `Non TS file size exceeded limit (${totalNonTsFileSize}). Largest files: ${files.map(file => `${file.name}:${file.size}`).join(", ")}`;
}
function getTop5LargestFiles({ propertyReader, hasTypeScriptFileExtension, host }: { propertyReader: FilePropertyReader<any>, hasTypeScriptFileExtension: (filename: string) => boolean, host: ServerHost }) {
function getTop5LargestFiles({ propertyReader, hasTSFileExtension, host }: { propertyReader: FilePropertyReader<any>, hasTSFileExtension: (filename: string) => boolean, host: ServerHost }) {
return fileNames.map(f => propertyReader.getFileName(f))
.filter(name => hasTypeScriptFileExtension(name))
.filter(name => hasTSFileExtension(name))
.map(name => ({ name, size: host.getFileSize!(name) })) // TODO: GH#18217
.sort((a, b) => b.size - a.size)
.slice(0, 5);
@@ -1585,22 +1661,23 @@ namespace ts.server {
}
/* @internal */
private createConfiguredProjectWithDelayLoad(configFileName: NormalizedPath) {
private createConfiguredProjectWithDelayLoad(configFileName: NormalizedPath, reason: string) {
const project = this.createConfiguredProject(configFileName);
project.pendingReload = ConfigFileProgramReloadLevel.Full;
project.pendingReloadReason = reason;
return project;
}
/* @internal */
private createAndLoadConfiguredProject(configFileName: NormalizedPath) {
private createAndLoadConfiguredProject(configFileName: NormalizedPath, reason: string) {
const project = this.createConfiguredProject(configFileName);
this.loadConfiguredProject(project);
this.loadConfiguredProject(project, reason);
return project;
}
/* @internal */
private createLoadAndUpdateConfiguredProject(configFileName: NormalizedPath) {
const project = this.createAndLoadConfiguredProject(configFileName);
private createLoadAndUpdateConfiguredProject(configFileName: NormalizedPath, reason: string) {
const project = this.createAndLoadConfiguredProject(configFileName, reason);
project.updateGraph();
return project;
}
@@ -1609,7 +1686,9 @@ namespace ts.server {
* Read the config file of the project, and update the project root file names.
*/
/* @internal */
private loadConfiguredProject(project: ConfiguredProject) {
private loadConfiguredProject(project: ConfiguredProject, reason: string) {
this.sendProjectLoadingStartEvent(project, reason);
// Read updated contents from disk
const configFilename = normalizePath(project.getConfigFilePath());
@@ -1646,6 +1725,7 @@ namespace ts.server {
};
}
project.configFileSpecs = parsedCommandLine.configFileSpecs;
project.canConfigFileJsonReportNoInputFiles = canJsonReportNoInutFiles(parsedCommandLine.raw);
project.setProjectErrors(configFileErrors);
project.updateReferences(parsedCommandLine.projectReferences);
const lastFileExceededProgramSize = this.getFilenameForExceededTotalSizeLimitForNonTsFiles(project.canonicalConfigFilePath, compilerOptions, parsedCommandLine.fileNames, fileNamePropertyReader);
@@ -1738,7 +1818,7 @@ namespace ts.server {
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);
project.updateErrorOnNoInputFiles(fileNamesResult);
this.updateNonInferredProjectFiles(project, fileNamesResult.fileNames.concat(project.getExternalFiles()), fileNamePropertyReader);
return project.updateGraph();
}
@@ -1747,7 +1827,7 @@ namespace ts.server {
* Read the config file of the project again by clearing the cache and update the project graph
*/
/* @internal */
reloadConfiguredProject(project: ConfiguredProject) {
reloadConfiguredProject(project: ConfiguredProject, reason: string) {
// At this point, there is no reason to not have configFile in the host
const host = project.getCachedDirectoryStructureHost();
@@ -1757,7 +1837,7 @@ namespace ts.server {
this.logger.info(`Reloading configured project ${configFileName}`);
// Load project from the disk
this.loadConfiguredProject(project);
this.loadConfiguredProject(project, reason);
project.updateGraph();
this.sendConfigFileDiagEvent(project, configFileName);
@@ -1923,18 +2003,97 @@ namespace ts.server {
if (!info.isDynamicOrHasMixedContent() &&
(!this.globalCacheLocationDirectoryPath ||
!startsWith(info.path, this.globalCacheLocationDirectoryPath))) {
const { fileName } = info;
info.fileWatcher = this.watchFactory.watchFilePath(
this.host,
fileName,
(fileName, eventKind, path) => this.onSourceFileChanged(fileName, eventKind, path),
PollingInterval.Medium,
info.path,
WatchType.ClosedScriptInfo
);
const indexOfNodeModules = info.path.indexOf("/node_modules/");
if (!this.host.getModifiedTime || indexOfNodeModules === -1) {
info.fileWatcher = this.watchFactory.watchFilePath(
this.host,
info.fileName,
(fileName, eventKind, path) => this.onSourceFileChanged(fileName, eventKind, path),
PollingInterval.Medium,
info.path,
WatchType.ClosedScriptInfo
);
}
else {
info.mTime = this.getModifiedTime(info);
info.fileWatcher = this.watchClosedScriptInfoInNodeModules(info.path.substr(0, indexOfNodeModules) as Path);
}
}
}
private watchClosedScriptInfoInNodeModules(dir: Path): ScriptInfoInNodeModulesWatcher {
// Watch only directory
const existing = this.scriptInfoInNodeModulesWatchers.get(dir);
if (existing) {
existing.refCount++;
return existing;
}
const watchDir = dir + "/node_modules" as Path;
const watcher = this.watchFactory.watchDirectory(
this.host,
watchDir,
(fileOrDirectory) => {
const fileOrDirectoryPath = this.toPath(fileOrDirectory);
// Has extension
Debug.assert(result.refCount > 0);
if (watchDir === fileOrDirectoryPath) {
this.refreshScriptInfosInDirectory(watchDir);
}
else {
const info = this.getScriptInfoForPath(fileOrDirectoryPath);
if (info) {
if (isScriptInfoWatchedFromNodeModules(info)) {
this.refreshScriptInfo(info);
}
}
// Folder
else if (!hasExtension(fileOrDirectoryPath)) {
this.refreshScriptInfosInDirectory(fileOrDirectoryPath);
}
}
},
WatchDirectoryFlags.Recursive,
WatchType.NodeModulesForClosedScriptInfo
);
const result: ScriptInfoInNodeModulesWatcher = {
close: () => {
if (result.refCount === 1) {
watcher.close();
this.scriptInfoInNodeModulesWatchers.delete(dir);
}
else {
result.refCount--;
}
},
refCount: 1
};
this.scriptInfoInNodeModulesWatchers.set(dir, result);
return result;
}
private getModifiedTime(info: ScriptInfo) {
return (this.host.getModifiedTime!(info.path) || missingFileModifiedTime).getTime();
}
private refreshScriptInfo(info: ScriptInfo) {
const mTime = this.getModifiedTime(info);
if (mTime !== info.mTime) {
const eventKind = getFileWatcherEventKind(info.mTime!, mTime);
info.mTime = mTime;
this.onSourceFileChanged(info.fileName, eventKind, info.path);
}
}
private refreshScriptInfosInDirectory(dir: Path) {
dir = dir + directorySeparator as Path;
this.filenameToScriptInfo.forEach(info => {
if (isScriptInfoWatchedFromNodeModules(info) && startsWith(info.path, dir)) {
this.refreshScriptInfo(info);
}
});
}
private stopWatchingScriptInfo(info: ScriptInfo) {
if (info.fileWatcher) {
info.fileWatcher.close();
@@ -2031,7 +2190,6 @@ namespace ts.server {
if (project.hasExternalProjectRef() &&
project.pendingReload === ConfigFileProgramReloadLevel.Full &&
!this.pendingProjectUpdates.has(project.getProjectName())) {
this.loadConfiguredProject(project);
project.updateGraph();
}
});
@@ -2063,7 +2221,7 @@ namespace ts.server {
// as there is no need to load contents of the files from the disk
// Reload Projects
this.reloadConfiguredProjectForFiles(this.openFiles, /*delayReload*/ false, returnTrue);
this.reloadConfiguredProjectForFiles(this.openFiles, /*delayReload*/ false, returnTrue, "User requested reload projects");
this.ensureProjectForOpenFiles();
}
@@ -2074,7 +2232,8 @@ namespace ts.server {
/*delayReload*/ true,
ignoreIfNotRootOfInferredProject ?
isRootOfInferredProject => isRootOfInferredProject : // Reload open files if they are root of inferred project
returnTrue // Reload all the open files impacted by config file
returnTrue, // Reload all the open files impacted by config file
"Change in config file detected"
);
this.delayEnsureProjectForOpenFiles();
}
@@ -2086,7 +2245,7 @@ namespace ts.server {
* If the there is no existing project it just opens the configured project for the config file
* reloadForInfo provides a way to filter out files to reload configured project for
*/
private reloadConfiguredProjectForFiles<T>(openFiles: Map<T>, delayReload: boolean, shouldReloadProjectFor: (openFileValue: T) => boolean) {
private reloadConfiguredProjectForFiles<T>(openFiles: Map<T>, delayReload: boolean, shouldReloadProjectFor: (openFileValue: T) => boolean, reason: string) {
const updatedProjects = createMap<true>();
// try to reload config file for all open files
openFiles.forEach((openFileValue, path) => {
@@ -2107,11 +2266,12 @@ namespace ts.server {
if (!updatedProjects.has(configFileName)) {
if (delayReload) {
project.pendingReload = ConfigFileProgramReloadLevel.Full;
project.pendingReloadReason = reason;
this.delayUpdateProjectGraph(project);
}
else {
// reload from the disk
this.reloadConfiguredProject(project);
this.reloadConfiguredProject(project, reason);
}
updatedProjects.set(configFileName, true);
}
@@ -2198,7 +2358,8 @@ namespace ts.server {
const configFileName = this.getConfigFileNameForFile(originalFileInfo);
if (!configFileName) return undefined;
const configuredProject = this.findConfiguredProjectByProjectName(configFileName) || this.createAndLoadConfiguredProject(configFileName);
const configuredProject = this.findConfiguredProjectByProjectName(configFileName) ||
this.createAndLoadConfiguredProject(configFileName, `Creating project for original file: ${originalFileInfo.fileName} for location: ${location.fileName}`);
updateProjectIfDirty(configuredProject);
// Keep this configured project as referenced from project
addOriginalConfiguredProject(configuredProject);
@@ -2248,7 +2409,7 @@ namespace ts.server {
if (configFileName) {
project = this.findConfiguredProjectByProjectName(configFileName);
if (!project) {
project = this.createLoadAndUpdateConfiguredProject(configFileName);
project = this.createLoadAndUpdateConfiguredProject(configFileName, `Creating possible configured project for ${fileName} to open`);
// 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
@@ -2560,13 +2721,13 @@ namespace ts.server {
if (fileExtensionIs(baseName, "js")) {
const inferredTypingName = removeFileExtension(baseName);
const cleanedTypingName = removeMinAndVersionNumbers(inferredTypingName);
if (this.legacySafelist[cleanedTypingName]) {
const typeName = this.legacySafelist.get(cleanedTypingName);
if (typeName !== undefined) {
this.logger.info(`Excluded '${normalizedNames[i]}' because it matched ${cleanedTypingName} from the legacy safelist`);
excludedFiles.push(normalizedNames[i]);
// *exclude* it from the project...
exclude = true;
// ... but *include* it in the list of types to acquire
const typeName = this.legacySafelist[cleanedTypingName];
// Same best-effort dedupe as above
if (typeAcqInclude.indexOf(typeName) < 0) {
typeAcqInclude.push(typeName);
@@ -2689,8 +2850,8 @@ namespace ts.server {
if (!project) {
// errors are stored in the project, do not need to update the graph
project = this.getHostPreferences().lazyConfiguredProjectsFromExternalProject ?
this.createConfiguredProjectWithDelayLoad(tsconfigFile) :
this.createLoadAndUpdateConfiguredProject(tsconfigFile);
this.createConfiguredProjectWithDelayLoad(tsconfigFile, `Creating configured project in external project: ${proj.projectFileName}`) :
this.createLoadAndUpdateConfiguredProject(tsconfigFile, `Creating configured project in external project: ${proj.projectFileName}`);
}
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
+26 -11
View File
@@ -254,6 +254,11 @@ namespace ts.server {
installPackage(options: InstallPackageOptions): Promise<ApplyCodeActionCommandResult> {
return this.typingsCache.installPackage({ ...options, projectName: this.projectName, projectRootPath: this.toPath(this.currentDirectory) });
}
/* @internal */
inspectValue(options: InspectValueOptions): Promise<ValueInfo> {
return this.typingsCache.inspectValue(options);
}
private get typingsCache(): TypingsCache {
return this.projectService.typingsCache;
}
@@ -352,6 +357,10 @@ namespace ts.server {
return this.projectService.host.readFile(fileName);
}
writeFile(fileName: string, content: string): void {
return this.projectService.host.writeFile(fileName, content);
}
fileExists(file: string): boolean {
// As an optimization, don't hit the disks for files we already know don't exist
// (because we're watching for their creation).
@@ -574,7 +583,7 @@ namespace ts.server {
for (const f of this.program.getSourceFiles()) {
this.detachScriptInfoIfNotRoot(f.fileName);
}
const projectReferences = this.program.getProjectReferences();
const projectReferences = this.program.getResolvedProjectReferences();
if (projectReferences) {
for (const ref of projectReferences) {
if (ref) {
@@ -653,7 +662,7 @@ namespace ts.server {
return this.rootFiles;
}
return map(this.program.getSourceFiles(), sourceFile => {
const scriptInfo = this.projectService.getScriptInfoForPath(sourceFile.resolvedPath || sourceFile.path);
const scriptInfo = this.projectService.getScriptInfoForPath(sourceFile.resolvedPath);
Debug.assert(!!scriptInfo, "getScriptInfo", () => `scriptInfo for a file '${sourceFile.fileName}' Path: '${sourceFile.path}' / '${sourceFile.resolvedPath}' is missing.`);
return scriptInfo!;
});
@@ -1311,10 +1320,15 @@ namespace ts.server {
/* @internal */
pendingReload: ConfigFileProgramReloadLevel;
/* @internal */
pendingReloadReason: string | undefined;
/*@internal*/
configFileSpecs: ConfigFileSpecs | undefined;
/*@internal*/
canConfigFileJsonReportNoInputFiles: boolean;
/** Ref count to the project when opened from external project */
private externalProjectRefCount = 0;
@@ -1327,6 +1341,9 @@ namespace ts.server {
protected isInitialLoadPending: () => boolean = returnTrue;
/*@internal*/
sendLoadingProjectFinish = false;
/*@internal*/
constructor(configFileName: NormalizedPath,
projectService: ProjectService,
@@ -1359,12 +1376,15 @@ namespace ts.server {
result = this.projectService.reloadFileNamesOfConfiguredProject(this);
break;
case ConfigFileProgramReloadLevel.Full:
this.projectService.reloadConfiguredProject(this);
const reason = Debug.assertDefined(this.pendingReloadReason);
this.pendingReloadReason = undefined;
this.projectService.reloadConfiguredProject(this, reason);
result = true;
break;
default:
result = super.updateGraph();
}
this.projectService.sendProjectLoadingFinishEvent(this);
this.projectService.sendProjectTelemetry(this);
this.projectService.sendSurveyReady(this);
return result;
@@ -1390,7 +1410,7 @@ namespace ts.server {
/*@internal*/
getResolvedProjectReferences() {
const program = this.getCurrentProgram();
return program && program.getProjectReferences();
return program && program.getResolvedProjectReferences();
}
enablePlugins() {
@@ -1531,13 +1551,8 @@ namespace ts.server {
}
/*@internal*/
updateErrorOnNoInputFiles(hasFileNames: boolean) {
if (hasFileNames) {
filterMutate(this.projectErrors!, error => !isErrorNoInputFiles(error)); // TODO: GH#18217
}
else if (!this.configFileSpecs!.filesSpecs && !some(this.projectErrors, isErrorNoInputFiles)) { // TODO: GH#18217
this.projectErrors!.push(getErrorForNoInputFiles(this.configFileSpecs!, this.getConfigFilePath()));
}
updateErrorOnNoInputFiles(fileNameResult: ExpandResult) {
updateErrorForNoInputFiles(fileNameResult, this.getConfigFilePath(), this.configFileSpecs!, this.projectErrors!, this.canConfigFileJsonReportNoInputFiles);
}
}
+54 -6
View File
@@ -1087,16 +1087,17 @@ namespace ts.server.protocol {
/**
* Information about the item to be renamed.
*/
export interface RenameInfo {
export type RenameInfo = RenameInfoSuccess | RenameInfoFailure;
export interface RenameInfoSuccess {
/**
* True if item can be renamed.
*/
canRename: boolean;
canRename: true;
/**
* Error message if item can not be renamed.
* File or directory to rename.
* If set, `getEditsForFileRename` should be called instead of `findRenameLocations`.
*/
localizedErrorMessage?: string;
fileToRename?: string;
/**
* Display name of the item to be renamed.
@@ -1117,6 +1118,16 @@ namespace ts.server.protocol {
* Optional modifiers for the kind (such as 'public').
*/
kindModifiers: string;
/** Span of text to rename. */
triggerSpan: TextSpan;
}
export interface RenameInfoFailure {
canRename: false;
/**
* Error message if item can not be renamed.
*/
localizedErrorMessage: string;
}
/**
@@ -1126,7 +1137,12 @@ namespace ts.server.protocol {
/** The file to which the spans apply */
file: string;
/** The text spans in this group */
locs: TextSpan[];
locs: RenameTextSpan[];
}
export interface RenameTextSpan extends TextSpan {
readonly prefixText?: string;
readonly suffixText?: string;
}
export interface RenameResponseBody {
@@ -2436,6 +2452,30 @@ namespace ts.server.protocol {
openFiles: string[];
}
export type ProjectLoadingStartEventName = "projectLoadingStart";
export interface ProjectLoadingStartEvent extends Event {
event: ProjectLoadingStartEventName;
body: ProjectLoadingStartEventBody;
}
export interface ProjectLoadingStartEventBody {
/** name of the project */
projectName: string;
/** reason for loading */
reason: string;
}
export type ProjectLoadingFinishEventName = "projectLoadingFinish";
export interface ProjectLoadingFinishEvent extends Event {
event: ProjectLoadingFinishEventName;
body: ProjectLoadingFinishEventBody;
}
export interface ProjectLoadingFinishEventBody {
/** name of the project */
projectName: string;
}
export type SurveyReadyEventName = "surveyReady";
export interface SurveyReadyEvent extends Event {
@@ -2728,6 +2768,14 @@ namespace ts.server.protocol {
payload: TypingsInstalledTelemetryEventPayload;
}
/* __GDPR__
"typingsinstalled" : {
"${include}": ["${TypeScriptCommonProperties}"],
"installedPackages": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" },
"installSuccess": { "classification": "SystemMetaData", "purpose": "FeatureInsight" },
"typingsInstallerVersion": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
}
*/
export interface TypingsInstalledTelemetryEventPayload {
/**
* Comma separated list of installed typing packages
+4 -1
View File
@@ -167,7 +167,7 @@ namespace ts.server {
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)) {
if (!hasTSFileExtension(this.fileName)) {
const fileSize = this.host.getFileSize ? this.host.getFileSize(fileName) : getText().length;
if (fileSize > maxFileSize) {
Debug.assert(!!this.info.containingProjects.length);
@@ -250,6 +250,9 @@ namespace ts.server {
/*@internal*/
cacheSourceFile: DocumentRegistrySourceFileCache;
/*@internal*/
mTime?: number;
constructor(
private readonly host: ServerHost,
readonly fileName: NormalizedPath,
+74 -24
View File
@@ -336,16 +336,23 @@ namespace ts.server {
function combineProjectOutputForReferences(projects: Projects, defaultProject: Project, initialLocation: sourcemaps.SourceMappableLocation, projectService: ProjectService): ReadonlyArray<ReferencedSymbol> {
const outputs: ReferencedSymbol[] = [];
combineProjectOutputWorker<sourcemaps.SourceMappableLocation>(projects, defaultProject, initialLocation, projectService, ({ project, location }, tryAddToTodo) => {
combineProjectOutputWorker<sourcemaps.SourceMappableLocation>(projects, defaultProject, initialLocation, projectService, ({ project, location }, getMappedLocation) => {
for (const outputReferencedSymbol of project.getLanguageService().findReferences(location.fileName, location.position) || emptyArray) {
let symbolToAddTo = find(outputs, o => documentSpansEqual(o.definition, outputReferencedSymbol.definition));
const mappedDefinitionFile = getMappedLocation(project, documentSpanLocation(outputReferencedSymbol.definition));
const definition: ReferencedSymbolDefinitionInfo = mappedDefinitionFile === undefined ? outputReferencedSymbol.definition : {
...outputReferencedSymbol.definition,
textSpan: createTextSpan(mappedDefinitionFile.position, outputReferencedSymbol.definition.textSpan.length),
fileName: mappedDefinitionFile.fileName,
};
let symbolToAddTo = find(outputs, o => documentSpansEqual(o.definition, definition));
if (!symbolToAddTo) {
symbolToAddTo = { definition: outputReferencedSymbol.definition, references: [] };
symbolToAddTo = { definition, references: [] };
outputs.push(symbolToAddTo);
}
for (const ref of outputReferencedSymbol.references) {
if (!contains(symbolToAddTo.references, ref, documentSpansEqual) && !tryAddToTodo(project, documentSpanLocation(ref))) {
// If it's in a mapped file, that is added to the todo list by `getMappedLocation`.
if (!contains(symbolToAddTo.references, ref, documentSpansEqual) && !getMappedLocation(project, documentSpanLocation(ref))) {
symbolToAddTo.references.push(ref);
}
}
@@ -373,12 +380,17 @@ namespace ts.server {
}
}
type CombineProjectOutputCallback<TLocation extends sourcemaps.SourceMappableLocation | undefined> = (
where: ProjectAndLocation<TLocation>,
getMappedLocation: (project: Project, location: sourcemaps.SourceMappableLocation) => sourcemaps.SourceMappableLocation | undefined,
) => void;
function combineProjectOutputWorker<TLocation extends sourcemaps.SourceMappableLocation | undefined>(
projects: Projects,
defaultProject: Project,
initialLocation: TLocation,
projectService: ProjectService,
cb: (where: ProjectAndLocation<TLocation>, getMappedLocation: (project: Project, location: sourcemaps.SourceMappableLocation) => boolean) => void,
cb: CombineProjectOutputCallback<TLocation>,
getDefinition: (() => sourcemaps.SourceMappableLocation | undefined) | undefined,
): void {
let toDo: ProjectAndLocation<TLocation>[] | undefined;
@@ -417,13 +429,13 @@ namespace ts.server {
projectService: ProjectService,
toDo: ProjectAndLocation<TLocation>[] | undefined,
seenProjects: Map<true>,
cb: (where: ProjectAndLocation<TLocation>, getMappedLocation: (project: Project, location: sourcemaps.SourceMappableLocation) => boolean) => void,
cb: CombineProjectOutputCallback<TLocation>,
): ProjectAndLocation<TLocation>[] | undefined {
if (projectAndLocation.project.getCancellationToken().isCancellationRequested()) return undefined; // Skip rest of toDo if cancelled
cb(projectAndLocation, (project, location) => {
seenProjects.set(projectAndLocation.project.projectName, true);
const originalLocation = projectService.getOriginalLocationEnsuringConfiguredProject(project, location);
if (!originalLocation) return false;
if (!originalLocation) return undefined;
const originalScriptInfo = projectService.getScriptInfo(originalLocation.fileName)!;
toDo = toDo || [];
@@ -437,7 +449,7 @@ namespace ts.server {
for (const symlinkedProject of symlinkedProjects) addToTodo({ project: symlinkedProject, location: originalLocation as TLocation }, toDo!, seenProjects);
});
}
return true;
return originalLocation;
});
return toDo;
}
@@ -478,6 +490,7 @@ namespace ts.server {
globalPlugins?: ReadonlyArray<string>;
pluginProbeLocations?: ReadonlyArray<string>;
allowLocalPluginLoads?: boolean;
typesMapLocation?: string;
}
export class Session implements EventSender {
@@ -538,6 +551,7 @@ namespace ts.server {
globalPlugins: opts.globalPlugins,
pluginProbeLocations: opts.pluginProbeLocations,
allowLocalPluginLoads: opts.allowLocalPluginLoads,
typesMapLocation: opts.typesMapLocation,
syntaxOnly: opts.syntaxOnly,
};
this.projectService = new ProjectService(settings);
@@ -554,9 +568,19 @@ namespace ts.server {
const { openFiles } = event.data;
this.projectsUpdatedInBackgroundEvent(openFiles);
break;
case ProjectLoadingStartEvent:
const { project, reason } = event.data;
this.event<protocol.ProjectLoadingStartEventBody>(
{ projectName: project.getProjectName(), reason },
ProjectLoadingStartEvent);
break;
case ProjectLoadingFinishEvent:
const { project: finishProject } = event.data;
this.event<protocol.ProjectLoadingFinishEventBody>({ projectName: finishProject.getProjectName() }, ProjectLoadingStartEvent);
break;
case LargeFileReferencedEvent:
const { file, fileSize, maxFileSize } = event.data;
this.event<protocol.LargeFileReferencedEventBody>({ file, fileSize, maxFileSize }, "largeFileReferenced");
this.event<protocol.LargeFileReferencedEventBody>({ file, fileSize, maxFileSize }, LargeFileReferencedEvent);
break;
case ConfigFileDiagEvent:
const { triggerFile, configFileName: configFile, diagnostics } = event.data;
@@ -565,14 +589,14 @@ namespace ts.server {
triggerFile,
configFile,
diagnostics: bakedDiags
}, "configFileDiag");
}, ConfigFileDiagEvent);
break;
case SurveyReady:
const { surveyId } = event.data;
this.event<protocol.SurveyReadyEventBody>({ surveyId }, "surveyReady");
this.event<protocol.SurveyReadyEventBody>({ surveyId }, SurveyReady);
break;
case ProjectLanguageServiceStateEvent: {
const eventName: protocol.ProjectLanguageServiceStateEventName = "projectLanguageServiceState";
const eventName: protocol.ProjectLanguageServiceStateEventName = ProjectLanguageServiceStateEvent;
this.event<protocol.ProjectLanguageServiceStateEventBody>({
projectName: event.data.project.getProjectName(),
languageServiceEnabled: event.data.languageServiceEnabled
@@ -603,11 +627,15 @@ namespace ts.server {
// Send project changed event
this.event<protocol.ProjectsUpdatedInBackgroundEventBody>({
openFiles
}, "projectsUpdatedInBackground");
}, ProjectsUpdatedInBackgroundEvent);
}
}
public logError(err: Error, cmd: string) {
public logError(err: Error, cmd: string): void {
this.logErrorWorker(err, cmd);
}
private logErrorWorker(err: Error, cmd: string, fileRequest?: protocol.FileRequestArgs): void {
let msg = "Exception on executing command " + cmd;
if (err.message) {
msg += ":\n" + indent(err.message);
@@ -615,6 +643,19 @@ namespace ts.server {
msg += "\n" + indent((<StackTraceError>err).stack!);
}
}
if (fileRequest && this.logger.hasLevel(LogLevel.verbose)) {
try {
const { file, project } = this.getFileAndProject(fileRequest);
const scriptInfo = project.getScriptInfoForNormalizedPath(file);
if (scriptInfo) {
const text = getSnapshotText(scriptInfo.getSnapshot());
msg += `\n\nFile text of ${fileRequest.file}:${indent(text)}\n`;
}
}
catch {} // tslint:disable-line no-empty
}
this.logger.msg(msg, Msg.Err);
}
@@ -1096,7 +1137,7 @@ namespace ts.server {
return projectInfo;
}
private getRenameInfo(args: protocol.FileLocationRequestArgs) {
private getRenameInfo(args: protocol.FileLocationRequestArgs): RenameInfo {
const { file, project } = this.getFileAndProject(args);
const position = this.getPositionInFile(args, file);
return project.getLanguageService().getRenameInfo(file, position);
@@ -1149,21 +1190,28 @@ namespace ts.server {
if (!simplifiedResult) return locations;
const defaultProject = this.getDefaultProject(args);
const renameInfo = Session.mapRenameInfo(defaultProject.getLanguageService().getRenameInfo(file, position));
const renameInfo: protocol.RenameInfo = this.mapRenameInfo(defaultProject.getLanguageService().getRenameInfo(file, position), Debug.assertDefined(this.projectService.getScriptInfo(file)));
return { info: renameInfo, locs: this.toSpanGroups(locations) };
}
// strips 'triggerSpan'
private static mapRenameInfo({ canRename, localizedErrorMessage, displayName, fullDisplayName, kind, kindModifiers }: RenameInfo): protocol.RenameInfo {
return { canRename, localizedErrorMessage, displayName, fullDisplayName, kind, kindModifiers };
private mapRenameInfo(info: RenameInfo, scriptInfo: ScriptInfo): protocol.RenameInfo {
if (info.canRename) {
const { canRename, fileToRename, displayName, fullDisplayName, kind, kindModifiers, triggerSpan } = info;
return identity<protocol.RenameInfoSuccess>(
{ canRename, fileToRename, displayName, fullDisplayName, kind, kindModifiers, triggerSpan: this.toLocationTextSpan(triggerSpan, scriptInfo) });
}
else {
return info;
}
}
private toSpanGroups(locations: ReadonlyArray<RenameLocation>): ReadonlyArray<protocol.SpanGroup> {
const map = createMap<protocol.SpanGroup>();
for (const { fileName, textSpan } of locations) {
for (const { fileName, textSpan, originalTextSpan: _, originalFileName: _1, ...prefixSuffixText } of locations) {
let group = map.get(fileName);
if (!group) map.set(fileName, group = { file: fileName, locs: [] });
group.locs.push(this.toLocationTextSpan(textSpan, Debug.assertDefined(this.projectService.getScriptInfo(fileName))));
const scriptInfo = Debug.assertDefined(this.projectService.getScriptInfo(fileName));
group.locs.push({ ...this.toLocationTextSpan(textSpan, scriptInfo), ...prefixSuffixText });
}
return arrayFrom(map.values());
}
@@ -1818,8 +1866,8 @@ namespace ts.server {
private applyCodeActionCommand(args: protocol.ApplyCodeActionCommandRequestArgs): {} {
const commands = args.command as CodeActionCommand | CodeActionCommand[]; // They should be sending back the command we sent them.
for (const command of toArray(commands)) {
const { project } = this.getFileAndProject(command);
project.getLanguageService().applyCodeActionCommand(command).then(
const { file, project } = this.getFileAndProject(command);
project.getLanguageService().applyCodeActionCommand(command, this.getFormatOptions(file)).then(
_result => { /* TODO: GH#20447 report success message? */ },
_error => { /* TODO: GH#20447 report errors */ });
}
@@ -2310,8 +2358,10 @@ namespace ts.server {
}
let request: protocol.Request | undefined;
let relevantFile: protocol.FileRequestArgs | undefined;
try {
request = <protocol.Request>JSON.parse(message);
relevantFile = request.arguments && (request as protocol.FileRequest).arguments.file ? (request as protocol.FileRequest).arguments : undefined;
const { response, responseRequired } = this.executeCommand(request);
if (this.logger.hasLevel(LogLevel.requestTime)) {
@@ -2337,7 +2387,7 @@ namespace ts.server {
this.doOutput({ canceled: true }, request!.command, request!.seq, /*success*/ true);
return;
}
this.logError(err, message);
this.logErrorWorker(err, message, relevantFile);
this.doOutput(
/*info*/ undefined,
request ? request.command : CommandNames.Unknown,
+7
View File
@@ -8,6 +8,8 @@ namespace ts.server {
export interface ITypingsInstaller {
isKnownTypesPackageName(name: string): boolean;
installPackage(options: InstallPackageOptionsWithProject): Promise<ApplyCodeActionCommandResult>;
/* @internal */
inspectValue(options: InspectValueOptions): Promise<ValueInfo>;
enqueueInstallTypingsRequest(p: Project, typeAcquisition: TypeAcquisition, unresolvedImports: SortedReadonlyArray<string> | undefined): void;
attach(projectService: ProjectService): void;
onProjectClosed(p: Project): void;
@@ -18,6 +20,7 @@ namespace ts.server {
isKnownTypesPackageName: returnFalse,
// Should never be called because we never provide a types registry.
installPackage: notImplemented,
inspectValue: notImplemented,
enqueueInstallTypingsRequest: noop,
attach: noop,
onProjectClosed: noop,
@@ -95,6 +98,10 @@ namespace ts.server {
return this.installer.installPackage(options);
}
inspectValue(options: InspectValueOptions): Promise<ValueInfo> {
return this.installer.inspectValue(options);
}
enqueueInstallTypingsForProject(project: Project, unresolvedImports: SortedReadonlyArray<string> | undefined, forceRefresh: boolean) {
const typeAcquisition = project.getTypeAcquisition();
+4 -2
View File
@@ -246,14 +246,16 @@ namespace ts.server {
return index === 0 || value !== array[index - 1];
}
const indentStr = "\n ";
/* @internal */
export function indent(str: string): string {
return "\n " + str;
return indentStr + str.replace(/\n/g, indentStr);
}
/** Put stringified JSON on the next line, indented. */
/* @internal */
export function stringifyIndented(json: {}): string {
return "\n " + JSON.stringify(json);
return indentStr + JSON.stringify(json);
}
}
@@ -138,7 +138,7 @@ namespace ts.codefix {
default: {
// Don't try to declare members in JavaScript files
if (isSourceFileJavaScript(sourceFile)) {
if (isSourceFileJS(sourceFile)) {
return;
}
const prop = createProperty(/*decorators*/ undefined, modifiers, memberDeclaration.name, /*questionToken*/ undefined,
+174 -131
View File
@@ -2,42 +2,37 @@
namespace ts.codefix {
const fixId = "convertToAsyncFunction";
const errorCodes = [Diagnostics.This_may_be_converted_to_an_async_function.code];
let codeActionSucceeded = true;
registerCodeFix({
errorCodes,
getCodeActions(context: CodeFixContext) {
codeActionSucceeded = true;
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)];
return codeActionSucceeded ? [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;
readonly identifier: Identifier;
readonly types: Type[];
numberOfAssignmentsOriginal: number; // number of times the variable should be assigned in the refactor
}
interface SymbolAndIdentifier {
identifier: Identifier;
symbol: Symbol;
readonly identifier: Identifier;
readonly 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;
readonly checker: TypeChecker;
readonly synthNamesMap: Map<SynthIdentifier>; // keys are the symbol id of the identifier
readonly allVarNames: ReadonlyArray<SymbolAndIdentifier>;
readonly setOfExpressionsToReturn: ReadonlyMap<true>; // keys are the node ids of the expressions
readonly constIdentifiers: Identifier[];
readonly originalTypeMap: ReadonlyMap<Type>; // keys are the node id of the identifier
readonly isInJSFile: boolean;
}
function convertToAsyncFunction(changes: textChanges.ChangeTracker, sourceFile: SourceFile, position: number, checker: TypeChecker, context: CodeFixContextBase): void {
@@ -61,19 +56,19 @@ namespace ts.codefix {
const synthNamesMap: Map<SynthIdentifier> = createMap();
const originalTypeMap: Map<Type> = createMap();
const allVarNames: SymbolAndIdentifier[] = [];
const isInJSFile = isInJavaScriptFile(functionToConvert);
const isInJavascript = isInJSFile(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 };
const transformer: Transformer = { checker, synthNamesMap, allVarNames, setOfExpressionsToReturn, constIdentifiers, originalTypeMap, isInJSFile: isInJavascript };
if (!returnStatements.length) {
return;
}
// add the async keyword
changes.insertModifierBefore(sourceFile, SyntaxKind.AsyncKeyword, functionToConvert);
changes.insertLastModifierBefore(sourceFile, SyntaxKind.AsyncKeyword, functionToConvert);
function startTransformation(node: CallExpression, nodeToReplace: Node) {
const newNodes = transformExpression(node, transformer, node);
@@ -81,24 +76,19 @@ namespace ts.codefix {
}
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);
}
});
}
forEachChild(statement, function visit(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[] {
function getConstIdentifiers(synthNamesMap: ReadonlyMap<SynthIdentifier>): Identifier[] {
const constIdentifiers: Identifier[] = [];
synthNamesMap.forEach((val) => {
if (val.numberOfAssignmentsOriginal === 0) {
@@ -165,6 +155,7 @@ namespace ts.codefix {
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
const collidingSymbolMap: Map<Symbol[]> = createMap();
forEachChild(nodeToRename, function visit(node: Node) {
if (!isIdentifier(node)) {
forEachChild(node, visit);
@@ -181,20 +172,26 @@ namespace ts.codefix {
// 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);
if (lastCallSignature && !isFunctionLikeDeclaration(node.parent) && !synthNamesMap.has(symbolIdString)) {
const firstParameter = firstOrUndefined(lastCallSignature.parameters);
const ident = firstParameter && isParameter(firstParameter.valueDeclaration) && tryCast(firstParameter.valueDeclaration.name, isIdentifier) || createOptimisticUniqueName("result");
const synthName = getNewNameIfConflict(ident, collidingSymbolMap);
synthNamesMap.set(symbolIdString, synthName);
allVarNames.push({ identifier: synthName.identifier, symbol });
addNameToFrequencyMap(collidingSymbolMap, ident.text, 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))) {
const originalName = node.text;
const collidingSymbols = collidingSymbolMap.get(originalName);
// 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);
if (collidingSymbols && collidingSymbols.some(prevSymbol => prevSymbol !== symbol)) {
const newName = getNewNameIfConflict(node, collidingSymbolMap);
identsToRenameMap.set(symbolIdString, newName.identifier);
synthNamesMap.set(symbolIdString, newName);
allVarNames.push({ identifier: newName.identifier, symbol });
addNameToFrequencyMap(collidingSymbolMap, originalName, symbol);
}
else {
const identifier = getSynthesizedDeepClone(node);
@@ -202,6 +199,7 @@ namespace ts.codefix {
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 });
addNameToFrequencyMap(collidingSymbolMap, originalName, symbol);
}
}
}
@@ -229,9 +227,7 @@ namespace ts.codefix {
if (renameInfo) {
const type = checker.getTypeAtLocation(node);
if (type) {
originalType.set(getNodeId(clone).toString(), type);
}
originalType.set(getNodeId(clone).toString(), type);
}
}
@@ -244,17 +240,27 @@ namespace ts.codefix {
}
function getNewNameIfConflict(name: Identifier, allVarNames: SymbolAndIdentifier[]): SynthIdentifier {
const numVarsSameName = allVarNames.filter(elem => elem.identifier.text === name.text).length;
function addNameToFrequencyMap(renamedVarNameFrequencyMap: Map<Symbol[]>, originalName: string, symbol: Symbol) {
if (renamedVarNameFrequencyMap.has(originalName)) {
renamedVarNameFrequencyMap.get(originalName)!.push(symbol);
}
else {
renamedVarNameFrequencyMap.set(originalName, [symbol]);
}
}
function getNewNameIfConflict(name: Identifier, originalNames: ReadonlyMap<Symbol[]>): SynthIdentifier {
const numVarsSameName = (originalNames.get(name.text) || emptyArray).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[] {
// should be kept up to date with isFixablePromiseHandler in suggestionDiagnostics.ts
function transformExpression(node: Expression, transformer: Transformer, outermostParent: CallExpression, prevArgName?: SynthIdentifier): ReadonlyArray<Statement> {
if (!node) {
return [];
return emptyArray;
}
const originalType = isIdentifier(node) && transformer.originalTypeMap.get(getNodeId(node).toString());
@@ -273,10 +279,11 @@ namespace ts.codefix {
return transformPromiseCall(node, transformer, prevArgName);
}
return [];
codeActionSucceeded = false;
return emptyArray;
}
function transformCatch(node: CallExpression, transformer: Transformer, prevArgName?: SynthIdentifier): Statement[] {
function transformCatch(node: CallExpression, transformer: Transformer, prevArgName?: SynthIdentifier): ReadonlyArray<Statement> {
const func = node.arguments[0];
const argName = getArgName(func, transformer);
const shouldReturn = transformer.setOfExpressionsToReturn.get(getNodeId(node).toString());
@@ -290,20 +297,21 @@ namespace ts.codefix {
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));
const newSynthName = createUniqueSynthName(prevArgName);
transformer.synthNamesMap.set(key, newSynthName);
}
});
// update the constIdentifiers list
if (transformer.constIdentifiers.some(elem => elem.text === prevArgName.identifier.text)) {
transformer.constIdentifiers.push(getNewNameIfConflict(prevArgName.identifier, transformer.allVarNames).identifier);
transformer.constIdentifiers.push(createUniqueSynthName(prevArgName).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 catchArg = argName ? argName.identifier.text : "e";
const catchClause = createCatchClause(catchArg, createBlock(transformationBody));
/*
@@ -322,7 +330,13 @@ namespace ts.codefix {
return varDeclList ? [varDeclList, tryStatement] : [tryStatement];
}
function transformThen(node: CallExpression, transformer: Transformer, outermostParent: CallExpression, prevArgName?: SynthIdentifier): Statement[] {
function createUniqueSynthName(prevArgName: SynthIdentifier) {
const renamedPrevArg = createOptimisticUniqueName(prevArgName.identifier.text);
const newSynthName = { identifier: renamedPrevArg, types: [], numberOfAssignmentsOriginal: 0 };
return newSynthName;
}
function transformThen(node: CallExpression, transformer: Transformer, outermostParent: CallExpression, prevArgName?: SynthIdentifier): ReadonlyArray<Statement> {
const [res, rej] = node.arguments;
if (!res) {
@@ -339,79 +353,95 @@ namespace ts.codefix {
const transformationBody2 = getTransformationBody(rej, prevArgName, argNameRej, node, transformer);
const catchArg = argNameRej.identifier.text.length > 0 ? argNameRej.identifier.text : "e";
const catchArg = argNameRej ? 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 [createTry(tryBlock, catchClause, /* finallyBlock */ undefined)];
}
return [];
return transformExpression(node.expression, transformer, node, argNameRes).concat(transformationBody);
}
function getFlagOfIdentifier(node: Identifier, constIdentifiers: Identifier[]): NodeFlags {
function getFlagOfIdentifier(node: Identifier, constIdentifiers: ReadonlyArray<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[] {
function transformPromiseCall(node: Expression, transformer: Transformer, prevArgName?: SynthIdentifier): ReadonlyArray<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
if (prevArgName && !shouldReturn && (!originalNodeParent || isPropertyAccessExpression(originalNodeParent))) {
return createTransformedStatement(prevArgName, createAwait(node), transformer);
}
else if (!hasPrevArgName && !shouldReturn && (!originalNodeParent || isPropertyAccessExpression(originalNodeParent))) {
else if (!prevArgName && !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))]);
function createTransformedStatement(prevArgName: SynthIdentifier | undefined, rightHandSide: Expression, transformer: Transformer): ReadonlyArray<Statement> {
if (!prevArgName || prevArgName.identifier.text.length === 0) {
// if there's no argName to assign to, there still might be side effects
return [createStatement(rightHandSide)];
}
return createNodeArray([createVariableStatement(/*modifiers*/ undefined,
(createVariableDeclarationList([createVariableDeclaration(getSynthesizedDeepClone(prevArgName.identifier), /*type*/ undefined, rightHandSide)], getFlagOfIdentifier(prevArgName.identifier, transformer.constIdentifiers))))]);
if (prevArgName.types.length < prevArgName.numberOfAssignmentsOriginal) {
// if the variable has already been declared, we don't need "let" or "const"
return [createStatement(createAssignment(getSynthesizedDeepClone(prevArgName.identifier), rightHandSide))];
}
return [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> {
// should be kept up to date with isFixablePromiseArgument in suggestionDiagnostics.ts
function getTransformationBody(func: Expression, prevArgName: SynthIdentifier | undefined, argName: SynthIdentifier | undefined, parent: CallExpression, transformer: Transformer): ReadonlyArray<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)]);
case SyntaxKind.NullKeyword:
// do not produce a transformed statement for a null argument
break;
case SyntaxKind.Identifier: // identifier includes undefined
if (!argName) {
// undefined was argument passed to promise handler
break;
}
if (!hasPrevArgName) break;
const synthCall = createCall(getSynthesizedDeepClone(func as Identifier), /*typeArguments*/ undefined, [argName.identifier]);
if (shouldReturn) {
return [createReturn(synthCall)];
}
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!);
const type = transformer.originalTypeMap.get(getNodeId(func).toString()) || transformer.checker.getTypeAtLocation(func);
const callSignatures = transformer.checker.getSignaturesOfType(type, SignatureKind.Call);
if (!callSignatures.length) {
// if identifier in handler has no call signatures, it's invalid
codeActionSucceeded = false;
break;
}
const returnType = callSignatures[0].getReturnType();
const varDeclOrAssignment = createTransformedStatement(prevArgName, createAwait(synthCall), transformer);
if (prevArgName) {
prevArgName.types.push(returnType);
}
return varDeclOrAssignment;
case SyntaxKind.FunctionDeclaration:
case SyntaxKind.FunctionExpression:
case SyntaxKind.ArrowFunction:
case SyntaxKind.ArrowFunction: {
const funcBody = (func as FunctionExpression | ArrowFunction).body;
// Arrow functions with block bodies { } will enter this control flow
if (isFunctionLikeDeclaration(func) && func.body && isBlock(func.body) && func.body.statements) {
if (isBlock(funcBody)) {
let refactoredStmts: Statement[] = [];
let seenReturnStatement = false;
for (const statement of funcBody.statements) {
if (isReturnStatement(statement)) {
seenReturnStatement = true;
}
for (const statement of func.body.statements) {
if (getReturnStatementsWithPromiseHandlers(statement).length) {
refactoredStmts = refactoredStmts.concat(getInnerTransformationBody(transformer, [statement], prevArgName));
}
@@ -420,47 +450,64 @@ namespace ts.codefix {
}
}
return shouldReturn ? getSynthesizedDeepClones(createNodeArray(refactoredStmts)) :
removeReturns(createNodeArray(refactoredStmts), prevArgName!.identifier, transformer.constIdentifiers);
return shouldReturn ? refactoredStmts.map(s => getSynthesizedDeepClone(s)) :
removeReturns(
refactoredStmts,
prevArgName === undefined ? undefined : prevArgName.identifier,
transformer,
seenReturnStatement);
}
else {
const funcBody = (<ArrowFunction>func).body;
const innerRetStmts = getReturnStatementsWithPromiseHandlers(createReturn(funcBody as Expression));
const innerRetStmts = getReturnStatementsWithPromiseHandlers(createReturn(funcBody));
const innerCbBody = getInnerTransformationBody(transformer, innerRetStmts, prevArgName);
if (innerCbBody.length > 0) {
return createNodeArray(innerCbBody);
return 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;
const type = transformer.checker.getTypeAtLocation(func);
const returnType = getLastCallSignature(type, transformer.checker)!.getReturnType();
const rightHandSide = getSynthesizedDeepClone(funcBody);
const possiblyAwaitedRightHandSide = !!transformer.checker.getPromisedTypeOfPromise(returnType) ? createAwait(rightHandSide) : rightHandSide;
if (!shouldReturn) {
const transformedStatement = createTransformedStatement(prevArgName, possiblyAwaitedRightHandSide, transformer);
if (prevArgName) {
prevArgName.types.push(returnType);
}
return transformedStatement;
}
else {
return createNodeArray([createReturn(getSynthesizedDeepClone(funcBody) as Expression)]);
return [createReturn(possiblyAwaitedRightHandSide)];
}
}
}
default:
// If no cases apply, we've found a transformation body we don't know how to handle, so the refactoring should no-op to avoid deleting code.
codeActionSucceeded = false;
break;
}
return createNodeArray([]);
return emptyArray;
}
function getLastCallSignature(type: Type, checker: TypeChecker): Signature {
const callSignatures = type && checker.getSignaturesOfType(type, SignatureKind.Call);
return callSignatures && callSignatures[callSignatures.length - 1];
function getLastCallSignature(type: Type, checker: TypeChecker): Signature | undefined {
const callSignatures = checker.getSignaturesOfType(type, SignatureKind.Call);
return lastOrUndefined(callSignatures);
}
function removeReturns(stmts: NodeArray<Statement>, prevArgName: Identifier, constIdentifiers: Identifier[]): NodeArray<Statement> {
function removeReturns(stmts: ReadonlyArray<Statement>, prevArgName: Identifier | undefined, transformer: Transformer, seenReturnStatement: boolean): ReadonlyArray<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)))));
const possiblyAwaitedExpression = isPromiseReturningExpression(stmt.expression, transformer.checker) ? createAwait(stmt.expression) : stmt.expression;
if (prevArgName === undefined) {
ret.push(createExpressionStatement(possiblyAwaitedExpression));
}
else {
ret.push(createVariableStatement(/*modifiers*/ undefined,
(createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, possiblyAwaitedExpression)], getFlagOfIdentifier(prevArgName, transformer.constIdentifiers)))));
}
}
}
else {
@@ -468,15 +515,21 @@ namespace ts.codefix {
}
}
return createNodeArray(ret);
// if block has no return statement, need to define prevArgName as undefined to prevent undeclared variables
if (!seenReturnStatement && prevArgName !== undefined) {
ret.push(createVariableStatement(/*modifiers*/ undefined,
(createVariableDeclarationList([createVariableDeclaration(prevArgName, /*type*/ undefined, createIdentifier("undefined"))], getFlagOfIdentifier(prevArgName, transformer.constIdentifiers)))));
}
return ret;
}
function getInnerTransformationBody(transformer: Transformer, innerRetStmts: Node[], prevArgName?: SynthIdentifier) {
function getInnerTransformationBody(transformer: Transformer, innerRetStmts: ReadonlyArray<Node>, prevArgName?: SynthIdentifier) {
let innerCbBody: Statement[] = [];
for (const stmt of innerRetStmts) {
forEachChild(stmt, function visit(node: Node) {
forEachChild(stmt, function visit(node) {
if (isCallExpression(node)) {
const temp = transformExpression(node, transformer, node, prevArgName);
innerCbBody = innerCbBody.concat(temp);
@@ -492,15 +545,7 @@ namespace ts.codefix {
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 {
function getArgName(funcNode: Expression, transformer: Transformer): SynthIdentifier | undefined {
const numberOfAssignmentsOriginal = 0;
const types: Type[] = [];
@@ -510,23 +555,21 @@ namespace ts.codefix {
if (isFunctionLikeDeclaration(funcNode)) {
if (funcNode.parameters.length > 0) {
const param = funcNode.parameters[0].name as Identifier;
name = getMapEntryIfExists(param);
name = getMapEntryOrDefault(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);
name = getMapEntryOrDefault(funcNode);
}
if (!name || name.identifier === undefined || name.identifier.text === "_" || name.identifier.text === "undefined") {
return { identifier: createIdentifier(""), types, numberOfAssignmentsOriginal };
// return undefined argName when arg is null or undefined
if (!name || name.identifier.text === "undefined") {
return undefined;
}
return name;
function getMapEntryIfExists(identifier: Identifier): SynthIdentifier {
function getMapEntryOrDefault(identifier: Identifier): SynthIdentifier {
const originalNode = getOriginalNode(identifier);
const symbol = getSymbol(originalNode);
@@ -546,4 +589,4 @@ namespace ts.codefix {
return node.original ? node.original : node;
}
}
}
}
@@ -12,7 +12,7 @@ namespace ts.codefix {
getCodeActions(context) {
const { sourceFile, program, span, host, formatContext } = context;
if (!isInJavaScriptFile(sourceFile) || !isCheckJsEnabledForFile(sourceFile, program.getCompilerOptions())) {
if (!isInJSFile(sourceFile) || !isCheckJsEnabledForFile(sourceFile, program.getCompilerOptions())) {
return undefined;
}
@@ -20,7 +20,7 @@ namespace ts.codefix {
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)) :
singleElementArray(getActionsForAddMissingMemberInJavascriptFile(context, declSourceFile, parentDeclaration, token.text, makeStatic)) :
getActionsForAddMissingMemberInTypeScriptFile(context, declSourceFile, parentDeclaration, token, makeStatic);
return concatenate(singleElementArray(methodCodeAction), addMember);
},
@@ -131,7 +131,7 @@ namespace ts.codefix {
if (classOrInterface) {
const makeStatic = ((leftExpressionType as TypeReference).target || leftExpressionType) !== checker.getDeclaredTypeOfSymbol(symbol);
const declSourceFile = classOrInterface.getSourceFile();
const inJs = isSourceFileJavaScript(declSourceFile);
const inJs = isSourceFileJS(declSourceFile);
const call = tryCast(parent.parent, isCallExpression);
return { kind: InfoKind.ClassOrInterface, token, parentDeclaration: classOrInterface, makeStatic, declSourceFile, inJs, call };
}
@@ -142,7 +142,7 @@ namespace ts.codefix {
return undefined;
}
function getActionsForAddMissingMemberInJavaScriptFile(context: CodeFixContext, declSourceFile: SourceFile, classDeclaration: ClassLikeDeclaration, tokenName: string, makeStatic: boolean): CodeFixAction | undefined {
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);
+132 -14
View File
@@ -1,6 +1,9 @@
/* @internal */
namespace ts.codefix {
const fixId = "fixCannotFindModule";
const fixName = "fixCannotFindModule";
const fixIdInstallTypesPackage = "installTypesPackage";
const fixIdGenerateTypes = "generateTypes";
const errorCodeCannotFindModule = Diagnostics.Cannot_find_module_0.code;
const errorCodes = [
errorCodeCannotFindModule,
@@ -10,26 +13,141 @@ namespace ts.codefix {
errorCodes,
getCodeActions: context => {
const { host, sourceFile, span: { start } } = context;
const packageName = getTypesPackageNameToInstall(host, sourceFile, start, context.errorCode);
return packageName === undefined ? []
: [createCodeFixAction(fixId, /*changes*/ [], [Diagnostics.Install_0, packageName], fixId, Diagnostics.Install_all_missing_types_packages, getCommand(sourceFile.fileName, packageName))];
const packageName = tryGetImportedPackageName(sourceFile, start);
if (packageName === undefined) return undefined;
const typesPackageName = getTypesPackageNameToInstall(packageName, host, context.errorCode);
return typesPackageName === undefined
? singleElementArray(tryGetGenerateTypesAction(context, packageName))
: [createCodeFixAction(fixName, /*changes*/ [], [Diagnostics.Install_0, typesPackageName], fixIdInstallTypesPackage, Diagnostics.Install_all_missing_types_packages, getInstallCommand(sourceFile.fileName, typesPackageName))];
},
fixIds: [fixIdInstallTypesPackage, fixIdGenerateTypes],
getAllCodeActions: context => {
let savedTypesDir: string | null | undefined = null; // tslint:disable-line no-null-keyword
return codeFixAll(context, errorCodes, (changes, diag, commands) => {
const packageName = tryGetImportedPackageName(diag.file, diag.start);
if (packageName === undefined) return undefined;
switch (context.fixId) {
case fixIdInstallTypesPackage: {
const pkg = getTypesPackageNameToInstall(packageName, context.host, diag.code);
if (pkg) {
commands.push(getInstallCommand(diag.file.fileName, pkg));
}
break;
}
case fixIdGenerateTypes: {
const typesDir = savedTypesDir !== null ? savedTypesDir : savedTypesDir = getOrCreateTypesDirectory(changes, context);
const command = typesDir === undefined ? undefined : tryGenerateTypes(typesDir, packageName, context);
if (command) commands.push(command);
break;
}
default:
Debug.fail(`Bad fixId: ${context.fixId}`);
}
});
},
fixIds: [fixId],
getAllCodeActions: context => codeFixAll(context, errorCodes, (_, diag, commands) => {
const pkg = getTypesPackageNameToInstall(context.host, diag.file, diag.start, diag.code);
if (pkg) {
commands.push(getCommand(diag.file.fileName, pkg));
}
}),
});
function getCommand(fileName: string, packageName: string): InstallPackageAction {
function tryGetGenerateTypesAction(context: CodeFixContextBase, packageName: string): CodeFixAction | undefined {
let command: GenerateTypesAction | undefined;
const changes = textChanges.ChangeTracker.with(context, t => {
const typesDir = getOrCreateTypesDirectory(t, context);
command = typesDir === undefined ? undefined : tryGenerateTypes(typesDir, packageName, context);
});
return command && createCodeFixAction(fixName, changes, [Diagnostics.Generate_types_for_0, packageName], fixIdGenerateTypes, Diagnostics.Generate_types_for_all_packages_without_types, command);
}
function tryGenerateTypes(typesDir: string, packageName: string, context: CodeFixContextBase): GenerateTypesAction | undefined {
const file = context.sourceFile.fileName;
const fileToGenerateTypesFor = tryResolveJSModule(packageName, getDirectoryPath(file), context.host as ModuleResolutionHost); // TODO: GH#18217
if (fileToGenerateTypesFor === undefined) return undefined;
const outputFileName = resolvePath(getDirectoryPath(context.program.getCompilerOptions().configFile!.fileName), typesDir, packageName + ".d.ts");
if (context.host.fileExists!(outputFileName)) return undefined;
return { type: "generate types", file, fileToGenerateTypesFor, outputFileName };
}
// If no types directory exists yet, adds it to tsconfig.json
function getOrCreateTypesDirectory(changes: textChanges.ChangeTracker, context: CodeFixContextBase): string | undefined {
const { configFile } = context.program.getCompilerOptions();
if (!configFile) return undefined;
const tsconfigObjectLiteral = getTsConfigObjectLiteralExpression(configFile);
if (!tsconfigObjectLiteral) return undefined;
const compilerOptionsProperty = findProperty(tsconfigObjectLiteral, "compilerOptions");
if (!compilerOptionsProperty) {
const newCompilerOptions = createObjectLiteral([makeDefaultBaseUrl(), makeDefaultPaths()]);
changes.insertNodeAtObjectStart(configFile, tsconfigObjectLiteral, createJsonPropertyAssignment("compilerOptions", newCompilerOptions));
return defaultTypesDirectoryName;
}
const compilerOptions = compilerOptionsProperty.initializer;
if (!isObjectLiteralExpression(compilerOptions)) return defaultTypesDirectoryName;
const baseUrl = getOrAddBaseUrl(changes, configFile, compilerOptions);
const typesDirectoryFromPathMapping = getOrAddPathMapping(changes, configFile, compilerOptions);
return combinePaths(baseUrl, typesDirectoryFromPathMapping);
}
const defaultBaseUrl = ".";
function makeDefaultBaseUrl(): PropertyAssignment {
return createJsonPropertyAssignment("baseUrl", createStringLiteral(defaultBaseUrl));
}
function getOrAddBaseUrl(changes: textChanges.ChangeTracker, tsconfig: TsConfigSourceFile, compilerOptions: ObjectLiteralExpression): string {
const baseUrlProp = findProperty(compilerOptions, "baseUrl");
if (baseUrlProp) {
return isStringLiteral(baseUrlProp.initializer) ? baseUrlProp.initializer.text : defaultBaseUrl;
}
else {
changes.insertNodeAtObjectStart(tsconfig, compilerOptions, makeDefaultBaseUrl());
return defaultBaseUrl;
}
}
const defaultTypesDirectoryName = "types";
function makeDefaultPathMapping(): PropertyAssignment {
return createJsonPropertyAssignment("*", createArrayLiteral([createStringLiteral(`${defaultTypesDirectoryName}/*`)]));
}
function makeDefaultPaths(): PropertyAssignment {
return createJsonPropertyAssignment("paths", createObjectLiteral([makeDefaultPathMapping()]));
}
function getOrAddPathMapping(changes: textChanges.ChangeTracker, tsconfig: TsConfigSourceFile, compilerOptions: ObjectLiteralExpression) {
const paths = findProperty(compilerOptions, "paths");
if (!paths || !isObjectLiteralExpression(paths.initializer)) {
changes.insertNodeAtObjectStart(tsconfig, compilerOptions, makeDefaultPaths());
return defaultTypesDirectoryName;
}
// Look for an existing path mapping. Should look like `"*": "foo/*"`.
const existing = firstDefined(paths.initializer.properties, prop =>
isPropertyAssignment(prop) && isStringLiteral(prop.name) && prop.name.text === "*" && isArrayLiteralExpression(prop.initializer)
? firstDefined(prop.initializer.elements, value => isStringLiteral(value) ? tryRemoveSuffix(value.text, "/*") : undefined)
: undefined);
if (existing) return existing;
changes.insertNodeAtObjectStart(tsconfig, paths.initializer, makeDefaultPathMapping());
return defaultTypesDirectoryName;
}
function createJsonPropertyAssignment(name: string, initializer: Expression) {
return createPropertyAssignment(createStringLiteral(name), initializer);
}
function findProperty(obj: ObjectLiteralExpression, name: string): PropertyAssignment | undefined {
return find(obj.properties, (p): p is PropertyAssignment => isPropertyAssignment(p) && !!p.name && isStringLiteral(p.name) && p.name.text === name);
}
function getInstallCommand(fileName: string, packageName: string): InstallPackageAction {
return { type: "install package", file: fileName, packageName };
}
function getTypesPackageNameToInstall(host: LanguageServiceHost, sourceFile: SourceFile, pos: number, diagCode: number): string | undefined {
function tryGetImportedPackageName(sourceFile: SourceFile, pos: number): string | undefined {
const moduleName = cast(getTokenAtPosition(sourceFile, pos), isStringLiteral).text;
const { packageName } = getPackageName(moduleName);
const { packageName } = parsePackageName(moduleName);
return isExternalModuleNameRelative(packageName) ? undefined : packageName;
}
function getTypesPackageNameToInstall(packageName: string, host: LanguageServiceHost, diagCode: number): string | undefined {
return diagCode === errorCodeCannotFindModule
? (JsTyping.nodeCoreModules.has(packageName) ? "@types/node" : undefined)
: (host.isKnownTypesPackageName!(packageName) ? getTypesPackageName(packageName) : undefined); // TODO: GH#18217
@@ -110,7 +110,7 @@ namespace ts.codefix {
function getDefaultValueFromType (checker: TypeChecker, type: Type): Expression | undefined {
if (type.flags & TypeFlags.BooleanLiteral) {
return type === checker.getFalseType() ? createFalse() : createTrue();
return (type === checker.getFalseType() || type === checker.getFalseType(/*fresh*/ true)) ? createFalse() : createTrue();
}
else if (type.isLiteral()) {
return createLiteral(type.value);
+227
View File
@@ -0,0 +1,227 @@
/* @internal */
namespace ts {
export function generateTypesForModule(name: string, moduleValue: unknown, formatSettings: FormatCodeSettings): string {
return valueInfoToDeclarationFileText(inspectValue(name, moduleValue), formatSettings);
}
export function valueInfoToDeclarationFileText(valueInfo: ValueInfo, formatSettings: FormatCodeSettings): string {
return textChanges.getNewFileText(toStatements(valueInfo, OutputKind.ExportEquals), ScriptKind.TS, "\n", formatting.getFormatContext(formatSettings));
}
const enum OutputKind { ExportEquals, NamedExport, NamespaceMember }
function toNamespaceMemberStatements(info: ValueInfo): ReadonlyArray<Statement> {
return toStatements(info, OutputKind.NamespaceMember);
}
function toStatements(info: ValueInfo, kind: OutputKind): ReadonlyArray<Statement> {
const isDefault = info.name === InternalSymbolName.Default;
const name = isDefault ? "_default" : info.name;
if (!isValidIdentifier(name) || isDefault && kind !== OutputKind.NamedExport) return emptyArray;
const modifiers = isDefault && info.kind === ValueKind.FunctionOrClass ? [createModifier(SyntaxKind.ExportKeyword), createModifier(SyntaxKind.DefaultKeyword)]
: kind === OutputKind.ExportEquals ? [createModifier(SyntaxKind.DeclareKeyword)]
: kind === OutputKind.NamedExport ? [createModifier(SyntaxKind.ExportKeyword)]
: undefined;
const exportEquals = () => kind === OutputKind.ExportEquals ? [exportEqualsOrDefault(info.name, /*isExportEquals*/ true)] : emptyArray;
const exportDefault = () => isDefault ? [exportEqualsOrDefault("_default", /*isExportEquals*/ false)] : emptyArray;
switch (info.kind) {
case ValueKind.FunctionOrClass:
return [...exportEquals(), ...functionOrClassToStatements(modifiers, name, info)];
case ValueKind.Object:
const { members } = info;
if (kind === OutputKind.ExportEquals) {
return flatMap(members, v => toStatements(v, OutputKind.NamedExport));
}
if (members.some(m => m.kind === ValueKind.FunctionOrClass)) {
// If some member is a function, use a namespace so it gets a FunctionDeclaration or ClassDeclaration.
return [...exportDefault(), createNamespace(modifiers, name, flatMap(members, toNamespaceMemberStatements))];
}
// falls through
case ValueKind.Const:
case ValueKind.Array: {
const comment = info.kind === ValueKind.Const ? info.comment : undefined;
const constVar = createVariableStatement(modifiers, createVariableDeclarationList([createVariableDeclaration(name, toType(info))], NodeFlags.Const));
return [...exportEquals(), ...exportDefault(), addComment(constVar, comment)];
}
default:
return Debug.assertNever(info);
}
}
function exportEqualsOrDefault(name: string, isExportEquals: boolean): ExportAssignment {
return createExportAssignment(/*decorators*/ undefined, /*modifiers*/ undefined, isExportEquals, createIdentifier(name));
}
function functionOrClassToStatements(modifiers: Modifiers, name: string, { source, prototypeMembers, namespaceMembers }: ValueInfoFunctionOrClass): ReadonlyArray<Statement> {
const fnAst = parseClassOrFunctionBody(source);
const { parameters, returnType } = fnAst === undefined ? { parameters: emptyArray, returnType: anyType() } : getParametersAndReturnType(fnAst);
const instanceProperties = typeof fnAst === "object" ? getConstructorFunctionInstanceProperties(fnAst) : emptyArray;
const classStaticMembers: ClassElement[] | undefined =
instanceProperties.length !== 0 || prototypeMembers.length !== 0 || fnAst === undefined || typeof fnAst !== "number" && fnAst.kind === SyntaxKind.Constructor ? [] : undefined;
const namespaceStatements = flatMap(namespaceMembers, info => {
if (!isValidIdentifier(info.name)) return undefined;
if (classStaticMembers) {
switch (info.kind) {
case ValueKind.Object:
if (info.members.some(m => m.kind === ValueKind.FunctionOrClass)) {
break;
}
// falls through
case ValueKind.Array:
case ValueKind.Const:
classStaticMembers.push(
addComment(
createProperty(/*decorators*/ undefined, [createModifier(SyntaxKind.StaticKeyword)], info.name, /*questionOrExclamationToken*/ undefined, toType(info), /*initializer*/ undefined),
info.kind === ValueKind.Const ? info.comment : undefined));
return undefined;
case ValueKind.FunctionOrClass:
if (!info.namespaceMembers.length) { // Else, can't merge a static method with a namespace. Must make it a function on the namespace.
const sig = tryGetMethod(info, [createModifier(SyntaxKind.StaticKeyword)]);
if (sig) {
classStaticMembers.push(sig);
return undefined;
}
}
}
}
return toStatements(info, OutputKind.NamespaceMember);
});
const decl = classStaticMembers
? createClassDeclaration(
/*decorators*/ undefined,
modifiers,
name,
/*typeParameters*/ undefined,
/*heritageClauses*/ undefined,
[
...classStaticMembers,
...(parameters.length ? [createConstructor(/*decorators*/ undefined, /*modifiers*/ undefined, parameters, /*body*/ undefined)] : emptyArray),
...instanceProperties,
// ignore non-functions on the prototype
...mapDefined(prototypeMembers, info => info.kind === ValueKind.FunctionOrClass ? tryGetMethod(info) : undefined),
])
: createFunctionDeclaration(/*decorators*/ undefined, modifiers, /*asteriskToken*/ undefined, name, /*typeParameters*/ undefined, parameters, returnType, /*body*/ undefined);
return [decl, ...(namespaceStatements.length === 0 ? emptyArray : [createNamespace(modifiers && modifiers.map(m => getSynthesizedDeepClone(m)), name, namespaceStatements)])];
}
function tryGetMethod({ name, source }: ValueInfoFunctionOrClass, modifiers?: Modifiers): MethodDeclaration | undefined {
if (!isValidIdentifier(name)) return undefined;
const fnAst = parseClassOrFunctionBody(source);
if (fnAst === undefined || (typeof fnAst !== "number" && fnAst.kind === SyntaxKind.Constructor)) return undefined;
const sig = getParametersAndReturnType(fnAst);
return sig && createMethod(
/*decorators*/ undefined,
modifiers,
/*asteriskToken*/ undefined,
name,
/*questionToken*/ undefined,
/*typeParameters*/ undefined,
sig.parameters,
sig.returnType,
/*body*/ undefined);
}
function toType(info: ValueInfo): TypeNode {
switch (info.kind) {
case ValueKind.Const:
return createTypeReferenceNode(info.typeName, /*typeArguments*/ undefined);
case ValueKind.Array:
return createArrayTypeNode(toType(info.inner));
case ValueKind.FunctionOrClass:
return createTypeReferenceNode("Function", /*typeArguments*/ undefined); // Normally we create a FunctionDeclaration, but this can happen for a function in an array.
case ValueKind.Object:
return createTypeLiteralNode(info.members.map(m => createPropertySignature(/*modifiers*/ undefined, m.name, /*questionToken*/ undefined, toType(m), /*initializer*/ undefined)));
default:
return Debug.assertNever(info);
}
}
// Parses assignments to "this.x" in the constructor into class property declarations
function getConstructorFunctionInstanceProperties(fnAst: FunctionOrConstructorNode): ReadonlyArray<PropertyDeclaration> {
const members: PropertyDeclaration[] = [];
forEachOwnNodeOfFunction(fnAst, node => {
if (isAssignmentExpression(node, /*excludeCompoundAssignment*/ true) &&
isPropertyAccessExpression(node.left) && node.left.expression.kind === SyntaxKind.ThisKeyword) {
const name = node.left.name.text;
if (!isJsPrivate(name)) members.push(createProperty(/*decorators*/ undefined, /*modifiers*/ undefined, name, /*questionOrExclamationToken*/ undefined, anyType(), /*initializer*/ undefined));
}
});
return members;
}
interface ParametersAndReturnType { readonly parameters: ReadonlyArray<ParameterDeclaration>; readonly returnType: TypeNode; }
function getParametersAndReturnType(fnAst: FunctionOrConstructor): ParametersAndReturnType {
if (typeof fnAst === "number") {
return { parameters: fill(fnAst, i => makeParameter(`p${i}`, anyType())), returnType: anyType() };
}
let usedArguments = false, hasReturn = false;
forEachOwnNodeOfFunction(fnAst, node => {
usedArguments = usedArguments || isIdentifier(node) && node.text === "arguments";
hasReturn = hasReturn || isReturnStatement(node) && !!node.expression && node.expression.kind !== SyntaxKind.VoidExpression;
});
const parameters = [
...fnAst.parameters.map(p => makeParameter(`${p.name.getText()}`, inferParameterType(fnAst, p))),
...(usedArguments ? [makeRestParameter()] : emptyArray),
];
return { parameters, returnType: hasReturn ? anyType() : createKeywordTypeNode(SyntaxKind.VoidKeyword) };
}
function makeParameter(name: string, type: TypeNode): ParameterDeclaration {
return createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, /*dotDotDotToken*/ undefined, name, /*questionToken*/ undefined, type);
}
function makeRestParameter(): ParameterDeclaration {
return createParameter(/*decorators*/ undefined, /*modifiers*/ undefined, createToken(SyntaxKind.DotDotDotToken), "args", /*questionToken*/ undefined, createArrayTypeNode(anyType()));
}
type FunctionOrConstructorNode = FunctionExpression | ArrowFunction | ConstructorDeclaration | MethodDeclaration;
type FunctionOrConstructor = FunctionOrConstructorNode | number; // number is for native function
/** Returns 'undefined' for class with no declared constructor */
function parseClassOrFunctionBody(source: string | number): FunctionOrConstructor | undefined {
if (typeof source === "number") return source;
const classOrFunction = tryCast(parseExpression(source), (node): node is FunctionExpression | ArrowFunction | ClassExpression => isFunctionExpression(node) || isArrowFunction(node) || isClassExpression(node));
return classOrFunction
? isClassExpression(classOrFunction) ? find(classOrFunction.members, isConstructorDeclaration) : classOrFunction
// If that didn't parse, it's a method `m() {}`. Parse again inside of an object literal.
: cast(first(cast(parseExpression(`{ ${source} }`), isObjectLiteralExpression).properties), isMethodDeclaration);
}
function parseExpression(expr: string): Expression {
const text = `const _ = ${expr}`;
const srcFile = createSourceFile("test.ts", text, ScriptTarget.Latest, /*setParentNodes*/ true);
return first(cast(first(srcFile.statements), isVariableStatement).declarationList.declarations).initializer!;
}
function inferParameterType(_fn: FunctionOrConstructor, _param: ParameterDeclaration): TypeNode {
// TODO: Inspect function body for clues (see inferFromUsage.ts)
return anyType();
}
// Descends through all nodes in a function, but not in nested functions.
function forEachOwnNodeOfFunction(fnAst: FunctionOrConstructorNode, cb: (node: Node) => void) {
fnAst.body!.forEachChild(function recur(node) {
cb(node);
if (!isFunctionLike(node)) node.forEachChild(recur);
});
}
function isValidIdentifier(name: string): boolean {
const keyword = stringToToken(name);
return !(keyword && isNonContextualKeyword(keyword)) && isIdentifierText(name, ScriptTarget.ESNext);
}
type Modifiers = ReadonlyArray<Modifier> | undefined;
function addComment<T extends Node>(node: T, comment: string | undefined): T {
if (comment !== undefined) addSyntheticLeadingComment(node, SyntaxKind.SingleLineCommentTrivia, comment);
return node;
}
function anyType(): KeywordTypeNode {
return createKeywordTypeNode(SyntaxKind.AnyKeyword);
}
function createNamespace(modifiers: Modifiers, name: string, statements: ReadonlyArray<Statement>): NamespaceDeclaration {
return createModuleDeclaration(/*decorators*/ undefined, modifiers, createIdentifier(name), createModuleBlock(statements), NodeFlags.Namespace) as NamespaceDeclaration;
}
}
+8 -8
View File
@@ -185,20 +185,20 @@ namespace ts.codefix {
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) });
result.push({ moduleSymbol, importKind: defaultInfo.kind, exportedSymbolIsTypeOnly: isTypeOnlySymbol(defaultInfo.symbol, checker) });
}
for (const exported of checker.getExportsOfModule(moduleSymbol)) {
if (exported.name === symbolName && skipAlias(exported, checker) === exportedSymbol) {
result.push({ moduleSymbol, importKind: ImportKind.Named, exportedSymbolIsTypeOnly: isTypeOnlySymbol(exported) });
result.push({ moduleSymbol, importKind: ImportKind.Named, exportedSymbolIsTypeOnly: isTypeOnlySymbol(exported, checker) });
}
}
});
return result;
}
function isTypeOnlySymbol(s: Symbol): boolean {
return !(s.flags & SymbolFlags.Value);
function isTypeOnlySymbol(s: Symbol, checker: TypeChecker): boolean {
return !(skipAlias(s, checker).flags & SymbolFlags.Value);
}
function getFixForImport(
@@ -267,7 +267,7 @@ namespace ts.codefix {
function getExistingImportDeclarations({ moduleSymbol, importKind, exportedSymbolIsTypeOnly }: SymbolExportInfo, checker: TypeChecker, sourceFile: SourceFile): ReadonlyArray<FixAddToExistingImportInfo> {
// Can't use an es6 import for a type in JS.
return exportedSymbolIsTypeOnly && isSourceFileJavaScript(sourceFile) ? emptyArray : mapDefined<StringLiteralLike, FixAddToExistingImportInfo>(sourceFile.imports, moduleSpecifier => {
return exportedSymbolIsTypeOnly && isSourceFileJS(sourceFile) ? emptyArray : mapDefined<StringLiteralLike, FixAddToExistingImportInfo>(sourceFile.imports, moduleSpecifier => {
const i = importFromModuleSpecifier(moduleSpecifier);
return (i.kind === SyntaxKind.ImportDeclaration || i.kind === SyntaxKind.ImportEqualsDeclaration)
&& checker.getSymbolAtLocation(moduleSpecifier) === moduleSymbol ? { declaration: i, importKind } : undefined;
@@ -282,7 +282,7 @@ namespace ts.codefix {
host: LanguageServiceHost,
preferences: UserPreferences,
): ReadonlyArray<FixAddNewImport | FixUseImportType> {
const isJs = isSourceFileJavaScript(sourceFile);
const isJs = isSourceFileJS(sourceFile);
const choicesForEachExportingModule = flatMap(moduleSymbols, ({ moduleSymbol, importKind, exportedSymbolIsTypeOnly }) =>
moduleSpecifiers.getModuleSpecifiers(moduleSymbol, program.getCompilerOptions(), sourceFile, host, program.getSourceFiles(), preferences, program.redirectTargetsMap)
.map((moduleSpecifier): FixAddNewImport | FixUseImportType =>
@@ -398,7 +398,7 @@ namespace ts.codefix {
// Maps symbol id to info for modules providing that symbol (original export + re-exports).
const originalSymbolToExportInfos = createMultiMap<SymbolExportInfo>();
function addSymbol(moduleSymbol: Symbol, exportedSymbol: Symbol, importKind: ImportKind): void {
originalSymbolToExportInfos.add(getUniqueSymbolId(exportedSymbol, checker).toString(), { moduleSymbol, importKind, exportedSymbolIsTypeOnly: isTypeOnlySymbol(exportedSymbol) });
originalSymbolToExportInfos.add(getUniqueSymbolId(exportedSymbol, checker).toString(), { moduleSymbol, importKind, exportedSymbolIsTypeOnly: isTypeOnlySymbol(exportedSymbol, checker) });
}
forEachExternalModuleToImportFrom(checker, sourceFile, program.getSourceFiles(), moduleSymbol => {
cancellationToken.throwIfCancellationRequested();
@@ -424,7 +424,7 @@ namespace ts.codefix {
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 };
return info && { symbol, kind, ...info };
}
function getDefaultLikeExportWorker(moduleSymbol: Symbol, checker: TypeChecker): { readonly symbol: Symbol, readonly kind: ImportKind.Default | ImportKind.Equals } | undefined {
+96 -43
View File
@@ -25,24 +25,21 @@ namespace ts.codefix {
registerCodeFix({
errorCodes,
getCodeActions(context) {
const { sourceFile, program, span: { start }, errorCode, cancellationToken } = context;
if (isSourceFileJavaScript(sourceFile)) {
return undefined; // TODO: GH#20113
}
const { sourceFile, program, span: { start }, errorCode, cancellationToken, host } = context;
const token = getTokenAtPosition(sourceFile, start);
let declaration!: Declaration | undefined;
const changes = textChanges.ChangeTracker.with(context, changes => { declaration = doChange(changes, sourceFile, token, errorCode, program, cancellationToken, /*markSeenseen*/ returnTrue); });
const changes = textChanges.ChangeTracker.with(context, changes => { declaration = doChange(changes, sourceFile, token, errorCode, program, cancellationToken, /*markSeen*/ returnTrue, host); });
const name = declaration && getNameOfDeclaration(declaration);
return !name || changes.length === 0 ? undefined
: [createCodeFixAction(fixId, changes, [getDiagnostic(errorCode, token), name.getText(sourceFile)], fixId, Diagnostics.Infer_all_types_from_usage)];
},
fixIds: [fixId],
getAllCodeActions(context) {
const { sourceFile, program, cancellationToken } = context;
const { sourceFile, program, cancellationToken, host } = context;
const markSeen = nodeSeenTracker();
return codeFixAll(context, errorCodes, (changes, err) => {
doChange(changes, sourceFile, getTokenAtPosition(err.file, err.start), err.code, program, cancellationToken, markSeen);
doChange(changes, sourceFile, getTokenAtPosition(err.file, err.start), err.code, program, cancellationToken, markSeen, host);
});
},
});
@@ -50,7 +47,7 @@ namespace ts.codefix {
function getDiagnostic(errorCode: number, token: Node): DiagnosticMessage {
switch (errorCode) {
case Diagnostics.Parameter_0_implicitly_has_an_1_type.code:
return isSetAccessor(getContainingFunction(token)!) ? Diagnostics.Infer_type_of_0_from_usage : Diagnostics.Infer_parameter_types_from_usage; // TODO: GH#18217
return isSetAccessorDeclaration(getContainingFunction(token)!) ? Diagnostics.Infer_type_of_0_from_usage : Diagnostics.Infer_parameter_types_from_usage; // TODO: GH#18217
case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code:
return Diagnostics.Infer_parameter_types_from_usage;
default:
@@ -58,8 +55,8 @@ namespace ts.codefix {
}
}
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node, errorCode: number, program: Program, cancellationToken: CancellationToken, markSeen: NodeSeenTracker): Declaration | undefined {
if (!isParameterPropertyModifier(token.kind) && token.kind !== SyntaxKind.Identifier && token.kind !== SyntaxKind.DotDotDotToken) {
function doChange(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node, errorCode: number, program: Program, cancellationToken: CancellationToken, markSeen: NodeSeenTracker, host: LanguageServiceHost): Declaration | undefined {
if (!isParameterPropertyModifier(token.kind) && token.kind !== SyntaxKind.Identifier && token.kind !== SyntaxKind.DotDotDotToken && token.kind !== SyntaxKind.ThisKeyword) {
return undefined;
}
@@ -69,7 +66,15 @@ namespace ts.codefix {
case Diagnostics.Member_0_implicitly_has_an_1_type.code:
case Diagnostics.Variable_0_implicitly_has_type_1_in_some_locations_where_its_type_cannot_be_determined.code:
if ((isVariableDeclaration(parent) && markSeen(parent)) || isPropertyDeclaration(parent) || isPropertySignature(parent)) { // handle bad location
annotateVariableDeclaration(changes, sourceFile, parent, program, cancellationToken);
annotateVariableDeclaration(changes, sourceFile, parent, program, host, cancellationToken);
return parent;
}
if (isPropertyAccessExpression(parent)) {
const type = inferTypeForVariableFromUsage(parent.name, program, cancellationToken);
const typeNode = type && getTypeNodeIfAccessible(type, parent, program, host);
if (typeNode) {
changes.tryInsertJSDocType(sourceFile, parent, typeNode);
}
return parent;
}
return undefined;
@@ -77,7 +82,7 @@ namespace ts.codefix {
case Diagnostics.Variable_0_implicitly_has_an_1_type.code: {
const symbol = program.getTypeChecker().getSymbolAtLocation(token);
if (symbol && symbol.valueDeclaration && isVariableDeclaration(symbol.valueDeclaration) && markSeen(symbol.valueDeclaration)) {
annotateVariableDeclaration(changes, sourceFile, symbol.valueDeclaration, program, cancellationToken);
annotateVariableDeclaration(changes, sourceFile, symbol.valueDeclaration, program, host, cancellationToken);
return symbol.valueDeclaration;
}
return undefined;
@@ -92,15 +97,15 @@ namespace ts.codefix {
switch (errorCode) {
// Parameter declarations
case Diagnostics.Parameter_0_implicitly_has_an_1_type.code:
if (isSetAccessor(containingFunction)) {
annotateSetAccessor(changes, sourceFile, containingFunction, program, cancellationToken);
if (isSetAccessorDeclaration(containingFunction)) {
annotateSetAccessor(changes, sourceFile, containingFunction, program, host, cancellationToken);
return containingFunction;
}
// falls through
case Diagnostics.Rest_parameter_0_implicitly_has_an_any_type.code:
if (markSeen(containingFunction)) {
const param = cast(parent, isParameter);
annotateParameters(changes, param, containingFunction, sourceFile, program, cancellationToken);
annotateParameters(changes, param, containingFunction, sourceFile, program, host, cancellationToken);
return param;
}
return undefined;
@@ -108,16 +113,16 @@ namespace ts.codefix {
// Get Accessor declarations
case Diagnostics.Property_0_implicitly_has_type_any_because_its_get_accessor_lacks_a_return_type_annotation.code:
case Diagnostics._0_which_lacks_return_type_annotation_implicitly_has_an_1_return_type.code:
if (isGetAccessor(containingFunction) && isIdentifier(containingFunction.name)) {
annotate(changes, sourceFile, containingFunction, inferTypeForVariableFromUsage(containingFunction.name, program, cancellationToken), program);
if (isGetAccessorDeclaration(containingFunction) && isIdentifier(containingFunction.name)) {
annotate(changes, sourceFile, containingFunction, inferTypeForVariableFromUsage(containingFunction.name, program, cancellationToken), program, host);
return containingFunction;
}
return undefined;
// Set Accessor declarations
case Diagnostics.Property_0_implicitly_has_type_any_because_its_set_accessor_lacks_a_parameter_type_annotation.code:
if (isSetAccessor(containingFunction)) {
annotateSetAccessor(changes, sourceFile, containingFunction, program, cancellationToken);
if (isSetAccessorDeclaration(containingFunction)) {
annotateSetAccessor(changes, sourceFile, containingFunction, program, host, cancellationToken);
return containingFunction;
}
return undefined;
@@ -127,9 +132,9 @@ namespace ts.codefix {
}
}
function annotateVariableDeclaration(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: VariableDeclaration | PropertyDeclaration | PropertySignature, program: Program, cancellationToken: CancellationToken): void {
function annotateVariableDeclaration(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: VariableDeclaration | PropertyDeclaration | PropertySignature, program: Program, host: LanguageServiceHost, cancellationToken: CancellationToken): void {
if (isIdentifier(declaration.name)) {
annotate(changes, sourceFile, declaration, inferTypeForVariableFromUsage(declaration.name, program, cancellationToken), program);
annotate(changes, sourceFile, declaration, inferTypeForVariableFromUsage(declaration.name, program, cancellationToken), program, host);
}
}
@@ -145,40 +150,67 @@ namespace ts.codefix {
return false;
}
function annotateParameters(changes: textChanges.ChangeTracker, parameterDeclaration: ParameterDeclaration, containingFunction: FunctionLike, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): void {
function annotateParameters(changes: textChanges.ChangeTracker, parameterDeclaration: ParameterDeclaration, containingFunction: FunctionLike, sourceFile: SourceFile, program: Program, host: LanguageServiceHost, cancellationToken: CancellationToken): void {
if (!isIdentifier(parameterDeclaration.name) || !isApplicableFunctionForInference(containingFunction)) {
return;
}
const types = inferTypeForParametersFromUsage(containingFunction, sourceFile, program, cancellationToken) ||
containingFunction.parameters.map(p => isIdentifier(p.name) ? inferTypeForVariableFromUsage(p.name, program, cancellationToken) : undefined);
// We didn't actually find a set of type inference positions matching each parameter position
if (!types || containingFunction.parameters.length !== types.length) {
return;
}
const parameterInferences = inferTypeForParametersFromUsage(containingFunction, sourceFile, program, cancellationToken) ||
containingFunction.parameters.map<ParameterInference>(p => ({
declaration: p,
type: isIdentifier(p.name) ? inferTypeForVariableFromUsage(p.name, program, cancellationToken) : undefined
}));
Debug.assert(containingFunction.parameters.length === parameterInferences.length);
zipWith(containingFunction.parameters, types, (parameter, type) => {
if (!parameter.type && !parameter.initializer) {
annotate(changes, sourceFile, parameter, type, program);
if (isInJSFile(containingFunction)) {
annotateJSDocParameters(changes, sourceFile, parameterInferences, program, host);
}
else {
for (const { declaration, type } of parameterInferences) {
if (declaration && !declaration.type && !declaration.initializer) {
annotate(changes, sourceFile, declaration, type, program, host);
}
}
});
}
}
function annotateSetAccessor(changes: textChanges.ChangeTracker, sourceFile: SourceFile, setAccessorDeclaration: SetAccessorDeclaration, program: Program, cancellationToken: CancellationToken): void {
function annotateSetAccessor(changes: textChanges.ChangeTracker, sourceFile: SourceFile, setAccessorDeclaration: SetAccessorDeclaration, program: Program, host: LanguageServiceHost, cancellationToken: CancellationToken): void {
const param = firstOrUndefined(setAccessorDeclaration.parameters);
if (param && isIdentifier(setAccessorDeclaration.name) && isIdentifier(param.name)) {
const type = inferTypeForVariableFromUsage(setAccessorDeclaration.name, program, cancellationToken) ||
inferTypeForVariableFromUsage(param.name, program, cancellationToken);
annotate(changes, sourceFile, param, type, program);
if (isInJSFile(setAccessorDeclaration)) {
annotateJSDocParameters(changes, sourceFile, [{ declaration: param, type }], program, host);
}
else {
annotate(changes, sourceFile, param, type, program, host);
}
}
}
function annotate(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: textChanges.TypeAnnotatable, type: Type | undefined, program: Program): void {
const typeNode = type && getTypeNodeIfAccessible(type, declaration, program.getTypeChecker());
if (typeNode) changes.tryInsertTypeAnnotation(sourceFile, declaration, typeNode);
function annotate(changes: textChanges.ChangeTracker, sourceFile: SourceFile, declaration: textChanges.TypeAnnotatable, type: Type | undefined, program: Program, host: LanguageServiceHost): void {
const typeNode = type && getTypeNodeIfAccessible(type, declaration, program, host);
if (typeNode) {
if (isInJSFile(sourceFile) && declaration.kind !== SyntaxKind.PropertySignature) {
changes.tryInsertJSDocType(sourceFile, declaration, typeNode);
}
else {
changes.tryInsertTypeAnnotation(sourceFile, declaration, typeNode);
}
}
}
function getTypeNodeIfAccessible(type: Type, enclosingScope: Node, checker: TypeChecker): TypeNode | undefined {
function annotateJSDocParameters(changes: textChanges.ChangeTracker, sourceFile: SourceFile, parameterInferences: ParameterInference[], program: Program, host: LanguageServiceHost): void {
const result = mapDefined(parameterInferences, inference => {
const param = inference.declaration;
const typeNode = inference.type && getTypeNodeIfAccessible(inference.type, param, program, host);
return typeNode && !param.initializer && !getJSDocType(param) ? { ...inference, typeNode } : undefined;
});
changes.tryInsertJSDocParameters(sourceFile, result);
}
function getTypeNodeIfAccessible(type: Type, enclosingScope: Node, program: Program, host: LanguageServiceHost): TypeNode | undefined {
const checker = program.getTypeChecker();
let typeIsAccessible = true;
const notAccessible = () => { typeIsAccessible = false; };
const res = checker.typeToTypeNode(type, enclosingScope, /*flags*/ undefined, {
@@ -189,6 +221,14 @@ namespace ts.codefix {
reportInaccessibleThisError: notAccessible,
reportPrivateInBaseOfClassExpression: notAccessible,
reportInaccessibleUniqueSymbolError: notAccessible,
moduleResolverHost: {
readFile: host.readFile,
fileExists: host.fileExists,
directoryExists: host.directoryExists,
getSourceFiles: program.getSourceFiles,
getCurrentDirectory: program.getCurrentDirectory,
getCommonSourceDirectory: program.getCommonSourceDirectory,
}
});
return typeIsAccessible ? res : undefined;
}
@@ -196,14 +236,14 @@ namespace ts.codefix {
function getReferences(token: PropertyName | Token<SyntaxKind.ConstructorKeyword>, program: Program, cancellationToken: CancellationToken): ReadonlyArray<Identifier> {
// Position shouldn't matter since token is not a SourceFile.
return mapDefined(FindAllReferences.getReferenceEntriesForNode(-1, token, program, program.getSourceFiles(), cancellationToken), entry =>
entry.type === "node" ? tryCast(entry.node, isIdentifier) : undefined);
entry.kind !== FindAllReferences.EntryKind.Span ? tryCast(entry.node, isIdentifier) : undefined);
}
function inferTypeForVariableFromUsage(token: Identifier, program: Program, cancellationToken: CancellationToken): Type | undefined {
return InferFromReference.inferTypeFromReferences(getReferences(token, program, cancellationToken), program.getTypeChecker(), cancellationToken);
}
function inferTypeForParametersFromUsage(containingFunction: FunctionLikeDeclaration, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): (Type | undefined)[] | undefined {
function inferTypeForParametersFromUsage(containingFunction: FunctionLikeDeclaration, sourceFile: SourceFile, program: Program, cancellationToken: CancellationToken): ParameterInference[] | undefined {
switch (containingFunction.kind) {
case SyntaxKind.Constructor:
case SyntaxKind.FunctionExpression:
@@ -219,6 +259,13 @@ namespace ts.codefix {
}
}
interface ParameterInference {
declaration: ParameterDeclaration;
type?: Type;
typeNode?: TypeNode;
isOptional?: boolean;
}
namespace InferFromReference {
interface CallContext {
argumentTypes: Type[];
@@ -246,7 +293,7 @@ namespace ts.codefix {
return getTypeFromUsageContext(usageContext, checker);
}
export function inferTypeForParametersFromReferences(references: ReadonlyArray<Identifier>, declaration: FunctionLikeDeclaration, checker: TypeChecker, cancellationToken: CancellationToken): (Type | undefined)[] | undefined {
export function inferTypeForParametersFromReferences(references: ReadonlyArray<Identifier>, declaration: FunctionLikeDeclaration, checker: TypeChecker, cancellationToken: CancellationToken): ParameterInference[] | undefined {
if (references.length === 0) {
return undefined;
}
@@ -265,8 +312,10 @@ namespace ts.codefix {
return callContexts && declaration.parameters.map((parameter, parameterIndex) => {
const types: Type[] = [];
const isRest = isRestParameter(parameter);
let isOptional = false;
for (const callContext of callContexts) {
if (callContext.argumentTypes.length <= parameterIndex) {
isOptional = isInJSFile(declaration);
continue;
}
@@ -280,10 +329,14 @@ namespace ts.codefix {
}
}
if (!types.length) {
return undefined;
return { declaration: parameter };
}
const type = checker.getWidenedType(checker.getUnionType(types, UnionReduction.Subtype));
return isRest ? checker.createArrayType(type) : type;
return {
type: isRest ? checker.createArrayType(type) : type,
isOptional: isOptional && !isRest,
declaration: parameter
};
});
}
+40 -26
View File
@@ -43,7 +43,7 @@ namespace ts.Completions {
}
const contextToken = findPrecedingToken(position, sourceFile);
if (triggerCharacter && (!contextToken || !isValidTrigger(sourceFile, triggerCharacter, contextToken, position))) return undefined;
if (triggerCharacter && !isValidTrigger(sourceFile, triggerCharacter, contextToken, position)) return undefined;
if (isInString(sourceFile, position, contextToken)) {
return !contextToken || !isStringLiteralLike(contextToken)
@@ -134,7 +134,7 @@ namespace ts.Completions {
if (isUncheckedFile(sourceFile, compilerOptions)) {
const uniqueNames = getCompletionEntriesFromSymbols(symbols, entries, location, sourceFile, typeChecker, compilerOptions.target!, log, completionKind, preferences, propertyAccessToConvert, isJsxInitializer, recommendedCompletion, symbolToOriginInfoMap);
getJavaScriptCompletionEntries(sourceFile, location!.pos, uniqueNames, compilerOptions.target!, entries); // TODO: GH#18217
getJSCompletionEntries(sourceFile, location!.pos, uniqueNames, compilerOptions.target!, entries); // TODO: GH#18217
}
else {
if ((!symbols || symbols.length === 0) && keywordFilters === KeywordCompletionFilters.None) {
@@ -161,7 +161,7 @@ namespace ts.Completions {
}
function isUncheckedFile(sourceFile: SourceFile, compilerOptions: CompilerOptions): boolean {
return isSourceFileJavaScript(sourceFile) && !isCheckJsEnabledForFile(sourceFile, compilerOptions);
return isSourceFileJS(sourceFile) && !isCheckJsEnabledForFile(sourceFile, compilerOptions);
}
function isMemberCompletionKind(kind: CompletionKind): boolean {
@@ -175,7 +175,7 @@ namespace ts.Completions {
}
}
function getJavaScriptCompletionEntries(
function getJSCompletionEntries(
sourceFile: SourceFile,
position: number,
uniqueNames: Map<true>,
@@ -390,11 +390,12 @@ namespace ts.Completions {
}
type StringLiteralCompletion = { readonly kind: StringLiteralCompletionKind.Paths, readonly paths: ReadonlyArray<PathCompletions.PathCompletion> } | StringLiteralCompletionsFromProperties | StringLiteralCompletionsFromTypes;
function getStringLiteralCompletionEntries(sourceFile: SourceFile, node: StringLiteralLike, position: number, typeChecker: TypeChecker, compilerOptions: CompilerOptions, host: LanguageServiceHost): StringLiteralCompletion | undefined {
switch (node.parent.kind) {
const { parent } = node;
switch (parent.kind) {
case SyntaxKind.LiteralType:
switch (node.parent.parent.kind) {
switch (parent.parent.kind) {
case SyntaxKind.TypeReference:
return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(node.parent as LiteralTypeNode)), isNewIdentifier: false };
return { kind: StringLiteralCompletionKind.Types, types: getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(parent as LiteralTypeNode)), isNewIdentifier: false };
case SyntaxKind.IndexedAccessType:
// Get all apparent property names
// i.e. interface Foo {
@@ -402,17 +403,21 @@ namespace ts.Completions {
// bar: string;
// }
// let x: Foo["/*completion position*/"]
return stringLiteralCompletionsFromProperties(typeChecker.getTypeFromTypeNode((node.parent.parent as IndexedAccessTypeNode).objectType));
return stringLiteralCompletionsFromProperties(typeChecker.getTypeFromTypeNode((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;
case SyntaxKind.UnionType: {
if (!isTypeReferenceNode(parent.parent.parent)) return undefined;
const alreadyUsedTypes = getAlreadyUsedTypesInStringLiteralUnion(parent.parent as UnionTypeNode, parent as LiteralTypeNode);
const types = getStringLiteralTypes(typeChecker.getTypeArgumentConstraint(parent.parent as UnionTypeNode)).filter(t => !contains(alreadyUsedTypes, t.value));
return { kind: StringLiteralCompletionKind.Types, types, isNewIdentifier: false };
}
default:
return undefined;
}
case SyntaxKind.PropertyAssignment:
if (isObjectLiteralExpression(node.parent.parent) && (<PropertyAssignment>node.parent).name === node) {
if (isObjectLiteralExpression(parent.parent) && (<PropertyAssignment>parent).name === node) {
// Get quoted name of properties of the object literal expression
// i.e. interface ConfigFiles {
// 'jspm:dev': string
@@ -425,12 +430,12 @@ namespace ts.Completions {
// foo({
// '/*completion position*/'
// });
return stringLiteralCompletionsFromProperties(typeChecker.getContextualType(node.parent.parent));
return stringLiteralCompletionsFromProperties(typeChecker.getContextualType(parent.parent));
}
return fromContextualType();
case SyntaxKind.ElementAccessExpression: {
const { expression, argumentExpression } = node.parent as ElementAccessExpression;
const { expression, argumentExpression } = parent as ElementAccessExpression;
if (node === argumentExpression) {
// Get all names of properties on the expression
// i.e. interface A {
@@ -445,7 +450,7 @@ namespace ts.Completions {
case SyntaxKind.CallExpression:
case SyntaxKind.NewExpression:
if (!isRequireCall(node.parent, /*checkArgumentIsStringLiteralLike*/ false) && !isImportCall(node.parent)) {
if (!isRequireCall(parent, /*checkArgumentIsStringLiteralLike*/ false) && !isImportCall(parent)) {
const argumentInfo = SignatureHelp.getArgumentInfoForCompletions(node, position, sourceFile);
// Get string literal completions from specialized signatures of the target
// i.e. declare function f(a: 'A');
@@ -476,6 +481,11 @@ namespace ts.Completions {
}
}
function getAlreadyUsedTypesInStringLiteralUnion(union: UnionTypeNode, current: LiteralTypeNode): ReadonlyArray<string> {
return mapDefined(union.types, type =>
type !== current && isLiteralTypeNode(type) && isStringLiteral(type.literal) ? type.literal.text : undefined);
}
function getStringLiteralCompletionsFromSignature(argumentInfo: SignatureHelp.ArgumentInfoForCompletions, checker: TypeChecker): StringLiteralCompletionsFromTypes {
let isNewIdentifier = false;
@@ -1190,9 +1200,9 @@ namespace ts.Completions {
function tryGetJsxCompletionSymbols(): GlobalsSearch {
const jsxContainer = tryGetContainingJsxElement(contextToken);
// Cursor is inside a JSX self-closing element or opening element
const attrsType = jsxContainer && typeChecker.getAllAttributesTypeFromJsxOpeningLikeElement(jsxContainer);
const attrsType = jsxContainer && typeChecker.getContextualType(jsxContainer.attributes);
if (!attrsType) return GlobalsSearch.Continue;
symbols = filterJsxAttributes(typeChecker.getPropertiesOfType(attrsType), jsxContainer!.attributes.properties);
symbols = filterJsxAttributes(getPropertiesForObjectExpression(attrsType, jsxContainer!.attributes, typeChecker), jsxContainer!.attributes.properties);
completionKind = CompletionKind.MemberLike;
isNewIdentifierLocation = false;
return GlobalsSearch.Success;
@@ -1268,10 +1278,10 @@ namespace ts.Completions {
if (sourceFile.externalModuleIndicator) return true;
// If already using commonjs, don't introduce ES6.
if (sourceFile.commonJsModuleIndicator) return false;
// If some file is using ES6 modules, assume that it's OK to add more.
if (programContainsEs6Modules(program)) return true;
// For JS, stay on the safe side.
if (isUncheckedFile) return false;
// If some file is using ES6 modules, assume that it's OK to add more.
if (programContainsEs6Modules(program)) return true;
// If module transpilation is enabled or we're targeting es6 or above, or not emitting, OK.
return compilerOptionsIndicateEs6Modules(program.getCompilerOptions());
}
@@ -1387,7 +1397,7 @@ namespace ts.Completions {
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)) {
some(resolvedModuleSymbol.declarations, d => !!d.getSourceFile().externalModuleIndicator)) {
symbols.push(resolvedModuleSymbol);
symbolToOriginInfoMap[getSymbolId(resolvedModuleSymbol)] = { kind: SymbolOriginInfoKind.Export, moduleSymbol, isDefaultExport: false };
}
@@ -1703,6 +1713,9 @@ namespace ts.Completions {
break;
case SyntaxKind.AsteriskToken:
return isMethodDeclaration(parent) ? tryCast(parent.parent, isObjectLiteralExpression) : undefined;
case SyntaxKind.Identifier:
return (contextToken as Identifier).text === "async" && isShorthandPropertyAssignment(contextToken.parent)
? contextToken.parent.parent : undefined;
}
}
@@ -1918,7 +1931,6 @@ namespace ts.Completions {
// Previous token may have been a keyword that was converted to an identifier.
switch (keywordForNode(contextToken)) {
case SyntaxKind.AbstractKeyword:
case SyntaxKind.AsyncKeyword:
case SyntaxKind.ClassKeyword:
case SyntaxKind.ConstKeyword:
case SyntaxKind.DeclareKeyword:
@@ -1933,6 +1945,8 @@ namespace ts.Completions {
case SyntaxKind.VarKeyword:
case SyntaxKind.YieldKeyword:
return true;
case SyntaxKind.AsyncKeyword:
return isPropertyDeclaration(contextToken.parent);
}
return isDeclarationName(contextToken)
@@ -2197,7 +2211,7 @@ namespace ts.Completions {
return jsdoc && jsdoc.tags && (rangeContainsPosition(jsdoc, position) ? findLast(jsdoc.tags, tag => tag.pos < position) : undefined);
}
function getPropertiesForObjectExpression(contextualType: Type, obj: ObjectLiteralExpression, checker: TypeChecker): Symbol[] {
function getPropertiesForObjectExpression(contextualType: Type, obj: ObjectLiteralExpression | JsxAttributes, checker: TypeChecker): Symbol[] {
return contextualType.isUnion()
? checker.getAllPossiblePropertiesOfTypes(contextualType.types.filter(memberType =>
// If we're providing completions for an object literal, skip primitive, array-like, or callable types since those shouldn't be implemented by object literals.
@@ -2262,7 +2276,7 @@ namespace ts.Completions {
return !!type.getStringIndexType() || !!type.getNumberIndexType();
}
function isValidTrigger(sourceFile: SourceFile, triggerCharacter: CompletionsTriggerCharacter, contextToken: Node, position: number): boolean {
function isValidTrigger(sourceFile: SourceFile, triggerCharacter: CompletionsTriggerCharacter, contextToken: Node | undefined, position: number): boolean {
switch (triggerCharacter) {
case ".":
case "@":
@@ -2271,14 +2285,14 @@ namespace ts.Completions {
case "'":
case "`":
// Only automatically bring up completions if this is an opening quote.
return isStringLiteralOrTemplate(contextToken) && position === contextToken.getStart(sourceFile) + 1;
return !!contextToken && isStringLiteralOrTemplate(contextToken) && position === contextToken.getStart(sourceFile) + 1;
case "<":
// Opening JSX tag
return contextToken.kind === SyntaxKind.LessThanToken && (!isBinaryExpression(contextToken.parent) || binaryExpressionMayBeOpenTag(contextToken.parent));
return !!contextToken && contextToken.kind === SyntaxKind.LessThanToken && (!isBinaryExpression(contextToken.parent) || binaryExpressionMayBeOpenTag(contextToken.parent));
case "/":
return isStringLiteralLike(contextToken)
return !!contextToken && (isStringLiteralLike(contextToken)
? !!tryGetImportFromModuleSpecifier(contextToken)
: contextToken.kind === SyntaxKind.SlashToken && isJsxClosingElement(contextToken.parent);
: contextToken.kind === SyntaxKind.SlashToken && isJsxClosingElement(contextToken.parent));
default:
return Debug.assertNever(triggerCharacter);
}
+4 -4
View File
@@ -121,10 +121,6 @@ namespace ts {
const buckets = createMap<Map<DocumentRegistryEntry>>();
const getCanonicalFileName = createGetCanonicalFileName(!!useCaseSensitiveFileNames);
function getKeyForCompilationSettings(settings: CompilerOptions): DocumentRegistryBucketKey {
return <DocumentRegistryBucketKey>`_${settings.target}|${settings.module}|${settings.noResolve}|${settings.jsx}|${settings.allowJs}|${settings.baseUrl}|${JSON.stringify(settings.typeRoots)}|${JSON.stringify(settings.rootDirs)}|${JSON.stringify(settings.paths)}`;
}
function getBucketForCompilationSettings(key: DocumentRegistryBucketKey, createIfMissing: boolean): Map<DocumentRegistryEntry> {
let bucket = buckets.get(key);
if (!bucket && createIfMissing) {
@@ -273,4 +269,8 @@ namespace ts {
getKeyForCompilationSettings
};
}
function getKeyForCompilationSettings(settings: CompilerOptions): DocumentRegistryBucketKey {
return sourceFileAffectingCompilerOptions.map(option => getCompilerOptionValue(settings, option)).join("|") as DocumentRegistryBucketKey;
}
}
+125 -82
View File
@@ -13,19 +13,20 @@ namespace ts.FindAllReferences {
| { readonly type: DefinitionKind.This; readonly node: Node }
| { readonly type: DefinitionKind.String; readonly node: StringLiteral };
export const enum EntryKind { Span, Node, StringLiteral, SearchedLocalFoundProperty, SearchedPropertyFoundLocal }
export type NodeEntryKind = EntryKind.Node | EntryKind.StringLiteral | EntryKind.SearchedLocalFoundProperty | EntryKind.SearchedPropertyFoundLocal;
export type Entry = NodeEntry | SpanEntry;
export interface NodeEntry {
type: "node";
node: Node;
isInString?: true;
readonly kind: NodeEntryKind;
readonly node: Node;
}
export interface SpanEntry {
type: "span";
fileName: string;
textSpan: TextSpan;
readonly kind: EntryKind.Span;
readonly fileName: string;
readonly textSpan: TextSpan;
}
export function nodeEntry(node: Node, isInString?: true): NodeEntry {
return { type: "node", node: (node as NamedDeclaration).name || node, isInString };
export function nodeEntry(node: Node, kind: NodeEntryKind = EntryKind.Node): NodeEntry {
return { kind, node: (node as NamedDeclaration).name || node };
}
export interface Options {
@@ -33,7 +34,7 @@ namespace ts.FindAllReferences {
readonly findInComments?: boolean;
/**
* True if we are renaming the symbol.
* If so, we will find fewer references -- if it is referenced by several different names, we sill only find references for the original name.
* If so, we will find fewer references -- if it is referenced by several different names, we still only find references for the original name.
*/
readonly isForRename?: boolean;
/** True if we are searching for implementations. We will have a different method of adding references if so. */
@@ -84,10 +85,15 @@ namespace ts.FindAllReferences {
}
}
export function findReferencedEntries(program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, node: Node, position: number, options: Options | undefined): ReferenceEntry[] | undefined {
return map(flattenEntries(Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options)), toReferenceEntry);
export function findReferenceOrRenameEntries<T>(
program: Program, cancellationToken: CancellationToken, sourceFiles: ReadonlyArray<SourceFile>, node: Node, position: number, options: Options | undefined,
convertEntry: ToReferenceOrRenameEntry<T>,
): T[] | undefined {
return map(flattenEntries(Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options)), entry => convertEntry(entry, node));
}
export type ToReferenceOrRenameEntry<T> = (entry: Entry, originalNode: Node) => T;
export function getReferenceEntriesForNode(position: number, node: Node, program: Program, sourceFiles: ReadonlyArray<SourceFile>, cancellationToken: CancellationToken, options: Options = {}, sourceFilesSet: ReadonlyMap<true> = arrayToSet(sourceFiles, f => f.fileName)): Entry[] | undefined {
return flattenEntries(Core.getReferencedSymbolsForNode(position, node, program, sourceFiles, cancellationToken, options, sourceFilesSet));
}
@@ -143,26 +149,64 @@ namespace ts.FindAllReferences {
return { displayParts, kind: symbolKind };
}
function toReferenceEntry(entry: Entry): ReferenceEntry {
if (entry.type === "span") {
return { textSpan: entry.textSpan, fileName: entry.fileName, isWriteAccess: false, isDefinition: false };
}
export function toRenameLocation(entry: Entry, originalNode: Node): RenameLocation {
return { ...entryToDocumentSpan(entry), ...getPrefixAndSuffixText(entry, originalNode) };
}
const { node, isInString } = entry;
const sourceFile = node.getSourceFile();
export function toReferenceEntry(entry: Entry): ReferenceEntry {
const { textSpan, fileName } = entryToDocumentSpan(entry);
if (entry.kind === EntryKind.Span) {
return { textSpan, fileName, isWriteAccess: false, isDefinition: false };
}
const { kind, node } = entry;
return {
fileName: sourceFile.fileName,
textSpan: getTextSpan(node, sourceFile),
textSpan,
fileName,
isWriteAccess: isWriteAccessForReference(node),
isDefinition: node.kind === SyntaxKind.DefaultKeyword
|| !!getDeclarationFromName(node)
|| isLiteralComputedPropertyDeclarationName(node),
isInString,
isInString: kind === EntryKind.StringLiteral ? true : undefined,
};
}
function entryToDocumentSpan(entry: Entry): DocumentSpan {
if (entry.kind === EntryKind.Span) {
return { textSpan: entry.textSpan, fileName: entry.fileName };
}
else {
const sourceFile = entry.node.getSourceFile();
return { textSpan: getTextSpan(entry.node, sourceFile), fileName: sourceFile.fileName };
}
}
function getPrefixAndSuffixText(entry: Entry, originalNode: Node): { readonly prefixText?: string, readonly suffixText?: string } {
if (entry.kind !== EntryKind.Span && isIdentifier(originalNode)) {
const { node, kind } = entry;
const name = originalNode.text;
const isShorthandAssignment = isShorthandPropertyAssignment(node.parent);
if (isShorthandAssignment || isObjectBindingElementWithoutPropertyName(node.parent)) {
if (kind === EntryKind.SearchedLocalFoundProperty) {
return { prefixText: name + ": " };
}
else if (kind === EntryKind.SearchedPropertyFoundLocal) {
return { suffixText: ": " + name };
}
else {
return isShorthandAssignment
// In `const o = { x }; o.x`, symbolAtLocation at `x` in `{ x }` is the property symbol.
? { suffixText: ": " + name }
// For a binding element `const { x } = o;`, symbolAtLocation at `x` is the property symbol.
: { prefixText: name + ": " };
}
}
}
return emptyOptions;
}
function toImplementationLocation(entry: Entry, checker: TypeChecker): ImplementationLocation {
if (entry.type === "node") {
if (entry.kind !== EntryKind.Span) {
const { node } = entry;
const sourceFile = node.getSourceFile();
return { textSpan: getTextSpan(node, sourceFile), fileName: sourceFile.fileName, ...implementationKindDisplayParts(node, checker) };
@@ -196,18 +240,18 @@ namespace ts.FindAllReferences {
}
export function toHighlightSpan(entry: Entry): { fileName: string, span: HighlightSpan } {
if (entry.type === "span") {
if (entry.kind === EntryKind.Span) {
const { fileName, textSpan } = entry;
return { fileName, span: { textSpan, kind: HighlightSpanKind.reference } };
}
const { node, isInString } = entry;
const { node, kind } = entry;
const sourceFile = node.getSourceFile();
const writeAccess = isWriteAccessForReference(node);
const span: HighlightSpan = {
textSpan: getTextSpan(node, sourceFile),
kind: writeAccess ? HighlightSpanKind.writtenReference : HighlightSpanKind.reference,
isInString
isInString: kind === EntryKind.StringLiteral ? true : undefined,
};
return { fileName: sourceFile.fileName, span };
}
@@ -348,11 +392,11 @@ namespace ts.FindAllReferences.Core {
}
}
// import("foo") with no qualifier will reference the `export =` of the module, which may be referenced anyway.
return { type: "node", node: reference.literal };
return nodeEntry(reference.literal);
}
else {
return {
type: "span",
kind: EntryKind.Span,
fileName: reference.referencingFile.fileName,
textSpan: createTextSpanFromRange(reference.ref),
};
@@ -366,7 +410,7 @@ namespace ts.FindAllReferences.Core {
break;
case SyntaxKind.ModuleDeclaration:
if (sourceFilesSet.has(decl.getSourceFile().fileName)) {
references.push({ type: "node", node: (decl as ModuleDeclaration).name });
references.push(nodeEntry((decl as ModuleDeclaration).name));
}
break;
default:
@@ -422,7 +466,7 @@ namespace ts.FindAllReferences.Core {
searchForImportsOfExport(node, symbol, { exportingModuleSymbol: Debug.assertDefined(symbol.parent, "Expected export symbol to have a parent"), exportKind: ExportKind.Default }, state);
}
else {
const search = state.createSearch(node, symbol, /*comingFrom*/ undefined, { allSearchSymbols: node ? populateSearchSymbolSet(symbol, node, checker, !!options.implementations) : [symbol] });
const search = state.createSearch(node, symbol, /*comingFrom*/ undefined, { allSearchSymbols: node ? populateSearchSymbolSet(symbol, node, checker, !!options.isForRename, !!options.implementations) : [symbol] });
// Try to get the smallest valid scope that we can limit our search to;
// otherwise we'll need to search globally (i.e. include each file).
@@ -581,21 +625,21 @@ namespace ts.FindAllReferences.Core {
* Callback to add references for a particular searched symbol.
* This initializes a reference group, so only call this if you will add at least one reference.
*/
referenceAdder(searchSymbol: Symbol): (node: Node) => void {
referenceAdder(searchSymbol: Symbol): (node: Node, kind?: NodeEntryKind) => void {
const symbolId = getSymbolId(searchSymbol);
let references = this.symbolIdToReferences[symbolId];
if (!references) {
references = this.symbolIdToReferences[symbolId] = [];
this.result.push({ definition: { type: DefinitionKind.Symbol, symbol: searchSymbol }, references });
}
return node => references.push(nodeEntry(node));
return (node, kind) => references.push(nodeEntry(node, kind));
}
/** Add a reference with no associated definition. */
addStringOrCommentReference(fileName: string, textSpan: TextSpan): void {
this.result.push({
definition: undefined,
references: [{ type: "span", fileName, textSpan }]
references: [{ kind: EntryKind.Span, fileName, textSpan }]
});
}
@@ -707,21 +751,6 @@ namespace ts.FindAllReferences.Core {
: undefined;
}
function getObjectBindingElementWithoutPropertyName(symbol: Symbol): BindingElement & { name: Identifier } | undefined {
const bindingElement = getDeclarationOfKind<BindingElement>(symbol, SyntaxKind.BindingElement);
if (bindingElement &&
bindingElement.parent.kind === SyntaxKind.ObjectBindingPattern &&
isIdentifier(bindingElement.name) &&
!bindingElement.propertyName) {
return bindingElement as BindingElement & { name: Identifier };
}
}
function getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol: Symbol, checker: TypeChecker): Symbol | undefined {
const bindingElement = getObjectBindingElementWithoutPropertyName(symbol);
return bindingElement && getPropertySymbolFromBindingElement(checker, bindingElement);
}
/**
* Determines the smallest scope in which a symbol may have named references.
* Note that not every construct has been accounted for. This function can
@@ -754,7 +783,7 @@ namespace ts.FindAllReferences.Core {
// If symbol is of object binding pattern element without property name we would want to
// look for property too and that could be anywhere
if (getObjectBindingElementWithoutPropertyName(symbol)) {
if (declarations.some(isObjectBindingElementWithoutPropertyName)) {
return undefined;
}
@@ -1099,13 +1128,14 @@ namespace ts.FindAllReferences.Core {
}
}
function addReference(referenceLocation: Node, relatedSymbol: Symbol, state: State): void {
const addRef = state.referenceAdder(relatedSymbol);
function addReference(referenceLocation: Node, relatedSymbol: Symbol | RelatedSymbol, state: State): void {
const { kind, symbol } = "kind" in relatedSymbol ? relatedSymbol : { kind: undefined, symbol: relatedSymbol };
const addRef = state.referenceAdder(symbol);
if (state.options.implementations) {
addImplementationReferences(referenceLocation, addRef, state);
}
else {
addRef(referenceLocation);
addRef(referenceLocation, kind);
}
}
@@ -1428,7 +1458,7 @@ namespace ts.FindAllReferences.Core {
const references = flatMap(sourceFiles, sourceFile => {
cancellationToken.throwIfCancellationRequested();
return mapDefined(getPossibleSymbolReferenceNodes(sourceFile, node.text), ref =>
isStringLiteral(ref) && ref.text === node.text ? nodeEntry(ref, /*isInString*/ true) : undefined);
isStringLiteral(ref) && ref.text === node.text ? nodeEntry(ref, EntryKind.StringLiteral) : undefined);
});
return [{
@@ -1439,35 +1469,21 @@ namespace ts.FindAllReferences.Core {
// For certain symbol kinds, we need to include other symbols in the search set.
// This is not needed when searching for re-exports.
function populateSearchSymbolSet(symbol: Symbol, location: Node, checker: TypeChecker, implementations: boolean): Symbol[] {
function populateSearchSymbolSet(symbol: Symbol, location: Node, checker: TypeChecker, isForRename: boolean, implementations: boolean): Symbol[] {
const result: Symbol[] = [];
forEachRelatedSymbol<void>(symbol, location, checker,
forEachRelatedSymbol<void>(symbol, location, checker, isForRename,
(sym, root, base) => { result.push(base || root || sym); },
/*allowBaseTypes*/ () => !implementations);
return result;
}
function forEachRelatedSymbol<T>(
symbol: Symbol, location: Node, checker: TypeChecker,
cbSymbol: (symbol: Symbol, rootSymbol?: Symbol, baseSymbol?: Symbol) => T | undefined,
symbol: Symbol, location: Node, checker: TypeChecker, isForRenamePopulateSearchSymbolSet: boolean,
cbSymbol: (symbol: Symbol, rootSymbol?: Symbol, baseSymbol?: Symbol, kind?: NodeEntryKind) => T | undefined,
allowBaseTypes: (rootSymbol: Symbol) => boolean,
): T | undefined {
const containingObjectLiteralElement = getContainingObjectLiteralElement(location);
if (containingObjectLiteralElement) {
// If the location is in a context sensitive location (i.e. in an object literal) try
// to get a contextual type for it, and add the property symbol from the contextual
// type to the search set
const contextualType = checker.getContextualType(containingObjectLiteralElement.parent);
const res = contextualType && firstDefined(getPropertySymbolsFromContextualType(containingObjectLiteralElement, checker, contextualType, /*unionSymbolOk*/ true), fromRoot);
if (res) return res;
// If the location is name of property symbol from object literal destructuring pattern
// Search the property symbol
// for ( { property: p2 } of elems) { }
const propertySymbol = getPropertySymbolOfDestructuringAssignment(location, checker);
const res1 = propertySymbol && cbSymbol(propertySymbol);
if (res1) return res1;
/* Because in short-hand property assignment, location has two meaning : property name and as value of the property
* When we do findAllReference at the position of the short-hand property assignment, we would want to have references to position of
* property name and variable declaration of the identifier.
@@ -1479,8 +1495,29 @@ namespace ts.FindAllReferences.Core {
* so that when matching with potential reference symbol, both symbols from property declaration and variable declaration
* will be included correctly.
*/
const shorthandValueSymbol = checker.getShorthandAssignmentValueSymbol(location.parent);
const res2 = shorthandValueSymbol && cbSymbol(shorthandValueSymbol);
const shorthandValueSymbol = checker.getShorthandAssignmentValueSymbol(location.parent); // gets the local symbol
if (shorthandValueSymbol && isForRenamePopulateSearchSymbolSet) {
// When renaming 'x' in `const o = { x }`, just rename the local variable, not the property.
return cbSymbol(shorthandValueSymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.SearchedLocalFoundProperty);
}
// If the location is in a context sensitive location (i.e. in an object literal) try
// to get a contextual type for it, and add the property symbol from the contextual
// type to the search set
const contextualType = checker.getContextualType(containingObjectLiteralElement.parent);
const res = contextualType && firstDefined(
getPropertySymbolsFromContextualType(containingObjectLiteralElement, checker, contextualType, /*unionSymbolOk*/ true),
sym => fromRoot(sym, EntryKind.SearchedPropertyFoundLocal));
if (res) return res;
// If the location is name of property symbol from object literal destructuring pattern
// Search the property symbol
// for ( { property: p2 } of elems) { }
const propertySymbol = getPropertySymbolOfDestructuringAssignment(location, checker);
const res1 = propertySymbol && cbSymbol(propertySymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.SearchedPropertyFoundLocal);
if (res1) return res1;
const res2 = shorthandValueSymbol && cbSymbol(shorthandValueSymbol, /*rootSymbol*/ undefined, /*baseSymbol*/ undefined, EntryKind.SearchedLocalFoundProperty);
if (res2) return res2;
}
@@ -1494,12 +1531,14 @@ namespace ts.FindAllReferences.Core {
return fromRoot(symbol.flags & SymbolFlags.FunctionScopedVariable ? paramProps[1] : paramProps[0]);
}
// If this is symbol of binding element without propertyName declaration in Object binding pattern
// Include the property in the search
const bindingElementPropertySymbol = getPropertySymbolOfObjectBindingPatternWithoutPropertyName(symbol, checker);
return bindingElementPropertySymbol && fromRoot(bindingElementPropertySymbol);
// symbolAtLocation for a binding element is the local symbol. See if the search symbol is the property.
// Don't do this when populating search set for a rename -- just rename the local.
if (!isForRenamePopulateSearchSymbolSet) {
const bindingElementPropertySymbol = isObjectBindingElementWithoutPropertyName(location.parent) ? getPropertySymbolFromBindingElement(checker, location.parent) : undefined;
return bindingElementPropertySymbol && fromRoot(bindingElementPropertySymbol, EntryKind.SearchedPropertyFoundLocal);
}
function fromRoot(sym: Symbol): T | undefined {
function fromRoot(sym: Symbol, kind?: NodeEntryKind): T | undefined {
// If this is a union property:
// - In populateSearchSymbolsSet we will add all the symbols from all its source symbols in all unioned types.
// - In findRelatedSymbol, we will just use the union symbol if any source symbol is included in the search.
@@ -1507,20 +1546,24 @@ namespace ts.FindAllReferences.Core {
// - In populateSearchSymbolsSet, add the root the list
// - In findRelatedSymbol, return the source symbol if that is in the search. (Do not return the instantiation symbol.)
return firstDefined(checker.getRootSymbols(sym), rootSymbol =>
cbSymbol(sym, rootSymbol)
cbSymbol(sym, rootSymbol, /*baseSymbol*/ undefined, kind)
// Add symbol of properties/methods of the same name in base classes and implemented interfaces definitions
|| (rootSymbol.parent && rootSymbol.parent.flags & (SymbolFlags.Class | SymbolFlags.Interface) && allowBaseTypes(rootSymbol)
? getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, checker, base => cbSymbol(sym, rootSymbol, base))
? getPropertySymbolsFromBaseTypes(rootSymbol.parent, rootSymbol.name, checker, base => cbSymbol(sym, rootSymbol, base, kind))
: undefined));
}
}
function getRelatedSymbol(search: Search, referenceSymbol: Symbol, referenceLocation: Node, state: State): Symbol | undefined {
interface RelatedSymbol {
readonly symbol: Symbol;
readonly kind: NodeEntryKind | undefined;
}
function getRelatedSymbol(search: Search, referenceSymbol: Symbol, referenceLocation: Node, state: State): RelatedSymbol | undefined {
const { checker } = state;
return forEachRelatedSymbol(referenceSymbol, referenceLocation, checker,
(sym, rootSymbol, baseSymbol) => search.includes(baseSymbol || rootSymbol || sym)
return forEachRelatedSymbol(referenceSymbol, referenceLocation, checker, /*isForRenamePopulateSearchSymbolSet*/ false,
(sym, rootSymbol, baseSymbol, kind): RelatedSymbol | undefined => search.includes(baseSymbol || rootSymbol || sym)
// For a base type, use the symbol for the derived type. For a synthetic (e.g. union) property, use the union symbol.
? rootSymbol && !(getCheckFlags(sym) & CheckFlags.Synthetic) ? rootSymbol : sym
? { symbol: rootSymbol && !(getCheckFlags(sym) & CheckFlags.Synthetic) ? rootSymbol : sym, kind }
: undefined,
/*allowBaseTypes*/ rootSymbol =>
!(search.parents && !search.parents.some(parent => explicitlyInheritsFrom(rootSymbol.parent!, parent, state.inheritsFromCache, checker))));
+3 -3
View File
@@ -753,17 +753,17 @@ namespace ts.formatting {
const listEndToken = getCloseTokenForOpenToken(listStartToken);
if (listEndToken !== SyntaxKind.Unknown && formattingScanner.isOnToken()) {
let tokenInfo = formattingScanner.readTokenInfo(parent);
let tokenInfo: TokenInfo | undefined = formattingScanner.readTokenInfo(parent);
if (tokenInfo.token.kind === SyntaxKind.CommaToken && isCallLikeExpression(parent)) {
formattingScanner.advance();
tokenInfo = formattingScanner.readTokenInfo(parent);
tokenInfo = formattingScanner.isOnToken() ? formattingScanner.readTokenInfo(parent) : undefined;
}
// consume the list end token only if it is still belong to the parent
// there might be the case when current token matches end token but does not considered as one
// function (x: function) <--
// without this check close paren will be interpreted as list end token for function expression which is wrong
if (tokenInfo.token.kind === listEndToken && rangeContainsRange(parent, tokenInfo.token)) {
if (tokenInfo && tokenInfo.token.kind === listEndToken && rangeContainsRange(parent, tokenInfo.token)) {
// consume list end token
consumeTokenAndAdvanceScanner(tokenInfo, parent, listDynamicIndentation, parent);
}
+16 -8
View File
@@ -72,7 +72,7 @@ namespace ts {
case "compilerOptions":
forEachProperty(property.initializer, (property, propertyName) => {
const option = getOptionFromName(propertyName);
if (option && (option.isFilePath || option.type === "list" && (option as CommandLineOptionOfListType).element.isFilePath)) {
if (option && (option.isFilePath || option.type === "list" && option.element.isFilePath)) {
updatePaths(property);
}
else if (propertyName === "paths") {
@@ -196,15 +196,23 @@ namespace ts {
}
function getSourceFileToImportFromResolved(resolved: ResolvedModuleWithFailedLookupLocations | undefined, oldToNew: PathUpdater, host: LanguageServiceHost): ToImport | undefined {
return resolved && (
(resolved.resolvedModule && getIfExists(resolved.resolvedModule.resolvedFileName)) || firstDefined(resolved.failedLookupLocations, getIfExists));
// Search through all locations looking for a moved file, and only then test already existing files.
// This is because if `a.ts` is compiled to `a.js` and `a.ts` is moved, we don't want to resolve anything to `a.js`, but to `a.ts`'s new location.
return tryEach(tryGetNewFile) || tryEach(tryGetOldFile);
function getIfExists(oldLocation: string): ToImport | undefined {
const newLocation = oldToNew(oldLocation);
function tryEach(cb: (oldFileName: string) => ToImport | undefined): ToImport | undefined {
return resolved && (
(resolved.resolvedModule && cb(resolved.resolvedModule.resolvedFileName)) || firstDefined(resolved.failedLookupLocations, cb));
}
return host.fileExists!(oldLocation) || newLocation !== undefined && host.fileExists!(newLocation) // TODO: GH#18217
? newLocation !== undefined ? { newFileName: newLocation, updated: true } : { newFileName: oldLocation, updated: false }
: undefined;
function tryGetNewFile(oldFileName: string): ToImport | undefined {
const newFileName = oldToNew(oldFileName);
return newFileName !== undefined && host.fileExists!(newFileName) ? { newFileName, updated: true } : undefined; // TODO: GH#18217
}
function tryGetOldFile(oldFileName: string): ToImport | undefined {
const newFileName = oldToNew(oldFileName);
return host.fileExists!(oldFileName) ? newFileName !== undefined ? { newFileName, updated: true } : { newFileName: oldFileName, updated: false } : undefined; // TODO: GH#18217
}
}
+4 -4
View File
@@ -385,7 +385,7 @@ namespace ts.FindAllReferences {
}
/** Iterates over all statements at the top level or in module declarations. Returns the first truthy result. */
function forEachPossibleImportOrExportStatement<T>(sourceFileLike: SourceFileLike, action: (statement: Statement) => T): T | undefined {
function forEachPossibleImportOrExportStatement<T>(sourceFileLike: SourceFileLike, action: (statement: Statement) => T) {
return forEach(sourceFileLike.kind === SyntaxKind.SourceFile ? sourceFileLike.statements : sourceFileLike.body!.statements, statement => // TODO: GH#18217
action(statement) || (isAmbientModuleDeclaration(statement) && forEach(statement.body && statement.body.statements, action)));
}
@@ -502,11 +502,11 @@ namespace ts.FindAllReferences {
function getSpecialPropertyExport(node: BinaryExpression, useLhsSymbol: boolean): ExportedSymbol | undefined {
let kind: ExportKind;
switch (getSpecialPropertyAssignmentKind(node)) {
case SpecialPropertyAssignmentKind.ExportsProperty:
switch (getAssignmentDeclarationKind(node)) {
case AssignmentDeclarationKind.ExportsProperty:
kind = ExportKind.Named;
break;
case SpecialPropertyAssignmentKind.ModuleExports:
case AssignmentDeclarationKind.ModuleExports:
kind = ExportKind.ExportEquals;
break;
default:
+4 -4
View File
@@ -208,7 +208,7 @@ namespace ts.JsDoc {
kindModifiers: "",
displayParts: [textPart(name)],
documentation: emptyArray,
tags: emptyArray,
tags: undefined,
codeActions: undefined,
};
}
@@ -242,7 +242,7 @@ namespace ts.JsDoc {
kindModifiers: "",
displayParts: [textPart(name)],
documentation: emptyArray,
tags: emptyArray,
tags: undefined,
codeActions: undefined,
};
}
@@ -312,7 +312,7 @@ namespace ts.JsDoc {
const preamble = "/**" + newLine + indentationStr + " * ";
const result =
preamble + newLine +
parameterDocComments(parameters, hasJavaScriptFileExtension(sourceFile.fileName), indentationStr, newLine) +
parameterDocComments(parameters, hasJSFileExtension(sourceFile.fileName), indentationStr, newLine) +
indentationStr + " */" +
(tokenStart === position ? newLine + indentationStr : "");
@@ -383,7 +383,7 @@ namespace ts.JsDoc {
case SyntaxKind.BinaryExpression: {
const be = commentOwner as BinaryExpression;
if (getSpecialPropertyAssignmentKind(be) === SpecialPropertyAssignmentKind.None) {
if (getAssignmentDeclarationKind(be) === AssignmentDeclarationKind.None) {
return "quit";
}
const parameters = isFunctionLike(be.right) ? be.right.parameters : emptyArray;
+38 -16
View File
@@ -270,17 +270,17 @@ namespace ts.NavigationBar {
break;
case SyntaxKind.BinaryExpression: {
const special = getSpecialPropertyAssignmentKind(node as BinaryExpression);
const special = getAssignmentDeclarationKind(node as BinaryExpression);
switch (special) {
case SpecialPropertyAssignmentKind.ExportsProperty:
case SpecialPropertyAssignmentKind.ModuleExports:
case SpecialPropertyAssignmentKind.PrototypeProperty:
case SpecialPropertyAssignmentKind.Prototype:
case AssignmentDeclarationKind.ExportsProperty:
case AssignmentDeclarationKind.ModuleExports:
case AssignmentDeclarationKind.PrototypeProperty:
case AssignmentDeclarationKind.Prototype:
addNodeWithRecursiveChild(node, (node as BinaryExpression).right);
return;
case SpecialPropertyAssignmentKind.ThisProperty:
case SpecialPropertyAssignmentKind.Property:
case SpecialPropertyAssignmentKind.None:
case AssignmentDeclarationKind.ThisProperty:
case AssignmentDeclarationKind.Property:
case AssignmentDeclarationKind.None:
break;
default:
Debug.assertNever(special);
@@ -631,28 +631,50 @@ namespace ts.NavigationBar {
}
function getFunctionOrClassName(node: FunctionExpression | FunctionDeclaration | ArrowFunction | ClassLikeDeclaration): string {
const { parent } = node;
if (node.name && getFullWidth(node.name) > 0) {
return declarationNameToString(node.name);
}
// See if it is a var initializer. If so, use the var name.
else if (node.parent.kind === SyntaxKind.VariableDeclaration) {
return declarationNameToString((node.parent as VariableDeclaration).name);
else if (isVariableDeclaration(parent)) {
return declarationNameToString(parent.name);
}
// See if it is of the form "<expr> = function(){...}". If so, use the text from the left-hand side.
else if (node.parent.kind === SyntaxKind.BinaryExpression &&
(node.parent as BinaryExpression).operatorToken.kind === SyntaxKind.EqualsToken) {
return nodeText((node.parent as BinaryExpression).left).replace(whiteSpaceRegex, "");
else if (isBinaryExpression(parent) && parent.operatorToken.kind === SyntaxKind.EqualsToken) {
return nodeText(parent.left).replace(whiteSpaceRegex, "");
}
// See if it is a property assignment, and if so use the property name
else if (node.parent.kind === SyntaxKind.PropertyAssignment && (node.parent as PropertyAssignment).name) {
return nodeText((node.parent as PropertyAssignment).name);
else if (isPropertyAssignment(parent)) {
return nodeText(parent.name);
}
// Default exports are named "default"
else if (getModifierFlags(node) & ModifierFlags.Default) {
return "default";
}
else if (isClassLike(node)) {
return "<class>";
}
else if (isCallExpression(parent)) {
const name = getCalledExpressionName(parent.expression);
if (name !== undefined) {
const args = mapDefined(parent.arguments, a => isStringLiteral(a) ? a.getText(curSourceFile) : undefined).join(", ");
return `${name}(${args}) callback`;
}
}
return "<function>";
}
function getCalledExpressionName(expr: Expression): string | undefined {
if (isIdentifier(expr)) {
return expr.text;
}
else if (isPropertyAccessExpression(expr)) {
const left = getCalledExpressionName(expr.expression);
const right = expr.name.text;
return left === undefined ? right : `${left}.${right}`;
}
else {
return isClassLike(node) ? "<class>" : "<function>";
return undefined;
}
}
+48 -15
View File
@@ -151,11 +151,41 @@ namespace ts.Completions.PathCompletions {
}
}
}
// check for a version redirect
const packageJsonPath = findPackageJson(baseDirectory, host);
if (packageJsonPath) {
const packageJson = readJson(packageJsonPath, host as { readFile: (filename: string) => string | undefined });
const typesVersions = (packageJson as any).typesVersions;
if (typeof typesVersions === "object") {
const versionResult = getPackageJsonTypesVersionsPaths(typesVersions);
const versionPaths = versionResult && versionResult.paths;
const rest = absolutePath.slice(ensureTrailingDirectorySeparator(baseDirectory).length);
if (versionPaths) {
addCompletionEntriesFromPaths(result, rest, baseDirectory, extensions, versionPaths, host);
}
}
}
}
return result;
}
function addCompletionEntriesFromPaths(result: NameAndKind[], fragment: string, baseDirectory: string, fileExtensions: ReadonlyArray<string>, paths: MapLike<string[]>, host: LanguageServiceHost) {
for (const path in paths) {
if (!hasProperty(paths, path)) continue;
const patterns = paths[path];
if (patterns) {
for (const { name, kind } of getCompletionsForPathMapping(path, patterns, fragment, baseDirectory, fileExtensions, host)) {
// Path mappings may provide a duplicate way to get to something we've already added, so don't add again.
if (!result.some(entry => entry.name === name)) {
result.push(nameAndKind(name, kind));
}
}
}
}
}
/**
* Check all of the declared modules and those in node modules. Possible sources of modules:
* Modules that are found by the type checker
@@ -171,19 +201,10 @@ namespace ts.Completions.PathCompletions {
const fileExtensions = getSupportedExtensionsForModuleResolution(compilerOptions);
if (baseUrl) {
const projectDir = compilerOptions.project || host.getCurrentDirectory();
const absolute = isRootedDiskPath(baseUrl) ? baseUrl : combinePaths(projectDir, baseUrl);
getCompletionEntriesForDirectoryFragment(fragment, normalizePath(absolute), fileExtensions, /*includeExtensions*/ false, host, /*exclude*/ undefined, result);
for (const path in paths!) {
const patterns = paths![path];
if (paths!.hasOwnProperty(path) && patterns) {
for (const { name, kind } of getCompletionsForPathMapping(path, patterns, fragment, baseUrl, fileExtensions, host)) {
// Path mappings may provide a duplicate way to get to something we've already added, so don't add again.
if (!result.some(entry => entry.name === name)) {
result.push(nameAndKind(name, kind));
}
}
}
const absolute = normalizePath(combinePaths(projectDir, baseUrl));
getCompletionEntriesForDirectoryFragment(fragment, absolute, fileExtensions, /*includeExtensions*/ false, host, /*exclude*/ undefined, result);
if (paths) {
addCompletionEntriesFromPaths(result, fragment, absolute, fileExtensions, paths, host);
}
}
@@ -329,7 +350,7 @@ namespace ts.Completions.PathCompletions {
const seen = createMap<true>();
if (options.types) {
for (const typesName of options.types) {
const moduleName = getUnmangledNameForScopedPackage(typesName);
const moduleName = unmangleScopedPackageName(typesName);
pushResult(moduleName);
}
}
@@ -363,7 +384,7 @@ namespace ts.Completions.PathCompletions {
for (let typeDirectory of directories) {
typeDirectory = normalizePath(typeDirectory);
const directoryName = getBaseFileName(typeDirectory);
const moduleName = getUnmangledNameForScopedPackage(directoryName);
const moduleName = unmangleScopedPackageName(directoryName);
pushResult(moduleName);
}
}
@@ -390,6 +411,18 @@ namespace ts.Completions.PathCompletions {
return paths;
}
function findPackageJson(directory: string, host: LanguageServiceHost): string | undefined {
let packageJson: string | undefined;
forEachAncestorDirectory(directory, ancestor => {
if (ancestor === "node_modules") return true;
packageJson = findConfigFile(ancestor, (f) => tryFileExists(host, f), "package.json");
if (packageJson) {
return true; // break out
}
});
return packageJson;
}
function enumerateNodeModulesVisibleToScript(host: LanguageServiceHost, scriptPath: string): ReadonlyArray<string> {
if (!host.readFile || !host.fileExists) return emptyArray;
+3 -3
View File
@@ -719,7 +719,7 @@ namespace ts.refactor.extractSymbol {
// Make a unique name for the extracted function
const file = scope.getSourceFile();
const functionNameText = getUniqueName(isClassLike(scope) ? "newMethod" : "newFunction", file);
const isJS = isInJavaScriptFile(scope);
const isJS = isInJSFile(scope);
const functionName = createIdentifier(functionNameText);
@@ -1006,7 +1006,7 @@ namespace ts.refactor.extractSymbol {
// Make a unique name for the extracted variable
const file = scope.getSourceFile();
const localNameText = getUniqueName(isClassLike(scope) ? "newProperty" : "newLocal", file);
const isJS = isInJavaScriptFile(scope);
const isJS = isInJSFile(scope);
const variableType = isJS || !checker.isContextSensitive(node)
? undefined
@@ -1424,7 +1424,7 @@ namespace ts.refactor.extractSymbol {
if (expressionDiagnostic) {
constantErrors.push(expressionDiagnostic);
}
if (isClassLike(scope) && isInJavaScriptFile(scope)) {
if (isClassLike(scope) && isInJSFile(scope)) {
constantErrors.push(createDiagnosticForNode(scope, Messages.cannotExtractToJSClass));
}
if (isArrowFunction(scope) && !isBlock(scope.body)) {

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