├── .github └── workflows │ └── nodejs.yml ├── .gitignore ├── .npmignore ├── .npmrc ├── .versionrc.js ├── CHANGELOG.md ├── LICENSE ├── README.md ├── __test__ ├── __snapshot__ │ ├── arrow-function │ │ └── type.ts │ ├── assert │ │ └── index.ts │ ├── class │ │ └── type.ts │ ├── decorators │ │ └── index.ts │ ├── enum │ │ └── type.ts │ ├── export │ │ ├── normal.ts │ │ └── type.ts │ ├── expression │ │ ├── type.ts │ │ └── variables.ts │ ├── for │ │ └── index.ts │ ├── function │ │ └── type.ts │ ├── identifier │ │ └── normal.ts │ ├── import │ │ ├── normal.ts │ │ └── type.ts │ ├── jsx │ │ └── index.ts │ ├── object │ │ └── index.ts │ ├── satisfies │ │ └── index.ts │ └── try │ │ └── index.ts ├── api │ └── parseExpressionAt.test.ts ├── arrow-function │ └── type.test.ts ├── assert │ └── index.test.ts ├── class │ └── type.test.ts ├── decorators │ └── index.test.ts ├── enum │ └── type.test.ts ├── export │ ├── normal.test.ts │ └── type.test.ts ├── expression │ ├── type.test.ts │ └── variables.test.ts ├── for │ └── index.test.ts ├── function │ └── type.test.ts ├── identifier │ └── normal.test.ts ├── import │ ├── normal.test.ts │ └── type.test.ts ├── jsx │ └── index.test.ts ├── object │ └── index.test.ts ├── run_test262.ts ├── satisfies │ └── index.test.ts ├── static │ └── plugin.test.ts ├── try │ └── type.test.ts └── utils.ts ├── jest.config.js ├── package.json ├── src ├── error.ts ├── extentions │ ├── decorators.ts │ ├── import-assertions.ts │ └── jsx │ │ ├── index.ts │ │ └── xhtml.ts ├── index.ts ├── middleware.ts ├── parseutil.ts ├── scopeflags.ts ├── tokenType.ts ├── types.ts └── whitespace.ts ├── tsconfig.json └── yarn.lock /.github/workflows/nodejs.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean install of node dependencies, build the source code and run tests across different versions of node 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions 3 | 4 | name: Node.js CI 5 | 6 | on: 7 | push: 8 | branches: 9 | - master 10 | pull_request: 11 | branches: 12 | - master 13 | 14 | jobs: 15 | build: 16 | runs-on: ${{ matrix.os }} 17 | 18 | strategy: 19 | matrix: 20 | node-version: [ 14.x, 16.x ] 21 | os: [ubuntu-latest] 22 | 23 | steps: 24 | - uses: actions/checkout@v3 25 | - name: Use Node.js ${{ matrix.node-version }} 26 | uses: actions/setup-node@v2 27 | with: 28 | node-version: ${{ matrix.node-version }} 29 | cache: 'yarn' 30 | - run: yarn 31 | - run: yarn build 32 | - run: yarn global add codecov 33 | - run: yarn test 34 | - run: yarn test:test262 35 | 36 | - run: codecov -f coverage/*.json 37 | - run: bash <(curl -s https://codecov.io/bash) 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | lerna-debug.log* 8 | 9 | # Diagnostic reports (https://nodejs.org/api/report.html) 10 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 11 | # ide 12 | 13 | .idea/ 14 | 15 | # Runtime data 16 | pids 17 | *.pid 18 | *.seed 19 | *.pid.lock 20 | 21 | # Directory for instrumented libs generated by jscoverage/JSCover 22 | lib-cov 23 | 24 | # Coverage directory used by tools like istanbul 25 | coverage 26 | *.lcov 27 | 28 | # nyc test coverage 29 | .nyc_output 30 | 31 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 32 | .grunt 33 | 34 | # Bower dependency directory (https://bower.io/) 35 | bower_components 36 | 37 | # node-waf configuration 38 | .lock-wscript 39 | 40 | # Compiled binary addons (https://nodejs.org/api/addons.html) 41 | build/Release 42 | 43 | # Dependency directories 44 | node_modules/ 45 | jspm_packages/ 46 | 47 | # TypeScript v1 declaration files 48 | typings/ 49 | 50 | # TypeScript cache 51 | *.tsbuildinfo 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Microbundle cache 60 | .rpt2_cache/ 61 | .rts2_cache_cjs/ 62 | .rts2_cache_es/ 63 | .rts2_cache_umd/ 64 | 65 | # Optional REPL history 66 | .node_repl_history 67 | 68 | # Output of 'npm pack' 69 | *.tgz 70 | 71 | # Yarn Integrity file 72 | .yarn-integrity 73 | 74 | # dotenv environment variables file 75 | .env 76 | .env.test 77 | 78 | # parcel-bundler cache (https://parceljs.org/) 79 | .cache 80 | 81 | # Next.js build output 82 | .next 83 | 84 | # Nuxt.js build / generate output 85 | .nuxt 86 | dist 87 | 88 | # Gatsby files 89 | .cache/ 90 | # Comment in the public line in if your project uses Gatsby and *not* Next.js 91 | # https://nextjs.org/blog/next-9-1#public-directory-support 92 | # public 93 | 94 | # vuepress build output 95 | .vuepress/dist 96 | 97 | # Serverless directories 98 | .serverless/ 99 | 100 | # FuseBox cache 101 | .fusebox/ 102 | 103 | # DynamoDB Local files 104 | .dynamodb/ 105 | 106 | # TernJS port file 107 | .tern-port 108 | 109 | lib 110 | 111 | .DS_Store 112 | 113 | test262/yarn.lock 114 | test262/package-lock.json 115 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | __test__ 2 | src 3 | coverage 4 | .github 5 | .idea 6 | .versionrc.js 7 | jest.config.js 8 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry = https://registry.npmjs.org/ 2 | -------------------------------------------------------------------------------- /.versionrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "types": [ 3 | { "type": "feat", "section": "✨ Features" }, 4 | { "type": "fix", "section": "🐛 Bug Fixes" }, 5 | { "type": "refactor", "section": "♻️ Code Refactoring" }, 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Tyreal Hu 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 | # acorn-typescript 2 | [![npm version](https://img.shields.io/npm/v/acorn-typescript.svg?style=flat)](https://www.npmjs.com/package/acorn-typescript)[![Coverage Status](https://codecov.io/gh/TyrealHu/acorn-typescript/branch/master/graph/badge.svg)](https://codecov.io/gh/TyrealHu/acorn-typescript) 3 | --- 4 | 5 | This is plugin for [Acorn](http://marijnhaverbeke.nl/acorn/) - a tiny, fast JavaScript parser, written completely in JavaScript. 6 | 7 | It was created as an experimental alternative, faster [TypeScript](https://www.typescriptlang.org/) parser. It will help you to parse 8 | typescript script into typeScript AST. 9 | 10 | ## Usage 11 | 12 | Requiring this module provides you with an Acorn plugin that you can use like this: 13 | 14 | ```typescript 15 | import * as acorn from 'acorn' 16 | import tsPlugin from 'acorn-typescript' 17 | 18 | /* 19 | * 20 | * */ 21 | const node = acorn.Parser.extend(tsPlugin()).parse(` 22 | const a = 1 23 | type A = number 24 | export { 25 | a, 26 | type A as B 27 | } 28 | `, { 29 | sourceType: 'module', 30 | ecmaVersion: 'latest', 31 | locations: true 32 | }) 33 | ``` 34 | 35 | If you want to enable parsing within a TypeScript ambient context, where certain syntax have different rules (like .d.ts files and inside [declare module blocks](https://www.typescriptlang.org/docs/handbook/declaration-files/introduction.html)). 36 | ```typescript 37 | import * as acorn from 'acorn' 38 | import tsPlugin from 'acorn-typescript' 39 | 40 | /* 41 | * 42 | * */ 43 | const node = acorn.Parser.extend(tsPlugin({ dts: true })).parse(` 44 | const a = 1 45 | type A = number 46 | export { 47 | a, 48 | type A as B 49 | } 50 | `, { 51 | sourceType: 'module', 52 | ecmaVersion: 'latest', 53 | locations: true 54 | }) 55 | ``` 56 | 57 | ## Notice 58 | - You have to enable options.locations while using acorn-typescript 59 | ```ts 60 | acorn.parse(input, { 61 | sourceType: 'module', 62 | ecmaVersion: 'latest', 63 | // here 64 | locations: true 65 | }) 66 | ``` 67 | 68 | ## SUPPORTED 69 | - Typescript normal syntax 70 | - Support to parse TypeScript [Decorators](https://www.typescriptlang.org/docs/handbook/decorators.html) 71 | - Support to parse JSX & TSX 72 | 73 | ## CHANGELOG 74 | 75 | [click](./CHANGELOG.md) 76 | 77 | ## RoadMap 78 | - support import-assertions 79 | 80 | ## License 81 | [MIT](https://couto.mit-license.org/) 82 | -------------------------------------------------------------------------------- /__test__/__snapshot__/assert/index.ts: -------------------------------------------------------------------------------- 1 | const AssertionSnapshot = { 2 | ImportAssert: { 3 | 'type': 'Program', 4 | 'start': 0, 5 | 'end': 54, 6 | 'loc': { 7 | 'start': { 8 | 'line': 1, 9 | 'column': 0, 10 | 'index': 0 11 | }, 12 | 'end': { 13 | 'line': 1, 14 | 'column': 54, 15 | 'index': 54 16 | } 17 | }, 18 | 'body': [ 19 | { 20 | 'type': 'ImportDeclaration', 21 | 'start': 0, 22 | 'end': 54, 23 | 'loc': { 24 | 'start': { 25 | 'line': 1, 26 | 'column': 0, 27 | 'index': 0 28 | }, 29 | 'end': { 30 | 'line': 1, 31 | 'column': 54, 32 | 'index': 54 33 | } 34 | }, 35 | 'importKind': 'value', 36 | 'specifiers': [ 37 | { 38 | 'type': 'ImportDefaultSpecifier', 39 | 'start': 7, 40 | 'end': 11, 41 | 'loc': { 42 | 'start': { 43 | 'line': 1, 44 | 'column': 7, 45 | 'index': 7 46 | }, 47 | 'end': { 48 | 'line': 1, 49 | 'column': 11, 50 | 'index': 11 51 | } 52 | }, 53 | 'local': { 54 | 'type': 'Identifier', 55 | 'start': 7, 56 | 'end': 11, 57 | 'loc': { 58 | 'start': { 59 | 'line': 1, 60 | 'column': 7, 61 | 'index': 7 62 | }, 63 | 'end': { 64 | 'line': 1, 65 | 'column': 11, 66 | 'index': 11 67 | } 68 | }, 69 | 'name': 'json' 70 | } 71 | } 72 | ], 73 | 'source': { 74 | 'type': 'Literal', 75 | 'start': 17, 76 | 'end': 29, 77 | 'loc': { 78 | 'start': { 79 | 'line': 1, 80 | 'column': 17, 81 | 'index': 17 82 | }, 83 | 'end': { 84 | 'line': 1, 85 | 'column': 29, 86 | 'index': 29 87 | } 88 | }, 89 | 'value': './foo.json', 90 | 'raw': '\'./foo.json\'' 91 | }, 92 | 'attributes': [ 93 | { 94 | 'type': 'ImportAttribute', 95 | 'start': 39, 96 | 'end': 51, 97 | 'loc': { 98 | 'start': { 99 | 'line': 1, 100 | 'column': 39, 101 | 'index': 39 102 | }, 103 | 'end': { 104 | 'line': 1, 105 | 'column': 51, 106 | 'index': 51 107 | } 108 | }, 109 | 'key': { 110 | 'type': 'Identifier', 111 | 'start': 39, 112 | 'end': 43, 113 | 'loc': { 114 | 'start': { 115 | 'line': 1, 116 | 'column': 39, 117 | 'index': 39 118 | }, 119 | 'end': { 120 | 'line': 1, 121 | 'column': 43, 122 | 'index': 43 123 | } 124 | }, 125 | 'name': 'type' 126 | }, 127 | 'value': { 128 | 'type': 'Literal', 129 | 'start': 45, 130 | 'end': 51, 131 | 'loc': { 132 | 'start': { 133 | 'line': 1, 134 | 'column': 45, 135 | 'index': 45 136 | }, 137 | 'end': { 138 | 'line': 1, 139 | 'column': 51, 140 | 'index': 51 141 | } 142 | }, 143 | 'value': 'json', 144 | 'raw': '\'json\'' 145 | } 146 | } 147 | ] 148 | } 149 | ], 150 | 'sourceType': 'module' 151 | }, 152 | ImportWith: { 153 | 'type': 'Program', 154 | 'start': 0, 155 | 'end': 52, 156 | 'loc': { 157 | 'start': { 158 | 'line': 1, 159 | 'column': 0, 160 | 'index': 0 161 | }, 162 | 'end': { 163 | 'line': 1, 164 | 'column': 52, 165 | 'index': 52 166 | } 167 | }, 168 | 'body': [ 169 | { 170 | 'type': 'ImportDeclaration', 171 | 'start': 0, 172 | 'end': 52, 173 | 'loc': { 174 | 'start': { 175 | 'line': 1, 176 | 'column': 0, 177 | 'index': 0 178 | }, 179 | 'end': { 180 | 'line': 1, 181 | 'column': 52, 182 | 'index': 52 183 | } 184 | }, 185 | 'importKind': 'value', 186 | 'specifiers': [ 187 | { 188 | 'type': 'ImportDefaultSpecifier', 189 | 'start': 7, 190 | 'end': 11, 191 | 'loc': { 192 | 'start': { 193 | 'line': 1, 194 | 'column': 7, 195 | 'index': 7 196 | }, 197 | 'end': { 198 | 'line': 1, 199 | 'column': 11, 200 | 'index': 11 201 | } 202 | }, 203 | 'local': { 204 | 'type': 'Identifier', 205 | 'start': 7, 206 | 'end': 11, 207 | 'loc': { 208 | 'start': { 209 | 'line': 1, 210 | 'column': 7, 211 | 'index': 7 212 | }, 213 | 'end': { 214 | 'line': 1, 215 | 'column': 11, 216 | 'index': 11 217 | } 218 | }, 219 | 'name': 'json' 220 | } 221 | } 222 | ], 223 | 'source': { 224 | 'type': 'Literal', 225 | 'start': 17, 226 | 'end': 29, 227 | 'loc': { 228 | 'start': { 229 | 'line': 1, 230 | 'column': 17, 231 | 'index': 17 232 | }, 233 | 'end': { 234 | 'line': 1, 235 | 'column': 29, 236 | 'index': 29 237 | } 238 | }, 239 | 'value': './foo.json', 240 | 'raw': '\'./foo.json\'' 241 | }, 242 | 'attributes': [ 243 | { 244 | 'type': 'ImportAttribute', 245 | 'start': 37, 246 | 'end': 49, 247 | 'loc': { 248 | 'start': { 249 | 'line': 1, 250 | 'column': 37, 251 | 'index': 37 252 | }, 253 | 'end': { 254 | 'line': 1, 255 | 'column': 49, 256 | 'index': 49 257 | } 258 | }, 259 | 'key': { 260 | 'type': 'Identifier', 261 | 'start': 37, 262 | 'end': 41, 263 | 'loc': { 264 | 'start': { 265 | 'line': 1, 266 | 'column': 37, 267 | 'index': 37 268 | }, 269 | 'end': { 270 | 'line': 1, 271 | 'column': 41, 272 | 'index': 41 273 | } 274 | }, 275 | 'name': 'type' 276 | }, 277 | 'value': { 278 | 'type': 'Literal', 279 | 'start': 43, 280 | 'end': 49, 281 | 'loc': { 282 | 'start': { 283 | 'line': 1, 284 | 'column': 43, 285 | 'index': 43 286 | }, 287 | 'end': { 288 | 'line': 1, 289 | 'column': 49, 290 | 'index': 49 291 | } 292 | }, 293 | 'value': 'json', 294 | 'raw': '\'json\'' 295 | } 296 | } 297 | ] 298 | } 299 | ], 300 | 'sourceType': 'module' 301 | }, 302 | DynamicImportAssert: { 303 | 'type': 'Program', 304 | 'start': 0, 305 | 'end': 49, 306 | 'loc': { 307 | 'start': { 308 | 'line': 1, 309 | 'column': 0, 310 | 'index': 0 311 | }, 312 | 'end': { 313 | 'line': 1, 314 | 'column': 49, 315 | 'index': 49 316 | } 317 | }, 318 | 'body': [ 319 | { 320 | 'type': 'ExpressionStatement', 321 | 'start': 0, 322 | 'end': 49, 323 | 'loc': { 324 | 'start': { 325 | 'line': 1, 326 | 'column': 0, 327 | 'index': 0 328 | }, 329 | 'end': { 330 | 'line': 1, 331 | 'column': 49, 332 | 'index': 49 333 | } 334 | }, 335 | 'expression': { 336 | 'type': 'ImportExpression', 337 | 'start': 0, 338 | 'end': 48, 339 | 'loc': { 340 | 'start': { 341 | 'line': 1, 342 | 'column': 0, 343 | 'index': 0 344 | }, 345 | 'end': { 346 | 'line': 1, 347 | 'column': 48, 348 | 'index': 48 349 | } 350 | }, 351 | 'source': { 352 | 'type': 'Literal', 353 | 'start': 7, 354 | 'end': 19, 355 | 'loc': { 356 | 'start': { 357 | 'line': 1, 358 | 'column': 7, 359 | 'index': 7 360 | }, 361 | 'end': { 362 | 'line': 1, 363 | 'column': 19, 364 | 'index': 19 365 | } 366 | }, 367 | 'value': './foo.json', 368 | 'raw': '"./foo.json"' 369 | }, 370 | 'arguments': [ 371 | { 372 | 'type': 'ObjectExpression', 373 | 'start': 21, 374 | 'end': 47, 375 | 'loc': { 376 | 'start': { 377 | 'line': 1, 378 | 'column': 21, 379 | 'index': 21 380 | }, 381 | 'end': { 382 | 'line': 1, 383 | 'column': 47, 384 | 'index': 47 385 | } 386 | }, 387 | 'properties': [ 388 | { 389 | 'type': 'Property', 390 | 'start': 23, 391 | 'end': 45, 392 | 'loc': { 393 | 'start': { 394 | 'line': 1, 395 | 'column': 23, 396 | 'index': 23 397 | }, 398 | 'end': { 399 | 'line': 1, 400 | 'column': 45, 401 | 'index': 45 402 | } 403 | }, 404 | 'method': false, 405 | 'shorthand': false, 406 | 'computed': false, 407 | 'key': { 408 | 'type': 'Identifier', 409 | 'start': 23, 410 | 'end': 27, 411 | 'loc': { 412 | 'start': { 413 | 'line': 1, 414 | 'column': 23, 415 | 'index': 23 416 | }, 417 | 'end': { 418 | 'line': 1, 419 | 'column': 27, 420 | 'index': 27 421 | } 422 | }, 423 | 'name': 'with' 424 | }, 425 | 'value': { 426 | 'type': 'ObjectExpression', 427 | 'start': 29, 428 | 'end': 45, 429 | 'loc': { 430 | 'start': { 431 | 'line': 1, 432 | 'column': 29, 433 | 'index': 29 434 | }, 435 | 'end': { 436 | 'line': 1, 437 | 'column': 45, 438 | 'index': 45 439 | } 440 | }, 441 | 'properties': [ 442 | { 443 | 'type': 'Property', 444 | 'start': 31, 445 | 'end': 43, 446 | 'loc': { 447 | 'start': { 448 | 'line': 1, 449 | 'column': 31, 450 | 'index': 31 451 | }, 452 | 'end': { 453 | 'line': 1, 454 | 'column': 43, 455 | 'index': 43 456 | } 457 | }, 458 | 'method': false, 459 | 'shorthand': false, 460 | 'computed': false, 461 | 'key': { 462 | 'type': 'Identifier', 463 | 'start': 31, 464 | 'end': 35, 465 | 'loc': { 466 | 'start': { 467 | 'line': 1, 468 | 'column': 31, 469 | 'index': 31 470 | }, 471 | 'end': { 472 | 'line': 1, 473 | 'column': 35, 474 | 'index': 35 475 | } 476 | }, 477 | 'name': 'type' 478 | }, 479 | 'value': { 480 | 'type': 'Literal', 481 | 'start': 37, 482 | 'end': 43, 483 | 'loc': { 484 | 'start': { 485 | 'line': 1, 486 | 'column': 37, 487 | 'index': 37 488 | }, 489 | 'end': { 490 | 'line': 1, 491 | 'column': 43, 492 | 'index': 43 493 | } 494 | }, 495 | 'value': 'json', 496 | 'raw': '"json"' 497 | }, 498 | 'kind': 'init' 499 | } 500 | ] 501 | }, 502 | 'kind': 'init' 503 | } 504 | ] 505 | } 506 | ] 507 | } 508 | } 509 | ], 510 | 'sourceType': 'module' 511 | }, 512 | ExportAllAsAssert: { 513 | 'type': 'Program', 514 | 'start': 0, 515 | 'end': 57, 516 | 'loc': { 517 | 'start': { 518 | 'line': 1, 519 | 'column': 0, 520 | 'index': 0 521 | }, 522 | 'end': { 523 | 'line': 1, 524 | 'column': 57, 525 | 'index': 57 526 | } 527 | }, 528 | 'body': [ 529 | { 530 | 'type': 'ExportAllDeclaration', 531 | 'start': 0, 532 | 'end': 57, 533 | 'loc': { 534 | 'start': { 535 | 'line': 1, 536 | 'column': 0, 537 | 'index': 0 538 | }, 539 | 'end': { 540 | 'line': 1, 541 | 'column': 57, 542 | 'index': 57 543 | } 544 | }, 545 | 'exportKind': 'value', 546 | 'exported': { 547 | 'type': 'Identifier', 548 | 'start': 12, 549 | 'end': 16, 550 | 'loc': { 551 | 'start': { 552 | 'line': 1, 553 | 'column': 12, 554 | 'index': 12 555 | }, 556 | 'end': { 557 | 'line': 1, 558 | 'column': 16, 559 | 'index': 16 560 | } 561 | }, 562 | 'name': 'name' 563 | }, 564 | 'source': { 565 | 'type': 'Literal', 566 | 'start': 22, 567 | 'end': 34, 568 | 'loc': { 569 | 'start': { 570 | 'line': 1, 571 | 'column': 22, 572 | 'index': 22 573 | }, 574 | 'end': { 575 | 'line': 1, 576 | 'column': 34, 577 | 'index': 34 578 | } 579 | }, 580 | 'value': './foo.json', 581 | 'raw': '"./foo.json"' 582 | }, 583 | 'attributes': [ 584 | { 585 | 'type': 'ImportAttribute', 586 | 'start': 42, 587 | 'end': 54, 588 | 'loc': { 589 | 'start': { 590 | 'line': 1, 591 | 'column': 42, 592 | 'index': 42 593 | }, 594 | 'end': { 595 | 'line': 1, 596 | 'column': 54, 597 | 'index': 54 598 | } 599 | }, 600 | 'key': { 601 | 'type': 'Identifier', 602 | 'start': 42, 603 | 'end': 46, 604 | 'loc': { 605 | 'start': { 606 | 'line': 1, 607 | 'column': 42, 608 | 'index': 42 609 | }, 610 | 'end': { 611 | 'line': 1, 612 | 'column': 46, 613 | 'index': 46 614 | } 615 | }, 616 | 'name': 'type' 617 | }, 618 | 'value': { 619 | 'type': 'Literal', 620 | 'start': 48, 621 | 'end': 54, 622 | 'loc': { 623 | 'start': { 624 | 'line': 1, 625 | 'column': 48, 626 | 'index': 48 627 | }, 628 | 'end': { 629 | 'line': 1, 630 | 'column': 54, 631 | 'index': 54 632 | } 633 | }, 634 | 'value': 'json', 635 | 'raw': '"json"' 636 | } 637 | } 638 | ] 639 | } 640 | ], 641 | 'sourceType': 'module' 642 | } 643 | } 644 | 645 | export default AssertionSnapshot 646 | -------------------------------------------------------------------------------- /__test__/__snapshot__/enum/type.ts: -------------------------------------------------------------------------------- 1 | const EnumTypeSnapshot = { 2 | Normal: { 3 | 'type': 'Program', 4 | 'start': 0, 5 | 'end': 64, 6 | 'loc': { 7 | 'start': { 'line': 1, 'column': 0, 'index': 0 }, 8 | 'end': { 'line': 5, 'column': 1, 'index': 64 } 9 | }, 10 | 'body': [{ 11 | 'type': 'TSEnumDeclaration', 12 | 'start': 0, 13 | 'end': 64, 14 | 'loc': { 15 | 'start': { 'line': 1, 'column': 0, 'index': 0 }, 16 | 'end': { 'line': 5, 'column': 1, 'index': 64 } 17 | }, 18 | 'id': { 19 | 'type': 'Identifier', 20 | 'start': 5, 21 | 'end': 12, 22 | 'loc': { 23 | 'start': { 'line': 1, 'column': 5, 'index': 5 }, 24 | 'end': { 'line': 1, 'column': 12, 'index': 12 } 25 | }, 26 | 'name': 'Student' 27 | }, 28 | 'members': [{ 29 | 'type': 'TSEnumMember', 30 | 'start': 16, 31 | 'end': 31, 32 | 'loc': { 33 | 'start': { 'line': 2, 'column': 1, 'index': 16 }, 34 | 'end': { 'line': 2, 'column': 16, 'index': 31 } 35 | }, 36 | 'id': { 37 | 'type': 'Identifier', 38 | 'start': 16, 39 | 'end': 20, 40 | 'loc': { 41 | 'start': { 'line': 2, 'column': 1, 'index': 16 }, 42 | 'end': { 'line': 2, 'column': 5, 'index': 20 } 43 | }, 44 | 'name': 'name' 45 | }, 46 | 'initializer': { 47 | 'type': 'Literal', 48 | 'start': 23, 49 | 'end': 31, 50 | 'loc': { 51 | 'start': { 'line': 2, 'column': 8, 'index': 23 }, 52 | 'end': { 'line': 2, 'column': 16, 'index': 31 } 53 | }, 54 | 'value': 'tyreal', 55 | 'raw': '\'tyreal\'' 56 | } 57 | }, { 58 | 'type': 'TSEnumMember', 59 | 'start': 34, 60 | 'end': 42, 61 | 'loc': { 62 | 'start': { 'line': 3, 'column': 1, 'index': 34 }, 63 | 'end': { 'line': 3, 'column': 9, 'index': 42 } 64 | }, 65 | 'id': { 66 | 'type': 'Identifier', 67 | 'start': 34, 68 | 'end': 37, 69 | 'loc': { 70 | 'start': { 'line': 3, 'column': 1, 'index': 34 }, 71 | 'end': { 'line': 3, 'column': 4, 'index': 37 } 72 | }, 73 | 'name': 'age' 74 | }, 75 | 'initializer': { 76 | 'type': 'Literal', 77 | 'start': 40, 78 | 'end': 42, 79 | 'loc': { 80 | 'start': { 'line': 3, 'column': 7, 'index': 40 }, 81 | 'end': { 'line': 3, 'column': 9, 'index': 42 } 82 | }, 83 | 'value': 22, 84 | 'raw': '22' 85 | } 86 | }, { 87 | 'type': 'TSEnumMember', 88 | 'start': 45, 89 | 'end': 62, 90 | 'loc': { 91 | 'start': { 'line': 4, 'column': 1, 'index': 45 }, 92 | 'end': { 'line': 4, 'column': 18, 'index': 62 } 93 | }, 94 | 'id': { 95 | 'type': 'Identifier', 96 | 'start': 45, 97 | 'end': 51, 98 | 'loc': { 99 | 'start': { 'line': 4, 'column': 1, 'index': 45 }, 100 | 'end': { 'line': 4, 'column': 7, 'index': 51 } 101 | }, 102 | 'name': 'school' 103 | }, 104 | 'initializer': { 105 | 'type': 'Literal', 106 | 'start': 54, 107 | 'end': 62, 108 | 'loc': { 109 | 'start': { 'line': 4, 'column': 10, 'index': 54 }, 110 | 'end': { 'line': 4, 'column': 18, 'index': 62 } 111 | }, 112 | 'value': 'string', 113 | 'raw': '\'string\'' 114 | } 115 | }] 116 | }], 117 | 'sourceType': 'module' 118 | } 119 | } 120 | 121 | export default EnumTypeSnapshot 122 | -------------------------------------------------------------------------------- /__test__/__snapshot__/for/index.ts: -------------------------------------------------------------------------------- 1 | const ForSnapshot = { 2 | of: { 3 | 'type': 'Program', 4 | 'start': 0, 5 | 'end': 65, 6 | 'loc': { 7 | 'start': { 8 | 'line': 1, 9 | 'column': 0, 10 | 'index': 0 11 | }, 12 | 'end': { 13 | 'line': 4, 14 | 'column': 1, 15 | 'index': 65 16 | } 17 | }, 18 | 'body': [ 19 | { 20 | 'type': 'VariableDeclaration', 21 | 'start': 0, 22 | 'end': 16, 23 | 'loc': { 24 | 'start': { 25 | 'line': 1, 26 | 'column': 0, 27 | 'index': 0 28 | }, 29 | 'end': { 30 | 'line': 1, 31 | 'column': 16, 32 | 'index': 16 33 | } 34 | }, 35 | 'declarations': [ 36 | { 37 | 'type': 'VariableDeclarator', 38 | 'start': 6, 39 | 'end': 16, 40 | 'loc': { 41 | 'start': { 42 | 'line': 1, 43 | 'column': 6, 44 | 'index': 6 45 | }, 46 | 'end': { 47 | 'line': 1, 48 | 'column': 16, 49 | 'index': 16 50 | } 51 | }, 52 | 'id': { 53 | 'type': 'Identifier', 54 | 'start': 6, 55 | 'end': 11, 56 | 'loc': { 57 | 'start': { 58 | 'line': 1, 59 | 'column': 6, 60 | 'index': 6 61 | }, 62 | 'end': { 63 | 'line': 1, 64 | 'column': 11, 65 | 'index': 11 66 | } 67 | }, 68 | 'name': 'words' 69 | }, 70 | 'init': { 71 | 'type': 'ArrayExpression', 72 | 'start': 14, 73 | 'end': 16, 74 | 'loc': { 75 | 'start': { 76 | 'line': 1, 77 | 'column': 14, 78 | 'index': 14 79 | }, 80 | 'end': { 81 | 'line': 1, 82 | 'column': 16, 83 | 'index': 16 84 | } 85 | }, 86 | 'elements': [] 87 | } 88 | } 89 | ], 90 | 'kind': 'const' 91 | }, 92 | { 93 | 'type': 'ForOfStatement', 94 | 'start': 17, 95 | 'end': 65, 96 | 'loc': { 97 | 'start': { 98 | 'line': 2, 99 | 'column': 0, 100 | 'index': 17 101 | }, 102 | 'end': { 103 | 'line': 4, 104 | 'column': 1, 105 | 'index': 65 106 | } 107 | }, 108 | 'await': false, 109 | 'left': { 110 | 'type': 'VariableDeclaration', 111 | 'start': 22, 112 | 'end': 32, 113 | 'loc': { 114 | 'start': { 115 | 'line': 2, 116 | 'column': 5, 117 | 'index': 22 118 | }, 119 | 'end': { 120 | 'line': 2, 121 | 'column': 15, 122 | 'index': 32 123 | } 124 | }, 125 | 'declarations': [ 126 | { 127 | 'type': 'VariableDeclarator', 128 | 'start': 28, 129 | 'end': 32, 130 | 'loc': { 131 | 'start': { 132 | 'line': 2, 133 | 'column': 11, 134 | 'index': 28 135 | }, 136 | 'end': { 137 | 'line': 2, 138 | 'column': 15, 139 | 'index': 32 140 | } 141 | }, 142 | 'id': { 143 | 'type': 'Identifier', 144 | 'start': 28, 145 | 'end': 32, 146 | 'loc': { 147 | 'start': { 148 | 'line': 2, 149 | 'column': 11, 150 | 'index': 28 151 | }, 152 | 'end': { 153 | 'line': 2, 154 | 'column': 15, 155 | 'index': 32 156 | } 157 | }, 158 | 'name': 'word' 159 | }, 160 | 'init': null 161 | } 162 | ], 163 | 'kind': 'const' 164 | }, 165 | 'right': { 166 | 'type': 'Identifier', 167 | 'start': 36, 168 | 'end': 41, 169 | 'loc': { 170 | 'start': { 171 | 'line': 2, 172 | 'column': 19, 173 | 'index': 36 174 | }, 175 | 'end': { 176 | 'line': 2, 177 | 'column': 24, 178 | 'index': 41 179 | } 180 | }, 181 | 'name': 'words' 182 | }, 183 | 'body': { 184 | 'type': 'BlockStatement', 185 | 'start': 43, 186 | 'end': 65, 187 | 'loc': { 188 | 'start': { 189 | 'line': 2, 190 | 'column': 26, 191 | 'index': 43 192 | }, 193 | 'end': { 194 | 'line': 4, 195 | 'column': 1, 196 | 'index': 65 197 | } 198 | }, 199 | 'body': [ 200 | { 201 | 'type': 'ExpressionStatement', 202 | 'start': 46, 203 | 'end': 63, 204 | 'loc': { 205 | 'start': { 206 | 'line': 3, 207 | 'column': 1, 208 | 'index': 46 209 | }, 210 | 'end': { 211 | 'line': 3, 212 | 'column': 18, 213 | 'index': 63 214 | } 215 | }, 216 | 'expression': { 217 | 'type': 'CallExpression', 218 | 'start': 46, 219 | 'end': 63, 220 | 'loc': { 221 | 'start': { 222 | 'line': 3, 223 | 'column': 1, 224 | 'index': 46 225 | }, 226 | 'end': { 227 | 'line': 3, 228 | 'column': 18, 229 | 'index': 63 230 | } 231 | }, 232 | 'callee': { 233 | 'type': 'MemberExpression', 234 | 'start': 46, 235 | 'end': 57, 236 | 'loc': { 237 | 'start': { 238 | 'line': 3, 239 | 'column': 1, 240 | 'index': 46 241 | }, 242 | 'end': { 243 | 'line': 3, 244 | 'column': 12, 245 | 'index': 57 246 | } 247 | }, 248 | 'object': { 249 | 'type': 'Identifier', 250 | 'start': 46, 251 | 'end': 53, 252 | 'loc': { 253 | 'start': { 254 | 'line': 3, 255 | 'column': 1, 256 | 'index': 46 257 | }, 258 | 'end': { 259 | 'line': 3, 260 | 'column': 8, 261 | 'index': 53 262 | } 263 | }, 264 | 'name': 'console' 265 | }, 266 | 'property': { 267 | 'type': 'Identifier', 268 | 'start': 54, 269 | 'end': 57, 270 | 'loc': { 271 | 'start': { 272 | 'line': 3, 273 | 'column': 9, 274 | 'index': 54 275 | }, 276 | 'end': { 277 | 'line': 3, 278 | 'column': 12, 279 | 'index': 57 280 | } 281 | }, 282 | 'name': 'log' 283 | }, 284 | 'computed': false, 285 | 'optional': false 286 | }, 287 | 'arguments': [ 288 | { 289 | 'type': 'Identifier', 290 | 'start': 58, 291 | 'end': 62, 292 | 'loc': { 293 | 'start': { 294 | 'line': 3, 295 | 'column': 13, 296 | 'index': 58 297 | }, 298 | 'end': { 299 | 'line': 3, 300 | 'column': 17, 301 | 'index': 62 302 | } 303 | }, 304 | 'name': 'word' 305 | } 306 | ], 307 | 'optional': false 308 | } 309 | } 310 | ] 311 | } 312 | } 313 | ], 314 | 'sourceType': 'module' 315 | }, 316 | inWithoutDecl: { 317 | type: "Program", 318 | start: 0, 319 | end: 42, 320 | loc: { 321 | start: { line: 1, column: 0, index: 0 }, 322 | end: { line: 3, column: 1, index: 42 }, 323 | }, 324 | body: [ 325 | { 326 | type: "ForInStatement", 327 | start: 0, 328 | end: 42, 329 | loc: { 330 | start: { line: 1, column: 0, index: 0 }, 331 | end: { line: 3, column: 1, index: 42 }, 332 | }, 333 | left: { 334 | type: "Identifier", 335 | start: 5, 336 | end: 9, 337 | loc: { 338 | start: { line: 1, column: 5, index: 5 }, 339 | end: { line: 1, column: 9, index: 9 }, 340 | }, 341 | name: "word", 342 | }, 343 | right: { 344 | type: "Identifier", 345 | start: 13, 346 | end: 18, 347 | loc: { 348 | start: { line: 1, column: 13, index: 13 }, 349 | end: { line: 1, column: 18, index: 18 }, 350 | }, 351 | name: "words", 352 | }, 353 | body: { 354 | type: "BlockStatement", 355 | start: 20, 356 | end: 42, 357 | loc: { 358 | start: { line: 1, column: 20, index: 20 }, 359 | end: { line: 3, column: 1, index: 42 }, 360 | }, 361 | body: [ 362 | { 363 | type: "ExpressionStatement", 364 | start: 23, 365 | end: 40, 366 | loc: { 367 | start: { line: 2, column: 1, index: 23 }, 368 | end: { line: 2, column: 18, index: 40 }, 369 | }, 370 | expression: { 371 | type: "CallExpression", 372 | start: 23, 373 | end: 40, 374 | loc: { 375 | start: { line: 2, column: 1, index: 23 }, 376 | end: { line: 2, column: 18, index: 40 }, 377 | }, 378 | callee: { 379 | type: "MemberExpression", 380 | start: 23, 381 | end: 34, 382 | loc: { 383 | start: { line: 2, column: 1, index: 23 }, 384 | end: { line: 2, column: 12, index: 34 }, 385 | }, 386 | object: { 387 | type: "Identifier", 388 | start: 23, 389 | end: 30, 390 | loc: { 391 | start: { line: 2, column: 1, index: 23 }, 392 | end: { line: 2, column: 8, index: 30 }, 393 | }, 394 | name: "console", 395 | }, 396 | property: { 397 | type: "Identifier", 398 | start: 31, 399 | end: 34, 400 | loc: { 401 | start: { line: 2, column: 9, index: 31 }, 402 | end: { line: 2, column: 12, index: 34 }, 403 | }, 404 | name: "log", 405 | }, 406 | computed: false, 407 | optional: false, 408 | }, 409 | arguments: [ 410 | { 411 | type: "Identifier", 412 | start: 35, 413 | end: 39, 414 | loc: { 415 | start: { line: 2, column: 13, index: 35 }, 416 | end: { line: 2, column: 17, index: 39 }, 417 | }, 418 | name: "word", 419 | }, 420 | ], 421 | optional: false, 422 | }, 423 | }, 424 | ], 425 | }, 426 | }, 427 | ], 428 | sourceType: "module", 429 | }, 430 | }; 431 | 432 | export default ForSnapshot; 433 | -------------------------------------------------------------------------------- /__test__/__snapshot__/identifier/normal.ts: -------------------------------------------------------------------------------- 1 | const NormalIdentifierSnapshot = { 2 | Issue50: { 3 | 'type': 'Program', 4 | 'start': 0, 5 | 'end': 25, 6 | 'loc': { 7 | 'start': { 8 | 'line': 1, 9 | 'column': 0, 10 | 'index': 0 11 | }, 12 | 'end': { 13 | 'line': 2, 14 | 'column': 8, 15 | 'index': 25 16 | } 17 | }, 18 | 'body': [ 19 | { 20 | 'type': 'TSTypeAliasDeclaration', 21 | 'start': 0, 22 | 'end': 16, 23 | 'loc': { 24 | 'start': { 25 | 'line': 1, 26 | 'column': 0, 27 | 'index': 0 28 | }, 29 | 'end': { 30 | 'line': 1, 31 | 'column': 16, 32 | 'index': 16 33 | } 34 | }, 35 | 'id': { 36 | 'type': 'Identifier', 37 | 'start': 5, 38 | 'end': 8, 39 | 'loc': { 40 | 'start': { 41 | 'line': 1, 42 | 'column': 5, 43 | 'index': 5 44 | }, 45 | 'end': { 46 | 'line': 1, 47 | 'column': 8, 48 | 'index': 8 49 | } 50 | }, 51 | 'name': 'abc' 52 | }, 53 | 'typeAnnotation': { 54 | 'type': 'TSLiteralType', 55 | 'start': 11, 56 | 'end': 15, 57 | 'loc': { 58 | 'start': { 59 | 'line': 1, 60 | 'column': 11, 61 | 'index': 11 62 | }, 63 | 'end': { 64 | 'line': 1, 65 | 'column': 15, 66 | 'index': 15 67 | } 68 | }, 69 | 'literal': { 70 | 'type': 'Literal', 71 | 'start': 11, 72 | 'end': 15, 73 | 'loc': { 74 | 'start': { 75 | 'line': 1, 76 | 'column': 11, 77 | 'index': 11 78 | }, 79 | 'end': { 80 | 'line': 1, 81 | 'column': 15, 82 | 'index': 15 83 | } 84 | }, 85 | 'value': 1234, 86 | 'raw': '1234' 87 | } 88 | } 89 | }, 90 | { 91 | 'type': 'VariableDeclaration', 92 | 'start': 17, 93 | 'end': 25, 94 | 'loc': { 95 | 'start': { 96 | 'line': 2, 97 | 'column': 0, 98 | 'index': 17 99 | }, 100 | 'end': { 101 | 'line': 2, 102 | 'column': 8, 103 | 'index': 25 104 | } 105 | }, 106 | 'declarations': [ 107 | { 108 | 'type': 'VariableDeclarator', 109 | 'start': 21, 110 | 'end': 24, 111 | 'loc': { 112 | 'start': { 113 | 'line': 2, 114 | 'column': 4, 115 | 'index': 21 116 | }, 117 | 'end': { 118 | 'line': 2, 119 | 'column': 7, 120 | 'index': 24 121 | } 122 | }, 123 | 'id': { 124 | 'type': 'Identifier', 125 | 'start': 21, 126 | 'end': 24, 127 | 'loc': { 128 | 'start': { 129 | 'line': 2, 130 | 'column': 4, 131 | 'index': 21 132 | }, 133 | 'end': { 134 | 'line': 2, 135 | 'column': 7, 136 | 'index': 24 137 | } 138 | }, 139 | 'name': 'abc' 140 | }, 141 | 'init': null 142 | } 143 | ], 144 | 'kind': 'var' 145 | } 146 | ], 147 | 'sourceType': 'module' 148 | }, 149 | ExportIdentifierAs: { 150 | type: 'Program', 151 | start: 0, 152 | end: 34, 153 | loc: { 154 | start: { line: 1, column: 0, index: 0 }, 155 | end: { line: 2, column: 21, index: 34 } 156 | }, 157 | body: [ 158 | { 159 | type: 'VariableDeclaration', 160 | start: 0, 161 | end: 12, 162 | loc: { 163 | start: { line: 1, column: 0, index: 0 }, 164 | end: { line: 1, column: 12, index: 12 } 165 | }, 166 | declarations: [ 167 | { 168 | type: 'VariableDeclarator', 169 | start: 4, 170 | end: 11, 171 | loc: { 172 | start: { line: 1, column: 4, index: 4 }, 173 | end: { line: 1, column: 11, index: 11 } 174 | }, 175 | id: { 176 | type: 'Identifier', 177 | start: 4, 178 | end: 7, 179 | loc: { 180 | start: { line: 1, column: 4, index: 4 }, 181 | end: { line: 1, column: 7, index: 7 } 182 | }, 183 | name: 'foo' 184 | }, 185 | init: { 186 | type: 'Literal', 187 | start: 10, 188 | end: 11, 189 | loc: { 190 | start: { line: 1, column: 10, index: 10 }, 191 | end: { line: 1, column: 11, index: 11 } 192 | }, 193 | value: 8, 194 | raw: '8' 195 | } 196 | } 197 | ], 198 | kind: 'var' 199 | }, 200 | { 201 | type: 'ExportNamedDeclaration', 202 | start: 13, 203 | end: 34, 204 | loc: { 205 | start: { line: 2, column: 0, index: 13 }, 206 | end: { line: 2, column: 21, index: 34 } 207 | }, 208 | exportKind: 'value', 209 | declaration: null, 210 | specifiers: [ 211 | { 212 | type: 'ExportSpecifier', 213 | start: 22, 214 | end: 31, 215 | loc: { 216 | start: { line: 2, column: 9, index: 22 }, 217 | end: { line: 2, column: 18, index: 31 } 218 | }, 219 | local: { 220 | type: 'Identifier', 221 | start: 22, 222 | end: 25, 223 | loc: { 224 | start: { line: 2, column: 9, index: 22 }, 225 | end: { line: 2, column: 12, index: 25 } 226 | }, 227 | name: 'foo' 228 | }, 229 | exportKind: 'value', 230 | exported: { 231 | type: 'Identifier', 232 | start: 29, 233 | end: 31, 234 | loc: { 235 | start: { line: 2, column: 16, index: 29 }, 236 | end: { line: 2, column: 18, index: 31 } 237 | }, 238 | name: 'as' 239 | } 240 | } 241 | ], 242 | source: null 243 | } 244 | ], 245 | sourceType: 'module' 246 | }, 247 | ImportIdentifierAs: { 248 | type: 'Program', 249 | start: 0, 250 | end: 36, 251 | loc: { 252 | start: { line: 1, column: 0, index: 0 }, 253 | end: { line: 1, column: 36, index: 36 } 254 | }, 255 | body: [ 256 | { 257 | type: 'ImportDeclaration', 258 | start: 0, 259 | end: 36, 260 | loc: { 261 | start: { line: 1, column: 0, index: 0 }, 262 | end: { line: 1, column: 36, index: 36 } 263 | }, 264 | importKind: 'value', 265 | specifiers: [ 266 | { 267 | type: 'ImportSpecifier', 268 | start: 9, 269 | end: 17, 270 | loc: { 271 | start: { line: 1, column: 9, index: 9 }, 272 | end: { line: 1, column: 17, index: 17 } 273 | }, 274 | imported: { 275 | type: 'Identifier', 276 | start: 9, 277 | end: 11, 278 | loc: { 279 | start: { line: 1, column: 9, index: 9 }, 280 | end: { line: 1, column: 11, index: 11 } 281 | }, 282 | name: 'as' 283 | }, 284 | importKind: 'value', 285 | local: { 286 | type: 'Identifier', 287 | start: 15, 288 | end: 17, 289 | loc: { 290 | start: { line: 1, column: 15, index: 15 }, 291 | end: { line: 1, column: 17, index: 17 } 292 | }, 293 | name: 'as' 294 | } 295 | } 296 | ], 297 | source: { 298 | type: 'Literal', 299 | start: 25, 300 | end: 35, 301 | loc: { 302 | start: { line: 1, column: 25, index: 25 }, 303 | end: { line: 1, column: 35, index: 35 } 304 | }, 305 | value: './foo.js', 306 | raw: '\'./foo.js\'' 307 | } 308 | } 309 | ], 310 | sourceType: 'module' 311 | } 312 | } 313 | 314 | export default NormalIdentifierSnapshot 315 | -------------------------------------------------------------------------------- /__test__/__snapshot__/import/type.ts: -------------------------------------------------------------------------------- 1 | const ImportTypeSnapshot = { 2 | ImportDefaultType: { 3 | 'type': 'Program', 4 | 'start': 0, 5 | 'end': 34, 6 | 'loc': { 7 | 'start': { 8 | 'line': 1, 9 | 'column': 0, 10 | 'index': 0 11 | }, 12 | 'end': { 13 | 'line': 1, 14 | 'column': 34, 15 | 'index': 34 16 | } 17 | }, 18 | 'body': [ 19 | { 20 | 'type': 'ImportDeclaration', 21 | 'start': 0, 22 | 'end': 34, 23 | 'loc': { 24 | 'start': { 25 | 'line': 1, 26 | 'column': 0, 27 | 'index': 0 28 | }, 29 | 'end': { 30 | 'line': 1, 31 | 'column': 34, 32 | 'index': 34 33 | } 34 | }, 35 | 'importKind': 'type', 36 | 'specifiers': [ 37 | { 38 | 'type': 'ImportDefaultSpecifier', 39 | 'start': 12, 40 | 'end': 16, 41 | 'loc': { 42 | 'start': { 43 | 'line': 1, 44 | 'column': 12, 45 | 'index': 12 46 | }, 47 | 'end': { 48 | 'line': 1, 49 | 'column': 16, 50 | 'index': 16 51 | } 52 | }, 53 | 'local': { 54 | 'type': 'Identifier', 55 | 'start': 12, 56 | 'end': 16, 57 | 'loc': { 58 | 'start': { 59 | 'line': 1, 60 | 'column': 12, 61 | 'index': 12 62 | }, 63 | 'end': { 64 | 'line': 1, 65 | 'column': 16, 66 | 'index': 16 67 | } 68 | }, 69 | 'name': 'Test' 70 | } 71 | } 72 | ], 73 | 'source': { 74 | 'type': 'Literal', 75 | 'start': 22, 76 | 'end': 34, 77 | 'loc': { 78 | 'start': { 79 | 'line': 1, 80 | 'column': 22, 81 | 'index': 22 82 | }, 83 | 'end': { 84 | 'line': 1, 85 | 'column': 34, 86 | 'index': 34 87 | } 88 | }, 89 | 'value': './index.ts', 90 | 'raw': '\'./index.ts\'' 91 | } 92 | } 93 | ], 94 | 'sourceType': 'module' 95 | }, 96 | ImportNameAsType: { 97 | 'type': 'Program', 98 | 'start': 0, 99 | 'end': 47, 100 | 'loc': { 101 | 'start': { 102 | 'line': 1, 103 | 'column': 0, 104 | 'index': 0 105 | }, 106 | 'end': { 107 | 'line': 1, 108 | 'column': 47, 109 | 'index': 47 110 | } 111 | }, 112 | 'body': [ 113 | { 114 | 'type': 'ImportDeclaration', 115 | 'start': 0, 116 | 'end': 47, 117 | 'loc': { 118 | 'start': { 119 | 'line': 1, 120 | 'column': 0, 121 | 'index': 0 122 | }, 123 | 'end': { 124 | 'line': 1, 125 | 'column': 47, 126 | 'index': 47 127 | } 128 | }, 129 | 'importKind': 'type', 130 | 'specifiers': [ 131 | { 132 | 'type': 'ImportSpecifier', 133 | 'start': 14, 134 | 'end': 27, 135 | 'loc': { 136 | 'start': { 137 | 'line': 1, 138 | 'column': 14, 139 | 'index': 14 140 | }, 141 | 'end': { 142 | 'line': 1, 143 | 'column': 27, 144 | 'index': 27 145 | } 146 | }, 147 | 'imported': { 148 | 'type': 'Identifier', 149 | 'start': 14, 150 | 'end': 18, 151 | 'loc': { 152 | 'start': { 153 | 'line': 1, 154 | 'column': 14, 155 | 'index': 14 156 | }, 157 | 'end': { 158 | 'line': 1, 159 | 'column': 18, 160 | 'index': 18 161 | } 162 | }, 163 | 'name': 'Test' 164 | }, 165 | 'importKind': 'value', 166 | 'local': { 167 | 'type': 'Identifier', 168 | 'start': 22, 169 | 'end': 27, 170 | 'loc': { 171 | 'start': { 172 | 'line': 1, 173 | 'column': 22, 174 | 'index': 22 175 | }, 176 | 'end': { 177 | 'line': 1, 178 | 'column': 27, 179 | 'index': 27 180 | } 181 | }, 182 | 'name': 'Test1' 183 | } 184 | } 185 | ], 186 | 'source': { 187 | 'type': 'Literal', 188 | 'start': 35, 189 | 'end': 47, 190 | 'loc': { 191 | 'start': { 192 | 'line': 1, 193 | 'column': 35, 194 | 'index': 35 195 | }, 196 | 'end': { 197 | 'line': 1, 198 | 'column': 47, 199 | 'index': 47 200 | } 201 | }, 202 | 'value': './index.ts', 203 | 'raw': '\'./index.ts\'' 204 | } 205 | } 206 | ], 207 | 'sourceType': 'module' 208 | }, 209 | ImportNamespaceType: { 210 | 'type': 'Program', 211 | 'start': 0, 212 | 'end': 39, 213 | 'loc': { 214 | 'start': { 215 | 'line': 1, 216 | 'column': 0, 217 | 'index': 0 218 | }, 219 | 'end': { 220 | 'line': 1, 221 | 'column': 39, 222 | 'index': 39 223 | } 224 | }, 225 | 'body': [ 226 | { 227 | 'type': 'ImportDeclaration', 228 | 'start': 0, 229 | 'end': 39, 230 | 'loc': { 231 | 'start': { 232 | 'line': 1, 233 | 'column': 0, 234 | 'index': 0 235 | }, 236 | 'end': { 237 | 'line': 1, 238 | 'column': 39, 239 | 'index': 39 240 | } 241 | }, 242 | 'importKind': 'type', 243 | 'specifiers': [ 244 | { 245 | 'type': 'ImportNamespaceSpecifier', 246 | 'start': 12, 247 | 'end': 21, 248 | 'loc': { 249 | 'start': { 250 | 'line': 1, 251 | 'column': 12, 252 | 'index': 12 253 | }, 254 | 'end': { 255 | 'line': 1, 256 | 'column': 21, 257 | 'index': 21 258 | } 259 | }, 260 | 'local': { 261 | 'type': 'Identifier', 262 | 'start': 17, 263 | 'end': 21, 264 | 'loc': { 265 | 'start': { 266 | 'line': 1, 267 | 'column': 17, 268 | 'index': 17 269 | }, 270 | 'end': { 271 | 'line': 1, 272 | 'column': 21, 273 | 'index': 21 274 | } 275 | }, 276 | 'name': 'Test' 277 | } 278 | } 279 | ], 280 | 'source': { 281 | 'type': 'Literal', 282 | 'start': 27, 283 | 'end': 39, 284 | 'loc': { 285 | 'start': { 286 | 'line': 1, 287 | 'column': 27, 288 | 'index': 27 289 | }, 290 | 'end': { 291 | 'line': 1, 292 | 'column': 39, 293 | 'index': 39 294 | } 295 | }, 296 | 'value': './index.ts', 297 | 'raw': '\'./index.ts\'' 298 | } 299 | } 300 | ], 301 | 'sourceType': 'module' 302 | }, 303 | ImportComplexType: { 304 | 'type': 'Program', 305 | 'start': 0, 306 | 'end': 147, 307 | 'loc': { 308 | 'start': { 309 | 'line': 1, 310 | 'column': 0, 311 | 'index': 0 312 | }, 313 | 'end': { 314 | 'line': 4, 315 | 'column': 41, 316 | 'index': 147 317 | } 318 | }, 319 | 'body': [ 320 | { 321 | 'type': 'ImportDeclaration', 322 | 'start': 0, 323 | 'end': 19, 324 | 'loc': { 325 | 'start': { 326 | 'line': 1, 327 | 'column': 0, 328 | 'index': 0 329 | }, 330 | 'end': { 331 | 'line': 1, 332 | 'column': 19, 333 | 'index': 19 334 | } 335 | }, 336 | 'importKind': 'value', 337 | 'specifiers': [], 338 | 'source': { 339 | 'type': 'Literal', 340 | 'start': 7, 341 | 'end': 19, 342 | 'loc': { 343 | 'start': { 344 | 'line': 1, 345 | 'column': 7, 346 | 'index': 7 347 | }, 348 | 'end': { 349 | 'line': 1, 350 | 'column': 19, 351 | 'index': 19 352 | } 353 | }, 354 | 'value': './index.ts', 355 | 'raw': '\'./index.ts\'' 356 | } 357 | }, 358 | { 359 | 'type': 'ImportDeclaration', 360 | 'start': 20, 361 | 'end': 56, 362 | 'loc': { 363 | 'start': { 364 | 'line': 2, 365 | 'column': 0, 366 | 'index': 20 367 | }, 368 | 'end': { 369 | 'line': 2, 370 | 'column': 36, 371 | 'index': 56 372 | } 373 | }, 374 | 'importKind': 'type', 375 | 'specifiers': [ 376 | { 377 | 'type': 'ImportDefaultSpecifier', 378 | 'start': 32, 379 | 'end': 37, 380 | 'loc': { 381 | 'start': { 382 | 'line': 2, 383 | 'column': 12, 384 | 'index': 32 385 | }, 386 | 'end': { 387 | 'line': 2, 388 | 'column': 17, 389 | 'index': 37 390 | } 391 | }, 392 | 'local': { 393 | 'type': 'Identifier', 394 | 'start': 32, 395 | 'end': 37, 396 | 'loc': { 397 | 'start': { 398 | 'line': 2, 399 | 'column': 12, 400 | 'index': 32 401 | }, 402 | 'end': { 403 | 'line': 2, 404 | 'column': 17, 405 | 'index': 37 406 | } 407 | }, 408 | 'name': 'Test1' 409 | } 410 | } 411 | ], 412 | 'source': { 413 | 'type': 'Literal', 414 | 'start': 43, 415 | 'end': 56, 416 | 'loc': { 417 | 'start': { 418 | 'line': 2, 419 | 'column': 23, 420 | 'index': 43 421 | }, 422 | 'end': { 423 | 'line': 2, 424 | 'column': 36, 425 | 'index': 56 426 | } 427 | }, 428 | 'value': './index1.ts', 429 | 'raw': '\'./index1.ts\'' 430 | } 431 | }, 432 | { 433 | 'type': 'ImportDeclaration', 434 | 'start': 57, 435 | 'end': 105, 436 | 'loc': { 437 | 'start': { 438 | 'line': 3, 439 | 'column': 0, 440 | 'index': 57 441 | }, 442 | 'end': { 443 | 'line': 3, 444 | 'column': 48, 445 | 'index': 105 446 | } 447 | }, 448 | 'importKind': 'type', 449 | 'specifiers': [ 450 | { 451 | 'type': 'ImportSpecifier', 452 | 'start': 71, 453 | 'end': 84, 454 | 'loc': { 455 | 'start': { 456 | 'line': 3, 457 | 'column': 14, 458 | 'index': 71 459 | }, 460 | 'end': { 461 | 'line': 3, 462 | 'column': 27, 463 | 'index': 84 464 | } 465 | }, 466 | 'imported': { 467 | 'type': 'Identifier', 468 | 'start': 71, 469 | 'end': 75, 470 | 'loc': { 471 | 'start': { 472 | 'line': 3, 473 | 'column': 14, 474 | 'index': 71 475 | }, 476 | 'end': { 477 | 'line': 3, 478 | 'column': 18, 479 | 'index': 75 480 | } 481 | }, 482 | 'name': 'Test' 483 | }, 484 | 'importKind': 'value', 485 | 'local': { 486 | 'type': 'Identifier', 487 | 'start': 79, 488 | 'end': 84, 489 | 'loc': { 490 | 'start': { 491 | 'line': 3, 492 | 'column': 22, 493 | 'index': 79 494 | }, 495 | 'end': { 496 | 'line': 3, 497 | 'column': 27, 498 | 'index': 84 499 | } 500 | }, 501 | 'name': 'Test2' 502 | } 503 | } 504 | ], 505 | 'source': { 506 | 'type': 'Literal', 507 | 'start': 92, 508 | 'end': 105, 509 | 'loc': { 510 | 'start': { 511 | 'line': 3, 512 | 'column': 35, 513 | 'index': 92 514 | }, 515 | 'end': { 516 | 'line': 3, 517 | 'column': 48, 518 | 'index': 105 519 | } 520 | }, 521 | 'value': './index2.ts', 522 | 'raw': '\'./index2.ts\'' 523 | } 524 | }, 525 | { 526 | 'type': 'ImportDeclaration', 527 | 'start': 106, 528 | 'end': 147, 529 | 'loc': { 530 | 'start': { 531 | 'line': 4, 532 | 'column': 0, 533 | 'index': 106 534 | }, 535 | 'end': { 536 | 'line': 4, 537 | 'column': 41, 538 | 'index': 147 539 | } 540 | }, 541 | 'importKind': 'type', 542 | 'specifiers': [ 543 | { 544 | 'type': 'ImportNamespaceSpecifier', 545 | 'start': 118, 546 | 'end': 128, 547 | 'loc': { 548 | 'start': { 549 | 'line': 4, 550 | 'column': 12, 551 | 'index': 118 552 | }, 553 | 'end': { 554 | 'line': 4, 555 | 'column': 22, 556 | 'index': 128 557 | } 558 | }, 559 | 'local': { 560 | 'type': 'Identifier', 561 | 'start': 123, 562 | 'end': 128, 563 | 'loc': { 564 | 'start': { 565 | 'line': 4, 566 | 'column': 17, 567 | 'index': 123 568 | }, 569 | 'end': { 570 | 'line': 4, 571 | 'column': 22, 572 | 'index': 128 573 | } 574 | }, 575 | 'name': 'Test3' 576 | } 577 | } 578 | ], 579 | 'source': { 580 | 'type': 'Literal', 581 | 'start': 134, 582 | 'end': 147, 583 | 'loc': { 584 | 'start': { 585 | 'line': 4, 586 | 'column': 28, 587 | 'index': 134 588 | }, 589 | 'end': { 590 | 'line': 4, 591 | 'column': 41, 592 | 'index': 147 593 | } 594 | }, 595 | 'value': './index3.ts', 596 | 'raw': '\'./index3.ts\'' 597 | } 598 | } 599 | ], 600 | 'sourceType': 'module' 601 | } 602 | } 603 | 604 | export default ImportTypeSnapshot 605 | -------------------------------------------------------------------------------- /__test__/__snapshot__/satisfies/index.ts: -------------------------------------------------------------------------------- 1 | const SatisfiesSnapshot = { 2 | Normal: { 3 | 'type': 'Program', 4 | 'start': 0, 5 | 'end': 25, 6 | 'loc': { 7 | 'start': { 8 | 'line': 1, 9 | 'column': 0, 10 | 'index': 0 11 | }, 12 | 'end': { 13 | 'line': 1, 14 | 'column': 25, 15 | 'index': 25 16 | } 17 | }, 18 | 'body': [ 19 | { 20 | 'type': 'VariableDeclaration', 21 | 'start': 0, 22 | 'end': 25, 23 | 'loc': { 24 | 'start': { 25 | 'line': 1, 26 | 'column': 0, 27 | 'index': 0 28 | }, 29 | 'end': { 30 | 'line': 1, 31 | 'column': 25, 32 | 'index': 25 33 | } 34 | }, 35 | 'declarations': [ 36 | { 37 | 'type': 'VariableDeclarator', 38 | 'start': 6, 39 | 'end': 25, 40 | 'loc': { 41 | 'start': { 42 | 'line': 1, 43 | 'column': 6, 44 | 'index': 6 45 | }, 46 | 'end': { 47 | 'line': 1, 48 | 'column': 25, 49 | 'index': 25 50 | } 51 | }, 52 | 'id': { 53 | 'type': 'Identifier', 54 | 'start': 6, 55 | 'end': 7, 56 | 'loc': { 57 | 'start': { 58 | 'line': 1, 59 | 'column': 6, 60 | 'index': 6 61 | }, 62 | 'end': { 63 | 'line': 1, 64 | 'column': 7, 65 | 'index': 7 66 | } 67 | }, 68 | 'name': 'a' 69 | }, 70 | 'init': { 71 | 'type': 'TSSatisfiesExpression', 72 | 'start': 10, 73 | 'end': 25, 74 | 'loc': { 75 | 'start': { 76 | 'line': 1, 77 | 'column': 10, 78 | 'index': 10 79 | }, 80 | 'end': { 81 | 'line': 1, 82 | 'column': 25, 83 | 'index': 25 84 | } 85 | }, 86 | 'expression': { 87 | 'type': 'Literal', 88 | 'start': 10, 89 | 'end': 11, 90 | 'loc': { 91 | 'start': { 92 | 'line': 1, 93 | 'column': 10, 94 | 'index': 10 95 | }, 96 | 'end': { 97 | 'line': 1, 98 | 'column': 11, 99 | 'index': 11 100 | } 101 | }, 102 | 'value': 1, 103 | 'raw': '1' 104 | }, 105 | 'typeAnnotation': { 106 | 'type': 'TSAnyKeyword', 107 | 'start': 22, 108 | 'end': 25, 109 | 'loc': { 110 | 'start': { 111 | 'line': 1, 112 | 'column': 22, 113 | 'index': 22 114 | }, 115 | 'end': { 116 | 'line': 1, 117 | 'column': 25, 118 | 'index': 25 119 | } 120 | } 121 | } 122 | } 123 | } 124 | ], 125 | 'kind': 'const' 126 | } 127 | ], 128 | 'sourceType': 'module' 129 | } 130 | } 131 | 132 | export default SatisfiesSnapshot 133 | -------------------------------------------------------------------------------- /__test__/__snapshot__/try/index.ts: -------------------------------------------------------------------------------- 1 | const TryTypeSnapshot = { 2 | Normal: { 3 | 'type': 'Program', 4 | 'start': 0, 5 | 'end': 38, 6 | 'loc': { 7 | 'start': { 8 | 'line': 1, 9 | 'column': 0, 10 | 'index': 0 11 | }, 12 | 'end': { 13 | 'line': 3, 14 | 'column': 13, 15 | 'index': 38 16 | } 17 | }, 18 | 'body': [ 19 | { 20 | 'type': 'TryStatement', 21 | 'start': 0, 22 | 'end': 38, 23 | 'loc': { 24 | 'start': { 25 | 'line': 1, 26 | 'column': 0, 27 | 'index': 0 28 | }, 29 | 'end': { 30 | 'line': 3, 31 | 'column': 13, 32 | 'index': 38 33 | } 34 | }, 35 | 'block': { 36 | 'type': 'BlockStatement', 37 | 'start': 4, 38 | 'end': 26, 39 | 'loc': { 40 | 'start': { 41 | 'line': 1, 42 | 'column': 4, 43 | 'index': 4 44 | }, 45 | 'end': { 46 | 'line': 3, 47 | 'column': 1, 48 | 'index': 26 49 | } 50 | }, 51 | 'body': [ 52 | { 53 | 'type': 'ExpressionStatement', 54 | 'start': 8, 55 | 'end': 24, 56 | 'loc': { 57 | 'start': { 58 | 'line': 2, 59 | 'column': 2, 60 | 'index': 8 61 | }, 62 | 'end': { 63 | 'line': 2, 64 | 'column': 18, 65 | 'index': 24 66 | } 67 | }, 68 | 'expression': { 69 | 'type': 'CallExpression', 70 | 'start': 8, 71 | 'end': 24, 72 | 'loc': { 73 | 'start': { 74 | 'line': 2, 75 | 'column': 2, 76 | 'index': 8 77 | }, 78 | 'end': { 79 | 'line': 2, 80 | 'column': 18, 81 | 'index': 24 82 | } 83 | }, 84 | 'callee': { 85 | 'type': 'MemberExpression', 86 | 'start': 8, 87 | 'end': 19, 88 | 'loc': { 89 | 'start': { 90 | 'line': 2, 91 | 'column': 2, 92 | 'index': 8 93 | }, 94 | 'end': { 95 | 'line': 2, 96 | 'column': 13, 97 | 'index': 19 98 | } 99 | }, 100 | 'object': { 101 | 'type': 'Identifier', 102 | 'start': 8, 103 | 'end': 15, 104 | 'loc': { 105 | 'start': { 106 | 'line': 2, 107 | 'column': 2, 108 | 'index': 8 109 | }, 110 | 'end': { 111 | 'line': 2, 112 | 'column': 9, 113 | 'index': 15 114 | } 115 | }, 116 | 'name': 'console' 117 | }, 118 | 'property': { 119 | 'type': 'Identifier', 120 | 'start': 16, 121 | 'end': 19, 122 | 'loc': { 123 | 'start': { 124 | 'line': 2, 125 | 'column': 10, 126 | 'index': 16 127 | }, 128 | 'end': { 129 | 'line': 2, 130 | 'column': 13, 131 | 'index': 19 132 | } 133 | }, 134 | 'name': 'log' 135 | }, 136 | 'computed': false, 137 | 'optional': false 138 | }, 139 | 'arguments': [ 140 | { 141 | 'type': 'Literal', 142 | 'start': 20, 143 | 'end': 23, 144 | 'loc': { 145 | 'start': { 146 | 'line': 2, 147 | 'column': 14, 148 | 'index': 20 149 | }, 150 | 'end': { 151 | 'line': 2, 152 | 'column': 17, 153 | 'index': 23 154 | } 155 | }, 156 | 'value': 123, 157 | 'raw': '123' 158 | } 159 | ], 160 | 'optional': false 161 | } 162 | } 163 | ] 164 | }, 165 | 'handler': { 166 | 'type': 'CatchClause', 167 | 'start': 27, 168 | 'end': 38, 169 | 'loc': { 170 | 'start': { 171 | 'line': 3, 172 | 'column': 2, 173 | 'index': 27 174 | }, 175 | 'end': { 176 | 'line': 3, 177 | 'column': 13, 178 | 'index': 38 179 | } 180 | }, 181 | 'param': { 182 | 'type': 'Identifier', 183 | 'start': 33, 184 | 'end': 34, 185 | 'loc': { 186 | 'start': { 187 | 'line': 3, 188 | 'column': 8, 189 | 'index': 33 190 | }, 191 | 'end': { 192 | 'line': 3, 193 | 'column': 9, 194 | 'index': 34 195 | } 196 | }, 197 | 'name': 'e' 198 | }, 199 | 'body': { 200 | 'type': 'BlockStatement', 201 | 'start': 36, 202 | 'end': 38, 203 | 'loc': { 204 | 'start': { 205 | 'line': 3, 206 | 'column': 11, 207 | 'index': 36 208 | }, 209 | 'end': { 210 | 'line': 3, 211 | 'column': 13, 212 | 'index': 38 213 | } 214 | }, 215 | 'body': [] 216 | } 217 | }, 218 | 'finalizer': null 219 | } 220 | ], 221 | 'sourceType': 'module' 222 | }, 223 | WithType: { 224 | 'type': 'Program', 225 | 'start': 0, 226 | 'end': 43, 227 | 'loc': { 228 | 'start': { 229 | 'line': 1, 230 | 'column': 0, 231 | 'index': 0 232 | }, 233 | 'end': { 234 | 'line': 3, 235 | 'column': 18, 236 | 'index': 43 237 | } 238 | }, 239 | 'body': [ 240 | { 241 | 'type': 'TryStatement', 242 | 'start': 0, 243 | 'end': 43, 244 | 'loc': { 245 | 'start': { 246 | 'line': 1, 247 | 'column': 0, 248 | 'index': 0 249 | }, 250 | 'end': { 251 | 'line': 3, 252 | 'column': 18, 253 | 'index': 43 254 | } 255 | }, 256 | 'block': { 257 | 'type': 'BlockStatement', 258 | 'start': 4, 259 | 'end': 26, 260 | 'loc': { 261 | 'start': { 262 | 'line': 1, 263 | 'column': 4, 264 | 'index': 4 265 | }, 266 | 'end': { 267 | 'line': 3, 268 | 'column': 1, 269 | 'index': 26 270 | } 271 | }, 272 | 'body': [ 273 | { 274 | 'type': 'ExpressionStatement', 275 | 'start': 8, 276 | 'end': 24, 277 | 'loc': { 278 | 'start': { 279 | 'line': 2, 280 | 'column': 2, 281 | 'index': 8 282 | }, 283 | 'end': { 284 | 'line': 2, 285 | 'column': 18, 286 | 'index': 24 287 | } 288 | }, 289 | 'expression': { 290 | 'type': 'CallExpression', 291 | 'start': 8, 292 | 'end': 24, 293 | 'loc': { 294 | 'start': { 295 | 'line': 2, 296 | 'column': 2, 297 | 'index': 8 298 | }, 299 | 'end': { 300 | 'line': 2, 301 | 'column': 18, 302 | 'index': 24 303 | } 304 | }, 305 | 'callee': { 306 | 'type': 'MemberExpression', 307 | 'start': 8, 308 | 'end': 19, 309 | 'loc': { 310 | 'start': { 311 | 'line': 2, 312 | 'column': 2, 313 | 'index': 8 314 | }, 315 | 'end': { 316 | 'line': 2, 317 | 'column': 13, 318 | 'index': 19 319 | } 320 | }, 321 | 'object': { 322 | 'type': 'Identifier', 323 | 'start': 8, 324 | 'end': 15, 325 | 'loc': { 326 | 'start': { 327 | 'line': 2, 328 | 'column': 2, 329 | 'index': 8 330 | }, 331 | 'end': { 332 | 'line': 2, 333 | 'column': 9, 334 | 'index': 15 335 | } 336 | }, 337 | 'name': 'console' 338 | }, 339 | 'property': { 340 | 'type': 'Identifier', 341 | 'start': 16, 342 | 'end': 19, 343 | 'loc': { 344 | 'start': { 345 | 'line': 2, 346 | 'column': 10, 347 | 'index': 16 348 | }, 349 | 'end': { 350 | 'line': 2, 351 | 'column': 13, 352 | 'index': 19 353 | } 354 | }, 355 | 'name': 'log' 356 | }, 357 | 'computed': false, 358 | 'optional': false 359 | }, 360 | 'arguments': [ 361 | { 362 | 'type': 'Literal', 363 | 'start': 20, 364 | 'end': 23, 365 | 'loc': { 366 | 'start': { 367 | 'line': 2, 368 | 'column': 14, 369 | 'index': 20 370 | }, 371 | 'end': { 372 | 'line': 2, 373 | 'column': 17, 374 | 'index': 23 375 | } 376 | }, 377 | 'value': 123, 378 | 'raw': '123' 379 | } 380 | ], 381 | 'optional': false 382 | } 383 | } 384 | ] 385 | }, 386 | 'handler': { 387 | 'type': 'CatchClause', 388 | 'start': 27, 389 | 'end': 43, 390 | 'loc': { 391 | 'start': { 392 | 'line': 3, 393 | 'column': 2, 394 | 'index': 27 395 | }, 396 | 'end': { 397 | 'line': 3, 398 | 'column': 18, 399 | 'index': 43 400 | } 401 | }, 402 | 'param': { 403 | 'type': 'Identifier', 404 | 'start': 33, 405 | 'end': 14, 406 | 'loc': { 407 | 'start': { 408 | 'line': 3, 409 | 'column': 8, 410 | 'index': 33 411 | }, 412 | 'end': { 413 | 'line': 3, 414 | 'column': 14, 415 | 'index': 39 416 | } 417 | }, 418 | 'name': 'e', 419 | 'typeAnnotation': { 420 | 'type': 'TSTypeAnnotation', 421 | 'start': 34, 422 | 'end': 39, 423 | 'loc': { 424 | 'start': { 425 | 'line': 3, 426 | 'column': 9, 427 | 'index': 34 428 | }, 429 | 'end': { 430 | 'line': 3, 431 | 'column': 14, 432 | 'index': 39 433 | } 434 | }, 435 | 'typeAnnotation': { 436 | 'type': 'TSAnyKeyword', 437 | 'start': 36, 438 | 'end': 39, 439 | 'loc': { 440 | 'start': { 441 | 'line': 3, 442 | 'column': 11, 443 | 'index': 36 444 | }, 445 | 'end': { 446 | 'line': 3, 447 | 'column': 14, 448 | 'index': 39 449 | } 450 | } 451 | } 452 | } 453 | }, 454 | 'body': { 455 | 'type': 'BlockStatement', 456 | 'start': 41, 457 | 'end': 43, 458 | 'loc': { 459 | 'start': { 460 | 'line': 3, 461 | 'column': 16, 462 | 'index': 41 463 | }, 464 | 'end': { 465 | 'line': 3, 466 | 'column': 18, 467 | 'index': 43 468 | } 469 | }, 470 | 'body': [] 471 | } 472 | }, 473 | 'finalizer': null 474 | } 475 | ], 476 | 'sourceType': 'module' 477 | }, 478 | CatchRedeclaredVarStatementCaptured: { 479 | type: "Program", 480 | start: 0, 481 | end: 80, 482 | loc: { 483 | start: { line: 1, column: 0, index: 0 }, 484 | end: { line: 5, column: 1, index: 80 }, 485 | }, 486 | body: [ 487 | { 488 | type: "TryStatement", 489 | start: 0, 490 | end: 80, 491 | loc: { 492 | start: { line: 1, column: 0, index: 0 }, 493 | end: { line: 5, column: 1, index: 80 }, 494 | }, 495 | block: { 496 | type: "BlockStatement", 497 | start: 4, 498 | end: 28, 499 | loc: { 500 | start: { line: 1, column: 4, index: 4 }, 501 | end: { line: 3, column: 1, index: 28 }, 502 | }, 503 | body: [ 504 | { 505 | type: "ThrowStatement", 506 | start: 8, 507 | end: 26, 508 | loc: { 509 | start: { line: 2, column: 2, index: 8 }, 510 | end: { line: 2, column: 20, index: 26 }, 511 | }, 512 | argument: { 513 | type: "NewExpression", 514 | start: 14, 515 | end: 25, 516 | loc: { 517 | start: { line: 2, column: 8, index: 14 }, 518 | end: { line: 2, column: 19, index: 25 }, 519 | }, 520 | callee: { 521 | type: "Identifier", 522 | start: 18, 523 | end: 23, 524 | loc: { 525 | start: { line: 2, column: 12, index: 18 }, 526 | end: { line: 2, column: 17, index: 23 }, 527 | }, 528 | name: "Error", 529 | }, 530 | arguments: [], 531 | }, 532 | }, 533 | ], 534 | }, 535 | handler: { 536 | type: "CatchClause", 537 | start: 29, 538 | end: 80, 539 | loc: { 540 | start: { line: 3, column: 2, index: 29 }, 541 | end: { line: 5, column: 1, index: 80 }, 542 | }, 543 | param: { 544 | type: "Identifier", 545 | start: 36, 546 | end: 39, 547 | loc: { 548 | start: { line: 3, column: 9, index: 36 }, 549 | end: { line: 3, column: 12, index: 39 }, 550 | }, 551 | name: "foo", 552 | }, 553 | body: { 554 | type: "BlockStatement", 555 | start: 41, 556 | end: 80, 557 | loc: { 558 | start: { line: 3, column: 14, index: 41 }, 559 | end: { line: 5, column: 1, index: 80 }, 560 | }, 561 | body: [ 562 | { 563 | type: "VariableDeclaration", 564 | start: 45, 565 | end: 78, 566 | loc: { 567 | start: { line: 4, column: 2, index: 45 }, 568 | end: { line: 4, column: 35, index: 78 }, 569 | }, 570 | declarations: [ 571 | { 572 | type: "VariableDeclarator", 573 | start: 49, 574 | end: 77, 575 | loc: { 576 | start: { line: 4, column: 6, index: 49 }, 577 | end: { line: 4, column: 34, index: 77 }, 578 | }, 579 | id: { 580 | type: "Identifier", 581 | start: 49, 582 | end: 52, 583 | loc: { 584 | start: { line: 4, column: 6, index: 49 }, 585 | end: { line: 4, column: 9, index: 52 }, 586 | }, 587 | name: "foo", 588 | }, 589 | init: { 590 | type: "Literal", 591 | start: 55, 592 | end: 77, 593 | loc: { 594 | start: { line: 4, column: 12, index: 55 }, 595 | end: { line: 4, column: 34, index: 77 }, 596 | }, 597 | value: "initializer in catch", 598 | raw: '"initializer in catch"', 599 | }, 600 | }, 601 | ], 602 | kind: "var", 603 | }, 604 | ], 605 | }, 606 | }, 607 | finalizer: null, 608 | }, 609 | ], 610 | sourceType: "module", 611 | } 612 | } 613 | 614 | export default TryTypeSnapshot 615 | -------------------------------------------------------------------------------- /__test__/api/parseExpressionAt.test.ts: -------------------------------------------------------------------------------- 1 | import { generateSource, Parser } from '../utils' 2 | 3 | function parseExpressionAt(input: string, pos: number) { 4 | return Parser.parseExpressionAt(input, pos, { 5 | sourceType: 'module', 6 | ecmaVersion: 'latest', 7 | locations: true 8 | }) 9 | } 10 | 11 | describe('parseExpressionAt API', function() { 12 | it('normal', function() { 13 | const node = parseExpressionAt(generateSource([ 14 | ` {}`, 16 | `} />` 17 | ]), 14) 18 | 19 | expect(node.type).toEqual('ArrowFunctionExpression') 20 | }) 21 | }) 22 | 23 | -------------------------------------------------------------------------------- /__test__/arrow-function/type.test.ts: -------------------------------------------------------------------------------- 1 | import { equalNode, generateSource, parseSource } from '../utils' 2 | import ArrowFunctionTypeSnapshot from '../__snapshot__/arrow-function/type' 3 | 4 | const issue38File = ` 5 | let defaultHashSize = 0 6 | export const getHashPlaceholderGenerator = (): any => { 7 | let nextIndex = 0; 8 | return (optionName: string, hashSize: number = defaultHashSize) => {} 9 | } 10 | ` 11 | 12 | const issue39File = `export const getPureFunctions = ({ treeshake }: NormalizedInputOptions): PureFunctions => {};` 13 | 14 | describe('arrow-function type test', () => { 15 | it('assignment pattern', () => { 16 | const node = parseSource(generateSource([ 17 | `(x = 42): void => {}` 18 | ])) 19 | 20 | equalNode(node, ArrowFunctionTypeSnapshot.AssignmentPattern) 21 | }) 22 | 23 | it('issue 32', () => { 24 | const node = parseSource(generateSource([ 25 | `const testApp = async(app: string, index: number) => {`, 26 | `};` 27 | ])) 28 | 29 | equalNode(node, ArrowFunctionTypeSnapshot.Issue32) 30 | }) 31 | 32 | it('issue 38', () => { 33 | const node = parseSource(issue38File) 34 | 35 | equalNode(node, ArrowFunctionTypeSnapshot.Issue38) 36 | }) 37 | 38 | it('issue 39', () => { 39 | const node = parseSource(issue39File) 40 | 41 | equalNode(node, ArrowFunctionTypeSnapshot.Issue39) 42 | }) 43 | }) 44 | -------------------------------------------------------------------------------- /__test__/assert/index.test.ts: -------------------------------------------------------------------------------- 1 | import { equalNode, parseSource, parseSourceShouldThrowError } from '../utils' 2 | import AssertionSnapshot from '../__snapshot__/assert' 3 | 4 | describe('assert', () => { 5 | it('import assert', () => { 6 | const node = parseSource(`import json from './foo.json' assert { type: 'json' };`) 7 | 8 | equalNode(node, AssertionSnapshot.ImportAssert) 9 | }) 10 | 11 | it('import with', () => { 12 | const node = parseSource(`import json from './foo.json' with { type: 'json' };`) 13 | 14 | equalNode(node, AssertionSnapshot.ImportWith) 15 | }) 16 | 17 | it('import with duplicate', () => { 18 | const res = parseSourceShouldThrowError( 19 | `import json from './foo.json' with { type: 'json', type: 'json' };`, 20 | 'Duplicated key in attributes', 21 | '(1:63)' 22 | ) 23 | 24 | expect(res).toBe(true) 25 | }) 26 | 27 | it('dynamic import assert', () => { 28 | const node = parseSource(`import("./foo.json", { with: { type: "json" } });`) 29 | 30 | equalNode(node, AssertionSnapshot.DynamicImportAssert) 31 | }) 32 | 33 | it('export all as assert', () => { 34 | const node = parseSource(`export * as name from "./foo.json" with { type: "json" };`) 35 | 36 | equalNode(node, AssertionSnapshot.ExportAllAsAssert) 37 | }) 38 | }) 39 | -------------------------------------------------------------------------------- /__test__/class/type.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | equalNode, 3 | generateSource, 4 | parseSource, 5 | parseSourceShouldThrowError 6 | } from '../utils' 7 | import ClassTypeSnapshot from '../__snapshot__/class/type' 8 | import { TypeScriptError } from '../../src/error' 9 | 10 | const issue33File = ` 11 | export default class Bundle { 12 | private readonly facadeChunkByModule = new Map(); 13 | private readonly includedNamespaces = new Set(); 14 | 15 | constructor( 16 | private readonly outputOptions: NormalizedOutputOptions, 17 | private readonly unsetOptions: ReadonlySet, 18 | private readonly inputOptions: NormalizedInputOptions, 19 | private readonly pluginDriver: PluginDriver, 20 | private readonly graph: Graph 21 | ) {} 22 | } 23 | ` 24 | 25 | const issue34File = ` 26 | export default class Graph { 27 | readonly acornParser: typeof acorn.Parser; 28 | readonly cachedModules = new Map(); 29 | readonly deoptimizationTracker = new PathTracker(); 30 | entryModules: Module[] = []; 31 | readonly fileOperationQueue: Queue; 32 | readonly moduleLoader: ModuleLoader; 33 | readonly modulesById = new Map(); 34 | needsTreeshakingPass = false; 35 | phase: BuildPhase = BuildPhase.LOAD_AND_PARSE; 36 | readonly pluginDriver: PluginDriver; 37 | readonly pureFunctions: PureFunctions; 38 | readonly scope = new GlobalScope(); 39 | readonly watchFiles: Record = Object.create(null); 40 | watchMode = false; 41 | 42 | private readonly externalModules: ExternalModule[] = []; 43 | private implicitEntryModules: Module[] = []; 44 | private modules: Module[] = []; 45 | private declare pluginCache?: Record; 46 | } 47 | ` 48 | 49 | const issue35File = ` 50 | export class PluginDriver { 51 | public readonly emitFile: EmitFile; 52 | public finaliseAssets: () => void; 53 | public getFileName: (fileReferenceId: string) => string; 54 | public readonly setChunkInformation: (facadeChunkByModule: ReadonlyMap) => void; 55 | public readonly setOutputBundle: ( 56 | bundle: OutputBundleWithPlaceholders, 57 | outputOptions: NormalizedOutputOptions 58 | ) => void; 59 | 60 | private readonly fileEmitter: FileEmitter; 61 | private readonly pluginContexts: ReadonlyMap; 62 | private readonly plugins: readonly Plugin[]; 63 | private readonly sortedPlugins = new Map(); 64 | private readonly unfulfilledActions = new Set(); 65 | 66 | hookFirst( 67 | hookName: H, 68 | parameters: Parameters, 69 | replaceContext?: ReplaceContext | null, 70 | skipped?: ReadonlySet | null 71 | ): Promise | null> { 72 | let promise: Promise | null> = Promise.resolve(null); 73 | for (const plugin of this.getSortedPlugins(hookName)) { 74 | if (skipped && skipped.has(plugin)) continue; 75 | promise = promise.then(result => { 76 | if (result != null) return result; 77 | return this.runHook(hookName, parameters, plugin, replaceContext); 78 | }); 79 | } 80 | return promise; 81 | } 82 | } 83 | ` 84 | 85 | const issue36File = ` 86 | const getIdMatcher = >( 87 | option: 88 | | undefined 89 | | boolean 90 | | string 91 | | RegExp 92 | | (string | RegExp)[] 93 | | ((id: string, ...parameters: T) => boolean | null | void) 94 | ): ((id: string, ...parameters: T) => boolean) => { 95 | if (option === true) { 96 | return () => true; 97 | } 98 | if (typeof option === 'function') { 99 | return (id, ...parameters) => (!id.startsWith('\\0') && option(id, ...parameters)) || false; 100 | } 101 | if (option) { 102 | const ids = new Set(); 103 | const matchers: RegExp[] = []; 104 | for (const value of ensureArray(option)) { 105 | if (value instanceof RegExp) { 106 | matchers.push(value); 107 | } else { 108 | ids.add(value); 109 | } 110 | } 111 | return (id: string, ..._arguments) => ids.has(id) || matchers.some(matcher => matcher.test(id)); 112 | } 113 | return () => false; 114 | }; 115 | ` 116 | 117 | // const issue41File = `import json from './foo.json' assert { type: 'json' };` 118 | 119 | const issue42File = ` 120 | export class ObjectEntity extends ExpressionEntity { 121 | constructor( 122 | properties: ObjectProperty[] | PropertyMap, 123 | private prototypeExpression: ExpressionEntity | null, 124 | private immutable = false 125 | ) {} 126 | } 127 | ` 128 | 129 | const issue44File = ` 130 | class Test { 131 | parseNode(esTreeNode: GenericEsTreeNode): void { 132 | const { param } = esTreeNode; 133 | if (param) { 134 | (this.param as GenericEsTreeNode) = new (this.context.getNodeConstructor(param.type))( 135 | param, this,this.scope 136 | ); 137 | this.param!.declare('parameter', UNKNOWN_EXPRESSION); 138 | } 139 | super.parseNode(esTreeNode); 140 | } 141 | } 142 | ` 143 | 144 | describe('class', () => { 145 | it('normal property', () => { 146 | const node = parseSource(generateSource([ 147 | `class Student {`, 148 | ` name: string`, 149 | ` age: number`, 150 | ` school: string`, 151 | ` constructor(name: string, age: number, school: string) {`, 152 | ` this.name = name`, 153 | ` this.age = age`, 154 | ` this.school = school`, 155 | ` }`, 156 | ` study() {`, 157 | ` console.log('Im studying')`, 158 | ` }`, 159 | `}` 160 | ])) 161 | 162 | equalNode(node, ClassTypeSnapshot.NormalProperty) 163 | }) 164 | 165 | it('private property', () => { 166 | const node = parseSource(generateSource([ 167 | `class Student {`, 168 | ` private name: string`, 169 | ` private age: number`, 170 | ` private school: string`, 171 | ` constructor(name: string, age: number, school: string) {`, 172 | ` this.name = name`, 173 | ` this.age = age`, 174 | ` this.school = school`, 175 | ` }`, 176 | ` study() {`, 177 | ` console.log('Im studying')`, 178 | ` }`, 179 | `}` 180 | ])) 181 | 182 | equalNode(node, ClassTypeSnapshot.PrivateProperty) 183 | }) 184 | 185 | it('protected property', () => { 186 | const node = parseSource(generateSource([ 187 | `class Student {`, 188 | ` protected name: string`, 189 | ` protected age: number`, 190 | ` protected school: string`, 191 | ` constructor(name: string, age: number, school: string) {`, 192 | ` this.name = name`, 193 | ` this.age = age`, 194 | ` this.school = school`, 195 | ` }`, 196 | ` study() {`, 197 | ` console.log('Im studying')`, 198 | ` }`, 199 | `}` 200 | ])) 201 | 202 | 203 | equalNode(node, ClassTypeSnapshot.ProtectedProperty) 204 | }) 205 | 206 | it('readonly property', () => { 207 | const node = parseSource(generateSource([ 208 | `class Student {`, 209 | ` readonly name: string`, 210 | ` readonly age: number`, 211 | ` readonly school: string`, 212 | ` constructor(name: string, age: number, school: string) {`, 213 | ` this.name = name`, 214 | ` this.age = age`, 215 | ` this.school = school`, 216 | ` }`, 217 | ` study() {`, 218 | ` console.log('Im studying')`, 219 | ` }`, 220 | `}` 221 | ])) 222 | 223 | equalNode(node, ClassTypeSnapshot.ReadonlyProperty) 224 | }) 225 | 226 | it('public property', () => { 227 | const node = parseSource(generateSource([ 228 | `class Student {`, 229 | ` public name: string`, 230 | ` public age: number`, 231 | ` public school: string`, 232 | ` constructor(name: string, age: number, school: string) {`, 233 | ` this.name = name`, 234 | ` this.age = age`, 235 | ` this.school = school`, 236 | ` }`, 237 | ` study() {`, 238 | ` console.log('Im studying')`, 239 | ` }`, 240 | `}` 241 | ])) 242 | 243 | equalNode(node, ClassTypeSnapshot.PublicProperty) 244 | }) 245 | 246 | it('static property', () => { 247 | const node = parseSource(generateSource([ 248 | `class Student {`, 249 | ` static school: string = 'gdut'`, 250 | ` static study() {`, 251 | ` console.log('Im studying')`, 252 | ` }`, 253 | `}` 254 | ])) 255 | 256 | equalNode(node, ClassTypeSnapshot.StaticFunction) 257 | }) 258 | 259 | it('static async methods', () => { 260 | const node = parseSource(generateSource([ 261 | `class Student {`, 262 | ` static async study(): Promise {`, 263 | ` console.log('Im studying')`, 264 | ` }`, 265 | ` static async * students(): AsyncIterable {`, 266 | ` yield 'John Smith'`, 267 | ` }`, 268 | `}` 269 | ])) 270 | 271 | equalNode(node, ClassTypeSnapshot.StaticAsyncMethods) 272 | }) 273 | 274 | it('static getter/setter', () => { 275 | const node = parseSource(generateSource([ 276 | `class C {`, 277 | ` static get foo(): number {}`, 278 | ` static set foo(value: number) {}`, 279 | `}` 280 | ])) 281 | 282 | equalNode(node, ClassTypeSnapshot.StaticGetterSetter) 283 | }) 284 | 285 | it('escaped static method ', () => { 286 | // See: https://github.com/tc39/test262/blob/main/test/language/statements/class/syntax/escaped-static.js 287 | expect(() => { 288 | parseSource(generateSource([ 289 | `class C {`, 290 | ` st\\u0061tic m() {}`, 291 | `}` 292 | ])) 293 | }).toThrowError() 294 | }) 295 | 296 | it('private class method', () => { 297 | const node = parseSource(generateSource([ 298 | `class Student {`, 299 | ` private study() {`, 300 | ` console.log('Im studying')`, 301 | ` }`, 302 | `}` 303 | ])) 304 | 305 | equalNode(node, ClassTypeSnapshot.PrivateClassMethod) 306 | }) 307 | 308 | it('computed property', () => { 309 | const node = parseSource(generateSource([ 310 | `class Student {`, 311 | ` private _school: string`, 312 | ` get school() {`, 313 | ` return this._school`, 314 | ` }`, 315 | ` set school(value: string) {`, 316 | ` this._school = value`, 317 | ` }`, 318 | `}` 319 | ])) 320 | 321 | equalNode(node, ClassTypeSnapshot.ComputedProperty) 322 | }) 323 | 324 | it('abstract class', () => { 325 | const node = parseSource(generateSource([ 326 | `abstract class Person {`, 327 | ` name: string;`, 328 | ` constructor(name: string) {`, 329 | ` this.name = name;`, 330 | ` }`, 331 | ` display(): void{`, 332 | ` console.log(this.name);`, 333 | ` }`, 334 | ` abstract find(string): Person;`, 335 | `}`, 336 | `class Employee extends Person {`, 337 | ` empCode: number;`, 338 | ` constructor(name: string, code: number) {`, 339 | ` super(name);`, 340 | ` this.empCode = code;`, 341 | ` }`, 342 | ` find(name:string): Person {`, 343 | ` return new Employee(name, 1);`, 344 | ` }`, 345 | `}` 346 | ])) 347 | 348 | equalNode(node, ClassTypeSnapshot.AbstractClass) 349 | }) 350 | 351 | it('private id class method', () => { 352 | const node = parseSource(generateSource([ 353 | `class Student {`, 354 | ` #study() {`, 355 | ` console.log('Im studying')`, 356 | ` }`, 357 | `}` 358 | ])) 359 | 360 | equalNode(node, ClassTypeSnapshot.PrivateIdClassMethod) 361 | }) 362 | 363 | it('class duplicate method', () => { 364 | const node = parseSource(generateSource([ 365 | `class Student {`, 366 | ` study(book: 'math'): void`, 367 | ` study(book: 'english'): void`, 368 | ` study(book: 'math' | 'english'): void {`, 369 | ` console.log('Im studying')`, 370 | ` }`, 371 | `}` 372 | ])) 373 | 374 | equalNode(node, ClassTypeSnapshot.ClassDuplicateMethod) 375 | }) 376 | 377 | it('class duplicate constructor', () => { 378 | const node = parseSource(generateSource([ 379 | `class Student {`, 380 | ` constructor(book: 'math'): void`, 381 | ` constructor(book: 'english'): void`, 382 | ` constructor(book: 'math' | 'english'): void {`, 383 | ` console.log('Im studying')`, 384 | ` }`, 385 | `}` 386 | ])) 387 | 388 | equalNode(node, ClassTypeSnapshot.ClassDuplicateConstructor) 389 | }) 390 | 391 | it('class abstract method with body', function() { 392 | const res = parseSourceShouldThrowError(generateSource([ 393 | `abstract class Person {`, 394 | ` abstract find(string): Person {}`, 395 | `}` 396 | ]), TypeScriptError.AbstractMethodHasImplementation({ 397 | methodName: 'find' 398 | }), '(2:2)') 399 | 400 | expect(res).toBe(true) 401 | }) 402 | 403 | it('definite property', () => { 404 | const node = parseSource(generateSource([ 405 | `class Student {`, 406 | ` name!: string`, 407 | `}` 408 | ])) 409 | 410 | equalNode(node, ClassTypeSnapshot.DefiniteProperty) 411 | }) 412 | 413 | it('accessor', () => { 414 | const node = parseSource(generateSource([ 415 | `class Person {`, 416 | ` accessor name: string;`, 417 | ` constructor(name: string) {`, 418 | ` this.name = name;`, 419 | ` }`, 420 | `}` 421 | ])) 422 | 423 | equalNode(node, ClassTypeSnapshot.Accessor) 424 | }) 425 | 426 | it('escaped keyword property ', () => { 427 | const node = parseSource(generateSource([ 428 | `class C {`, 429 | ` \\u0069n: string`, 430 | `}` 431 | ])) 432 | 433 | equalNode(node, ClassTypeSnapshot.EscapedKeywordProperty) 434 | }) 435 | 436 | it('duplicate constructor', () => { 437 | expect(() => { 438 | parseSource(generateSource([ 439 | `class C {`, 440 | ` constructor(){}`, 441 | ` constructor(){}`, 442 | `}` 443 | ])) 444 | }).toThrowError() 445 | }) 446 | 447 | it('constructor signature', () => { 448 | const node = parseSource(generateSource([ 449 | `class C {`, 450 | ` constructor()`, 451 | ` constructor(){}`, 452 | `}` 453 | ])) 454 | 455 | equalNode(node, ClassTypeSnapshot.ConstructorSignature) 456 | }) 457 | 458 | it('issue 33', () => { 459 | const node = parseSource(issue33File) 460 | 461 | equalNode(node, ClassTypeSnapshot.Issue33) 462 | }) 463 | 464 | it('issue 34', () => { 465 | const node = parseSource(issue34File) 466 | 467 | equalNode(node, ClassTypeSnapshot.Issue34) 468 | }) 469 | 470 | it('issue 35', () => { 471 | const node = parseSource(issue35File) 472 | 473 | equalNode(node, ClassTypeSnapshot.Issue35) 474 | }) 475 | 476 | it('issue 36', () => { 477 | const node = parseSource(issue36File) 478 | 479 | equalNode(node, ClassTypeSnapshot.Issue36) 480 | }) 481 | 482 | // todo: feature request 483 | // it('issue 41', () => { 484 | // const node = parseSource(issue41File) 485 | // console.log(JSON.stringify(node, null, 2)) 486 | // }) 487 | 488 | it('issue 42', () => { 489 | const node = parseSource(issue42File) 490 | 491 | equalNode(node, ClassTypeSnapshot.Issue42) 492 | }) 493 | 494 | it('issue 44', () => { 495 | const node = parseSource(issue44File) 496 | 497 | equalNode(node, ClassTypeSnapshot.Issue44) 498 | }) 499 | }) 500 | 501 | -------------------------------------------------------------------------------- /__test__/decorators/index.test.ts: -------------------------------------------------------------------------------- 1 | import { equalNode, generateSource, parseSource } from '../utils' 2 | import DecoratorsSnapshot from '../__snapshot__/decorators' 3 | 4 | describe('decorators', () => { 5 | it('class method', () => { 6 | const node = parseSource(generateSource([ 7 | `function first() {`, 8 | ` console.log("first(): factory evaluated");`, 9 | ` return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {`, 10 | ` console.log("first(): called");`, 11 | ` };`, 12 | `}`, 13 | `class ExampleClass {`, 14 | ` @first()`, 15 | ` method() {}`, 16 | `}` 17 | ])) 18 | 19 | equalNode(node, DecoratorsSnapshot.ClassMethod) 20 | }) 21 | 22 | it('class', () => { 23 | const node = parseSource(generateSource([ 24 | `function reportableClassDecorator(constructor: T) {`, 25 | ` return class extends constructor {`, 26 | ` reportingURL = "http://www...";`, 27 | ` };`, 28 | `}`, 29 | `@reportableClassDecorator`, 30 | `class ExampleClass {`, 31 | ` title: string`, 32 | ` constructor(t: string) {`, 33 | ` this.title = t;`, 34 | ` }`, 35 | `}` 36 | ])) 37 | 38 | equalNode(node, DecoratorsSnapshot.Class) 39 | }) 40 | 41 | it('class accessor', () => { 42 | const node = parseSource(generateSource([ 43 | `function configurable(value: Boolean) {`, 44 | ` return function (target: any, propertyKey: string, descriptor: PropertyDescriptor) {`, 45 | ` descriptor.configurable = value;`, 46 | ` };`, 47 | `}`, 48 | `class ExampleClass {`, 49 | ` title: string`, 50 | ` constructor(t: string) {`, 51 | ` this.title = t;`, 52 | ` }`, 53 | ` @configurable(false)`, 54 | ` get x() {`, 55 | ` return this.title;`, 56 | ` }`, 57 | `}` 58 | ])) 59 | 60 | equalNode(node, DecoratorsSnapshot.ClassAccessor) 61 | }) 62 | 63 | it('class property', () => { 64 | const node = parseSource(generateSource([ 65 | `function format(target: string) {`, 66 | ` return target`, 67 | `}`, 68 | `class ExampleClass {`, 69 | ` @format('Hello, %s')`, 70 | ` title: string`, 71 | ` constructor(t: string) {`, 72 | ` this.title = t;`, 73 | ` }`, 74 | `}` 75 | ])) 76 | 77 | equalNode(node, DecoratorsSnapshot.ClassProperty) 78 | }) 79 | 80 | it('class params', () => { 81 | const node = parseSource(generateSource([ 82 | `class MyClass {`, 83 | ` myMethod(@logParam myParameter: string) {}`, 84 | `}`, 85 | `function logParam(target: any, methodKey: string, parameterIndex: number) {`, 86 | ` target.test = methodKey;`, 87 | `}` 88 | ])) 89 | 90 | equalNode(node, DecoratorsSnapshot.ClassParams) 91 | }) 92 | }) 93 | 94 | -------------------------------------------------------------------------------- /__test__/enum/type.test.ts: -------------------------------------------------------------------------------- 1 | import { equalNode, generateSource, parseSource } from '../utils' 2 | import EnumTypeSnapshot from '../__snapshot__/enum/type' 3 | 4 | describe('enum', () => { 5 | it('normal', () => { 6 | const node = parseSource(generateSource([ 7 | `enum Student {`, 8 | ` name = 'tyreal',`, 9 | ` age = 22,`, 10 | ` school = 'string'`, 11 | `}` 12 | ])) 13 | 14 | equalNode(node, EnumTypeSnapshot.Normal) 15 | }) 16 | }) 17 | 18 | -------------------------------------------------------------------------------- /__test__/export/normal.test.ts: -------------------------------------------------------------------------------- 1 | import { equalNode, generateSource, parseSource } from '../utils' 2 | import NormalExportSnapshot from '../__snapshot__/export/normal' 3 | 4 | describe('normal export', () => { 5 | it('export default object', () => { 6 | const node = parseSource(generateSource([ 7 | `export default {`, 8 | ` a: '12345'`, 9 | '}' 10 | ])) 11 | 12 | equalNode(node, NormalExportSnapshot.ExportDefaultObject) 13 | }) 14 | 15 | it('export default function', () => { 16 | const node = parseSource(generateSource([ 17 | `export default function() {`, 18 | ` console.log('12345')`, 19 | '}' 20 | ])) 21 | 22 | equalNode(node, NormalExportSnapshot.ExportDefaultFunction) 23 | }) 24 | 25 | it('export default function with name', () => { 26 | const node = parseSource(generateSource([ 27 | `export default function Test() {`, 28 | ` console.log('12345')`, 29 | '}' 30 | ])) 31 | 32 | equalNode(node, NormalExportSnapshot.ExportDefaultFunctionWithName) 33 | }) 34 | 35 | it('export default arrow function', () => { 36 | const node = parseSource(generateSource([ 37 | `export default () => {`, 38 | ` console.log('12345')`, 39 | '}' 40 | ])) 41 | 42 | equalNode(node, NormalExportSnapshot.ExportDefaultArrowFunction) 43 | }) 44 | 45 | it('export default anonymous class', () => { 46 | const node = parseSource(generateSource([ 47 | `export default class {}`, 48 | ])) 49 | 50 | equalNode(node, NormalExportSnapshot.ExportDefaultAnonymousClass) 51 | }) 52 | 53 | it('export const', () => { 54 | const node = parseSource(generateSource([ 55 | `export const test = '12345'` 56 | ])) 57 | 58 | equalNode(node, NormalExportSnapshot.ExportConst) 59 | }) 60 | 61 | it('export', () => { 62 | const node = parseSource(generateSource([ 63 | `const Name = 'tyreal'`, 64 | `let Age = 22`, 65 | `export {`, 66 | ` Name,`, 67 | ` Age`, 68 | `}` 69 | ])) 70 | 71 | equalNode(node, NormalExportSnapshot.Export) 72 | }) 73 | }) 74 | -------------------------------------------------------------------------------- /__test__/export/type.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | equalNode, 3 | generateSource, parseDtsSource, 4 | parseSource, 5 | parseSourceShouldThrowError 6 | } from '../utils' 7 | import ExportTypeSnapshot from '../__snapshot__/export/type' 8 | import { TypeScriptError } from '../../src/error' 9 | 10 | describe('export type', () => { 11 | it('export type', () => { 12 | const node = parseSource(generateSource([ 13 | `export type Test = string | number` 14 | ])) 15 | 16 | equalNode(node, ExportTypeSnapshot.Type) 17 | }) 18 | 19 | it('export serious type', () => { 20 | const node = parseSource(generateSource([ 21 | `type Name = string`, 22 | `type Age = number`, 23 | `export {`, 24 | ` Name,`, 25 | ` Age`, 26 | `}` 27 | ])) 28 | 29 | equalNode(node, ExportTypeSnapshot.SeriousType) 30 | }) 31 | 32 | it('export type and const', () => { 33 | const node = parseSource(generateSource([ 34 | `const a = 1`, 35 | `type A = number`, 36 | `export {`, 37 | ` a,`, 38 | ` type A`, 39 | `}` 40 | ])) 41 | 42 | equalNode(node, ExportTypeSnapshot.ExportTypeAndConst) 43 | }) 44 | 45 | it('export type with as and const', () => { 46 | const node = parseSource(generateSource([ 47 | `const a = 1`, 48 | `type A = number`, 49 | `export {`, 50 | ` a,`, 51 | ` type A as B`, 52 | `}` 53 | ])) 54 | 55 | equalNode(node, ExportTypeSnapshot.ExportTypeWithAsAndConst) 56 | }) 57 | 58 | it('export type type with as', () => { 59 | const node = parseSource(generateSource([ 60 | `const a = 1`, 61 | `type type = number`, 62 | `export {`, 63 | ` a,`, 64 | ` type type as A`, 65 | `}` 66 | ])) 67 | 68 | equalNode(node, ExportTypeSnapshot.ExportTypeTypeWithAs) 69 | }) 70 | 71 | it('export type type with as as', () => { 72 | const node = parseSource(generateSource([ 73 | `const a = 1`, 74 | `type type = number`, 75 | `export {`, 76 | ` a,`, 77 | ` type type as as`, 78 | `}` 79 | ])) 80 | 81 | equalNode(node, ExportTypeSnapshot.ExportTypeTypeWithAsAs) 82 | }) 83 | 84 | it('export type as as with name', () => { 85 | const node = parseSource(generateSource([ 86 | `const as = 'test'`, 87 | `export {`, 88 | ` type as as someName`, 89 | `}` 90 | ])) 91 | 92 | equalNode(node, ExportTypeSnapshot.ExportTypeAsAsWithName) 93 | }) 94 | 95 | it('dts export duplicate', () => { 96 | const node = parseDtsSource(generateSource([ 97 | `export function defineConfig(options: RollupOptions): RollupOptions;`, 98 | `export function defineConfig(options: RollupOptions[]): RollupOptions[];` 99 | ])) 100 | 101 | equalNode(node, ExportTypeSnapshot.DtsExportDuplicate) 102 | }) 103 | 104 | it('export outer type type with name', () => { 105 | const res = parseSourceShouldThrowError(generateSource([ 106 | `const A = 'test'`, 107 | `export type {`, 108 | ` type A`, 109 | `}` 110 | ]), TypeScriptError.TypeModifierIsUsedInTypeExports, '(3:2)') 111 | 112 | expect(res).toBe(true) 113 | }) 114 | }) 115 | -------------------------------------------------------------------------------- /__test__/expression/type.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | equalNode, 3 | generateSource, 4 | parseDtsSource, 5 | parseSource 6 | } from '../utils' 7 | import ExpressionTypeSnapshot from '../__snapshot__/expression/type' 8 | 9 | describe('expression type test', () => { 10 | it('normal interface', () => { 11 | const node = parseSource(generateSource([ 12 | `interface Student {`, 13 | ` name: string`, 14 | ` age: number`, 15 | ` school: string`, 16 | `}` 17 | ])) 18 | 19 | equalNode(node, ExpressionTypeSnapshot.NormalInterface) 20 | }) 21 | 22 | it('nested interface', () => { 23 | const node = parseSource(generateSource([ 24 | `interface Student {`, 25 | ` name: string`, 26 | ` age: number`, 27 | ` family: string[]`, 28 | ` interest: {`, 29 | ` artificialIntelligence: string`, 30 | ` study: string`, 31 | ` }`, 32 | `}` 33 | ])) 34 | 35 | equalNode(node, ExpressionTypeSnapshot.NestedInterface) 36 | }) 37 | 38 | it('extend interface', () => { 39 | const node = parseSource(generateSource([ 40 | `interface Person {`, 41 | ` name: string`, 42 | ` age: number`, 43 | `}`, 44 | ``, 45 | `interface Student extends Person {`, 46 | ` family: string[]`, 47 | ` interest: {`, 48 | ` artificialIntelligence: string`, 49 | ` study: string`, 50 | ` }`, 51 | `}` 52 | ])) 53 | 54 | equalNode(node, ExpressionTypeSnapshot.ExtendsInterface) 55 | }) 56 | 57 | it('normal type', () => { 58 | const node = parseSource(generateSource([ 59 | `type School = 'Tsinghua' | 'Peking' | 'GDUT'` 60 | ])) 61 | 62 | equalNode(node, ExpressionTypeSnapshot.NormalType) 63 | }) 64 | 65 | it('enum', () => { 66 | const node = parseSource(generateSource([ 67 | `enum Test {`, 68 | ` Start = 'start',`, 69 | ` End = 'end'`, 70 | `}` 71 | ])) 72 | 73 | equalNode(node, ExpressionTypeSnapshot.Enum) 74 | }) 75 | 76 | it('declare', () => { 77 | const node = parseSource(generateSource([ 78 | `declare module '*.png' {`, 79 | ` const value: string;`, 80 | ` export default value;`, 81 | `}` 82 | ])) 83 | 84 | equalNode(node, ExpressionTypeSnapshot.Declare) 85 | }) 86 | 87 | it('declare namespace', () => { 88 | const node = parseSource(generateSource([ 89 | `declare namespace myLib {`, 90 | ` let timeout: number;`, 91 | ` const version: string;`, 92 | ` class Cat {`, 93 | ` constructor(n: number);`, 94 | ` readonly age: number;`, 95 | ` purr(): void;`, 96 | ` }`, 97 | ` interface CatSettings {`, 98 | ` weight: number;`, 99 | ` name: string;`, 100 | ` tailLength?: number;`, 101 | ` }`, 102 | ` type VetID = string | number;`, 103 | ` function checkCat(c: Cat, s?: VetID);`, 104 | `}` 105 | ])) 106 | 107 | equalNode(node, ExpressionTypeSnapshot.DeclareNamespace) 108 | }) 109 | 110 | it(`issue 29 dts`, () => { 111 | const node = parseDtsSource(generateSource([`import type { ReactNode, Ref } from "react";`, 112 | `import type { CommonProps } from "./types";`, 113 | `export type SlideApi = {`, 114 | ` goToNextSlide: () => void;`, 115 | ` goToPreviousSlide: () => void;`, 116 | `};`, 117 | `export type SlideProps = CommonProps & {`, 118 | ` children: ReactNode; `, 119 | ` defaultSlide?: number; `, 120 | ` onSlideChange?: (slide: number) => void;`, 121 | ` ref?: Ref;`, 122 | `};`, 123 | `declare function SlideProps(props: SlideProps): JSX.Element;`, 124 | `export default SlideProps;` 125 | ])) 126 | 127 | equalNode(node, ExpressionTypeSnapshot.Issue29Dts) 128 | }) 129 | }) 130 | -------------------------------------------------------------------------------- /__test__/expression/variables.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | equalNode, 3 | generateSource, 4 | parseSource, 5 | parseSourceShouldThrowError 6 | } from '../utils' 7 | import VariablesTypeSnapshot from '../__snapshot__/expression/variables' 8 | import { TypeScriptError } from '../../src/error' 9 | 10 | const issueFile43 = ` 11 | const binaryOperators: { 12 | [operator in any]?: (left: any, right: any) => any; 13 | } = { 14 | '<': (left, right) => left! < right! 15 | }; 16 | ` 17 | 18 | describe('variables declaration', () => { 19 | it('number', () => { 20 | const node = parseSource(generateSource([ 21 | `const test: number = 123` 22 | ])) 23 | 24 | equalNode(node, VariablesTypeSnapshot.Number) 25 | }) 26 | 27 | it('number with definite', () => { 28 | const node = parseSource(generateSource([ 29 | `let test!: number` 30 | ])) 31 | 32 | equalNode(node, VariablesTypeSnapshot.NumberWithDefinite) 33 | }) 34 | 35 | it('string', () => { 36 | const node = parseSource(generateSource([ 37 | `const test: string = '12355'` 38 | ])) 39 | 40 | equalNode(node, VariablesTypeSnapshot.String) 41 | }) 42 | 43 | it('undefined', () => { 44 | const node = parseSource(generateSource([ 45 | `const test: undefined = undefined` 46 | ])) 47 | 48 | equalNode(node, VariablesTypeSnapshot.Undefined) 49 | }) 50 | 51 | it('boolean', () => { 52 | const node = parseSource(generateSource([ 53 | `const test: boolean = false` 54 | ])) 55 | 56 | equalNode(node, VariablesTypeSnapshot.Boolean) 57 | }) 58 | 59 | it('bigint', () => { 60 | const node = parseSource(generateSource([ 61 | `const test: bigint = BigInt('123123')` 62 | ])) 63 | 64 | equalNode(node, VariablesTypeSnapshot.BigInt) 65 | }) 66 | 67 | it('object', () => { 68 | const node = parseSource(generateSource([ 69 | `const test: object = {`, 70 | ' a: 1,', 71 | ' b: 2', 72 | '}' 73 | ])) 74 | 75 | equalNode(node, VariablesTypeSnapshot.Object) 76 | }) 77 | 78 | it('symbol', () => { 79 | const node = parseSource(generateSource([ 80 | `const test: symbol = Symbol('123')`, 81 | ])) 82 | 83 | equalNode(node, VariablesTypeSnapshot.Symbol) 84 | }) 85 | 86 | it('unknown', () => { 87 | const node = parseSource(generateSource([ 88 | `const test: unknown = 123`, 89 | ])) 90 | 91 | equalNode(node, VariablesTypeSnapshot.Unknown) 92 | }) 93 | 94 | it('any', () => { 95 | const node = parseSource(generateSource([ 96 | `const test: any = 123`, 97 | ])) 98 | 99 | equalNode(node, VariablesTypeSnapshot.Any) 100 | }) 101 | 102 | it('type', () => { 103 | const node = parseSource(generateSource([ 104 | `type TestType = string | number | object`, 105 | `const test: TestType = 123`, 106 | ])) 107 | 108 | equalNode(node, VariablesTypeSnapshot.Type) 109 | }) 110 | 111 | it('interface', () => { 112 | const node = parseSource(generateSource([ 113 | `interface Student {`, 114 | ` name: string`, 115 | ` age: number`, 116 | ` school: string`, 117 | `}`, 118 | `const test: Student = {`, 119 | ` name: 'tyreal',`, 120 | ` age: 22,`, 121 | ` school: 'gdut',`, 122 | `}` 123 | ])) 124 | 125 | equalNode(node, VariablesTypeSnapshot.Interface) 126 | }) 127 | 128 | it('union', () => { 129 | const node = parseSource(generateSource([ 130 | `const test: string | number = 123`, 131 | ])) 132 | 133 | equalNode(node, VariablesTypeSnapshot.Union) 134 | }) 135 | 136 | it('let union', () => { 137 | const node = parseSource(generateSource([ 138 | `let test: string | number = 123`, 139 | ])) 140 | 141 | equalNode(node, VariablesTypeSnapshot.LetUnion) 142 | }) 143 | 144 | it('expression list arrow function and var', () => { 145 | const node = parseSource(generateSource([ 146 | `let test1 = 2,`, 147 | ` test = (name: string, age: number): void => {`, 148 | ` console.log(name, age)`, 149 | ` }` 150 | ])) 151 | 152 | equalNode(node, VariablesTypeSnapshot.ExpressionListArrowFunctionAndVar) 153 | }) 154 | 155 | it('expression list arrow function and param is function', () => { 156 | const node = parseSource(generateSource([ 157 | `let test = (name: string, speak: (() => void)): void => {`, 158 | ` console.log(name, age)`, 159 | `}` 160 | ])) 161 | 162 | equalNode(node, VariablesTypeSnapshot.ExpressionListArrowFunctionAndParamIsFunction) 163 | }) 164 | 165 | it('expression with paren', () => { 166 | const node = parseSource(generateSource([ 167 | `let test = (1 === 2)` 168 | ])) 169 | 170 | equalNode(node, VariablesTypeSnapshot.ExpressionWithParen) 171 | }) 172 | 173 | it('expression equal function', () => { 174 | const node = parseSource(generateSource([ 175 | `let test = function(): void {}` 176 | ])) 177 | 178 | equalNode(node, VariablesTypeSnapshot.ExpressionEqualFunction) 179 | }) 180 | 181 | it('expression equal arrow function', () => { 182 | const node = parseSource(generateSource([ 183 | `let test = (): void => {}` 184 | ])) 185 | 186 | equalNode(node, VariablesTypeSnapshot.ExpressionEqualArrowFunction) 187 | }) 188 | 189 | it('expression equal async function', () => { 190 | const node = parseSource(generateSource([ 191 | `let test = async function(): Promise {}` 192 | ])) 193 | 194 | equalNode(node, VariablesTypeSnapshot.ExpressionEqualAsyncFunction) 195 | }) 196 | 197 | it('expression equal async arrow function', () => { 198 | const node = parseSource(generateSource([ 199 | `let test = async (): Promise => {}` 200 | ])) 201 | 202 | equalNode(node, VariablesTypeSnapshot.ExpressionEqualAsyncArrowFunction) 203 | }) 204 | 205 | it('1 as number', () => { 206 | const node = parseSource(generateSource([ 207 | `let test = 1 as number` 208 | ])) 209 | 210 | equalNode(node, VariablesTypeSnapshot.OneAsNumber) 211 | }) 212 | //console.log(JSON.stringify(node, null, 2)) 213 | it('parse generics without comma', () => { 214 | const node = parseSource(generateSource([ 215 | `const a: Foo = 1` 216 | ])) 217 | 218 | equalNode(node, VariablesTypeSnapshot.ParseGenericsWithoutComma) 219 | }) 220 | 221 | it('parse generics with comma', () => { 222 | const res = parseSourceShouldThrowError(generateSource([ 223 | `const a: Foo = 1` 224 | ]), TypeScriptError.GenericsEndWithComma, '(1:16)') 225 | 226 | expect(res).toBe(false) 227 | }) 228 | 229 | it('parse condition express error', () => { 230 | const res = parseSourceShouldThrowError(generateSource([ 231 | `const a = true ? : 1` 232 | ]), 'Unexpected token', '(1:17)') 233 | 234 | expect(res).toBe(true) 235 | }) 236 | 237 | it('issue 43', () => { 238 | const node = parseSource(issueFile43) 239 | 240 | equalNode(node, VariablesTypeSnapshot.IssueFile43) 241 | }) 242 | }) 243 | -------------------------------------------------------------------------------- /__test__/for/index.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | equalNode, 3 | generateSource, 4 | parseSource, 5 | parseSourceShouldThrowError 6 | } from '../utils' 7 | import ForSnapshot from '../__snapshot__/for' 8 | 9 | describe('for', () => { 10 | it('of', () => { 11 | const node = parseSource(generateSource([ 12 | `const words = []`, 13 | `for (const word of words) {`, 14 | ` console.log(word)`, 15 | `}` 16 | ])) 17 | 18 | equalNode(node, ForSnapshot.of) 19 | }) 20 | it('in without decl', () => { 21 | const node = parseSource(generateSource([ 22 | `for (word in words) {`, 23 | ` console.log(word)`, 24 | `}` 25 | ])) 26 | 27 | equalNode(node, ForSnapshot.inWithoutDecl) 28 | }) 29 | it('async in for of without decl', () => { 30 | const res = parseSourceShouldThrowError(generateSource([ 31 | `var async;`, 32 | `for (async of [1]) ;` 33 | ]), 'Unexpected token', '(2:14)') 34 | 35 | expect(res).toBe(true) 36 | }) 37 | }) 38 | 39 | -------------------------------------------------------------------------------- /__test__/function/type.test.ts: -------------------------------------------------------------------------------- 1 | import { equalNode, generateSource, parseSource } from '../utils' 2 | import FunctionTypeSnapshot from '../__snapshot__/function/type' 3 | 4 | describe('function type test', () => { 5 | it('no parameter with void', () => { 6 | const node = parseSource(generateSource([ 7 | `function test(): void {`, 8 | ` console.log(123)`, 9 | `}` 10 | ])) 11 | 12 | equalNode(node, FunctionTypeSnapshot.NoParameterWithVoid) 13 | }) 14 | 15 | it('no parameter with never', () => { 16 | const node = parseSource(generateSource([ 17 | `function test(): never {`, 18 | ` throw new Error('123')`, 19 | `}` 20 | ])) 21 | 22 | equalNode(node, FunctionTypeSnapshot.NoParameterWithNever) 23 | }) 24 | 25 | it('no parameter with string', () => { 26 | const node = parseSource(generateSource([ 27 | `function test(): string {`, 28 | ` return '123'`, 29 | `}` 30 | ])) 31 | 32 | equalNode(node, FunctionTypeSnapshot.NoParameterWithString) 33 | }) 34 | 35 | it('no parameter with number', () => { 36 | const node = parseSource(generateSource([ 37 | `function test(): number {`, 38 | ` return 123`, 39 | `}` 40 | ])) 41 | 42 | equalNode(node, FunctionTypeSnapshot.NoParameterWithNumber) 43 | }) 44 | 45 | it('no parameter with undefined', () => { 46 | const node = parseSource(generateSource([ 47 | `function test(): undefined {`, 48 | ` return undefined`, 49 | `}` 50 | ])) 51 | 52 | equalNode(node, FunctionTypeSnapshot.NoParameterWithUndefined) 53 | }) 54 | 55 | it('no parameter with boolean', () => { 56 | const node = parseSource(generateSource([ 57 | `function test(): boolean {`, 58 | ` return true`, 59 | `}` 60 | ])) 61 | 62 | equalNode(node, FunctionTypeSnapshot.NoParameterWithBoolean) 63 | }) 64 | 65 | it('no parameter with bigint', () => { 66 | const node = parseSource(generateSource([ 67 | `function test(): bigint {`, 68 | ` return BigInt('123123')`, 69 | `}` 70 | ])) 71 | 72 | equalNode(node, FunctionTypeSnapshot.NoParameterWithBigInt) 73 | }) 74 | 75 | it('no parameter with object', () => { 76 | const node = parseSource(generateSource([ 77 | `function test(): object {`, 78 | ` return { a: 1 }`, 79 | `}` 80 | ])) 81 | 82 | equalNode(node, FunctionTypeSnapshot.NoParameterWithObject) 83 | }) 84 | 85 | it('no parameter with symbol', () => { 86 | const node = parseSource(generateSource([ 87 | `function test(): symbol {`, 88 | ` return Symbol('123')`, 89 | `}` 90 | ])) 91 | 92 | equalNode(node, FunctionTypeSnapshot.NoParameterWithSymbol) 93 | }) 94 | 95 | it('no parameter with unknown', () => { 96 | const node = parseSource(generateSource([ 97 | `function test(): unknown {`, 98 | ` return 123`, 99 | `}` 100 | ])) 101 | 102 | equalNode(node, FunctionTypeSnapshot.NoParameterWithUnknown) 103 | }) 104 | 105 | it('no parameter with any', () => { 106 | const node = parseSource(generateSource([ 107 | `function test(): any {`, 108 | ` return 123`, 109 | `}` 110 | ])) 111 | 112 | equalNode(node, FunctionTypeSnapshot.NoParameterWithAny) 113 | }) 114 | 115 | it('no parameter with type', () => { 116 | const node = parseSource(generateSource([ 117 | `type TestType = string | number | object`, 118 | `function test(): TestType {`, 119 | ` return 123`, 120 | `}` 121 | ])) 122 | 123 | equalNode(node, FunctionTypeSnapshot.NoParameterWithType) 124 | }) 125 | 126 | it('no parameter with interface', () => { 127 | const node = parseSource(generateSource([ 128 | `interface Student {`, 129 | ` name: string`, 130 | ` age: number`, 131 | ` school: string`, 132 | `}`, 133 | `function test(): Student {`, 134 | ` return {`, 135 | ` name: 'tyreal',`, 136 | ` age: 22,`, 137 | ` school: 'gdut',`, 138 | ` }`, 139 | `}` 140 | ])) 141 | 142 | equalNode(node, FunctionTypeSnapshot.NoParameterWithInterface) 143 | }) 144 | 145 | it('no parameter with union', () => { 146 | const node = parseSource(generateSource([ 147 | `function test(): string | number {`, 148 | ` return 123`, 149 | `}` 150 | ])) 151 | 152 | equalNode(node, FunctionTypeSnapshot.NoParameterWithUnion) 153 | }) 154 | 155 | it('one parameter with void', () => { 156 | const node = parseSource(generateSource([ 157 | `function test(name: string): void {`, 158 | ` console.log(name)`, 159 | `}` 160 | ])) 161 | 162 | equalNode(node, FunctionTypeSnapshot.OneParameterWithVoid) 163 | }) 164 | 165 | it('one optional parameter with void', () => { 166 | const node = parseSource(generateSource([ 167 | `function test(name?: string): void {`, 168 | ` console.log(name)`, 169 | `}` 170 | ])) 171 | 172 | equalNode(node, FunctionTypeSnapshot.OneOptionalParameterWithVoid) 173 | }) 174 | 175 | it('complex function', () => { 176 | const node = parseSource(generateSource([ 177 | `interface Family {`, 178 | ` father: string`, 179 | ` mother: string`, 180 | `}`, 181 | `function test(name: string, family: Family, age?: number): Family {`, 182 | ` console.log(name, age)`, 183 | ` return family`, 184 | `}` 185 | ])) 186 | 187 | equalNode(node, FunctionTypeSnapshot.ComplexFunction) 188 | }) 189 | 190 | it('async generator function', () => { 191 | const node = parseSource(generateSource([ 192 | `async function * test(p: Promise): void {`, 193 | ` yield * await p`, 194 | `}` 195 | ])) 196 | 197 | equalNode(node, FunctionTypeSnapshot.AsyncGeneratorFunction) 198 | }) 199 | 200 | it('async arrow function with one param', () => { 201 | const node = parseSource(generateSource([ 202 | `a = async x => {}` 203 | ])) 204 | 205 | equalNode(node, FunctionTypeSnapshot.AsyncArrowFunctionWithOneParam) 206 | }) 207 | 208 | it('declare function types', () => { 209 | const node = parseSource(generateSource([ 210 | `function test(a: string): string`, 211 | `function test(a: number): number`, 212 | `function test(a: number | string): number | string {`, 213 | ` return a`, 214 | `}` 215 | ])) 216 | 217 | equalNode(node, FunctionTypeSnapshot.DeclareFunctionTypes) 218 | }) 219 | 220 | it('declare function comma after rest element', () => { 221 | const node = parseSource(generateSource([ 222 | `declare function test(a: number | string, ...b,): number | string;`, 223 | ])) 224 | 225 | equalNode(node, FunctionTypeSnapshot.DeclareFunctionCommaAfterRestElement) 226 | }) 227 | 228 | it('arrow function with optional param', () => { 229 | const node = parseSource(generateSource([ 230 | `const test = (name: string, age?: number) => 42` 231 | ])) 232 | 233 | equalNode(node, FunctionTypeSnapshot.ArrowFunctionWithOptionalParam) 234 | }) 235 | }) 236 | -------------------------------------------------------------------------------- /__test__/identifier/normal.test.ts: -------------------------------------------------------------------------------- 1 | import { equalNode, generateSource, parseSource } from "../utils"; 2 | import NormalIdentifierSnapshot from "../__snapshot__/identifier/normal"; 3 | 4 | describe("normal identifier test", () => { 5 | it("export identifier `as`", () => { 6 | const node = parseSource( 7 | generateSource([`var foo = 8;`, `export { foo as as };`]) 8 | ); 9 | 10 | equalNode(node, NormalIdentifierSnapshot.ExportIdentifierAs); 11 | }); 12 | 13 | it("import identifier `as`", () => { 14 | const node = parseSource( 15 | generateSource([`import { as as as } from './foo.js';`]) 16 | ); 17 | 18 | equalNode(node, NormalIdentifierSnapshot.ImportIdentifierAs); 19 | }); 20 | 21 | it('issue 50', () => { 22 | const node = parseSource( 23 | generateSource([`type abc = 1234;`, `var abc;`]) 24 | ); 25 | 26 | equalNode(node, NormalIdentifierSnapshot.Issue50); 27 | }) 28 | }); 29 | -------------------------------------------------------------------------------- /__test__/import/normal.test.ts: -------------------------------------------------------------------------------- 1 | import { equalNode, generateSource, parseSource } from '../utils' 2 | import NormalImportSnapshot from '../__snapshot__/import/normal' 3 | 4 | describe('normal syntax', () => { 5 | it('import without specifiers', () => { 6 | const node = parseSource(generateSource([ 7 | `import './index.js'` 8 | ])) 9 | 10 | equalNode(node, NormalImportSnapshot.ImportWithoutSpecifiers) 11 | }) 12 | 13 | it('import default specifiers', () => { 14 | const node = parseSource(generateSource([ 15 | `import test from './index.js'` 16 | ])) 17 | 18 | equalNode(node, NormalImportSnapshot.ImportDefaultSpecifier) 19 | }) 20 | 21 | it('import name specifiers', function() { 22 | const node = parseSource(generateSource([ 23 | `import { test, name } from './index.js'` 24 | ])) 25 | 26 | equalNode(node, NormalImportSnapshot.ImportNameSpecifiers) 27 | }) 28 | 29 | it('import namespace specifiers', function() { 30 | const node = parseSource(generateSource([ 31 | `import * as test from './index.js'` 32 | ])) 33 | 34 | equalNode(node, NormalImportSnapshot.ImportNamespaceSpecifier) 35 | }) 36 | 37 | it('import name as specifiers', function() { 38 | const node = parseSource(generateSource([ 39 | `import { test as test1 } from './index.js'` 40 | ])) 41 | 42 | equalNode(node, NormalImportSnapshot.ImportNameAsSpecifiers) 43 | }) 44 | 45 | it('import complex specifiers', function() { 46 | const node = parseSource(generateSource([ 47 | `import './index3.js'`, 48 | `import test, { name, age, school as school1 } from './index.js'`, 49 | `import * as test1 from './index1.js'` 50 | ])) 51 | 52 | equalNode(node, NormalImportSnapshot.ImportComplexSpecifiers) 53 | }) 54 | 55 | it('import namespace type specifiers', function() { 56 | const node = parseSource(generateSource([ 57 | `import test, { name, type age, school as school1 } from './index.js'`, 58 | ])) 59 | 60 | equalNode(node, NormalImportSnapshot.ImportNamespaceType) 61 | }) 62 | 63 | it('import namespace type specifiers with as', function() { 64 | const node = parseSource(generateSource([ 65 | `import test, { name, type age as age1, school as school1 } from './index.js'`, 66 | ])) 67 | 68 | equalNode(node, NormalImportSnapshot.ImportNamespaceTypeWithAs) 69 | }) 70 | 71 | it('import type specifier with as', function() { 72 | const node = parseSource(generateSource([ 73 | `import test, { type as age } from './index.js'`, 74 | ])) 75 | 76 | equalNode(node, NormalImportSnapshot.ImportTypeSpecifierWithAs) 77 | }) 78 | 79 | it('import type specifier with as as', function() { 80 | const node = parseSource(generateSource([ 81 | `import test, { type as as } from './index.js'`, 82 | ])) 83 | 84 | equalNode(node, NormalImportSnapshot.ImportTypeSpecifierWithAsAs) 85 | }) 86 | 87 | it('import type specifier with as as', function() { 88 | const node = parseSource(generateSource([ 89 | `import { type as as somethings } from './index.js'`, 90 | ])) 91 | 92 | equalNode(node, NormalImportSnapshot.ImportTypeSpecifierWithAsAsSomethings) 93 | }) 94 | 95 | it('issue 45', function() { 96 | const node = parseSource(generateSource([ 97 | `import assert from './index.js'`, 98 | ])) 99 | 100 | equalNode(node, NormalImportSnapshot.Issue45) 101 | }) 102 | }) 103 | -------------------------------------------------------------------------------- /__test__/import/type.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | equalNode, 3 | generateSource, 4 | parseSource, 5 | parseSourceShouldThrowError 6 | } from '../utils' 7 | import ImportTypeSnapshot from '../__snapshot__/import/type' 8 | import { TypeScriptError } from '../../src/error' 9 | 10 | describe('type syntax', () => { 11 | it('import default specifiers with type token', () => { 12 | const node = parseSource(generateSource([ 13 | `import type Test from './index.ts'` 14 | ])) 15 | 16 | equalNode(node, ImportTypeSnapshot.ImportDefaultType) 17 | }) 18 | 19 | it('import name as specifiers with type token', function() { 20 | const node = parseSource(generateSource([ 21 | `import type { Test as Test1 } from './index.ts'` 22 | ])) 23 | 24 | equalNode(node, ImportTypeSnapshot.ImportNameAsType) 25 | }) 26 | 27 | it('import namespace specifiers with type token', function() { 28 | const node = parseSource(generateSource([ 29 | `import type * as Test from './index.ts'` 30 | ])) 31 | 32 | equalNode(node, ImportTypeSnapshot.ImportNamespaceType) 33 | }) 34 | 35 | it('import complex type', function() { 36 | const node = parseSource(generateSource([ 37 | `import './index.ts'`, 38 | `import type Test1 from './index1.ts'`, 39 | `import type { Test as Test2 } from './index2.ts'`, 40 | `import type * as Test3 from './index3.ts'` 41 | ])) 42 | 43 | equalNode(node, ImportTypeSnapshot.ImportComplexType) 44 | }) 45 | 46 | it('import type specifiers with outer type', function() { 47 | const res = parseSourceShouldThrowError(generateSource([ 48 | `import type { type Test1 } from './index1.ts'`, 49 | ]), TypeScriptError.TypeModifierIsUsedInTypeImports, '(1:14)') 50 | 51 | expect(res).toBe(true) 52 | }) 53 | }) 54 | -------------------------------------------------------------------------------- /__test__/jsx/index.test.ts: -------------------------------------------------------------------------------- 1 | import { equalNode, generateSource, parseSource } from '../utils' 2 | import JSXSnapshot from '../__snapshot__/jsx' 3 | 4 | const issue46File = ` 5 | import * as React from 'react' 6 | import { Link as RRLink } from 'react-router-dom'; 7 | 8 | const Link = (props: React.ComponentProps) => null 9 | `; 10 | 11 | const issue48File = ` 12 | import styled from 'styled-components'; 13 | 14 | type ExtendedProps = { 15 | $anyprop: string; 16 | }; 17 | 18 | const StyledDiv = styled.div\` 19 | color: red; 20 | \`; 21 | ` 22 | 23 | describe('jsx', function() { 24 | it('simple', () => { 25 | const node = parseSource(generateSource([ 26 | `
` 27 | ])) 28 | 29 | equalNode(node, JSXSnapshot.Simple) 30 | }) 31 | 32 | it('value with colon', () => { 33 | const node = parseSource(generateSource([ 34 | ` {value} ` 35 | ])) 36 | 37 | equalNode(node, JSXSnapshot.ValueWithColon) 38 | }) 39 | 40 | it('props with expr', () => { 41 | const node = parseSource(generateSource([ 42 | `` 43 | ])) 44 | 45 | equalNode(node, JSXSnapshot.PropsWithExpr) 46 | }) 47 | 48 | it('jsx with type generics', () => { 49 | const node = parseSource(generateSource([ 50 | ` />` 51 | ])) 52 | 53 | equalNode(node, JSXSnapshot.JsxWithTypeGenerics) 54 | }) 55 | 56 | it('tsx', () => { 57 | const node = parseSource(generateSource([ 58 | 'import * as React from "react";', 59 | 'import UserInterface from \'../UserInterface\'', 60 | 'export default class UserComponent extends React.Component {', 61 | 'constructor (props: UserInterface){', 62 | ' super(props);', 63 | '}', 64 | 'render() {', 65 | ' return ( ', 66 | '
', 67 | ' >User Component', 68 | ' Hello, {this.props.name}', 69 | '
', 70 | ' You are {this.props.age} years old', 71 | '
', 72 | ' You live at: {this.props.address}', 73 | '
', 74 | ' You were born: {this.props.dob.toDateString()}', 75 | '
', 76 | ' );', 77 | ' }', 78 | '}', 79 | '' 80 | ])) 81 | 82 | console.log(JSON.stringify(node, null, 2)) 83 | equalNode(node, JSXSnapshot.Tsx) 84 | }) 85 | 86 | it('issue 29 jsx', () => { 87 | const node = parseSource(generateSource(['import React, { forwardRef } from "react";', 88 | 'import PropTypes from "prop-types";', 89 | 'const CustomButton = forwardRef(', 90 | ' (', 91 | ' {', 92 | ' iconStart,', 93 | ' iconEnd,', 94 | ' text', 95 | ' },', 96 | ' ref', 97 | ' ) => {', 98 | ' return (', 99 | ' ', 104 | ' );', 105 | ' }', 106 | ');', 107 | 'CustomButton.displayName = "CustomButton";', 108 | 'CustomButton.propTypes = {', 109 | ' text: PropTypes.string,', 110 | ' iconStart: PropTypes.element,', 111 | ' iconEnd: PropTypes.element,', '};', 112 | 'export default CustomButton;' 113 | ])) 114 | 115 | equalNode(node, JSXSnapshot.Issue29Jsx) 116 | }) 117 | 118 | it('issue 46', () => { 119 | const node = parseSource(issue46File) 120 | 121 | equalNode(node, JSXSnapshot.Issue46) 122 | }) 123 | 124 | it('issue 48', () => { 125 | const node = parseSource(issue48File) 126 | 127 | equalNode(node, JSXSnapshot.Issue48) 128 | }) 129 | }) 130 | -------------------------------------------------------------------------------- /__test__/object/index.test.ts: -------------------------------------------------------------------------------- 1 | import { equalNode, generateSource, parseSource } from '../utils' 2 | import ObjectSnapshot from '../__snapshot__/object' 3 | 4 | describe('object', function() { 5 | it('get and set with this', function() { 6 | const node = parseSource(generateSource([ 7 | 'const test = {', 8 | ' privateName: \'tyreal\',', 9 | ' get name(this) {', 10 | ' return this.privateName', 11 | ' },', 12 | ' set name(this, _name) {', 13 | ' this.privateName = _name', 14 | ' }', 15 | '}' 16 | ])) 17 | 18 | equalNode(node, ObjectSnapshot.GetAndSetWithThis) 19 | }) 20 | 21 | it('get and set without this', function() { 22 | const node = parseSource(generateSource([ 23 | 'const test = {', 24 | ' privateName: \'tyreal\',', 25 | ' get name() {', 26 | ' return this.privateName', 27 | ' },', 28 | ' set name(_name: string) {', 29 | ' this.privateName = _name', 30 | ' }', 31 | '}' 32 | ])) 33 | 34 | equalNode(node, ObjectSnapshot.GetAndSetWithoutThis) 35 | }) 36 | 37 | it('normal object', function() { 38 | const node = parseSource(generateSource([ 39 | 'const test = {', 40 | ' privateName: \'tyreal\',', 41 | ' speak() {', 42 | ' console.log(123)', 43 | ' },', 44 | '}' 45 | ])) 46 | 47 | equalNode(node, ObjectSnapshot.NormalObject) 48 | }) 49 | 50 | 51 | it('async arrow function in subscript', () => { 52 | const node = parseSource(generateSource([ 53 | 'async () => {', 54 | ' console.log(123)', 55 | '}' 56 | ])) 57 | 58 | equalNode(node, ObjectSnapshot.AsyncArrowFunctionInSubscript) 59 | }) 60 | }) 61 | -------------------------------------------------------------------------------- /__test__/run_test262.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path' 2 | // @ts-ignore - no types 3 | import * as run from 'test262-parser-runner' 4 | import * as acorn from 'acorn' 5 | import { tsPlugin } from '../src' 6 | 7 | const parser = acorn.Parser.extend(tsPlugin()) 8 | const UNSUPPORTED_FEATURES: string[] = [ 9 | 'regexp-v-flag', 10 | 'regexp-duplicate-named-groups', 11 | 'import-assertions', 12 | 'decorators', 13 | 'json-modules', 14 | 'import-attributes' 15 | ] 16 | 17 | const SKIP_FILES: string[] = [ 18 | // `1 < 2 > 3;` cannot be parsed well. 19 | // This is because `< 2 >` is judged as TypeArguments. 20 | // See https://github.com/TyrealHu/acorn-typescript/issues/21 21 | 'test/language/punctuators/S7.7_A1.js' 22 | ] 23 | 24 | 25 | // Some keywords still don't throw an error. 26 | // See https://github.com/TyrealHu/acorn-typescript/issues/23 27 | const WHITELIST: string[] = [ 28 | // `this` variable name. e.g. `var this = 42` 29 | 'language/identifiers/val-this.js', 30 | 'language/identifiers/val-this-via-escape-hex.js', 31 | 'language/identifiers/val-this-via-escape-hex4.js', 32 | 'language/module-code/early-dup-export-as-star-as.js', 33 | 'language/module-code/early-dup-export-dflt-id.js', 34 | 'language/module-code/early-dup-export-id-as.js', 35 | 'language/module-code/early-dup-export-id.js', 36 | 'language/module-code/early-dup-export-star-as-dflt.js', 37 | // import assert 38 | 'language/expressions/dynamic-import/syntax/invalid/nested-arrow-assignment-expression-not-extensible-args.js', 39 | 'language/expressions/dynamic-import/syntax/invalid/nested-arrow-not-extensible-args.js', 40 | 'language/expressions/dynamic-import/syntax/invalid/nested-async-arrow-function-await-not-extensible-args.js', 41 | 'language/expressions/dynamic-import/syntax/invalid/nested-async-arrow-function-return-await-not-extensible-args.js', 42 | 'language/expressions/dynamic-import/syntax/invalid/nested-async-function-await-not-extensible-args.js', 43 | 'language/expressions/dynamic-import/syntax/invalid/nested-async-function-not-extensible-args.js', 44 | 'language/expressions/dynamic-import/syntax/invalid/nested-async-function-return-await-not-extensible-args.js', 45 | 'language/expressions/dynamic-import/syntax/invalid/nested-async-gen-await-not-extensible-args.js', 46 | 'language/expressions/dynamic-import/syntax/invalid/nested-block-labeled-not-extensible-args.js', 47 | 'language/expressions/dynamic-import/syntax/invalid/nested-block-not-extensible-args.js', 48 | 'language/expressions/dynamic-import/syntax/invalid/nested-do-while-not-extensible-args.js', 49 | 'language/expressions/dynamic-import/syntax/invalid/nested-else-not-extensible-args.js', 50 | 'language/expressions/dynamic-import/syntax/invalid/nested-else-braceless-not-extensible-args.js', 51 | 'language/expressions/dynamic-import/syntax/invalid/nested-function-not-extensible-args.js', 52 | 'language/expressions/dynamic-import/syntax/invalid/nested-function-return-not-extensible-args.js', 53 | 'language/expressions/dynamic-import/syntax/invalid/nested-if-braceless-not-extensible-args.js', 54 | 'language/expressions/dynamic-import/syntax/invalid/nested-if-not-extensible-args.js', 55 | 'language/expressions/dynamic-import/syntax/invalid/nested-while-not-extensible-args.js', 56 | 'language/expressions/dynamic-import/syntax/invalid/top-level-not-extensible-args.js', 57 | ].flatMap((s) => [s + ' (default)', s + ' (strict mode)']) 58 | 59 | WHITELIST.push('language/expressions/dynamic-import/syntax/invalid/nested-with-expression-not-extensible-args.js (default)') 60 | WHITELIST.push('language/expressions/dynamic-import/syntax/invalid/nested-with-not-extensible-args.js (default)') 61 | 62 | run( 63 | (content, { sourceType }) => { 64 | return parser.parse(content, { 65 | sourceType, 66 | ecmaVersion: 'latest', 67 | locations: true 68 | }) 69 | }, 70 | { 71 | testsDirectory: path.dirname(require.resolve('test262/package.json')), 72 | skip: (test) => { 73 | return ( 74 | (test.attrs.features && 75 | UNSUPPORTED_FEATURES.some((f) => test.attrs.features.includes(f))) || 76 | SKIP_FILES.includes(test.file) 77 | ) 78 | }, 79 | whitelist: WHITELIST.map((filename) => 80 | path.sep === '/' ? filename : filename.split('/').join(path.sep) 81 | ) 82 | } 83 | ) 84 | -------------------------------------------------------------------------------- /__test__/satisfies/index.test.ts: -------------------------------------------------------------------------------- 1 | import { 2 | equalNode, 3 | parseSourceAllowSatisfies, 4 | parseSourceShouldThrowError 5 | } from '../utils' 6 | import SatisfiesSnapshot from '../__snapshot__/satisfies' 7 | 8 | describe('satisfies', function() { 9 | it('normal', function() { 10 | const node = parseSourceAllowSatisfies('const a = 1 satisfies any') 11 | 12 | equalNode(node, SatisfiesSnapshot.Normal) 13 | }) 14 | 15 | it('should error', function() { 16 | const res = parseSourceShouldThrowError( 17 | 'const a = 1 satisfies any', 18 | 'Unexpected token', 19 | '(1:12)' 20 | ) 21 | 22 | expect(res).toBe(true) 23 | }) 24 | }) 25 | -------------------------------------------------------------------------------- /__test__/static/plugin.test.ts: -------------------------------------------------------------------------------- 1 | import * as acorn from 'acorn' 2 | import tsPlugin from '../../src' 3 | import type { AcornTypeScript } from '../../src/types' 4 | 5 | function checkAcornTypeScriptUndefined(acornTypeScript?: AcornTypeScript): boolean { 6 | if (!acornTypeScript) return false 7 | 8 | return Boolean(acornTypeScript.tokTypes) 9 | && Boolean(acornTypeScript.keywordsRegExp) 10 | && Boolean(acornTypeScript.tokenIsLiteralPropertyName) 11 | && Boolean(acornTypeScript.tokenIsKeywordOrIdentifier) 12 | && Boolean(acornTypeScript.tokenIsIdentifier) 13 | && Boolean(acornTypeScript.tokenIsTSDeclarationStart) 14 | && Boolean(acornTypeScript.tokenIsTSTypeOperator) 15 | && Boolean(acornTypeScript.tokenIsTemplate) 16 | } 17 | 18 | function checkAcornTypeScriptEqual( 19 | acornTypeScriptOne?: AcornTypeScript, 20 | acornTypeScriptTwo?: AcornTypeScript 21 | ): boolean { 22 | if (!acornTypeScriptTwo || !acornTypeScriptOne) return false 23 | if ( 24 | !checkAcornTypeScriptUndefined(acornTypeScriptOne) || 25 | !checkAcornTypeScriptUndefined(acornTypeScriptTwo) 26 | ) return false 27 | 28 | return (acornTypeScriptOne.tokTypes === acornTypeScriptTwo.tokTypes) && 29 | (acornTypeScriptOne.keywordsRegExp === acornTypeScriptTwo.keywordsRegExp) && 30 | (acornTypeScriptOne.tokenIsLiteralPropertyName === acornTypeScriptTwo.tokenIsLiteralPropertyName) && 31 | (acornTypeScriptOne.tokenIsKeywordOrIdentifier === acornTypeScriptTwo.tokenIsKeywordOrIdentifier) && 32 | (acornTypeScriptOne.tokenIsIdentifier === acornTypeScriptTwo.tokenIsIdentifier) && 33 | (acornTypeScriptOne.tokenIsTSDeclarationStart === acornTypeScriptTwo.tokenIsTSDeclarationStart) && 34 | (acornTypeScriptOne.tokenIsTSTypeOperator === acornTypeScriptTwo.tokenIsTSTypeOperator) && 35 | (acornTypeScriptOne.tokenIsTemplate === acornTypeScriptTwo.tokenIsTemplate) 36 | } 37 | 38 | describe('static plugin', function() { 39 | it('acornTypeScript', function() { 40 | let acornTypeScript: any 41 | acorn.Parser.extend(tsPlugin(), function(BaseParser) { 42 | acornTypeScript = (BaseParser as any).acornTypeScript 43 | return BaseParser 44 | }) 45 | 46 | expect(checkAcornTypeScriptUndefined(acornTypeScript)).toBe(true) 47 | }) 48 | 49 | it('acornTypeScript in two plugins', function() { 50 | let acornTypeScriptOne: any 51 | let acornTypeScriptTwo: any 52 | acorn.Parser.extend(tsPlugin(), function(BaseParser) { 53 | acornTypeScriptOne = (BaseParser as any).acornTypeScript 54 | return BaseParser 55 | }, function(BaseParser) { 56 | acornTypeScriptTwo = (BaseParser as any).acornTypeScript 57 | return BaseParser 58 | }) 59 | 60 | expect( 61 | checkAcornTypeScriptEqual(acornTypeScriptOne, acornTypeScriptTwo) 62 | ).toBe(true) 63 | }) 64 | }) 65 | -------------------------------------------------------------------------------- /__test__/try/type.test.ts: -------------------------------------------------------------------------------- 1 | import { equalNode, generateSource, parseSource } from '../utils' 2 | import TryTypeSnapshot from '../__snapshot__/try' 3 | 4 | describe('try statement', function() { 5 | it('normal', function() { 6 | const node = parseSource(generateSource([ 7 | `try {`, 8 | ` console.log(123)`, 9 | `} catch(e) {}` 10 | ])) 11 | 12 | equalNode(node, TryTypeSnapshot.Normal) 13 | }) 14 | 15 | it('with type', function() { 16 | const node = parseSource(generateSource([ 17 | `try {`, 18 | ` console.log(123)`, 19 | `} catch(e: any) {}` 20 | ])) 21 | 22 | // console.log(JSON.stringify(node, null, 2)) 23 | equalNode(node, TryTypeSnapshot.WithType) 24 | }) 25 | 26 | it('catch redeclared var statement captured', function() { 27 | const node = parseSource(generateSource([ 28 | `try {`, 29 | ` throw new Error();`, 30 | `} catch (foo) {`, 31 | ` var foo = "initializer in catch";`, 32 | `}` 33 | ])) 34 | 35 | equalNode(node, TryTypeSnapshot.CatchRedeclaredVarStatementCaptured) 36 | }) 37 | }) 38 | -------------------------------------------------------------------------------- /__test__/utils.ts: -------------------------------------------------------------------------------- 1 | import * as acorn from 'acorn' 2 | import tsPlugin from '../src' 3 | 4 | export const Parser = acorn.Parser.extend(tsPlugin()) 5 | 6 | export const DtsParser = acorn.Parser.extend(tsPlugin({ 7 | dts: true 8 | })) 9 | 10 | export const AllowSatisfiesParser = acorn.Parser.extend(tsPlugin({ 11 | allowSatisfies: true 12 | })) 13 | 14 | export function equalNode(node, snapshot) { 15 | expect(node).toEqual(snapshot) 16 | } 17 | 18 | export function parseDtsSource(input: string) { 19 | return DtsParser.parse(input, { 20 | sourceType: 'module', 21 | ecmaVersion: 'latest', 22 | locations: true 23 | }) 24 | } 25 | 26 | export function parseSource(input: string) { 27 | return Parser.parse(input, { 28 | sourceType: 'module', 29 | ecmaVersion: 'latest', 30 | locations: true 31 | }) 32 | } 33 | 34 | export function parseSourceAllowSatisfies(input: string) { 35 | return AllowSatisfiesParser.parse(input, { 36 | sourceType: 'module', 37 | ecmaVersion: 'latest', 38 | locations: true 39 | }) 40 | } 41 | 42 | export function parseSourceShouldThrowError(input: string, message: string, loc: string): boolean { 43 | try { 44 | Parser.parse(input, { 45 | sourceType: 'module', 46 | ecmaVersion: 'latest', 47 | locations: true 48 | }) 49 | 50 | return false 51 | } catch (e) { 52 | // console.log(e.message) 53 | // console.log(`${message} ${loc}`) 54 | return e.message === `${message} ${loc}` 55 | } 56 | } 57 | 58 | export function generateSource(input: string[]): string { 59 | return input.join('\n') 60 | } 61 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | // For a detailed explanation regarding each configuration property, visit: 2 | // https://jestjs.io/docs/en/configuration.html 3 | 4 | module.exports = { 5 | // All imported modules in your tests should be mocked automatically 6 | // automock: false, 7 | 8 | // Stop running tests after `n` failures 9 | // bail: 0, 10 | 11 | // Respect "browser" field in package.json when resolving modules 12 | // browser: false, 13 | 14 | // The directory where Jest should store its cached dependency information 15 | // cacheDirectory: "/private/var/folders/h9/lgs7v_813jl7rdb_bfsqdw700000gn/T/jest_dx", 16 | 17 | // Automatically clear mock calls and instances between every test 18 | clearMocks: true, 19 | collectCoverageFrom: [ 20 | 'src/index.{js,ts}', 21 | ], 22 | 23 | // Indicates whether the coverage information should be collected while executing the test 24 | // collectCoverage: false, 25 | 26 | // An array of glob patterns indicating a set of files for which coverage information should be collected 27 | // collectCoverageFrom: null, 28 | 29 | // The directory where Jest should output its coverage files 30 | coverageDirectory: 'coverage', 31 | 32 | // An array of regexp pattern strings used to skip coverage collection 33 | coveragePathIgnorePatterns: ['/node_modules/', '/__test__/'], 34 | 35 | // A list of reporter names that Jest uses when writing coverage reports 36 | coverageReporters: ['json-summary', 'json', 'text', 'lcov', 'clover'], 37 | 38 | // An object that configures minimum threshold enforcement for coverage results 39 | // coverageThreshold: null, 40 | 41 | // A path to a custom dependency extractor 42 | // dependencyExtractor: null, 43 | 44 | // Make calling deprecated APIs throw helpful error messages 45 | // errorOnDeprecated: false, 46 | 47 | // Force coverage collection from ignored files usin a array of glob patterns 48 | // forceCoverageMatch: [], 49 | 50 | // A path to a module which exports an async function that is triggered once before all test suites 51 | // globalSetup: null, 52 | 53 | // A path to a module which exports an async function that is triggered once after all test suites 54 | // globalTeardown: null, 55 | 56 | // A set of global variables that need to be available in all test environments 57 | // globals: {}, 58 | 59 | // An array of directory names to be searched recursively up from the requiring module's location 60 | // moduleDirectories: [ 61 | // "node_modules" 62 | // ], 63 | 64 | // An array of file extensions your modules use 65 | // moduleFileExtensions: [ 66 | // "js", 67 | // "json", 68 | // "jsx", 69 | // "ts", 70 | // "tsx", 71 | // "node" 72 | // ], 73 | 74 | // A map from regular expressions to module names that allow to stub out resources with a single module 75 | // moduleNameMapper: {}, 76 | 77 | // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader 78 | // modulePathIgnorePatterns: [], 79 | 80 | // Activates notifications for test results 81 | // notify: false, 82 | 83 | // An enum that specifies notification mode. Requires { notify: true } 84 | // notifyMode: "failure-change", 85 | 86 | // A preset that is used as a base for Jest's configuration 87 | preset: 'ts-jest' 88 | 89 | // Run tests from one or more projects 90 | // projects: null, 91 | 92 | // Use this configuration option to add custom reporters to Jest 93 | // reporters: undefined, 94 | 95 | // Automatically reset mock state between every test 96 | // resetMocks: false, 97 | 98 | // Reset the module registry before running each individual test 99 | // resetModules: false, 100 | 101 | // A path to a custom resolver 102 | // resolver: null, 103 | 104 | // Automatically restore mock state between every test 105 | // restoreMocks: false, 106 | 107 | // The root directory that Jest should scan for tests and modules within 108 | // rootDir: null, 109 | 110 | // A list of paths to directories that Jest should use to search for files in 111 | // roots: [ 112 | // "" 113 | // ], 114 | 115 | // Allows you to use a custom runner instead of Jest's default test runner 116 | // runner: "jest-runner", 117 | 118 | // The paths to modules that run some code to configure or set up the testing environment before each test 119 | // setupFiles: [], 120 | 121 | // A list of paths to modules that run some code to configure or set up the testing framework before each test 122 | // setupFilesAfterEnv: [], 123 | 124 | // A list of paths to snapshot serializer modules Jest should use for snapshot testing 125 | // snapshotSerializers: [], 126 | 127 | // The test environment that will be used for testing 128 | // testEnvironment: "jest-environment-jsdom", 129 | 130 | // Options that will be passed to the testEnvironment 131 | // testEnvironmentOptions: {}, 132 | 133 | // Adds a location field to test results 134 | // testLocationInResults: false, 135 | 136 | // The glob patterns Jest uses to detect test files 137 | // ,testMatch: [ 138 | // "**/__test__/**/react.spec.[jt]s?(x)", 139 | // // "**/?(*.)+(spec|test).[tj]s?(x)" 140 | // ], 141 | 142 | // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped 143 | // testPathIgnorePatterns: [ 144 | // "/node_modules/" 145 | // ], 146 | 147 | // The regexp pattern or array of patterns that Jest uses to detect test files 148 | // testRegex: [], 149 | 150 | // This option allows the use of a custom results processor 151 | // testResultsProcessor: null, 152 | 153 | // This option allows use of a custom test runner 154 | // testRunner: "jasmine2", 155 | 156 | // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href 157 | // testURL: "http://localhost", 158 | 159 | // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" 160 | // timers: "real", 161 | 162 | // A map from regular expressions to paths to transformers 163 | // transform: null, 164 | 165 | // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation 166 | // transformIgnorePatterns: [ 167 | // "/node_modules/" 168 | // ], 169 | 170 | // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them 171 | // unmockedModulePathPatterns: undefined, 172 | 173 | // Indicates whether each individual test should be reported during the run 174 | // verbose: null, 175 | 176 | // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode 177 | // watchPathIgnorePatterns: [], 178 | 179 | // Whether to use watchman for file crawling 180 | // watchman: true, 181 | } 182 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "acorn-typescript", 3 | "version": "1.4.13", 4 | "description": "Alternative, TypeScript parser", 5 | "source": "src/index.ts", 6 | "main": "lib/index.js", 7 | "module": "lib/index.mjs", 8 | "types": "lib/index.d.ts", 9 | "scripts": { 10 | "build": "microbundle --define process.env.NODE_ENV=production --no-sourcemap --tsconfig ./tsconfig.json --format esm,cjs", 11 | "test": "jest --collect-coverage --silent", 12 | "test:test262": "ts-node -T __test__/run_test262.ts", 13 | "release-major": "yarn build && yarn test && standard-version --release-as major", 14 | "release-minor": "yarn build && yarn test && standard-version --release-as minor", 15 | "release-patch": "yarn build && yarn test && standard-version --release-as patch" 16 | }, 17 | "exports": { 18 | ".": [ 19 | { 20 | "import": "./lib/index.mjs", 21 | "require": "./lib/index.js", 22 | "default": "./lib/index.js" 23 | }, 24 | "./lib/index.js" 25 | ] 26 | }, 27 | "repository": { 28 | "type": "git", 29 | "url": "git+https://github.com/TyrealHu/acorn-typescript.git" 30 | }, 31 | "author": "tyrealhu", 32 | "license": "MIT", 33 | "bugs": { 34 | "url": "https://github.com/TyrealHu/acorn-typescript/issues" 35 | }, 36 | "homepage": "https://github.com/TyrealHu/acorn-typescript#readme", 37 | "devDependencies": { 38 | "@types/jest": "^24.1.0", 39 | "acorn": "^8.9.0", 40 | "acorn-jsx": "^5.3.2", 41 | "jest": "^24.1.0", 42 | "microbundle": "^0.15.1", 43 | "standard-version": "^9.5.0", 44 | "ts-jest": "^26.0.0", 45 | "ts-node": "^10.9.1", 46 | "typescript": "^4.8.4", 47 | "test262": "git+https://github.com/tc39/test262.git#dac69563480b9f22709fd49d61a32b3a0513b6b1", 48 | "test262-parser-runner": "^0.5.0" 49 | }, 50 | "peerDependencies": { 51 | "acorn": ">=8.9.0" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/error.ts: -------------------------------------------------------------------------------- 1 | export const TypeScriptError = { 2 | AbstractMethodHasImplementation: ({ methodName }) => 3 | `Method '${methodName}' cannot have an implementation because it is marked abstract.`, 4 | AbstractPropertyHasInitializer: ({ 5 | propertyName 6 | }) => 7 | `Property '${propertyName}' cannot have an initializer because it is marked abstract.`, 8 | AccesorCannotDeclareThisParameter: 9 | '\'get\' and \'set\' accessors cannot declare \'this\' parameters.', 10 | AccesorCannotHaveTypeParameters: 'An accessor cannot have type parameters.', 11 | CannotFindName: ({ name }) => `Cannot find name '${name}'.`, 12 | ClassMethodHasDeclare: 'Class methods cannot have the \'declare\' modifier.', 13 | ClassMethodHasReadonly: 'Class methods cannot have the \'readonly\' modifier.', 14 | ConstInitiailizerMustBeStringOrNumericLiteralOrLiteralEnumReference: 15 | 'A \'const\' initializer in an ambient context must be a string or numeric literal or literal enum reference.', 16 | ConstructorHasTypeParameters: 17 | 'Type parameters cannot appear on a constructor declaration.', 18 | DeclareAccessor: ({ kind }) => 19 | `'declare' is not allowed in ${kind}ters.`, 20 | DeclareClassFieldHasInitializer: 21 | 'Initializers are not allowed in ambient contexts.', 22 | DeclareFunctionHasImplementation: 23 | 'An implementation cannot be declared in ambient contexts.', 24 | DuplicateAccessibilityModifier: 25 | // `Accessibility modifier already seen: ${modifier}` would be more helpful. 26 | // eslint-disable-next-line @typescript-eslint/no-unused-vars 27 | () => 28 | `Accessibility modifier already seen.`, 29 | DuplicateModifier: ({ modifier }) => 30 | `Duplicate modifier: '${modifier}'.`, 31 | // `token` matches the terminology used by typescript: 32 | // https://github.com/microsoft/TypeScript/blob/main/src/compiler/types.ts#L2915 33 | EmptyHeritageClauseType: ({ token }) => 34 | `'${token}' list cannot be empty.`, 35 | EmptyTypeArguments: 'Type argument list cannot be empty.', 36 | EmptyTypeParameters: 'Type parameter list cannot be empty.', 37 | ExpectedAmbientAfterExportDeclare: 38 | '\'export declare\' must be followed by an ambient declaration.', 39 | ImportAliasHasImportType: 'An import alias can not use \'import type\'.', 40 | IncompatibleModifiers: ({ 41 | modifiers 42 | 43 | }) => 44 | `'${modifiers[0]}' modifier cannot be used with '${modifiers[1]}' modifier.`, 45 | IndexSignatureHasAbstract: 46 | 'Index signatures cannot have the \'abstract\' modifier.', 47 | IndexSignatureHasAccessibility: ({ 48 | modifier 49 | }) => 50 | `Index signatures cannot have an accessibility modifier ('${modifier}').`, 51 | IndexSignatureHasDeclare: 52 | 'Index signatures cannot have the \'declare\' modifier.', 53 | IndexSignatureHasOverride: 54 | '\'override\' modifier cannot appear on an index signature.', 55 | IndexSignatureHasStatic: 56 | 'Index signatures cannot have the \'static\' modifier.', 57 | InitializerNotAllowedInAmbientContext: 58 | 'Initializers are not allowed in ambient contexts.', 59 | InvalidModifierOnTypeMember: ({ modifier }) => 60 | `'${modifier}' modifier cannot appear on a type member.`, 61 | InvalidModifierOnTypeParameter: ({ modifier }) => 62 | `'${modifier}' modifier cannot appear on a type parameter.`, 63 | InvalidModifierOnTypeParameterPositions: ({ 64 | modifier 65 | }) => 66 | `'${modifier}' modifier can only appear on a type parameter of a class, interface or type alias.`, 67 | InvalidModifiersOrder: ({ 68 | orderedModifiers 69 | }) => 70 | `'${orderedModifiers[0]}' modifier must precede '${orderedModifiers[1]}' modifier.`, 71 | InvalidPropertyAccessAfterInstantiationExpression: 72 | 'Invalid property access after an instantiation expression. ' + 73 | 'You can either wrap the instantiation expression in parentheses, or delete the type arguments.', 74 | InvalidTupleMemberLabel: 75 | 'Tuple members must be labeled with a simple identifier.', 76 | MissingInterfaceName: 77 | '\'interface\' declarations must be followed by an identifier.', 78 | MixedLabeledAndUnlabeledElements: 79 | 'Tuple members must all have names or all not have names.', 80 | NonAbstractClassHasAbstractMethod: 81 | 'Abstract methods can only appear within an abstract class.', 82 | NonClassMethodPropertyHasAbstractModifer: 83 | '\'abstract\' modifier can only appear on a class, method, or property declaration.', 84 | OptionalTypeBeforeRequired: 85 | 'A required element cannot follow an optional element.', 86 | OverrideNotInSubClass: 87 | 'This member cannot have an \'override\' modifier because its containing class does not extend another class.', 88 | PatternIsOptional: 89 | 'A binding pattern parameter cannot be optional in an implementation signature.', 90 | PrivateElementHasAbstract: 91 | 'Private elements cannot have the \'abstract\' modifier.', 92 | PrivateElementHasAccessibility: ({ 93 | modifier 94 | }) => 95 | `Private elements cannot have an accessibility modifier ('${modifier}').`, 96 | PrivateMethodsHasAccessibility: ({ 97 | modifier 98 | }) => 99 | `Private methods cannot have an accessibility modifier ('${modifier}').`, 100 | ReadonlyForMethodSignature: 101 | '\'readonly\' modifier can only appear on a property declaration or index signature.', 102 | ReservedArrowTypeParam: 103 | 'This syntax is reserved in files with the .mts or .cts extension. Add a trailing comma, as in `() => ...`.', 104 | ReservedTypeAssertion: 105 | 'This syntax is reserved in files with the .mts or .cts extension. Use an `as` expression instead.', 106 | SetAccesorCannotHaveOptionalParameter: 107 | 'A \'set\' accessor cannot have an optional parameter.', 108 | SetAccesorCannotHaveRestParameter: 109 | 'A \'set\' accessor cannot have rest parameter.', 110 | SetAccesorCannotHaveReturnType: 111 | 'A \'set\' accessor cannot have a return type annotation.', 112 | SingleTypeParameterWithoutTrailingComma: ({ typeParameterName }) => 113 | `Single type parameter ${typeParameterName} should have a trailing comma. Example usage: <${typeParameterName},>.`, 114 | StaticBlockCannotHaveModifier: 115 | 'Static class blocks cannot have any modifier.', 116 | TypeAnnotationAfterAssign: 117 | 'Type annotations must come before default assignments, e.g. instead of `age = 25: number` use `age: number = 25`.', 118 | TypeImportCannotSpecifyDefaultAndNamed: 119 | 'A type-only import can specify a default import or named bindings, but not both.', 120 | TypeModifierIsUsedInTypeExports: 121 | 'The \'type\' modifier cannot be used on a named export when \'export type\' is used on its export statement.', 122 | TypeModifierIsUsedInTypeImports: 123 | 'The \'type\' modifier cannot be used on a named import when \'import type\' is used on its import statement.', 124 | UnexpectedParameterModifier: 125 | 'A parameter property is only allowed in a constructor implementation.', 126 | UnexpectedReadonly: 127 | '\'readonly\' type modifier is only permitted on array and tuple literal types.', 128 | GenericsEndWithComma: `Trailing comma is not allowed at the end of generics.`, 129 | UnexpectedTypeAnnotation: 'Did not expect a type annotation here.', 130 | UnexpectedTypeCastInParameter: 'Unexpected type cast in parameter position.', 131 | UnsupportedImportTypeArgument: 132 | 'Argument in a type import must be a string literal.', 133 | UnsupportedParameterPropertyKind: 134 | 'A parameter property may not be declared using a binding pattern.', 135 | UnsupportedSignatureParameterKind: ({ type }) => 136 | `Name in a signature must be an Identifier, ObjectPattern or ArrayPattern, instead got ${type}.`, 137 | LetInLexicalBinding: 138 | '\'let\' is not allowed to be used as a name in \'let\' or \'const\' declarations.' 139 | } 140 | 141 | export const DecoratorsError = { 142 | UnexpectedLeadingDecorator: 'Leading decorators must be attached to a class declaration.', 143 | DecoratorConstructor: 144 | 'Decorators can\'t be used with a constructor. Did you mean \'@dec class { ... }\'?', 145 | TrailingDecorator: 'Decorators must be attached to a class element.', 146 | SpreadElementDecorator: `Decorators can't be used with SpreadElement` 147 | } 148 | -------------------------------------------------------------------------------- /src/extentions/decorators.ts: -------------------------------------------------------------------------------- 1 | import { DecoratorsError } from '../error' 2 | import type { AcornParseClass } from '../middleware' 3 | import type { AcornTypeScript } from '../types' 4 | import type * as acornNamespace from 'acorn' 5 | 6 | export default function generateParseDecorators( 7 | Parse: typeof AcornParseClass, 8 | acornTypeScript: AcornTypeScript, 9 | acorn: typeof acornNamespace 10 | ) { 11 | const { tokTypes: tt } = acorn 12 | const { tokTypes } = acornTypeScript 13 | return class ParseDecorators extends Parse { 14 | takeDecorators(node: any): void { 15 | const decorators = 16 | this.decoratorStack[this.decoratorStack.length - 1] 17 | if (decorators.length) { 18 | node.decorators = decorators 19 | this.resetStartLocationFromNode(node, decorators[0]) 20 | this.decoratorStack[this.decoratorStack.length - 1] = [] 21 | } 22 | } 23 | 24 | parseDecorators(allowExport?: boolean): void { 25 | const currentContextDecorators = this.decoratorStack[this.decoratorStack.length - 1] 26 | while (this.match(tokTypes.at)) { 27 | const decorator = this.parseDecorator() 28 | currentContextDecorators.push(decorator) 29 | } 30 | 31 | if (this.match(tt._export)) { 32 | if (!allowExport) { 33 | this.unexpected() 34 | } 35 | 36 | } else if (!this.canHaveLeadingDecorator()) { 37 | this.raise(this.start, DecoratorsError.UnexpectedLeadingDecorator) 38 | } 39 | } 40 | 41 | parseDecorator(): any { 42 | const node = this.startNode() 43 | this.next() 44 | 45 | // Every time a decorator class expression is evaluated, a new empty array is pushed onto the stack 46 | // So that the decorators of any nested class expressions will be dealt with separately 47 | this.decoratorStack.push([]) 48 | 49 | const startPos = this.start 50 | const startLoc = this.startLoc 51 | let expr: any 52 | 53 | if (this.match(tt.parenL)) { 54 | const startPos = this.start 55 | const startLoc = this.startLoc 56 | this.next() // eat '(' 57 | expr = this.parseExpression() 58 | this.expect(tt.parenR) 59 | 60 | if (this.options.preserveParens) { 61 | let par = this.startNodeAt(startPos, startLoc) 62 | par.expression = expr 63 | expr = this.finishNode(par, 'ParenthesizedExpression') 64 | } 65 | } else { 66 | expr = this.parseIdent(false) 67 | 68 | while (this.eat(tt.dot)) { 69 | const node = this.startNodeAt(startPos, startLoc) 70 | node.object = expr 71 | node.property = this.parseIdent(true) 72 | node.computed = false 73 | expr = this.finishNode(node, 'MemberExpression') 74 | } 75 | } 76 | 77 | node.expression = this.parseMaybeDecoratorArguments(expr) 78 | this.decoratorStack.pop() 79 | 80 | return this.finishNode(node, 'Decorator') 81 | } 82 | 83 | parseMaybeDecoratorArguments(expr: any): any { 84 | if (this.eat(tt.parenL)) { 85 | const node = this.startNodeAtNode(expr) 86 | node.callee = expr 87 | node.arguments = this.parseExprList(tt.parenR, false) 88 | return this.finishNode(node, 'CallExpression') 89 | } 90 | 91 | return expr 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/extentions/import-assertions.ts: -------------------------------------------------------------------------------- 1 | import { AcornParseClass } from '../middleware' 2 | import { AcornTypeScript } from '../types' 3 | import * as acornNamespace from 'acorn' 4 | 5 | export default function generateParseImportAssertions( 6 | Parse: typeof AcornParseClass, 7 | acornTypeScript: AcornTypeScript, 8 | acorn: typeof acornNamespace 9 | ) { 10 | const { tokTypes } = acornTypeScript 11 | const { tokTypes: tt } = acorn 12 | return class ImportAttributes extends Parse { 13 | parseMaybeImportAttributes(node) { 14 | // import assertions 15 | if (this.type === tt._with || this.type === tokTypes.assert) { 16 | this.next() 17 | const attributes = this.parseImportAttributes() 18 | if (attributes) { 19 | node.attributes = attributes 20 | } 21 | } 22 | } 23 | 24 | parseImportAttributes() { 25 | this.expect(tt.braceL) 26 | const attrs = this.parseWithEntries() 27 | this.expect(tt.braceR) 28 | return attrs 29 | } 30 | 31 | parseWithEntries() { 32 | const attrs = [] 33 | const attrNames = new Set() 34 | 35 | do { 36 | if (this.type === tt.braceR) { 37 | break 38 | } 39 | 40 | const node = this.startNode() 41 | 42 | // parse withionKey : IdentifierName, StringLiteral 43 | let withionKeyNode 44 | if (this.type === tt.string) { 45 | withionKeyNode = this.parseLiteral(this.value) 46 | } else { 47 | withionKeyNode = this.parseIdent(true) 48 | } 49 | this.next() 50 | node.key = withionKeyNode 51 | 52 | // check if we already have an entry for an attribute 53 | // if a duplicate entry is found, throw an error 54 | // for now this logic will come into play only when someone declares `type` twice 55 | if (attrNames.has(node.key.name)) { 56 | this.raise(this.pos, 'Duplicated key in attributes') 57 | } 58 | attrNames.add(node.key.name) 59 | 60 | if (this.type !== tt.string) { 61 | this.raise( 62 | this.pos, 63 | 'Only string is supported as an attribute value' 64 | ) 65 | } 66 | 67 | node.value = this.parseLiteral(this.value) 68 | 69 | attrs.push(this.finishNode(node, 'ImportAttribute')) 70 | } while (this.eat(tt.comma)) 71 | 72 | return attrs 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /src/extentions/jsx/index.ts: -------------------------------------------------------------------------------- 1 | import XHTMLEntities from './xhtml' 2 | import type { AcornParseClass } from '../../middleware' 3 | import type { AcornTypeScript } from '../../types' 4 | import type * as acornNamespace from 'acorn' 5 | 6 | const hexNumber = /^[\da-fA-F]+$/ 7 | const decimalNumber = /^\d+$/ 8 | 9 | // Transforms JSX element name to string. 10 | 11 | function getQualifiedJSXName(object) { 12 | if (!object) 13 | return object 14 | 15 | if (object.type === 'JSXIdentifier') 16 | return object.name 17 | 18 | if (object.type === 'JSXNamespacedName') 19 | return object.namespace.name + ':' + object.name.name 20 | 21 | if (object.type === 'JSXMemberExpression') 22 | return getQualifiedJSXName(object.object) + '.' + 23 | getQualifiedJSXName(object.property) 24 | } 25 | 26 | 27 | /** 28 | * 29 | * { 30 | * allowNamespaces: options.allowNamespaces !== false, 31 | * allowNamespacedObjects: !!options.allowNamespacedObjects 32 | * } 33 | * */ 34 | export default function generateJsxParser( 35 | acorn: typeof acornNamespace, 36 | acornTypeScript: AcornTypeScript, 37 | Parser: typeof AcornParseClass, 38 | jsxOptions?: { 39 | allowNamespaces?: boolean, 40 | allowNamespacedObjects?: boolean 41 | } 42 | ) { 43 | const tt = acorn.tokTypes 44 | const tok = acornTypeScript.tokTypes 45 | const isNewLine = acorn.isNewLine 46 | const isIdentifierChar = acorn.isIdentifierChar 47 | const options = Object.assign({ 48 | allowNamespaces: true, 49 | allowNamespacedObjects: true 50 | }, jsxOptions || {}) 51 | 52 | return class JsxParser extends Parser { 53 | // Reads inline JSX contents token. 54 | jsx_readToken() { 55 | let out = '', chunkStart = this.pos 56 | for (; ;) { 57 | if (this.pos >= this.input.length) 58 | this.raise(this.start, 'Unterminated JSX contents') 59 | let ch = this.input.charCodeAt(this.pos) 60 | 61 | switch (ch) { 62 | case 60: // '<' 63 | case 123: // '{' 64 | if (this.pos === this.start) { 65 | if (ch === 60 && this.exprAllowed) { 66 | ++this.pos 67 | return this.finishToken(tok.jsxTagStart) 68 | } 69 | return this.getTokenFromCode(ch) 70 | } 71 | out += this.input.slice(chunkStart, this.pos) 72 | return this.finishToken(tok.jsxText, out) 73 | 74 | case 38: // '&' 75 | out += this.input.slice(chunkStart, this.pos) 76 | out += this.jsx_readEntity() 77 | chunkStart = this.pos 78 | break 79 | 80 | case 62: // '>' 81 | case 125: // '}' 82 | this.raise( 83 | this.pos, 84 | 'Unexpected token `' + this.input[this.pos] + '`. Did you mean `' + 85 | (ch === 62 ? '>' : '}') + '` or ' + '`{"' + this.input[this.pos] + '"}' + '`?' 86 | ) 87 | 88 | default: 89 | if (isNewLine(ch)) { 90 | out += this.input.slice(chunkStart, this.pos) 91 | out += this.jsx_readNewLine(true) 92 | chunkStart = this.pos 93 | } else { 94 | ++this.pos 95 | } 96 | } 97 | } 98 | } 99 | 100 | jsx_readNewLine(normalizeCRLF) { 101 | let ch = this.input.charCodeAt(this.pos) 102 | let out 103 | ++this.pos 104 | if (ch === 13 && this.input.charCodeAt(this.pos) === 10) { 105 | ++this.pos 106 | out = normalizeCRLF ? '\n' : '\r\n' 107 | } else { 108 | out = String.fromCharCode(ch) 109 | } 110 | if (this.options.locations) { 111 | ++this.curLine 112 | this.lineStart = this.pos 113 | } 114 | 115 | return out 116 | } 117 | 118 | jsx_readString(quote) { 119 | let out = '', chunkStart = ++this.pos 120 | for (; ;) { 121 | if (this.pos >= this.input.length) 122 | this.raise(this.start, 'Unterminated string constant') 123 | let ch = this.input.charCodeAt(this.pos) 124 | if (ch === quote) break 125 | if (ch === 38) { // '&' 126 | out += this.input.slice(chunkStart, this.pos) 127 | out += this.jsx_readEntity() 128 | chunkStart = this.pos 129 | } else if (isNewLine(ch)) { 130 | out += this.input.slice(chunkStart, this.pos) 131 | out += this.jsx_readNewLine(false) 132 | chunkStart = this.pos 133 | } else { 134 | ++this.pos 135 | } 136 | } 137 | out += this.input.slice(chunkStart, this.pos++) 138 | return this.finishToken(tt.string, out) 139 | } 140 | 141 | jsx_readEntity() { 142 | let str = '', count = 0, entity 143 | let ch = this.input[this.pos] 144 | if (ch !== '&') 145 | this.raise(this.pos, 'Entity must start with an ampersand') 146 | let startPos = ++this.pos 147 | while (this.pos < this.input.length && count++ < 10) { 148 | ch = this.input[this.pos++] 149 | if (ch === ';') { 150 | if (str[0] === '#') { 151 | if (str[1] === 'x') { 152 | str = str.substr(2) 153 | if (hexNumber.test(str)) 154 | entity = String.fromCharCode(parseInt(str, 16)) 155 | } else { 156 | str = str.substr(1) 157 | if (decimalNumber.test(str)) 158 | entity = String.fromCharCode(parseInt(str, 10)) 159 | } 160 | } else { 161 | entity = XHTMLEntities[str] 162 | } 163 | break 164 | } 165 | str += ch 166 | } 167 | if (!entity) { 168 | this.pos = startPos 169 | return '&' 170 | } 171 | return entity 172 | } 173 | 174 | // Read a JSX identifier (valid tag or attribute name). 175 | // 176 | // Optimized version since JSX identifiers can't contain 177 | // escape characters and so can be read as single slice. 178 | // Also assumes that first character was already checked 179 | // by isIdentifierStart in readToken. 180 | 181 | jsx_readWord() { 182 | let ch, start = this.pos 183 | do { 184 | ch = this.input.charCodeAt(++this.pos) 185 | } while (isIdentifierChar(ch) || ch === 45) // '-' 186 | return this.finishToken(tok.jsxName, this.input.slice(start, this.pos)) 187 | } 188 | 189 | // Parse next token as JSX identifier 190 | 191 | jsx_parseIdentifier() { 192 | let node = this.startNode() 193 | if (this.type === tok.jsxName) 194 | node.name = this.value 195 | else if (this.type.keyword) 196 | node.name = this.type.keyword 197 | else 198 | this.unexpected() 199 | this.next() 200 | return this.finishNode(node, 'JSXIdentifier') 201 | } 202 | 203 | // Parse namespaced identifier. 204 | 205 | jsx_parseNamespacedName() { 206 | let startPos = this.start, startLoc = this.startLoc 207 | let name = this.jsx_parseIdentifier() 208 | if (!options.allowNamespaces || !this.eat(tt.colon)) return name 209 | var node = this.startNodeAt(startPos, startLoc) 210 | node.namespace = name 211 | node.name = this.jsx_parseIdentifier() 212 | return this.finishNode(node, 'JSXNamespacedName') 213 | } 214 | 215 | // Parses element name in any form - namespaced, member 216 | // or single identifier. 217 | 218 | jsx_parseElementName() { 219 | if (this.type === tok.jsxTagEnd) return '' 220 | let startPos = this.start, startLoc = this.startLoc 221 | let node = this.jsx_parseNamespacedName() 222 | if (this.type === tt.dot && node.type === 'JSXNamespacedName' && !options.allowNamespacedObjects) { 223 | this.unexpected() 224 | } 225 | while (this.eat(tt.dot)) { 226 | let newNode = this.startNodeAt(startPos, startLoc) 227 | newNode.object = node 228 | newNode.property = this.jsx_parseIdentifier() 229 | node = this.finishNode(newNode, 'JSXMemberExpression') 230 | } 231 | return node 232 | } 233 | 234 | // Parses any type of JSX attribute value. 235 | 236 | jsx_parseAttributeValue() { 237 | switch (this.type) { 238 | case tt.braceL: 239 | let node = this.jsx_parseExpressionContainer() 240 | if (node.expression.type === 'JSXEmptyExpression') 241 | this.raise(node.start, 'JSX attributes must only be assigned a non-empty expression') 242 | return node 243 | 244 | case tok.jsxTagStart: 245 | case tt.string: 246 | return this.parseExprAtom() 247 | 248 | default: 249 | this.raise(this.start, 'JSX value should be either an expression or a quoted JSX text') 250 | } 251 | } 252 | 253 | // JSXEmptyExpression is unique type since it doesn't actually parse anything, 254 | // and so it should start at the end of last read token (left brace) and finish 255 | // at the beginning of the next one (right brace). 256 | 257 | jsx_parseEmptyExpression() { 258 | let node = this.startNodeAt(this.lastTokEnd, this.lastTokEndLoc) 259 | return this.finishNodeAt(node, 'JSXEmptyExpression', this.start, this.startLoc) 260 | } 261 | 262 | // Parses JSX expression enclosed into curly brackets. 263 | 264 | jsx_parseExpressionContainer(): any { 265 | let node = this.startNode() 266 | this.next() 267 | node.expression = this.type === tt.braceR 268 | ? this.jsx_parseEmptyExpression() 269 | : this.parseExpression() 270 | this.expect(tt.braceR) 271 | return this.finishNode(node, 'JSXExpressionContainer') 272 | } 273 | 274 | // Parses following JSX attribute name-value pair. 275 | 276 | jsx_parseAttribute() { 277 | let node = this.startNode() 278 | if (this.eat(tt.braceL)) { 279 | this.expect(tt.ellipsis) 280 | node.argument = this.parseMaybeAssign() 281 | this.expect(tt.braceR) 282 | return this.finishNode(node, 'JSXSpreadAttribute') 283 | } 284 | node.name = this.jsx_parseNamespacedName() 285 | node.value = this.eat(tt.eq) ? this.jsx_parseAttributeValue() : null 286 | return this.finishNode(node, 'JSXAttribute') 287 | } 288 | 289 | // Parses JSX opening tag starting after '<'. 290 | 291 | jsx_parseOpeningElementAt(startPos, startLoc): any { 292 | let node = this.startNodeAt(startPos, startLoc) 293 | node.attributes = [] 294 | let nodeName = this.jsx_parseElementName() 295 | if (nodeName) node.name = nodeName 296 | while (this.type !== tt.slash && this.type !== tok.jsxTagEnd) 297 | node.attributes.push(this.jsx_parseAttribute()) 298 | node.selfClosing = this.eat(tt.slash) 299 | this.expect(tok.jsxTagEnd) 300 | return this.finishNode(node, nodeName ? 'JSXOpeningElement' : 'JSXOpeningFragment') 301 | } 302 | 303 | // Parses JSX closing tag starting after '') 352 | } 353 | } 354 | let fragmentOrElement = openingElement.name ? 'Element' : 'Fragment' 355 | 356 | node['opening' + fragmentOrElement] = openingElement 357 | node['closing' + fragmentOrElement] = closingElement 358 | node.children = children 359 | if (this.type === tt.relational && this.value === '<') { 360 | this.raise(this.start, 'Adjacent JSX elements must be wrapped in an enclosing tag') 361 | } 362 | return this.finishNode(node, 'JSX' + fragmentOrElement) 363 | } 364 | 365 | // Parse JSX text 366 | 367 | jsx_parseText() { 368 | let node = this.parseLiteral(this.value) 369 | node.type = 'JSXText' 370 | return node 371 | } 372 | 373 | // Parses entire JSX element from current position. 374 | 375 | jsx_parseElement() { 376 | let startPos = this.start, startLoc = this.startLoc 377 | this.next() 378 | return this.jsx_parseElementAt(startPos, startLoc) 379 | } 380 | } 381 | } 382 | -------------------------------------------------------------------------------- /src/extentions/jsx/xhtml.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | quot: '\u0022', 3 | amp: '&', 4 | apos: '\u0027', 5 | lt: '<', 6 | gt: '>', 7 | nbsp: '\u00A0', 8 | iexcl: '\u00A1', 9 | cent: '\u00A2', 10 | pound: '\u00A3', 11 | curren: '\u00A4', 12 | yen: '\u00A5', 13 | brvbar: '\u00A6', 14 | sect: '\u00A7', 15 | uml: '\u00A8', 16 | copy: '\u00A9', 17 | ordf: '\u00AA', 18 | laquo: '\u00AB', 19 | not: '\u00AC', 20 | shy: '\u00AD', 21 | reg: '\u00AE', 22 | macr: '\u00AF', 23 | deg: '\u00B0', 24 | plusmn: '\u00B1', 25 | sup2: '\u00B2', 26 | sup3: '\u00B3', 27 | acute: '\u00B4', 28 | micro: '\u00B5', 29 | para: '\u00B6', 30 | middot: '\u00B7', 31 | cedil: '\u00B8', 32 | sup1: '\u00B9', 33 | ordm: '\u00BA', 34 | raquo: '\u00BB', 35 | frac14: '\u00BC', 36 | frac12: '\u00BD', 37 | frac34: '\u00BE', 38 | iquest: '\u00BF', 39 | Agrave: '\u00C0', 40 | Aacute: '\u00C1', 41 | Acirc: '\u00C2', 42 | Atilde: '\u00C3', 43 | Auml: '\u00C4', 44 | Aring: '\u00C5', 45 | AElig: '\u00C6', 46 | Ccedil: '\u00C7', 47 | Egrave: '\u00C8', 48 | Eacute: '\u00C9', 49 | Ecirc: '\u00CA', 50 | Euml: '\u00CB', 51 | Igrave: '\u00CC', 52 | Iacute: '\u00CD', 53 | Icirc: '\u00CE', 54 | Iuml: '\u00CF', 55 | ETH: '\u00D0', 56 | Ntilde: '\u00D1', 57 | Ograve: '\u00D2', 58 | Oacute: '\u00D3', 59 | Ocirc: '\u00D4', 60 | Otilde: '\u00D5', 61 | Ouml: '\u00D6', 62 | times: '\u00D7', 63 | Oslash: '\u00D8', 64 | Ugrave: '\u00D9', 65 | Uacute: '\u00DA', 66 | Ucirc: '\u00DB', 67 | Uuml: '\u00DC', 68 | Yacute: '\u00DD', 69 | THORN: '\u00DE', 70 | szlig: '\u00DF', 71 | agrave: '\u00E0', 72 | aacute: '\u00E1', 73 | acirc: '\u00E2', 74 | atilde: '\u00E3', 75 | auml: '\u00E4', 76 | aring: '\u00E5', 77 | aelig: '\u00E6', 78 | ccedil: '\u00E7', 79 | egrave: '\u00E8', 80 | eacute: '\u00E9', 81 | ecirc: '\u00EA', 82 | euml: '\u00EB', 83 | igrave: '\u00EC', 84 | iacute: '\u00ED', 85 | icirc: '\u00EE', 86 | iuml: '\u00EF', 87 | eth: '\u00F0', 88 | ntilde: '\u00F1', 89 | ograve: '\u00F2', 90 | oacute: '\u00F3', 91 | ocirc: '\u00F4', 92 | otilde: '\u00F5', 93 | ouml: '\u00F6', 94 | divide: '\u00F7', 95 | oslash: '\u00F8', 96 | ugrave: '\u00F9', 97 | uacute: '\u00FA', 98 | ucirc: '\u00FB', 99 | uuml: '\u00FC', 100 | yacute: '\u00FD', 101 | thorn: '\u00FE', 102 | yuml: '\u00FF', 103 | OElig: '\u0152', 104 | oelig: '\u0153', 105 | Scaron: '\u0160', 106 | scaron: '\u0161', 107 | Yuml: '\u0178', 108 | fnof: '\u0192', 109 | circ: '\u02C6', 110 | tilde: '\u02DC', 111 | Alpha: '\u0391', 112 | Beta: '\u0392', 113 | Gamma: '\u0393', 114 | Delta: '\u0394', 115 | Epsilon: '\u0395', 116 | Zeta: '\u0396', 117 | Eta: '\u0397', 118 | Theta: '\u0398', 119 | Iota: '\u0399', 120 | Kappa: '\u039A', 121 | Lambda: '\u039B', 122 | Mu: '\u039C', 123 | Nu: '\u039D', 124 | Xi: '\u039E', 125 | Omicron: '\u039F', 126 | Pi: '\u03A0', 127 | Rho: '\u03A1', 128 | Sigma: '\u03A3', 129 | Tau: '\u03A4', 130 | Upsilon: '\u03A5', 131 | Phi: '\u03A6', 132 | Chi: '\u03A7', 133 | Psi: '\u03A8', 134 | Omega: '\u03A9', 135 | alpha: '\u03B1', 136 | beta: '\u03B2', 137 | gamma: '\u03B3', 138 | delta: '\u03B4', 139 | epsilon: '\u03B5', 140 | zeta: '\u03B6', 141 | eta: '\u03B7', 142 | theta: '\u03B8', 143 | iota: '\u03B9', 144 | kappa: '\u03BA', 145 | lambda: '\u03BB', 146 | mu: '\u03BC', 147 | nu: '\u03BD', 148 | xi: '\u03BE', 149 | omicron: '\u03BF', 150 | pi: '\u03C0', 151 | rho: '\u03C1', 152 | sigmaf: '\u03C2', 153 | sigma: '\u03C3', 154 | tau: '\u03C4', 155 | upsilon: '\u03C5', 156 | phi: '\u03C6', 157 | chi: '\u03C7', 158 | psi: '\u03C8', 159 | omega: '\u03C9', 160 | thetasym: '\u03D1', 161 | upsih: '\u03D2', 162 | piv: '\u03D6', 163 | ensp: '\u2002', 164 | emsp: '\u2003', 165 | thinsp: '\u2009', 166 | zwnj: '\u200C', 167 | zwj: '\u200D', 168 | lrm: '\u200E', 169 | rlm: '\u200F', 170 | ndash: '\u2013', 171 | mdash: '\u2014', 172 | lsquo: '\u2018', 173 | rsquo: '\u2019', 174 | sbquo: '\u201A', 175 | ldquo: '\u201C', 176 | rdquo: '\u201D', 177 | bdquo: '\u201E', 178 | dagger: '\u2020', 179 | Dagger: '\u2021', 180 | bull: '\u2022', 181 | hellip: '\u2026', 182 | permil: '\u2030', 183 | prime: '\u2032', 184 | Prime: '\u2033', 185 | lsaquo: '\u2039', 186 | rsaquo: '\u203A', 187 | oline: '\u203E', 188 | frasl: '\u2044', 189 | euro: '\u20AC', 190 | image: '\u2111', 191 | weierp: '\u2118', 192 | real: '\u211C', 193 | trade: '\u2122', 194 | alefsym: '\u2135', 195 | larr: '\u2190', 196 | uarr: '\u2191', 197 | rarr: '\u2192', 198 | darr: '\u2193', 199 | harr: '\u2194', 200 | crarr: '\u21B5', 201 | lArr: '\u21D0', 202 | uArr: '\u21D1', 203 | rArr: '\u21D2', 204 | dArr: '\u21D3', 205 | hArr: '\u21D4', 206 | forall: '\u2200', 207 | part: '\u2202', 208 | exist: '\u2203', 209 | empty: '\u2205', 210 | nabla: '\u2207', 211 | isin: '\u2208', 212 | notin: '\u2209', 213 | ni: '\u220B', 214 | prod: '\u220F', 215 | sum: '\u2211', 216 | minus: '\u2212', 217 | lowast: '\u2217', 218 | radic: '\u221A', 219 | prop: '\u221D', 220 | infin: '\u221E', 221 | ang: '\u2220', 222 | and: '\u2227', 223 | or: '\u2228', 224 | cap: '\u2229', 225 | cup: '\u222A', 226 | 'int': '\u222B', 227 | there4: '\u2234', 228 | sim: '\u223C', 229 | cong: '\u2245', 230 | asymp: '\u2248', 231 | ne: '\u2260', 232 | equiv: '\u2261', 233 | le: '\u2264', 234 | ge: '\u2265', 235 | sub: '\u2282', 236 | sup: '\u2283', 237 | nsub: '\u2284', 238 | sube: '\u2286', 239 | supe: '\u2287', 240 | oplus: '\u2295', 241 | otimes: '\u2297', 242 | perp: '\u22A5', 243 | sdot: '\u22C5', 244 | lceil: '\u2308', 245 | rceil: '\u2309', 246 | lfloor: '\u230A', 247 | rfloor: '\u230B', 248 | lang: '\u2329', 249 | rang: '\u232A', 250 | loz: '\u25CA', 251 | spades: '\u2660', 252 | clubs: '\u2663', 253 | hearts: '\u2665', 254 | diams: '\u2666' 255 | }; 256 | -------------------------------------------------------------------------------- /src/middleware.ts: -------------------------------------------------------------------------------- 1 | import type { Parser, Node, TokenType, Position } from 'acorn' 2 | import type { Options } from 'acorn' 3 | 4 | export declare class AcornParseClass extends Parser { 5 | options: Options & { 6 | onComment: any 7 | } 8 | pos: number 9 | potentialArrowAt: number 10 | yieldPos: number 11 | value: any 12 | containsEsc: boolean 13 | decoratorStack: any[] 14 | awaitPos: number 15 | keywords: any 16 | awaitIdentPos: number 17 | strict: boolean 18 | lastTokStart: number 19 | lastTokEnd: number 20 | treatFunctionsAsVar: boolean 21 | inGenerator: any 22 | exprAllowed: boolean 23 | labels: any[] 24 | scopeStack: any[] 25 | inModule: any 26 | undefinedExports: any 27 | lastTokEndLoc: any 28 | lastTokStartLoc: any 29 | context: any[] 30 | endLoc: any 31 | startLoc: any 32 | potentialArrowInForAwait: boolean 33 | 34 | constructor(options: Options, input: string, startPos?: number); 35 | 36 | parseImport(node: Node): any; 37 | 38 | currentScope(): any 39 | 40 | treatFunctionsAsVarInScope(scope: any): boolean 41 | 42 | declareName(name?: any, bindingType?: any, loc?: any): any 43 | 44 | parseImportSpecifier(): any 45 | 46 | parseExport(node: Node, exports: any): any 47 | 48 | parseExportDeclaration(node: Node): any 49 | 50 | parseExportSpecifiers(exports: any): any[] 51 | 52 | parseModuleExportName(): any 53 | 54 | expectContextual(name: string) 55 | 56 | semicolon() 57 | 58 | eat(type: TokenType): boolean 59 | 60 | checkExport(exports: any, name: any, pos: number) 61 | 62 | unexpected(pos?: number) 63 | 64 | startNode(): any 65 | 66 | startNodeAt(pos: number, loc: any): any 67 | 68 | isAsyncFunction(): boolean 69 | 70 | checkVariableExport(exports: any, decls: any) 71 | 72 | checkUnreserved(options: { 73 | start: number, 74 | end: number, 75 | name: string 76 | }) 77 | 78 | checkLocalExport(id: any): any 79 | 80 | parseMaybeDefault(startPos: number, startLoc: any, left: any): any 81 | 82 | finishOp(type: TokenType, size: number) 83 | 84 | getTokenFromCode(code: number): TokenType 85 | 86 | readToken_lt_gt(code: number): TokenType 87 | 88 | fullCharCodeAtPos(): number 89 | 90 | canInsertSemicolon(): boolean 91 | 92 | parseFunctionParams(node: any): void 93 | 94 | expect(type: TokenType): void 95 | 96 | readWord1(): string 97 | 98 | parseArrowExpression(node: any, param: any, isAsync?: boolean, forInit?: boolean) 99 | 100 | curContext(): any 101 | 102 | updateContext(prevType: TokenType) 103 | 104 | isContextual(name: string): boolean 105 | 106 | eatContextual(name): boolean 107 | 108 | parseLiteral(value: string): any 109 | 110 | checkLValSimple(expr: any, bindingType?: number, checkClashes?: any) 111 | 112 | enterScope(flags: any): void 113 | 114 | exitScope(): void 115 | 116 | parseFunctionStatement(node: any, isAsync?: boolean, declarationPosition?: any) 117 | 118 | parseObj(isPattern?: boolean, refDestructuringErrors?: any) 119 | 120 | parseBindingList(close: TokenType, allowEmpty?: boolean, allowTrailingComma?: boolean, allowModifiers?: boolean) 121 | 122 | parsePropertyName(prop: any): any 123 | 124 | isLet(context?: any): boolean 125 | 126 | parseTemplateElement({ isTagged }: { isTagged: boolean }): any 127 | 128 | parseExpression(forInit?: boolean, refDestructuringErrors?: any): any 129 | 130 | initFunction(node: any): void 131 | 132 | parseFunctionBody(node: any, isArrowFunction?: boolean, isMethod?: boolean, forInit?: boolean) 133 | 134 | parseSubscripts(base: any, startPos: number, startLoc: Position, noCalls?: any, forInit?: any) 135 | 136 | parseSpread(refDestructuringErrors: any): any 137 | 138 | parseExprList(close: TokenType, allowTrailingComma?: any, allowEmpty?: any, refDestructuringErrors?: any): any 139 | 140 | parseExprOp(left: any, leftStartPos: number, leftStartLoc: Position, minPrec?: any, forInit?: any) 141 | 142 | toAssignableList(exprList: any[], isBinding?: boolean) 143 | 144 | parseMaybeUnary(refExpressionErrors?: any, sawUnary?: boolean, incDec?: boolean, forInit?: boolean): any 145 | 146 | readRegexp(): any 147 | 148 | overrideContext(ctx: any) 149 | 150 | isSimpleAssignTarget(expr: any): boolean 151 | 152 | parseExprImport(forNew?: boolean): any 153 | 154 | next(ignoreEscapeSequenceInKeyword?: boolean): any 155 | 156 | parseStatement(context: any, topLevel?: boolean, exports?: any): any 157 | 158 | parseExpressionStatement(node: any, expre: any) 159 | 160 | shouldParseExportStatement(): boolean 161 | 162 | parseExprOps(forInit?: boolean, refDestructuringErrors?: any): any 163 | 164 | checkExpressionErrors(refDestructuringErrors: any, andThrow?: boolean) 165 | 166 | parseParenItem(item: any): any 167 | 168 | parseClassId(node: any, isStatement?: boolean | 'nullableID') 169 | 170 | parseClassField(field: any): any 171 | 172 | parseClassStaticBlock(node: any): any 173 | 174 | isClassElementNameStart(): boolean 175 | 176 | parseClassElementName(element: any) 177 | 178 | parseClassSuper(node: any) 179 | 180 | parseVarId(decl: any, kind: 'var' | 'let' | 'const') 181 | 182 | parseMaybeAssign(forInit?: boolean, refDestructuringErrors?: any, afterLeftParse?: any) 183 | 184 | toAssignable(node: any, isBinding?: boolean, refDestructuringErrors?: any) 185 | 186 | curPosition(): Position 187 | 188 | checkPatternErrors(refDestructuringErrors?: any, isAssign?: boolean) 189 | 190 | parseExprSubscripts(refDestructuringErrors?: any, forInit?: boolean): any 191 | 192 | checkYieldAwaitInDefaultParams() 193 | 194 | parseParenExpression(): any 195 | 196 | parseBindingAtom(): any 197 | 198 | afterTrailingComma(tokType: TokenType, notNext?: boolean) 199 | 200 | parsePrivateIdent(): any 201 | 202 | parseExportSpecifier(exports): any 203 | 204 | parseRestBinding(): any 205 | 206 | parseBlock(createNewLexicalScope?: boolean, node?: any, exitStrict?: boolean): any 207 | 208 | enterClassBody(): any 209 | 210 | exitClassBody() 211 | 212 | parseIdentNode(): any 213 | 214 | parseVar(node, isFor, kind, allowMissingInitializer): any 215 | 216 | parseExportDefaultDeclaration(): any 217 | 218 | parseIdent(liberal?: boolean): any 219 | 220 | copyNode(node: any): any 221 | 222 | checkLValPattern(expr: any, bindingType?: number, checkClashes?: any) 223 | 224 | checkLValInnerPattern(expr: any, bindingType?: number, checkClashes?: any) 225 | 226 | isAsyncProp(prop: any): boolean 227 | 228 | shouldParseArrow(): boolean 229 | 230 | parseYield(forInit?: any): any 231 | 232 | parseProperty(isPattern?: boolean, refDestructuringErrors?: any): any 233 | 234 | takeDecorators(node: any): void 235 | 236 | parseDecorators(allowExport?: boolean): void 237 | 238 | parseDecorator(): any 239 | 240 | parseMaybeDecoratorArguments(expr: any): any 241 | 242 | resetStartLocationFromNode(node: Node, locationNode: Node): void 243 | 244 | match(type: TokenType): boolean 245 | 246 | canHaveLeadingDecorator(): boolean 247 | 248 | startNodeAtNode(type: Node): any 249 | 250 | readToken(code: number): any 251 | 252 | jsx_readToken(): any 253 | 254 | jsx_readString(quote: any): any 255 | 256 | jsx_parseText(): any 257 | 258 | jsx_parseElement(): any 259 | 260 | jsx_readWord(): any 261 | 262 | jsx_parseElementName(): any 263 | 264 | jsx_parseAttribute(): any 265 | 266 | finishToken(token: TokenType, val?: string): any 267 | 268 | parseExprAtom(refDestructuringErrors?: any, forInit?: boolean, forNew?: boolean): any 269 | 270 | parseImportSpecifiers(): any 271 | 272 | parseImportDefaultSpecifier(): any 273 | 274 | parseImportNamespaceSpecifier(): any 275 | 276 | parseImportAttributes(): any 277 | 278 | parseMaybeImportAttributes(node: any): any 279 | } 280 | -------------------------------------------------------------------------------- /src/parseutil.ts: -------------------------------------------------------------------------------- 1 | export class DestructuringErrors { 2 | public shorthandAssign: number 3 | public trailingComma: number 4 | public parenthesizedAssign: number 5 | public parenthesizedBind: number 6 | public doubleProto: number 7 | 8 | constructor() { 9 | this.shorthandAssign = 10 | this.trailingComma = 11 | this.parenthesizedAssign = 12 | this.parenthesizedBind = 13 | this.doubleProto = -1 14 | } 15 | } 16 | 17 | export function isPrivateNameConflicted(privateNameMap, element) { 18 | const name = element.key.name 19 | const curr = privateNameMap[name] 20 | 21 | let next = "true" 22 | if (element.type === "MethodDefinition" && (element.kind === "get" || element.kind === "set")) { 23 | next = (element.static ? "s" : "i") + element.kind 24 | } 25 | 26 | // `class { get #a(){}; static set #a(_){} }` is also conflict. 27 | if ( 28 | curr === "iget" && next === "iset" || 29 | curr === "iset" && next === "iget" || 30 | curr === "sget" && next === "sset" || 31 | curr === "sset" && next === "sget" 32 | ) { 33 | privateNameMap[name] = "true" 34 | return false 35 | } else if (!curr) { 36 | privateNameMap[name] = next 37 | return false 38 | } else { 39 | return true 40 | } 41 | } 42 | 43 | export function checkKeyName(node, name) { 44 | const {computed, key} = node 45 | return !computed && ( 46 | key.type === "Identifier" && key.name === name || 47 | key.type === "Literal" && key.value === name 48 | ) 49 | } 50 | -------------------------------------------------------------------------------- /src/scopeflags.ts: -------------------------------------------------------------------------------- 1 | // Each scope gets a bitset that may contain these flags 2 | // prettier-ignore 3 | export const 4 | // Up to 0b00100000000 is reserved in acorn. 5 | TS_SCOPE_OTHER = 0b01000000000, 6 | TS_SCOPE_TS_MODULE = 0b10000000000; 7 | 8 | // These flags are meant to be _only_ used inside the Scope class (or subclasses). 9 | // prettier-ignore 10 | export const BIND_KIND_VALUE = 0b000000_0000_01, 11 | BIND_KIND_TYPE = 0b000000_0000_10, 12 | // Used in checkLVal and declareName to determine the type of a binding 13 | BIND_SCOPE_VAR = 0b000000_0001_00, // Var-style binding 14 | BIND_SCOPE_LEXICAL = 0b000000_0010_00, // Let- or const-style binding 15 | BIND_SCOPE_FUNCTION = 0b000000_0100_00, // Function declaration 16 | BIND_SCOPE_OUTSIDE = 0b000000_1000_00, // Special case for function names as 17 | // bound inside the function 18 | // Misc flags 19 | BIND_FLAGS_NONE = 0b000001_0000_00, 20 | BIND_FLAGS_CLASS = 0b000010_0000_00, 21 | BIND_FLAGS_TS_ENUM = 0b000100_0000_00, 22 | BIND_FLAGS_TS_CONST_ENUM = 0b001000_0000_00, 23 | BIND_FLAGS_TS_EXPORT_ONLY = 0b010000_0000_00, 24 | BIND_FLAGS_FLOW_DECLARE_FN = 0b100000_0000_00; 25 | 26 | // These flags are meant to be _only_ used by Scope consumers 27 | // prettier-ignore 28 | /* = is value? | is type? | scope | misc flags */ 29 | export const BIND_CLASS = BIND_KIND_VALUE | BIND_KIND_TYPE | BIND_SCOPE_LEXICAL | BIND_FLAGS_CLASS , 30 | BIND_LEXICAL = BIND_KIND_VALUE | 0 | BIND_SCOPE_LEXICAL | 0 , 31 | BIND_VAR = BIND_KIND_VALUE | 0 | BIND_SCOPE_VAR | 0 , 32 | BIND_FUNCTION = BIND_KIND_VALUE | 0 | BIND_SCOPE_FUNCTION | 0 , 33 | BIND_TS_INTERFACE = 0 | BIND_KIND_TYPE | 0 | BIND_FLAGS_CLASS , 34 | BIND_TS_TYPE = 0 | BIND_KIND_TYPE | 0 | 0 , 35 | BIND_TS_ENUM = BIND_KIND_VALUE | BIND_KIND_TYPE | BIND_SCOPE_LEXICAL | BIND_FLAGS_TS_ENUM, 36 | BIND_TS_AMBIENT = 0 | 0 | 0 | BIND_FLAGS_TS_EXPORT_ONLY, 37 | // These bindings don't introduce anything in the scope. They are used for assignments and 38 | // function expressions IDs. 39 | BIND_NONE = 0 | 0 | 0 | BIND_FLAGS_NONE , 40 | BIND_OUTSIDE = BIND_KIND_VALUE | 0 | 0 | BIND_FLAGS_NONE , 41 | 42 | BIND_TS_CONST_ENUM = BIND_TS_ENUM | BIND_FLAGS_TS_CONST_ENUM, 43 | BIND_TS_NAMESPACE = 0 | 0 | 0 | BIND_FLAGS_TS_EXPORT_ONLY, 44 | 45 | BIND_FLOW_DECLARE_FN = BIND_FLAGS_FLOW_DECLARE_FN; 46 | 47 | export type BindingTypes = 48 | | typeof BIND_NONE 49 | | typeof BIND_OUTSIDE 50 | | typeof BIND_VAR 51 | | typeof BIND_LEXICAL 52 | | typeof BIND_CLASS 53 | | typeof BIND_FUNCTION 54 | | typeof BIND_TS_INTERFACE 55 | | typeof BIND_TS_TYPE 56 | | typeof BIND_TS_ENUM 57 | | typeof BIND_TS_AMBIENT 58 | | typeof BIND_TS_NAMESPACE; 59 | 60 | // prettier-ignore 61 | export const CLASS_ELEMENT_FLAG_STATIC = 0b1_00, 62 | CLASS_ELEMENT_KIND_GETTER = 0b0_10, 63 | CLASS_ELEMENT_KIND_SETTER = 0b0_01, 64 | CLASS_ELEMENT_KIND_ACCESSOR = CLASS_ELEMENT_KIND_GETTER | CLASS_ELEMENT_KIND_SETTER; 65 | 66 | // prettier-ignore 67 | export const CLASS_ELEMENT_STATIC_GETTER = CLASS_ELEMENT_KIND_GETTER | CLASS_ELEMENT_FLAG_STATIC, 68 | CLASS_ELEMENT_STATIC_SETTER = CLASS_ELEMENT_KIND_SETTER | CLASS_ELEMENT_FLAG_STATIC, 69 | CLASS_ELEMENT_INSTANCE_GETTER = CLASS_ELEMENT_KIND_GETTER, 70 | CLASS_ELEMENT_INSTANCE_SETTER = CLASS_ELEMENT_KIND_SETTER, 71 | CLASS_ELEMENT_OTHER = 0; 72 | 73 | export type ClassElementTypes = 74 | | typeof CLASS_ELEMENT_STATIC_GETTER 75 | | typeof CLASS_ELEMENT_STATIC_SETTER 76 | | typeof CLASS_ELEMENT_INSTANCE_GETTER 77 | | typeof CLASS_ELEMENT_INSTANCE_SETTER 78 | | typeof CLASS_ELEMENT_OTHER; 79 | 80 | export const SCOPE_ARROW = 16 81 | -------------------------------------------------------------------------------- /src/tokenType.ts: -------------------------------------------------------------------------------- 1 | // @ts-ignore 2 | import { TokenType, keywordTypes, tokTypes, TokContext } from 'acorn' 3 | import { AcornTypeScript } from './types' 4 | 5 | const startsExpr = true 6 | 7 | // Succinct definitions of keyword token types 8 | 9 | function kwLike(_name, options: any = {}) { 10 | return new TokenType('name', options) 11 | } 12 | 13 | const acornTypeScriptMap = new WeakMap() 14 | 15 | export function generateAcornTypeScript(_acorn: any): AcornTypeScript { 16 | const acorn = _acorn.Parser.acorn || _acorn 17 | let acornTypeScript = acornTypeScriptMap.get(acorn) 18 | if (!acornTypeScript) { 19 | const tsKwTokenType = generateTsKwTokenType() 20 | const tsTokenType = generateTsTokenType() 21 | const tsTokenContext = generateTsTokenContext() 22 | const tsKeywordsRegExp = new RegExp( 23 | `^(?:${Object.keys(tsKwTokenType).join('|')})$` 24 | ) 25 | 26 | tsTokenType.jsxTagStart.updateContext = function() { 27 | this.context.push(tsTokenContext.tc_expr) // treat as beginning of 28 | // JSX expression 29 | this.context.push(tsTokenContext.tc_oTag) // start opening tag context 30 | this.exprAllowed = false 31 | } 32 | 33 | tsTokenType.jsxTagEnd.updateContext = function(prevType) { 34 | let out = this.context.pop() 35 | if (out === tsTokenContext.tc_oTag && prevType === tokTypes.slash || out === tsTokenContext.tc_cTag) { 36 | this.context.pop() 37 | this.exprAllowed = this.curContext() === tsTokenContext.tc_expr 38 | } else { 39 | this.exprAllowed = true 40 | } 41 | } 42 | 43 | function tokenIsLiteralPropertyName(token: TokenType): boolean { 44 | return [ 45 | ...[tokTypes.name, tokTypes.string, tokTypes.num], 46 | ...Object.values(keywordTypes), 47 | ...Object.values(tsKwTokenType) 48 | ].includes(token) 49 | } 50 | 51 | function tokenIsKeywordOrIdentifier(token: TokenType): boolean { 52 | return [ 53 | ...[tokTypes.name], 54 | ...Object.values(keywordTypes), 55 | ...Object.values(tsKwTokenType) 56 | ].includes(token) 57 | } 58 | 59 | function tokenIsIdentifier(token: TokenType): boolean { 60 | return [...Object.values(tsKwTokenType), tokTypes.name].includes(token) 61 | } 62 | 63 | function tokenIsTSDeclarationStart(token: TokenType): boolean { 64 | return [ 65 | tsKwTokenType.abstract, 66 | tsKwTokenType.declare, 67 | tsKwTokenType.enum, 68 | tsKwTokenType.module, 69 | tsKwTokenType.namespace, 70 | tsKwTokenType.interface, 71 | tsKwTokenType.type 72 | ].includes(token) 73 | } 74 | 75 | function tokenIsTSTypeOperator(token: TokenType): boolean { 76 | return [ 77 | tsKwTokenType.keyof, 78 | tsKwTokenType.readonly, 79 | tsKwTokenType.unique 80 | ].includes(token) 81 | } 82 | 83 | function tokenIsTemplate(token: TokenType): boolean { 84 | return token === tokTypes.invalidTemplate 85 | } 86 | 87 | acornTypeScript = { 88 | tokTypes: { 89 | ...tsKwTokenType, 90 | ...tsTokenType 91 | }, 92 | tokContexts: { 93 | ...tsTokenContext 94 | }, 95 | keywordsRegExp: tsKeywordsRegExp, 96 | tokenIsLiteralPropertyName, 97 | tokenIsKeywordOrIdentifier, 98 | tokenIsIdentifier, 99 | tokenIsTSDeclarationStart, 100 | tokenIsTSTypeOperator, 101 | tokenIsTemplate 102 | } 103 | } 104 | 105 | return acornTypeScript 106 | } 107 | 108 | function generateTsTokenContext() { 109 | return { 110 | tc_oTag: new TokContext('...', true, true) 113 | } 114 | } 115 | 116 | function generateTsTokenType() { 117 | return { 118 | at: new TokenType('@'), 119 | jsxName: new TokenType('jsxName'), 120 | jsxText: new TokenType('jsxText', { beforeExpr: true }), 121 | jsxTagStart: new TokenType('jsxTagStart', { startsExpr: true }), 122 | jsxTagEnd: new TokenType('jsxTagEnd') 123 | } 124 | } 125 | 126 | function generateTsKwTokenType() { 127 | return { 128 | assert: kwLike('assert', { startsExpr }), 129 | asserts: kwLike('asserts', { startsExpr }), 130 | global: kwLike('global', { startsExpr }), 131 | keyof: kwLike('keyof', { startsExpr }), 132 | readonly: kwLike('readonly', { startsExpr }), 133 | unique: kwLike('unique', { startsExpr }), 134 | abstract: kwLike('abstract', { startsExpr }), 135 | declare: kwLike('declare', { startsExpr }), 136 | enum: kwLike('enum', { startsExpr }), 137 | module: kwLike('module', { startsExpr }), 138 | namespace: kwLike('namespace', { startsExpr }), 139 | interface: kwLike('interface', { startsExpr }), 140 | type: kwLike('type', { startsExpr }) 141 | } 142 | } 143 | 144 | 145 | -------------------------------------------------------------------------------- /src/types.ts: -------------------------------------------------------------------------------- 1 | import type { Position, TokContext, TokenType } from 'acorn' 2 | 3 | export type Accessibility = 'public' | 'protected' | 'private'; 4 | 5 | export type VarianceAnnotations = 'in' | 'out'; 6 | 7 | export type ClassAccessor = 'accessor' 8 | 9 | export type TsModifier = 10 | | 'readonly' 11 | | 'abstract' 12 | | 'declare' 13 | | 'static' 14 | | 'override' 15 | | Accessibility 16 | | VarianceAnnotations 17 | | ClassAccessor; 18 | 19 | export type LookaheadState = { 20 | pos: number; 21 | value: any; 22 | type: TokenType; 23 | start: number; 24 | end: number; 25 | context: TokContext[]; 26 | startLoc: any; 27 | endLoc: any; 28 | lastTokEndLoc: any; 29 | lastTokStartLoc: any; 30 | lastTokStart: any; 31 | lastTokEnd: any 32 | curLine: number; 33 | lineStart: number; 34 | curPosition: () => Position; 35 | containsEsc: boolean; 36 | }; 37 | 38 | export type ParsingContext = 39 | | 'EnumMembers' 40 | | 'HeritageClauseElement' 41 | | 'TupleElementTypes' 42 | | 'TypeMembers' 43 | | 'TypeParametersOrArguments'; 44 | 45 | export type ModifierBase = { 46 | accessibility?: Accessibility; 47 | } & { 48 | [key in TsModifier]?: boolean | undefined | null; 49 | }; 50 | 51 | export type TryParse = { 52 | node: Node; 53 | error: Error; 54 | thrown: Thrown; 55 | aborted: Aborted; 56 | failState: FailState; 57 | }; 58 | 59 | export type AcornTypeScript = { 60 | tokTypes: Record 61 | tokContexts: Record 62 | keywordsRegExp: RegExp 63 | tokenIsLiteralPropertyName(token: TokenType): boolean 64 | tokenIsKeywordOrIdentifier(token: TokenType): boolean 65 | tokenIsIdentifier(token: TokenType): boolean 66 | tokenIsTSDeclarationStart(token: TokenType): boolean 67 | tokenIsTSTypeOperator(token: TokenType): boolean 68 | tokenIsTemplate(token: TokenType): boolean 69 | } 70 | 71 | export type AcornJsx = { 72 | tokTypes: { 73 | jsxName: TokenType, 74 | jsxText: TokenType, 75 | jsxTagEnd: TokenType, 76 | jsxTagStart: TokenType 77 | } 78 | tokContexts: { 79 | tc_oTag: TokContext, 80 | tc_cTag: TokContext, 81 | tc_expr: TokContext 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/whitespace.ts: -------------------------------------------------------------------------------- 1 | export const skipWhiteSpaceInLine = 2 | /(?:[^\S\n\r\u2028\u2029]|\/\/.*|\/\*.*?\*\/)*/y 3 | 4 | // Skip whitespace and single-line comments, including /* no newline here */. 5 | // After this RegExp matches, its lastIndex points to a line terminator, or 6 | // the start of multi-line comment (which is effectively a line terminator), 7 | // or the end of string. 8 | export const skipWhiteSpaceToLineBreak = new RegExp( 9 | // Unfortunately JS doesn't support Perl's atomic /(?>pattern)/ or 10 | // possessive quantifiers, so we use a trick to prevent backtracking 11 | // when the look-ahead for line terminator fails. 12 | '(?=(' + 13 | // Capture the whitespace and comments that should be skipped inside 14 | // a look-ahead assertion, and then re-match the group as a unit. 15 | skipWhiteSpaceInLine.source + 16 | '))\\1' + 17 | // Look-ahead for either line terminator, start of multi-line comment, 18 | // or end of string. 19 | /(?=[\n\r\u2028\u2029]|\/\*(?!.*?\*\/)|$)/.source, 20 | 'y' // sticky 21 | ) 22 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "allowJs": false, 4 | "target": "es6", 5 | "allowSyntheticDefaultImports": true, 6 | "moduleResolution": "node", 7 | "outDir": "lib", 8 | "experimentalDecorators": true, 9 | "lib": ["es2017", "dom"], 10 | "noUnusedLocals": true, 11 | "noUnusedParameters": true, 12 | "preserveConstEnums": true, 13 | "removeComments": false, 14 | "sourceMap": true, 15 | "strict": false 16 | }, 17 | "include": ["./src/*", "./types/*"], 18 | "exclude": ["node_modules", "lib"] 19 | } 20 | --------------------------------------------------------------------------------