mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge branch 'master' into preserveTypeAliases
# Conflicts: # tests/baselines/reference/modularizeLibrary_UsingES5LibAndES6FeatureLibs.types
This commit is contained in:
commit
4c9675cc44
95 files changed
+2228
-494
No files matched your search
+12
-3
@@ -189,16 +189,25 @@ import { f as g } from "file1";
|
||||
var x = g();
|
||||
```
|
||||
|
||||
## Managing the Baselines
|
||||
## Managing the baselines
|
||||
|
||||
Compiler tests generate baselines: one file each for the emitted `.js`, the errors produced by the compiler, the type of each expression, and symbol for each identifier. Additionally, some tests generate baselines for the source map output.
|
||||
Most tests generate "baselines" to find differences in output.
|
||||
As an example, compiler tests usually emit one file each for
|
||||
|
||||
- the `.js` and `.d.ts` output (all in the same `.js` output file),
|
||||
- the errors produced by the compiler (in an `.errors.txt` file),
|
||||
- the types of each expression (in a `.types` file),
|
||||
- the symbols for each identifier (in a `.symbols` file), and
|
||||
- the source map outputs for files if a test opts into them (in a `.js.map` file).
|
||||
|
||||
When a change in the baselines is detected, the test will fail. To inspect changes vs the expected baselines, use
|
||||
|
||||
```Shell
|
||||
gulp diff
|
||||
git diff --diff-filter=AM --no-index ./tests/baselines/reference ./tests/baselines/local
|
||||
```
|
||||
|
||||
Alternatively, you can set the `DIFF` environment variable and run `gulp diff`, or manually run your favorite folder diffing tool between `tests/baselines/reference` and `tests/baselines/local`. Our team largely uses Beyond Compare and WinMerge.
|
||||
|
||||
After verifying that the changes in the baselines are correct, run
|
||||
|
||||
```Shell
|
||||
|
||||
Generated
+6
-6
@@ -585,9 +585,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "14.14.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.14.tgz",
|
||||
"integrity": "sha512-UHnOPWVWV1z+VV8k6L1HhG7UbGBgIdghqF3l9Ny9ApPghbjICXkUJSd/b9gOgQfjM1r+37cipdw/HJ3F6ICEnQ==",
|
||||
"version": "14.14.19",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.14.19.tgz",
|
||||
"integrity": "sha512-4nhBPStMK04rruRVtVc6cDqhu7S9GZai0fpXgPXrFpcPX6Xul8xnrjSdGB4KPBVYG/R5+fXWdCM8qBoiULWGPQ==",
|
||||
"dev": true
|
||||
},
|
||||
"@types/node-fetch": {
|
||||
@@ -7912,9 +7912,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"uglify-js": {
|
||||
"version": "3.12.2",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.12.2.tgz",
|
||||
"integrity": "sha512-rWYleAvfJPjduYCt+ELvzybNah/zIkRteGXIBO8X0lteRZPGladF61hFi8tU7qKTsF7u6DUQCtT9k00VlFOgkg==",
|
||||
"version": "3.12.4",
|
||||
"resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.12.4.tgz",
|
||||
"integrity": "sha512-L5i5jg/SHkEqzN18gQMTWsZk3KelRsfD1wUVNqtq0kzqWQqcJjyL8yc1o8hJgRrWqrAl2mUFbhfznEIoi7zi2A==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
|
||||
@@ -5933,7 +5933,7 @@ namespace ts {
|
||||
return factory.createPropertySignature(
|
||||
/*modifiers*/ undefined,
|
||||
name,
|
||||
t.typeExpression && isJSDocOptionalType(t.typeExpression.type) ? factory.createToken(SyntaxKind.QuestionToken) : undefined,
|
||||
t.isBracketed || t.typeExpression && isJSDocOptionalType(t.typeExpression.type) ? factory.createToken(SyntaxKind.QuestionToken) : undefined,
|
||||
overrideTypeNode || (t.typeExpression && visitNode(t.typeExpression.type, visitExistingNodeTreeSymbols)) || factory.createKeywordTypeNode(SyntaxKind.AnyKeyword)
|
||||
);
|
||||
}));
|
||||
@@ -33470,7 +33470,7 @@ namespace ts {
|
||||
if (isInJSFile(node)) {
|
||||
const typeTag = getJSDocTypeTag(node);
|
||||
if (typeTag && typeTag.typeExpression && !getContextualCallSignature(getTypeFromTypeNode(typeTag.typeExpression), node)) {
|
||||
error(typeTag, Diagnostics.The_type_of_a_function_declaration_must_match_the_function_s_signature);
|
||||
error(typeTag.typeExpression.type, Diagnostics.The_type_of_a_function_declaration_must_match_the_function_s_signature);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -40222,7 +40222,9 @@ namespace ts {
|
||||
if (node.exclamationToken && (node.parent.parent.kind !== SyntaxKind.VariableStatement || !node.type || node.initializer || node.flags & NodeFlags.Ambient)) {
|
||||
const message = node.initializer
|
||||
? Diagnostics.Declarations_with_initializers_cannot_also_have_definite_assignment_assertions
|
||||
: Diagnostics.Declarations_with_definite_assignment_assertions_must_also_have_type_annotations;
|
||||
: !node.type
|
||||
? Diagnostics.Declarations_with_definite_assignment_assertions_must_also_have_type_annotations
|
||||
: Diagnostics.A_definite_assignment_assertion_is_not_permitted_in_this_context;
|
||||
return grammarErrorOnNode(node.exclamationToken, message);
|
||||
}
|
||||
|
||||
|
||||
@@ -6143,6 +6143,34 @@
|
||||
"category": "Message",
|
||||
"code": 95148
|
||||
},
|
||||
"Return type must be inferred from a function": {
|
||||
"category": "Message",
|
||||
"code": 95149
|
||||
},
|
||||
"Could not determine function return type": {
|
||||
"category": "Message",
|
||||
"code": 95150
|
||||
},
|
||||
"Could not convert to arrow function": {
|
||||
"category": "Message",
|
||||
"code": 95151
|
||||
},
|
||||
"Could not convert to named function": {
|
||||
"category": "Message",
|
||||
"code": 95152
|
||||
},
|
||||
"Could not convert to anonymous function": {
|
||||
"category": "Message",
|
||||
"code": 95153
|
||||
},
|
||||
"Can only convert string concatenation": {
|
||||
"category": "Message",
|
||||
"code": 95154
|
||||
},
|
||||
"Selection is not a valid statement or statements": {
|
||||
"category": "Message",
|
||||
"code": 95155
|
||||
},
|
||||
|
||||
"No value exists in scope for the shorthand property '{0}'. Either declare one or provide an initializer.": {
|
||||
"category": "Error",
|
||||
|
||||
@@ -2992,7 +2992,7 @@ namespace ts {
|
||||
}
|
||||
|
||||
export function getEffectiveImplementsTypeNodes(node: ClassLikeDeclaration): undefined | readonly ExpressionWithTypeArguments[]{
|
||||
if(isInJSFile(node)) {
|
||||
if (isInJSFile(node)) {
|
||||
return getJSDocImplementsTags(node).map(n => n.class);
|
||||
}
|
||||
else {
|
||||
|
||||
@@ -3420,6 +3420,12 @@ namespace FourSlash {
|
||||
}
|
||||
}
|
||||
|
||||
public verifyRefactorKindsAvailable(kind: string, expected: string[], preferences = ts.emptyOptions) {
|
||||
const refactors = this.getApplicableRefactorsAtSelection("invoked", kind, preferences);
|
||||
const availableKinds = ts.flatMap(refactors, refactor => refactor.actions).map(action => action.kind);
|
||||
assert.deepEqual(availableKinds.sort(), expected.sort(), `Expected kinds to be equal`);
|
||||
}
|
||||
|
||||
public verifyRefactorsAvailable(names: readonly string[]): void {
|
||||
assert.deepEqual(unique(this.getApplicableRefactorsAtSelection(), r => r.name), names);
|
||||
}
|
||||
@@ -3833,14 +3839,14 @@ namespace FourSlash {
|
||||
test(renameKeys(newFileContents, key => pathUpdater(key) || key), "with file moved");
|
||||
}
|
||||
|
||||
private getApplicableRefactorsAtSelection(triggerReason: ts.RefactorTriggerReason = "implicit") {
|
||||
return this.getApplicableRefactorsWorker(this.getSelection(), this.activeFile.fileName, ts.emptyOptions, triggerReason);
|
||||
private getApplicableRefactorsAtSelection(triggerReason: ts.RefactorTriggerReason = "implicit", kind?: string, preferences = ts.emptyOptions) {
|
||||
return this.getApplicableRefactorsWorker(this.getSelection(), this.activeFile.fileName, preferences, triggerReason, kind);
|
||||
}
|
||||
private getApplicableRefactors(rangeOrMarker: Range | Marker, preferences = ts.emptyOptions, triggerReason: ts.RefactorTriggerReason = "implicit"): readonly ts.ApplicableRefactorInfo[] {
|
||||
return this.getApplicableRefactorsWorker("position" in rangeOrMarker ? rangeOrMarker.position : rangeOrMarker, rangeOrMarker.fileName, preferences, triggerReason); // eslint-disable-line no-in-operator
|
||||
private getApplicableRefactors(rangeOrMarker: Range | Marker, preferences = ts.emptyOptions, triggerReason: ts.RefactorTriggerReason = "implicit", kind?: string): readonly ts.ApplicableRefactorInfo[] {
|
||||
return this.getApplicableRefactorsWorker("position" in rangeOrMarker ? rangeOrMarker.position : rangeOrMarker, rangeOrMarker.fileName, preferences, triggerReason, kind); // eslint-disable-line no-in-operator
|
||||
}
|
||||
private getApplicableRefactorsWorker(positionOrRange: number | ts.TextRange, fileName: string, preferences = ts.emptyOptions, triggerReason: ts.RefactorTriggerReason): readonly ts.ApplicableRefactorInfo[] {
|
||||
return this.languageService.getApplicableRefactors(fileName, positionOrRange, preferences, triggerReason) || ts.emptyArray;
|
||||
private getApplicableRefactorsWorker(positionOrRange: number | ts.TextRange, fileName: string, preferences = ts.emptyOptions, triggerReason: ts.RefactorTriggerReason, kind?: string): readonly ts.ApplicableRefactorInfo[] {
|
||||
return this.languageService.getApplicableRefactors(fileName, positionOrRange, preferences, triggerReason, kind) || ts.emptyArray;
|
||||
}
|
||||
|
||||
public configurePlugin(pluginName: string, configuration: any): void {
|
||||
|
||||
@@ -215,6 +215,10 @@ namespace FourSlashInterface {
|
||||
this.state.verifyRefactorAvailable(this.negative, triggerReason, name, actionName);
|
||||
}
|
||||
|
||||
public refactorKindAvailable(kind: string, expected: string[], preferences = ts.emptyOptions) {
|
||||
this.state.verifyRefactorKindsAvailable(kind, expected, preferences);
|
||||
}
|
||||
|
||||
public toggleLineComment(newFileContent: string) {
|
||||
this.state.toggleLineComment(newFileContent);
|
||||
}
|
||||
|
||||
Vendored
+92
-4
@@ -1,15 +1,103 @@
|
||||
declare namespace Reflect {
|
||||
/**
|
||||
* Calls the function with the specified object as the this value
|
||||
* and the elements of specified array as the arguments.
|
||||
* @param target The function to call.
|
||||
* @param thisArgument The object to be used as the this object.
|
||||
* @param argumentsList An array of argument values to be passed to the function.
|
||||
*/
|
||||
function apply(target: Function, thisArgument: any, argumentsList: ArrayLike<any>): any;
|
||||
function construct(target: Function, argumentsList: ArrayLike<any>, newTarget?: any): any;
|
||||
|
||||
/**
|
||||
* Constructs the target with the elements of specified array as the arguments
|
||||
* and the specified constructor as the `new.target` value.
|
||||
* @param target The constructor to invoke.
|
||||
* @param argumentsList An array of argument values to be passed to the constructor.
|
||||
* @param newTarget The constructor to be used as the `new.target` object.
|
||||
*/
|
||||
function construct(target: Function, argumentsList: ArrayLike<any>, newTarget?: Function): any;
|
||||
|
||||
/**
|
||||
* Adds a property to an object, or modifies attributes of an existing property.
|
||||
* @param target Object on which to add or modify the property. This can be a native JavaScript object
|
||||
* (that is, a user-defined object or a built in object) or a DOM object.
|
||||
* @param propertyKey The property name.
|
||||
* @param attributes Descriptor for the property. It can be for a data property or an accessor property.
|
||||
*/
|
||||
function defineProperty(target: object, propertyKey: PropertyKey, attributes: PropertyDescriptor): boolean;
|
||||
|
||||
/**
|
||||
* Removes a property from an object, equivalent to `delete target[propertyKey]`,
|
||||
* except it won't throw if `target[propertyKey]` is non-configurable.
|
||||
* @param target Object from which to remove the own property.
|
||||
* @param propertyKey The property name.
|
||||
*/
|
||||
function deleteProperty(target: object, propertyKey: PropertyKey): boolean;
|
||||
|
||||
/**
|
||||
* Gets the property of target, equivalent to `target[propertyKey]` when `receiver === target`.
|
||||
* @param target Object that contains the property on itself or in its prototype chain.
|
||||
* @param propertyKey The property name.
|
||||
* @param receiver The reference to use as the `this` value in the getter function,
|
||||
* if `target[propertyKey]` is an accessor property.
|
||||
*/
|
||||
function get(target: object, propertyKey: PropertyKey, receiver?: any): any;
|
||||
|
||||
/**
|
||||
* Gets the own property descriptor of the specified object.
|
||||
* An own property descriptor is one that is defined directly on the object and is not inherited from the object's prototype.
|
||||
* @param target Object that contains the property.
|
||||
* @param propertyKey The property name.
|
||||
*/
|
||||
function getOwnPropertyDescriptor(target: object, propertyKey: PropertyKey): PropertyDescriptor | undefined;
|
||||
function getPrototypeOf(target: object): object;
|
||||
|
||||
/**
|
||||
* Returns the prototype of an object.
|
||||
* @param target The object that references the prototype.
|
||||
*/
|
||||
function getPrototypeOf(target: object): object | null;
|
||||
|
||||
/**
|
||||
* Equivalent to `propertyKey in target`.
|
||||
* @param target Object that contains the property on itself or in its prototype chain.
|
||||
* @param propertyKey Name of the property.
|
||||
*/
|
||||
function has(target: object, propertyKey: PropertyKey): boolean;
|
||||
|
||||
/**
|
||||
* Returns a value that indicates whether new properties can be added to an object.
|
||||
* @param target Object to test.
|
||||
*/
|
||||
function isExtensible(target: object): boolean;
|
||||
function ownKeys(target: object): PropertyKey[];
|
||||
|
||||
/**
|
||||
* Returns the string and symbol keys of the own properties of an object. The own properties of an object
|
||||
* are those that are defined directly on that object, and are not inherited from the object's prototype.
|
||||
* @param target Object that contains the own properties.
|
||||
*/
|
||||
function ownKeys(target: object): (string | symbol)[];
|
||||
|
||||
/**
|
||||
* Prevents the addition of new properties to an object.
|
||||
* @param target Object to make non-extensible.
|
||||
* @return Whether the object has been made non-extensible.
|
||||
*/
|
||||
function preventExtensions(target: object): boolean;
|
||||
|
||||
/**
|
||||
* Sets the property of target, equivalent to `target[propertyKey] = value` when `receiver === target`.
|
||||
* @param target Object that contains the property on itself or in its prototype chain.
|
||||
* @param propertyKey Name of the property.
|
||||
* @param receiver The reference to use as the `this` value in the setter function,
|
||||
* if `target[propertyKey]` is an accessor property.
|
||||
*/
|
||||
function set(target: object, propertyKey: PropertyKey, value: any, receiver?: any): boolean;
|
||||
function setPrototypeOf(target: object, proto: any): boolean;
|
||||
|
||||
/**
|
||||
* Sets the prototype of a specified object o to object proto or null.
|
||||
* @param target The object to change its prototype.
|
||||
* @param proto The value of the new prototype or null.
|
||||
* @return Whether setting the prototype was successful.
|
||||
*/
|
||||
function setPrototypeOf(target: object, proto: object | null): boolean;
|
||||
}
|
||||
Vendored
+236
-16
@@ -54,6 +54,239 @@ declare namespace Intl {
|
||||
*/
|
||||
type RelativeTimeFormatStyle = "long" | "short" | "narrow";
|
||||
|
||||
/**
|
||||
* Unicode Calendar Identifier
|
||||
*
|
||||
* [Reference](http://unicode.org/reports/tr35/#UnicodeCalendarIdentifier)
|
||||
*
|
||||
* [Source](https://github.com/unicode-org/cldr/blob/b805d0b/common/bcp47/calendar.xml)
|
||||
*/
|
||||
type Calendar =
|
||||
// Thai Buddhist calendar
|
||||
| "buddhist"
|
||||
// Traditional Chinese calendar
|
||||
| "chinese"
|
||||
// Coptic calendar
|
||||
| "coptic"
|
||||
// Traditional Korean calendar
|
||||
| "dangi"
|
||||
// Ethiopic calendar, Amete Alem (epoch approx. 5493 B.C.E)
|
||||
| "ethiopic-amete-alem" | "ethioaa"
|
||||
// Ethiopic calendar, Amete Mihret (epoch approx, 8 C.E.)
|
||||
| "ethiopic"
|
||||
// Gregorian calendar
|
||||
| "gregorian"
|
||||
// Gregorian calendar (alias)
|
||||
| "gregory"
|
||||
// Traditional Hebrew calendar
|
||||
| "hebrew"
|
||||
// Indian calendar
|
||||
| "indian"
|
||||
// Islamic calendar
|
||||
| "islamic"
|
||||
// Islamic calendar, Umm al-Qura
|
||||
| "islamic-umalqura"
|
||||
// Islamic calendar, tabular (intercalary years [2,5,7,10,13,16,18,21,24,26,29] - astronomical epoch)
|
||||
| "islamic-tbla"
|
||||
// Islamic calendar, tabular (intercalary years [2,5,7,10,13,16,18,21,24,26,29] - civil epoch)
|
||||
| "islamic-civil"
|
||||
| "islamicc" // Deprecated alias
|
||||
// Islamic calendar, Saudi Arabia sighting
|
||||
| "islamic-rgsa"
|
||||
// ISO calendar (Gregorian calendar using the ISO 8601 calendar week rules)
|
||||
| "iso8601"
|
||||
// Japanese Imperial calendar
|
||||
| "japanese"
|
||||
// Persian calendar
|
||||
| "persian"
|
||||
// Republic of China calendar
|
||||
| "roc"
|
||||
;
|
||||
|
||||
/**
|
||||
* Unicode Number System Identifier
|
||||
*
|
||||
* [Reference](http://unicode.org/reports/tr35/#UnicodeNumberSystemIdentifier)
|
||||
*
|
||||
* [Source](https://github.com/unicode-org/cldr/blob/be7a953/common/bcp47/number.xml)
|
||||
*/
|
||||
type NumberingSystem =
|
||||
// Adlam digits
|
||||
| "adlm"
|
||||
// Ahom digits
|
||||
| "ahom"
|
||||
// Arabic-Indic digits
|
||||
| "arab"
|
||||
// Extended Arabic-Indic digits
|
||||
| "arabext"
|
||||
// Armenian upper case numerals — algorithmic
|
||||
| "armn"
|
||||
// Armenian lower case numerals — algorithmic
|
||||
| "armnlow"
|
||||
// Balinese digits
|
||||
| "bali"
|
||||
// Bengali digits
|
||||
| "beng"
|
||||
// Bhaiksuki digits
|
||||
| "bhks"
|
||||
// Brahmi digits
|
||||
| "brah"
|
||||
// Chakma digits
|
||||
| "cakm"
|
||||
// Cham digits
|
||||
| "cham"
|
||||
// Cyrillic numerals — algorithmic
|
||||
| "cyrl"
|
||||
// Devanagari digits
|
||||
| "deva"
|
||||
// Dives Akuru digits
|
||||
| "diak"
|
||||
// Ethiopic numerals — algorithmic
|
||||
| "ethi"
|
||||
// Financial numerals — may be algorithmic
|
||||
| "finance"
|
||||
// Full width digits
|
||||
| "fullwide"
|
||||
// Georgian numerals — algorithmic
|
||||
| "geor"
|
||||
// Gunjala Gondi digits
|
||||
| "gong"
|
||||
// Masaram Gondi digits
|
||||
| "gonm"
|
||||
// Greek upper case numerals — algorithmic
|
||||
| "grek"
|
||||
// Greek lower case numerals — algorithmic
|
||||
| "greklow"
|
||||
// Gujarati digits
|
||||
| "gujr"
|
||||
// Gurmukhi digits
|
||||
| "guru"
|
||||
// Han-character day-of-month numbering for lunar/other traditional calendars"
|
||||
| "hanidays"
|
||||
// Positional decimal system using Chinese number ideographs as digits
|
||||
| "hanidec"
|
||||
// Simplified Chinese numerals — algorithmic
|
||||
| "hans"
|
||||
// Simplified Chinese financial numerals — algorithmic
|
||||
| "hansfin"
|
||||
// Traditional Chinese numerals — algorithmic
|
||||
| "hant"
|
||||
// Traditional Chinese financial numerals — algorithmic
|
||||
| "hantfin"
|
||||
// Hebrew numerals — algorithmic
|
||||
| "hebr"
|
||||
// Pahawh Hmong digits
|
||||
| "hmng"
|
||||
// Nyiakeng Puachue Hmong digits
|
||||
| "hmnp"
|
||||
// Javanese digits
|
||||
| "java"
|
||||
// Japanese numerals — algorithmic
|
||||
| "jpan"
|
||||
// Japanese financial numerals — algorithmic
|
||||
| "jpanfin"
|
||||
// Japanese first-year Gannen numbering for Japanese calendar
|
||||
| "jpanyear"
|
||||
// Kayah Li digits
|
||||
| "kali"
|
||||
// Khmer digits
|
||||
| "khmr"
|
||||
// Kannada digits
|
||||
| "knda"
|
||||
// Tai Tham Hora (secular) digits
|
||||
| "lana"
|
||||
// Tai Tham Tham (ecclesiastical) digits
|
||||
| "lanatham"
|
||||
// Lao digits
|
||||
| "laoo"
|
||||
// Latin digits
|
||||
| "latn"
|
||||
// Lepcha digits
|
||||
| "lepc"
|
||||
// Limbu digits
|
||||
| "limb"
|
||||
// Mathematical bold digits
|
||||
| "mathbold"
|
||||
// Mathematical double-struck digits
|
||||
| "mathdbl"
|
||||
// Mathematical monospace digits
|
||||
| "mathmono"
|
||||
// Mathematical sans-serif bold digits
|
||||
| "mathsanb"
|
||||
// Mathematical sans-serif digits
|
||||
| "mathsans"
|
||||
// Malayalam digits
|
||||
| "mlym"
|
||||
// Modi digits
|
||||
| "modi"
|
||||
// Mongolian digits
|
||||
| "mong"
|
||||
// Mro digits
|
||||
| "mroo"
|
||||
// Meetei Mayek digits
|
||||
| "mtei"
|
||||
// Myanmar digits
|
||||
| "mymr"
|
||||
// Myanmar Shan digits
|
||||
| "mymrshan"
|
||||
// Myanmar Tai Laing digits
|
||||
| "mymrtlng"
|
||||
// Native digits
|
||||
| "native"
|
||||
// Newa digits
|
||||
| "newa"
|
||||
// N'Ko digits
|
||||
| "nkoo"
|
||||
// Ol Chiki digits
|
||||
| "olck"
|
||||
// Oriya digits
|
||||
| "orya"
|
||||
// Osmanya digits
|
||||
| "osma"
|
||||
// Hanifi Rohingya digits
|
||||
| "rohg"
|
||||
// Roman upper case numerals — algorithmic
|
||||
| "roman"
|
||||
// Roman lowercase numerals — algorithmic
|
||||
| "romanlow"
|
||||
// Saurashtra digits
|
||||
| "saur"
|
||||
// Sharada digits
|
||||
| "shrd"
|
||||
// Khudawadi digits
|
||||
| "sind"
|
||||
// Sinhala Lith digits
|
||||
| "sinh"
|
||||
// Sora_Sompeng digits
|
||||
| "sora"
|
||||
// Sundanese digits
|
||||
| "sund"
|
||||
// Takri digits
|
||||
| "takr"
|
||||
// New Tai Lue digits
|
||||
| "talu"
|
||||
// Tamil numerals — algorithmic
|
||||
| "taml"
|
||||
// Modern Tamil decimal digits
|
||||
| "tamldec"
|
||||
// Telugu digits
|
||||
| "telu"
|
||||
// Thai digits
|
||||
| "thai"
|
||||
// Tirhuta digits
|
||||
| "tirh"
|
||||
// Tibetan digits
|
||||
| "tibt"
|
||||
// Traditional numerals — may be algorithmic
|
||||
| "traditional" | "traditio"
|
||||
// Vai digits
|
||||
| "vaii"
|
||||
// Warang Citi digits
|
||||
| "wara"
|
||||
// Wancho digits
|
||||
| "wcho"
|
||||
;
|
||||
|
||||
/**
|
||||
* An object with some or all of properties of `options` parameter
|
||||
* of `Intl.RelativeTimeFormat` constructor.
|
||||
@@ -281,23 +514,10 @@ declare namespace Intl {
|
||||
interface DateTimeFormatOptions {
|
||||
dateStyle?: "full" | "long" | "medium" | "short";
|
||||
timeStyle?: "full" | "long" | "medium" | "short";
|
||||
calendar?: "buddhist" | "chinese" | " coptic" | "ethiopia" | "ethiopic" | "gregory" | " hebrew" | "indian" | "islamic" | "iso8601" | " japanese" | "persian" | "roc";
|
||||
dayPeriod?: "narrow" | "short" | " long";
|
||||
numberingSystem?: "arab" | "arabext" | " bali" | "beng" | "deva" | "fullwide" | " gujr" | "guru" | "hanidec" | "khmr" | " knda" | "laoo" | "latn" | "limb" | "mlym" | " mong" | "mymr" | "orya" | "tamldec" | " telu" | "thai" | "tibt";
|
||||
localeMatcher?: "best fit" | "lookup";
|
||||
timeZone?: string;
|
||||
hour12?: boolean;
|
||||
calendar?: Calendar;
|
||||
dayPeriod?: "narrow" | "short" | "long";
|
||||
numberingSystem?: NumberingSystem;
|
||||
hourCycle?: "h11" | "h12" | "h23" | "h24";
|
||||
formatMatcher?: "best fit" | "basic";
|
||||
weekday?: "long" | "short" | "narrow";
|
||||
era?: "long" | "short" | "narrow";
|
||||
year?: "numeric" | "2-digit";
|
||||
month?: "numeric" | "2-digit" | "long" | "short" | "narrow";
|
||||
day?: "numeric" | "2-digit";
|
||||
hour?: "numeric" | "2-digit";
|
||||
minute?: "numeric" | "2-digit";
|
||||
second?: "numeric" | "2-digit";
|
||||
fractionalSecondDigits?: 0 | 1 | 2 | 3;
|
||||
timeZoneName?: "long" | "short";
|
||||
}
|
||||
}
|
||||
Vendored
+40
-28
@@ -1199,7 +1199,7 @@ interface ConcatArray<T> {
|
||||
|
||||
interface Array<T> {
|
||||
/**
|
||||
* Gets or sets the length of the array. This is a number one higher than the highest element defined in an array.
|
||||
* Gets or sets the length of the array. This is a number one higher than the highest index in the array.
|
||||
*/
|
||||
length: number;
|
||||
/**
|
||||
@@ -1212,44 +1212,54 @@ interface Array<T> {
|
||||
toLocaleString(): string;
|
||||
/**
|
||||
* Removes the last element from an array and returns it.
|
||||
* If the array is empty, undefined is returned and the array is not modified.
|
||||
*/
|
||||
pop(): T | undefined;
|
||||
/**
|
||||
* Appends new elements to an array, and returns the new length of the array.
|
||||
* @param items New elements of the Array.
|
||||
* Appends new elements to the end of an array, and returns the new length of the array.
|
||||
* @param items New elements to add to the array.
|
||||
*/
|
||||
push(...items: T[]): number;
|
||||
/**
|
||||
* Combines two or more arrays.
|
||||
* @param items Additional items to add to the end of array1.
|
||||
* This method returns a new array without modifying any existing arrays.
|
||||
* @param items Additional arrays and/or items to add to the end of the array.
|
||||
*/
|
||||
concat(...items: ConcatArray<T>[]): T[];
|
||||
/**
|
||||
* Combines two or more arrays.
|
||||
* @param items Additional items to add to the end of array1.
|
||||
* This method returns a new array without modifying any existing arrays.
|
||||
* @param items Additional arrays and/or items to add to the end of the array.
|
||||
*/
|
||||
concat(...items: (T | ConcatArray<T>)[]): T[];
|
||||
/**
|
||||
* Adds all the elements of an array separated by the specified separator string.
|
||||
* @param separator A string used to separate one element of an array from the next in the resulting String. If omitted, the array elements are separated with a comma.
|
||||
* Adds all the elements of an array into a string, separated by the specified separator string.
|
||||
* @param separator A string used to separate one element of the array from the next in the resulting string. If omitted, the array elements are separated with a comma.
|
||||
*/
|
||||
join(separator?: string): string;
|
||||
/**
|
||||
* Reverses the elements in an Array.
|
||||
* Reverses the elements in an array in place.
|
||||
* This method mutates the array and returns a reference to the same array.
|
||||
*/
|
||||
reverse(): T[];
|
||||
/**
|
||||
* Removes the first element from an array and returns it.
|
||||
* If the array is empty, undefined is returned and the array is not modified.
|
||||
*/
|
||||
shift(): T | undefined;
|
||||
/**
|
||||
* Returns a section of an array.
|
||||
* @param start The beginning of the specified portion of the array.
|
||||
* @param end The end of the specified portion of the array. This is exclusive of the element at the index 'end'.
|
||||
* Returns a copy of a section of an array.
|
||||
* For both start and end, a negative index can be used to indicate an offset from the end of the array.
|
||||
* For example, -2 refers to the second to last element of the array.
|
||||
* @param start The beginning index of the specified portion of the array.
|
||||
* If start is undefined, then the slice begins at index 0.
|
||||
* @param end The end index of the specified portion of the array. This is exclusive of the element at the index 'end'.
|
||||
* If end is undefined, then the slice extends to the end of the array.
|
||||
*/
|
||||
slice(start?: number, end?: number): T[];
|
||||
/**
|
||||
* Sorts an array.
|
||||
* Sorts an array in place.
|
||||
* This method mutates the array and returns a reference to the same array.
|
||||
* @param compareFn Function used to determine the order of the elements. It is expected to return
|
||||
* a negative value if first argument is less than second argument, zero if they're equal and a positive
|
||||
* value otherwise. If omitted, the elements are sorted in ascending, ASCII character order.
|
||||
@@ -1262,6 +1272,7 @@ interface Array<T> {
|
||||
* Removes elements from an array and, if necessary, inserts new elements in their place, returning the deleted elements.
|
||||
* @param start The zero-based location in the array from which to start removing elements.
|
||||
* @param deleteCount The number of elements to remove.
|
||||
* @returns An array containing the elements that were deleted.
|
||||
*/
|
||||
splice(start: number, deleteCount?: number): T[];
|
||||
/**
|
||||
@@ -1269,23 +1280,24 @@ interface Array<T> {
|
||||
* @param start The zero-based location in the array from which to start removing elements.
|
||||
* @param deleteCount The number of elements to remove.
|
||||
* @param items Elements to insert into the array in place of the deleted elements.
|
||||
* @returns An array containing the elements that were deleted.
|
||||
*/
|
||||
splice(start: number, deleteCount: number, ...items: T[]): T[];
|
||||
/**
|
||||
* Inserts new elements at the start of an array.
|
||||
* @param items Elements to insert at the start of the Array.
|
||||
* Inserts new elements at the start of an array, and returns the new length of the array.
|
||||
* @param items Elements to insert at the start of the array.
|
||||
*/
|
||||
unshift(...items: T[]): number;
|
||||
/**
|
||||
* Returns the index of the first occurrence of a value in an array.
|
||||
* Returns the index of the first occurrence of a value in an array, or -1 if it is not present.
|
||||
* @param searchElement The value to locate in the array.
|
||||
* @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the search starts at index 0.
|
||||
*/
|
||||
indexOf(searchElement: T, fromIndex?: number): number;
|
||||
/**
|
||||
* Returns the index of the last occurrence of a specified value in an array.
|
||||
* Returns the index of the last occurrence of a specified value in an array, or -1 if it is not present.
|
||||
* @param searchElement The value to locate in the array.
|
||||
* @param fromIndex The array index at which to begin the search. If fromIndex is omitted, the search starts at the last index in the array.
|
||||
* @param fromIndex The array index at which to begin searching backward. If fromIndex is omitted, the search starts at the last index in the array.
|
||||
*/
|
||||
lastIndexOf(searchElement: T, fromIndex?: number): number;
|
||||
/**
|
||||
@@ -4318,17 +4330,17 @@ declare namespace Intl {
|
||||
};
|
||||
|
||||
interface DateTimeFormatOptions {
|
||||
localeMatcher?: string;
|
||||
weekday?: string;
|
||||
era?: string;
|
||||
year?: string;
|
||||
month?: string;
|
||||
day?: string;
|
||||
hour?: string;
|
||||
minute?: string;
|
||||
second?: string;
|
||||
timeZoneName?: string;
|
||||
formatMatcher?: string;
|
||||
localeMatcher?: "best fit" | "lookup";
|
||||
weekday?: "long" | "short" | "narrow";
|
||||
era?: "long" | "short" | "narrow";
|
||||
year?: "numeric" | "2-digit";
|
||||
month?: "numeric" | "2-digit" | "long" | "short" | "narrow";
|
||||
day?: "numeric" | "2-digit";
|
||||
hour?: "numeric" | "2-digit";
|
||||
minute?: "numeric" | "2-digit";
|
||||
second?: "numeric" | "2-digit";
|
||||
timeZoneName?: "long" | "short";
|
||||
formatMatcher?: "best fit" | "basic";
|
||||
hour12?: boolean;
|
||||
timeZone?: string;
|
||||
}
|
||||
|
||||
@@ -566,7 +566,8 @@ namespace ts.server.protocol {
|
||||
arguments: GetApplicableRefactorsRequestArgs;
|
||||
}
|
||||
export type GetApplicableRefactorsRequestArgs = FileLocationOrRangeRequestArgs & {
|
||||
triggerReason?: RefactorTriggerReason
|
||||
triggerReason?: RefactorTriggerReason;
|
||||
kind?: string;
|
||||
};
|
||||
|
||||
export type RefactorTriggerReason = "implicit" | "invoked";
|
||||
@@ -626,6 +627,11 @@ namespace ts.server.protocol {
|
||||
* the current context.
|
||||
*/
|
||||
notApplicableReason?: string;
|
||||
|
||||
/**
|
||||
* The hierarchical dotted name of the refactor action.
|
||||
*/
|
||||
kind?: string;
|
||||
}
|
||||
|
||||
export interface GetEditsForRefactorRequest extends Request {
|
||||
|
||||
@@ -2129,7 +2129,7 @@ namespace ts.server {
|
||||
private getApplicableRefactors(args: protocol.GetApplicableRefactorsRequestArgs): protocol.ApplicableRefactorInfo[] {
|
||||
const { file, project } = this.getFileAndProject(args);
|
||||
const scriptInfo = project.getScriptInfoForNormalizedPath(file)!;
|
||||
return project.getLanguageService().getApplicableRefactors(file, this.extractPositionOrRange(args, scriptInfo), this.getPreferences(file), args.triggerReason);
|
||||
return project.getLanguageService().getApplicableRefactors(file, this.extractPositionOrRange(args, scriptInfo), this.getPreferences(file), args.triggerReason, args.kind);
|
||||
}
|
||||
|
||||
private getEditsForRefactor(args: protocol.GetEditsForRefactorRequestArgs, simplifiedResult: boolean): RefactorEditInfo | protocol.RefactorEditInfo {
|
||||
|
||||
@@ -235,7 +235,6 @@ namespace ts.codefix {
|
||||
return transformThen(node, transformer, prevArgName);
|
||||
}
|
||||
if (isPromiseReturningCallExpression(node, transformer.checker, "catch")) {
|
||||
if (node.arguments.length === 0) return silentFail();
|
||||
return transformCatch(node, transformer, prevArgName);
|
||||
}
|
||||
if (isPropertyAccessExpression(node)) {
|
||||
@@ -252,15 +251,13 @@ namespace ts.codefix {
|
||||
}
|
||||
|
||||
function transformCatch(node: CallExpression, transformer: Transformer, prevArgName?: SynthBindingName): readonly Statement[] {
|
||||
const func = node.arguments[0];
|
||||
const argName = getArgBindingName(func, transformer);
|
||||
const func = singleOrUndefined(node.arguments);
|
||||
const argName = func ? getArgBindingName(func, transformer) : undefined;
|
||||
let possibleNameForVarDecl: SynthIdentifier | undefined;
|
||||
|
||||
/*
|
||||
If there is another call in the chain after the .catch() we are transforming, we will need to save the result of both paths (try block and catch block)
|
||||
To do this, we will need to synthesize a variable that we were not aware of while we were adding identifiers to the synthNamesMap
|
||||
We will use the prevArgName and then update the synthNamesMap with a new variable name for the next transformation step
|
||||
*/
|
||||
// If there is another call in the chain after the .catch() we are transforming, we will need to save the result of both paths (try block and catch block)
|
||||
// To do this, we will need to synthesize a variable that we were not aware of while we were adding identifiers to the synthNamesMap
|
||||
// We will use the prevArgName and then update the synthNamesMap with a new variable name for the next transformation step
|
||||
if (prevArgName && !shouldReturn(node, transformer)) {
|
||||
if (isSynthIdentifier(prevArgName)) {
|
||||
possibleNameForVarDecl = prevArgName;
|
||||
@@ -282,14 +279,12 @@ namespace ts.codefix {
|
||||
}
|
||||
|
||||
const tryBlock = factory.createBlock(transformExpression(node.expression, transformer, possibleNameForVarDecl));
|
||||
const transformationBody = getTransformationBody(func, possibleNameForVarDecl, argName, node, transformer);
|
||||
const transformationBody = func ? getTransformationBody(func, possibleNameForVarDecl, argName, node, transformer) : emptyArray;
|
||||
const catchArg = argName ? isSynthIdentifier(argName) ? argName.identifier.text : argName.bindingPattern : "e";
|
||||
const catchVariableDeclaration = factory.createVariableDeclaration(catchArg);
|
||||
const catchClause = factory.createCatchClause(catchVariableDeclaration, factory.createBlock(transformationBody));
|
||||
|
||||
/*
|
||||
In order to avoid an implicit any, we will synthesize a type for the declaration using the unions of the types of both paths (try block and catch block)
|
||||
*/
|
||||
// In order to avoid an implicit any, we will synthesize a type for the declaration using the unions of the types of both paths (try block and catch block)
|
||||
let varDeclList: VariableStatement | undefined;
|
||||
let varDeclIdentifier: Identifier | undefined;
|
||||
if (possibleNameForVarDecl && !shouldReturn(node, transformer)) {
|
||||
|
||||
@@ -52,6 +52,6 @@ namespace ts.codefix {
|
||||
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
|
||||
: (host.isKnownTypesPackageName?.(packageName) ? getTypesPackageName(packageName) : undefined);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,8 @@ namespace ts.codefix {
|
||||
type AcceptedNameType = Identifier | StringLiteral;
|
||||
type ContainerDeclaration = ClassLikeDeclaration | ObjectLiteralExpression;
|
||||
|
||||
interface Info {
|
||||
type Info = AccessorInfo | refactor.RefactorErrorInfo;
|
||||
interface AccessorInfo {
|
||||
readonly container: ContainerDeclaration;
|
||||
readonly isStatic: boolean;
|
||||
readonly isReadonly: boolean;
|
||||
@@ -16,20 +17,12 @@ namespace ts.codefix {
|
||||
readonly renameAccessor: boolean;
|
||||
}
|
||||
|
||||
type InfoOrError = {
|
||||
info: Info,
|
||||
error?: never
|
||||
} | {
|
||||
info?: never,
|
||||
error: string
|
||||
};
|
||||
|
||||
export function generateAccessorFromProperty(file: SourceFile, program: Program, start: number, end: number, context: textChanges.TextChangesContext, _actionName: string): FileTextChanges[] | undefined {
|
||||
const fieldInfo = getAccessorConvertiblePropertyAtPosition(file, program, start, end);
|
||||
if (!fieldInfo || !fieldInfo.info) return undefined;
|
||||
if (!fieldInfo || refactor.isRefactorErrorInfo(fieldInfo)) return undefined;
|
||||
|
||||
const changeTracker = textChanges.ChangeTracker.fromContext(context);
|
||||
const { isStatic, isReadonly, fieldName, accessorName, originalName, type, container, declaration } = fieldInfo.info;
|
||||
const { isStatic, isReadonly, fieldName, accessorName, originalName, type, container, declaration } = fieldInfo;
|
||||
|
||||
suppressLeadingAndTrailingTrivia(fieldName);
|
||||
suppressLeadingAndTrailingTrivia(accessorName);
|
||||
@@ -112,7 +105,7 @@ namespace ts.codefix {
|
||||
return modifierFlags;
|
||||
}
|
||||
|
||||
export function getAccessorConvertiblePropertyAtPosition(file: SourceFile, program: Program, start: number, end: number, considerEmptySpans = true): InfoOrError | undefined {
|
||||
export function getAccessorConvertiblePropertyAtPosition(file: SourceFile, program: Program, start: number, end: number, considerEmptySpans = true): Info | undefined {
|
||||
const node = getTokenAtPosition(file, start);
|
||||
const cursorRequest = start === end && considerEmptySpans;
|
||||
const declaration = findAncestor(node.parent, isAcceptedDeclaration);
|
||||
@@ -142,17 +135,15 @@ namespace ts.codefix {
|
||||
const fieldName = createPropertyName(startWithUnderscore ? name : getUniqueName(`_${name}`, file), declaration.name);
|
||||
const accessorName = createPropertyName(startWithUnderscore ? getUniqueName(name.substring(1), file) : name, declaration.name);
|
||||
return {
|
||||
info: {
|
||||
isStatic: hasStaticModifier(declaration),
|
||||
isReadonly: hasEffectiveReadonlyModifier(declaration),
|
||||
type: getDeclarationType(declaration, program),
|
||||
container: declaration.kind === SyntaxKind.Parameter ? declaration.parent.parent : declaration.parent,
|
||||
originalName: (<AcceptedNameType>declaration.name).text,
|
||||
declaration,
|
||||
fieldName,
|
||||
accessorName,
|
||||
renameAccessor: startWithUnderscore
|
||||
}
|
||||
isStatic: hasStaticModifier(declaration),
|
||||
isReadonly: hasEffectiveReadonlyModifier(declaration),
|
||||
type: getDeclarationType(declaration, program),
|
||||
container: declaration.kind === SyntaxKind.Parameter ? declaration.parent.parent : declaration.parent,
|
||||
originalName: (<AcceptedNameType>declaration.name).text,
|
||||
declaration,
|
||||
fieldName,
|
||||
accessorName,
|
||||
renameAccessor: startWithUnderscore
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,9 @@ namespace ts.refactor {
|
||||
|
||||
export function getApplicableRefactors(context: RefactorContext): ApplicableRefactorInfo[] {
|
||||
return arrayFrom(flatMapIterator(refactors.values(), refactor =>
|
||||
context.cancellationToken && context.cancellationToken.isCancellationRequested() ? undefined : refactor.getAvailableActions(context)));
|
||||
context.cancellationToken && context.cancellationToken.isCancellationRequested() ||
|
||||
!refactor.kinds?.some(kind => refactorKindBeginsWith(kind, context.kind)) ? undefined :
|
||||
refactor.getAvailableActions(context)));
|
||||
}
|
||||
|
||||
export function getEditsForRefactor(context: RefactorContext, refactorName: string, actionName: string): RefactorEditInfo | undefined {
|
||||
|
||||
@@ -2,45 +2,40 @@
|
||||
namespace ts.refactor.addOrRemoveBracesToArrowFunction {
|
||||
const refactorName = "Add or remove braces in an arrow function";
|
||||
const refactorDescription = Diagnostics.Add_or_remove_braces_in_an_arrow_function.message;
|
||||
const addBracesActionName = "Add braces to arrow function";
|
||||
const removeBracesActionName = "Remove braces from arrow function";
|
||||
const addBracesActionDescription = Diagnostics.Add_braces_to_arrow_function.message;
|
||||
const removeBracesActionDescription = Diagnostics.Remove_braces_from_arrow_function.message;
|
||||
registerRefactor(refactorName, { getEditsForAction, getAvailableActions });
|
||||
|
||||
interface Info {
|
||||
const addBracesAction = {
|
||||
name: "Add braces to arrow function",
|
||||
description: Diagnostics.Add_braces_to_arrow_function.message,
|
||||
kind: "refactor.rewrite.arrow.braces.add",
|
||||
};
|
||||
const removeBracesAction = {
|
||||
name: "Remove braces from arrow function",
|
||||
description: Diagnostics.Remove_braces_from_arrow_function.message,
|
||||
kind: "refactor.rewrite.arrow.braces.remove"
|
||||
};
|
||||
registerRefactor(refactorName, {
|
||||
kinds: [removeBracesAction.kind],
|
||||
getEditsForAction,
|
||||
getAvailableActions });
|
||||
|
||||
interface FunctionBracesInfo {
|
||||
func: ArrowFunction;
|
||||
expression: Expression | undefined;
|
||||
returnStatement?: ReturnStatement;
|
||||
addBraces: boolean;
|
||||
}
|
||||
|
||||
type InfoOrError = {
|
||||
info: Info,
|
||||
error?: never
|
||||
} | {
|
||||
info?: never,
|
||||
error: string
|
||||
};
|
||||
|
||||
function getAvailableActions(context: RefactorContext): readonly ApplicableRefactorInfo[] {
|
||||
const { file, startPosition, triggerReason } = context;
|
||||
const info = getConvertibleArrowFunctionAtPosition(file, startPosition, triggerReason === "invoked");
|
||||
if (!info) return emptyArray;
|
||||
|
||||
if (info.error === undefined) {
|
||||
if (!isRefactorErrorInfo(info)) {
|
||||
return [{
|
||||
name: refactorName,
|
||||
description: refactorDescription,
|
||||
actions: [
|
||||
info.info.addBraces ?
|
||||
{
|
||||
name: addBracesActionName,
|
||||
description: addBracesActionDescription
|
||||
} : {
|
||||
name: removeBracesActionName,
|
||||
description: removeBracesActionDescription
|
||||
}
|
||||
info.addBraces ? addBracesAction : removeBracesAction
|
||||
]
|
||||
}];
|
||||
}
|
||||
@@ -49,15 +44,10 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction {
|
||||
return [{
|
||||
name: refactorName,
|
||||
description: refactorDescription,
|
||||
actions: [{
|
||||
name: addBracesActionName,
|
||||
description: addBracesActionDescription,
|
||||
notApplicableReason: info.error
|
||||
}, {
|
||||
name: removeBracesActionName,
|
||||
description: removeBracesActionDescription,
|
||||
notApplicableReason: info.error
|
||||
}]
|
||||
actions: [
|
||||
{ ...addBracesAction, notApplicableReason: info.error },
|
||||
{ ...removeBracesAction, notApplicableReason: info.error },
|
||||
]
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -67,19 +57,19 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction {
|
||||
function getEditsForAction(context: RefactorContext, actionName: string): RefactorEditInfo | undefined {
|
||||
const { file, startPosition } = context;
|
||||
const info = getConvertibleArrowFunctionAtPosition(file, startPosition);
|
||||
if (!info || !info.info) return undefined;
|
||||
Debug.assert(info && !isRefactorErrorInfo(info), "Expected applicable refactor info");
|
||||
|
||||
const { expression, returnStatement, func } = info.info;
|
||||
const { expression, returnStatement, func } = info;
|
||||
|
||||
let body: ConciseBody;
|
||||
|
||||
if (actionName === addBracesActionName) {
|
||||
if (actionName === addBracesAction.name) {
|
||||
const returnStatement = factory.createReturnStatement(expression);
|
||||
body = factory.createBlock([returnStatement], /* multiLine */ true);
|
||||
suppressLeadingAndTrailingTrivia(body);
|
||||
copyLeadingComments(expression!, returnStatement, file, SyntaxKind.MultiLineCommentTrivia, /* hasTrailingNewLine */ true);
|
||||
}
|
||||
else if (actionName === removeBracesActionName && returnStatement) {
|
||||
else if (actionName === removeBracesAction.name && returnStatement) {
|
||||
const actualExpression = expression || factory.createVoidZero();
|
||||
body = needsParentheses(actualExpression) ? factory.createParenthesizedExpression(actualExpression) : actualExpression;
|
||||
suppressLeadingAndTrailingTrivia(body);
|
||||
@@ -98,7 +88,7 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction {
|
||||
return { renameFilename: undefined, renameLocation: undefined, edits };
|
||||
}
|
||||
|
||||
function getConvertibleArrowFunctionAtPosition(file: SourceFile, startPosition: number, considerFunctionBodies = true): InfoOrError | undefined {
|
||||
function getConvertibleArrowFunctionAtPosition(file: SourceFile, startPosition: number, considerFunctionBodies = true, kind?: string): FunctionBracesInfo | RefactorErrorInfo | undefined {
|
||||
const node = getTokenAtPosition(file, startPosition);
|
||||
const func = getContainingFunction(node);
|
||||
|
||||
@@ -118,26 +108,13 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (isExpression(func.body)) {
|
||||
return {
|
||||
info: {
|
||||
func,
|
||||
addBraces: true,
|
||||
expression: func.body
|
||||
}
|
||||
};
|
||||
if (refactorKindBeginsWith(addBracesAction.kind, kind) && isExpression(func.body)) {
|
||||
return { func, addBraces: true, expression: func.body };
|
||||
}
|
||||
else if (func.body.statements.length === 1) {
|
||||
else if (refactorKindBeginsWith(removeBracesAction.kind, kind) && isBlock(func.body) && func.body.statements.length === 1) {
|
||||
const firstStatement = first(func.body.statements);
|
||||
if (isReturnStatement(firstStatement)) {
|
||||
return {
|
||||
info: {
|
||||
func,
|
||||
addBraces: false,
|
||||
expression: firstStatement.expression,
|
||||
returnStatement: firstStatement
|
||||
}
|
||||
};
|
||||
return { func, addBraces: false, expression: firstStatement.expression, returnStatement: firstStatement };
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
|
||||
@@ -3,15 +3,30 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression {
|
||||
const refactorName = "Convert arrow function or function expression";
|
||||
const refactorDescription = getLocaleSpecificMessage(Diagnostics.Convert_arrow_function_or_function_expression);
|
||||
|
||||
const toAnonymousFunctionActionName = "Convert to anonymous function";
|
||||
const toNamedFunctionActionName = "Convert to named function";
|
||||
const toArrowFunctionActionName = "Convert to arrow function";
|
||||
|
||||
const toAnonymousFunctionActionDescription = getLocaleSpecificMessage(Diagnostics.Convert_to_anonymous_function);
|
||||
const toNamedFunctionActionDescription = getLocaleSpecificMessage(Diagnostics.Convert_to_named_function);
|
||||
const toArrowFunctionActionDescription = getLocaleSpecificMessage(Diagnostics.Convert_to_arrow_function);
|
||||
|
||||
registerRefactor(refactorName, { getEditsForAction, getAvailableActions });
|
||||
const toAnonymousFunctionAction = {
|
||||
name: "Convert to anonymous function",
|
||||
description: getLocaleSpecificMessage(Diagnostics.Convert_to_anonymous_function),
|
||||
kind: "refactor.rewrite.function.anonymous",
|
||||
};
|
||||
const toNamedFunctionAction = {
|
||||
name: "Convert to named function",
|
||||
description: getLocaleSpecificMessage(Diagnostics.Convert_to_named_function),
|
||||
kind: "refactor.rewrite.function.named",
|
||||
};
|
||||
const toArrowFunctionAction = {
|
||||
name: "Convert to arrow function",
|
||||
description: getLocaleSpecificMessage(Diagnostics.Convert_to_arrow_function),
|
||||
kind: "refactor.rewrite.function.arrow",
|
||||
};
|
||||
registerRefactor(refactorName, {
|
||||
kinds: [
|
||||
toAnonymousFunctionAction.kind,
|
||||
toNamedFunctionAction.kind,
|
||||
toArrowFunctionAction.kind
|
||||
],
|
||||
getEditsForAction,
|
||||
getAvailableActions
|
||||
});
|
||||
|
||||
interface FunctionInfo {
|
||||
readonly selectedVariableDeclaration: boolean;
|
||||
@@ -26,38 +41,50 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression {
|
||||
}
|
||||
|
||||
function getAvailableActions(context: RefactorContext): readonly ApplicableRefactorInfo[] {
|
||||
const { file, startPosition, program } = context;
|
||||
const { file, startPosition, program, kind } = context;
|
||||
const info = getFunctionInfo(file, startPosition, program);
|
||||
|
||||
if (!info) return emptyArray;
|
||||
const { selectedVariableDeclaration, func } = info;
|
||||
const possibleActions: RefactorActionInfo[] = [];
|
||||
|
||||
if (selectedVariableDeclaration || (isArrowFunction(func) && isVariableDeclaration(func.parent))) {
|
||||
possibleActions.push({
|
||||
name: toNamedFunctionActionName,
|
||||
description: toNamedFunctionActionDescription
|
||||
});
|
||||
const errors: RefactorActionInfo[] = [];
|
||||
if (refactorKindBeginsWith(toNamedFunctionAction.kind, kind)) {
|
||||
const error = selectedVariableDeclaration || (isArrowFunction(func) && isVariableDeclaration(func.parent)) ?
|
||||
undefined : getLocaleSpecificMessage(Diagnostics.Could_not_convert_to_named_function);
|
||||
if (error) {
|
||||
errors.push({ ...toNamedFunctionAction, notApplicableReason: error });
|
||||
}
|
||||
else {
|
||||
possibleActions.push(toNamedFunctionAction);
|
||||
}
|
||||
}
|
||||
|
||||
if (!selectedVariableDeclaration && isArrowFunction(func)) {
|
||||
possibleActions.push({
|
||||
name: toAnonymousFunctionActionName,
|
||||
description: toAnonymousFunctionActionDescription
|
||||
});
|
||||
if (refactorKindBeginsWith(toAnonymousFunctionAction.kind, kind)) {
|
||||
const error = !selectedVariableDeclaration && isArrowFunction(func) ?
|
||||
undefined: getLocaleSpecificMessage(Diagnostics.Could_not_convert_to_anonymous_function);
|
||||
if (error) {
|
||||
errors.push({ ...toAnonymousFunctionAction, notApplicableReason: error });
|
||||
}
|
||||
else {
|
||||
possibleActions.push(toAnonymousFunctionAction);
|
||||
}
|
||||
}
|
||||
|
||||
if (isFunctionExpression(func)) {
|
||||
possibleActions.push({
|
||||
name: toArrowFunctionActionName,
|
||||
description: toArrowFunctionActionDescription
|
||||
});
|
||||
if (refactorKindBeginsWith(toArrowFunctionAction.kind, kind)) {
|
||||
const error = isFunctionExpression(func) ? undefined : getLocaleSpecificMessage(Diagnostics.Could_not_convert_to_arrow_function);
|
||||
if (error) {
|
||||
errors.push({ ...toArrowFunctionAction, notApplicableReason: error });
|
||||
}
|
||||
else {
|
||||
possibleActions.push(toArrowFunctionAction);
|
||||
}
|
||||
}
|
||||
|
||||
return [{
|
||||
name: refactorName,
|
||||
description: refactorDescription,
|
||||
actions: possibleActions
|
||||
actions: possibleActions.length === 0 && context.preferences.provideRefactorNotApplicableReason ?
|
||||
errors : possibleActions
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -70,18 +97,18 @@ namespace ts.refactor.convertArrowFunctionOrFunctionExpression {
|
||||
const edits: FileTextChanges[] = [];
|
||||
|
||||
switch (actionName) {
|
||||
case toAnonymousFunctionActionName:
|
||||
case toAnonymousFunctionAction.name:
|
||||
edits.push(...getEditInfoForConvertToAnonymousFunction(context, func));
|
||||
break;
|
||||
|
||||
case toNamedFunctionActionName:
|
||||
case toNamedFunctionAction.name:
|
||||
const variableInfo = getVariableInfo(func);
|
||||
if (!variableInfo) return undefined;
|
||||
|
||||
edits.push(...getEditInfoForConvertToNamedFunction(context, func, variableInfo));
|
||||
break;
|
||||
|
||||
case toArrowFunctionActionName:
|
||||
case toArrowFunctionAction.name:
|
||||
if (!isFunctionExpression(func)) return undefined;
|
||||
edits.push(...getEditInfoForConvertToArrowFunction(context, func));
|
||||
break;
|
||||
|
||||
@@ -1,54 +1,62 @@
|
||||
/* @internal */
|
||||
namespace ts.refactor {
|
||||
const refactorName = "Convert export";
|
||||
const actionNameDefaultToNamed = "Convert default export to named export";
|
||||
const actionNameNamedToDefault = "Convert named export to default export";
|
||||
|
||||
const defaultToNamedAction = {
|
||||
name: "Convert default export to named export",
|
||||
description: Diagnostics.Convert_default_export_to_named_export.message,
|
||||
kind: "refactor.rewrite.export.named"
|
||||
};
|
||||
const namedToDefaultAction = {
|
||||
name: "Convert named export to default export",
|
||||
description: Diagnostics.Convert_named_export_to_default_export.message,
|
||||
kind: "refactor.rewrite.export.default"
|
||||
};
|
||||
|
||||
registerRefactor(refactorName, {
|
||||
kinds: [
|
||||
defaultToNamedAction.kind,
|
||||
namedToDefaultAction.kind
|
||||
],
|
||||
getAvailableActions(context): readonly ApplicableRefactorInfo[] {
|
||||
const info = getInfo(context, context.triggerReason === "invoked");
|
||||
if (!info) return emptyArray;
|
||||
|
||||
if (info.error === undefined) {
|
||||
const description = info.info.wasDefault ? Diagnostics.Convert_default_export_to_named_export.message : Diagnostics.Convert_named_export_to_default_export.message;
|
||||
const actionName = info.info.wasDefault ? actionNameDefaultToNamed : actionNameNamedToDefault;
|
||||
return [{ name: refactorName, description, actions: [{ name: actionName, description }] }];
|
||||
if (!isRefactorErrorInfo(info)) {
|
||||
const action = info.wasDefault ? defaultToNamedAction : namedToDefaultAction;
|
||||
return [{ name: refactorName, description: action.description, actions: [action] }];
|
||||
}
|
||||
|
||||
if (context.preferences.provideRefactorNotApplicableReason) {
|
||||
return [
|
||||
{ name: refactorName, description: Diagnostics.Convert_default_export_to_named_export.message, actions: [{ name: actionNameDefaultToNamed, description: Diagnostics.Convert_default_export_to_named_export.message, notApplicableReason: info.error }] },
|
||||
{ name: refactorName, description: Diagnostics.Convert_named_export_to_default_export.message, actions: [{ name: actionNameNamedToDefault, description: Diagnostics.Convert_named_export_to_default_export.message, notApplicableReason: info.error }] },
|
||||
{ name: refactorName, description: Diagnostics.Convert_default_export_to_named_export.message, actions: [
|
||||
{ ...defaultToNamedAction, notApplicableReason: info.error },
|
||||
{ ...namedToDefaultAction, notApplicableReason: info.error },
|
||||
]}
|
||||
];
|
||||
}
|
||||
|
||||
return emptyArray;
|
||||
},
|
||||
getEditsForAction(context, actionName): RefactorEditInfo {
|
||||
Debug.assert(actionName === actionNameDefaultToNamed || actionName === actionNameNamedToDefault, "Unexpected action name");
|
||||
const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, Debug.checkDefined(getInfo(context)?.info, "context must have info"), t, context.cancellationToken));
|
||||
Debug.assert(actionName === defaultToNamedAction.name || actionName === namedToDefaultAction.name, "Unexpected action name");
|
||||
const info = getInfo(context);
|
||||
Debug.assert(info && !isRefactorErrorInfo(info), "Expected applicable refactor info");
|
||||
const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, info, t, context.cancellationToken));
|
||||
return { edits, renameFilename: undefined, renameLocation: undefined };
|
||||
},
|
||||
});
|
||||
|
||||
// If a VariableStatement, will have exactly one VariableDeclaration, with an Identifier for a name.
|
||||
type ExportToConvert = FunctionDeclaration | ClassDeclaration | InterfaceDeclaration | EnumDeclaration | NamespaceDeclaration | TypeAliasDeclaration | VariableStatement;
|
||||
interface Info {
|
||||
interface ExportInfo {
|
||||
readonly exportNode: ExportToConvert;
|
||||
readonly exportName: Identifier; // This is exportNode.name except for VariableStatement_s.
|
||||
readonly wasDefault: boolean;
|
||||
readonly exportingModuleSymbol: Symbol;
|
||||
}
|
||||
|
||||
type InfoOrError = {
|
||||
info: Info,
|
||||
error?: never
|
||||
} | {
|
||||
info?: never,
|
||||
error: string
|
||||
};
|
||||
|
||||
function getInfo(context: RefactorContext, considerPartialSpans = true): InfoOrError | undefined {
|
||||
function getInfo(context: RefactorContext, considerPartialSpans = true): ExportInfo | RefactorErrorInfo | undefined {
|
||||
const { file } = context;
|
||||
const span = getRefactorContextSpan(context);
|
||||
const token = getTokenAtPosition(file, span.start);
|
||||
@@ -74,7 +82,7 @@ namespace ts.refactor {
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
case SyntaxKind.ModuleDeclaration: {
|
||||
const node = exportNode as FunctionDeclaration | ClassDeclaration | InterfaceDeclaration | EnumDeclaration | TypeAliasDeclaration | NamespaceDeclaration;
|
||||
return node.name && isIdentifier(node.name) ? { info: { exportNode: node, exportName: node.name, wasDefault, exportingModuleSymbol } } : undefined;
|
||||
return node.name && isIdentifier(node.name) ? { exportNode: node, exportName: node.name, wasDefault, exportingModuleSymbol } : undefined;
|
||||
}
|
||||
case SyntaxKind.VariableStatement: {
|
||||
const vs = exportNode as VariableStatement;
|
||||
@@ -85,19 +93,19 @@ namespace ts.refactor {
|
||||
const decl = first(vs.declarationList.declarations);
|
||||
if (!decl.initializer) return undefined;
|
||||
Debug.assert(!wasDefault, "Can't have a default flag here");
|
||||
return isIdentifier(decl.name) ? { info: { exportNode: vs, exportName: decl.name, wasDefault, exportingModuleSymbol } } : undefined;
|
||||
return isIdentifier(decl.name) ? { exportNode: vs, exportName: decl.name, wasDefault, exportingModuleSymbol } : undefined;
|
||||
}
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
function doChange(exportingSourceFile: SourceFile, program: Program, info: Info, changes: textChanges.ChangeTracker, cancellationToken: CancellationToken | undefined): void {
|
||||
function doChange(exportingSourceFile: SourceFile, program: Program, info: ExportInfo, changes: textChanges.ChangeTracker, cancellationToken: CancellationToken | undefined): void {
|
||||
changeExport(exportingSourceFile, info, changes, program.getTypeChecker());
|
||||
changeImports(program, info, changes, cancellationToken);
|
||||
}
|
||||
|
||||
function changeExport(exportingSourceFile: SourceFile, { wasDefault, exportNode, exportName }: Info, changes: textChanges.ChangeTracker, checker: TypeChecker): void {
|
||||
function changeExport(exportingSourceFile: SourceFile, { wasDefault, exportNode, exportName }: ExportInfo, changes: textChanges.ChangeTracker, checker: TypeChecker): void {
|
||||
if (wasDefault) {
|
||||
changes.delete(exportingSourceFile, Debug.checkDefined(findModifier(exportNode, SyntaxKind.DefaultKeyword), "Should find a default keyword in modifier list"));
|
||||
}
|
||||
@@ -131,7 +139,7 @@ namespace ts.refactor {
|
||||
}
|
||||
}
|
||||
|
||||
function changeImports(program: Program, { wasDefault, exportName, exportingModuleSymbol }: Info, changes: textChanges.ChangeTracker, cancellationToken: CancellationToken | undefined): void {
|
||||
function changeImports(program: Program, { wasDefault, exportName, exportingModuleSymbol }: ExportInfo, changes: textChanges.ChangeTracker, cancellationToken: CancellationToken | undefined): void {
|
||||
const checker = program.getTypeChecker();
|
||||
const exportSymbol = Debug.checkDefined(checker.getSymbolAtLocation(exportName), "Export name should resolve to a symbol");
|
||||
FindAllReferences.Core.eachExportReference(program.getSourceFiles(), checker, cancellationToken, exportSymbol, exportingModuleSymbol, exportName.text, wasDefault, ref => {
|
||||
|
||||
@@ -1,46 +1,55 @@
|
||||
/* @internal */
|
||||
namespace ts.refactor {
|
||||
const refactorName = "Convert import";
|
||||
const actionNameNamespaceToNamed = "Convert namespace import to named imports";
|
||||
const actionNameNamedToNamespace = "Convert named imports to namespace import";
|
||||
|
||||
type NamedImportBindingsOrError = {
|
||||
info: NamedImportBindings,
|
||||
error?: never
|
||||
} | {
|
||||
info?: never,
|
||||
error: string
|
||||
const namespaceToNamedAction = {
|
||||
name: "Convert namespace import to named imports",
|
||||
description: Diagnostics.Convert_namespace_import_to_named_imports.message,
|
||||
kind: "refactor.rewrite.import.named",
|
||||
};
|
||||
const namedToNamespaceAction = {
|
||||
name: "Convert named imports to namespace import",
|
||||
description: Diagnostics.Convert_named_imports_to_namespace_import.message,
|
||||
kind: "refactor.rewrite.import.namespace",
|
||||
};
|
||||
|
||||
registerRefactor(refactorName, {
|
||||
kinds: [
|
||||
namespaceToNamedAction.kind,
|
||||
namedToNamespaceAction.kind
|
||||
],
|
||||
getAvailableActions(context): readonly ApplicableRefactorInfo[] {
|
||||
const i = getImportToConvert(context, context.triggerReason === "invoked");
|
||||
if (!i) return emptyArray;
|
||||
const info = getImportToConvert(context, context.triggerReason === "invoked");
|
||||
if (!info) return emptyArray;
|
||||
|
||||
if (i.error === undefined) {
|
||||
const description = i.info.kind === SyntaxKind.NamespaceImport ? Diagnostics.Convert_namespace_import_to_named_imports.message : Diagnostics.Convert_named_imports_to_namespace_import.message;
|
||||
const actionName = i.info.kind === SyntaxKind.NamespaceImport ? actionNameNamespaceToNamed : actionNameNamedToNamespace;
|
||||
return [{ name: refactorName, description, actions: [{ name: actionName, description }] }];
|
||||
if (!isRefactorErrorInfo(info)) {
|
||||
const namespaceImport = info.kind === SyntaxKind.NamespaceImport;
|
||||
const action = namespaceImport ? namespaceToNamedAction : namedToNamespaceAction;
|
||||
return [{ name: refactorName, description: action.description, actions: [action] }];
|
||||
}
|
||||
|
||||
if (context.preferences.provideRefactorNotApplicableReason) {
|
||||
return [
|
||||
{ name: refactorName, description: Diagnostics.Convert_namespace_import_to_named_imports.message, actions: [{ name: actionNameNamespaceToNamed, description: Diagnostics.Convert_namespace_import_to_named_imports.message, notApplicableReason: i.error }] },
|
||||
{ name: refactorName, description: Diagnostics.Convert_named_imports_to_namespace_import.message, actions: [{ name: actionNameNamedToNamespace, description: Diagnostics.Convert_named_imports_to_namespace_import.message, notApplicableReason: i.error }] }
|
||||
{ name: refactorName, description: namespaceToNamedAction.description,
|
||||
actions: [{ ...namespaceToNamedAction, notApplicableReason: info.error }] },
|
||||
{ name: refactorName, description: namedToNamespaceAction.description,
|
||||
actions: [{ ...namedToNamespaceAction, notApplicableReason: info.error }] }
|
||||
];
|
||||
}
|
||||
|
||||
return emptyArray;
|
||||
},
|
||||
getEditsForAction(context, actionName): RefactorEditInfo {
|
||||
Debug.assert(actionName === actionNameNamespaceToNamed || actionName === actionNameNamedToNamespace, "Unexpected action name");
|
||||
const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, t, Debug.checkDefined(getImportToConvert(context)?.info, "Context must provide an import to convert")));
|
||||
Debug.assert(actionName === namespaceToNamedAction.name || actionName === namedToNamespaceAction.name, "Unexpected action name");
|
||||
const info = getImportToConvert(context);
|
||||
Debug.assert(info && !isRefactorErrorInfo(info), "Expected applicable refactor info");
|
||||
const edits = textChanges.ChangeTracker.with(context, t => doChange(context.file, context.program, t, info));
|
||||
return { edits, renameFilename: undefined, renameLocation: undefined };
|
||||
}
|
||||
});
|
||||
|
||||
// Can convert imports of the form `import * as m from "m";` or `import d, { x, y } from "m";`.
|
||||
function getImportToConvert(context: RefactorContext, considerPartialSpans = true): NamedImportBindingsOrError | undefined {
|
||||
function getImportToConvert(context: RefactorContext, considerPartialSpans = true): NamedImportBindings | RefactorErrorInfo | undefined {
|
||||
const { file } = context;
|
||||
const span = getRefactorContextSpan(context);
|
||||
const token = getTokenAtPosition(file, span.start);
|
||||
@@ -57,7 +66,7 @@ namespace ts.refactor {
|
||||
return { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_namespace_import_or_named_imports) };
|
||||
}
|
||||
|
||||
return { info: importClause.namedBindings };
|
||||
return importClause.namedBindings;
|
||||
}
|
||||
|
||||
function doChange(sourceFile: SourceFile, program: Program, changes: textChanges.ChangeTracker, toConvert: NamedImportBindings): void {
|
||||
|
||||
@@ -2,8 +2,17 @@
|
||||
namespace ts.refactor.addOrRemoveBracesToArrowFunction {
|
||||
const refactorName = "Convert overload list to single signature";
|
||||
const refactorDescription = Diagnostics.Convert_overload_list_to_single_signature.message;
|
||||
registerRefactor(refactorName, { getEditsForAction, getAvailableActions });
|
||||
|
||||
const functionOverloadAction = {
|
||||
name: refactorName,
|
||||
description: refactorDescription,
|
||||
kind: "refactor.rewrite.function.overloadList",
|
||||
};
|
||||
registerRefactor(refactorName, {
|
||||
kinds: [functionOverloadAction.kind],
|
||||
getEditsForAction,
|
||||
getAvailableActions
|
||||
});
|
||||
|
||||
function getAvailableActions(context: RefactorContext): readonly ApplicableRefactorInfo[] {
|
||||
const { file, startPosition, program } = context;
|
||||
@@ -13,10 +22,7 @@ namespace ts.refactor.addOrRemoveBracesToArrowFunction {
|
||||
return [{
|
||||
name: refactorName,
|
||||
description: refactorDescription,
|
||||
actions: [{
|
||||
name: refactorName,
|
||||
description: refactorDescription
|
||||
}]
|
||||
actions: [functionOverloadAction]
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,18 @@
|
||||
namespace ts.refactor.convertParamsToDestructuredObject {
|
||||
const refactorName = "Convert parameters to destructured object";
|
||||
const minimumParameterLength = 2;
|
||||
registerRefactor(refactorName, { getEditsForAction, getAvailableActions });
|
||||
const refactorDescription = getLocaleSpecificMessage(Diagnostics.Convert_parameters_to_destructured_object);
|
||||
|
||||
const toDestructuredAction = {
|
||||
name: refactorName,
|
||||
description: refactorDescription,
|
||||
kind: "refactor.rewrite.parameters.toDestructured"
|
||||
};
|
||||
registerRefactor(refactorName, {
|
||||
kinds: [toDestructuredAction.kind],
|
||||
getEditsForAction,
|
||||
getAvailableActions
|
||||
});
|
||||
|
||||
function getAvailableActions(context: RefactorContext): readonly ApplicableRefactorInfo[] {
|
||||
const { file, startPosition } = context;
|
||||
@@ -12,14 +22,10 @@ namespace ts.refactor.convertParamsToDestructuredObject {
|
||||
const functionDeclaration = getFunctionDeclarationAtPosition(file, startPosition, context.program.getTypeChecker());
|
||||
if (!functionDeclaration) return emptyArray;
|
||||
|
||||
const description = getLocaleSpecificMessage(Diagnostics.Convert_parameters_to_destructured_object);
|
||||
return [{
|
||||
name: refactorName,
|
||||
description,
|
||||
actions: [{
|
||||
name: refactorName,
|
||||
description
|
||||
}]
|
||||
description: refactorDescription,
|
||||
actions: [toDestructuredAction]
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,16 @@ namespace ts.refactor.convertStringOrTemplateLiteral {
|
||||
const refactorName = "Convert to template string";
|
||||
const refactorDescription = getLocaleSpecificMessage(Diagnostics.Convert_to_template_string);
|
||||
|
||||
registerRefactor(refactorName, { getEditsForAction, getAvailableActions });
|
||||
const convertStringAction = {
|
||||
name: refactorName,
|
||||
description: refactorDescription,
|
||||
kind: "refactor.rewrite.string"
|
||||
};
|
||||
registerRefactor(refactorName, {
|
||||
kinds: [convertStringAction.kind],
|
||||
getEditsForAction,
|
||||
getAvailableActions
|
||||
});
|
||||
|
||||
function getAvailableActions(context: RefactorContext): readonly ApplicableRefactorInfo[] {
|
||||
const { file, startPosition } = context;
|
||||
@@ -12,7 +21,13 @@ namespace ts.refactor.convertStringOrTemplateLiteral {
|
||||
const refactorInfo: ApplicableRefactorInfo = { name: refactorName, description: refactorDescription, actions: [] };
|
||||
|
||||
if (isBinaryExpression(maybeBinary) && isStringConcatenationValid(maybeBinary)) {
|
||||
refactorInfo.actions.push({ name: refactorName, description: refactorDescription });
|
||||
refactorInfo.actions.push(convertStringAction);
|
||||
return [refactorInfo];
|
||||
}
|
||||
else if (context.preferences.provideRefactorNotApplicableReason) {
|
||||
refactorInfo.actions.push({ ...convertStringAction,
|
||||
notApplicableReason: getLocaleSpecificMessage(Diagnostics.Can_only_convert_string_concatenation)
|
||||
});
|
||||
return [refactorInfo];
|
||||
}
|
||||
return emptyArray;
|
||||
|
||||
@@ -3,20 +3,26 @@ namespace ts.refactor.convertToOptionalChainExpression {
|
||||
const refactorName = "Convert to optional chain expression";
|
||||
const convertToOptionalChainExpressionMessage = getLocaleSpecificMessage(Diagnostics.Convert_to_optional_chain_expression);
|
||||
|
||||
registerRefactor(refactorName, { getAvailableActions, getEditsForAction });
|
||||
const toOptionalChainAction = {
|
||||
name: refactorName,
|
||||
description: convertToOptionalChainExpressionMessage,
|
||||
kind: "refactor.rewrite.expression.optionalChain",
|
||||
};
|
||||
registerRefactor(refactorName, {
|
||||
kinds: [toOptionalChainAction.kind],
|
||||
getAvailableActions,
|
||||
getEditsForAction
|
||||
});
|
||||
|
||||
function getAvailableActions(context: RefactorContext): readonly ApplicableRefactorInfo[] {
|
||||
const info = getInfo(context, context.triggerReason === "invoked");
|
||||
if (!info) return emptyArray;
|
||||
|
||||
if (!info.error) {
|
||||
if (!isRefactorErrorInfo(info)) {
|
||||
return [{
|
||||
name: refactorName,
|
||||
description: convertToOptionalChainExpressionMessage,
|
||||
actions: [{
|
||||
name: refactorName,
|
||||
description: convertToOptionalChainExpressionMessage
|
||||
}]
|
||||
actions: [toOptionalChainAction],
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -24,11 +30,7 @@ namespace ts.refactor.convertToOptionalChainExpression {
|
||||
return [{
|
||||
name: refactorName,
|
||||
description: convertToOptionalChainExpressionMessage,
|
||||
actions: [{
|
||||
name: refactorName,
|
||||
description: convertToOptionalChainExpressionMessage,
|
||||
notApplicableReason: info.error
|
||||
}]
|
||||
actions: [{ ...toOptionalChainAction, notApplicableReason: info.error }],
|
||||
}];
|
||||
}
|
||||
return emptyArray;
|
||||
@@ -36,24 +38,16 @@ namespace ts.refactor.convertToOptionalChainExpression {
|
||||
|
||||
function getEditsForAction(context: RefactorContext, actionName: string): RefactorEditInfo | undefined {
|
||||
const info = getInfo(context);
|
||||
if (!info || !info.info) return undefined;
|
||||
Debug.assert(info && !isRefactorErrorInfo(info), "Expected applicable refactor info");
|
||||
const edits = textChanges.ChangeTracker.with(context, t =>
|
||||
doChange(context.file, context.program.getTypeChecker(), t, Debug.checkDefined(info.info, "context must have info"), actionName)
|
||||
doChange(context.file, context.program.getTypeChecker(), t, info, actionName)
|
||||
);
|
||||
return { edits, renameFilename: undefined, renameLocation: undefined };
|
||||
}
|
||||
|
||||
type InfoOrError = {
|
||||
info: Info,
|
||||
error?: never;
|
||||
} | {
|
||||
info?: never,
|
||||
error: string;
|
||||
};
|
||||
|
||||
type Occurrence = PropertyAccessExpression | ElementAccessExpression | Identifier;
|
||||
|
||||
interface Info {
|
||||
interface OptionalChainInfo {
|
||||
finalExpression: PropertyAccessExpression | ElementAccessExpression | CallExpression,
|
||||
occurrences: Occurrence[],
|
||||
expression: ValidExpression,
|
||||
@@ -83,7 +77,7 @@ namespace ts.refactor.convertToOptionalChainExpression {
|
||||
return isValidExpression(node) || isValidStatement(node);
|
||||
}
|
||||
|
||||
function getInfo(context: RefactorContext, considerEmptySpans = true): InfoOrError | undefined {
|
||||
function getInfo(context: RefactorContext, considerEmptySpans = true): OptionalChainInfo | RefactorErrorInfo | undefined {
|
||||
const { file, program } = context;
|
||||
const span = getRefactorContextSpan(context);
|
||||
|
||||
@@ -103,7 +97,7 @@ namespace ts.refactor.convertToOptionalChainExpression {
|
||||
return isConditionalExpression(expression) ? getConditionalInfo(expression, checker) : getBinaryInfo(expression);
|
||||
}
|
||||
|
||||
function getConditionalInfo(expression: ConditionalExpression, checker: TypeChecker): InfoOrError | undefined {
|
||||
function getConditionalInfo(expression: ConditionalExpression, checker: TypeChecker): OptionalChainInfo | RefactorErrorInfo | undefined {
|
||||
const condition = expression.condition;
|
||||
const finalExpression = getFinalExpressionInChain(expression.whenTrue);
|
||||
|
||||
@@ -113,16 +107,16 @@ namespace ts.refactor.convertToOptionalChainExpression {
|
||||
|
||||
if ((isPropertyAccessExpression(condition) || isIdentifier(condition))
|
||||
&& getMatchingStart(condition, finalExpression.expression)) {
|
||||
return { info: { finalExpression, occurrences: [condition], expression } };
|
||||
return { finalExpression, occurrences: [condition], expression };
|
||||
}
|
||||
else if (isBinaryExpression(condition)) {
|
||||
const occurrences = getOccurrencesInExpression(finalExpression.expression, condition);
|
||||
return occurrences ? { info: { finalExpression, occurrences, expression } } :
|
||||
return occurrences ? { finalExpression, occurrences, expression } :
|
||||
{ error: getLocaleSpecificMessage(Diagnostics.Could_not_find_matching_access_expressions) };
|
||||
}
|
||||
}
|
||||
|
||||
function getBinaryInfo(expression: BinaryExpression): InfoOrError | undefined {
|
||||
function getBinaryInfo(expression: BinaryExpression): OptionalChainInfo | RefactorErrorInfo | undefined {
|
||||
if (expression.operatorToken.kind !== SyntaxKind.AmpersandAmpersandToken) {
|
||||
return { error: getLocaleSpecificMessage(Diagnostics.Can_only_convert_logical_AND_access_chains) };
|
||||
};
|
||||
@@ -131,7 +125,7 @@ namespace ts.refactor.convertToOptionalChainExpression {
|
||||
if (!finalExpression) return { error: getLocaleSpecificMessage(Diagnostics.Could_not_find_convertible_access_expression) };
|
||||
|
||||
const occurrences = getOccurrencesInExpression(finalExpression.expression, expression.left);
|
||||
return occurrences ? { info: { finalExpression, occurrences, expression } } :
|
||||
return occurrences ? { finalExpression, occurrences, expression } :
|
||||
{ error: getLocaleSpecificMessage(Diagnostics.Could_not_find_matching_access_expressions) };
|
||||
}
|
||||
|
||||
@@ -288,7 +282,7 @@ namespace ts.refactor.convertToOptionalChainExpression {
|
||||
return toConvert;
|
||||
}
|
||||
|
||||
function doChange(sourceFile: SourceFile, checker: TypeChecker, changes: textChanges.ChangeTracker, info: Info, _actionName: string): void {
|
||||
function doChange(sourceFile: SourceFile, checker: TypeChecker, changes: textChanges.ChangeTracker, info: OptionalChainInfo, _actionName: string): void {
|
||||
const { finalExpression, occurrences, expression } = info;
|
||||
const firstOccurrence = occurrences[occurrences.length - 1];
|
||||
const convertedChain = convertOccurrences(checker, finalExpression, occurrences);
|
||||
|
||||
@@ -1,39 +1,56 @@
|
||||
/* @internal */
|
||||
namespace ts.refactor.extractSymbol {
|
||||
const refactorName = "Extract Symbol";
|
||||
registerRefactor(refactorName, { getAvailableActions, getEditsForAction });
|
||||
|
||||
const extractConstantAction = {
|
||||
name: "Extract Constant",
|
||||
description: getLocaleSpecificMessage(Diagnostics.Extract_constant),
|
||||
kind: "refactor.extract.constant",
|
||||
};
|
||||
const extractFunctionAction = {
|
||||
name: "Extract Function",
|
||||
description: getLocaleSpecificMessage(Diagnostics.Extract_function),
|
||||
kind: "refactor.extract.function",
|
||||
};
|
||||
registerRefactor(refactorName, {
|
||||
kinds: [
|
||||
extractConstantAction.kind,
|
||||
extractFunctionAction.kind
|
||||
],
|
||||
getAvailableActions,
|
||||
getEditsForAction
|
||||
});
|
||||
|
||||
/**
|
||||
* Compute the associated code actions
|
||||
* Exported for tests.
|
||||
*/
|
||||
export function getAvailableActions(context: RefactorContext): readonly ApplicableRefactorInfo[] {
|
||||
const requestedRefactor = context.kind;
|
||||
const rangeToExtract = getRangeToExtract(context.file, getRefactorContextSpan(context), context.triggerReason === "invoked");
|
||||
|
||||
const targetRange = rangeToExtract.targetRange;
|
||||
|
||||
if (targetRange === undefined) {
|
||||
if (!rangeToExtract.errors || rangeToExtract.errors.length === 0 || !context.preferences.provideRefactorNotApplicableReason) {
|
||||
return emptyArray;
|
||||
}
|
||||
|
||||
return [{
|
||||
name: refactorName,
|
||||
description: getLocaleSpecificMessage(Diagnostics.Extract_function),
|
||||
actions: [{
|
||||
description: getLocaleSpecificMessage(Diagnostics.Extract_function),
|
||||
name: "function_extract_error",
|
||||
notApplicableReason: getStringError(rangeToExtract.errors)
|
||||
}]
|
||||
},
|
||||
{
|
||||
name: refactorName,
|
||||
description: getLocaleSpecificMessage(Diagnostics.Extract_constant),
|
||||
actions: [{
|
||||
description: getLocaleSpecificMessage(Diagnostics.Extract_constant),
|
||||
name: "constant_extract_error",
|
||||
notApplicableReason: getStringError(rangeToExtract.errors)
|
||||
}]
|
||||
}];
|
||||
const errors = [];
|
||||
if (refactorKindBeginsWith(extractFunctionAction.kind, requestedRefactor)) {
|
||||
errors.push({
|
||||
name: refactorName,
|
||||
description: extractFunctionAction.description,
|
||||
actions: [{ ...extractFunctionAction, notApplicableReason: getStringError(rangeToExtract.errors) }]
|
||||
});
|
||||
}
|
||||
if (refactorKindBeginsWith(extractConstantAction.kind, requestedRefactor)) {
|
||||
errors.push({
|
||||
name: refactorName,
|
||||
description: extractConstantAction.description,
|
||||
actions: [{ ...extractConstantAction, notApplicableReason: getStringError(rangeToExtract.errors) }]
|
||||
});
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
const extractions = getPossibleExtractions(targetRange, context);
|
||||
@@ -53,46 +70,54 @@ namespace ts.refactor.extractSymbol {
|
||||
let i = 0;
|
||||
for (const { functionExtraction, constantExtraction } of extractions) {
|
||||
const description = functionExtraction.description;
|
||||
if (functionExtraction.errors.length === 0) {
|
||||
// Don't issue refactorings with duplicated names.
|
||||
// Scopes come back in "innermost first" order, so extractions will
|
||||
// preferentially go into nearer scopes
|
||||
if (!usedFunctionNames.has(description)) {
|
||||
usedFunctionNames.set(description, true);
|
||||
functionActions.push({
|
||||
if(refactorKindBeginsWith(extractFunctionAction.kind, requestedRefactor)){
|
||||
if (functionExtraction.errors.length === 0) {
|
||||
// Don't issue refactorings with duplicated names.
|
||||
// Scopes come back in "innermost first" order, so extractions will
|
||||
// preferentially go into nearer scopes
|
||||
if (!usedFunctionNames.has(description)) {
|
||||
usedFunctionNames.set(description, true);
|
||||
functionActions.push({
|
||||
description,
|
||||
name: `function_scope_${i}`,
|
||||
kind: extractFunctionAction.kind
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (!innermostErrorFunctionAction) {
|
||||
innermostErrorFunctionAction = {
|
||||
description,
|
||||
name: `function_scope_${i}`
|
||||
});
|
||||
name: `function_scope_${i}`,
|
||||
notApplicableReason: getStringError(functionExtraction.errors),
|
||||
kind: extractFunctionAction.kind
|
||||
};
|
||||
}
|
||||
}
|
||||
else if (!innermostErrorFunctionAction) {
|
||||
innermostErrorFunctionAction = {
|
||||
description,
|
||||
name: `function_scope_${i}`,
|
||||
notApplicableReason: getStringError(functionExtraction.errors)
|
||||
};
|
||||
}
|
||||
|
||||
// Skip these since we don't have a way to report errors yet
|
||||
if (constantExtraction.errors.length === 0) {
|
||||
// Don't issue refactorings with duplicated names.
|
||||
// Scopes come back in "innermost first" order, so extractions will
|
||||
// preferentially go into nearer scopes
|
||||
const description = constantExtraction.description;
|
||||
if (!usedConstantNames.has(description)) {
|
||||
usedConstantNames.set(description, true);
|
||||
constantActions.push({
|
||||
if(refactorKindBeginsWith(extractConstantAction.kind, requestedRefactor)) {
|
||||
if (constantExtraction.errors.length === 0) {
|
||||
// Don't issue refactorings with duplicated names.
|
||||
// Scopes come back in "innermost first" order, so extractions will
|
||||
// preferentially go into nearer scopes
|
||||
const description = constantExtraction.description;
|
||||
if (!usedConstantNames.has(description)) {
|
||||
usedConstantNames.set(description, true);
|
||||
constantActions.push({
|
||||
description,
|
||||
name: `constant_scope_${i}`,
|
||||
kind: extractConstantAction.kind
|
||||
});
|
||||
}
|
||||
}
|
||||
else if (!innermostErrorConstantAction) {
|
||||
innermostErrorConstantAction = {
|
||||
description,
|
||||
name: `constant_scope_${i}`
|
||||
});
|
||||
name: `constant_scope_${i}`,
|
||||
notApplicableReason: getStringError(constantExtraction.errors),
|
||||
kind: extractConstantAction.kind
|
||||
};
|
||||
}
|
||||
}
|
||||
else if (!innermostErrorConstantAction) {
|
||||
innermostErrorConstantAction = {
|
||||
description,
|
||||
name: `constant_scope_${i}`,
|
||||
notApplicableReason: getStringError(constantExtraction.errors)
|
||||
};
|
||||
}
|
||||
|
||||
// *do* increment i anyway because we'll look for the i-th scope
|
||||
@@ -106,7 +131,7 @@ namespace ts.refactor.extractSymbol {
|
||||
infos.push({
|
||||
name: refactorName,
|
||||
description: getLocaleSpecificMessage(Diagnostics.Extract_function),
|
||||
actions: functionActions
|
||||
actions: functionActions,
|
||||
});
|
||||
}
|
||||
else if (context.preferences.provideRefactorNotApplicableReason && innermostErrorFunctionAction) {
|
||||
|
||||
@@ -1,25 +1,39 @@
|
||||
/* @internal */
|
||||
namespace ts.refactor {
|
||||
const refactorName = "Extract type";
|
||||
const extractToTypeAlias = "Extract to type alias";
|
||||
const extractToInterface = "Extract to interface";
|
||||
const extractToTypeDef = "Extract to typedef";
|
||||
|
||||
const extractToTypeAliasAction = {
|
||||
name: "Extract to type alias",
|
||||
description: getLocaleSpecificMessage(Diagnostics.Extract_to_type_alias),
|
||||
kind: "refactor.extract.type",
|
||||
};
|
||||
const extractToInterfaceAction = {
|
||||
name: "Extract to interface",
|
||||
description: getLocaleSpecificMessage(Diagnostics.Extract_to_interface),
|
||||
kind: "refactor.extract.interface",
|
||||
};
|
||||
const extractToTypeDefAction = {
|
||||
name: "Extract to typedef",
|
||||
description: getLocaleSpecificMessage(Diagnostics.Extract_to_typedef),
|
||||
kind: "refactor.extract.typedef"
|
||||
};
|
||||
|
||||
registerRefactor(refactorName, {
|
||||
kinds: [
|
||||
extractToTypeAliasAction.kind,
|
||||
extractToInterfaceAction.kind,
|
||||
extractToTypeDefAction.kind
|
||||
],
|
||||
getAvailableActions(context): readonly ApplicableRefactorInfo[] {
|
||||
const info = getRangeToExtract(context, context.triggerReason === "invoked");
|
||||
if (!info) return emptyArray;
|
||||
|
||||
if (info.error === undefined) {
|
||||
if (!isRefactorErrorInfo(info)) {
|
||||
return [{
|
||||
name: refactorName,
|
||||
description: getLocaleSpecificMessage(Diagnostics.Extract_type),
|
||||
actions: info.info.isJS ? [{
|
||||
name: extractToTypeDef, description: getLocaleSpecificMessage(Diagnostics.Extract_to_typedef)
|
||||
}] : append([{
|
||||
name: extractToTypeAlias, description: getLocaleSpecificMessage(Diagnostics.Extract_to_type_alias)
|
||||
}], info.info.typeElements && {
|
||||
name: extractToInterface, description: getLocaleSpecificMessage(Diagnostics.Extract_to_interface)
|
||||
})
|
||||
actions: info.isJS ?
|
||||
[extractToTypeDefAction] : append([extractToTypeAliasAction], info.typeElements && extractToInterfaceAction)
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -28,9 +42,9 @@ namespace ts.refactor {
|
||||
name: refactorName,
|
||||
description: getLocaleSpecificMessage(Diagnostics.Extract_type),
|
||||
actions: [
|
||||
{ name: extractToTypeDef, description: getLocaleSpecificMessage(Diagnostics.Extract_to_typedef), notApplicableReason: info.error },
|
||||
{ name: extractToTypeAlias, description: getLocaleSpecificMessage(Diagnostics.Extract_to_type_alias), notApplicableReason: info.error },
|
||||
{ name: extractToInterface, description: getLocaleSpecificMessage(Diagnostics.Extract_to_interface), notApplicableReason: info.error },
|
||||
{ ...extractToTypeDefAction, notApplicableReason: info.error },
|
||||
{ ...extractToTypeAliasAction, notApplicableReason: info.error },
|
||||
{ ...extractToInterfaceAction, notApplicableReason: info.error },
|
||||
]
|
||||
}];
|
||||
}
|
||||
@@ -39,18 +53,19 @@ namespace ts.refactor {
|
||||
},
|
||||
getEditsForAction(context, actionName): RefactorEditInfo {
|
||||
const { file, } = context;
|
||||
const info = Debug.checkDefined(getRangeToExtract(context)?.info, "Expected to find a range to extract");
|
||||
const info = getRangeToExtract(context);
|
||||
Debug.assert(info && !isRefactorErrorInfo(info), "Expected to find a range to extract");
|
||||
|
||||
const name = getUniqueName("NewType", file);
|
||||
const edits = textChanges.ChangeTracker.with(context, changes => {
|
||||
switch (actionName) {
|
||||
case extractToTypeAlias:
|
||||
case extractToTypeAliasAction.name:
|
||||
Debug.assert(!info.isJS, "Invalid actionName/JS combo");
|
||||
return doTypeAliasChange(changes, file, name, info);
|
||||
case extractToTypeDef:
|
||||
case extractToTypeDefAction.name:
|
||||
Debug.assert(info.isJS, "Invalid actionName/JS combo");
|
||||
return doTypedefChange(changes, file, name, info);
|
||||
case extractToInterface:
|
||||
case extractToInterfaceAction.name:
|
||||
Debug.assert(!info.isJS && !!info.typeElements, "Invalid actionName/JS combo");
|
||||
return doInterfaceChange(changes, file, name, info as InterfaceInfo);
|
||||
default:
|
||||
@@ -72,16 +87,9 @@ namespace ts.refactor {
|
||||
isJS: boolean; selection: TypeNode; firstStatement: Statement; typeParameters: readonly TypeParameterDeclaration[]; typeElements: readonly TypeElement[];
|
||||
}
|
||||
|
||||
type Info = TypeAliasInfo | InterfaceInfo;
|
||||
type InfoOrError = {
|
||||
info: Info,
|
||||
error?: never
|
||||
} | {
|
||||
info?: never,
|
||||
error: string
|
||||
};
|
||||
type ExtractInfo = TypeAliasInfo | InterfaceInfo;
|
||||
|
||||
function getRangeToExtract(context: RefactorContext, considerEmptySpans = true): InfoOrError | undefined {
|
||||
function getRangeToExtract(context: RefactorContext, considerEmptySpans = true): ExtractInfo | RefactorErrorInfo | undefined {
|
||||
const { file, startPosition } = context;
|
||||
const isJS = isSourceFileJS(file);
|
||||
const current = getTokenAtPosition(file, startPosition);
|
||||
@@ -98,7 +106,7 @@ namespace ts.refactor {
|
||||
if (!typeParameters) return { error: getLocaleSpecificMessage(Diagnostics.No_type_could_be_extracted_from_this_type_node) };
|
||||
|
||||
const typeElements = flattenTypeLiteralNodeReference(checker, selection);
|
||||
return { info: { isJS, selection, firstStatement, typeParameters, typeElements } };
|
||||
return { isJS, selection, firstStatement, typeParameters, typeElements };
|
||||
}
|
||||
|
||||
function flattenTypeLiteralNodeReference(checker: TypeChecker, node: TypeNode | undefined): readonly TypeElement[] | undefined {
|
||||
@@ -209,7 +217,7 @@ namespace ts.refactor {
|
||||
changes.replaceNode(file, selection, factory.createTypeReferenceNode(name, typeParameters.map(id => factory.createTypeReferenceNode(id.name, /* typeArguments */ undefined))), { leadingTriviaOption: textChanges.LeadingTriviaOption.Exclude, trailingTriviaOption: textChanges.TrailingTriviaOption.ExcludeWhitespace });
|
||||
}
|
||||
|
||||
function doTypedefChange(changes: textChanges.ChangeTracker, file: SourceFile, name: string, info: Info) {
|
||||
function doTypedefChange(changes: textChanges.ChangeTracker, file: SourceFile, name: string, info: ExtractInfo) {
|
||||
const { firstStatement, selection, typeParameters } = info;
|
||||
|
||||
const node = factory.createJSDocTypedefTag(
|
||||
|
||||
@@ -2,18 +2,25 @@
|
||||
namespace ts.refactor.generateGetAccessorAndSetAccessor {
|
||||
const actionName = "Generate 'get' and 'set' accessors";
|
||||
const actionDescription = Diagnostics.Generate_get_and_set_accessors.message;
|
||||
|
||||
const generateGetSetAction = {
|
||||
name: actionName,
|
||||
description: actionDescription,
|
||||
kind: "refactor.rewrite.property.generateAccessors",
|
||||
};
|
||||
registerRefactor(actionName, {
|
||||
kinds: [generateGetSetAction.kind],
|
||||
getEditsForAction(context, actionName) {
|
||||
if (!context.endPosition) return undefined;
|
||||
const info = codefix.getAccessorConvertiblePropertyAtPosition(context.file, context.program, context.startPosition, context.endPosition);
|
||||
if (!info || !info.info) return undefined;
|
||||
Debug.assert(info && !isRefactorErrorInfo(info), "Expected applicable refactor info");
|
||||
const edits = codefix.generateAccessorFromProperty(context.file, context.program, context.startPosition, context.endPosition, context, actionName);
|
||||
if (!edits) return undefined;
|
||||
|
||||
const renameFilename = context.file.fileName;
|
||||
const nameNeedRename = info.info.renameAccessor ? info.info.accessorName : info.info.fieldName;
|
||||
const nameNeedRename = info.renameAccessor ? info.accessorName : info.fieldName;
|
||||
const renameLocationOffset = isIdentifier(nameNeedRename) ? 0 : -1;
|
||||
const renameLocation = renameLocationOffset + getRenameLocation(edits, renameFilename, nameNeedRename.text, /*preferLastLocation*/ isParameter(info.info.declaration));
|
||||
const renameLocation = renameLocationOffset + getRenameLocation(edits, renameFilename, nameNeedRename.text, /*preferLastLocation*/ isParameter(info.declaration));
|
||||
|
||||
return { renameFilename, renameLocation, edits };
|
||||
},
|
||||
@@ -22,16 +29,11 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
|
||||
const info = codefix.getAccessorConvertiblePropertyAtPosition(context.file, context.program, context.startPosition, context.endPosition, context.triggerReason === "invoked");
|
||||
if (!info) return emptyArray;
|
||||
|
||||
if (!info.error) {
|
||||
if (!isRefactorErrorInfo(info)) {
|
||||
return [{
|
||||
name: actionName,
|
||||
description: actionDescription,
|
||||
actions: [
|
||||
{
|
||||
name: actionName,
|
||||
description: actionDescription
|
||||
}
|
||||
]
|
||||
actions: [generateGetSetAction],
|
||||
}];
|
||||
}
|
||||
|
||||
@@ -39,11 +41,7 @@ namespace ts.refactor.generateGetAccessorAndSetAccessor {
|
||||
return [{
|
||||
name: actionName,
|
||||
description: actionDescription,
|
||||
actions: [{
|
||||
name: actionName,
|
||||
description: actionDescription,
|
||||
notApplicableReason: info.error
|
||||
}]
|
||||
actions: [{ ...generateGetSetAction, notApplicableReason: info.error }],
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
/* @internal */
|
||||
namespace ts.refactor {
|
||||
/**
|
||||
* Returned by refactor funtions when some error message needs to be surfaced to users.
|
||||
*/
|
||||
export interface RefactorErrorInfo {
|
||||
error: string;
|
||||
};
|
||||
|
||||
/**
|
||||
* Checks if some refactor info has refactor error info.
|
||||
*/
|
||||
export function isRefactorErrorInfo(info: unknown): info is RefactorErrorInfo {
|
||||
return (info as RefactorErrorInfo).error !== undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if string "known" begins with string "requested".
|
||||
* Used to match requested kinds with a known kind.
|
||||
*/
|
||||
export function refactorKindBeginsWith(known: string, requested: string | undefined): boolean {
|
||||
if(!requested) return true;
|
||||
return known.substr(0, requested.length) === requested;
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,21 @@
|
||||
namespace ts.refactor.inferFunctionReturnType {
|
||||
const refactorName = "Infer function return type";
|
||||
const refactorDescription = Diagnostics.Infer_function_return_type.message;
|
||||
registerRefactor(refactorName, { getEditsForAction, getAvailableActions });
|
||||
|
||||
const inferReturnTypeAction = {
|
||||
name: refactorName,
|
||||
description: refactorDescription,
|
||||
kind: "refactor.rewrite.function.returnType"
|
||||
};
|
||||
registerRefactor(refactorName, {
|
||||
kinds: [inferReturnTypeAction.kind],
|
||||
getEditsForAction,
|
||||
getAvailableActions
|
||||
});
|
||||
|
||||
function getEditsForAction(context: RefactorContext): RefactorEditInfo | undefined {
|
||||
const info = getInfo(context);
|
||||
if (info) {
|
||||
if (info && !isRefactorErrorInfo(info)) {
|
||||
const edits = textChanges.ChangeTracker.with(context, t =>
|
||||
t.tryInsertTypeAnnotation(context.file, info.declaration, info.returnTypeNode));
|
||||
return { renameFilename: undefined, renameLocation: undefined, edits };
|
||||
@@ -16,14 +26,19 @@ namespace ts.refactor.inferFunctionReturnType {
|
||||
|
||||
function getAvailableActions(context: RefactorContext): readonly ApplicableRefactorInfo[] {
|
||||
const info = getInfo(context);
|
||||
if (info) {
|
||||
if (!info) return emptyArray;
|
||||
if (!isRefactorErrorInfo(info)) {
|
||||
return [{
|
||||
name: refactorName,
|
||||
description: refactorDescription,
|
||||
actions: [{
|
||||
name: refactorName,
|
||||
description: refactorDescription
|
||||
}]
|
||||
actions: [inferReturnTypeAction]
|
||||
}];
|
||||
}
|
||||
if (context.preferences.provideRefactorNotApplicableReason) {
|
||||
return [{
|
||||
name: refactorName,
|
||||
description: refactorDescription,
|
||||
actions: [{ ...inferReturnTypeAction, notApplicableReason: info.error }]
|
||||
}];
|
||||
}
|
||||
return emptyArray;
|
||||
@@ -35,21 +50,25 @@ namespace ts.refactor.inferFunctionReturnType {
|
||||
| ArrowFunction
|
||||
| MethodDeclaration;
|
||||
|
||||
interface Info {
|
||||
interface FunctionInfo {
|
||||
declaration: ConvertibleDeclaration;
|
||||
returnTypeNode: TypeNode;
|
||||
}
|
||||
|
||||
function getInfo(context: RefactorContext): Info | undefined {
|
||||
if (isInJSFile(context.file)) return;
|
||||
function getInfo(context: RefactorContext): FunctionInfo | RefactorErrorInfo | undefined {
|
||||
if (isInJSFile(context.file) || !refactorKindBeginsWith(inferReturnTypeAction.kind, context.kind)) return;
|
||||
|
||||
const token = getTokenAtPosition(context.file, context.startPosition);
|
||||
const declaration = findAncestor(token, isConvertibleDeclaration);
|
||||
if (!declaration || !declaration.body || declaration.type) return;
|
||||
if (!declaration || !declaration.body || declaration.type) {
|
||||
return { error: getLocaleSpecificMessage(Diagnostics.Return_type_must_be_inferred_from_a_function) };
|
||||
}
|
||||
|
||||
const typeChecker = context.program.getTypeChecker();
|
||||
const returnType = tryGetReturnType(typeChecker, declaration);
|
||||
if (!returnType) return;
|
||||
if (!returnType) {
|
||||
return { error: getLocaleSpecificMessage(Diagnostics.Could_not_determine_function_return_type) };
|
||||
};
|
||||
|
||||
const returnTypeNode = typeChecker.typeToTypeNode(returnType, declaration, NodeBuilderFlags.NoTruncation);
|
||||
if (returnTypeNode) {
|
||||
|
||||
@@ -1,11 +1,26 @@
|
||||
/* @internal */
|
||||
namespace ts.refactor {
|
||||
const refactorName = "Move to a new file";
|
||||
const description = getLocaleSpecificMessage(Diagnostics.Move_to_a_new_file);
|
||||
|
||||
const moveToNewFileAction = {
|
||||
name: refactorName,
|
||||
description,
|
||||
kind: "refactor.move.newFile",
|
||||
};
|
||||
registerRefactor(refactorName, {
|
||||
kinds: [moveToNewFileAction.kind],
|
||||
getAvailableActions(context): readonly ApplicableRefactorInfo[] {
|
||||
if (!context.preferences.allowTextChangesInNewFiles || getStatementsToMove(context) === undefined) return emptyArray;
|
||||
const description = getLocaleSpecificMessage(Diagnostics.Move_to_a_new_file);
|
||||
return [{ name: refactorName, description, actions: [{ name: refactorName, description }] }];
|
||||
const statements = getStatementsToMove(context);
|
||||
if (context.preferences.allowTextChangesInNewFiles && statements) {
|
||||
return [{ name: refactorName, description, actions: [moveToNewFileAction] }];
|
||||
}
|
||||
if (context.preferences.provideRefactorNotApplicableReason) {
|
||||
return [{ name: refactorName, description, actions:
|
||||
[{ ...moveToNewFileAction, notApplicableReason: getLocaleSpecificMessage(Diagnostics.Selection_is_not_a_valid_statement_or_statements) }]
|
||||
}];
|
||||
}
|
||||
return emptyArray;
|
||||
},
|
||||
getEditsForAction(context, actionName): RefactorEditInfo {
|
||||
Debug.assert(actionName === refactorName, "Wrong refactor invoked");
|
||||
|
||||
+24
-21
@@ -550,9 +550,8 @@ namespace ts {
|
||||
|
||||
getJsDocTags(): JSDocTagInfo[] {
|
||||
if (this.jsDocTags === undefined) {
|
||||
this.jsDocTags = this.declaration ? JsDoc.getJsDocTagsFromDeclarations([this.declaration]) : [];
|
||||
this.jsDocTags = this.declaration ? getJsDocTags([this.declaration], this.checker) : [];
|
||||
}
|
||||
|
||||
return this.jsDocTags;
|
||||
}
|
||||
}
|
||||
@@ -566,13 +565,26 @@ namespace ts {
|
||||
return getJSDocTags(node).some(tag => tag.tagName.text === "inheritDoc");
|
||||
}
|
||||
|
||||
function getJsDocTags(declarations: Declaration[], checker: TypeChecker): JSDocTagInfo[] {
|
||||
let tags = JsDoc.getJsDocTagsFromDeclarations(declarations);
|
||||
if (tags.length === 0 || declarations.some(hasJSDocInheritDocTag)) {
|
||||
forEachUnique(declarations, declaration => {
|
||||
const inheritedTags = findBaseOfDeclaration(checker, declaration, symbol => symbol.getJsDocTags());
|
||||
if (inheritedTags) {
|
||||
tags = [...inheritedTags, ...tags];
|
||||
}
|
||||
});
|
||||
}
|
||||
return tags;
|
||||
}
|
||||
|
||||
function getDocumentationComment(declarations: readonly Declaration[] | undefined, checker: TypeChecker | undefined): SymbolDisplayPart[] {
|
||||
if (!declarations) return emptyArray;
|
||||
|
||||
let doc = JsDoc.getJsDocCommentsFromDeclarations(declarations);
|
||||
if (doc.length === 0 || declarations.some(hasJSDocInheritDocTag)) {
|
||||
if (checker && (doc.length === 0 || declarations.some(hasJSDocInheritDocTag))) {
|
||||
forEachUnique(declarations, declaration => {
|
||||
const inheritedDocs = findInheritedJSDocComments(declaration, declaration.symbol.name, checker!); // TODO: GH#18217
|
||||
const inheritedDocs = findBaseOfDeclaration(checker, declaration, symbol => symbol.getDocumentationComment(checker));
|
||||
// TODO: GH#16312 Return a ReadonlyArray, avoid copying inheritedDocs
|
||||
if (inheritedDocs) doc = doc.length === 0 ? inheritedDocs.slice() : inheritedDocs.concat(lineBreakPart(), doc);
|
||||
});
|
||||
@@ -580,20 +592,10 @@ namespace ts {
|
||||
return doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to find JSDoc comments for possibly-inherited properties. Checks superclasses then traverses
|
||||
* implemented interfaces until a symbol is found with the same name and with documentation.
|
||||
* @param declaration The possibly-inherited declaration to find comments for.
|
||||
* @param propertyName The name of the possibly-inherited property.
|
||||
* @param typeChecker A TypeChecker, used to find inherited properties.
|
||||
* @returns A filled array of documentation comments if any were found, otherwise an empty array.
|
||||
*/
|
||||
function findInheritedJSDocComments(declaration: Declaration, propertyName: string, typeChecker: TypeChecker): readonly SymbolDisplayPart[] | undefined {
|
||||
function findBaseOfDeclaration<T>(checker: TypeChecker, declaration: Declaration, cb: (symbol: Symbol) => T[]): T[] | undefined {
|
||||
return firstDefined(declaration.parent ? getAllSuperTypeNodes(declaration.parent) : emptyArray, superTypeNode => {
|
||||
const superType = typeChecker.getTypeAtLocation(superTypeNode);
|
||||
const baseProperty = superType && typeChecker.getPropertyOfType(superType, propertyName);
|
||||
const inheritedDocs = baseProperty && baseProperty.getDocumentationComment(typeChecker);
|
||||
return inheritedDocs && inheritedDocs.length ? inheritedDocs : undefined;
|
||||
const symbol = checker.getPropertyOfType(checker.getTypeAtLocation(superTypeNode), declaration.symbol.name);
|
||||
return symbol ? cb(symbol) : undefined;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2451,7 +2453,7 @@ namespace ts {
|
||||
return Rename.getRenameInfo(program, getValidSourceFile(fileName), position, options);
|
||||
}
|
||||
|
||||
function getRefactorContext(file: SourceFile, positionOrRange: number | TextRange, preferences: UserPreferences, formatOptions?: FormatCodeSettings, triggerReason?: RefactorTriggerReason): RefactorContext {
|
||||
function getRefactorContext(file: SourceFile, positionOrRange: number | TextRange, preferences: UserPreferences, formatOptions?: FormatCodeSettings, triggerReason?: RefactorTriggerReason, kind?: string): RefactorContext {
|
||||
const [startPosition, endPosition] = typeof positionOrRange === "number" ? [positionOrRange, undefined] : [positionOrRange.pos, positionOrRange.end];
|
||||
return {
|
||||
file,
|
||||
@@ -2463,6 +2465,7 @@ namespace ts {
|
||||
cancellationToken,
|
||||
preferences,
|
||||
triggerReason,
|
||||
kind
|
||||
};
|
||||
}
|
||||
|
||||
@@ -2470,10 +2473,10 @@ namespace ts {
|
||||
return SmartSelectionRange.getSmartSelectionRange(position, syntaxTreeCache.getCurrentSourceFile(fileName));
|
||||
}
|
||||
|
||||
function getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences = emptyOptions, triggerReason: RefactorTriggerReason): ApplicableRefactorInfo[] {
|
||||
function getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences = emptyOptions, triggerReason: RefactorTriggerReason, kind: string): ApplicableRefactorInfo[] {
|
||||
synchronizeHostData();
|
||||
const file = getValidSourceFile(fileName);
|
||||
return refactor.getApplicableRefactors(getRefactorContext(file, positionOrRange, preferences, emptyOptions, triggerReason));
|
||||
return refactor.getApplicableRefactors(getRefactorContext(file, positionOrRange, preferences, emptyOptions, triggerReason, kind));
|
||||
}
|
||||
|
||||
function getEditsForRefactor(
|
||||
@@ -2694,7 +2697,7 @@ namespace ts {
|
||||
return symbol ? [symbol] : emptyArray;
|
||||
}
|
||||
|
||||
const discriminatedPropertySymbols = mapDefined(contextualType.types, t => isObjectLiteralExpression(node.parent) && checker.isTypeInvalidDueToUnionDiscriminant(t, node.parent) ? undefined : t.getProperty(name));
|
||||
const discriminatedPropertySymbols = mapDefined(contextualType.types, t => (isObjectLiteralExpression(node.parent)|| isJsxAttributes(node.parent)) && checker.isTypeInvalidDueToUnionDiscriminant(t, node.parent) ? undefined : t.getProperty(name));
|
||||
if (unionSymbolOk && (discriminatedPropertySymbols.length === 0 || discriminatedPropertySymbols.length === contextualType.types.length)) {
|
||||
const symbol = contextualType.getProperty(name);
|
||||
if (symbol) return [symbol];
|
||||
|
||||
@@ -100,31 +100,42 @@ namespace ts.SymbolDisplay {
|
||||
return ScriptElementKind.unknown;
|
||||
}
|
||||
|
||||
function isDeprecatedDeclaration(decl: Declaration) {
|
||||
return !!(getCombinedNodeFlagsAlwaysIncludeJSDoc(decl) & ModifierFlags.Deprecated);
|
||||
}
|
||||
|
||||
function getNormalizedSymbolModifiers(symbol: Symbol) {
|
||||
if (symbol.declarations && symbol.declarations.length) {
|
||||
const [declaration, ...declarations] = symbol.declarations;
|
||||
// omit deprecated flag if some declarations are not deprecated
|
||||
const excludeFlags = length(declarations) && isDeprecatedDeclaration(declaration) && some(declarations, d => !isDeprecatedDeclaration(d))
|
||||
? ModifierFlags.Deprecated
|
||||
: ModifierFlags.None;
|
||||
const modifiers = getNodeModifiers(declaration, excludeFlags);
|
||||
if (modifiers) {
|
||||
return modifiers.split(",");
|
||||
}
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
export function getSymbolModifiers(typeChecker: TypeChecker, symbol: Symbol): string {
|
||||
if (!symbol) {
|
||||
return ScriptElementKindModifier.none;
|
||||
}
|
||||
|
||||
const modifiers = new Set<string>();
|
||||
if (symbol.declarations && symbol.declarations.length > 0) {
|
||||
const kindModifiers = getNodeModifiers(symbol.declarations[0]);
|
||||
if (kindModifiers !== ScriptElementKindModifier.none) {
|
||||
kindModifiers.split(",").forEach(m => modifiers.add(m));
|
||||
}
|
||||
}
|
||||
const modifiers = new Set(getNormalizedSymbolModifiers(symbol));
|
||||
if (symbol.flags & SymbolFlags.Alias) {
|
||||
const resolvedSymbol = typeChecker.getAliasedSymbol(symbol);
|
||||
if (resolvedSymbol !== symbol && resolvedSymbol.declarations && resolvedSymbol.declarations.length > 0) {
|
||||
const kindModifiers = getNodeModifiers(resolvedSymbol.declarations[0]);
|
||||
if (kindModifiers !== ScriptElementKindModifier.none) {
|
||||
kindModifiers.split(",").forEach(m => modifiers.add(m));
|
||||
}
|
||||
if (resolvedSymbol !== symbol) {
|
||||
forEach(getNormalizedSymbolModifiers(resolvedSymbol), modifier => {
|
||||
modifiers.add(modifier);
|
||||
});
|
||||
}
|
||||
}
|
||||
if (symbol.flags & SymbolFlags.Optional) {
|
||||
modifiers.add(ScriptElementKindModifier.optionalModifier);
|
||||
}
|
||||
|
||||
return modifiers.size > 0 ? arrayFrom(modifiers.values()).join(",") : ScriptElementKindModifier.none;
|
||||
}
|
||||
|
||||
|
||||
@@ -116,6 +116,7 @@
|
||||
"refactors/extractSymbol.ts",
|
||||
"refactors/extractType.ts",
|
||||
"refactors/generateGetAccessorAndSetAccessor.ts",
|
||||
"refactors/helpers.ts",
|
||||
"refactors/moveToNewFile.ts",
|
||||
"refactors/addOrRemoveBracesToArrowFunction.ts",
|
||||
"refactors/convertParamsToDestructuredObject.ts",
|
||||
|
||||
+11
-1
@@ -520,7 +520,7 @@ namespace ts {
|
||||
/** @deprecated `fileName` will be ignored */
|
||||
applyCodeActionCommand(fileName: string, action: CodeActionCommand | CodeActionCommand[]): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
|
||||
|
||||
getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined, triggerReason?: RefactorTriggerReason): ApplicableRefactorInfo[];
|
||||
getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined, triggerReason?: RefactorTriggerReason, kind?: string): ApplicableRefactorInfo[];
|
||||
getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string, preferences: UserPreferences | undefined): RefactorEditInfo | undefined;
|
||||
organizeImports(scope: OrganizeImportsScope, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
|
||||
getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
|
||||
@@ -792,6 +792,11 @@ namespace ts {
|
||||
* the current context.
|
||||
*/
|
||||
notApplicableReason?: string;
|
||||
|
||||
/**
|
||||
* The hierarchical dotted name of the refactor action.
|
||||
*/
|
||||
kind?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1464,6 +1469,10 @@ namespace ts {
|
||||
|
||||
/** @internal */
|
||||
export interface Refactor {
|
||||
/** List of action kinds a refactor can provide.
|
||||
* Used to skip unnecessary calculation when specific refactors are requested. */
|
||||
kinds?: string[];
|
||||
|
||||
/** Compute the associated code actions */
|
||||
getEditsForAction(context: RefactorContext, actionName: string): RefactorEditInfo | undefined;
|
||||
|
||||
@@ -1480,5 +1489,6 @@ namespace ts {
|
||||
cancellationToken?: CancellationToken;
|
||||
preferences: UserPreferences;
|
||||
triggerReason?: RefactorTriggerReason;
|
||||
kind?: string;
|
||||
}
|
||||
}
|
||||
@@ -1588,9 +1588,11 @@ namespace ts {
|
||||
return n.kind === SyntaxKind.EndOfFileToken ? !!(n as EndOfFileToken).jsDoc : n.getWidth(sourceFile) !== 0;
|
||||
}
|
||||
|
||||
export function getNodeModifiers(node: Node): string {
|
||||
const flags = isDeclaration(node) ? getCombinedNodeFlagsAlwaysIncludeJSDoc(node) : ModifierFlags.None;
|
||||
export function getNodeModifiers(node: Node, excludeFlags = ModifierFlags.None): string {
|
||||
const result: string[] = [];
|
||||
const flags = isDeclaration(node)
|
||||
? getCombinedNodeFlagsAlwaysIncludeJSDoc(node) & ~excludeFlags
|
||||
: ModifierFlags.None;
|
||||
|
||||
if (flags & ModifierFlags.Private) result.push(ScriptElementKindModifier.privateMemberModifier);
|
||||
if (flags & ModifierFlags.Protected) result.push(ScriptElementKindModifier.protectedMemberModifier);
|
||||
|
||||
@@ -1577,6 +1577,18 @@ const fn = (): Promise<(message: string) => void> =>
|
||||
function [#|f|]() {
|
||||
return fn().then(res => res("test"));
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_emptyCatch1", `
|
||||
function [#|f|]() {
|
||||
return Promise.resolve().catch();
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunction("convertToAsyncFunction_emptyCatch2", `
|
||||
function [#|f|]() {
|
||||
return Promise.resolve(0).then(x => x).catch();
|
||||
}
|
||||
`);
|
||||
|
||||
_testConvertToAsyncFunctionWithModule("convertToAsyncFunction_importedFunction", `
|
||||
|
||||
+10
-1
@@ -5570,7 +5570,7 @@ declare namespace ts {
|
||||
applyCodeActionCommand(fileName: string, action: CodeActionCommand[]): Promise<ApplyCodeActionCommandResult[]>;
|
||||
/** @deprecated `fileName` will be ignored */
|
||||
applyCodeActionCommand(fileName: string, action: CodeActionCommand | CodeActionCommand[]): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
|
||||
getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined, triggerReason?: RefactorTriggerReason): ApplicableRefactorInfo[];
|
||||
getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined, triggerReason?: RefactorTriggerReason, kind?: string): ApplicableRefactorInfo[];
|
||||
getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string, preferences: UserPreferences | undefined): RefactorEditInfo | undefined;
|
||||
organizeImports(scope: OrganizeImportsScope, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
|
||||
getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
|
||||
@@ -5796,6 +5796,10 @@ declare namespace ts {
|
||||
* the current context.
|
||||
*/
|
||||
notApplicableReason?: string;
|
||||
/**
|
||||
* The hierarchical dotted name of the refactor action.
|
||||
*/
|
||||
kind?: string;
|
||||
}
|
||||
/**
|
||||
* A set of edits to make in response to a refactor action, plus an optional
|
||||
@@ -6926,6 +6930,7 @@ declare namespace ts.server.protocol {
|
||||
}
|
||||
type GetApplicableRefactorsRequestArgs = FileLocationOrRangeRequestArgs & {
|
||||
triggerReason?: RefactorTriggerReason;
|
||||
kind?: string;
|
||||
};
|
||||
type RefactorTriggerReason = "implicit" | "invoked";
|
||||
/**
|
||||
@@ -6978,6 +6983,10 @@ declare namespace ts.server.protocol {
|
||||
* the current context.
|
||||
*/
|
||||
notApplicableReason?: string;
|
||||
/**
|
||||
* The hierarchical dotted name of the refactor action.
|
||||
*/
|
||||
kind?: string;
|
||||
}
|
||||
interface GetEditsForRefactorRequest extends Request {
|
||||
command: CommandTypes.GetEditsForRefactor;
|
||||
|
||||
+5
-1
@@ -5570,7 +5570,7 @@ declare namespace ts {
|
||||
applyCodeActionCommand(fileName: string, action: CodeActionCommand[]): Promise<ApplyCodeActionCommandResult[]>;
|
||||
/** @deprecated `fileName` will be ignored */
|
||||
applyCodeActionCommand(fileName: string, action: CodeActionCommand | CodeActionCommand[]): Promise<ApplyCodeActionCommandResult | ApplyCodeActionCommandResult[]>;
|
||||
getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined, triggerReason?: RefactorTriggerReason): ApplicableRefactorInfo[];
|
||||
getApplicableRefactors(fileName: string, positionOrRange: number | TextRange, preferences: UserPreferences | undefined, triggerReason?: RefactorTriggerReason, kind?: string): ApplicableRefactorInfo[];
|
||||
getEditsForRefactor(fileName: string, formatOptions: FormatCodeSettings, positionOrRange: number | TextRange, refactorName: string, actionName: string, preferences: UserPreferences | undefined): RefactorEditInfo | undefined;
|
||||
organizeImports(scope: OrganizeImportsScope, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
|
||||
getEditsForFileRename(oldFilePath: string, newFilePath: string, formatOptions: FormatCodeSettings, preferences: UserPreferences | undefined): readonly FileTextChanges[];
|
||||
@@ -5796,6 +5796,10 @@ declare namespace ts {
|
||||
* the current context.
|
||||
*/
|
||||
notApplicableReason?: string;
|
||||
/**
|
||||
* The hierarchical dotted name of the refactor action.
|
||||
*/
|
||||
kind?: string;
|
||||
}
|
||||
/**
|
||||
* A set of edits to make in response to a refactor action, plus an optional
|
||||
|
||||
@@ -4,7 +4,7 @@ tests/cases/conformance/jsdoc/test.js(7,24): error TS2322: Type 'number' is not
|
||||
tests/cases/conformance/jsdoc/test.js(10,17): error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/jsdoc/test.js(12,14): error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/jsdoc/test.js(14,24): error TS2322: Type 'number' is not assignable to type 'string'.
|
||||
tests/cases/conformance/jsdoc/test.js(28,5): error TS8030: The type of a function declaration must match the function's signature.
|
||||
tests/cases/conformance/jsdoc/test.js(28,12): error TS8030: The type of a function declaration must match the function's signature.
|
||||
tests/cases/conformance/jsdoc/test.js(34,5): error TS2322: Type '1 | 2' is not assignable to type '2 | 3'.
|
||||
Type '1' is not assignable to type '2 | 3'.
|
||||
|
||||
@@ -50,7 +50,7 @@ tests/cases/conformance/jsdoc/test.js(34,5): error TS2322: Type '1 | 2' is not a
|
||||
/** @typedef {{(s: string): 0 | 1; (b: boolean): 2 | 3 }} Gioconda */
|
||||
|
||||
/** @type {Gioconda} */
|
||||
~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~
|
||||
!!! error TS8030: The type of a function declaration must match the function's signature.
|
||||
function monaLisa(sb) {
|
||||
return typeof sb === 'string' ? 1 : 2;
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
tests/cases/conformance/jsdoc/test.js(1,5): error TS8030: The type of a function declaration must match the function's signature.
|
||||
tests/cases/conformance/jsdoc/test.js(1,12): error TS8030: The type of a function declaration must match the function's signature.
|
||||
tests/cases/conformance/jsdoc/test.js(7,5): error TS2741: Property 'prop' is missing in type '(prop: any) => void' but required in type '{ prop: string; }'.
|
||||
tests/cases/conformance/jsdoc/test.js(10,5): error TS8030: The type of a function declaration must match the function's signature.
|
||||
tests/cases/conformance/jsdoc/test.js(10,12): error TS8030: The type of a function declaration must match the function's signature.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/test.js (3 errors) ====
|
||||
/** @type {number} */
|
||||
~~~~~~~~~~~~~~
|
||||
~~~~~~
|
||||
!!! error TS8030: The type of a function declaration must match the function's signature.
|
||||
function f() {
|
||||
return 1
|
||||
@@ -19,7 +19,7 @@ tests/cases/conformance/jsdoc/test.js(10,5): error TS8030: The type of a functio
|
||||
}
|
||||
|
||||
/** @type {(a: number) => number} */
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
!!! error TS8030: The type of a function declaration must match the function's signature.
|
||||
function add1(a, b) { return a + b; }
|
||||
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// ==ORIGINAL==
|
||||
|
||||
function /*[#|*/f/*|]*/() {
|
||||
return Promise.resolve().catch();
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
async function f() {
|
||||
try {
|
||||
return Promise.resolve();
|
||||
} catch (e) { }
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// ==ORIGINAL==
|
||||
|
||||
function /*[#|*/f/*|]*/() {
|
||||
return Promise.resolve().catch();
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
async function f() {
|
||||
try {
|
||||
return Promise.resolve();
|
||||
} catch (e) { }
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// ==ORIGINAL==
|
||||
|
||||
function /*[#|*/f/*|]*/() {
|
||||
return Promise.resolve(0).then(x => x).catch();
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
async function f() {
|
||||
try {
|
||||
const x = await Promise.resolve(0);
|
||||
return x;
|
||||
} catch (e) { }
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// ==ORIGINAL==
|
||||
|
||||
function /*[#|*/f/*|]*/() {
|
||||
return Promise.resolve(0).then(x => x).catch();
|
||||
}
|
||||
|
||||
// ==ASYNC FUNCTION::Convert to async function==
|
||||
|
||||
async function f() {
|
||||
try {
|
||||
const x = await Promise.resolve(0);
|
||||
return x;
|
||||
} catch (e) { }
|
||||
}
|
||||
@@ -9,11 +9,12 @@ tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(35,15): erro
|
||||
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(69,10): error TS1264: Declarations with definite assignment assertions must also have type annotations.
|
||||
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(70,10): error TS1263: Declarations with initializers cannot also have definite assignment assertions.
|
||||
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(71,10): error TS1263: Declarations with initializers cannot also have definite assignment assertions.
|
||||
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(76,15): error TS1264: Declarations with definite assignment assertions must also have type annotations.
|
||||
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(77,15): error TS1264: Declarations with definite assignment assertions must also have type annotations.
|
||||
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(76,15): error TS1255: A definite assignment assertion '!' is not permitted in this context.
|
||||
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(77,15): error TS1255: A definite assignment assertion '!' is not permitted in this context.
|
||||
tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(80,7): error TS1255: A definite assignment assertion '!' is not permitted in this context.
|
||||
|
||||
|
||||
==== tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts (13 errors) ====
|
||||
==== tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts (14 errors) ====
|
||||
// Suppress strict property initialization check
|
||||
|
||||
class C1 {
|
||||
@@ -113,8 +114,14 @@ tests/cases/conformance/controlFlow/definiteAssignmentAssertions.ts(77,15): erro
|
||||
|
||||
declare let v1!: number;
|
||||
~
|
||||
!!! error TS1264: Declarations with definite assignment assertions must also have type annotations.
|
||||
!!! error TS1255: A definite assignment assertion '!' is not permitted in this context.
|
||||
declare var v2!: number;
|
||||
~
|
||||
!!! error TS1264: Declarations with definite assignment assertions must also have type annotations.
|
||||
!!! error TS1255: A definite assignment assertion '!' is not permitted in this context.
|
||||
|
||||
declare namespace foo {
|
||||
var v!: number;
|
||||
~
|
||||
!!! error TS1255: A definite assignment assertion '!' is not permitted in this context.
|
||||
}
|
||||
|
||||
@@ -76,6 +76,10 @@ function f4() {
|
||||
|
||||
declare let v1!: number;
|
||||
declare var v2!: number;
|
||||
|
||||
declare namespace foo {
|
||||
var v!: number;
|
||||
}
|
||||
|
||||
|
||||
//// [definiteAssignmentAssertions.js]
|
||||
@@ -166,3 +170,6 @@ declare function f3(): void;
|
||||
declare function f4(): void;
|
||||
declare let v1: number;
|
||||
declare var v2: number;
|
||||
declare namespace foo {
|
||||
var v: number;
|
||||
}
|
||||
@@ -147,3 +147,10 @@ declare let v1!: number;
|
||||
declare var v2!: number;
|
||||
>v2 : Symbol(v2, Decl(definiteAssignmentAssertions.ts, 76, 11))
|
||||
|
||||
declare namespace foo {
|
||||
>foo : Symbol(foo, Decl(definiteAssignmentAssertions.ts, 76, 24))
|
||||
|
||||
var v!: number;
|
||||
>v : Symbol(v, Decl(definiteAssignmentAssertions.ts, 79, 4))
|
||||
}
|
||||
|
||||
@@ -158,3 +158,10 @@ declare let v1!: number;
|
||||
declare var v2!: number;
|
||||
>v2 : number
|
||||
|
||||
declare namespace foo {
|
||||
>foo : typeof foo
|
||||
|
||||
var v!: number;
|
||||
>v : number
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ tests/cases/conformance/es6/destructuring/destructuringParameterDeclaration4.ts(
|
||||
a1(...array2); // Error parameter type is (number|string)[]
|
||||
~~~~~~
|
||||
!!! error TS2552: Cannot find name 'array2'. Did you mean 'Array'?
|
||||
!!! related TS2728 /.ts/lib.es5.d.ts:1403:13: 'Array' is declared here.
|
||||
!!! related TS2728 /.ts/lib.es5.d.ts:1415:13: 'Array' is declared here.
|
||||
a5([1, 2, "string", false, true]); // Error, parameter type is [any, any, [[any]]]
|
||||
~~~~~~~~
|
||||
!!! error TS2322: Type 'string' is not assignable to type '[[any]]'.
|
||||
|
||||
@@ -33,8 +33,8 @@ tests/cases/compiler/destructuringTuple.ts(11,60): error TS2769: No overload mat
|
||||
!!! error TS2769: Overload 2 of 3, '(callbackfn: (previousValue: [], currentValue: number, currentIndex: number, array: number[]) => [], initialValue: []): []', gave the following error.
|
||||
!!! error TS2769: Type 'never[]' is not assignable to type '[]'.
|
||||
!!! error TS2769: Target allows only 0 element(s) but source may have more.
|
||||
!!! related TS6502 /.ts/lib.es5.d.ts:1368:24: The expected type comes from the return type of this signature.
|
||||
!!! related TS6502 /.ts/lib.es5.d.ts:1374:27: The expected type comes from the return type of this signature.
|
||||
!!! related TS6502 /.ts/lib.es5.d.ts:1380:24: The expected type comes from the return type of this signature.
|
||||
!!! related TS6502 /.ts/lib.es5.d.ts:1386:27: The expected type comes from the return type of this signature.
|
||||
~~
|
||||
!!! error TS2769: No overload matches this call.
|
||||
!!! error TS2769: Overload 1 of 2, '(...items: ConcatArray<never>[]): never[]', gave the following error.
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
//// [foo.js]
|
||||
/**
|
||||
* foo
|
||||
*
|
||||
* @public
|
||||
* @param {object} opts
|
||||
* @param {number} opts.a
|
||||
* @param {number} [opts.b]
|
||||
* @param {number} [opts.c]
|
||||
* @returns {number}
|
||||
*/
|
||||
function foo({ a, b, c }) {
|
||||
return a + b + c;
|
||||
}
|
||||
|
||||
|
||||
//// [foo.js]
|
||||
/**
|
||||
* foo
|
||||
*
|
||||
* @public
|
||||
* @param {object} opts
|
||||
* @param {number} opts.a
|
||||
* @param {number} [opts.b]
|
||||
* @param {number} [opts.c]
|
||||
* @returns {number}
|
||||
*/
|
||||
function foo({ a, b, c }) {
|
||||
return a + b + c;
|
||||
}
|
||||
|
||||
|
||||
//// [foo.d.ts]
|
||||
/**
|
||||
* foo
|
||||
*
|
||||
* @public
|
||||
* @param {object} opts
|
||||
* @param {number} opts.a
|
||||
* @param {number} [opts.b]
|
||||
* @param {number} [opts.c]
|
||||
* @returns {number}
|
||||
*/
|
||||
declare function foo({ a, b, c }: {
|
||||
a: number;
|
||||
b?: number;
|
||||
c?: number;
|
||||
}): number;
|
||||
@@ -0,0 +1,23 @@
|
||||
=== tests/cases/conformance/jsdoc/declarations/foo.js ===
|
||||
/**
|
||||
* foo
|
||||
*
|
||||
* @public
|
||||
* @param {object} opts
|
||||
* @param {number} opts.a
|
||||
* @param {number} [opts.b]
|
||||
* @param {number} [opts.c]
|
||||
* @returns {number}
|
||||
*/
|
||||
function foo({ a, b, c }) {
|
||||
>foo : Symbol(foo, Decl(foo.js, 0, 0))
|
||||
>a : Symbol(a, Decl(foo.js, 10, 14))
|
||||
>b : Symbol(b, Decl(foo.js, 10, 17))
|
||||
>c : Symbol(c, Decl(foo.js, 10, 20))
|
||||
|
||||
return a + b + c;
|
||||
>a : Symbol(a, Decl(foo.js, 10, 14))
|
||||
>b : Symbol(b, Decl(foo.js, 10, 17))
|
||||
>c : Symbol(c, Decl(foo.js, 10, 20))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
=== tests/cases/conformance/jsdoc/declarations/foo.js ===
|
||||
/**
|
||||
* foo
|
||||
*
|
||||
* @public
|
||||
* @param {object} opts
|
||||
* @param {number} opts.a
|
||||
* @param {number} [opts.b]
|
||||
* @param {number} [opts.c]
|
||||
* @returns {number}
|
||||
*/
|
||||
function foo({ a, b, c }) {
|
||||
>foo : ({ a, b, c }: { a: number; b?: number; c?: number;}) => number
|
||||
>a : number
|
||||
>b : number
|
||||
>c : number
|
||||
|
||||
return a + b + c;
|
||||
>a + b + c : number
|
||||
>a + b : number
|
||||
>a : number
|
||||
>b : number
|
||||
>c : number
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
//// [foo.js]
|
||||
/**
|
||||
* foo
|
||||
*
|
||||
* @public
|
||||
* @param {object} opts
|
||||
* @param {number} opts.a
|
||||
* @param {number} [opts.b]
|
||||
* @param {number} [opts.c]
|
||||
* @returns {number}
|
||||
*/
|
||||
function foo({ a, b, c }) {
|
||||
return a + (b ?? 0) + (c ?? 0);
|
||||
}
|
||||
|
||||
|
||||
//// [foo.js]
|
||||
"use strict";
|
||||
/**
|
||||
* foo
|
||||
*
|
||||
* @public
|
||||
* @param {object} opts
|
||||
* @param {number} opts.a
|
||||
* @param {number} [opts.b]
|
||||
* @param {number} [opts.c]
|
||||
* @returns {number}
|
||||
*/
|
||||
function foo({ a, b, c }) {
|
||||
return a + (b ?? 0) + (c ?? 0);
|
||||
}
|
||||
|
||||
|
||||
//// [foo.d.ts]
|
||||
/**
|
||||
* foo
|
||||
*
|
||||
* @public
|
||||
* @param {object} opts
|
||||
* @param {number} opts.a
|
||||
* @param {number} [opts.b]
|
||||
* @param {number} [opts.c]
|
||||
* @returns {number}
|
||||
*/
|
||||
declare function foo({ a, b, c }: {
|
||||
a: number;
|
||||
b?: number | undefined;
|
||||
c?: number | undefined;
|
||||
}): number;
|
||||
@@ -0,0 +1,23 @@
|
||||
=== tests/cases/conformance/jsdoc/declarations/foo.js ===
|
||||
/**
|
||||
* foo
|
||||
*
|
||||
* @public
|
||||
* @param {object} opts
|
||||
* @param {number} opts.a
|
||||
* @param {number} [opts.b]
|
||||
* @param {number} [opts.c]
|
||||
* @returns {number}
|
||||
*/
|
||||
function foo({ a, b, c }) {
|
||||
>foo : Symbol(foo, Decl(foo.js, 0, 0))
|
||||
>a : Symbol(a, Decl(foo.js, 10, 14))
|
||||
>b : Symbol(b, Decl(foo.js, 10, 17))
|
||||
>c : Symbol(c, Decl(foo.js, 10, 20))
|
||||
|
||||
return a + (b ?? 0) + (c ?? 0);
|
||||
>a : Symbol(a, Decl(foo.js, 10, 14))
|
||||
>b : Symbol(b, Decl(foo.js, 10, 17))
|
||||
>c : Symbol(c, Decl(foo.js, 10, 20))
|
||||
}
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
=== tests/cases/conformance/jsdoc/declarations/foo.js ===
|
||||
/**
|
||||
* foo
|
||||
*
|
||||
* @public
|
||||
* @param {object} opts
|
||||
* @param {number} opts.a
|
||||
* @param {number} [opts.b]
|
||||
* @param {number} [opts.c]
|
||||
* @returns {number}
|
||||
*/
|
||||
function foo({ a, b, c }) {
|
||||
>foo : ({ a, b, c }: { a: number; b?: number | undefined; c?: number | undefined;}) => number
|
||||
>a : number
|
||||
>b : number | undefined
|
||||
>c : number | undefined
|
||||
|
||||
return a + (b ?? 0) + (c ?? 0);
|
||||
>a + (b ?? 0) + (c ?? 0) : number
|
||||
>a + (b ?? 0) : number
|
||||
>a : number
|
||||
>(b ?? 0) : number
|
||||
>b ?? 0 : number
|
||||
>b : number | undefined
|
||||
>0 : 0
|
||||
>(c ?? 0) : number
|
||||
>c ?? 0 : number
|
||||
>c : number | undefined
|
||||
>0 : 0
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ normal(12);
|
||||
* @param {string} [opts1.w="hi"] doc5
|
||||
*/
|
||||
function foo1(opts1) {
|
||||
>foo1 : (opts1: { x: string; y?: string | undefined; z: string | undefined; w: string | undefined;}) => void
|
||||
>foo1 : (opts1: { x: string; y?: string | undefined; z?: string | undefined; w?: string | undefined;}) => void
|
||||
>opts1 : { x: string; y?: string | undefined; z?: string | undefined; w?: string | undefined; }
|
||||
|
||||
opts1.x;
|
||||
@@ -92,7 +92,7 @@ foo3({x: 'abc'});
|
||||
* @param {string} [opts4[].w="hi"]
|
||||
*/
|
||||
function foo4(opts4) {
|
||||
>foo4 : (opts4: { x: string; y?: string | undefined; z: string; w: string;}) => void
|
||||
>foo4 : (opts4: { x: string; y?: string | undefined; z?: string; w?: string;}) => void
|
||||
>opts4 : { x: string; y?: string | undefined; z?: string | undefined; w?: string | undefined; }[]
|
||||
|
||||
opts4[0].x;
|
||||
|
||||
@@ -16,10 +16,10 @@ var p = new Proxy(t, {});
|
||||
>{} : {}
|
||||
|
||||
Reflect.ownKeys({});
|
||||
>Reflect.ownKeys({}) : PropertyKey[]
|
||||
>Reflect.ownKeys : (target: object) => PropertyKey[]
|
||||
>Reflect.ownKeys({}) : (string | symbol)[]
|
||||
>Reflect.ownKeys : (target: object) => (string | symbol)[]
|
||||
>Reflect : typeof Reflect
|
||||
>ownKeys : (target: object) => PropertyKey[]
|
||||
>ownKeys : (target: object) => (string | symbol)[]
|
||||
>{} : {}
|
||||
|
||||
function* idGen() {
|
||||
|
||||
@@ -447,7 +447,7 @@ tests/cases/compiler/promisePermutations.ts(160,21): error TS2769: No overload m
|
||||
!!! error TS2769: The last overload gave the following error.
|
||||
!!! error TS2769: Argument of type '(x: any) => IPromise<string>' is not assignable to parameter of type '(error: any) => Promise<number>'.
|
||||
!!! error TS2769: Property 'catch' is missing in type 'IPromise<string>' but required in type 'Promise<number>'.
|
||||
!!! related TS2728 /.ts/lib.es5.d.ts:1448:5: 'catch' is declared here.
|
||||
!!! related TS2728 /.ts/lib.es5.d.ts:1460:5: 'catch' is declared here.
|
||||
!!! related TS2771 tests/cases/compiler/promisePermutations.ts:5:5: The last overload is declared here.
|
||||
var s10g = s10.then(testFunctionP, nIPromise, sIPromise).then(sPromise, sIPromise, sIPromise); // ok
|
||||
|
||||
|
||||
@@ -351,7 +351,7 @@ tests/cases/compiler/promisePermutations2.ts(159,21): error TS2345: Argument of
|
||||
~~~~~~~~~
|
||||
!!! error TS2345: Argument of type '(x: any) => IPromise<string>' is not assignable to parameter of type '(error: any) => Promise<number>'.
|
||||
!!! error TS2345: Property 'catch' is missing in type 'IPromise<string>' but required in type 'Promise<number>'.
|
||||
!!! related TS2728 /.ts/lib.es5.d.ts:1448:5: 'catch' is declared here.
|
||||
!!! related TS2728 /.ts/lib.es5.d.ts:1460:5: 'catch' is declared here.
|
||||
var s10g = s10.then(testFunctionP, nIPromise, sIPromise).then(sPromise, sIPromise, sIPromise); // ok
|
||||
|
||||
var r11: IPromise<number>;
|
||||
|
||||
@@ -398,7 +398,7 @@ tests/cases/compiler/promisePermutations3.ts(165,21): error TS2345: Argument of
|
||||
!!! error TS2769: The last overload gave the following error.
|
||||
!!! error TS2769: Argument of type '(x: any) => IPromise<string>' is not assignable to parameter of type '(error: any) => Promise<number>'.
|
||||
!!! error TS2769: Property 'catch' is missing in type 'IPromise<string>' but required in type 'Promise<number>'.
|
||||
!!! related TS2728 /.ts/lib.es5.d.ts:1448:5: 'catch' is declared here.
|
||||
!!! related TS2728 /.ts/lib.es5.d.ts:1460:5: 'catch' is declared here.
|
||||
!!! related TS2771 tests/cases/compiler/promisePermutations3.ts:7:5: The last overload is declared here.
|
||||
var s10g = s10.then(testFunctionP, nIPromise, sIPromise).then(sPromise, sIPromise, sIPromise); // ok
|
||||
|
||||
@@ -445,5 +445,5 @@ tests/cases/compiler/promisePermutations3.ts(165,21): error TS2345: Argument of
|
||||
~~~~~~~~~~~~~~~
|
||||
!!! error TS2345: Argument of type '{ <T>(x: T): IPromise<T>; <T>(x: T, y: T): Promise<T>; }' is not assignable to parameter of type '(value: (x: any) => any) => Promise<unknown>'.
|
||||
!!! error TS2345: Property 'catch' is missing in type 'IPromise<any>' but required in type 'Promise<unknown>'.
|
||||
!!! related TS2728 /.ts/lib.es5.d.ts:1448:5: 'catch' is declared here.
|
||||
!!! related TS2728 /.ts/lib.es5.d.ts:1460:5: 'catch' is declared here.
|
||||
var s12c = s12.then(testFunction12P, testFunction12, testFunction12); // ok
|
||||
@@ -0,0 +1,110 @@
|
||||
[
|
||||
{
|
||||
"marker": {
|
||||
"fileName": "/tests/cases/fourslash/quickInfoJsDocTags1.ts",
|
||||
"position": 298
|
||||
},
|
||||
"quickInfo": {
|
||||
"kind": "function",
|
||||
"kindModifiers": "",
|
||||
"textSpan": {
|
||||
"start": 298,
|
||||
"length": 3
|
||||
},
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "function",
|
||||
"kind": "keyword"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "foo",
|
||||
"kind": "functionName"
|
||||
},
|
||||
{
|
||||
"text": "(",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": "x",
|
||||
"kind": "parameterName"
|
||||
},
|
||||
{
|
||||
"text": ":",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "any",
|
||||
"kind": "keyword"
|
||||
},
|
||||
{
|
||||
"text": ")",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": ":",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "void",
|
||||
"kind": "keyword"
|
||||
}
|
||||
],
|
||||
"documentation": [
|
||||
{
|
||||
"text": "Doc",
|
||||
"kind": "text"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"name": "author",
|
||||
"text": "Me <me@domain.tld>"
|
||||
},
|
||||
{
|
||||
"name": "augments",
|
||||
"text": "C<T> Augments it"
|
||||
},
|
||||
{
|
||||
"name": "template",
|
||||
"text": "T A template"
|
||||
},
|
||||
{
|
||||
"name": "type",
|
||||
"text": "{number | string} A type"
|
||||
},
|
||||
{
|
||||
"name": "typedef",
|
||||
"text": "NumOrStr"
|
||||
},
|
||||
{
|
||||
"name": "property",
|
||||
"text": "{number} x The prop"
|
||||
},
|
||||
{
|
||||
"name": "param",
|
||||
"text": "x The param"
|
||||
},
|
||||
{
|
||||
"name": "returns",
|
||||
"text": "The result"
|
||||
},
|
||||
{
|
||||
"name": "see",
|
||||
"text": "x (the parameter)"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,94 @@
|
||||
[
|
||||
{
|
||||
"marker": {
|
||||
"fileName": "/tests/cases/fourslash/quickInfoJsDocTags3.ts",
|
||||
"position": 290
|
||||
},
|
||||
"quickInfo": {
|
||||
"kind": "method",
|
||||
"kindModifiers": "",
|
||||
"textSpan": {
|
||||
"start": 290,
|
||||
"length": 6
|
||||
},
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "(",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": "method",
|
||||
"kind": "text"
|
||||
},
|
||||
{
|
||||
"text": ")",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "Bar",
|
||||
"kind": "className"
|
||||
},
|
||||
{
|
||||
"text": ".",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": "method",
|
||||
"kind": "methodName"
|
||||
},
|
||||
{
|
||||
"text": "(",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": ")",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": ":",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "void",
|
||||
"kind": "keyword"
|
||||
}
|
||||
],
|
||||
"documentation": [
|
||||
{
|
||||
"text": "comment",
|
||||
"kind": "text"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"name": "author",
|
||||
"text": "Me <me@domain.tld>"
|
||||
},
|
||||
{
|
||||
"name": "see",
|
||||
"text": "x (the parameter)"
|
||||
},
|
||||
{
|
||||
"name": "param",
|
||||
"text": "x - x comment"
|
||||
},
|
||||
{
|
||||
"name": "param",
|
||||
"text": "y - y comment"
|
||||
},
|
||||
{
|
||||
"name": "throws",
|
||||
"text": "{Error} comment"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,134 @@
|
||||
[
|
||||
{
|
||||
"marker": {
|
||||
"fileName": "/tests/cases/fourslash/quickInfoJsDocTags4.ts",
|
||||
"position": 309
|
||||
},
|
||||
"quickInfo": {
|
||||
"kind": "method",
|
||||
"kindModifiers": "",
|
||||
"textSpan": {
|
||||
"start": 309,
|
||||
"length": 6
|
||||
},
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "(",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": "method",
|
||||
"kind": "text"
|
||||
},
|
||||
{
|
||||
"text": ")",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "Bar",
|
||||
"kind": "className"
|
||||
},
|
||||
{
|
||||
"text": ".",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": "method",
|
||||
"kind": "methodName"
|
||||
},
|
||||
{
|
||||
"text": "(",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": "x",
|
||||
"kind": "parameterName"
|
||||
},
|
||||
{
|
||||
"text": ":",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "number",
|
||||
"kind": "keyword"
|
||||
},
|
||||
{
|
||||
"text": ",",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "y",
|
||||
"kind": "parameterName"
|
||||
},
|
||||
{
|
||||
"text": ":",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "number",
|
||||
"kind": "keyword"
|
||||
},
|
||||
{
|
||||
"text": ")",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": ":",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "number",
|
||||
"kind": "keyword"
|
||||
}
|
||||
],
|
||||
"documentation": [
|
||||
{
|
||||
"text": "comment",
|
||||
"kind": "text"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"name": "author",
|
||||
"text": "Me <me@domain.tld>"
|
||||
},
|
||||
{
|
||||
"name": "see",
|
||||
"text": "x (the parameter)"
|
||||
},
|
||||
{
|
||||
"name": "param",
|
||||
"text": "x - x comment"
|
||||
},
|
||||
{
|
||||
"name": "param",
|
||||
"text": "y - y comment"
|
||||
},
|
||||
{
|
||||
"name": "returns",
|
||||
"text": "The result"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,134 @@
|
||||
[
|
||||
{
|
||||
"marker": {
|
||||
"fileName": "/tests/cases/fourslash/quickInfoJsDocTags5.js",
|
||||
"position": 285
|
||||
},
|
||||
"quickInfo": {
|
||||
"kind": "method",
|
||||
"kindModifiers": "",
|
||||
"textSpan": {
|
||||
"start": 285,
|
||||
"length": 6
|
||||
},
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "(",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": "method",
|
||||
"kind": "text"
|
||||
},
|
||||
{
|
||||
"text": ")",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "Bar",
|
||||
"kind": "className"
|
||||
},
|
||||
{
|
||||
"text": ".",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": "method",
|
||||
"kind": "methodName"
|
||||
},
|
||||
{
|
||||
"text": "(",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": "x",
|
||||
"kind": "parameterName"
|
||||
},
|
||||
{
|
||||
"text": ":",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "any",
|
||||
"kind": "keyword"
|
||||
},
|
||||
{
|
||||
"text": ",",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "y",
|
||||
"kind": "parameterName"
|
||||
},
|
||||
{
|
||||
"text": ":",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "any",
|
||||
"kind": "keyword"
|
||||
},
|
||||
{
|
||||
"text": ")",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": ":",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "number",
|
||||
"kind": "keyword"
|
||||
}
|
||||
],
|
||||
"documentation": [
|
||||
{
|
||||
"text": "comment",
|
||||
"kind": "text"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"name": "author",
|
||||
"text": "Me <me@domain.tld>"
|
||||
},
|
||||
{
|
||||
"name": "see",
|
||||
"text": "x (the parameter)"
|
||||
},
|
||||
{
|
||||
"name": "param",
|
||||
"text": "x - x comment"
|
||||
},
|
||||
{
|
||||
"name": "param",
|
||||
"text": "y - y comment"
|
||||
},
|
||||
{
|
||||
"name": "returns",
|
||||
"text": "The result"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,137 @@
|
||||
[
|
||||
{
|
||||
"marker": {
|
||||
"fileName": "/tests/cases/fourslash/quickInfoJsDocTags6.js",
|
||||
"position": 308
|
||||
},
|
||||
"quickInfo": {
|
||||
"kind": "method",
|
||||
"kindModifiers": "",
|
||||
"textSpan": {
|
||||
"start": 308,
|
||||
"length": 6
|
||||
},
|
||||
"displayParts": [
|
||||
{
|
||||
"text": "(",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": "method",
|
||||
"kind": "text"
|
||||
},
|
||||
{
|
||||
"text": ")",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "Bar",
|
||||
"kind": "className"
|
||||
},
|
||||
{
|
||||
"text": ".",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": "method",
|
||||
"kind": "methodName"
|
||||
},
|
||||
{
|
||||
"text": "(",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": "x",
|
||||
"kind": "parameterName"
|
||||
},
|
||||
{
|
||||
"text": ":",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "any",
|
||||
"kind": "keyword"
|
||||
},
|
||||
{
|
||||
"text": ",",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "y",
|
||||
"kind": "parameterName"
|
||||
},
|
||||
{
|
||||
"text": ":",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "any",
|
||||
"kind": "keyword"
|
||||
},
|
||||
{
|
||||
"text": ")",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": ":",
|
||||
"kind": "punctuation"
|
||||
},
|
||||
{
|
||||
"text": " ",
|
||||
"kind": "space"
|
||||
},
|
||||
{
|
||||
"text": "number",
|
||||
"kind": "keyword"
|
||||
}
|
||||
],
|
||||
"documentation": [
|
||||
{
|
||||
"text": "comment",
|
||||
"kind": "text"
|
||||
}
|
||||
],
|
||||
"tags": [
|
||||
{
|
||||
"name": "author",
|
||||
"text": "Me <me@domain.tld>"
|
||||
},
|
||||
{
|
||||
"name": "see",
|
||||
"text": "x (the parameter)"
|
||||
},
|
||||
{
|
||||
"name": "param",
|
||||
"text": "x - x comment"
|
||||
},
|
||||
{
|
||||
"name": "param",
|
||||
"text": "y - y comment"
|
||||
},
|
||||
{
|
||||
"name": "returns",
|
||||
"text": "The result"
|
||||
},
|
||||
{
|
||||
"name": "inheritDoc"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -5,4 +5,4 @@ tests/cases/compiler/redefineArray.ts(1,1): error TS2741: Property 'isArray' is
|
||||
Array = function (n:number, s:string) {return n;};
|
||||
~~~~~
|
||||
!!! error TS2741: Property 'isArray' is missing in type '(n: number, s: string) => number' but required in type 'ArrayConstructor'.
|
||||
!!! related TS2728 /.ts/lib.es5.d.ts:1399:5: 'isArray' is declared here.
|
||||
!!! related TS2728 /.ts/lib.es5.d.ts:1411:5: 'isArray' is declared here.
|
||||
@@ -1,10 +1,10 @@
|
||||
tests/cases/conformance/jsdoc/bug27346.js(2,4): error TS8030: The type of a function declaration must match the function's signature.
|
||||
tests/cases/conformance/jsdoc/bug27346.js(2,11): error TS8030: The type of a function declaration must match the function's signature.
|
||||
|
||||
|
||||
==== tests/cases/conformance/jsdoc/bug27346.js (1 errors) ====
|
||||
/**
|
||||
* @type {MyClass}
|
||||
~~~~~~~~~~~~~~~
|
||||
~~~~~~~
|
||||
!!! error TS8030: The type of a function declaration must match the function's signature.
|
||||
*/
|
||||
function MyClass() { }
|
||||
|
||||
@@ -78,3 +78,7 @@ function f4() {
|
||||
|
||||
declare let v1!: number;
|
||||
declare var v2!: number;
|
||||
|
||||
declare namespace foo {
|
||||
var v!: number;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @target: esnext
|
||||
// @outDir: ./out
|
||||
// @declaration: true
|
||||
// @filename: foo.js
|
||||
/**
|
||||
* foo
|
||||
*
|
||||
* @public
|
||||
* @param {object} opts
|
||||
* @param {number} opts.a
|
||||
* @param {number} [opts.b]
|
||||
* @param {number} [opts.c]
|
||||
* @returns {number}
|
||||
*/
|
||||
function foo({ a, b, c }) {
|
||||
return a + b + c;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
// @allowJs: true
|
||||
// @checkJs: true
|
||||
// @strict: true
|
||||
// @target: esnext
|
||||
// @outDir: ./out
|
||||
// @declaration: true
|
||||
// @filename: foo.js
|
||||
/**
|
||||
* foo
|
||||
*
|
||||
* @public
|
||||
* @param {object} opts
|
||||
* @param {number} opts.a
|
||||
* @param {number} [opts.b]
|
||||
* @param {number} [opts.c]
|
||||
* @returns {number}
|
||||
*/
|
||||
function foo({ a, b, c }) {
|
||||
return a + (b ?? 0) + (c ?? 0);
|
||||
}
|
||||
@@ -3,4 +3,4 @@
|
||||
////var a: Array<string> | Array<number>;
|
||||
////a./*1*/length
|
||||
|
||||
verify.quickInfoAt("1", "(property) Array<T>.length: number", "Gets or sets the length of the array. This is a number one higher than the highest element defined in an array.");
|
||||
verify.quickInfoAt("1", "(property) Array<T>.length: number", "Gets or sets the length of the array. This is a number one higher than the highest index in the array.");
|
||||
@@ -11,7 +11,7 @@ verify.completions({
|
||||
{
|
||||
name: "length",
|
||||
text: "(property) Array<number>.length: number",
|
||||
documentation: "Gets or sets the length of the array. This is a number one higher than the highest element defined in an array.",
|
||||
documentation: "Gets or sets the length of the array. This is a number one higher than the highest index in the array.",
|
||||
kind: "property",
|
||||
kindModifiers: "declare",
|
||||
},
|
||||
|
||||
File renamed without changes.
@@ -0,0 +1,15 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
/////** @deprecated foo */
|
||||
////declare function foo<T>();
|
||||
/////** @deprecated foo<T> */
|
||||
////declare function foo<T>(x);
|
||||
////
|
||||
////foo/**/
|
||||
|
||||
verify.completions({
|
||||
marker: "",
|
||||
includes: [
|
||||
{ name: "foo", kind: "function", kindModifiers: "deprecated,declare" }
|
||||
]
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
/////** @deprecated foo */
|
||||
////declare function foo<T>();
|
||||
/////** ok */
|
||||
////declare function foo<T>(x);
|
||||
////
|
||||
////foo/**/
|
||||
|
||||
verify.completions({
|
||||
marker: "",
|
||||
includes: [
|
||||
{ name: "foo", kind: "function", kindModifiers: "declare" }
|
||||
]
|
||||
});
|
||||
@@ -244,6 +244,7 @@ declare namespace FourSlashInterface {
|
||||
|
||||
refactorAvailable(name: string, actionName?: string): void;
|
||||
refactorAvailableForTriggerReason(triggerReason: RefactorTriggerReason, name: string, action?: string): void;
|
||||
refactorKindAvailable(refactorKind: string, expected: string[], preferences?: {}): void;
|
||||
}
|
||||
class verify extends verifyNegatable {
|
||||
assertHasRanges(ranges: Range[]): void;
|
||||
|
||||
@@ -6,17 +6,29 @@
|
||||
//// }
|
||||
//// interface ElementAttributesProperty { props }
|
||||
//// }
|
||||
//// interface Props<T> {
|
||||
//// items: T[];
|
||||
//// renderItem: (item: T) => string;
|
||||
//// interface PropsA<T> {
|
||||
//// /** comments for A */
|
||||
//// name: 'A',
|
||||
//// items: T[];
|
||||
//// renderItem: (item: T) => string;
|
||||
//// }
|
||||
//// interface PropsB<T> {
|
||||
//// /** comments for B */
|
||||
//// name: 'B',
|
||||
//// items: T[];
|
||||
//// renderItem: (item: T) => string;
|
||||
//// }
|
||||
//// class Component<T> {
|
||||
//// constructor(props: Props<T>) {}
|
||||
//// props: Props<T>;
|
||||
//// }
|
||||
//// var b = new Component({items: [0, 1, 2], render/*0*/Item: it/*1*/em => item.toFixed()});
|
||||
//// var c = <Component items={[0, 1, 2]} render/*2*/Item={it/*3*/em => item.toFixed()}
|
||||
verify.quickInfoAt("0", "(property) Props<number>.renderItem: (item: number) => string");
|
||||
//// constructor(props: PropsA<T> | PropsB<T>) {}
|
||||
//// props: PropsA<T> | PropsB<T>;
|
||||
//// }
|
||||
//// var b = new Component({items: [0, 1, 2], render/*0*/Item: it/*1*/em => item.toFixed(), name/*2*/: 'A',});
|
||||
//// var c = <Component items={[0, 1, 2]} render/*3*/Item={it/*4*/em => item.toFixed()} name/*5*/="A" />
|
||||
|
||||
|
||||
verify.quickInfoAt("0", "(property) PropsA<number>.renderItem: (item: number) => string");
|
||||
verify.quickInfoAt("1", "(parameter) item: number");
|
||||
verify.quickInfoAt("2", "(JSX attribute) Props<number>.renderItem: (item: number) => string");
|
||||
verify.quickInfoAt("3", "(parameter) item: number");
|
||||
verify.quickInfoAt("2", `(property) PropsA<T>.name: "A"`, 'comments for A');
|
||||
verify.quickInfoAt("3", "(JSX attribute) PropsA<number>.renderItem: (item: number) => string");
|
||||
verify.quickInfoAt("4", "(parameter) item: number");
|
||||
verify.quickInfoAt("5", `(JSX attribute) PropsA<T>.name: "A"`, 'comments for A');
|
||||
@@ -1,18 +0,0 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @Filename: quickInfoJsDocTags.ts
|
||||
/////**
|
||||
//// * Doc
|
||||
//// * @author Me <me@domain.tld>
|
||||
//// * @augments {C<T>} Augments it
|
||||
//// * @template T A template
|
||||
//// * @type {number | string} A type
|
||||
//// * @typedef {number | string} NumOrStr
|
||||
//// * @property {number} x The prop
|
||||
//// * @param {number} x The param
|
||||
//// * @returns The result
|
||||
//// * @see x (the parameter)
|
||||
//// */
|
||||
////function /**/foo(x) {}
|
||||
|
||||
verify.baselineQuickInfo();
|
||||
@@ -1,7 +1,18 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @Filename: quickInfoJsDocTags1.ts
|
||||
/////** Doc */
|
||||
////const /**/x = 0;
|
||||
|
||||
verify.quickInfoAt("", "const x: 0", "Doc");
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @Filename: quickInfoJsDocTags1.ts
|
||||
/////**
|
||||
//// * Doc
|
||||
//// * @author Me <me@domain.tld>
|
||||
//// * @augments {C<T>} Augments it
|
||||
//// * @template T A template
|
||||
//// * @type {number | string} A type
|
||||
//// * @typedef {number | string} NumOrStr
|
||||
//// * @property {number} x The prop
|
||||
//// * @param {number} x The param
|
||||
//// * @returns The result
|
||||
//// * @see x (the parameter)
|
||||
//// */
|
||||
////function /**/foo(x) {}
|
||||
|
||||
verify.baselineQuickInfo();
|
||||
@@ -0,0 +1,7 @@
|
||||
/// <reference path='fourslash.ts'/>
|
||||
|
||||
// @Filename: quickInfoJsDocTags2.ts
|
||||
/////** Doc */
|
||||
////const /**/x = 0;
|
||||
|
||||
verify.quickInfoAt("", "const x: 0", "Doc");
|
||||
@@ -0,0 +1,22 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: quickInfoJsDocTags3.ts
|
||||
////interface Foo {
|
||||
//// /**
|
||||
//// * comment
|
||||
//// * @author Me <me@domain.tld>
|
||||
//// * @see x (the parameter)
|
||||
//// * @param {number} x - x comment
|
||||
//// * @param {number} y - y comment
|
||||
//// * @throws {Error} comment
|
||||
//// */
|
||||
//// method(x: number, y: number): void;
|
||||
////}
|
||||
////
|
||||
////class Bar implements Foo {
|
||||
//// /**/method(): void {
|
||||
//// throw new Error("Method not implemented.");
|
||||
//// }
|
||||
////}
|
||||
|
||||
verify.baselineQuickInfo();
|
||||
@@ -0,0 +1,25 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @Filename: quickInfoJsDocTags4.ts
|
||||
////class Foo {
|
||||
//// /**
|
||||
//// * comment
|
||||
//// * @author Me <me@domain.tld>
|
||||
//// * @see x (the parameter)
|
||||
//// * @param {number} x - x comment
|
||||
//// * @param {number} y - y comment
|
||||
//// * @returns The result
|
||||
//// */
|
||||
//// method(x: number, y: number): number {
|
||||
//// return x + y;
|
||||
//// }
|
||||
////}
|
||||
////
|
||||
////class Bar extends Foo {
|
||||
//// /**/method(x: number, y: number): number {
|
||||
//// const res = super.method(x, y) + 100;
|
||||
//// return res;
|
||||
//// }
|
||||
////}
|
||||
|
||||
verify.baselineQuickInfo();
|
||||
@@ -0,0 +1,28 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @noEmit: true
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: quickInfoJsDocTags5.js
|
||||
////class Foo {
|
||||
//// /**
|
||||
//// * comment
|
||||
//// * @author Me <me@domain.tld>
|
||||
//// * @see x (the parameter)
|
||||
//// * @param {number} x - x comment
|
||||
//// * @param {number} y - y comment
|
||||
//// * @returns The result
|
||||
//// */
|
||||
//// method(x, y) {
|
||||
//// return x + y;
|
||||
//// }
|
||||
////}
|
||||
////
|
||||
////class Bar extends Foo {
|
||||
//// /**/method(x, y) {
|
||||
//// const res = super.method(x, y) + 100;
|
||||
//// return res;
|
||||
//// }
|
||||
////}
|
||||
|
||||
verify.baselineQuickInfo();
|
||||
@@ -0,0 +1,29 @@
|
||||
/// <reference path="fourslash.ts" />
|
||||
|
||||
// @noEmit: true
|
||||
// @allowJs: true
|
||||
|
||||
// @Filename: quickInfoJsDocTags6.js
|
||||
////class Foo {
|
||||
//// /**
|
||||
//// * comment
|
||||
//// * @author Me <me@domain.tld>
|
||||
//// * @see x (the parameter)
|
||||
//// * @param {number} x - x comment
|
||||
//// * @param {number} y - y comment
|
||||
//// * @returns The result
|
||||
//// */
|
||||
//// method(x, y) {
|
||||
//// return x + y;
|
||||
//// }
|
||||
////}
|
||||
////
|
||||
////class Bar extends Foo {
|
||||
//// /** @inheritDoc */
|
||||
//// /**/method(x, y) {
|
||||
//// const res = super.method(x, y) + 100;
|
||||
//// return res;
|
||||
//// }
|
||||
////}
|
||||
|
||||
verify.baselineQuickInfo();
|
||||
@@ -0,0 +1,16 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// const foo: /*a*/string/*b*/ = /*c*/1/*d*/;
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorKindAvailable("refactor.extract",
|
||||
[
|
||||
"refactor.extract.type"
|
||||
]);
|
||||
|
||||
goTo.select("c", "d");
|
||||
verify.refactorKindAvailable("refactor.extract",
|
||||
[
|
||||
"refactor.extract.constant",
|
||||
"refactor.extract.function"
|
||||
]);
|
||||
@@ -0,0 +1,11 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// class A {
|
||||
//// /*a*/public a: string;/*b*/
|
||||
//// }
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorKindAvailable("refactor.rewrite.property",
|
||||
[
|
||||
"refactor.rewrite.property.generateAccessors"
|
||||
]);
|
||||
@@ -0,0 +1,12 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// /*a*/const moveMe = 1;/*b*/
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorKindAvailable("refactor.move",
|
||||
[
|
||||
"refactor.move.newFile"
|
||||
],
|
||||
{
|
||||
allowTextChangesInNewFiles: true
|
||||
});
|
||||
@@ -0,0 +1,9 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// /*a*/export function f() {}/*b*/
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorKindAvailable("refactor.rewrite.export",
|
||||
[
|
||||
"refactor.rewrite.export.default"
|
||||
]);
|
||||
@@ -0,0 +1,12 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// const arrow = () /*a*/=>/*b*/ 1;
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorKindAvailable("refactor.rewrite",
|
||||
[
|
||||
"refactor.rewrite.arrow.braces.add",
|
||||
"refactor.rewrite.function.named",
|
||||
"refactor.rewrite.function.anonymous",
|
||||
"refactor.rewrite.function.returnType"
|
||||
]);
|
||||
@@ -0,0 +1,10 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// /*a*/declare function foo(): void;
|
||||
//// declare function foo(a: string): void;/*b*/
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorKindAvailable("refactor.rewrite",
|
||||
[
|
||||
"refactor.rewrite.function.overloadList"
|
||||
]);
|
||||
@@ -0,0 +1,9 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// /*a*/import * as m from "m";/*b*/
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorKindAvailable("refactor.rewrite",
|
||||
[
|
||||
"refactor.rewrite.import.named"
|
||||
]);
|
||||
@@ -0,0 +1,10 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// /*a*/foo && foo.bar/*b*/
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorKindAvailable("refactor.rewrite",
|
||||
[
|
||||
"refactor.rewrite.expression.optionalChain"
|
||||
]);
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// function(/*a*/a: number, b: number/*b*/): number {}
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorKindAvailable("refactor.rewrite",
|
||||
[
|
||||
"refactor.rewrite.parameters.toDestructured"
|
||||
]);
|
||||
@@ -0,0 +1,9 @@
|
||||
/// <reference path='fourslash.ts' />
|
||||
|
||||
//// const foo = /*a*/"a" + bar/*b*/;
|
||||
|
||||
goTo.select("a", "b");
|
||||
verify.refactorKindAvailable("refactor.rewrite",
|
||||
[
|
||||
"refactor.rewrite.string"
|
||||
]);
|
||||
Reference in new issue
Block a user