├── .gitignore ├── .npmignore ├── .vscode └── launch.json ├── LICENSE.txt ├── README.md ├── images └── inspect-tokens.png ├── package-lock.json ├── package.json ├── src ├── constants.ts ├── index.ts └── test │ └── semanticTokens.test.ts ├── test └── index.js ├── tsconfig.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | .DS_Store 3 | .project 4 | *.log 5 | 6 | # Dependencies 7 | node_modules 8 | 9 | # Intermediary compilation files 10 | lib 11 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .npmignore 2 | /src 3 | /lib/**/*.map 4 | /lib/test 5 | /test 6 | tsconfig.json 7 | .vscode 8 | .project 9 | node_modules 10 | *.test.js 11 | *.js.map -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "node", 9 | "request": "launch", 10 | "name": "Launch Program", 11 | "skipFiles": [ 12 | "/**" 13 | ], 14 | "program": "${workspaceFolder}/test/index.js", 15 | "preLaunchTask": "tsc: build - tsconfig.json", 16 | "outFiles": [ 17 | "${workspaceFolder}/lib/**/*.js" 18 | ] 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Microsoft 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## REPOSITORY IS ARCHIVED 3 | 4 | ***The plugin is obsolete: TypeScript 4.x has adopted the extended semantic highlighting implemented by this plugin. 5 | The repository is no longer maintained*** 6 | 7 | 8 | -------- 9 | 10 | A [TypeScript plugin](https://github.com/Microsoft/TypeScript/wiki/Writing-a-Language-Service-Plugin) that replaces `getEncodedSemanticClassifications` and `getEncodedSyntacticClassifications` to provide more classifications to be used by the new [Semantic Highlighting APIs](https://github.com/microsoft/vscode/wiki/Semantic-Highlighting-Overview) in VS Code. 11 | 12 | The purpose of this plugin is to test and enable the new VS Code semantic highlight capabilities. 13 | 14 | Once proven, the extended classifications will (hopefully) be adapted by the TypeScript language server and the plugin is no longer needed any more. 15 | 16 | ### New Classifications 17 | 18 | The plugin uses new token classifications, consisting of a `TokenType` and with any number of `TokenModifier`s. 19 | 20 | ``` 21 | export const enum TokenType { 22 | class, enum, interface, namespace, typeParameter, type, parameter, variable, enumMember, property, function, member 23 | } 24 | 25 | export const enum TokenModifier { 26 | declaration, static, async, readonly, local, defaultLibrary 27 | } 28 | ``` 29 | 30 | ### Classification Encoding 31 | 32 | The new classifications are retured in place of old the classifications. They are encoded as follows: 33 | ``` 34 | TSClassification = ((TokenType + 1) << 8) + TokenModifierSet; 35 | 36 | ``` 37 | 38 | All new classifications have a value >= 0x100 to not overlap with the old classifications. Old classifications are no longer emmitted once the plugin is active. 39 | 40 | ### Implemented Features 41 | 42 | Examples for each feature can be seen in the [test cases](https://github.com/aeschli/typescript-vscode-sh-plugin/blob/master/src/test/semanticTokens.test.ts). To try them out in VSCode, copy the added snippet to a `TypeScript` editor and use the `Developer: Inspect Editor Tokens and Scopes` command to see the semantic token information ar the current cursor location. 43 | 44 | 45 | - all token types listed above 46 | - classification for all declarations and references 47 | - modifier `declaration` when on the identifier of the declaration node 48 | ``` 49 | class A { field: number; member(param: number) { let var= param + this.field; } } 50 | ``` 51 | - modifier `defaultLibrary` when in an symbol that comes from the default libraries. 52 | ``` 53 | Math.max(Number.Nan, parseInt('33')) 54 | ``` 55 | - variables, properties and parameters 56 | - modifier `readonly` when defined as `const` or `readonly` 57 | ``` 58 | const var; 59 | ``` 60 | - modifier `local` when not declared top-level 61 | ``` 62 | function global(p: number) { const global; 63 | ``` 64 | - functions and members 65 | - modifier `async` when defined as `async` 66 | - modifier `static` when defined as `static` 67 | -variables & properties with constructor signatures 68 | - variables & properties that have a constructor type, are classified as `class` 69 | ``` 70 | Number.isInteger(1); 71 | ``` 72 | - variables & properties with call signatures 73 | - variables, properties and parameters that have a function type (but no properties) are classified as `function` resp `member` ([#89337](https://github.com/microsoft/vscode/issues/89337)) 74 | ``` 75 | const callback = () => {}; 76 | ``` 77 | - if the variable/member/parameter type is callable but also has properties, it stays a variable/member/parameter, unless used in a callExpression 78 | ``` 79 | var fs = require('fs); require.resolve('foo/bar'); 80 | ``` 81 | - jsx 82 | - no semantic highlighting for JSX element names (for now): [#88911](https://github.com/microsoft/vscode/issues/88911) [#89224](https://github.com/microsoft/vscode/issues/89224). 83 | 84 | 85 | ### Under discussion 86 | - add `typeAlias` pas a new token type 87 | - object literal keys are currently also classified as properties 88 | 89 | ### Try it out 90 | 91 | #### In VS Code 92 | - make sure semantic highlighting is enabled (on by default in insiders and since 1.43 in stable) 93 | `"editor.semanticHighlighting.enabled": true` 94 | - open a TypeScript or JavaScript file in VSCode and wait for the language server to get active 95 | - use the `Developer: Inspect Editor Tokens and Scopes` command to inspect the semantic information at a given cursor location. 96 | 97 | ![Inspect Editor Tokens](./images/inspect-tokens.png) 98 | 99 | 100 | #### Run the Tests 101 | 102 | - `yarn && yarn test` in the folder of the cloned repo. 103 | -------------------------------------------------------------------------------- /images/inspect-tokens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/aeschli/typescript-vscode-sh-plugin/3f78245cc741c776eb0ee12d25d6db2b1c51c2fd/images/inspect-tokens.png -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-vscode-sh-plugin", 3 | "version": "0.7.3", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/node": { 8 | "version": "12.12.24", 9 | "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.24.tgz", 10 | "integrity": "sha512-1Ciqv9pqwVtW6FsIUKSZNB82E5Cu1I2bBTj1xuIHXLe/1zYLl3956Nbhg2MzSYHVfl9/rmanjbQIb7LibfCnug==", 11 | "dev": true 12 | }, 13 | "typescript": { 14 | "version": "3.7.4", 15 | "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.4.tgz", 16 | "integrity": "sha512-A25xv5XCtarLwXpcDNZzCGvW2D1S3/bACratYBx2sax8PefsFhlYmkQicKHvpYflFS8if4zne5zT5kpJ7pzuvw==", 17 | "dev": true 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "typescript-vscode-sh-plugin", 3 | "version": "0.7.3", 4 | "description": "TypeScript plugin that provides richer semantic highlighing", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "prepublishOnly": "npm run compile", 8 | "compile": "tsc", 9 | "test": "npm run compile && node ./test", 10 | "preversion": "npm run compile", 11 | "postversion": "git push && git push --tags" 12 | }, 13 | "author": "Microsoft", 14 | "license": "MIT", 15 | "repository": { 16 | "type": "git", 17 | "url": "git://github.com/aeschli/typescript-vscode-sh-plugin.git" 18 | }, 19 | "devDependencies": { 20 | "@types/node": "^12.12.0", 21 | "@types/mocha": "5.2.7", 22 | "typescript": "^4.2.3", 23 | "mocha": "^8.3.2", 24 | "glob": "^7.1.6", 25 | "@types/react": "^17.0.3" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/constants.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | // typescript-vscode-sh-plugin encodes type and modifiers in the classification: 7 | // TSClassification = ((TokenType + 1) << typeOffset) + TokenModifier 8 | 9 | export const enum TokenType { 10 | class, enum, interface, namespace, typeParameter, type, parameter, variable, enumMember, property, function, member, _ 11 | } 12 | 13 | export const enum TokenModifier { 14 | declaration, static, async, readonly, defaultLibrary, local, _ 15 | } 16 | 17 | export const enum TokenEncodingConsts { 18 | typeOffset = 8, 19 | modifierMask = (1 << typeOffset) - 1 20 | } 21 | 22 | export declare const enum VersionRequirement { 23 | major = 3, 24 | minor = 7 25 | } 26 | 27 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | 2 | /*--------------------------------------------------------------------------------------------- 3 | * Copyright (c) Microsoft Corporation. All rights reserved. 4 | * Licensed under the MIT License. See License.txt in the project root for license information. 5 | *--------------------------------------------------------------------------------------------*/ 6 | 7 | import ts from 'typescript/lib/tsserverlibrary'; 8 | import { TokenType, TokenModifier, TokenEncodingConsts, VersionRequirement } from './constants'; 9 | 10 | export = function init(modules: { typescript: typeof import("typescript/lib/tsserverlibrary") }) { 11 | const ts = modules.typescript; 12 | const [majorVersion, minorVersion] = ts.version.split('.').map(p => Number(p)); 13 | 14 | function checkRequiredVersion(requiredMajor: number, requiredMinor: number) { 15 | return requiredMajor < majorVersion || ((majorVersion === requiredMajor) && requiredMinor <= minorVersion); 16 | } 17 | 18 | function decorate(languageService: ts.LanguageService, logger?: ts.server.Logger) { 19 | const intercept: Partial = Object.create(null); 20 | 21 | if (!checkRequiredVersion(VersionRequirement.major, VersionRequirement.minor)) { 22 | logger?.msg(`typescript-vscode-sh-plugin not active, version ${VersionRequirement.major}.${VersionRequirement.minor} required, is ${ts.version}`, ts.server.Msg.Info); 23 | return languageService; 24 | } 25 | 26 | const olderThan42 = majorVersion < 4 || majorVersion === 4 && minorVersion < 2; 27 | logger?.msg(`typescript-vscode-sh-plugin active for version < 4.2 and JS/JSX files. Current version : ${ts.version}`, ts.server.Msg.Info); 28 | logger?.msg(`Intercepting getEncodedSemanticClassifications and getEncodedSyntacticClassifications.`, ts.server.Msg.Info); 29 | 30 | intercept.getEncodedSemanticClassifications = (filename: string, span: ts.TextSpan, format?: ts.SemanticClassificationFormat) => { 31 | if (olderThan42 || filename.match(/\.js(x)?$/)) { 32 | return { 33 | spans: getSemanticTokens(languageService, filename, span), 34 | endOfLineState: ts.EndOfLineState.None 35 | } 36 | } 37 | return languageService.getEncodedSemanticClassifications(filename, span, format); 38 | }; 39 | 40 | intercept.getEncodedSyntacticClassifications = (_filename: string, _span: ts.TextSpan) => { 41 | return { 42 | spans: [], 43 | endOfLineState: ts.EndOfLineState.None 44 | } 45 | }; 46 | 47 | return new Proxy(languageService, { 48 | get: (target: any, property: keyof ts.LanguageService) => { 49 | return intercept[property] || target[property]; 50 | }, 51 | }); 52 | } 53 | 54 | function getSemanticTokens(jsLanguageService: ts.LanguageService, fileName: string, span: ts.TextSpan): number[] { 55 | let resultTokens: number[] = []; 56 | 57 | const collector = (node: ts.Node, typeIdx: number, modifierSet: number) => { 58 | resultTokens.push(node.getStart(), node.getWidth(), ((typeIdx + 1) << TokenEncodingConsts.typeOffset) + modifierSet); 59 | }; 60 | const program = jsLanguageService.getProgram(); 61 | if (program) { 62 | const sourceFile = program.getSourceFile(fileName); 63 | if (sourceFile) { 64 | collectTokens(program, sourceFile, span, collector); 65 | } 66 | } 67 | return resultTokens; 68 | } 69 | 70 | function collectTokens(program: ts.Program, sourceFile: ts.SourceFile, span: ts.TextSpan, collector: (node: ts.Node, tokenType: number, tokenModifier: number) => void) { 71 | const typeChecker = program.getTypeChecker(); 72 | 73 | let inJSXElement = false; 74 | 75 | function visit(node: ts.Node) { 76 | if (!node || !ts.textSpanIntersectsWith(span, node.pos, node.getFullWidth()) || node.getFullWidth() === 0) { 77 | return; 78 | } 79 | const prevInJSXElement = inJSXElement; 80 | if (ts.isJsxElement(node) || ts.isJsxSelfClosingElement(node)) { 81 | inJSXElement = true; 82 | } 83 | if (ts.isJsxExpression(node)) { 84 | inJSXElement = false; 85 | } 86 | 87 | if (ts.isIdentifier(node) && !inJSXElement && !inImportClause(node)) { 88 | let symbol = typeChecker.getSymbolAtLocation(node); 89 | if (symbol) { 90 | if (symbol.flags & ts.SymbolFlags.Alias) { 91 | symbol = typeChecker.getAliasedSymbol(symbol); 92 | } 93 | let typeIdx = classifySymbol(symbol, getMeaningFromLocation(node)); 94 | if (typeIdx !== undefined) { 95 | let modifierSet = 0; 96 | if (node.parent) { 97 | const parentIsDeclaration = (ts.isBindingElement(node.parent) || tokenFromDeclarationMapping[node.parent.kind] === typeIdx); 98 | if (parentIsDeclaration && (node.parent).name === node) { 99 | modifierSet = 1 << TokenModifier.declaration; 100 | } 101 | } 102 | 103 | // property declaration in constructor 104 | if (typeIdx === TokenType.parameter && isRightSideOfQualifiedNameOrPropertyAccess(node)) { 105 | typeIdx = TokenType.property; 106 | } 107 | 108 | typeIdx = reclassifyByType(typeChecker, node, typeIdx); 109 | 110 | const decl = symbol.valueDeclaration; 111 | if (decl) { 112 | const modifiers = ts.getCombinedModifierFlags(decl); 113 | const nodeFlags = ts.getCombinedNodeFlags(decl); 114 | if (modifiers & ts.ModifierFlags.Static) { 115 | modifierSet |= 1 << TokenModifier.static; 116 | } 117 | if (modifiers & ts.ModifierFlags.Async) { 118 | modifierSet |= 1 << TokenModifier.async; 119 | } 120 | if (typeIdx !== TokenType.class && typeIdx !== TokenType.interface) { 121 | if ((modifiers & ts.ModifierFlags.Readonly) || (nodeFlags & ts.NodeFlags.Const) || (symbol.getFlags() & ts.SymbolFlags.EnumMember)) { 122 | modifierSet |= 1 << TokenModifier.readonly; 123 | } 124 | } 125 | if ((typeIdx === TokenType.variable || typeIdx === TokenType.function) && isLocalDeclaration(decl, sourceFile)) { 126 | modifierSet |= 1 << TokenModifier.local; 127 | } 128 | if (program.isSourceFileDefaultLibrary(decl.getSourceFile())) { 129 | modifierSet |= 1 << TokenModifier.defaultLibrary; 130 | } 131 | } else if (symbol.declarations && symbol.declarations.some(d => program.isSourceFileDefaultLibrary(d.getSourceFile()))) { 132 | modifierSet |= 1 << TokenModifier.defaultLibrary; 133 | } 134 | 135 | collector(node, typeIdx, modifierSet); 136 | 137 | } 138 | } 139 | } 140 | ts.forEachChild(node, visit); 141 | 142 | inJSXElement = prevInJSXElement; 143 | } 144 | visit(sourceFile); 145 | } 146 | 147 | function classifySymbol(symbol: ts.Symbol, meaning: SemanticMeaning): TokenType | undefined { 148 | const flags = symbol.getFlags(); 149 | if (flags & ts.SymbolFlags.Class) { 150 | return TokenType.class; 151 | } else if (flags & ts.SymbolFlags.Enum) { 152 | return TokenType.enum; 153 | } else if (flags & ts.SymbolFlags.TypeAlias) { 154 | return TokenType.type; 155 | } else if (flags & ts.SymbolFlags.Interface) { 156 | if (meaning & SemanticMeaning.Type) { 157 | return TokenType.interface; 158 | } 159 | } else if (flags & ts.SymbolFlags.TypeParameter) { 160 | return TokenType.typeParameter; 161 | } 162 | let decl = symbol.valueDeclaration || symbol.declarations && symbol.declarations[0]; 163 | if (decl && ts.isBindingElement(decl)) { 164 | decl = getDeclarationForBindingElement(decl); 165 | } 166 | return decl && tokenFromDeclarationMapping[decl.kind]; 167 | } 168 | 169 | function reclassifyByType(typeChecker: ts.TypeChecker, node: ts.Node, typeIdx: TokenType): TokenType { 170 | // type based classifications 171 | if (typeIdx === TokenType.variable || typeIdx === TokenType.property || typeIdx === TokenType.parameter) { 172 | const type = typeChecker.getTypeAtLocation(node); 173 | if (type) { 174 | const test = (condition: (type: ts.Type) => boolean) => { 175 | return condition(type) || type.isUnion() && type.types.some(condition); 176 | } 177 | if (typeIdx !== TokenType.parameter && test(t => t.getConstructSignatures().length > 0)) { 178 | return TokenType.class; 179 | } 180 | if (test(t => t.getCallSignatures().length > 0) && !test(t => t.getProperties().length > 0) || isExpressionInCallExpression(node)) { 181 | return typeIdx === TokenType.property ? TokenType.member : TokenType.function; 182 | } 183 | } 184 | } 185 | return typeIdx; 186 | } 187 | 188 | function isLocalDeclaration(decl: ts.Declaration, sourceFile: ts.SourceFile): boolean { 189 | if (ts.isBindingElement(decl)) { 190 | decl = getDeclarationForBindingElement(decl); 191 | } 192 | if (ts.isVariableDeclaration(decl)) { 193 | return (!ts.isSourceFile(decl.parent.parent.parent) || ts.isCatchClause(decl.parent)) && decl.getSourceFile() === sourceFile; 194 | } else if (ts.isFunctionDeclaration(decl)) { 195 | return !ts.isSourceFile(decl.parent) && decl.getSourceFile() === sourceFile; 196 | } 197 | return false; 198 | } 199 | 200 | function getDeclarationForBindingElement(element: ts.BindingElement): ts.VariableDeclaration | ts.ParameterDeclaration { 201 | while (true) { 202 | if (ts.isBindingElement(element.parent.parent)) { 203 | element = element.parent.parent; 204 | } else { 205 | return element.parent.parent; 206 | } 207 | } 208 | } 209 | 210 | function inImportClause(node: ts.Node): boolean { 211 | const parent = node.parent; 212 | return parent && (ts.isImportClause(parent) || ts.isImportSpecifier(parent) || ts.isNamespaceImport(parent)); 213 | } 214 | 215 | function isExpressionInCallExpression(node: ts.Node): boolean { 216 | while (isRightSideOfQualifiedNameOrPropertyAccess(node)) { 217 | node = node.parent 218 | } 219 | return ts.isCallExpression(node.parent) && node.parent.expression === node; 220 | } 221 | 222 | function isRightSideOfQualifiedNameOrPropertyAccess(node: ts.Node): boolean { 223 | return (ts.isQualifiedName(node.parent) && node.parent.right === node) || (ts.isPropertyAccessExpression(node.parent) && node.parent.name === node); 224 | } 225 | 226 | const enum SemanticMeaning { 227 | None = 0x0, 228 | Value = 0x1, 229 | Type = 0x2, 230 | Namespace = 0x4, 231 | All = Value | Type | Namespace 232 | } 233 | 234 | function getMeaningFromLocation(node: ts.Node): SemanticMeaning { 235 | const f = (ts).getMeaningFromLocation; 236 | if (typeof f === 'function') { 237 | return f(node); 238 | } 239 | return SemanticMeaning.All; 240 | } 241 | 242 | const tokenFromDeclarationMapping: { [name: string]: TokenType } = { 243 | [ts.SyntaxKind.VariableDeclaration]: TokenType.variable, 244 | [ts.SyntaxKind.Parameter]: TokenType.parameter, 245 | [ts.SyntaxKind.PropertyDeclaration]: TokenType.property, 246 | [ts.SyntaxKind.ModuleDeclaration]: TokenType.namespace, 247 | [ts.SyntaxKind.EnumDeclaration]: TokenType.enum, 248 | [ts.SyntaxKind.EnumMember]: TokenType.enumMember, 249 | [ts.SyntaxKind.ClassDeclaration]: TokenType.class, 250 | [ts.SyntaxKind.MethodDeclaration]: TokenType.member, 251 | [ts.SyntaxKind.FunctionDeclaration]: TokenType.function, 252 | [ts.SyntaxKind.FunctionExpression]: TokenType.function, 253 | [ts.SyntaxKind.MethodSignature]: TokenType.member, 254 | [ts.SyntaxKind.GetAccessor]: TokenType.property, 255 | [ts.SyntaxKind.SetAccessor]: TokenType.property, 256 | [ts.SyntaxKind.PropertySignature]: TokenType.property, 257 | [ts.SyntaxKind.InterfaceDeclaration]: TokenType.interface, 258 | [ts.SyntaxKind.TypeAliasDeclaration]: TokenType.type, 259 | [ts.SyntaxKind.TypeParameter]: TokenType.typeParameter, 260 | [ts.SyntaxKind.PropertyAssignment]: TokenType.property, 261 | [ts.SyntaxKind.ShorthandPropertyAssignment]: TokenType.property 262 | }; 263 | 264 | return { 265 | create(info: ts.server.PluginCreateInfo) { 266 | return decorate(info.languageService, info.project.projectService.logger); 267 | }, 268 | onConfigurationChanged(_config: any) { 269 | }, 270 | // added for testing 271 | decorate(languageService: ts.LanguageService): ts.LanguageService { 272 | return decorate(languageService); 273 | } 274 | }; 275 | }; 276 | 277 | -------------------------------------------------------------------------------- /src/test/semanticTokens.test.ts: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | import 'mocha'; 7 | import * as assert from 'assert'; 8 | import * as path from 'path'; 9 | 10 | import * as ts from 'typescript/lib/tsserverlibrary'; 11 | import initPlugin from '../index'; 12 | import { TokenType, TokenModifier, TokenEncodingConsts } from '../constants'; 13 | 14 | interface ExpectedToken { 15 | startLine: number; 16 | character: number; 17 | length: number; 18 | tokenClassifiction: string; 19 | } 20 | 21 | function t(startLine: number, character: number, length: number, tokenClassifiction: string): ExpectedToken { 22 | return { startLine, character, length, tokenClassifiction }; 23 | } 24 | 25 | 26 | const tokenTypes: string[] = []; 27 | tokenTypes[TokenType.class] = 'class'; 28 | tokenTypes[TokenType.enum] = 'enum'; 29 | tokenTypes[TokenType.interface] = 'interface'; 30 | tokenTypes[TokenType.namespace] = 'namespace'; 31 | tokenTypes[TokenType.typeParameter] = 'typeParameter'; 32 | tokenTypes[TokenType.type] = 'type'; 33 | tokenTypes[TokenType.parameter] = 'parameter'; 34 | tokenTypes[TokenType.variable] = 'variable'; 35 | tokenTypes[TokenType.enumMember] = 'enumMember'; 36 | tokenTypes[TokenType.property] = 'property'; 37 | tokenTypes[TokenType.function] = 'function'; 38 | tokenTypes[TokenType.member] = 'member'; 39 | 40 | const tokenModifiers: string[] = []; 41 | tokenModifiers[TokenModifier.async] = 'async'; 42 | tokenModifiers[TokenModifier.declaration] = 'declaration'; 43 | tokenModifiers[TokenModifier.readonly] = 'readonly'; 44 | tokenModifiers[TokenModifier.static] = 'static'; 45 | tokenModifiers[TokenModifier.local] = 'local'; 46 | tokenModifiers[TokenModifier.defaultLibrary] = 'defaultLibrary'; 47 | 48 | 49 | function getTokenTypeFromClassification(tsClassification: number): number | undefined { 50 | if (tsClassification > TokenEncodingConsts.modifierMask) { 51 | return (tsClassification >> TokenEncodingConsts.typeOffset) - 1; 52 | } 53 | return undefined; 54 | } 55 | 56 | function getTokenModifierFromClassification(tsClassification: number) { 57 | return tsClassification & TokenEncodingConsts.modifierMask; 58 | } 59 | 60 | function assertTokens(mainFileName: string, files: { [name: string]: string } = {}, expected: ExpectedToken[], span?: ts.TextSpan): void { 61 | const sourceRoot = __dirname; // use the current directory as root for all test files to enable module lookup 62 | const mainFilePath = sourceRoot + mainFileName; 63 | 64 | function findFilePath(moduleName: string) { 65 | for (let fileName in files) { 66 | if (fileName.startsWith(moduleName + '.')) { 67 | return sourceRoot + fileName; 68 | } 69 | } 70 | return undefined; 71 | } 72 | 73 | let compilerOptions: ts.CompilerOptions = { 74 | allowNonTsExtensions: true, 75 | allowJs: true, 76 | lib: ['lib.es6.d.ts'], 77 | target: ts.ScriptTarget.Latest, 78 | moduleResolution: ts.ModuleResolutionKind.NodeJs, 79 | jsx: ts.JsxEmit.React, 80 | allowSyntheticDefaultImports: true, 81 | types: ["node"] 82 | }; 83 | 84 | const host: ts.LanguageServiceHost = { 85 | getCompilationSettings: () => compilerOptions, 86 | getScriptFileNames: () => [...Object.keys(files).map(k => sourceRoot + k)], 87 | getScriptKind: (_fileName) => { 88 | const ext = path.extname(_fileName); 89 | switch (ext) { 90 | case '.js': return ts.ScriptKind.JS; 91 | case '.tsx': return ts.ScriptKind.TSX; 92 | case '.jsx': return ts.ScriptKind.JSX; 93 | default: return ts.ScriptKind.TS; 94 | } 95 | }, 96 | getScriptVersion: (_fileName: string) => '1', 97 | getScriptSnapshot: (fileName: string) => { 98 | let text: string; 99 | if (fileName.startsWith(sourceRoot)) { 100 | text = files[fileName.substr(sourceRoot.length)] || ''; 101 | } else { 102 | text = ts.sys.readFile(fileName) || ''; 103 | } 104 | return { 105 | getText: (start, end) => text.substring(start, end), 106 | getLength: () => text.length, 107 | getChangeRange: () => undefined 108 | }; 109 | }, 110 | getCurrentDirectory: () => __dirname, 111 | getDirectories: ts.sys.getDirectories, 112 | // directoryExists: ts.sys.directoryExists, 113 | // fileExists: ts.sys.fileExists, 114 | // readFile: ts.sys.readFile, 115 | 116 | resolveModuleNames: (moduleNames: string[], containingFile: string): (ts.ResolvedModule | undefined)[] => { 117 | const resolvedModules: (ts.ResolvedModule | undefined)[] = []; 118 | for (const moduleName of moduleNames) { 119 | if (moduleName.startsWith('./')) { 120 | let resolvedFileName = findFilePath(moduleName.substring(2)); 121 | if (!resolvedFileName) { 122 | resolvedFileName = path.join(path.dirname(containingFile), moduleName + '.ts'); 123 | } 124 | resolvedModules.push({ resolvedFileName }); 125 | } else { 126 | let result = ts.resolveModuleName(moduleName, containingFile, compilerOptions, { 127 | fileExists: ts.sys.fileExists, 128 | readFile: ts.sys.readFile, 129 | }); 130 | if (result.resolvedModule) { 131 | resolvedModules.push(result.resolvedModule); 132 | } else { 133 | resolvedModules.push(undefined); 134 | } 135 | } 136 | } 137 | return resolvedModules; 138 | }, 139 | getDefaultLibFileName: (options) => ts.getDefaultLibFilePath(options) 140 | }; 141 | 142 | let languageService = ts.createLanguageService(host); 143 | 144 | 145 | languageService = initPlugin({ typescript: ts }).decorate(languageService); 146 | 147 | const mainContent = files[mainFileName]; 148 | 149 | if (!span) { 150 | span = { start: 0, length: mainContent.length }; 151 | } 152 | 153 | const diagnostics = languageService.getSemanticDiagnostics(mainFilePath); 154 | for (let d of diagnostics) { 155 | console.log(d.messageText); 156 | } 157 | for (let k in files) { 158 | const diagnostics = languageService.getSemanticDiagnostics(sourceRoot + k); 159 | for (let d of diagnostics) { 160 | console.log(d.messageText); 161 | } 162 | } 163 | 164 | const result = languageService.getEncodedSemanticClassifications(mainFilePath, span, ts.SemanticClassificationFormat.TwentyTwenty); 165 | 166 | const sourceFile = languageService.getProgram()?.getSourceFile(mainFilePath)!; 167 | let actualRanges = []; 168 | let snippet = ''; 169 | let i = 0; 170 | while (i < result.spans.length) { 171 | const start = result.spans[i++], len = result.spans[i++], classification = result.spans[i++]; 172 | const lineAndChar = sourceFile.getLineAndCharacterOfPosition(start)!; 173 | const typeIdx = getTokenTypeFromClassification(classification) || 0; 174 | const modSet = getTokenModifierFromClassification(classification); 175 | 176 | const tokenClassifiction = [tokenTypes[typeIdx], ...tokenModifiers.filter((_, i) => modSet & 1 << i)].join('.'); 177 | actualRanges.push(t(lineAndChar.line, lineAndChar.character, len, tokenClassifiction)); 178 | snippet += `t(${lineAndChar.line}, ${lineAndChar.character}, ${len}, '${tokenClassifiction}'), `; 179 | } 180 | assert.deepEqual(actualRanges, expected, snippet); 181 | 182 | } 183 | 184 | suite('HTML Semantic Tokens', () => { 185 | 186 | test('Variables', () => { 187 | const input = [ 188 | /*0*/' var x = 9, y1 = [x];', 189 | /*1*/' try {', 190 | /*2*/' for (const s of y1) { x = s }', 191 | /*3*/' } catch (e) {', 192 | /*4*/' throw y1;', 193 | /*5*/' }', 194 | ].join('\n'); 195 | assertTokens('main.ts', { 'main.ts': input }, [ 196 | t(0, 6, 1, 'variable.declaration'), t(0, 13, 2, 'variable.declaration'), t(0, 19, 1, 'variable'), 197 | t(2, 15, 1, 'variable.declaration.readonly.local'), t(2, 20, 2, 'variable'), t(2, 26, 1, 'variable'), t(2, 30, 1, 'variable.readonly.local'), 198 | t(3, 11, 1, 'variable.declaration.local'), 199 | t(4, 10, 2, 'variable') 200 | ]); 201 | }); 202 | 203 | test('Functions', () => { 204 | const input = [ 205 | /*0*/'function foo(p1) {', 206 | /*1*/' return foo(Math.abs(p1))', 207 | /*2*/'}', 208 | /*3*/'`/${window.location}`.split("/").forEach(s => foo(s));', 209 | ].join('\n'); 210 | assertTokens('main.ts', { 'main.ts': input }, [ 211 | t(0, 9, 3, 'function.declaration'), t(0, 13, 2, 'parameter.declaration'), 212 | t(1, 9, 3, 'function'), t(1, 13, 4, 'variable.defaultLibrary'), t(1, 18, 3, 'member.defaultLibrary'), t(1, 22, 2, 'parameter'), 213 | t(3, 4, 6, 'variable.defaultLibrary'), t(3, 11, 8, 'property.defaultLibrary'), t(3, 22, 5, 'member.defaultLibrary'), t(3, 33, 7, 'member.defaultLibrary'), t(3, 41, 1, 'parameter.declaration'), t(3, 46, 3, 'function'), t(3, 50, 1, 'parameter') 214 | ]); 215 | }); 216 | 217 | test('Members', () => { 218 | const input = [ 219 | /*0*/'class A {', 220 | /*1*/' static x = 9;', 221 | /*2*/' f = 9;', 222 | /*3*/' async m() { return A.x + await this.m(); };', 223 | /*4*/' get s() { return this.f; ', 224 | /*5*/' static t() { return new A().f; };', 225 | /*6*/' constructor() {}', 226 | /*8*/'}', 227 | ].join('\n'); 228 | assertTokens('main.ts', { 'main.ts': input }, [ 229 | t(0, 6, 1, 'class.declaration'), t(1, 9, 1, 'property.declaration.static'), 230 | t(2, 2, 1, 'property.declaration'), 231 | t(3, 8, 1, 'member.declaration.async'), t(3, 21, 1, 'class'), t(3, 23, 1, 'property.static'), t(3, 38, 1, 'member.async'), 232 | t(4, 6, 1, 'property.declaration'), t(4, 24, 1, 'property'), 233 | t(5, 9, 1, 'member.declaration.static'), t(5, 26, 1, 'class'), t(5, 30, 1, 'property'), //# 234 | ]); 235 | }); 236 | 237 | test('Class Properties', () => { 238 | const input = [ 239 | /*0*/'class A { ', 240 | /*1*/' private y: number;', 241 | /*2*/' constructor(public x : number, _y : number) { this.y = _y; }', 242 | /*3*/' get z() : number { return this.x + this.y; }', 243 | /*4*/' set a(v: number) { }', 244 | /*5*/'}', 245 | ].join('\n'); 246 | assertTokens('main.ts', { 'main.ts': input }, [ 247 | t(0, 6, 1, 'class.declaration'), 248 | t(1, 10, 1, 'property.declaration'), 249 | t(2, 21, 1, 'parameter.declaration'), t(2, 33, 2, 'parameter.declaration'), t(2, 53, 1, 'property'), t(2, 57, 2, 'parameter'), 250 | t(3, 6, 1, 'property.declaration'), t(3, 33, 1, 'property'), t(3, 42, 1, 'property'), 251 | t(4, 6, 1, 'property.declaration'), t(4, 8, 1, 'parameter.declaration') 252 | ]); 253 | }); 254 | 255 | test('Object Properties', () => { 256 | const input = [ 257 | /*0*/'let x = 1, y = 1;', 258 | /*1*/'const a1 = { e: 1 };', 259 | /*2*/'var a2 = { x };' 260 | ].join('\n'); 261 | assertTokens('main.ts', { 'main.ts': input }, [ 262 | t(0, 4, 1, 'variable.declaration'), t(0, 11, 1, 'variable.declaration'), 263 | t(1, 6, 2, 'variable.declaration.readonly'), t(1, 13, 1, 'property.declaration'), 264 | t(2, 4, 2, 'variable.declaration'), t(2, 11, 1, 'property.declaration') 265 | ]); 266 | }); 267 | 268 | test('Callable Variables & Properties', () => { 269 | const input = [ 270 | /*0*/'class A { onEvent: () => void; }', 271 | /*1*/'const x = new A().onEvent;', 272 | /*2*/'const match = (s: any) => x();', 273 | /*3*/'const other = match;', 274 | /*4*/'match({ other });', 275 | /*5*/'interface B = { (): string; }; var b: B', 276 | /*6*/'var s: String;', 277 | /*7*/'var t: { (): string; foo: string};', 278 | ].join('\n'); 279 | assertTokens('main.ts', { 'main.ts': input }, [ 280 | t(0, 6, 1, 'class.declaration'), t(0, 10, 7, 'member.declaration'), 281 | t(1, 6, 1, 'function.declaration.readonly'), t(1, 14, 1, 'class'), t(1, 18, 7, 'member'), 282 | t(2, 6, 5, 'function.declaration.readonly'), t(2, 15, 1, 'parameter.declaration'), t(2, 26, 1, 'function.readonly'), 283 | t(3, 6, 5, 'function.declaration.readonly'), t(3, 14, 5, 'function.readonly'), 284 | t(4, 0, 5, 'function.readonly'), t(4, 8, 5, 'member.declaration'), 285 | t(5, 10, 1, 'interface.declaration'), t(5, 35, 1, 'variable.declaration'), t(5, 38, 1, 'interface'), 286 | t(6, 4, 1, 'variable.declaration'), t(6, 7, 6, 'interface.defaultLibrary'), 287 | t(7, 4, 1, 'variable.declaration'), t(7, 21, 3, 'property.declaration'), 288 | ]); 289 | }); 290 | 291 | test('Callable Variables & Properties 2', () => { 292 | const input = [ 293 | /*0*/'import "node";', 294 | /*1*/'var fs = require("fs")', 295 | /*2*/`require.resolve('react');`, 296 | /*3*/`require.resolve.paths;`, 297 | /*4*/`interface LanguageMode { getFoldingRanges?: (d: string) => number[]; };`, 298 | /*5*/`function (mode: LanguageMode | undefined) { if (mode && mode.getFoldingRanges) { return mode.getFoldingRanges('a'); }};`, 299 | /*6*/`function b(a: () => void) { a(); };` 300 | ].join('\n'); 301 | assertTokens('main.ts', { 'main.ts': input }, [ 302 | t(1, 4, 2, 'variable.declaration'), t(1, 9, 7, 'function'), 303 | t(2, 0, 7, 'variable'), t(2, 8, 7, 'member'), 304 | t(3, 0, 7, 'variable'), t(3, 8, 7, 'property'), t(3, 16, 5, 'member'), 305 | t(4, 10, 12, 'interface.declaration'), t(4, 25, 16, 'member.declaration'), t(4, 45, 1, 'parameter.declaration'), 306 | t(5, 10, 4, 'parameter.declaration'), t(5, 16, 12, 'interface'), t(5, 48, 4, 'parameter'), t(5, 56, 4, 'parameter'), t(5, 61, 16, 'member'), t(5, 88, 4, 'parameter'), t(5, 93, 16, 'member'), 307 | t(6, 9, 1, 'function.declaration'), t(6, 11, 1, 'function.declaration'), t(6, 28, 1, 'function') 308 | ]); 309 | }); 310 | 311 | test('Constructor Types', () => { 312 | const input = [ 313 | /*0*/'Object.create(null);', 314 | /*1*/`const x = Promise.resolve(Number.MAX_VALUE);`, 315 | /*2*/`if (x instanceof Promise) {}` 316 | ].join('\n'); 317 | assertTokens('main.ts', { 'main.ts': input }, [ 318 | t(0, 0, 6, 'class.defaultLibrary'), t(0, 7, 6, 'member.defaultLibrary'), 319 | t(1, 6, 1, 'variable.declaration.readonly'), t(1, 10, 7, 'class.defaultLibrary'), t(1, 18, 7, 'member.defaultLibrary'), t(1, 26, 6, 'class.defaultLibrary'), t(1, 33, 9, 'property.readonly.defaultLibrary'), 320 | t(2, 4, 1, 'variable.readonly'), t(2, 17, 7, 'class.defaultLibrary') 321 | ]); 322 | }); 323 | 324 | test('Interfaces', () => { 325 | const input = [ 326 | /*0*/'interface Pos { x: number, y: number };', 327 | /*1*/'const p = { x: 1, y: 2 } as Pos;', 328 | /*2*/'const foo = (o: Pos) => o.x + o.y;', 329 | ].join('\n'); 330 | assertTokens('main.ts', { 'main.ts': input }, [ 331 | t(0, 10, 3, 'interface.declaration'), t(0, 16, 1, 'property.declaration'), t(0, 27, 1, 'property.declaration'), 332 | t(1, 6, 1, 'variable.declaration.readonly'), t(1, 12, 1, 'property.declaration'), t(1, 18, 1, 'property.declaration'), t(1, 28, 3, 'interface'), 333 | t(2, 6, 3, 'function.declaration.readonly'), t(2, 13, 1, 'parameter.declaration'), t(2, 16, 3, 'interface'), t(2, 24, 1, 'parameter'), t(2, 26, 1, 'property'), t(2, 30, 1, 'parameter'), t(2, 32, 1, 'property') ]); 334 | }); 335 | 336 | test('Enums', () => { 337 | const input = [ 338 | /*0*/'export enum TextDocumentSaveReason {', 339 | /*1*/' Manual = 1', 340 | /*2*/'}', 341 | ].join('\n'); 342 | assertTokens('main.ts', { 'main.ts': input }, [ 343 | t(0, 12, 22, 'enum.declaration'), 344 | t(1, 2, 6, 'enumMember.declaration.readonly') 345 | ]); 346 | }); 347 | 348 | 349 | test('Readonly', () => { 350 | const input = [ 351 | /*0*/'const f = 9;', 352 | /*1*/'class A { static readonly t = 9; static url: URL; }', 353 | /*2*/'const enum E { A = 9, B = A + 1 }', 354 | /*3*/'console.log(f + A.t + A.url.origin + E.A);', 355 | ].join('\n'); 356 | assertTokens('main.ts', { 'main.ts': input }, [ 357 | t(0, 6, 1, 'variable.declaration.readonly'), 358 | t(1, 6, 1, 'class.declaration'), t(1, 26, 1, 'property.declaration.static.readonly'), t(1, 40, 3, 'property.declaration.static'), t(1, 45, 3, 'interface.defaultLibrary'), 359 | t(2, 11, 1, 'enum.declaration'), t(2, 15, 1, 'enumMember.declaration.readonly'), t(2, 22, 1, 'enumMember.declaration.readonly'), t(2, 26, 1, 'enumMember.readonly'), 360 | t(3, 0, 7, 'variable.defaultLibrary'), t(3, 8, 3, 'member.defaultLibrary'), t(3, 12, 1, 'variable.readonly'), t(3, 16, 1, 'class'), t(3, 18, 1, 'property.static.readonly'), t(3, 22, 1, 'class'), t(3, 24, 3, 'property.static'), t(3, 28, 6, 'property.readonly.defaultLibrary'), t(3, 37, 1, 'enum'), t(3, 39, 1, 'enumMember.readonly') 361 | ]); 362 | }); 363 | 364 | 365 | test('Local', () => { 366 | const input = [ 367 | /*0*/'const f = 9;', 368 | /*1*/'if (f > 0) { let x = 9;', 369 | /*2*/' function foo(p: number) { var y = x; }', 370 | /*3*/'}' 371 | ].join('\n'); 372 | assertTokens('main.ts', { 'main.ts': input }, [ 373 | t(0, 6, 1, 'variable.declaration.readonly'), 374 | t(1, 4, 1, 'variable.readonly'), t(1, 17, 1, 'variable.declaration.local'), 375 | t(2, 11, 3, 'function.declaration.local'), t(2, 15, 1, 'parameter.declaration'), t(2, 32, 1, 'variable.declaration.local'), t(2, 36, 1, 'variable.local') 376 | ]); 377 | }); 378 | 379 | test('Type Aliases and Type Parameters', () => { 380 | const input = [ 381 | /*0*/'type MyMap = Map;', 382 | /*1*/'function f(t: T | number) : T { ', 383 | /*2*/' return new Map();', 384 | /*3*/'}', 385 | ].join('\n'); 386 | assertTokens('main.ts', { 'main.ts': input }, [ 387 | t(0, 5, 5, 'type.declaration'), t(0, 13, 3, 'interface.defaultLibrary'), 388 | t(1, 9, 1, 'function.declaration'), t(1, 11, 1, 'typeParameter.declaration'), t(1, 21, 5, 'type'), t(1, 28, 1, 'parameter.declaration'), t(1, 31, 1, 'typeParameter'), t(1, 45, 1, 'typeParameter'), 389 | t(2, 10, 1, 'typeParameter'), t(2, 27, 3, 'class.defaultLibrary'), t(2, 39, 5, 'type') 390 | ]); 391 | }); 392 | 393 | test('New Expressions', () => { 394 | const input = [ 395 | /*0*/'new Map();', 396 | /*1*/'class A {} new A();', 397 | /*2*/'class B { constructor(i: number){} } new B(1);', 398 | /*3*/'new Date()', 399 | /*4*/'new window.Date()' 400 | ].join('\n'); 401 | assertTokens('main.ts', { 'main.ts': input }, [ 402 | t(0, 4, 3, 'class.defaultLibrary'), 403 | t(1, 6, 1, 'class.declaration'), t(1, 15, 1, 'class'), 404 | t(2, 6, 1, 'class.declaration'), t(2, 22, 1, 'parameter.declaration'), t(2, 41, 1, 'class'), 405 | t(3, 4, 4, 'class.defaultLibrary'), 406 | t(4, 4, 6, 'variable.defaultLibrary'), t(4, 11, 4, 'class.defaultLibrary') 407 | ]); 408 | }); 409 | 410 | test('BindingElement as parameter', () => { 411 | const input = [ 412 | /*0*/'interface Person { name: string; age: number; }', 413 | /*1*/'function greet({ name, age }: Person) {', 414 | /*2*/' return `hello ` + name;', 415 | /*2*/'}', 416 | ].join('\n'); 417 | assertTokens('main.ts', { 'main.ts': input }, [ 418 | t(0, 10, 6, 'interface.declaration'), t(0, 19, 4, 'property.declaration'), t(0, 33, 3, 'property.declaration'), 419 | t(1, 9, 5, 'function.declaration'), t(1, 17, 4, 'parameter.declaration'), t(1, 23, 3, 'parameter.declaration'), t(1, 30, 6, 'interface'), 420 | t(2, 20, 4, 'parameter') 421 | ]); 422 | }); 423 | 424 | test('BindingElement as variable', () => { 425 | const input = [ 426 | 'interface Person { name: string; age: number; }', 427 | 'function loop(persons: Person[]) {', 428 | ' let totalAge = 0;', 429 | ' for (const { name: localName, age: localAge } of persons) {', 430 | ' totalAge += localAge;', 431 | ' }', 432 | '}', 433 | ].join('\n'); 434 | assertTokens('main.ts', { 'main.ts': input }, [ 435 | t(0, 10, 6, 'interface.declaration'), t(0, 19, 4, 'property.declaration'), t(0, 33, 3, 'property.declaration'), 436 | t(1, 9, 4, 'function.declaration'), t(1, 14, 7, 'parameter.declaration'), t(1, 23, 6, 'interface'), 437 | t(2, 8, 8, 'variable.declaration.local'), 438 | t(3, 17, 4, 'property'), t(3, 23, 9, 'variable.declaration.readonly.local'), t(3, 34, 3, 'property'), t(3, 39, 8, 'variable.declaration.readonly.local'), t(3, 53, 7, 'parameter'), 439 | t(4, 8, 8, 'variable.local'), t(4, 20, 8, 'variable.readonly.local'), 440 | ]); 441 | }); 442 | 443 | test('FunctionExpression', () => { 444 | const input = [ 445 | 'function getSum() {', 446 | ' return function sum() {', 447 | ' };', 448 | '}', 449 | ].join('\n'); 450 | assertTokens('main.ts', { 'main.ts': input }, [ 451 | t(0, 9, 6, 'function.declaration'), 452 | t(1, 20, 3, 'function.declaration'), 453 | ]); 454 | }); 455 | 456 | test('Import', () => { 457 | const input = [ 458 | /*0*/'import { A, I, f, c as d } from "./other"', 459 | /*1*/'A.f = 8 + f() + d;', 460 | ].join('\n'); 461 | const other = [ 462 | /*0*/'export class A { public static f = 9; }', 463 | /*1*/'export interface I { }', 464 | /*2*/'export function f() : number { return 1; }', 465 | /*3*/'export const c = 9;', 466 | ].join('\n'); 467 | assertTokens('main.ts', { 'main.ts': input, 'other.ts': other }, [ 468 | /*t(0, 9, 1, 'class'), t(0, 12, 1, 'interface'), t(0, 15, 1, 'function'), t(0, 18, 1, 'variable.readonly'),*/ 469 | t(1, 0, 1, 'class'), t(1, 2, 1, 'property.static'), t(1, 10, 1, 'function'), t(1, 16, 1, 'variable.readonly') 470 | ]); 471 | }); WeakMap 472 | 473 | test('Library', () => { 474 | const input = [ 475 | /*0*/'new WeakMap>();', 476 | /*1*/`console.log(eval('x + y'));`, 477 | /*2*/`Promise.resolve(null);`, 478 | /*3*/`setTimeout(s => { encodeURIComponent('abc'.replace('a', 'b'));})`, 479 | ].join('\n'); 480 | assertTokens('main.ts', { 'main.ts': input }, [ 481 | t(0, 4, 7, 'class.defaultLibrary'), t(0, 12, 8, 'interface.defaultLibrary'), t(0, 22, 5, 'interface.defaultLibrary'), t(0, 28, 6, 'interface.defaultLibrary'), 482 | t(1, 0, 7, 'variable.defaultLibrary'), t(1, 8, 3, 'member.defaultLibrary'), t(1, 12, 4, 'function.defaultLibrary'), 483 | t(2, 0, 7, 'class.defaultLibrary'), t(2, 8, 7, 'member.defaultLibrary'), t(2, 16, 14, 'interface.defaultLibrary'), t(2, 33, 9, 'interface.defaultLibrary'), 484 | t(3, 0, 10, 'function.defaultLibrary'), t(3, 11, 1, 'parameter.declaration'), t(3, 18, 18, 'function.defaultLibrary'), t(3, 43, 7, 'member.defaultLibrary'), 485 | ]); 486 | }); 487 | 488 | test('Library without value declaration', () => { 489 | const input = [ 490 | /*0*/'type MyIterator = IterableIterator<{ name: string }>;', 491 | ].join('\n'); 492 | assertTokens('main.ts', { 'main.ts': input }, [ 493 | t(0, 5, 10, 'type.declaration'), t(0, 18, 16, 'interface.defaultLibrary'), t(0, 37, 4, 'property.declaration'), 494 | ]); 495 | }) 496 | 497 | test('TSX', () => { 498 | const input = [ 499 | /*0*/'import * as React from "react";', 500 | /*1*/'function () {', 501 | /*2*/' return (
{React.version}
);', 502 | /*3*/'}', 503 | ].join('\n'); 504 | assertTokens('main.tsx', { 'main.tsx': input }, [ 505 | /*t(0, 7, 5, 'namespace'),*/ 506 | t(2, 32, 5, 'namespace'), t(2, 38, 7, 'variable.readonly') 507 | ]); 508 | }); 509 | 510 | 511 | test('JSX2', () => { 512 | const input = [ 513 | /*0*/'const MyComponent = (props) =>
', 514 | /*1*/'const ItemPrice = (props) => {', 515 | /*2*/' return ;', 516 | /*3*/'}', 517 | ].join('\n'); 518 | assertTokens('main.jsx', { 'main.jsx': input }, [ 519 | t(0, 6, 11, 'function.declaration.readonly'), t(0, 21, 5, 'parameter.declaration'), 520 | t(1, 6, 9, 'function.declaration.readonly'), t(1, 19, 5, 'parameter.declaration') 521 | ]); 522 | }); 523 | 524 | 525 | test('JS', () => { 526 | const input = [ 527 | /*0*/'function foo(x, base) { return -Number.parseInt(x, base); }', 528 | ].join('\n'); 529 | assertTokens('main.js', { 'main.js': input }, [ 530 | t(0, 9, 3, 'function.declaration'), t(0, 13, 1, 'parameter.declaration'), t(0, 16, 4, 'parameter.declaration'), t(0, 32, 6, 'class.defaultLibrary'), t(0, 39, 8, 'member.defaultLibrary'), t(0, 48, 1, 'parameter'), t(0, 51, 4, 'parameter') 531 | ]); 532 | }); 533 | 534 | // test for https://github.com/microsoft/TypeScript/issues/43747 535 | // test('JS', () => { 536 | // const input = [ 537 | // /*0*/'var test = { find: function () { this.text = null } }', 538 | // ].join('\n'); 539 | // assertTokens('main.js', { 'main.js': input }, [ 540 | // t(0, 4, 4, 'variable.declaration'), t(0, 13, 4, 'function.declaration') 541 | // ]); 542 | // }); 543 | }); 544 | -------------------------------------------------------------------------------- /test/index.js: -------------------------------------------------------------------------------- 1 | /*--------------------------------------------------------------------------------------------- 2 | * Copyright (c) Microsoft Corporation. All rights reserved. 3 | * Licensed under the MIT License. See License.txt in the project root for license information. 4 | *--------------------------------------------------------------------------------------------*/ 5 | 6 | const Mocha = require('mocha'); 7 | const glob = require('glob'); 8 | 9 | const options = { 10 | ui: 'tdd', 11 | useColors: (!process.env.BUILD_ARTIFACTSTAGINGDIRECTORY && process.platform !== 'win32'), 12 | timeout: 60000 13 | }; 14 | 15 | const mocha = new Mocha(options); 16 | glob.sync(__dirname + '/../lib/test/**/*.test.js').forEach(file => mocha.addFile(file)); 17 | mocha.run(failures => process.exit(failures ? -1 : 0)); 18 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "sourceMap": true, 7 | "declaration": true, 8 | "outDir": "lib", 9 | "noImplicitAny": true, 10 | "noUnusedParameters": true, 11 | "noUnusedLocals": true, 12 | "lib": [ 13 | "es6" 14 | ], 15 | "strict": true, 16 | "baseUrl": "./src" 17 | }, 18 | "include": [ 19 | "./src/**/*.ts" 20 | ] 21 | } -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@types/mocha@5.2.7": 6 | version "5.2.7" 7 | resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.2.7.tgz#315d570ccb56c53452ff8638738df60726d5b6ea" 8 | integrity sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ== 9 | 10 | "@types/node@^12.12.0": 11 | version "12.12.24" 12 | resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.24.tgz#d4606afd8cf6c609036b854360367d1b2c78931f" 13 | integrity sha512-1Ciqv9pqwVtW6FsIUKSZNB82E5Cu1I2bBTj1xuIHXLe/1zYLl3956Nbhg2MzSYHVfl9/rmanjbQIb7LibfCnug== 14 | 15 | "@types/prop-types@*": 16 | version "15.7.3" 17 | resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7" 18 | integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw== 19 | 20 | "@types/react@^17.0.3": 21 | version "17.0.3" 22 | resolved "https://registry.yarnpkg.com/@types/react/-/react-17.0.3.tgz#ba6e215368501ac3826951eef2904574c262cc79" 23 | integrity sha512-wYOUxIgs2HZZ0ACNiIayItyluADNbONl7kt8lkLjVK8IitMH5QMyAh75Fwhmo37r1m7L2JaFj03sIfxBVDvRAg== 24 | dependencies: 25 | "@types/prop-types" "*" 26 | "@types/scheduler" "*" 27 | csstype "^3.0.2" 28 | 29 | "@types/scheduler@*": 30 | version "0.16.1" 31 | resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.1.tgz#18845205e86ff0038517aab7a18a62a6b9f71275" 32 | integrity sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA== 33 | 34 | "@ungap/promise-all-settled@1.1.2": 35 | version "1.1.2" 36 | resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" 37 | integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== 38 | 39 | ansi-colors@4.1.1: 40 | version "4.1.1" 41 | resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" 42 | integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== 43 | 44 | ansi-regex@^3.0.0: 45 | version "3.0.0" 46 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" 47 | integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= 48 | 49 | ansi-regex@^5.0.0: 50 | version "5.0.0" 51 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" 52 | integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== 53 | 54 | ansi-styles@^4.0.0, ansi-styles@^4.1.0: 55 | version "4.3.0" 56 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" 57 | integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== 58 | dependencies: 59 | color-convert "^2.0.1" 60 | 61 | anymatch@~3.1.1: 62 | version "3.1.1" 63 | resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142" 64 | integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg== 65 | dependencies: 66 | normalize-path "^3.0.0" 67 | picomatch "^2.0.4" 68 | 69 | argparse@^2.0.1: 70 | version "2.0.1" 71 | resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" 72 | integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== 73 | 74 | balanced-match@^1.0.0: 75 | version "1.0.0" 76 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 77 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 78 | 79 | binary-extensions@^2.0.0: 80 | version "2.0.0" 81 | resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" 82 | integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== 83 | 84 | brace-expansion@^1.1.7: 85 | version "1.1.11" 86 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 87 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 88 | dependencies: 89 | balanced-match "^1.0.0" 90 | concat-map "0.0.1" 91 | 92 | braces@~3.0.2: 93 | version "3.0.2" 94 | resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" 95 | integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== 96 | dependencies: 97 | fill-range "^7.0.1" 98 | 99 | browser-stdout@1.3.1: 100 | version "1.3.1" 101 | resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" 102 | integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== 103 | 104 | camelcase@^6.0.0: 105 | version "6.2.0" 106 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" 107 | integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== 108 | 109 | chalk@^4.0.0: 110 | version "4.1.0" 111 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" 112 | integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A== 113 | dependencies: 114 | ansi-styles "^4.1.0" 115 | supports-color "^7.1.0" 116 | 117 | chokidar@3.5.1: 118 | version "3.5.1" 119 | resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.1.tgz#ee9ce7bbebd2b79f49f304799d5468e31e14e68a" 120 | integrity sha512-9+s+Od+W0VJJzawDma/gvBNQqkTiqYTWLuZoyAsivsI4AaWTCzHG06/TMjsf1cYe9Cb97UCEhjz7HvnPk2p/tw== 121 | dependencies: 122 | anymatch "~3.1.1" 123 | braces "~3.0.2" 124 | glob-parent "~5.1.0" 125 | is-binary-path "~2.1.0" 126 | is-glob "~4.0.1" 127 | normalize-path "~3.0.0" 128 | readdirp "~3.5.0" 129 | optionalDependencies: 130 | fsevents "~2.3.1" 131 | 132 | cliui@^7.0.2: 133 | version "7.0.4" 134 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" 135 | integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== 136 | dependencies: 137 | string-width "^4.2.0" 138 | strip-ansi "^6.0.0" 139 | wrap-ansi "^7.0.0" 140 | 141 | color-convert@^2.0.1: 142 | version "2.0.1" 143 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 144 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 145 | dependencies: 146 | color-name "~1.1.4" 147 | 148 | color-name@~1.1.4: 149 | version "1.1.4" 150 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 151 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 152 | 153 | concat-map@0.0.1: 154 | version "0.0.1" 155 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 156 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 157 | 158 | csstype@^3.0.2: 159 | version "3.0.7" 160 | resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.0.7.tgz#2a5fb75e1015e84dd15692f71e89a1450290950b" 161 | integrity sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g== 162 | 163 | debug@4.3.1: 164 | version "4.3.1" 165 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" 166 | integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== 167 | dependencies: 168 | ms "2.1.2" 169 | 170 | decamelize@^4.0.0: 171 | version "4.0.0" 172 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" 173 | integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== 174 | 175 | diff@5.0.0: 176 | version "5.0.0" 177 | resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" 178 | integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== 179 | 180 | emoji-regex@^8.0.0: 181 | version "8.0.0" 182 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 183 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 184 | 185 | escalade@^3.1.1: 186 | version "3.1.1" 187 | resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" 188 | integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== 189 | 190 | escape-string-regexp@4.0.0: 191 | version "4.0.0" 192 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" 193 | integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== 194 | 195 | fill-range@^7.0.1: 196 | version "7.0.1" 197 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" 198 | integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== 199 | dependencies: 200 | to-regex-range "^5.0.1" 201 | 202 | find-up@5.0.0: 203 | version "5.0.0" 204 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" 205 | integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== 206 | dependencies: 207 | locate-path "^6.0.0" 208 | path-exists "^4.0.0" 209 | 210 | flat@^5.0.2: 211 | version "5.0.2" 212 | resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" 213 | integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== 214 | 215 | fs.realpath@^1.0.0: 216 | version "1.0.0" 217 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 218 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 219 | 220 | fsevents@~2.3.1: 221 | version "2.3.2" 222 | resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" 223 | integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== 224 | 225 | get-caller-file@^2.0.5: 226 | version "2.0.5" 227 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 228 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 229 | 230 | glob-parent@~5.1.0: 231 | version "5.1.2" 232 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" 233 | integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== 234 | dependencies: 235 | is-glob "^4.0.1" 236 | 237 | glob@7.1.6, glob@^7.1.6: 238 | version "7.1.6" 239 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" 240 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== 241 | dependencies: 242 | fs.realpath "^1.0.0" 243 | inflight "^1.0.4" 244 | inherits "2" 245 | minimatch "^3.0.4" 246 | once "^1.3.0" 247 | path-is-absolute "^1.0.0" 248 | 249 | growl@1.10.5: 250 | version "1.10.5" 251 | resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" 252 | integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== 253 | 254 | has-flag@^4.0.0: 255 | version "4.0.0" 256 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 257 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 258 | 259 | he@1.2.0: 260 | version "1.2.0" 261 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" 262 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== 263 | 264 | inflight@^1.0.4: 265 | version "1.0.6" 266 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 267 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 268 | dependencies: 269 | once "^1.3.0" 270 | wrappy "1" 271 | 272 | inherits@2: 273 | version "2.0.4" 274 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 275 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 276 | 277 | is-binary-path@~2.1.0: 278 | version "2.1.0" 279 | resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" 280 | integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== 281 | dependencies: 282 | binary-extensions "^2.0.0" 283 | 284 | is-extglob@^2.1.1: 285 | version "2.1.1" 286 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 287 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 288 | 289 | is-fullwidth-code-point@^2.0.0: 290 | version "2.0.0" 291 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" 292 | integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= 293 | 294 | is-fullwidth-code-point@^3.0.0: 295 | version "3.0.0" 296 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 297 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 298 | 299 | is-glob@^4.0.1, is-glob@~4.0.1: 300 | version "4.0.1" 301 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" 302 | integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== 303 | dependencies: 304 | is-extglob "^2.1.1" 305 | 306 | is-number@^7.0.0: 307 | version "7.0.0" 308 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" 309 | integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== 310 | 311 | is-plain-obj@^2.1.0: 312 | version "2.1.0" 313 | resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" 314 | integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== 315 | 316 | isexe@^2.0.0: 317 | version "2.0.0" 318 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 319 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 320 | 321 | js-yaml@4.0.0: 322 | version "4.0.0" 323 | resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.0.0.tgz#f426bc0ff4b4051926cd588c71113183409a121f" 324 | integrity sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q== 325 | dependencies: 326 | argparse "^2.0.1" 327 | 328 | locate-path@^6.0.0: 329 | version "6.0.0" 330 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" 331 | integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== 332 | dependencies: 333 | p-locate "^5.0.0" 334 | 335 | log-symbols@4.0.0: 336 | version "4.0.0" 337 | resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.0.0.tgz#69b3cc46d20f448eccdb75ea1fa733d9e821c920" 338 | integrity sha512-FN8JBzLx6CzeMrB0tg6pqlGU1wCrXW+ZXGH481kfsBqer0hToTIiHdjH4Mq8xJUbvATujKCvaREGWpGUionraA== 339 | dependencies: 340 | chalk "^4.0.0" 341 | 342 | minimatch@3.0.4, minimatch@^3.0.4: 343 | version "3.0.4" 344 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 345 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 346 | dependencies: 347 | brace-expansion "^1.1.7" 348 | 349 | mocha@^8.3.2: 350 | version "8.3.2" 351 | resolved "https://registry.yarnpkg.com/mocha/-/mocha-8.3.2.tgz#53406f195fa86fbdebe71f8b1c6fb23221d69fcc" 352 | integrity sha512-UdmISwr/5w+uXLPKspgoV7/RXZwKRTiTjJ2/AC5ZiEztIoOYdfKb19+9jNmEInzx5pBsCyJQzarAxqIGBNYJhg== 353 | dependencies: 354 | "@ungap/promise-all-settled" "1.1.2" 355 | ansi-colors "4.1.1" 356 | browser-stdout "1.3.1" 357 | chokidar "3.5.1" 358 | debug "4.3.1" 359 | diff "5.0.0" 360 | escape-string-regexp "4.0.0" 361 | find-up "5.0.0" 362 | glob "7.1.6" 363 | growl "1.10.5" 364 | he "1.2.0" 365 | js-yaml "4.0.0" 366 | log-symbols "4.0.0" 367 | minimatch "3.0.4" 368 | ms "2.1.3" 369 | nanoid "3.1.20" 370 | serialize-javascript "5.0.1" 371 | strip-json-comments "3.1.1" 372 | supports-color "8.1.1" 373 | which "2.0.2" 374 | wide-align "1.1.3" 375 | workerpool "6.1.0" 376 | yargs "16.2.0" 377 | yargs-parser "20.2.4" 378 | yargs-unparser "2.0.0" 379 | 380 | ms@2.1.2: 381 | version "2.1.2" 382 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 383 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 384 | 385 | ms@2.1.3: 386 | version "2.1.3" 387 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" 388 | integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== 389 | 390 | nanoid@3.1.20: 391 | version "3.1.20" 392 | resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.20.tgz#badc263c6b1dcf14b71efaa85f6ab4c1d6cfc788" 393 | integrity sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw== 394 | 395 | normalize-path@^3.0.0, normalize-path@~3.0.0: 396 | version "3.0.0" 397 | resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" 398 | integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== 399 | 400 | once@^1.3.0: 401 | version "1.4.0" 402 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 403 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 404 | dependencies: 405 | wrappy "1" 406 | 407 | p-limit@^3.0.2: 408 | version "3.1.0" 409 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" 410 | integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== 411 | dependencies: 412 | yocto-queue "^0.1.0" 413 | 414 | p-locate@^5.0.0: 415 | version "5.0.0" 416 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" 417 | integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== 418 | dependencies: 419 | p-limit "^3.0.2" 420 | 421 | path-exists@^4.0.0: 422 | version "4.0.0" 423 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" 424 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== 425 | 426 | path-is-absolute@^1.0.0: 427 | version "1.0.1" 428 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 429 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 430 | 431 | picomatch@^2.0.4: 432 | version "2.2.1" 433 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a" 434 | integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA== 435 | 436 | picomatch@^2.2.1: 437 | version "2.2.2" 438 | resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" 439 | integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== 440 | 441 | randombytes@^2.1.0: 442 | version "2.1.0" 443 | resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" 444 | integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== 445 | dependencies: 446 | safe-buffer "^5.1.0" 447 | 448 | readdirp@~3.5.0: 449 | version "3.5.0" 450 | resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.5.0.tgz#9ba74c019b15d365278d2e91bb8c48d7b4d42c9e" 451 | integrity sha512-cMhu7c/8rdhkHXWsY+osBhfSy0JikwpHK/5+imo+LpeasTF8ouErHrlYkwT0++njiyuDvc7OFY5T3ukvZ8qmFQ== 452 | dependencies: 453 | picomatch "^2.2.1" 454 | 455 | require-directory@^2.1.1: 456 | version "2.1.1" 457 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 458 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= 459 | 460 | safe-buffer@^5.1.0: 461 | version "5.2.1" 462 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" 463 | integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== 464 | 465 | serialize-javascript@5.0.1: 466 | version "5.0.1" 467 | resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4" 468 | integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA== 469 | dependencies: 470 | randombytes "^2.1.0" 471 | 472 | "string-width@^1.0.2 || 2": 473 | version "2.1.1" 474 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" 475 | integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== 476 | dependencies: 477 | is-fullwidth-code-point "^2.0.0" 478 | strip-ansi "^4.0.0" 479 | 480 | string-width@^4.1.0, string-width@^4.2.0: 481 | version "4.2.2" 482 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" 483 | integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== 484 | dependencies: 485 | emoji-regex "^8.0.0" 486 | is-fullwidth-code-point "^3.0.0" 487 | strip-ansi "^6.0.0" 488 | 489 | strip-ansi@^4.0.0: 490 | version "4.0.0" 491 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" 492 | integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= 493 | dependencies: 494 | ansi-regex "^3.0.0" 495 | 496 | strip-ansi@^6.0.0: 497 | version "6.0.0" 498 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" 499 | integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== 500 | dependencies: 501 | ansi-regex "^5.0.0" 502 | 503 | strip-json-comments@3.1.1: 504 | version "3.1.1" 505 | resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" 506 | integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== 507 | 508 | supports-color@8.1.1: 509 | version "8.1.1" 510 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" 511 | integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== 512 | dependencies: 513 | has-flag "^4.0.0" 514 | 515 | supports-color@^7.1.0: 516 | version "7.2.0" 517 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" 518 | integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== 519 | dependencies: 520 | has-flag "^4.0.0" 521 | 522 | to-regex-range@^5.0.1: 523 | version "5.0.1" 524 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" 525 | integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== 526 | dependencies: 527 | is-number "^7.0.0" 528 | 529 | typescript@^4.2.3: 530 | version "4.2.3" 531 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.3.tgz#39062d8019912d43726298f09493d598048c1ce3" 532 | integrity sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw== 533 | 534 | which@2.0.2: 535 | version "2.0.2" 536 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 537 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 538 | dependencies: 539 | isexe "^2.0.0" 540 | 541 | wide-align@1.1.3: 542 | version "1.1.3" 543 | resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" 544 | integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== 545 | dependencies: 546 | string-width "^1.0.2 || 2" 547 | 548 | workerpool@6.1.0: 549 | version "6.1.0" 550 | resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.1.0.tgz#a8e038b4c94569596852de7a8ea4228eefdeb37b" 551 | integrity sha512-toV7q9rWNYha963Pl/qyeZ6wG+3nnsyvolaNUS8+R5Wtw6qJPTxIlOP1ZSvcGhEJw+l3HMMmtiNo9Gl61G4GVg== 552 | 553 | wrap-ansi@^7.0.0: 554 | version "7.0.0" 555 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" 556 | integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== 557 | dependencies: 558 | ansi-styles "^4.0.0" 559 | string-width "^4.1.0" 560 | strip-ansi "^6.0.0" 561 | 562 | wrappy@1: 563 | version "1.0.2" 564 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 565 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 566 | 567 | y18n@^5.0.5: 568 | version "5.0.5" 569 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.5.tgz#8769ec08d03b1ea2df2500acef561743bbb9ab18" 570 | integrity sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg== 571 | 572 | yargs-parser@20.2.4: 573 | version "20.2.4" 574 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" 575 | integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== 576 | 577 | yargs-parser@^20.2.2: 578 | version "20.2.7" 579 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.7.tgz#61df85c113edfb5a7a4e36eb8aa60ef423cbc90a" 580 | integrity sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw== 581 | 582 | yargs-unparser@2.0.0: 583 | version "2.0.0" 584 | resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" 585 | integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== 586 | dependencies: 587 | camelcase "^6.0.0" 588 | decamelize "^4.0.0" 589 | flat "^5.0.2" 590 | is-plain-obj "^2.1.0" 591 | 592 | yargs@16.2.0: 593 | version "16.2.0" 594 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" 595 | integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== 596 | dependencies: 597 | cliui "^7.0.2" 598 | escalade "^3.1.1" 599 | get-caller-file "^2.0.5" 600 | require-directory "^2.1.1" 601 | string-width "^4.2.0" 602 | y18n "^5.0.5" 603 | yargs-parser "^20.2.2" 604 | 605 | yocto-queue@^0.1.0: 606 | version "0.1.0" 607 | resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" 608 | integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== 609 | --------------------------------------------------------------------------------