tsc-ts 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -1
- package/dist/api/compiler/ast-utilities.d.ts +82 -0
- package/dist/api/compiler/ast-utilities.js +462 -0
- package/dist/api/compiler/ast.d.ts +2350 -0
- package/dist/api/compiler/ast.js +11206 -0
- package/dist/api/compiler/astnav.d.ts +37 -0
- package/dist/api/compiler/astnav.js +767 -0
- package/dist/api/compiler/binder-utilities.d.ts +182 -0
- package/dist/api/compiler/binder-utilities.js +1240 -0
- package/dist/api/compiler/binder.d.ts +33 -0
- package/dist/api/compiler/binder.js +2358 -0
- package/dist/api/compiler/character-codes.d.ts +161 -0
- package/dist/api/compiler/character-codes.js +160 -0
- package/dist/api/compiler/checker-calls.d.ts +46 -0
- package/dist/api/compiler/checker-calls.js +1640 -0
- package/dist/api/compiler/checker-classes.d.ts +30 -0
- package/dist/api/compiler/checker-classes.js +582 -0
- package/dist/api/compiler/checker-contextual.d.ts +77 -0
- package/dist/api/compiler/checker-contextual.js +1136 -0
- package/dist/api/compiler/checker-declaration-order.d.ts +12 -0
- package/dist/api/compiler/checker-declaration-order.js +356 -0
- package/dist/api/compiler/checker-declarations.d.ts +33 -0
- package/dist/api/compiler/checker-declarations.js +888 -0
- package/dist/api/compiler/checker-declared-types.d.ts +48 -0
- package/dist/api/compiler/checker-declared-types.js +787 -0
- package/dist/api/compiler/checker-decorators.d.ts +26 -0
- package/dist/api/compiler/checker-decorators.js +562 -0
- package/dist/api/compiler/checker-deprecation.d.ts +33 -0
- package/dist/api/compiler/checker-deprecation.js +315 -0
- package/dist/api/compiler/checker-destructuring.d.ts +34 -0
- package/dist/api/compiler/checker-destructuring.js +584 -0
- package/dist/api/compiler/checker-elaboration.d.ts +15 -0
- package/dist/api/compiler/checker-elaboration.js +290 -0
- package/dist/api/compiler/checker-emit-helpers.d.ts +58 -0
- package/dist/api/compiler/checker-emit-helpers.js +154 -0
- package/dist/api/compiler/checker-emit-resolver.d.ts +75 -0
- package/dist/api/compiler/checker-emit-resolver.js +579 -0
- package/dist/api/compiler/checker-evaluator.d.ts +27 -0
- package/dist/api/compiler/checker-evaluator.js +188 -0
- package/dist/api/compiler/checker-expressions.d.ts +67 -0
- package/dist/api/compiler/checker-expressions.js +1351 -0
- package/dist/api/compiler/checker-features.d.ts +6 -0
- package/dist/api/compiler/checker-features.js +354 -0
- package/dist/api/compiler/checker-flow.d.ts +86 -0
- package/dist/api/compiler/checker-flow.js +169 -0
- package/dist/api/compiler/checker-functions.d.ts +43 -0
- package/dist/api/compiler/checker-functions.js +1002 -0
- package/dist/api/compiler/checker-generated-code.d.ts +25 -0
- package/dist/api/compiler/checker-generated-code.js +168 -0
- package/dist/api/compiler/checker-globals.d.ts +14 -0
- package/dist/api/compiler/checker-globals.js +37 -0
- package/dist/api/compiler/checker-grammar.d.ts +35 -0
- package/dist/api/compiler/checker-grammar.js +2573 -0
- package/dist/api/compiler/checker-heritage.d.ts +28 -0
- package/dist/api/compiler/checker-heritage.js +900 -0
- package/dist/api/compiler/checker-inference.d.ts +179 -0
- package/dist/api/compiler/checker-inference.js +2105 -0
- package/dist/api/compiler/checker-iteration.d.ts +115 -0
- package/dist/api/compiler/checker-iteration.js +857 -0
- package/dist/api/compiler/checker-javascript.d.ts +42 -0
- package/dist/api/compiler/checker-javascript.js +441 -0
- package/dist/api/compiler/checker-jsdoc.d.ts +30 -0
- package/dist/api/compiler/checker-jsdoc.js +320 -0
- package/dist/api/compiler/checker-jsx.d.ts +94 -0
- package/dist/api/compiler/checker-jsx.js +1433 -0
- package/dist/api/compiler/checker-literals.d.ts +6 -0
- package/dist/api/compiler/checker-literals.js +43 -0
- package/dist/api/compiler/checker-members.d.ts +198 -0
- package/dist/api/compiler/checker-members.js +2126 -0
- package/dist/api/compiler/checker-modules.d.ts +85 -0
- package/dist/api/compiler/checker-modules.js +2141 -0
- package/dist/api/compiler/checker-narrowing.d.ts +120 -0
- package/dist/api/compiler/checker-narrowing.js +2797 -0
- package/dist/api/compiler/checker-object-literals.d.ts +14 -0
- package/dist/api/compiler/checker-object-literals.js +479 -0
- package/dist/api/compiler/checker-operators.d.ts +33 -0
- package/dist/api/compiler/checker-operators.js +1040 -0
- package/dist/api/compiler/checker-overloads.d.ts +7 -0
- package/dist/api/compiler/checker-overloads.js +270 -0
- package/dist/api/compiler/checker-property-access.d.ts +34 -0
- package/dist/api/compiler/checker-property-access.js +672 -0
- package/dist/api/compiler/checker-services.d.ts +49 -0
- package/dist/api/compiler/checker-services.js +995 -0
- package/dist/api/compiler/checker-signatures.d.ts +55 -0
- package/dist/api/compiler/checker-signatures.js +788 -0
- package/dist/api/compiler/checker-source-file.d.ts +27 -0
- package/dist/api/compiler/checker-source-file.js +619 -0
- package/dist/api/compiler/checker-statements.d.ts +18 -0
- package/dist/api/compiler/checker-statements.js +226 -0
- package/dist/api/compiler/checker-super.d.ts +13 -0
- package/dist/api/compiler/checker-super.js +241 -0
- package/dist/api/compiler/checker-symbol-types.d.ts +67 -0
- package/dist/api/compiler/checker-symbol-types.js +1885 -0
- package/dist/api/compiler/checker-symbols.d.ts +181 -0
- package/dist/api/compiler/checker-symbols.js +1782 -0
- package/dist/api/compiler/checker-type-factory.d.ts +142 -0
- package/dist/api/compiler/checker-type-factory.js +2501 -0
- package/dist/api/compiler/checker-type-nodes.d.ts +26 -0
- package/dist/api/compiler/checker-type-nodes.js +828 -0
- package/dist/api/compiler/checker-type-operators.d.ts +109 -0
- package/dist/api/compiler/checker-type-operators.js +1842 -0
- package/dist/api/compiler/checker-types.d.ts +1027 -0
- package/dist/api/compiler/checker-types.js +1697 -0
- package/dist/api/compiler/checker-unused.d.ts +19 -0
- package/dist/api/compiler/checker-unused.js +524 -0
- package/dist/api/compiler/checker-utilities.d.ts +33 -0
- package/dist/api/compiler/checker-utilities.js +141 -0
- package/dist/api/compiler/checker.d.ts +491 -0
- package/dist/api/compiler/checker.js +912 -0
- package/dist/api/compiler/command-line.d.ts +32 -0
- package/dist/api/compiler/command-line.js +383 -0
- package/dist/api/compiler/compile-program.d.ts +118 -0
- package/dist/api/compiler/compile-program.js +384 -0
- package/dist/api/compiler/diagnostic-locales.d.ts +22 -0
- package/dist/api/compiler/diagnostic-locales.js +64 -0
- package/dist/api/compiler/diagnostic-messages.d.ts +2166 -0
- package/dist/api/compiler/diagnostic-messages.js +184 -0
- package/dist/api/compiler/diagnostics.d.ts +167 -0
- package/dist/api/compiler/diagnostics.js +820 -0
- package/dist/api/compiler/emitter.d.ts +71 -0
- package/dist/api/compiler/emitter.js +327 -0
- package/dist/api/compiler/file-include.d.ts +117 -0
- package/dist/api/compiler/file-include.js +536 -0
- package/dist/api/compiler/file-loader.d.ts +261 -0
- package/dist/api/compiler/file-loader.js +1257 -0
- package/dist/api/compiler/file-system.d.ts +51 -0
- package/dist/api/compiler/file-system.js +132 -0
- package/dist/api/compiler/flow.d.ts +60 -0
- package/dist/api/compiler/flow.js +45 -0
- package/dist/api/compiler/instantiation.d.ts +74 -0
- package/dist/api/compiler/instantiation.js +799 -0
- package/dist/api/compiler/jsdoc.d.ts +75 -0
- package/dist/api/compiler/jsdoc.js +1229 -0
- package/dist/api/compiler/link-tables.d.ts +36 -0
- package/dist/api/compiler/link-tables.js +83 -0
- package/dist/api/compiler/locale-data.d.ts +24 -0
- package/dist/api/compiler/locale-data.js +183 -0
- package/dist/api/compiler/locale.d.ts +4 -0
- package/dist/api/compiler/locale.js +317 -0
- package/dist/api/compiler/locales/cs-CZ.d.ts +2 -0
- package/dist/api/compiler/locales/cs-CZ.js +3 -0
- package/dist/api/compiler/locales/de-DE.d.ts +2 -0
- package/dist/api/compiler/locales/de-DE.js +3 -0
- package/dist/api/compiler/locales/es-ES.d.ts +2 -0
- package/dist/api/compiler/locales/es-ES.js +3 -0
- package/dist/api/compiler/locales/fr-FR.d.ts +2 -0
- package/dist/api/compiler/locales/fr-FR.js +3 -0
- package/dist/api/compiler/locales/it-IT.d.ts +2 -0
- package/dist/api/compiler/locales/it-IT.js +3 -0
- package/dist/api/compiler/locales/ja-JP.d.ts +2 -0
- package/dist/api/compiler/locales/ja-JP.js +3 -0
- package/dist/api/compiler/locales/ko-KR.d.ts +2 -0
- package/dist/api/compiler/locales/ko-KR.js +3 -0
- package/dist/api/compiler/locales/pl-PL.d.ts +2 -0
- package/dist/api/compiler/locales/pl-PL.js +3 -0
- package/dist/api/compiler/locales/pt-BR.d.ts +2 -0
- package/dist/api/compiler/locales/pt-BR.js +3 -0
- package/dist/api/compiler/locales/ru-RU.d.ts +2 -0
- package/dist/api/compiler/locales/ru-RU.js +3 -0
- package/dist/api/compiler/locales/tr-TR.d.ts +2 -0
- package/dist/api/compiler/locales/tr-TR.js +3 -0
- package/dist/api/compiler/locales/zh-CN.d.ts +2 -0
- package/dist/api/compiler/locales/zh-CN.js +3 -0
- package/dist/api/compiler/locales/zh-TW.d.ts +2 -0
- package/dist/api/compiler/locales/zh-TW.js +3 -0
- package/dist/api/compiler/module-resolution-types.d.ts +83 -0
- package/dist/api/compiler/module-resolution-types.js +176 -0
- package/dist/api/compiler/module-resolution.d.ts +71 -0
- package/dist/api/compiler/module-resolution.js +1598 -0
- package/dist/api/compiler/module-specifiers.d.ts +64 -0
- package/dist/api/compiler/module-specifiers.js +1101 -0
- package/dist/api/compiler/name-resolver.d.ts +43 -0
- package/dist/api/compiler/name-resolver.js +509 -0
- package/dist/api/compiler/node-builder-names.d.ts +32 -0
- package/dist/api/compiler/node-builder-names.js +854 -0
- package/dist/api/compiler/node-builder-pseudo.d.ts +36 -0
- package/dist/api/compiler/node-builder-pseudo.js +744 -0
- package/dist/api/compiler/node-builder-reuse.d.ts +4 -0
- package/dist/api/compiler/node-builder-reuse.js +647 -0
- package/dist/api/compiler/node-builder.d.ts +270 -0
- package/dist/api/compiler/node-builder.js +2645 -0
- package/dist/api/compiler/option-declarations.d.ts +90 -0
- package/dist/api/compiler/option-declarations.js +1460 -0
- package/dist/api/compiler/options.d.ts +289 -0
- package/dist/api/compiler/options.js +1197 -0
- package/dist/api/compiler/output-paths.d.ts +42 -0
- package/dist/api/compiler/output-paths.js +195 -0
- package/dist/api/compiler/package-json.d.ts +175 -0
- package/dist/api/compiler/package-json.js +1015 -0
- package/dist/api/compiler/parallel-parse.d.ts +219 -0
- package/dist/api/compiler/parallel-parse.js +537 -0
- package/dist/api/compiler/parser.d.ts +587 -0
- package/dist/api/compiler/parser.js +6407 -0
- package/dist/api/compiler/path.d.ts +91 -0
- package/dist/api/compiler/path.js +705 -0
- package/dist/api/compiler/printer/async-helpers.d.ts +22 -0
- package/dist/api/compiler/printer/async-helpers.js +91 -0
- package/dist/api/compiler/printer/auto-generate.d.ts +13 -0
- package/dist/api/compiler/printer/auto-generate.js +20 -0
- package/dist/api/compiler/printer/decorator-helpers.d.ts +24 -0
- package/dist/api/compiler/printer/decorator-helpers.js +118 -0
- package/dist/api/compiler/printer/emit-context.d.ts +154 -0
- package/dist/api/compiler/printer/emit-context.js +576 -0
- package/dist/api/compiler/printer/emit-flags.d.ts +60 -0
- package/dist/api/compiler/printer/emit-flags.js +2 -0
- package/dist/api/compiler/printer/factory-base.d.ts +171 -0
- package/dist/api/compiler/printer/factory-base.js +1505 -0
- package/dist/api/compiler/printer/factory.d.ts +147 -0
- package/dist/api/compiler/printer/factory.js +542 -0
- package/dist/api/compiler/printer/helpers.d.ts +27 -0
- package/dist/api/compiler/printer/helpers.js +164 -0
- package/dist/api/compiler/printer/name-generator.d.ts +41 -0
- package/dist/api/compiler/printer/name-generator.js +283 -0
- package/dist/api/compiler/printer/printer.d.ts +411 -0
- package/dist/api/compiler/printer/printer.js +4517 -0
- package/dist/api/compiler/printer/text-writer.d.ts +46 -0
- package/dist/api/compiler/printer/text-writer.js +172 -0
- package/dist/api/compiler/printer/utilities.d.ts +82 -0
- package/dist/api/compiler/printer/utilities.js +817 -0
- package/dist/api/compiler/program-checker.d.ts +156 -0
- package/dist/api/compiler/program-checker.js +526 -0
- package/dist/api/compiler/program-utilities.d.ts +52 -0
- package/dist/api/compiler/program-utilities.js +365 -0
- package/dist/api/compiler/program.d.ts +180 -0
- package/dist/api/compiler/program.js +1011 -0
- package/dist/api/compiler/pseudo-bigint.d.ts +5 -0
- package/dist/api/compiler/pseudo-bigint.js +61 -0
- package/dist/api/compiler/regexp-checker.d.ts +38 -0
- package/dist/api/compiler/regexp-checker.js +942 -0
- package/dist/api/compiler/relations.d.ts +263 -0
- package/dist/api/compiler/relations.js +4002 -0
- package/dist/api/compiler/reparser.d.ts +48 -0
- package/dist/api/compiler/reparser.js +1323 -0
- package/dist/api/compiler/scanner.d.ts +256 -0
- package/dist/api/compiler/scanner.js +2853 -0
- package/dist/api/compiler/side-state.d.ts +16 -0
- package/dist/api/compiler/side-state.js +89 -0
- package/dist/api/compiler/sourcemap.d.ts +55 -0
- package/dist/api/compiler/sourcemap.js +340 -0
- package/dist/api/compiler/spelling.d.ts +14 -0
- package/dist/api/compiler/spelling.js +128 -0
- package/dist/api/compiler/symbol-accessibility.d.ts +57 -0
- package/dist/api/compiler/symbol-accessibility.js +894 -0
- package/dist/api/compiler/symbol.d.ts +240 -0
- package/dist/api/compiler/symbol.js +228 -0
- package/dist/api/compiler/symlinks.d.ts +32 -0
- package/dist/api/compiler/symlinks.js +114 -0
- package/dist/api/compiler/syntax-kind.d.ts +389 -0
- package/dist/api/compiler/syntax-kind.js +2 -0
- package/dist/api/compiler/timeline.d.ts +9 -0
- package/dist/api/compiler/timeline.js +54 -0
- package/dist/api/compiler/transformers/alias-references.d.ts +39 -0
- package/dist/api/compiler/transformers/alias-references.js +676 -0
- package/dist/api/compiler/transformers/async-utilities.d.ts +51 -0
- package/dist/api/compiler/transformers/async-utilities.js +260 -0
- package/dist/api/compiler/transformers/async.d.ts +53 -0
- package/dist/api/compiler/transformers/async.js +645 -0
- package/dist/api/compiler/transformers/class-fields.d.ts +206 -0
- package/dist/api/compiler/transformers/class-fields.js +2418 -0
- package/dist/api/compiler/transformers/class-utilities.d.ts +46 -0
- package/dist/api/compiler/transformers/class-utilities.js +261 -0
- package/dist/api/compiler/transformers/commonjs-module.d.ts +103 -0
- package/dist/api/compiler/transformers/commonjs-module.js +1180 -0
- package/dist/api/compiler/transformers/const-enum-inliner.d.ts +11 -0
- package/dist/api/compiler/transformers/const-enum-inliner.js +36 -0
- package/dist/api/compiler/transformers/declarations-diagnostics.d.ts +52 -0
- package/dist/api/compiler/transformers/declarations-diagnostics.js +538 -0
- package/dist/api/compiler/transformers/declarations-pseudo.d.ts +160 -0
- package/dist/api/compiler/transformers/declarations-pseudo.js +797 -0
- package/dist/api/compiler/transformers/declarations-resolver.d.ts +152 -0
- package/dist/api/compiler/transformers/declarations-resolver.js +35 -0
- package/dist/api/compiler/transformers/declarations-syntactic.d.ts +119 -0
- package/dist/api/compiler/transformers/declarations-syntactic.js +1582 -0
- package/dist/api/compiler/transformers/declarations-tracker.d.ts +46 -0
- package/dist/api/compiler/transformers/declarations-tracker.js +197 -0
- package/dist/api/compiler/transformers/declarations.d.ts +175 -0
- package/dist/api/compiler/transformers/declarations.js +2380 -0
- package/dist/api/compiler/transformers/decorator-metadata.d.ts +54 -0
- package/dist/api/compiler/transformers/decorator-metadata.js +554 -0
- package/dist/api/compiler/transformers/decorator-utilities.d.ts +38 -0
- package/dist/api/compiler/transformers/decorator-utilities.js +238 -0
- package/dist/api/compiler/transformers/destructuring.d.ts +25 -0
- package/dist/api/compiler/transformers/destructuring.js +626 -0
- package/dist/api/compiler/transformers/downlevel.d.ts +6 -0
- package/dist/api/compiler/transformers/downlevel.js +45 -0
- package/dist/api/compiler/transformers/emit-resolver.d.ts +61 -0
- package/dist/api/compiler/transformers/emit-resolver.js +197 -0
- package/dist/api/compiler/transformers/es-decorators.d.ts +118 -0
- package/dist/api/compiler/transformers/es-decorators.js +1901 -0
- package/dist/api/compiler/transformers/exponentiation.d.ts +11 -0
- package/dist/api/compiler/transformers/exponentiation.js +76 -0
- package/dist/api/compiler/transformers/external-module-info.d.ts +35 -0
- package/dist/api/compiler/transformers/external-module-info.js +351 -0
- package/dist/api/compiler/transformers/for-await.d.ts +43 -0
- package/dist/api/compiler/transformers/for-await.js +469 -0
- package/dist/api/compiler/transformers/import-elision.d.ts +16 -0
- package/dist/api/compiler/transformers/import-elision.js +124 -0
- package/dist/api/compiler/transformers/jsx-entities.d.ts +1 -0
- package/dist/api/compiler/transformers/jsx-entities.js +256 -0
- package/dist/api/compiler/transformers/jsx.d.ts +71 -0
- package/dist/api/compiler/transformers/jsx.js +700 -0
- package/dist/api/compiler/transformers/legacy-decorators.d.ts +56 -0
- package/dist/api/compiler/transformers/legacy-decorators.js +564 -0
- package/dist/api/compiler/transformers/logical-assignment.d.ts +14 -0
- package/dist/api/compiler/transformers/logical-assignment.js +62 -0
- package/dist/api/compiler/transformers/module-utilities.d.ts +9 -0
- package/dist/api/compiler/transformers/module-utilities.js +36 -0
- package/dist/api/compiler/transformers/module.d.ts +49 -0
- package/dist/api/compiler/transformers/module.js +296 -0
- package/dist/api/compiler/transformers/named-evaluation.d.ts +26 -0
- package/dist/api/compiler/transformers/named-evaluation.js +266 -0
- package/dist/api/compiler/transformers/nullish-coalescing.d.ts +9 -0
- package/dist/api/compiler/transformers/nullish-coalescing.js +26 -0
- package/dist/api/compiler/transformers/object-rest-spread.d.ts +34 -0
- package/dist/api/compiler/transformers/object-rest-spread.js +411 -0
- package/dist/api/compiler/transformers/optional-catch.d.ts +9 -0
- package/dist/api/compiler/transformers/optional-catch.js +20 -0
- package/dist/api/compiler/transformers/optional-chain.d.ts +14 -0
- package/dist/api/compiler/transformers/optional-chain.js +188 -0
- package/dist/api/compiler/transformers/reference-resolver.d.ts +128 -0
- package/dist/api/compiler/transformers/reference-resolver.js +1155 -0
- package/dist/api/compiler/transformers/runtime-syntax.d.ts +71 -0
- package/dist/api/compiler/transformers/runtime-syntax.js +753 -0
- package/dist/api/compiler/transformers/subtree-facts.d.ts +9 -0
- package/dist/api/compiler/transformers/subtree-facts.js +203 -0
- package/dist/api/compiler/transformers/syntax-facts.d.ts +51 -0
- package/dist/api/compiler/transformers/syntax-facts.js +254 -0
- package/dist/api/compiler/transformers/tagged-template.d.ts +17 -0
- package/dist/api/compiler/transformers/tagged-template.js +148 -0
- package/dist/api/compiler/transformers/transformer.d.ts +17 -0
- package/dist/api/compiler/transformers/transformer.js +54 -0
- package/dist/api/compiler/transformers/type-eraser.d.ts +21 -0
- package/dist/api/compiler/transformers/type-eraser.js +346 -0
- package/dist/api/compiler/transformers/type-serialization.d.ts +20 -0
- package/dist/api/compiler/transformers/type-serialization.js +347 -0
- package/dist/api/compiler/transformers/using.d.ts +56 -0
- package/dist/api/compiler/transformers/using.js +453 -0
- package/dist/api/compiler/transformers/utilities.d.ts +50 -0
- package/dist/api/compiler/transformers/utilities.js +347 -0
- package/dist/api/compiler/transformers/visitor-base.d.ts +6 -0
- package/dist/api/compiler/transformers/visitor-base.js +817 -0
- package/dist/api/compiler/transformers/visitor-hooks.d.ts +29 -0
- package/dist/api/compiler/transformers/visitor-hooks.js +189 -0
- package/dist/api/compiler/tsconfig.d.ts +177 -0
- package/dist/api/compiler/tsconfig.js +1311 -0
- package/dist/api/compiler/type-printer.d.ts +15 -0
- package/dist/api/compiler/type-printer.js +74 -0
- package/dist/api/compiler/types.d.ts +87 -0
- package/dist/api/compiler/types.js +23 -0
- package/dist/api/compiler/unicode-identifiers.d.ts +2 -0
- package/dist/api/compiler/unicode-identifiers.js +209 -0
- package/dist/api/compiler/unicode-properties.d.ts +8 -0
- package/dist/api/compiler/unicode-properties.js +531 -0
- package/dist/api/compiler/vfs-match.d.ts +24 -0
- package/dist/api/compiler/vfs-match.js +587 -0
- package/dist/api/library/ast.d.ts +3 -2
- package/dist/api/library/ast.generated.d.ts +127 -139
- package/dist/api/library/checker.d.ts +51 -0
- package/dist/api/library/checker.js +318 -0
- package/dist/api/library/diagnostics.d.ts +13 -0
- package/dist/api/library/diagnostics.js +50 -0
- package/dist/api/library/disk.d.ts +13 -0
- package/dist/api/library/disk.js +66 -0
- package/dist/api/library/errors.d.ts +13 -0
- package/dist/api/library/errors.js +24 -0
- package/dist/api/library/host.d.ts +24 -0
- package/dist/api/library/host.js +52 -0
- package/dist/api/library/index.d.ts +5 -1
- package/dist/api/library/index.js +4 -0
- package/dist/api/library/nodes.d.ts +51 -0
- package/dist/api/library/nodes.js +196 -0
- package/dist/api/library/options.d.ts +144 -0
- package/dist/api/library/options.js +308 -0
- package/dist/api/library/parse.d.ts +19 -0
- package/dist/api/library/parse.js +41 -0
- package/dist/api/library/program.d.ts +21 -0
- package/dist/api/library/program.js +234 -0
- package/dist/api/library/types.d.ts +14 -1
- package/package.json +12 -8
- package/src/compiler/ast-utilities.ts +548 -0
- package/src/compiler/ast.ts +12862 -0
- package/src/compiler/astnav.ts +799 -0
- package/src/compiler/binder-utilities.ts +1392 -0
- package/src/compiler/binder.ts +2703 -0
- package/src/compiler/build-info.ts +1197 -0
- package/src/compiler/character-codes.ts +323 -0
- package/src/compiler/checker-calls.ts +2155 -0
- package/src/compiler/checker-classes.ts +706 -0
- package/src/compiler/checker-contextual.ts +1457 -0
- package/src/compiler/checker-declaration-order.ts +438 -0
- package/src/compiler/checker-declarations.ts +1194 -0
- package/src/compiler/checker-declared-types.ts +919 -0
- package/src/compiler/checker-decorators.ts +694 -0
- package/src/compiler/checker-deprecation.ts +359 -0
- package/src/compiler/checker-destructuring.ts +805 -0
- package/src/compiler/checker-elaboration.ts +477 -0
- package/src/compiler/checker-emit-helpers.ts +224 -0
- package/src/compiler/checker-emit-resolver.ts +769 -0
- package/src/compiler/checker-evaluator.ts +243 -0
- package/src/compiler/checker-expressions.ts +1831 -0
- package/src/compiler/checker-features.ts +361 -0
- package/src/compiler/checker-flow.ts +394 -0
- package/src/compiler/checker-functions.ts +1296 -0
- package/src/compiler/checker-generated-code.ts +227 -0
- package/src/compiler/checker-globals.ts +52 -0
- package/src/compiler/checker-grammar.ts +3584 -0
- package/src/compiler/checker-heritage.ts +1233 -0
- package/src/compiler/checker-inference.ts +2576 -0
- package/src/compiler/checker-iteration.ts +1206 -0
- package/src/compiler/checker-javascript.ts +502 -0
- package/src/compiler/checker-jsdoc.ts +360 -0
- package/src/compiler/checker-jsx.ts +1924 -0
- package/src/compiler/checker-literals.ts +61 -0
- package/src/compiler/checker-members.ts +2436 -0
- package/src/compiler/checker-modules.ts +2886 -0
- package/src/compiler/checker-narrowing.ts +3230 -0
- package/src/compiler/checker-object-literals.ts +575 -0
- package/src/compiler/checker-operators.ts +1422 -0
- package/src/compiler/checker-overloads.ts +328 -0
- package/src/compiler/checker-property-access.ts +906 -0
- package/src/compiler/checker-services.ts +1149 -0
- package/src/compiler/checker-signatures.ts +1032 -0
- package/src/compiler/checker-source-file.ts +732 -0
- package/src/compiler/checker-statements.ts +292 -0
- package/src/compiler/checker-super.ts +261 -0
- package/src/compiler/checker-symbol-types.ts +2107 -0
- package/src/compiler/checker-symbols.ts +2150 -0
- package/src/compiler/checker-type-factory.ts +2579 -0
- package/src/compiler/checker-type-nodes.ts +1033 -0
- package/src/compiler/checker-type-operators.ts +2502 -0
- package/src/compiler/checker-types.ts +2340 -0
- package/src/compiler/checker-unused.ts +642 -0
- package/src/compiler/checker-utilities.ts +161 -0
- package/src/compiler/checker.ts +1116 -0
- package/src/compiler/command-line.ts +436 -0
- package/src/compiler/compile-program.ts +439 -0
- package/src/compiler/decoder.ts +1209 -0
- package/src/compiler/diagnostic-locales.ts +86 -0
- package/src/compiler/diagnostic-messages.ts +2349 -0
- package/src/compiler/diagnostics.ts +897 -0
- package/src/compiler/emitter.ts +434 -0
- package/src/compiler/encoder.ts +1945 -0
- package/src/compiler/file-include.ts +673 -0
- package/src/compiler/file-loader.ts +1528 -0
- package/src/compiler/file-system.ts +143 -0
- package/src/compiler/flow.ts +89 -0
- package/src/compiler/help.ts +473 -0
- package/src/compiler/incremental.ts +2784 -0
- package/src/compiler/init.ts +141 -0
- package/src/compiler/instantiation.ts +894 -0
- package/src/compiler/jsdoc.ts +1386 -0
- package/src/compiler/link-tables.ts +98 -0
- package/src/compiler/locale-data.ts +203 -0
- package/src/compiler/locale.ts +307 -0
- package/src/compiler/locales/cs-CZ.ts +5 -0
- package/src/compiler/locales/de-DE.ts +5 -0
- package/src/compiler/locales/es-ES.ts +5 -0
- package/src/compiler/locales/fr-FR.ts +5 -0
- package/src/compiler/locales/it-IT.ts +5 -0
- package/src/compiler/locales/ja-JP.ts +5 -0
- package/src/compiler/locales/ko-KR.ts +5 -0
- package/src/compiler/locales/pl-PL.ts +5 -0
- package/src/compiler/locales/pt-BR.ts +5 -0
- package/src/compiler/locales/ru-RU.ts +5 -0
- package/src/compiler/locales/tr-TR.ts +5 -0
- package/src/compiler/locales/zh-CN.ts +5 -0
- package/src/compiler/locales/zh-TW.ts +5 -0
- package/src/compiler/module-resolution-types.ts +243 -0
- package/src/compiler/module-resolution.ts +2072 -0
- package/src/compiler/module-specifiers.ts +1491 -0
- package/src/compiler/name-resolver.ts +646 -0
- package/src/compiler/node-builder-names.ts +1069 -0
- package/src/compiler/node-builder-pseudo.ts +892 -0
- package/src/compiler/node-builder-reuse.ts +764 -0
- package/src/compiler/node-builder.ts +3425 -0
- package/src/compiler/option-declarations.ts +1560 -0
- package/src/compiler/options.ts +1576 -0
- package/src/compiler/output-paths.ts +334 -0
- package/src/compiler/package-json.ts +1083 -0
- package/src/compiler/parallel-check.ts +1951 -0
- package/src/compiler/parallel-parse.ts +590 -0
- package/src/compiler/parse-thread.ts +140 -0
- package/src/compiler/parser.ts +7716 -0
- package/src/compiler/path.ts +717 -0
- package/src/compiler/printer/async-helpers.ts +183 -0
- package/src/compiler/printer/auto-generate.ts +27 -0
- package/src/compiler/printer/decorator-helpers.ts +218 -0
- package/src/compiler/printer/emit-context.ts +679 -0
- package/src/compiler/printer/emit-flags.ts +64 -0
- package/src/compiler/printer/factory-base.ts +2577 -0
- package/src/compiler/printer/factory.ts +764 -0
- package/src/compiler/printer/helpers.ts +291 -0
- package/src/compiler/printer/name-generator.ts +372 -0
- package/src/compiler/printer/printer.ts +5072 -0
- package/src/compiler/printer/text-writer.ts +183 -0
- package/src/compiler/printer/utilities.ts +884 -0
- package/src/compiler/program-checker.ts +592 -0
- package/src/compiler/program-utilities.ts +435 -0
- package/src/compiler/program.ts +1419 -0
- package/src/compiler/pseudo-bigint.ts +62 -0
- package/src/compiler/regexp-checker.ts +1142 -0
- package/src/compiler/relations.ts +5149 -0
- package/src/compiler/reparser.ts +1566 -0
- package/src/compiler/scanner.ts +2951 -0
- package/src/compiler/show-config.ts +239 -0
- package/src/compiler/side-state.ts +125 -0
- package/src/compiler/sourcemap.ts +366 -0
- package/src/compiler/spelling.ts +122 -0
- package/src/compiler/symbol-accessibility.ts +1071 -0
- package/src/compiler/symbol.ts +439 -0
- package/src/compiler/symlinks.ts +137 -0
- package/src/compiler/syntax-kind.ts +391 -0
- package/src/compiler/thread-entry.ts +191 -0
- package/src/compiler/timeline.ts +53 -0
- package/src/compiler/transformers/alias-references.ts +757 -0
- package/src/compiler/transformers/async-utilities.ts +335 -0
- package/src/compiler/transformers/async.ts +838 -0
- package/src/compiler/transformers/class-fields.ts +2967 -0
- package/src/compiler/transformers/class-utilities.ts +324 -0
- package/src/compiler/transformers/commonjs-module.ts +1621 -0
- package/src/compiler/transformers/const-enum-inliner.ts +50 -0
- package/src/compiler/transformers/declarations-diagnostics.ts +832 -0
- package/src/compiler/transformers/declarations-pseudo.ts +966 -0
- package/src/compiler/transformers/declarations-resolver.ts +249 -0
- package/src/compiler/transformers/declarations-syntactic.ts +1859 -0
- package/src/compiler/transformers/declarations-tracker.ts +269 -0
- package/src/compiler/transformers/declarations.ts +3120 -0
- package/src/compiler/transformers/decorator-metadata.ts +697 -0
- package/src/compiler/transformers/decorator-utilities.ts +283 -0
- package/src/compiler/transformers/destructuring.ts +708 -0
- package/src/compiler/transformers/downlevel.ts +50 -0
- package/src/compiler/transformers/emit-resolver.ts +258 -0
- package/src/compiler/transformers/es-decorators.ts +2682 -0
- package/src/compiler/transformers/exponentiation.ts +80 -0
- package/src/compiler/transformers/external-module-info.ts +412 -0
- package/src/compiler/transformers/for-await.ts +687 -0
- package/src/compiler/transformers/import-elision.ts +152 -0
- package/src/compiler/transformers/jsx-entities.ts +256 -0
- package/src/compiler/transformers/jsx.ts +824 -0
- package/src/compiler/transformers/legacy-decorators.ts +726 -0
- package/src/compiler/transformers/logical-assignment.ts +75 -0
- package/src/compiler/transformers/module-utilities.ts +42 -0
- package/src/compiler/transformers/module.ts +474 -0
- package/src/compiler/transformers/named-evaluation.ts +389 -0
- package/src/compiler/transformers/nullish-coalescing.ts +35 -0
- package/src/compiler/transformers/object-rest-spread.ts +577 -0
- package/src/compiler/transformers/optional-catch.ts +29 -0
- package/src/compiler/transformers/optional-chain.ts +246 -0
- package/src/compiler/transformers/reference-resolver.ts +1201 -0
- package/src/compiler/transformers/runtime-syntax.ts +942 -0
- package/src/compiler/transformers/subtree-facts.ts +245 -0
- package/src/compiler/transformers/syntax-facts.ts +353 -0
- package/src/compiler/transformers/tagged-template.ts +167 -0
- package/src/compiler/transformers/transformer.ts +56 -0
- package/src/compiler/transformers/type-eraser.ts +520 -0
- package/src/compiler/transformers/type-serialization.ts +374 -0
- package/src/compiler/transformers/using.ts +613 -0
- package/src/compiler/transformers/utilities.ts +419 -0
- package/src/compiler/transformers/visitor-base.ts +1601 -0
- package/src/compiler/transformers/visitor-hooks.ts +252 -0
- package/src/compiler/tsc-build.ts +1418 -0
- package/src/compiler/tsc-cli.ts +666 -0
- package/src/compiler/tsc-compile.ts +437 -0
- package/src/compiler/tsc-watch.ts +854 -0
- package/src/compiler/tsconfig.ts +1574 -0
- package/src/compiler/type-printer.ts +110 -0
- package/src/compiler/types.ts +115 -0
- package/src/compiler/unicode-identifiers.ts +212 -0
- package/src/compiler/unicode-properties.ts +537 -0
- package/src/compiler/vfs-match.ts +597 -0
- package/src/compiler/xxh3.ts +650 -0
- package/src/library/ast.generated.ts +141 -167
- package/src/library/ast.ts +4 -1
- package/src/library/checker.ts +384 -0
- package/src/library/diagnostics.ts +72 -0
- package/src/library/disk.ts +73 -0
- package/src/library/errors.ts +26 -0
- package/src/library/host.ts +63 -0
- package/src/library/index.ts +21 -0
- package/src/library/nodes.ts +232 -0
- package/src/library/options.ts +449 -0
- package/src/library/parse.ts +63 -0
- package/src/library/program.ts +293 -0
- package/src/library/types.ts +14 -1
|
@@ -0,0 +1,2951 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CharacterCodes,
|
|
3
|
+
charSize,
|
|
4
|
+
codePointAt,
|
|
5
|
+
isASCIILetter,
|
|
6
|
+
isDigit,
|
|
7
|
+
isHexDigit,
|
|
8
|
+
isIdentifierPart,
|
|
9
|
+
isIdentifierStart,
|
|
10
|
+
isLineBreak,
|
|
11
|
+
isOctalDigit,
|
|
12
|
+
isWhiteSpaceLike,
|
|
13
|
+
isWhiteSpaceSingleLine,
|
|
14
|
+
} from './character-codes.js';
|
|
15
|
+
import { Diagnostics } from './diagnostic-messages.js';
|
|
16
|
+
import type { DiagnosticMessage } from './diagnostics.js';
|
|
17
|
+
import { parsePseudoBigInt } from './pseudo-bigint.js';
|
|
18
|
+
import {
|
|
19
|
+
EscapeSequenceScanningFlags,
|
|
20
|
+
EscapeValue,
|
|
21
|
+
RegularExpressionFlags,
|
|
22
|
+
checkRegularExpression,
|
|
23
|
+
regularExpressionFlag,
|
|
24
|
+
} from './regexp-checker.js';
|
|
25
|
+
import { SyntaxKind } from './syntax-kind.js';
|
|
26
|
+
import {
|
|
27
|
+
CommentDirective,
|
|
28
|
+
CommentDirectiveKind,
|
|
29
|
+
CommentRange,
|
|
30
|
+
LanguageVariant,
|
|
31
|
+
ScriptTarget,
|
|
32
|
+
TokenFlags,
|
|
33
|
+
} from './types.js';
|
|
34
|
+
|
|
35
|
+
export { isIdentifierPart, isIdentifierStart } from './character-codes.js';
|
|
36
|
+
export { EscapeSequenceScanningFlags, EscapeValue } from './regexp-checker.js';
|
|
37
|
+
|
|
38
|
+
const textToKeyword: Map<string, SyntaxKind> = new Map<string, SyntaxKind>([
|
|
39
|
+
['abstract', SyntaxKind.AbstractKeyword],
|
|
40
|
+
['accessor', SyntaxKind.AccessorKeyword],
|
|
41
|
+
['any', SyntaxKind.AnyKeyword],
|
|
42
|
+
['as', SyntaxKind.AsKeyword],
|
|
43
|
+
['asserts', SyntaxKind.AssertsKeyword],
|
|
44
|
+
['assert', SyntaxKind.AssertKeyword],
|
|
45
|
+
['bigint', SyntaxKind.BigIntKeyword],
|
|
46
|
+
['boolean', SyntaxKind.BooleanKeyword],
|
|
47
|
+
['break', SyntaxKind.BreakKeyword],
|
|
48
|
+
['case', SyntaxKind.CaseKeyword],
|
|
49
|
+
['catch', SyntaxKind.CatchKeyword],
|
|
50
|
+
['class', SyntaxKind.ClassKeyword],
|
|
51
|
+
['continue', SyntaxKind.ContinueKeyword],
|
|
52
|
+
['const', SyntaxKind.ConstKeyword],
|
|
53
|
+
['constructor', SyntaxKind.ConstructorKeyword],
|
|
54
|
+
['debugger', SyntaxKind.DebuggerKeyword],
|
|
55
|
+
['declare', SyntaxKind.DeclareKeyword],
|
|
56
|
+
['default', SyntaxKind.DefaultKeyword],
|
|
57
|
+
['defer', SyntaxKind.DeferKeyword],
|
|
58
|
+
['delete', SyntaxKind.DeleteKeyword],
|
|
59
|
+
['do', SyntaxKind.DoKeyword],
|
|
60
|
+
['else', SyntaxKind.ElseKeyword],
|
|
61
|
+
['enum', SyntaxKind.EnumKeyword],
|
|
62
|
+
['export', SyntaxKind.ExportKeyword],
|
|
63
|
+
['extends', SyntaxKind.ExtendsKeyword],
|
|
64
|
+
['false', SyntaxKind.FalseKeyword],
|
|
65
|
+
['finally', SyntaxKind.FinallyKeyword],
|
|
66
|
+
['for', SyntaxKind.ForKeyword],
|
|
67
|
+
['from', SyntaxKind.FromKeyword],
|
|
68
|
+
['function', SyntaxKind.FunctionKeyword],
|
|
69
|
+
['get', SyntaxKind.GetKeyword],
|
|
70
|
+
['if', SyntaxKind.IfKeyword],
|
|
71
|
+
['immediate', SyntaxKind.ImmediateKeyword],
|
|
72
|
+
['implements', SyntaxKind.ImplementsKeyword],
|
|
73
|
+
['import', SyntaxKind.ImportKeyword],
|
|
74
|
+
['in', SyntaxKind.InKeyword],
|
|
75
|
+
['infer', SyntaxKind.InferKeyword],
|
|
76
|
+
['instanceof', SyntaxKind.InstanceOfKeyword],
|
|
77
|
+
['interface', SyntaxKind.InterfaceKeyword],
|
|
78
|
+
['intrinsic', SyntaxKind.IntrinsicKeyword],
|
|
79
|
+
['is', SyntaxKind.IsKeyword],
|
|
80
|
+
['keyof', SyntaxKind.KeyOfKeyword],
|
|
81
|
+
['let', SyntaxKind.LetKeyword],
|
|
82
|
+
['module', SyntaxKind.ModuleKeyword],
|
|
83
|
+
['namespace', SyntaxKind.NamespaceKeyword],
|
|
84
|
+
['never', SyntaxKind.NeverKeyword],
|
|
85
|
+
['new', SyntaxKind.NewKeyword],
|
|
86
|
+
['null', SyntaxKind.NullKeyword],
|
|
87
|
+
['number', SyntaxKind.NumberKeyword],
|
|
88
|
+
['object', SyntaxKind.ObjectKeyword],
|
|
89
|
+
['package', SyntaxKind.PackageKeyword],
|
|
90
|
+
['private', SyntaxKind.PrivateKeyword],
|
|
91
|
+
['protected', SyntaxKind.ProtectedKeyword],
|
|
92
|
+
['public', SyntaxKind.PublicKeyword],
|
|
93
|
+
['override', SyntaxKind.OverrideKeyword],
|
|
94
|
+
['out', SyntaxKind.OutKeyword],
|
|
95
|
+
['readonly', SyntaxKind.ReadonlyKeyword],
|
|
96
|
+
['require', SyntaxKind.RequireKeyword],
|
|
97
|
+
['global', SyntaxKind.GlobalKeyword],
|
|
98
|
+
['return', SyntaxKind.ReturnKeyword],
|
|
99
|
+
['satisfies', SyntaxKind.SatisfiesKeyword],
|
|
100
|
+
['set', SyntaxKind.SetKeyword],
|
|
101
|
+
['static', SyntaxKind.StaticKeyword],
|
|
102
|
+
['string', SyntaxKind.StringKeyword],
|
|
103
|
+
['super', SyntaxKind.SuperKeyword],
|
|
104
|
+
['switch', SyntaxKind.SwitchKeyword],
|
|
105
|
+
['symbol', SyntaxKind.SymbolKeyword],
|
|
106
|
+
['this', SyntaxKind.ThisKeyword],
|
|
107
|
+
['throw', SyntaxKind.ThrowKeyword],
|
|
108
|
+
['true', SyntaxKind.TrueKeyword],
|
|
109
|
+
['try', SyntaxKind.TryKeyword],
|
|
110
|
+
['type', SyntaxKind.TypeKeyword],
|
|
111
|
+
['typeof', SyntaxKind.TypeOfKeyword],
|
|
112
|
+
['undefined', SyntaxKind.UndefinedKeyword],
|
|
113
|
+
['unique', SyntaxKind.UniqueKeyword],
|
|
114
|
+
['unknown', SyntaxKind.UnknownKeyword],
|
|
115
|
+
['using', SyntaxKind.UsingKeyword],
|
|
116
|
+
['var', SyntaxKind.VarKeyword],
|
|
117
|
+
['void', SyntaxKind.VoidKeyword],
|
|
118
|
+
['while', SyntaxKind.WhileKeyword],
|
|
119
|
+
['with', SyntaxKind.WithKeyword],
|
|
120
|
+
['yield', SyntaxKind.YieldKeyword],
|
|
121
|
+
['async', SyntaxKind.AsyncKeyword],
|
|
122
|
+
['await', SyntaxKind.AwaitKeyword],
|
|
123
|
+
['of', SyntaxKind.OfKeyword],
|
|
124
|
+
]);
|
|
125
|
+
|
|
126
|
+
const textToToken: Map<string, SyntaxKind> = new Map<string, SyntaxKind>([
|
|
127
|
+
['{', SyntaxKind.OpenBraceToken],
|
|
128
|
+
['}', SyntaxKind.CloseBraceToken],
|
|
129
|
+
['(', SyntaxKind.OpenParenToken],
|
|
130
|
+
[')', SyntaxKind.CloseParenToken],
|
|
131
|
+
['[', SyntaxKind.OpenBracketToken],
|
|
132
|
+
[']', SyntaxKind.CloseBracketToken],
|
|
133
|
+
['.', SyntaxKind.DotToken],
|
|
134
|
+
['...', SyntaxKind.DotDotDotToken],
|
|
135
|
+
[';', SyntaxKind.SemicolonToken],
|
|
136
|
+
[',', SyntaxKind.CommaToken],
|
|
137
|
+
['<', SyntaxKind.LessThanToken],
|
|
138
|
+
['>', SyntaxKind.GreaterThanToken],
|
|
139
|
+
['<=', SyntaxKind.LessThanEqualsToken],
|
|
140
|
+
['>=', SyntaxKind.GreaterThanEqualsToken],
|
|
141
|
+
['==', SyntaxKind.EqualsEqualsToken],
|
|
142
|
+
['!=', SyntaxKind.ExclamationEqualsToken],
|
|
143
|
+
['===', SyntaxKind.EqualsEqualsEqualsToken],
|
|
144
|
+
['!==', SyntaxKind.ExclamationEqualsEqualsToken],
|
|
145
|
+
['=>', SyntaxKind.EqualsGreaterThanToken],
|
|
146
|
+
['+', SyntaxKind.PlusToken],
|
|
147
|
+
['-', SyntaxKind.MinusToken],
|
|
148
|
+
['**', SyntaxKind.AsteriskAsteriskToken],
|
|
149
|
+
['*', SyntaxKind.AsteriskToken],
|
|
150
|
+
['/', SyntaxKind.SlashToken],
|
|
151
|
+
['%', SyntaxKind.PercentToken],
|
|
152
|
+
['++', SyntaxKind.PlusPlusToken],
|
|
153
|
+
['--', SyntaxKind.MinusMinusToken],
|
|
154
|
+
['<<', SyntaxKind.LessThanLessThanToken],
|
|
155
|
+
['</', SyntaxKind.LessThanSlashToken],
|
|
156
|
+
['>>', SyntaxKind.GreaterThanGreaterThanToken],
|
|
157
|
+
['>>>', SyntaxKind.GreaterThanGreaterThanGreaterThanToken],
|
|
158
|
+
['&', SyntaxKind.AmpersandToken],
|
|
159
|
+
['|', SyntaxKind.BarToken],
|
|
160
|
+
['^', SyntaxKind.CaretToken],
|
|
161
|
+
['!', SyntaxKind.ExclamationToken],
|
|
162
|
+
['~', SyntaxKind.TildeToken],
|
|
163
|
+
['&&', SyntaxKind.AmpersandAmpersandToken],
|
|
164
|
+
['||', SyntaxKind.BarBarToken],
|
|
165
|
+
['?', SyntaxKind.QuestionToken],
|
|
166
|
+
['??', SyntaxKind.QuestionQuestionToken],
|
|
167
|
+
['?.', SyntaxKind.QuestionDotToken],
|
|
168
|
+
[':', SyntaxKind.ColonToken],
|
|
169
|
+
['=', SyntaxKind.EqualsToken],
|
|
170
|
+
['+=', SyntaxKind.PlusEqualsToken],
|
|
171
|
+
['-=', SyntaxKind.MinusEqualsToken],
|
|
172
|
+
['*=', SyntaxKind.AsteriskEqualsToken],
|
|
173
|
+
['**=', SyntaxKind.AsteriskAsteriskEqualsToken],
|
|
174
|
+
['/=', SyntaxKind.SlashEqualsToken],
|
|
175
|
+
['%=', SyntaxKind.PercentEqualsToken],
|
|
176
|
+
['<<=', SyntaxKind.LessThanLessThanEqualsToken],
|
|
177
|
+
['>>=', SyntaxKind.GreaterThanGreaterThanEqualsToken],
|
|
178
|
+
['>>>=', SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken],
|
|
179
|
+
['&=', SyntaxKind.AmpersandEqualsToken],
|
|
180
|
+
['|=', SyntaxKind.BarEqualsToken],
|
|
181
|
+
['^=', SyntaxKind.CaretEqualsToken],
|
|
182
|
+
['||=', SyntaxKind.BarBarEqualsToken],
|
|
183
|
+
['&&=', SyntaxKind.AmpersandAmpersandEqualsToken],
|
|
184
|
+
['??=', SyntaxKind.QuestionQuestionEqualsToken],
|
|
185
|
+
['@', SyntaxKind.AtToken],
|
|
186
|
+
['#', SyntaxKind.HashToken],
|
|
187
|
+
['`', SyntaxKind.BacktickToken],
|
|
188
|
+
]);
|
|
189
|
+
|
|
190
|
+
const tokenToText: string[] = [];
|
|
191
|
+
for (let kind = 0; kind <= SyntaxKind.LastToken; kind++) tokenToText.push('');
|
|
192
|
+
for (const [text, kind] of textToToken) tokenToText[kind] = text;
|
|
193
|
+
for (const [text, kind] of textToKeyword) tokenToText[kind] = text;
|
|
194
|
+
|
|
195
|
+
// Keywords bucketed by first letter and length, so identifiers are classified
|
|
196
|
+
// without allocating their text.
|
|
197
|
+
const keywordBucketStart = new Int32Array(26 * 13 + 2);
|
|
198
|
+
const keywordKinds = new Uint16Array(textToKeyword.size);
|
|
199
|
+
// The code units of every keyword, 12 slots each, in bucket order.
|
|
200
|
+
const keywordCodeUnits = new Uint16Array(textToKeyword.size * 12);
|
|
201
|
+
{
|
|
202
|
+
for (const text of textToKeyword.keys()) keywordBucketStart[keywordBucket(text) + 2]++;
|
|
203
|
+
for (let i = 2; i < keywordBucketStart.length; i++) keywordBucketStart[i] += keywordBucketStart[i - 1];
|
|
204
|
+
for (const [text, kind] of textToKeyword) {
|
|
205
|
+
const slot = keywordBucketStart[keywordBucket(text) + 1]++;
|
|
206
|
+
keywordKinds[slot] = kind;
|
|
207
|
+
for (let j = 0; j < text.length; j++) keywordCodeUnits[slot * 12 + j] = text.charCodeAt(j);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
function keywordBucket(text: string): number {
|
|
212
|
+
return (text.charCodeAt(0) - CharacterCodes.a) * 13 + text.length;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** The keyword kind of the code units `chars[start, end)`, or `Identifier`. */
|
|
216
|
+
function keywordKindAt(chars: Uint16Array, start: number, end: number): SyntaxKind {
|
|
217
|
+
const length = (end - start) | 0;
|
|
218
|
+
if (length < 2 || length > 12) return SyntaxKind.Identifier;
|
|
219
|
+
const first = chars[start] | 0;
|
|
220
|
+
if (first < CharacterCodes.a || first > CharacterCodes.z) return SyntaxKind.Identifier;
|
|
221
|
+
const bucket = ((first - CharacterCodes.a) * 13 + length) | 0;
|
|
222
|
+
const last = keywordBucketStart[bucket + 1] | 0;
|
|
223
|
+
for (let i = keywordBucketStart[bucket] | 0; i < last; i = (i + 1) | 0) {
|
|
224
|
+
const base = (i * 12) | 0;
|
|
225
|
+
let j = 1;
|
|
226
|
+
while (j < length && (keywordCodeUnits[(base + j) | 0] | 0) === (chars[(start + j) | 0] | 0)) j = (j + 1) | 0;
|
|
227
|
+
if (j === length) return (keywordKinds[i]! | 0) as SyntaxKind;
|
|
228
|
+
}
|
|
229
|
+
return SyntaxKind.Identifier;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/** The keyword kind of `text`, or `Identifier`. */
|
|
233
|
+
export function getIdentifierToken(text: string): SyntaxKind {
|
|
234
|
+
if (text.length < 2 || text.length > 12) return SyntaxKind.Identifier;
|
|
235
|
+
const first = text.charCodeAt(0);
|
|
236
|
+
if (first < CharacterCodes.a || first > CharacterCodes.z) return SyntaxKind.Identifier;
|
|
237
|
+
// `| 0`: a SyntaxKind is an int32, which lets its storage stay int32.
|
|
238
|
+
return (textToKeyword.get(text) ?? SyntaxKind.Identifier) | 0;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/** The keyword kind of an identifier's text, or `Unknown`. */
|
|
242
|
+
export function identifierToKeywordKind(text: string): SyntaxKind {
|
|
243
|
+
return (textToKeyword.get(text) ?? SyntaxKind.Unknown) | 0;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export function tokenToString(kind: SyntaxKind): string {
|
|
247
|
+
return kind >= 0 && kind < tokenToText.length ? tokenToText[kind]! : '';
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
export function stringToToken(text: string): SyntaxKind {
|
|
251
|
+
return (textToToken.get(text) ?? textToKeyword.get(text) ?? SyntaxKind.Unknown) | 0;
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/** Keywords longer than two characters, for spelling suggestions. */
|
|
255
|
+
export function getViableKeywordSuggestions(): string[] {
|
|
256
|
+
const result: string[] = [];
|
|
257
|
+
for (const text of textToKeyword.keys()) if (text.length > 2) result.push(text);
|
|
258
|
+
return result;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export function tokenIsIdentifierOrKeyword(token: SyntaxKind): boolean {
|
|
262
|
+
return token >= SyntaxKind.Identifier;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/** Whether `name` is a valid identifier (JSX names may contain `-` and `:`). */
|
|
266
|
+
export function isIdentifierText(name: string, languageVariant = LanguageVariant.Standard): boolean {
|
|
267
|
+
let ch = codePointAt(name, 0, name.length);
|
|
268
|
+
if (!isIdentifierStart(ch)) return false;
|
|
269
|
+
for (let i = charSize(ch); i < name.length; i += charSize(ch)) {
|
|
270
|
+
ch = codePointAt(name, i, name.length);
|
|
271
|
+
if (!isIdentifierPart(ch, languageVariant)) return false;
|
|
272
|
+
}
|
|
273
|
+
return true;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/** Receives scanner diagnostics. An abstract class rather than a function so native builds dispatch statically. */
|
|
277
|
+
export abstract class ScannerErrorReporter {
|
|
278
|
+
abstract onError(message: DiagnosticMessage, start: number, length: number, args: readonly string[]): void;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const noArgs: readonly string[] = [];
|
|
282
|
+
|
|
283
|
+
/** A snapshot of the scanner's token state for `Scanner.rewind`. */
|
|
284
|
+
export class ScannerState {
|
|
285
|
+
pos: number;
|
|
286
|
+
fullStartPos: number;
|
|
287
|
+
tokenStart: number;
|
|
288
|
+
token: SyntaxKind;
|
|
289
|
+
tokenFlags: TokenFlags;
|
|
290
|
+
tokenValue: string;
|
|
291
|
+
valueStart: number;
|
|
292
|
+
valueEnd: number;
|
|
293
|
+
commentDirectiveCount: number;
|
|
294
|
+
skipJSDocLeadingAsterisks: number;
|
|
295
|
+
|
|
296
|
+
constructor(
|
|
297
|
+
pos: number,
|
|
298
|
+
fullStartPos: number,
|
|
299
|
+
tokenStart: number,
|
|
300
|
+
token: SyntaxKind,
|
|
301
|
+
tokenFlags: TokenFlags,
|
|
302
|
+
tokenValue: string,
|
|
303
|
+
valueStart: number,
|
|
304
|
+
valueEnd: number,
|
|
305
|
+
commentDirectiveCount: number,
|
|
306
|
+
skipJSDocLeadingAsterisks: number,
|
|
307
|
+
) {
|
|
308
|
+
this.pos = pos | 0;
|
|
309
|
+
this.fullStartPos = fullStartPos | 0;
|
|
310
|
+
this.tokenStart = tokenStart | 0;
|
|
311
|
+
this.token = token;
|
|
312
|
+
this.tokenFlags = tokenFlags;
|
|
313
|
+
this.tokenValue = tokenValue;
|
|
314
|
+
this.valueStart = valueStart | 0;
|
|
315
|
+
this.valueEnd = valueEnd | 0;
|
|
316
|
+
this.commentDirectiveCount = commentDirectiveCount;
|
|
317
|
+
this.skipJSDocLeadingAsterisks = skipJSDocLeadingAsterisks;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/** @internal Overwrites this snapshot with the scanner's current state, like `Scanner.mark`. */
|
|
321
|
+
assign(scanner: Scanner): void {
|
|
322
|
+
this.pos = scanner.pos | 0;
|
|
323
|
+
this.fullStartPos = scanner.fullStartPos;
|
|
324
|
+
this.tokenStart = scanner.tokenStart;
|
|
325
|
+
this.token = scanner.token;
|
|
326
|
+
this.tokenFlags = scanner.tokenFlags;
|
|
327
|
+
this.tokenValue = scanner.tokenValue;
|
|
328
|
+
this.valueStart = scanner.valueStart;
|
|
329
|
+
this.valueEnd = scanner.valueEnd;
|
|
330
|
+
this.commentDirectiveCount = scanner.commentDirectives.length;
|
|
331
|
+
this.skipJSDocLeadingAsterisks = scanner.skipJSDocLeadingAsterisks;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* `[A-Za-z0-9_$]`, for an int32 code unit. The scanner's hot loops test this inline rather than
|
|
337
|
+
* calling `isWordCharacter`, whose parameter native builds keep as a double.
|
|
338
|
+
*/
|
|
339
|
+
function isASCIIIdentifierPart(c: number): boolean {
|
|
340
|
+
return (
|
|
341
|
+
(c >= CharacterCodes.a && c <= CharacterCodes.z) ||
|
|
342
|
+
(c >= CharacterCodes.A && c <= CharacterCodes.Z) ||
|
|
343
|
+
(c >= CharacterCodes._0 && c <= CharacterCodes._9) ||
|
|
344
|
+
c === CharacterCodes._ ||
|
|
345
|
+
c === CharacterCodes.$
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/** FNV-1a over a range's code units. The identifier scan computes the same hash as it goes. */
|
|
350
|
+
function rangeHash(chars: Uint16Array, start: number, end: number): number {
|
|
351
|
+
let hash = 0x811c9dc5 | 0;
|
|
352
|
+
for (let i = start | 0; i < end; i = (i + 1) | 0) hash = Math.imul(hash ^ (chars[i] | 0), 0x01000193);
|
|
353
|
+
return finishHash(hash);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
function finishHash(hash: number): number {
|
|
357
|
+
return hash ^ (hash >>> 15);
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/** Strings for ranges of one text, keyed by their code units: equal identifiers share one string. */
|
|
361
|
+
class IdentifierTable {
|
|
362
|
+
private text: string;
|
|
363
|
+
// Pairs of (entry index + 1, hash) per slot, (0, 0) when empty; linear probing.
|
|
364
|
+
private slots: Int32Array;
|
|
365
|
+
// Each entry's length in code units.
|
|
366
|
+
private lengths: Int32Array;
|
|
367
|
+
private texts: string[];
|
|
368
|
+
private count: number;
|
|
369
|
+
// Per entry: 1 once its text was recorded among the file's identifier texts (`markRecorded`).
|
|
370
|
+
private recorded: Uint8Array;
|
|
371
|
+
// The entry the last `intern` returned.
|
|
372
|
+
private lastEntry: number;
|
|
373
|
+
|
|
374
|
+
constructor(text: string) {
|
|
375
|
+
this.text = text;
|
|
376
|
+
this.slots = new Int32Array(512);
|
|
377
|
+
this.lengths = new Int32Array(128);
|
|
378
|
+
this.texts = [];
|
|
379
|
+
this.count = 0;
|
|
380
|
+
this.recorded = new Uint8Array(128);
|
|
381
|
+
this.lastEntry = -1;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Whether `text`, just returned by `intern`, still needs recording among the file's identifier
|
|
386
|
+
* texts; marks it recorded. Texts the table doesn't know are always recorded.
|
|
387
|
+
*/
|
|
388
|
+
markRecorded(text: string): boolean {
|
|
389
|
+
const entry = this.lastEntry;
|
|
390
|
+
if (entry < 0 || this.texts[entry] !== text) return true;
|
|
391
|
+
if (this.recorded[entry] !== 0) return false;
|
|
392
|
+
this.recorded[entry] = 1;
|
|
393
|
+
return true;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/** Empties the table for a new text. */
|
|
397
|
+
setText(text: string): void {
|
|
398
|
+
this.text = text;
|
|
399
|
+
if (this.count === 0) return;
|
|
400
|
+
this.slots.fill(0);
|
|
401
|
+
this.recorded.fill(0, 0, this.count);
|
|
402
|
+
this.texts.length = 0;
|
|
403
|
+
this.count = 0;
|
|
404
|
+
this.lastEntry = -1;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/**
|
|
408
|
+
* `text.substring(start, end)`, or the string interned for an equal range; `hash` is its `rangeHash`.
|
|
409
|
+
* A candidate of the same hash and length is compared with `startsWith`, which natively compares
|
|
410
|
+
* the bytes of both strings at once.
|
|
411
|
+
*/
|
|
412
|
+
intern(start: number, end: number, hash: number): string {
|
|
413
|
+
start = start | 0;
|
|
414
|
+
end = end | 0;
|
|
415
|
+
hash = hash | 0;
|
|
416
|
+
const length = (end - start) | 0;
|
|
417
|
+
const slots = this.slots;
|
|
418
|
+
const mask = ((slots.length >> 1) - 1) | 0;
|
|
419
|
+
let slot = hash & mask;
|
|
420
|
+
for (;;) {
|
|
421
|
+
const entry = slots[(slot * 2) | 0] | 0;
|
|
422
|
+
if (entry === 0) break;
|
|
423
|
+
if ((slots[(slot * 2 + 1) | 0] | 0) === hash && (this.lengths[(entry - 1) | 0] | 0) === length) {
|
|
424
|
+
const candidate = this.texts[(entry - 1) | 0]!;
|
|
425
|
+
if (this.text.startsWith(candidate, start)) {
|
|
426
|
+
this.lastEntry = (entry - 1) | 0;
|
|
427
|
+
return candidate;
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
slot = (slot + 1) & mask;
|
|
431
|
+
}
|
|
432
|
+
const value = this.text.substring(start, end);
|
|
433
|
+
const index = this.count | 0;
|
|
434
|
+
if (index === this.lengths.length) {
|
|
435
|
+
const lengths = new Int32Array(index * 2);
|
|
436
|
+
lengths.set(this.lengths);
|
|
437
|
+
this.lengths = lengths;
|
|
438
|
+
const recorded = new Uint8Array(index * 2);
|
|
439
|
+
recorded.set(this.recorded);
|
|
440
|
+
this.recorded = recorded;
|
|
441
|
+
}
|
|
442
|
+
this.lengths[index] = length;
|
|
443
|
+
this.texts.push(value);
|
|
444
|
+
this.count = (index + 1) | 0;
|
|
445
|
+
this.lastEntry = index;
|
|
446
|
+
slots[(slot * 2) | 0] = (index + 1) | 0;
|
|
447
|
+
slots[(slot * 2 + 1) | 0] = hash;
|
|
448
|
+
if (this.count * 2 > mask + 1) this.slots = rehash(slots);
|
|
449
|
+
return value;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
/** `IdentifierTable` slots in a table twice the size. */
|
|
454
|
+
function rehash(old: Int32Array): Int32Array {
|
|
455
|
+
const slots = new Int32Array(old.length * 2);
|
|
456
|
+
const mask = slots.length / 2 - 1;
|
|
457
|
+
for (let i = 0; i < old.length; i += 2) {
|
|
458
|
+
const entry = old[i];
|
|
459
|
+
if (entry === 0) continue;
|
|
460
|
+
const hash = old[i + 1];
|
|
461
|
+
let slot = hash & mask;
|
|
462
|
+
while (slots[slot * 2] !== 0) slot = (slot + 1) & mask;
|
|
463
|
+
slots[slot * 2] = entry;
|
|
464
|
+
slots[slot * 2 + 1] = hash;
|
|
465
|
+
}
|
|
466
|
+
return slots;
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
/**
|
|
470
|
+
* The code units a scanner with code units on demand copies at a time: few enough that the comments
|
|
471
|
+
* of a large declaration file copy a small part of it, enough that a file whose comments are all
|
|
472
|
+
* parsed is copied in a few hundred writes.
|
|
473
|
+
*/
|
|
474
|
+
const unitBlockSize = 1024;
|
|
475
|
+
|
|
476
|
+
function isLowSurrogate(ch: number): boolean {
|
|
477
|
+
return ch >= 0xdc00 && ch <= 0xdfff;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
/** Which line breaks a text holds, for the comment scans that search it (`Scanner.getTextKind`). */
|
|
481
|
+
const enum TextKind {
|
|
482
|
+
Unknown = 0,
|
|
483
|
+
/** Line feeds only. */
|
|
484
|
+
LF = 1,
|
|
485
|
+
/** Line feeds and carriage returns. */
|
|
486
|
+
LFAndCR = 2,
|
|
487
|
+
/** Also line or paragraph separators (U+2028, U+2029): comments are scanned code unit by code unit. */
|
|
488
|
+
Separators = 3,
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
/** The UTF-16 code units of `text`, followed by zeros so the scanner can peek past the end. */
|
|
492
|
+
function toCodeUnits(text: string): Uint16Array {
|
|
493
|
+
const chars = new Uint16Array(text.length + 4);
|
|
494
|
+
Buffer.from(chars.buffer).write(text, 'utf16le');
|
|
495
|
+
return chars;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// The two loops below scan long runs. They index `chars` from `pos` on an int32 counter, which
|
|
499
|
+
// native builds compile to an integer loop without allocating a view.
|
|
500
|
+
|
|
501
|
+
/** The position of the next `` ` ``, `$`, `\\` or CR at or after `pos`, or `end`. */
|
|
502
|
+
function skipTemplateText(chars: Uint16Array, pos: number, end: number): number {
|
|
503
|
+
for (let i = pos | 0; i < end; i = (i + 1) | 0) {
|
|
504
|
+
const c = chars[i] | 0;
|
|
505
|
+
if (
|
|
506
|
+
c === CharacterCodes.backtick ||
|
|
507
|
+
c === CharacterCodes.$ ||
|
|
508
|
+
c === CharacterCodes.backslash ||
|
|
509
|
+
c === CharacterCodes.carriageReturn
|
|
510
|
+
)
|
|
511
|
+
return i;
|
|
512
|
+
}
|
|
513
|
+
return end;
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/** The position of the next `*`, `@`, line break or non-ASCII unit at or after `pos`, or `end`. */
|
|
517
|
+
function skipCommentText(chars: Uint16Array, pos: number, end: number): number {
|
|
518
|
+
for (let i = pos | 0; i < end; i = (i + 1) | 0) {
|
|
519
|
+
const c = chars[i] | 0;
|
|
520
|
+
if (
|
|
521
|
+
c === CharacterCodes.asterisk ||
|
|
522
|
+
c === CharacterCodes.at ||
|
|
523
|
+
c === CharacterCodes.lineFeed ||
|
|
524
|
+
c === CharacterCodes.carriageReturn ||
|
|
525
|
+
c > CharacterCodes.maxAsciiCharacter
|
|
526
|
+
)
|
|
527
|
+
return i;
|
|
528
|
+
}
|
|
529
|
+
return end;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
function hasPrefixAt(text: string, pos: number, prefix: string): boolean {
|
|
533
|
+
if (pos + prefix.length > text.length) return false;
|
|
534
|
+
for (let i = 0; i < prefix.length; i++) if (text.charCodeAt(pos + i) !== prefix.charCodeAt(i)) return false;
|
|
535
|
+
return true;
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
/** Whether `chars[pos, end)` starts with `tag` followed by whitespace, `}`, `*` or `end`. */
|
|
539
|
+
function hasJSDocTag(chars: Uint16Array, pos: number, end: number, tag: string): boolean {
|
|
540
|
+
const tagEnd = pos + tag.length;
|
|
541
|
+
if (tagEnd > end) return false;
|
|
542
|
+
for (let i = 0; i < tag.length; i++) if (chars[pos + i] !== tag.charCodeAt(i)) return false;
|
|
543
|
+
if (tagEnd === end) return true;
|
|
544
|
+
const ch = chars[tagEnd];
|
|
545
|
+
return (
|
|
546
|
+
ch === CharacterCodes.space ||
|
|
547
|
+
ch === CharacterCodes.tab ||
|
|
548
|
+
ch === CharacterCodes.lineFeed ||
|
|
549
|
+
ch === CharacterCodes.carriageReturn ||
|
|
550
|
+
ch === CharacterCodes.closeBrace ||
|
|
551
|
+
ch === CharacterCodes.asterisk
|
|
552
|
+
);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/** Adds the `@deprecated` and `@see`/`@link` flags for a JSDoc tag name at `pos`. */
|
|
556
|
+
function jsDocTagFlags(chars: Uint16Array, pos: number, end: number, flags: TokenFlags): TokenFlags {
|
|
557
|
+
if ((flags & TokenFlags.PrecedingJSDocWithDeprecated) === 0 && hasJSDocTag(chars, pos, end, 'deprecated'))
|
|
558
|
+
flags |= TokenFlags.PrecedingJSDocWithDeprecated;
|
|
559
|
+
if (
|
|
560
|
+
(flags & TokenFlags.PrecedingJSDocWithSeeOrLink) === 0 &&
|
|
561
|
+
(hasJSDocTag(chars, pos, end, 'see') ||
|
|
562
|
+
hasJSDocTag(chars, pos, end, 'link') ||
|
|
563
|
+
hasJSDocTag(chars, pos, end, 'linkcode') ||
|
|
564
|
+
hasJSDocTag(chars, pos, end, 'linkplain'))
|
|
565
|
+
)
|
|
566
|
+
flags |= TokenFlags.PrecedingJSDocWithSeeOrLink;
|
|
567
|
+
return flags;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
function hexByte(value: number): string {
|
|
571
|
+
const hex = value.toString(16);
|
|
572
|
+
return hex.length < 2 ? '\\x0' + hex : '\\x' + hex;
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
function regularExpressionFlagName(target: ScriptTarget): string {
|
|
576
|
+
switch (target) {
|
|
577
|
+
case ScriptTarget.ES2018:
|
|
578
|
+
return 'es2018';
|
|
579
|
+
case ScriptTarget.ES2022:
|
|
580
|
+
return 'es2022';
|
|
581
|
+
default:
|
|
582
|
+
return 'es2024';
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Tokenizes TypeScript and JavaScript source text. Positions are UTF-16 offsets.
|
|
588
|
+
*
|
|
589
|
+
* ```ts
|
|
590
|
+
* const scanner = new Scanner();
|
|
591
|
+
* scanner.setText(text);
|
|
592
|
+
* while (scanner.scan() !== SyntaxKind.EndOfFile) console.log(scanner.getTokenText());
|
|
593
|
+
* ```
|
|
594
|
+
*/
|
|
595
|
+
export class Scanner {
|
|
596
|
+
/** @internal */ text: string;
|
|
597
|
+
// The text's UTF-16 code units: indexing a typed array is much cheaper than
|
|
598
|
+
// `charCodeAt` on large native strings.
|
|
599
|
+
/** @internal */ chars: Uint16Array;
|
|
600
|
+
/** @internal */ end: number;
|
|
601
|
+
private languageVariant: LanguageVariant;
|
|
602
|
+
private scriptTarget: ScriptTarget;
|
|
603
|
+
private onError: ScannerErrorReporter | undefined;
|
|
604
|
+
private skipTrivia: boolean;
|
|
605
|
+
|
|
606
|
+
// Writes of the token offsets below are coerced with `| 0` where the compiler can't bound the
|
|
607
|
+
// value, so native builds store them as 32-bit integers. `pos` too: every write (also in the
|
|
608
|
+
// regular expression checker) is `(pos + n) | 0` or an int32 value, never `++` or `+=`, and hot
|
|
609
|
+
// loops copy it into an int32 local and read code units as `chars[i] | 0`, so they run on
|
|
610
|
+
// integers instead of doubles. Positions stay far below 2^31, so `| 0` never changes a value.
|
|
611
|
+
/** @internal Current position; the end of the current token. */
|
|
612
|
+
pos: number;
|
|
613
|
+
/** @internal */ fullStartPos: number;
|
|
614
|
+
/** @internal */ tokenStart: number;
|
|
615
|
+
/** @internal */ token: SyntaxKind;
|
|
616
|
+
/** @internal */ tokenFlags: TokenFlags;
|
|
617
|
+
// The token value is `text[valueStart, valueEnd)` while `valueStart >= 0`,
|
|
618
|
+
// so identifiers and keywords don't allocate until their value is read.
|
|
619
|
+
/** @internal */ tokenValue: string;
|
|
620
|
+
/** @internal */ valueStart: number;
|
|
621
|
+
/** @internal */ valueEnd: number;
|
|
622
|
+
// `rangeHash` of `chars[hashStart, hashEnd)`, which the ASCII identifier scan computes as it goes.
|
|
623
|
+
private valueHash: number;
|
|
624
|
+
private hashStart: number;
|
|
625
|
+
private hashEnd: number;
|
|
626
|
+
/** @internal */ commentDirectives: CommentDirective[];
|
|
627
|
+
/** @internal */ skipJSDocLeadingAsterisks: number;
|
|
628
|
+
// The code units zeroed by `setTextEnd`.
|
|
629
|
+
private readonly cutUnits: Uint16Array;
|
|
630
|
+
private readonly identifiers: IdentifierTable;
|
|
631
|
+
// With code units on demand: per block of `unitBlockSize` code units, 1 once `chars` holds them
|
|
632
|
+
// (`loadUnits`); `chars` is zero elsewhere.
|
|
633
|
+
private loadedBlocks: Uint8Array | undefined;
|
|
634
|
+
// The line breaks the text holds, computed on first use.
|
|
635
|
+
private textKind: TextKind;
|
|
636
|
+
// The first LF and CR at or after `lineFeedFrom` and `carriageReturnFrom`: `lineFeedAt` and
|
|
637
|
+
// `carriageReturnAt` (the text length where there is none), found by `nextLineFeed` and
|
|
638
|
+
// `nextCarriageReturn`. -1 for none found yet.
|
|
639
|
+
private lineFeedFrom: number;
|
|
640
|
+
private lineFeedAt: number;
|
|
641
|
+
private carriageReturnFrom: number;
|
|
642
|
+
private carriageReturnAt: number;
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* With `unitsOnDemand`, the code units of the text are copied only for the ranges passed to
|
|
646
|
+
* `loadUnits`, for scanning a few ranges of a large text.
|
|
647
|
+
*/
|
|
648
|
+
constructor(text = '', unitsOnDemand = false) {
|
|
649
|
+
this.text = text;
|
|
650
|
+
if (unitsOnDemand) {
|
|
651
|
+
this.chars = new Uint16Array(text.length + 4);
|
|
652
|
+
this.loadedBlocks = new Uint8Array(((text.length + unitBlockSize - 1) / unitBlockSize) | 0);
|
|
653
|
+
} else {
|
|
654
|
+
this.chars = toCodeUnits(text);
|
|
655
|
+
this.loadedBlocks = undefined;
|
|
656
|
+
}
|
|
657
|
+
this.end = text.length | 0;
|
|
658
|
+
this.languageVariant = LanguageVariant.Standard;
|
|
659
|
+
this.scriptTarget = ScriptTarget.None;
|
|
660
|
+
this.onError = undefined;
|
|
661
|
+
this.skipTrivia = true;
|
|
662
|
+
this.pos = 0;
|
|
663
|
+
this.fullStartPos = 0;
|
|
664
|
+
this.tokenStart = 0;
|
|
665
|
+
this.token = SyntaxKind.Unknown;
|
|
666
|
+
this.tokenFlags = TokenFlags.None;
|
|
667
|
+
this.tokenValue = '';
|
|
668
|
+
this.valueStart = -1;
|
|
669
|
+
this.valueEnd = -1;
|
|
670
|
+
this.valueHash = 0;
|
|
671
|
+
this.hashStart = -1;
|
|
672
|
+
this.hashEnd = -1;
|
|
673
|
+
this.commentDirectives = [];
|
|
674
|
+
this.skipJSDocLeadingAsterisks = 0;
|
|
675
|
+
this.cutUnits = new Uint16Array(4);
|
|
676
|
+
this.identifiers = new IdentifierTable(text);
|
|
677
|
+
this.textKind = TextKind.Unknown;
|
|
678
|
+
this.lineFeedFrom = -1;
|
|
679
|
+
this.lineFeedAt = -1;
|
|
680
|
+
this.carriageReturnFrom = -1;
|
|
681
|
+
this.carriageReturnAt = -1;
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/** Sets the text to scan and resets the token state. */
|
|
685
|
+
setText(text: string): void {
|
|
686
|
+
this.text = text;
|
|
687
|
+
this.chars = toCodeUnits(text);
|
|
688
|
+
this.loadedBlocks = undefined;
|
|
689
|
+
this.identifiers.setText(text);
|
|
690
|
+
this.textKind = TextKind.Unknown;
|
|
691
|
+
this.lineFeedFrom = -1;
|
|
692
|
+
this.lineFeedAt = -1;
|
|
693
|
+
this.carriageReturnFrom = -1;
|
|
694
|
+
this.carriageReturnAt = -1;
|
|
695
|
+
this.end = text.length | 0;
|
|
696
|
+
this.pos = 0;
|
|
697
|
+
this.fullStartPos = 0;
|
|
698
|
+
this.tokenStart = 0;
|
|
699
|
+
this.token = SyntaxKind.Unknown;
|
|
700
|
+
this.tokenFlags = TokenFlags.None;
|
|
701
|
+
this.tokenValue = '';
|
|
702
|
+
this.valueStart = -1;
|
|
703
|
+
this.hashStart = -1;
|
|
704
|
+
this.commentDirectives = [];
|
|
705
|
+
this.skipJSDocLeadingAsterisks = 0;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/** @internal Like `setText(text.substring(0, end))` without copying, but keeps comment directives; pass the text length to undo. */
|
|
709
|
+
setTextEnd(end: number): void {
|
|
710
|
+
const chars = this.chars;
|
|
711
|
+
const cut = this.cutUnits;
|
|
712
|
+
// Restore the units zeroed by the previous call, then zero the units past `end`.
|
|
713
|
+
if (this.end < this.text.length) for (let i = 0; i < 4; i++) chars[this.end + i] = cut[i];
|
|
714
|
+
if (end < this.text.length)
|
|
715
|
+
for (let i = 0; i < 4; i++) {
|
|
716
|
+
cut[i] = chars[end + i];
|
|
717
|
+
chars[end + i] = 0;
|
|
718
|
+
}
|
|
719
|
+
this.end = end | 0;
|
|
720
|
+
this.pos = 0;
|
|
721
|
+
this.fullStartPos = 0;
|
|
722
|
+
this.tokenStart = 0;
|
|
723
|
+
this.token = SyntaxKind.Unknown;
|
|
724
|
+
this.tokenFlags = TokenFlags.None;
|
|
725
|
+
this.tokenValue = '';
|
|
726
|
+
this.valueStart = -1;
|
|
727
|
+
this.hashStart = -1;
|
|
728
|
+
this.skipJSDocLeadingAsterisks = 0;
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/**
|
|
732
|
+
* @internal Where the scanner copies code units on demand, copies those of `text[start, end)`
|
|
733
|
+
* and the four around each end, a block of `unitBlockSize` units at a time (and whole surrogate
|
|
734
|
+
* pairs); otherwise does nothing.
|
|
735
|
+
*/
|
|
736
|
+
loadUnits(start: number, end: number): void {
|
|
737
|
+
const blocks = this.loadedBlocks;
|
|
738
|
+
if (blocks === undefined) return;
|
|
739
|
+
const text = this.text;
|
|
740
|
+
const length = text.length;
|
|
741
|
+
const last = Math.min(blocks.length - 1, ((end + 4) / unitBlockSize) | 0);
|
|
742
|
+
for (let block = (Math.max(0, start - 4) / unitBlockSize) | 0; block <= last; block++) {
|
|
743
|
+
if (blocks[block] !== 0) continue;
|
|
744
|
+
// The run of blocks not copied yet.
|
|
745
|
+
let runEnd = block;
|
|
746
|
+
while (runEnd < last && blocks[runEnd + 1] === 0) runEnd++;
|
|
747
|
+
let from = block * unitBlockSize;
|
|
748
|
+
let to = Math.min(length, (runEnd + 1) * unitBlockSize);
|
|
749
|
+
if (from > 0 && isLowSurrogate(text.charCodeAt(from))) from--;
|
|
750
|
+
if (to < length && isLowSurrogate(text.charCodeAt(to))) to++;
|
|
751
|
+
Buffer.from(this.chars.buffer, from * 2, (to - from) * 2).write(text.substring(from, to), 'utf16le');
|
|
752
|
+
blocks.fill(1, block, runEnd + 1);
|
|
753
|
+
block = runEnd;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
setOnError(reporter: ScannerErrorReporter | undefined): void {
|
|
758
|
+
this.onError = reporter;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
setLanguageVariant(languageVariant: LanguageVariant): void {
|
|
762
|
+
this.languageVariant = languageVariant;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
setScriptTarget(scriptTarget: ScriptTarget): void {
|
|
766
|
+
this.scriptTarget = scriptTarget;
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
/** When false, `scan` returns whitespace, newline and comment trivia tokens. */
|
|
770
|
+
setSkipTrivia(skip: boolean): void {
|
|
771
|
+
this.skipTrivia = skip;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
/** Nests skipping of JSDoc leading `*` after line breaks; balance every `true` with a `false`. */
|
|
775
|
+
setSkipJSDocLeadingAsterisks(skip: boolean): void {
|
|
776
|
+
this.skipJSDocLeadingAsterisks += skip ? 1 : -1;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
getText(): string {
|
|
780
|
+
return this.text;
|
|
781
|
+
}
|
|
782
|
+
|
|
783
|
+
getToken(): SyntaxKind {
|
|
784
|
+
return this.token;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
getTokenFlags(): TokenFlags {
|
|
788
|
+
return this.tokenFlags;
|
|
789
|
+
}
|
|
790
|
+
|
|
791
|
+
/** Start of the token including leading trivia. */
|
|
792
|
+
getTokenFullStart(): number {
|
|
793
|
+
return this.fullStartPos;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
getTokenStart(): number {
|
|
797
|
+
return this.tokenStart;
|
|
798
|
+
}
|
|
799
|
+
|
|
800
|
+
getTokenEnd(): number {
|
|
801
|
+
return this.pos;
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
getTokenText(): string {
|
|
805
|
+
return this.text.substring(this.tokenStart, this.pos);
|
|
806
|
+
}
|
|
807
|
+
|
|
808
|
+
/** The cooked value: identifier text, string contents, normalized number, etc. */
|
|
809
|
+
getTokenValue(): string {
|
|
810
|
+
if (this.valueStart >= 0) {
|
|
811
|
+
this.tokenValue = this.text.substring(this.valueStart, this.valueEnd);
|
|
812
|
+
this.valueStart = -1;
|
|
813
|
+
}
|
|
814
|
+
return this.tokenValue;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Whether `text`, the identifier value just returned by `getIdentifierValue`, is the first of its
|
|
819
|
+
* file to be recorded; files record each identifier text once.
|
|
820
|
+
*/
|
|
821
|
+
recordIdentifierValue(text: string): boolean {
|
|
822
|
+
return this.identifiers.markRecorded(text);
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
/** @internal Like `getTokenValue`, but identifiers with the same text share one string. */
|
|
826
|
+
getIdentifierValue(): string {
|
|
827
|
+
const start = this.valueStart;
|
|
828
|
+
if (start >= 0) {
|
|
829
|
+
const end = this.valueEnd;
|
|
830
|
+
const hash =
|
|
831
|
+
start === this.hashStart && end === this.hashEnd ? this.valueHash : rangeHash(this.chars, start, end);
|
|
832
|
+
this.tokenValue = this.identifiers.intern(start, end, hash);
|
|
833
|
+
this.valueStart = -1;
|
|
834
|
+
}
|
|
835
|
+
return this.tokenValue;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
getCommentDirectives(): readonly CommentDirective[] {
|
|
839
|
+
return this.commentDirectives;
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
hasUnicodeEscape(): boolean {
|
|
843
|
+
return (this.tokenFlags & TokenFlags.UnicodeEscape) !== 0;
|
|
844
|
+
}
|
|
845
|
+
|
|
846
|
+
hasExtendedUnicodeEscape(): boolean {
|
|
847
|
+
return (this.tokenFlags & TokenFlags.ExtendedUnicodeEscape) !== 0;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
hasPrecedingLineBreak(): boolean {
|
|
851
|
+
return (this.tokenFlags & TokenFlags.PrecedingLineBreak) !== 0;
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
hasPrecedingJSDocComment(): boolean {
|
|
855
|
+
return (this.tokenFlags & TokenFlags.PrecedingJSDocComment) !== 0;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
hasPrecedingJSDocLeadingAsterisks(): boolean {
|
|
859
|
+
return (this.tokenFlags & TokenFlags.PrecedingJSDocLeadingAsterisks) !== 0;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
hasPrecedingJSDocWithDeprecatedTag(): boolean {
|
|
863
|
+
return (this.tokenFlags & TokenFlags.PrecedingJSDocWithDeprecated) !== 0;
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
hasPrecedingJSDocWithSeeOrLink(): boolean {
|
|
867
|
+
return (this.tokenFlags & TokenFlags.PrecedingJSDocWithSeeOrLink) !== 0;
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
isUnterminated(): boolean {
|
|
871
|
+
return (this.tokenFlags & TokenFlags.Unterminated) !== 0;
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
mark(): ScannerState {
|
|
875
|
+
return new ScannerState(
|
|
876
|
+
this.pos,
|
|
877
|
+
this.fullStartPos,
|
|
878
|
+
this.tokenStart,
|
|
879
|
+
this.token,
|
|
880
|
+
this.tokenFlags,
|
|
881
|
+
this.tokenValue,
|
|
882
|
+
this.valueStart,
|
|
883
|
+
this.valueEnd,
|
|
884
|
+
this.commentDirectives.length,
|
|
885
|
+
this.skipJSDocLeadingAsterisks,
|
|
886
|
+
);
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
rewind(state: ScannerState): void {
|
|
890
|
+
this.pos = state.pos;
|
|
891
|
+
this.fullStartPos = state.fullStartPos;
|
|
892
|
+
this.tokenStart = state.tokenStart;
|
|
893
|
+
this.token = state.token;
|
|
894
|
+
this.tokenFlags = state.tokenFlags;
|
|
895
|
+
this.tokenValue = state.tokenValue;
|
|
896
|
+
this.valueStart = state.valueStart;
|
|
897
|
+
this.valueEnd = state.valueEnd;
|
|
898
|
+
while (this.commentDirectives.length > state.commentDirectiveCount) this.commentDirectives.pop();
|
|
899
|
+
this.skipJSDocLeadingAsterisks = state.skipJSDocLeadingAsterisks;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
/** Runs `callback` and restores the scanner state afterwards. */
|
|
903
|
+
lookAhead<T>(callback: () => T): T {
|
|
904
|
+
const state = this.mark();
|
|
905
|
+
const result = callback();
|
|
906
|
+
this.rewind(state);
|
|
907
|
+
return result;
|
|
908
|
+
}
|
|
909
|
+
|
|
910
|
+
/** Runs `callback` and restores the scanner state if it returns `undefined`. */
|
|
911
|
+
tryScan<T>(callback: () => T | undefined): T | undefined {
|
|
912
|
+
const state = this.mark();
|
|
913
|
+
const result = callback();
|
|
914
|
+
if (result === undefined) this.rewind(state);
|
|
915
|
+
return result;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
/** Moves to `pos` without changing the current token. */
|
|
919
|
+
resetPos(pos: number): void {
|
|
920
|
+
if (pos < 0) throw new Error('Cannot reset token state to negative position');
|
|
921
|
+
this.pos = pos | 0;
|
|
922
|
+
this.fullStartPos = pos | 0;
|
|
923
|
+
this.tokenStart = pos | 0;
|
|
924
|
+
}
|
|
925
|
+
|
|
926
|
+
resetTokenState(pos: number): void {
|
|
927
|
+
this.resetPos(pos);
|
|
928
|
+
this.token = SyntaxKind.Unknown;
|
|
929
|
+
this.tokenValue = '';
|
|
930
|
+
this.valueStart = -1;
|
|
931
|
+
this.tokenFlags = TokenFlags.None;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
/** @internal */
|
|
935
|
+
languageVersion(): ScriptTarget {
|
|
936
|
+
return this.scriptTarget === ScriptTarget.None ? ScriptTarget.Latest : this.scriptTarget;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
private error(message: DiagnosticMessage): void {
|
|
940
|
+
this.errorAt(message, this.pos, 0, noArgs);
|
|
941
|
+
}
|
|
942
|
+
|
|
943
|
+
/** @internal */
|
|
944
|
+
errorAt(message: DiagnosticMessage, start: number, length: number, args: readonly string[]): void {
|
|
945
|
+
if (this.onError !== undefined) this.onError.onError(message, start, length, args);
|
|
946
|
+
}
|
|
947
|
+
|
|
948
|
+
/** @internal The code unit at `pos`, or -1 at the end. */
|
|
949
|
+
char(): number {
|
|
950
|
+
return this.pos < this.end ? this.chars[this.pos] | 0 : CharacterCodes.EOF;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
/** @internal The code unit at `pos + offset`, or -1 past the end. */
|
|
954
|
+
peek(offset: number): number {
|
|
955
|
+
const at = (this.pos + offset) | 0;
|
|
956
|
+
return at < this.end ? this.chars[at] | 0 : CharacterCodes.EOF;
|
|
957
|
+
}
|
|
958
|
+
|
|
959
|
+
/** @internal The code point at `pos`, or -1 at the end. */
|
|
960
|
+
codePoint(): number {
|
|
961
|
+
return this.codePointAt(this.pos, this.end);
|
|
962
|
+
}
|
|
963
|
+
|
|
964
|
+
/** @internal The code point at `pos`, combining a surrogate pair; -1 at or past `end`. */
|
|
965
|
+
codePointAt(pos: number, end: number): number {
|
|
966
|
+
if (pos >= end) return CharacterCodes.EOF;
|
|
967
|
+
const chars = this.chars;
|
|
968
|
+
const ch = chars[pos] | 0;
|
|
969
|
+
if (ch >= 0xd800 && ch <= 0xdbff && pos + 1 < end) {
|
|
970
|
+
const low = chars[pos + 1] | 0;
|
|
971
|
+
if (low >= 0xdc00 && low <= 0xdfff) return (ch - 0xd800) * 0x400 + (low - 0xdc00) + 0x10000;
|
|
972
|
+
}
|
|
973
|
+
return ch;
|
|
974
|
+
}
|
|
975
|
+
|
|
976
|
+
/** The code point ending just before `pos`; -1 at the start. */
|
|
977
|
+
private codePointBefore(pos: number): number {
|
|
978
|
+
if (pos <= 0) return CharacterCodes.EOF;
|
|
979
|
+
const ch = this.chars[pos - 1] | 0;
|
|
980
|
+
if (ch >= 0xdc00 && ch <= 0xdfff && pos >= 2) {
|
|
981
|
+
const high = this.chars[pos - 2] | 0;
|
|
982
|
+
if (high >= 0xd800 && high <= 0xdbff) return (high - 0xd800) * 0x400 + (ch - 0xdc00) + 0x10000;
|
|
983
|
+
}
|
|
984
|
+
return ch;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
private setValue(value: string): void {
|
|
988
|
+
this.tokenValue = value;
|
|
989
|
+
this.valueStart = -1;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
private setValueSlice(start: number, end: number): void {
|
|
993
|
+
this.valueStart = start | 0;
|
|
994
|
+
this.valueEnd = end | 0;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
scan(): SyntaxKind {
|
|
998
|
+
// `chars` is zero-padded, so peeking a few units past the end is safe.
|
|
999
|
+
const chars = this.chars;
|
|
1000
|
+
this.fullStartPos = this.pos | 0;
|
|
1001
|
+
this.tokenFlags = TokenFlags.None;
|
|
1002
|
+
for (;;) {
|
|
1003
|
+
const ch = this.pos < this.end ? chars[this.pos] | 0 : CharacterCodes.EOF;
|
|
1004
|
+
this.tokenStart = this.pos | 0;
|
|
1005
|
+
switch (ch) {
|
|
1006
|
+
case CharacterCodes.tab:
|
|
1007
|
+
case CharacterCodes.verticalTab:
|
|
1008
|
+
case CharacterCodes.formFeed:
|
|
1009
|
+
case CharacterCodes.space:
|
|
1010
|
+
if (this.skipTrivia) {
|
|
1011
|
+
let pos = (this.pos + 1) | 0;
|
|
1012
|
+
const end = this.end;
|
|
1013
|
+
while (pos < end) {
|
|
1014
|
+
const c = chars[pos] | 0;
|
|
1015
|
+
if (c !== CharacterCodes.space && c !== CharacterCodes.tab) break;
|
|
1016
|
+
pos = (pos + 1) | 0;
|
|
1017
|
+
}
|
|
1018
|
+
this.pos = pos;
|
|
1019
|
+
continue;
|
|
1020
|
+
}
|
|
1021
|
+
this.pos = (this.pos + 1) | 0;
|
|
1022
|
+
while (this.pos < this.end && isWhiteSpaceSingleLine(chars[this.pos] | 0)) this.pos = (this.pos + 1) | 0;
|
|
1023
|
+
return (this.token = SyntaxKind.WhitespaceTrivia);
|
|
1024
|
+
case CharacterCodes.lineFeed:
|
|
1025
|
+
case CharacterCodes.carriageReturn:
|
|
1026
|
+
this.tokenFlags |= TokenFlags.PrecedingLineBreak;
|
|
1027
|
+
if (this.skipTrivia) {
|
|
1028
|
+
let pos = (this.pos + 1) | 0;
|
|
1029
|
+
const end = this.end;
|
|
1030
|
+
while (pos < end) {
|
|
1031
|
+
const c = chars[pos] | 0;
|
|
1032
|
+
if (c !== CharacterCodes.space && (c < CharacterCodes.tab || c > CharacterCodes.carriageReturn)) break;
|
|
1033
|
+
pos = (pos + 1) | 0;
|
|
1034
|
+
}
|
|
1035
|
+
this.pos = pos;
|
|
1036
|
+
continue;
|
|
1037
|
+
}
|
|
1038
|
+
this.pos =
|
|
1039
|
+
(this.pos +
|
|
1040
|
+
(ch === CharacterCodes.carriageReturn && (chars[this.pos + 1] | 0) === CharacterCodes.lineFeed ? 2 : 1)) |
|
|
1041
|
+
0;
|
|
1042
|
+
return (this.token = SyntaxKind.NewLineTrivia);
|
|
1043
|
+
case CharacterCodes.exclamation:
|
|
1044
|
+
if ((chars[this.pos + 1] | 0) === CharacterCodes.equals) {
|
|
1045
|
+
if ((chars[this.pos + 2] | 0) === CharacterCodes.equals) {
|
|
1046
|
+
this.pos = (this.pos + 3) | 0;
|
|
1047
|
+
return (this.token = SyntaxKind.ExclamationEqualsEqualsToken);
|
|
1048
|
+
}
|
|
1049
|
+
this.pos = (this.pos + 2) | 0;
|
|
1050
|
+
return (this.token = SyntaxKind.ExclamationEqualsToken);
|
|
1051
|
+
}
|
|
1052
|
+
this.pos = (this.pos + 1) | 0;
|
|
1053
|
+
return (this.token = SyntaxKind.ExclamationToken);
|
|
1054
|
+
case CharacterCodes.doubleQuote:
|
|
1055
|
+
case CharacterCodes.singleQuote:
|
|
1056
|
+
this.scanString(false);
|
|
1057
|
+
return (this.token = SyntaxKind.StringLiteral);
|
|
1058
|
+
case CharacterCodes.backtick:
|
|
1059
|
+
return (this.token = this.scanTemplateAndSetTokenValue(false));
|
|
1060
|
+
case CharacterCodes.percent:
|
|
1061
|
+
if ((chars[this.pos + 1] | 0) === CharacterCodes.equals) {
|
|
1062
|
+
this.pos = (this.pos + 2) | 0;
|
|
1063
|
+
return (this.token = SyntaxKind.PercentEqualsToken);
|
|
1064
|
+
}
|
|
1065
|
+
this.pos = (this.pos + 1) | 0;
|
|
1066
|
+
return (this.token = SyntaxKind.PercentToken);
|
|
1067
|
+
case CharacterCodes.ampersand: {
|
|
1068
|
+
const next = chars[this.pos + 1] | 0;
|
|
1069
|
+
if (next === CharacterCodes.ampersand) {
|
|
1070
|
+
if ((chars[this.pos + 2] | 0) === CharacterCodes.equals) {
|
|
1071
|
+
this.pos = (this.pos + 3) | 0;
|
|
1072
|
+
return (this.token = SyntaxKind.AmpersandAmpersandEqualsToken);
|
|
1073
|
+
}
|
|
1074
|
+
this.pos = (this.pos + 2) | 0;
|
|
1075
|
+
return (this.token = SyntaxKind.AmpersandAmpersandToken);
|
|
1076
|
+
}
|
|
1077
|
+
if (next === CharacterCodes.equals) {
|
|
1078
|
+
this.pos = (this.pos + 2) | 0;
|
|
1079
|
+
return (this.token = SyntaxKind.AmpersandEqualsToken);
|
|
1080
|
+
}
|
|
1081
|
+
this.pos = (this.pos + 1) | 0;
|
|
1082
|
+
return (this.token = SyntaxKind.AmpersandToken);
|
|
1083
|
+
}
|
|
1084
|
+
case CharacterCodes.openParen:
|
|
1085
|
+
this.pos = (this.pos + 1) | 0;
|
|
1086
|
+
return (this.token = SyntaxKind.OpenParenToken);
|
|
1087
|
+
case CharacterCodes.closeParen:
|
|
1088
|
+
this.pos = (this.pos + 1) | 0;
|
|
1089
|
+
return (this.token = SyntaxKind.CloseParenToken);
|
|
1090
|
+
case CharacterCodes.asterisk: {
|
|
1091
|
+
const next = chars[this.pos + 1] | 0;
|
|
1092
|
+
if (next === CharacterCodes.equals) {
|
|
1093
|
+
this.pos = (this.pos + 2) | 0;
|
|
1094
|
+
return (this.token = SyntaxKind.AsteriskEqualsToken);
|
|
1095
|
+
}
|
|
1096
|
+
if (next === CharacterCodes.asterisk) {
|
|
1097
|
+
if ((chars[this.pos + 2] | 0) === CharacterCodes.equals) {
|
|
1098
|
+
this.pos = (this.pos + 3) | 0;
|
|
1099
|
+
return (this.token = SyntaxKind.AsteriskAsteriskEqualsToken);
|
|
1100
|
+
}
|
|
1101
|
+
this.pos = (this.pos + 2) | 0;
|
|
1102
|
+
return (this.token = SyntaxKind.AsteriskAsteriskToken);
|
|
1103
|
+
}
|
|
1104
|
+
this.pos = (this.pos + 1) | 0;
|
|
1105
|
+
if (
|
|
1106
|
+
this.skipJSDocLeadingAsterisks !== 0 &&
|
|
1107
|
+
(this.tokenFlags & TokenFlags.PrecedingJSDocLeadingAsterisks) === 0 &&
|
|
1108
|
+
(this.tokenFlags & TokenFlags.PrecedingLineBreak) !== 0
|
|
1109
|
+
) {
|
|
1110
|
+
this.tokenFlags |= TokenFlags.PrecedingJSDocLeadingAsterisks;
|
|
1111
|
+
continue;
|
|
1112
|
+
}
|
|
1113
|
+
return (this.token = SyntaxKind.AsteriskToken);
|
|
1114
|
+
}
|
|
1115
|
+
case CharacterCodes.plus: {
|
|
1116
|
+
const next = chars[this.pos + 1] | 0;
|
|
1117
|
+
if (next === CharacterCodes.equals) {
|
|
1118
|
+
this.pos = (this.pos + 2) | 0;
|
|
1119
|
+
return (this.token = SyntaxKind.PlusEqualsToken);
|
|
1120
|
+
}
|
|
1121
|
+
if (next === CharacterCodes.plus) {
|
|
1122
|
+
this.pos = (this.pos + 2) | 0;
|
|
1123
|
+
return (this.token = SyntaxKind.PlusPlusToken);
|
|
1124
|
+
}
|
|
1125
|
+
this.pos = (this.pos + 1) | 0;
|
|
1126
|
+
return (this.token = SyntaxKind.PlusToken);
|
|
1127
|
+
}
|
|
1128
|
+
case CharacterCodes.comma:
|
|
1129
|
+
this.pos = (this.pos + 1) | 0;
|
|
1130
|
+
return (this.token = SyntaxKind.CommaToken);
|
|
1131
|
+
case CharacterCodes.minus: {
|
|
1132
|
+
const next = chars[this.pos + 1] | 0;
|
|
1133
|
+
if (next === CharacterCodes.equals) {
|
|
1134
|
+
this.pos = (this.pos + 2) | 0;
|
|
1135
|
+
return (this.token = SyntaxKind.MinusEqualsToken);
|
|
1136
|
+
}
|
|
1137
|
+
if (next === CharacterCodes.minus) {
|
|
1138
|
+
this.pos = (this.pos + 2) | 0;
|
|
1139
|
+
return (this.token = SyntaxKind.MinusMinusToken);
|
|
1140
|
+
}
|
|
1141
|
+
this.pos = (this.pos + 1) | 0;
|
|
1142
|
+
return (this.token = SyntaxKind.MinusToken);
|
|
1143
|
+
}
|
|
1144
|
+
case CharacterCodes.dot: {
|
|
1145
|
+
const next = chars[this.pos + 1] | 0;
|
|
1146
|
+
if (isDigit(next)) return (this.token = this.scanNumber());
|
|
1147
|
+
if (next === CharacterCodes.dot && (chars[this.pos + 2] | 0) === CharacterCodes.dot) {
|
|
1148
|
+
this.pos = (this.pos + 3) | 0;
|
|
1149
|
+
return (this.token = SyntaxKind.DotDotDotToken);
|
|
1150
|
+
}
|
|
1151
|
+
this.pos = (this.pos + 1) | 0;
|
|
1152
|
+
return (this.token = SyntaxKind.DotToken);
|
|
1153
|
+
}
|
|
1154
|
+
case CharacterCodes.slash: {
|
|
1155
|
+
const next = chars[this.pos + 1] | 0;
|
|
1156
|
+
if (next === CharacterCodes.slash) {
|
|
1157
|
+
const pos = this.lineCommentEnd((this.pos + 2) | 0);
|
|
1158
|
+
this.pos = pos;
|
|
1159
|
+
this.processCommentDirective(this.tokenStart, pos, false);
|
|
1160
|
+
if (this.skipTrivia) continue;
|
|
1161
|
+
return (this.token = SyntaxKind.SingleLineCommentTrivia);
|
|
1162
|
+
}
|
|
1163
|
+
if (next === CharacterCodes.asterisk) {
|
|
1164
|
+
if (this.scanMultiLineComment()) continue;
|
|
1165
|
+
return (this.token = SyntaxKind.MultiLineCommentTrivia);
|
|
1166
|
+
}
|
|
1167
|
+
if (next === CharacterCodes.equals) {
|
|
1168
|
+
this.pos = (this.pos + 2) | 0;
|
|
1169
|
+
return (this.token = SyntaxKind.SlashEqualsToken);
|
|
1170
|
+
}
|
|
1171
|
+
this.pos = (this.pos + 1) | 0;
|
|
1172
|
+
return (this.token = SyntaxKind.SlashToken);
|
|
1173
|
+
}
|
|
1174
|
+
case CharacterCodes._0: {
|
|
1175
|
+
const next = chars[this.pos + 1] | 0;
|
|
1176
|
+
if (next === CharacterCodes.X || next === CharacterCodes.x) return (this.token = this.scanHexNumber());
|
|
1177
|
+
if (next === CharacterCodes.B || next === CharacterCodes.b)
|
|
1178
|
+
return (this.token = this.scanBinaryOrOctalNumber(2));
|
|
1179
|
+
if (next === CharacterCodes.O || next === CharacterCodes.o)
|
|
1180
|
+
return (this.token = this.scanBinaryOrOctalNumber(8));
|
|
1181
|
+
return (this.token = this.scanNumber());
|
|
1182
|
+
}
|
|
1183
|
+
case CharacterCodes._1:
|
|
1184
|
+
case CharacterCodes._2:
|
|
1185
|
+
case CharacterCodes._3:
|
|
1186
|
+
case CharacterCodes._4:
|
|
1187
|
+
case CharacterCodes._5:
|
|
1188
|
+
case CharacterCodes._6:
|
|
1189
|
+
case CharacterCodes._7:
|
|
1190
|
+
case CharacterCodes._8:
|
|
1191
|
+
case CharacterCodes._9:
|
|
1192
|
+
return (this.token = this.scanNumber());
|
|
1193
|
+
case CharacterCodes.colon:
|
|
1194
|
+
this.pos = (this.pos + 1) | 0;
|
|
1195
|
+
return (this.token = SyntaxKind.ColonToken);
|
|
1196
|
+
case CharacterCodes.semicolon:
|
|
1197
|
+
this.pos = (this.pos + 1) | 0;
|
|
1198
|
+
return (this.token = SyntaxKind.SemicolonToken);
|
|
1199
|
+
case CharacterCodes.lessThan: {
|
|
1200
|
+
const next = chars[this.pos + 1] | 0;
|
|
1201
|
+
if (next === CharacterCodes.lessThan && isConflictMarkerTrivia(this.text, this.pos)) {
|
|
1202
|
+
if (this.scanConflictMarker()) continue;
|
|
1203
|
+
return (this.token = SyntaxKind.ConflictMarkerTrivia);
|
|
1204
|
+
}
|
|
1205
|
+
if (next === CharacterCodes.lessThan) {
|
|
1206
|
+
if ((chars[this.pos + 2] | 0) === CharacterCodes.equals) {
|
|
1207
|
+
this.pos = (this.pos + 3) | 0;
|
|
1208
|
+
return (this.token = SyntaxKind.LessThanLessThanEqualsToken);
|
|
1209
|
+
}
|
|
1210
|
+
this.pos = (this.pos + 2) | 0;
|
|
1211
|
+
return (this.token = SyntaxKind.LessThanLessThanToken);
|
|
1212
|
+
}
|
|
1213
|
+
if (next === CharacterCodes.equals) {
|
|
1214
|
+
this.pos = (this.pos + 2) | 0;
|
|
1215
|
+
return (this.token = SyntaxKind.LessThanEqualsToken);
|
|
1216
|
+
}
|
|
1217
|
+
if (
|
|
1218
|
+
this.languageVariant === LanguageVariant.JSX &&
|
|
1219
|
+
next === CharacterCodes.slash &&
|
|
1220
|
+
(chars[this.pos + 2] | 0) !== CharacterCodes.asterisk
|
|
1221
|
+
) {
|
|
1222
|
+
this.pos = (this.pos + 2) | 0;
|
|
1223
|
+
return (this.token = SyntaxKind.LessThanSlashToken);
|
|
1224
|
+
}
|
|
1225
|
+
this.pos = (this.pos + 1) | 0;
|
|
1226
|
+
return (this.token = SyntaxKind.LessThanToken);
|
|
1227
|
+
}
|
|
1228
|
+
case CharacterCodes.equals: {
|
|
1229
|
+
const next = chars[this.pos + 1] | 0;
|
|
1230
|
+
if (next === CharacterCodes.equals && isConflictMarkerTrivia(this.text, this.pos)) {
|
|
1231
|
+
if (this.scanConflictMarker()) continue;
|
|
1232
|
+
return (this.token = SyntaxKind.ConflictMarkerTrivia);
|
|
1233
|
+
}
|
|
1234
|
+
if (next === CharacterCodes.equals) {
|
|
1235
|
+
if ((chars[this.pos + 2] | 0) === CharacterCodes.equals) {
|
|
1236
|
+
this.pos = (this.pos + 3) | 0;
|
|
1237
|
+
return (this.token = SyntaxKind.EqualsEqualsEqualsToken);
|
|
1238
|
+
}
|
|
1239
|
+
this.pos = (this.pos + 2) | 0;
|
|
1240
|
+
return (this.token = SyntaxKind.EqualsEqualsToken);
|
|
1241
|
+
}
|
|
1242
|
+
if (next === CharacterCodes.greaterThan) {
|
|
1243
|
+
this.pos = (this.pos + 2) | 0;
|
|
1244
|
+
return (this.token = SyntaxKind.EqualsGreaterThanToken);
|
|
1245
|
+
}
|
|
1246
|
+
this.pos = (this.pos + 1) | 0;
|
|
1247
|
+
return (this.token = SyntaxKind.EqualsToken);
|
|
1248
|
+
}
|
|
1249
|
+
case CharacterCodes.greaterThan:
|
|
1250
|
+
if ((chars[this.pos + 1] | 0) === CharacterCodes.greaterThan && isConflictMarkerTrivia(this.text, this.pos)) {
|
|
1251
|
+
if (this.scanConflictMarker()) continue;
|
|
1252
|
+
return (this.token = SyntaxKind.ConflictMarkerTrivia);
|
|
1253
|
+
}
|
|
1254
|
+
this.pos = (this.pos + 1) | 0;
|
|
1255
|
+
return (this.token = SyntaxKind.GreaterThanToken);
|
|
1256
|
+
case CharacterCodes.question: {
|
|
1257
|
+
const next = chars[this.pos + 1] | 0;
|
|
1258
|
+
if (next === CharacterCodes.dot && !isDigit(chars[this.pos + 2] | 0)) {
|
|
1259
|
+
this.pos = (this.pos + 2) | 0;
|
|
1260
|
+
return (this.token = SyntaxKind.QuestionDotToken);
|
|
1261
|
+
}
|
|
1262
|
+
if (next === CharacterCodes.question) {
|
|
1263
|
+
if ((chars[this.pos + 2] | 0) === CharacterCodes.equals) {
|
|
1264
|
+
this.pos = (this.pos + 3) | 0;
|
|
1265
|
+
return (this.token = SyntaxKind.QuestionQuestionEqualsToken);
|
|
1266
|
+
}
|
|
1267
|
+
this.pos = (this.pos + 2) | 0;
|
|
1268
|
+
return (this.token = SyntaxKind.QuestionQuestionToken);
|
|
1269
|
+
}
|
|
1270
|
+
this.pos = (this.pos + 1) | 0;
|
|
1271
|
+
return (this.token = SyntaxKind.QuestionToken);
|
|
1272
|
+
}
|
|
1273
|
+
case CharacterCodes.openBracket:
|
|
1274
|
+
this.pos = (this.pos + 1) | 0;
|
|
1275
|
+
return (this.token = SyntaxKind.OpenBracketToken);
|
|
1276
|
+
case CharacterCodes.closeBracket:
|
|
1277
|
+
this.pos = (this.pos + 1) | 0;
|
|
1278
|
+
return (this.token = SyntaxKind.CloseBracketToken);
|
|
1279
|
+
case CharacterCodes.caret:
|
|
1280
|
+
if ((chars[this.pos + 1] | 0) === CharacterCodes.equals) {
|
|
1281
|
+
this.pos = (this.pos + 2) | 0;
|
|
1282
|
+
return (this.token = SyntaxKind.CaretEqualsToken);
|
|
1283
|
+
}
|
|
1284
|
+
this.pos = (this.pos + 1) | 0;
|
|
1285
|
+
return (this.token = SyntaxKind.CaretToken);
|
|
1286
|
+
case CharacterCodes.openBrace:
|
|
1287
|
+
this.pos = (this.pos + 1) | 0;
|
|
1288
|
+
return (this.token = SyntaxKind.OpenBraceToken);
|
|
1289
|
+
case CharacterCodes.bar: {
|
|
1290
|
+
const next = chars[this.pos + 1] | 0;
|
|
1291
|
+
if (next === CharacterCodes.bar && isConflictMarkerTrivia(this.text, this.pos)) {
|
|
1292
|
+
if (this.scanConflictMarker()) continue;
|
|
1293
|
+
return (this.token = SyntaxKind.ConflictMarkerTrivia);
|
|
1294
|
+
}
|
|
1295
|
+
if (next === CharacterCodes.bar) {
|
|
1296
|
+
if ((chars[this.pos + 2] | 0) === CharacterCodes.equals) {
|
|
1297
|
+
this.pos = (this.pos + 3) | 0;
|
|
1298
|
+
return (this.token = SyntaxKind.BarBarEqualsToken);
|
|
1299
|
+
}
|
|
1300
|
+
this.pos = (this.pos + 2) | 0;
|
|
1301
|
+
return (this.token = SyntaxKind.BarBarToken);
|
|
1302
|
+
}
|
|
1303
|
+
if (next === CharacterCodes.equals) {
|
|
1304
|
+
this.pos = (this.pos + 2) | 0;
|
|
1305
|
+
return (this.token = SyntaxKind.BarEqualsToken);
|
|
1306
|
+
}
|
|
1307
|
+
this.pos = (this.pos + 1) | 0;
|
|
1308
|
+
return (this.token = SyntaxKind.BarToken);
|
|
1309
|
+
}
|
|
1310
|
+
case CharacterCodes.closeBrace:
|
|
1311
|
+
this.pos = (this.pos + 1) | 0;
|
|
1312
|
+
return (this.token = SyntaxKind.CloseBraceToken);
|
|
1313
|
+
case CharacterCodes.tilde:
|
|
1314
|
+
this.pos = (this.pos + 1) | 0;
|
|
1315
|
+
return (this.token = SyntaxKind.TildeToken);
|
|
1316
|
+
case CharacterCodes.at:
|
|
1317
|
+
this.pos = (this.pos + 1) | 0;
|
|
1318
|
+
return (this.token = SyntaxKind.AtToken);
|
|
1319
|
+
case CharacterCodes.backslash: {
|
|
1320
|
+
const codePoint = this.peekUnicodeEscape();
|
|
1321
|
+
if (codePoint >= 0 && isIdentifierStart(codePoint)) {
|
|
1322
|
+
const head = String.fromCodePoint(this.scanUnicodeEscape(true));
|
|
1323
|
+
this.setValue(head + this.scanIdentifierParts());
|
|
1324
|
+
return (this.token = getIdentifierToken(this.tokenValue));
|
|
1325
|
+
}
|
|
1326
|
+
return this.scanInvalidCharacter();
|
|
1327
|
+
}
|
|
1328
|
+
case CharacterCodes.hash:
|
|
1329
|
+
if ((chars[this.pos + 1] | 0) === CharacterCodes.exclamation) {
|
|
1330
|
+
if (this.pos === 0) {
|
|
1331
|
+
this.pos = scanShebangTrivia(this.text, 0) | 0;
|
|
1332
|
+
continue;
|
|
1333
|
+
}
|
|
1334
|
+
this.errorAt(Diagnostics.X_can_only_be_used_at_the_start_of_a_file, this.pos, 2, noArgs);
|
|
1335
|
+
this.pos = (this.pos + 1) | 0;
|
|
1336
|
+
return (this.token = SyntaxKind.Unknown);
|
|
1337
|
+
}
|
|
1338
|
+
if ((chars[this.pos + 1] | 0) === CharacterCodes.backslash) {
|
|
1339
|
+
this.pos = (this.pos + 1) | 0;
|
|
1340
|
+
const codePoint = this.peekUnicodeEscape();
|
|
1341
|
+
if (codePoint >= 0 && isIdentifierStart(codePoint)) {
|
|
1342
|
+
const head = '#' + String.fromCodePoint(this.scanUnicodeEscape(true));
|
|
1343
|
+
this.setValue(head + this.scanIdentifierParts());
|
|
1344
|
+
return (this.token = SyntaxKind.PrivateIdentifier);
|
|
1345
|
+
}
|
|
1346
|
+
this.pos = (this.pos - 1) | 0;
|
|
1347
|
+
}
|
|
1348
|
+
if (!this.scanIdentifier(1)) {
|
|
1349
|
+
this.errorAt(Diagnostics.Invalid_character, this.pos - 1, 1, noArgs);
|
|
1350
|
+
this.setValue('#');
|
|
1351
|
+
}
|
|
1352
|
+
return (this.token = SyntaxKind.PrivateIdentifier);
|
|
1353
|
+
default: {
|
|
1354
|
+
if (ch < 0) return (this.token = SyntaxKind.EndOfFile);
|
|
1355
|
+
if (this.scanIdentifier(0)) return (this.token = this.identifierKind());
|
|
1356
|
+
const codePoint = this.codePoint();
|
|
1357
|
+
if (codePoint === CharacterCodes.replacementCharacter) {
|
|
1358
|
+
this.errorAt(Diagnostics.File_appears_to_be_binary, 0, 0, noArgs);
|
|
1359
|
+
this.pos = this.end;
|
|
1360
|
+
return (this.token = SyntaxKind.NonTextFileMarkerTrivia);
|
|
1361
|
+
}
|
|
1362
|
+
if (isWhiteSpaceSingleLine(codePoint)) {
|
|
1363
|
+
this.pos = (this.pos + 1) | 0;
|
|
1364
|
+
if (codePoint === CharacterCodes.nextLine || this.skipTrivia) continue;
|
|
1365
|
+
while (this.pos < this.end && isWhiteSpaceSingleLine(chars[this.pos] | 0)) this.pos = (this.pos + 1) | 0;
|
|
1366
|
+
return (this.token = SyntaxKind.WhitespaceTrivia);
|
|
1367
|
+
}
|
|
1368
|
+
if (isLineBreak(codePoint)) {
|
|
1369
|
+
this.tokenFlags |= TokenFlags.PrecedingLineBreak;
|
|
1370
|
+
this.pos = (this.pos + 1) | 0;
|
|
1371
|
+
continue;
|
|
1372
|
+
}
|
|
1373
|
+
return this.scanInvalidCharacter();
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
}
|
|
1377
|
+
}
|
|
1378
|
+
|
|
1379
|
+
/** The kind of the identifier just scanned by `scanIdentifier`. */
|
|
1380
|
+
private identifierKind(): SyntaxKind {
|
|
1381
|
+
return this.valueStart >= 0
|
|
1382
|
+
? keywordKindAt(this.chars, this.valueStart, this.valueEnd)
|
|
1383
|
+
: getIdentifierToken(this.tokenValue);
|
|
1384
|
+
}
|
|
1385
|
+
|
|
1386
|
+
/** The line breaks the text holds, found once per text. */
|
|
1387
|
+
private getTextKind(): TextKind {
|
|
1388
|
+
let kind = this.textKind;
|
|
1389
|
+
if (kind === TextKind.Unknown) {
|
|
1390
|
+
const text = this.text;
|
|
1391
|
+
// Natively, the UTF-8 length is known without a search, and ASCII texts hold no separators.
|
|
1392
|
+
if (
|
|
1393
|
+
Buffer.byteLength(text, 'utf8') !== text.length &&
|
|
1394
|
+
(text.indexOf('\u2028') >= 0 || text.indexOf('\u2029') >= 0)
|
|
1395
|
+
)
|
|
1396
|
+
kind = TextKind.Separators;
|
|
1397
|
+
else kind = text.indexOf('\r') >= 0 ? TextKind.LFAndCR : TextKind.LF;
|
|
1398
|
+
this.textKind = kind;
|
|
1399
|
+
}
|
|
1400
|
+
return kind;
|
|
1401
|
+
}
|
|
1402
|
+
|
|
1403
|
+
/**
|
|
1404
|
+
* The end of the line comment whose text starts at `pos`: the next line break, or `end`. Found with
|
|
1405
|
+
* string searches (natively, byte searches) instead of a loop over code units, except in texts with
|
|
1406
|
+
* line or paragraph separators.
|
|
1407
|
+
*/
|
|
1408
|
+
private lineCommentEnd(pos: number): number {
|
|
1409
|
+
const end = this.end;
|
|
1410
|
+
const kind = this.getTextKind();
|
|
1411
|
+
if (kind !== TextKind.Separators) {
|
|
1412
|
+
let at = this.nextLineFeed(pos);
|
|
1413
|
+
if (kind === TextKind.LFAndCR) at = Math.min(at, this.nextCarriageReturn(pos));
|
|
1414
|
+
return at > end ? end : at | 0;
|
|
1415
|
+
}
|
|
1416
|
+
const chars = this.chars;
|
|
1417
|
+
while (pos < end && !isLineBreak(chars[pos] | 0)) pos = (pos + 1) | 0;
|
|
1418
|
+
return pos;
|
|
1419
|
+
}
|
|
1420
|
+
|
|
1421
|
+
/**
|
|
1422
|
+
* The position of the first LF at or after `pos`, or the text length. The last result is kept: as
|
|
1423
|
+
* the scanner moves forward each search starts where the previous one ended, so a text with few
|
|
1424
|
+
* LFs (CR line breaks) is not searched to its end once per line comment.
|
|
1425
|
+
*/
|
|
1426
|
+
private nextLineFeed(pos: number): number {
|
|
1427
|
+
if (pos >= this.lineFeedFrom && pos <= this.lineFeedAt) return this.lineFeedAt;
|
|
1428
|
+
const text = this.text;
|
|
1429
|
+
const at = text.indexOf('\n', pos);
|
|
1430
|
+
this.lineFeedFrom = pos;
|
|
1431
|
+
this.lineFeedAt = at < 0 ? text.length : at;
|
|
1432
|
+
return this.lineFeedAt;
|
|
1433
|
+
}
|
|
1434
|
+
|
|
1435
|
+
/** Like `nextLineFeed`, for CR: a text with LF line breaks and few CRs is searched once. */
|
|
1436
|
+
private nextCarriageReturn(pos: number): number {
|
|
1437
|
+
if (pos >= this.carriageReturnFrom && pos <= this.carriageReturnAt) return this.carriageReturnAt;
|
|
1438
|
+
const text = this.text;
|
|
1439
|
+
const at = text.indexOf('\r', pos);
|
|
1440
|
+
this.carriageReturnFrom = pos;
|
|
1441
|
+
this.carriageReturnAt = at < 0 ? text.length : at;
|
|
1442
|
+
return this.carriageReturnAt;
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
/** Scans `/* … *\/`; returns true if the comment is skipped as trivia. */
|
|
1446
|
+
private scanMultiLineComment(): boolean {
|
|
1447
|
+
const chars = this.chars;
|
|
1448
|
+
const end = this.end;
|
|
1449
|
+
let pos = (this.pos + 2) | 0;
|
|
1450
|
+
const isJSDoc =
|
|
1451
|
+
pos < end && (chars[pos] | 0) === CharacterCodes.asterisk && (chars[pos + 1] | 0) !== CharacterCodes.slash;
|
|
1452
|
+
let closed = false;
|
|
1453
|
+
let lastLineStart = this.tokenStart;
|
|
1454
|
+
let flags = this.tokenFlags;
|
|
1455
|
+
if (isJSDoc) flags |= TokenFlags.PrecedingJSDocComment;
|
|
1456
|
+
const kind = this.getTextKind();
|
|
1457
|
+
if (kind !== TextKind.Separators) {
|
|
1458
|
+
// String searches for the closing `*/`, then for the line breaks and JSDoc tags in the comment,
|
|
1459
|
+
// instead of a loop over code units; not in texts with line or paragraph separators.
|
|
1460
|
+
const text = this.text;
|
|
1461
|
+
const close = text.indexOf('*/', pos);
|
|
1462
|
+
closed = close >= 0 && close + 2 <= end;
|
|
1463
|
+
const bodyEnd = closed ? close : end;
|
|
1464
|
+
if (pos < bodyEnd) {
|
|
1465
|
+
const body = text.substring(pos, bodyEnd);
|
|
1466
|
+
// A forward search first: most comments have no line break, and searching back is slower.
|
|
1467
|
+
let lastBreak = body.indexOf('\n') >= 0 ? body.lastIndexOf('\n') : -1;
|
|
1468
|
+
if (kind === TextKind.LFAndCR && body.indexOf('\r') >= 0)
|
|
1469
|
+
lastBreak = Math.max(lastBreak, body.lastIndexOf('\r'));
|
|
1470
|
+
if (lastBreak >= 0) {
|
|
1471
|
+
lastLineStart = (pos + lastBreak + 1) | 0;
|
|
1472
|
+
flags |= TokenFlags.PrecedingLineBreak;
|
|
1473
|
+
}
|
|
1474
|
+
if (isJSDoc)
|
|
1475
|
+
for (let at = body.indexOf('@'); at >= 0; at = body.indexOf('@', at + 1))
|
|
1476
|
+
flags = jsDocTagFlags(chars, pos + at + 1, end, flags);
|
|
1477
|
+
}
|
|
1478
|
+
pos = closed ? (close + 2) | 0 : end;
|
|
1479
|
+
} else {
|
|
1480
|
+
while (pos < end) {
|
|
1481
|
+
pos = skipCommentText(chars, pos, end) | 0;
|
|
1482
|
+
if (pos >= end) break;
|
|
1483
|
+
const c = chars[pos] | 0;
|
|
1484
|
+
pos = (pos + 1) | 0;
|
|
1485
|
+
if (c === CharacterCodes.asterisk) {
|
|
1486
|
+
if ((chars[pos] | 0) === CharacterCodes.slash) {
|
|
1487
|
+
pos = (pos + 1) | 0;
|
|
1488
|
+
closed = true;
|
|
1489
|
+
break;
|
|
1490
|
+
}
|
|
1491
|
+
} else if (c === CharacterCodes.lineFeed || c === CharacterCodes.carriageReturn || c >= 0x2028) {
|
|
1492
|
+
if (isLineBreak(c)) {
|
|
1493
|
+
lastLineStart = pos;
|
|
1494
|
+
flags |= TokenFlags.PrecedingLineBreak;
|
|
1495
|
+
}
|
|
1496
|
+
} else if (c === CharacterCodes.at && isJSDoc) {
|
|
1497
|
+
flags = jsDocTagFlags(chars, pos, end, flags);
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
this.pos = pos;
|
|
1502
|
+
this.tokenFlags = flags;
|
|
1503
|
+
this.processCommentDirective(lastLineStart, pos, true);
|
|
1504
|
+
if (!closed) this.error(Diagnostics.Asterisk_Slash_expected);
|
|
1505
|
+
if (this.skipTrivia) return true;
|
|
1506
|
+
if (!closed) this.tokenFlags |= TokenFlags.Unterminated;
|
|
1507
|
+
return false;
|
|
1508
|
+
}
|
|
1509
|
+
|
|
1510
|
+
/** Scans a merge conflict marker; returns true if it is skipped as trivia. */
|
|
1511
|
+
private scanConflictMarker(): boolean {
|
|
1512
|
+
this.pos = scanConflictMarkerTrivia(this.text, this.pos, this) | 0;
|
|
1513
|
+
return this.skipTrivia;
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
private processCommentDirective(start: number, end: number, multiline: boolean): void {
|
|
1517
|
+
const text = this.text;
|
|
1518
|
+
const chars = this.chars;
|
|
1519
|
+
let pos = start;
|
|
1520
|
+
if (multiline) {
|
|
1521
|
+
while (pos < end && (chars[pos] === CharacterCodes.space || chars[pos] === CharacterCodes.tab)) pos++;
|
|
1522
|
+
while (pos < end && (chars[pos] === CharacterCodes.slash || chars[pos] === CharacterCodes.asterisk)) pos++;
|
|
1523
|
+
} else {
|
|
1524
|
+
pos += 2;
|
|
1525
|
+
while (pos < end && chars[pos] === CharacterCodes.slash) pos++;
|
|
1526
|
+
}
|
|
1527
|
+
while (pos < end && (chars[pos] === CharacterCodes.space || chars[pos] === CharacterCodes.tab)) pos++;
|
|
1528
|
+
if (!(pos < end && chars[pos] === CharacterCodes.at)) return;
|
|
1529
|
+
pos++;
|
|
1530
|
+
let kind: CommentDirectiveKind;
|
|
1531
|
+
if (hasPrefixAt(text, pos, 'ts-expect-error')) kind = CommentDirectiveKind.ExpectError;
|
|
1532
|
+
else if (hasPrefixAt(text, pos, 'ts-ignore')) kind = CommentDirectiveKind.Ignore;
|
|
1533
|
+
else return;
|
|
1534
|
+
this.commentDirectives.push(new CommentDirective(start, end, kind));
|
|
1535
|
+
}
|
|
1536
|
+
|
|
1537
|
+
/** @internal Scans an identifier after `prefixLength` units; sets the token value. */
|
|
1538
|
+
scanIdentifier(prefixLength: number): boolean {
|
|
1539
|
+
const text = this.text;
|
|
1540
|
+
const chars = this.chars;
|
|
1541
|
+
const start = this.pos;
|
|
1542
|
+
this.pos = (this.pos + prefixLength) | 0;
|
|
1543
|
+
let ch = this.char();
|
|
1544
|
+
if (isASCIILetter(ch) || ch === CharacterCodes._ || ch === CharacterCodes.$) {
|
|
1545
|
+
// Fast path for ASCII identifiers, which also hashes the units for interning.
|
|
1546
|
+
let pos = (this.pos + 1) | 0;
|
|
1547
|
+
const end = this.end;
|
|
1548
|
+
// The FNV-1a offset basis, as in `rangeHash` (a literal: native builds load module constants).
|
|
1549
|
+
let hash = 0x811c9dc5 | 0;
|
|
1550
|
+
for (let i = start; i < pos; i = (i + 1) | 0) hash = Math.imul(hash ^ (chars[i] | 0), 0x01000193);
|
|
1551
|
+
while (pos < end) {
|
|
1552
|
+
const c = chars[pos] | 0;
|
|
1553
|
+
if (!isASCIIIdentifierPart(c)) break;
|
|
1554
|
+
hash = Math.imul(hash ^ c, 0x01000193);
|
|
1555
|
+
pos = (pos + 1) | 0;
|
|
1556
|
+
}
|
|
1557
|
+
this.pos = pos;
|
|
1558
|
+
ch = pos < end ? chars[pos] | 0 : CharacterCodes.EOF;
|
|
1559
|
+
if (ch <= CharacterCodes.maxAsciiCharacter && ch !== CharacterCodes.backslash) {
|
|
1560
|
+
this.setValueSlice(start, pos);
|
|
1561
|
+
this.valueHash = finishHash(hash);
|
|
1562
|
+
this.hashStart = start;
|
|
1563
|
+
this.hashEnd = pos;
|
|
1564
|
+
return true;
|
|
1565
|
+
}
|
|
1566
|
+
this.pos = (start + prefixLength) | 0;
|
|
1567
|
+
}
|
|
1568
|
+
ch = this.codePoint();
|
|
1569
|
+
if (!isIdentifierStart(ch)) return false;
|
|
1570
|
+
do {
|
|
1571
|
+
this.pos = (this.pos + charSize(ch)) | 0;
|
|
1572
|
+
ch = this.codePoint();
|
|
1573
|
+
} while (isIdentifierPart(ch));
|
|
1574
|
+
if (ch === CharacterCodes.backslash) this.setValue(text.substring(start, this.pos) + this.scanIdentifierParts());
|
|
1575
|
+
else this.setValueSlice(start, this.pos);
|
|
1576
|
+
return true;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
/** Scans identifier parts including `\u` escapes and returns their cooked text. */
|
|
1580
|
+
private scanIdentifierParts(): string {
|
|
1581
|
+
let result = '';
|
|
1582
|
+
let start = this.pos;
|
|
1583
|
+
for (;;) {
|
|
1584
|
+
const ch = this.codePoint();
|
|
1585
|
+
if (isIdentifierPart(ch)) {
|
|
1586
|
+
this.pos = (this.pos + charSize(ch)) | 0;
|
|
1587
|
+
continue;
|
|
1588
|
+
}
|
|
1589
|
+
if (ch === CharacterCodes.backslash) {
|
|
1590
|
+
const escaped = this.peekUnicodeEscape();
|
|
1591
|
+
if (escaped >= 0 && isIdentifierPart(escaped)) {
|
|
1592
|
+
result += this.text.substring(start, this.pos) + String.fromCodePoint(this.scanUnicodeEscape(true));
|
|
1593
|
+
start = this.pos;
|
|
1594
|
+
continue;
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
break;
|
|
1598
|
+
}
|
|
1599
|
+
return start === this.pos ? result : result + this.text.substring(start, this.pos);
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1602
|
+
private scanInvalidCharacter(): SyntaxKind {
|
|
1603
|
+
const size = charSize(this.codePoint());
|
|
1604
|
+
this.errorAt(Diagnostics.Invalid_character, this.pos, size, noArgs);
|
|
1605
|
+
this.pos = (this.pos + size) | 0;
|
|
1606
|
+
return (this.token = SyntaxKind.Unknown);
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
/** Scans a quoted string and sets its cooked value. */
|
|
1610
|
+
private scanString(jsxAttributeString: boolean): void {
|
|
1611
|
+
const text = this.text;
|
|
1612
|
+
const chars = this.chars;
|
|
1613
|
+
const quote = this.char();
|
|
1614
|
+
if (quote === CharacterCodes.singleQuote) this.tokenFlags |= TokenFlags.SingleQuote;
|
|
1615
|
+
let start = (this.pos + 1) | 0;
|
|
1616
|
+
// Fast path: no escapes or line breaks before the closing quote.
|
|
1617
|
+
let pos = start;
|
|
1618
|
+
const end = this.end;
|
|
1619
|
+
while (pos < end) {
|
|
1620
|
+
const ch = chars[pos] | 0;
|
|
1621
|
+
if (ch === quote) {
|
|
1622
|
+
this.setValueSlice(start, pos);
|
|
1623
|
+
this.pos = (pos + 1) | 0;
|
|
1624
|
+
return;
|
|
1625
|
+
}
|
|
1626
|
+
if (
|
|
1627
|
+
!jsxAttributeString &&
|
|
1628
|
+
(ch === CharacterCodes.backslash || ch === CharacterCodes.lineFeed || ch === CharacterCodes.carriageReturn)
|
|
1629
|
+
)
|
|
1630
|
+
break;
|
|
1631
|
+
pos = (pos + 1) | 0;
|
|
1632
|
+
}
|
|
1633
|
+
this.pos = pos;
|
|
1634
|
+
let result = '';
|
|
1635
|
+
for (;;) {
|
|
1636
|
+
const ch = this.char();
|
|
1637
|
+
if (ch < 0) {
|
|
1638
|
+
result += text.substring(start, this.pos);
|
|
1639
|
+
this.tokenFlags |= TokenFlags.Unterminated;
|
|
1640
|
+
this.error(Diagnostics.Unterminated_string_literal);
|
|
1641
|
+
break;
|
|
1642
|
+
}
|
|
1643
|
+
if (ch === quote) {
|
|
1644
|
+
result += text.substring(start, this.pos);
|
|
1645
|
+
this.pos = (this.pos + 1) | 0;
|
|
1646
|
+
break;
|
|
1647
|
+
}
|
|
1648
|
+
if (ch === CharacterCodes.backslash && !jsxAttributeString) {
|
|
1649
|
+
result += text.substring(start, this.pos);
|
|
1650
|
+
result += this.scanEscapeSequence(
|
|
1651
|
+
EscapeSequenceScanningFlags.String | EscapeSequenceScanningFlags.ReportErrors,
|
|
1652
|
+
);
|
|
1653
|
+
start = this.pos;
|
|
1654
|
+
continue;
|
|
1655
|
+
}
|
|
1656
|
+
if ((ch === CharacterCodes.lineFeed || ch === CharacterCodes.carriageReturn) && !jsxAttributeString) {
|
|
1657
|
+
result += text.substring(start, this.pos);
|
|
1658
|
+
this.tokenFlags |= TokenFlags.Unterminated;
|
|
1659
|
+
this.error(Diagnostics.Unterminated_string_literal);
|
|
1660
|
+
break;
|
|
1661
|
+
}
|
|
1662
|
+
this.pos = (this.pos + 1) | 0;
|
|
1663
|
+
}
|
|
1664
|
+
this.setValue(result);
|
|
1665
|
+
}
|
|
1666
|
+
|
|
1667
|
+
/** Scans a template literal part starting at `` ` `` or `}`. */
|
|
1668
|
+
private scanTemplateAndSetTokenValue(shouldEmitInvalidEscapeError: boolean): SyntaxKind {
|
|
1669
|
+
const text = this.text;
|
|
1670
|
+
const chars = this.chars;
|
|
1671
|
+
const end = this.end;
|
|
1672
|
+
const startedWithBacktick = this.char() === CharacterCodes.backtick;
|
|
1673
|
+
let start = this.pos + 1;
|
|
1674
|
+
let pos = start;
|
|
1675
|
+
// The value is `text[start, pos)` unless escapes or CRs make it `cooked`.
|
|
1676
|
+
let cooked = false;
|
|
1677
|
+
let result = '';
|
|
1678
|
+
let token = SyntaxKind.Unknown;
|
|
1679
|
+
for (;;) {
|
|
1680
|
+
pos = skipTemplateText(chars, pos, end);
|
|
1681
|
+
const ch = pos < end ? chars[pos] : CharacterCodes.EOF;
|
|
1682
|
+
if (ch < 0 || ch === CharacterCodes.backtick) {
|
|
1683
|
+
this.pos = pos | 0;
|
|
1684
|
+
if (ch === CharacterCodes.backtick) {
|
|
1685
|
+
this.pos = (this.pos + 1) | 0;
|
|
1686
|
+
} else {
|
|
1687
|
+
this.tokenFlags |= TokenFlags.Unterminated;
|
|
1688
|
+
this.error(Diagnostics.Unterminated_template_literal);
|
|
1689
|
+
}
|
|
1690
|
+
token = startedWithBacktick ? SyntaxKind.NoSubstitutionTemplateLiteral : SyntaxKind.TemplateTail;
|
|
1691
|
+
break;
|
|
1692
|
+
}
|
|
1693
|
+
if (ch === CharacterCodes.$) {
|
|
1694
|
+
if (chars[pos + 1] !== CharacterCodes.openBrace) {
|
|
1695
|
+
pos++;
|
|
1696
|
+
continue;
|
|
1697
|
+
}
|
|
1698
|
+
this.pos = (pos + 2) | 0;
|
|
1699
|
+
token = startedWithBacktick ? SyntaxKind.TemplateHead : SyntaxKind.TemplateMiddle;
|
|
1700
|
+
break;
|
|
1701
|
+
}
|
|
1702
|
+
result += text.substring(start, pos);
|
|
1703
|
+
cooked = true;
|
|
1704
|
+
if (ch === CharacterCodes.backslash) {
|
|
1705
|
+
this.pos = pos | 0;
|
|
1706
|
+
result += this.scanEscapeSequence(
|
|
1707
|
+
shouldEmitInvalidEscapeError
|
|
1708
|
+
? EscapeSequenceScanningFlags.String | EscapeSequenceScanningFlags.ReportErrors
|
|
1709
|
+
: EscapeSequenceScanningFlags.String,
|
|
1710
|
+
);
|
|
1711
|
+
pos = this.pos;
|
|
1712
|
+
} else {
|
|
1713
|
+
// <CR><LF> and <CR> are normalized to <LF> in template values.
|
|
1714
|
+
result += '\n';
|
|
1715
|
+
pos++;
|
|
1716
|
+
if (pos < end && chars[pos] === CharacterCodes.lineFeed) pos++;
|
|
1717
|
+
}
|
|
1718
|
+
start = pos;
|
|
1719
|
+
}
|
|
1720
|
+
if (cooked) this.setValue(result + text.substring(start, pos));
|
|
1721
|
+
else this.setValueSlice(start, pos);
|
|
1722
|
+
return token;
|
|
1723
|
+
}
|
|
1724
|
+
|
|
1725
|
+
/** Scans an escape sequence at `\` and returns its cooked value. */
|
|
1726
|
+
private scanEscapeSequence(flags: EscapeSequenceScanningFlags): string {
|
|
1727
|
+
const start = this.pos;
|
|
1728
|
+
const value = this.scanEscapeCodePoint(flags);
|
|
1729
|
+
if (value >= 0) return String.fromCodePoint(value);
|
|
1730
|
+
return value === EscapeValue.Empty ? '' : this.text.substring(start, this.pos);
|
|
1731
|
+
}
|
|
1732
|
+
|
|
1733
|
+
/**
|
|
1734
|
+
* @internal Scans an escape sequence at `\`. Returns its code point, `EscapeValue.Empty`
|
|
1735
|
+
* for a line continuation, or `EscapeValue.Raw` when the value is the escape's own text.
|
|
1736
|
+
*/
|
|
1737
|
+
scanEscapeCodePoint(flags: EscapeSequenceScanningFlags): number {
|
|
1738
|
+
const start = this.pos;
|
|
1739
|
+
this.pos = (this.pos + 1) | 0;
|
|
1740
|
+
let ch = this.char();
|
|
1741
|
+
if (ch < 0) {
|
|
1742
|
+
this.error(Diagnostics.Unexpected_end_of_text);
|
|
1743
|
+
return EscapeValue.Empty;
|
|
1744
|
+
}
|
|
1745
|
+
this.pos = (this.pos + 1) | 0;
|
|
1746
|
+
switch (ch) {
|
|
1747
|
+
case CharacterCodes._0:
|
|
1748
|
+
case CharacterCodes._1:
|
|
1749
|
+
case CharacterCodes._2:
|
|
1750
|
+
case CharacterCodes._3:
|
|
1751
|
+
case CharacterCodes._4:
|
|
1752
|
+
case CharacterCodes._5:
|
|
1753
|
+
case CharacterCodes._6:
|
|
1754
|
+
case CharacterCodes._7: {
|
|
1755
|
+
// '\0' not followed by a digit is the null character; '\08' is '\0' + '8'.
|
|
1756
|
+
if (ch === CharacterCodes._0 && !isDigit(this.char())) return 0;
|
|
1757
|
+
// '\1', '\17', '\177', but '\4', '\47' and not '\477'.
|
|
1758
|
+
if (ch <= CharacterCodes._3 && isOctalDigit(this.char())) this.pos = (this.pos + 1) | 0;
|
|
1759
|
+
if (isOctalDigit(this.char())) this.pos = (this.pos + 1) | 0;
|
|
1760
|
+
this.tokenFlags |= TokenFlags.ContainsInvalidEscape;
|
|
1761
|
+
if ((flags & EscapeSequenceScanningFlags.ReportInvalidEscapeErrors) !== 0) {
|
|
1762
|
+
const code = parseInt(this.text.substring(start + 1, this.pos), 8);
|
|
1763
|
+
const args = [hexByte(code)];
|
|
1764
|
+
if (
|
|
1765
|
+
(flags & EscapeSequenceScanningFlags.RegularExpression) !== 0 &&
|
|
1766
|
+
(flags & EscapeSequenceScanningFlags.AtomEscape) === 0 &&
|
|
1767
|
+
ch !== CharacterCodes._0
|
|
1768
|
+
)
|
|
1769
|
+
this.errorAt(
|
|
1770
|
+
Diagnostics.Octal_escape_sequences_and_backreferences_are_not_allowed_in_a_character_class_If_this_was_intended_as_an_escape_sequence_use_the_syntax_0_instead,
|
|
1771
|
+
start,
|
|
1772
|
+
this.pos - start,
|
|
1773
|
+
args,
|
|
1774
|
+
);
|
|
1775
|
+
else
|
|
1776
|
+
this.errorAt(
|
|
1777
|
+
Diagnostics.Octal_escape_sequences_are_not_allowed_Use_the_syntax_0,
|
|
1778
|
+
start,
|
|
1779
|
+
this.pos - start,
|
|
1780
|
+
args,
|
|
1781
|
+
);
|
|
1782
|
+
return code;
|
|
1783
|
+
}
|
|
1784
|
+
return EscapeValue.Raw;
|
|
1785
|
+
}
|
|
1786
|
+
case CharacterCodes._8:
|
|
1787
|
+
case CharacterCodes._9:
|
|
1788
|
+
this.tokenFlags |= TokenFlags.ContainsInvalidEscape;
|
|
1789
|
+
if ((flags & EscapeSequenceScanningFlags.ReportInvalidEscapeErrors) !== 0) {
|
|
1790
|
+
if (
|
|
1791
|
+
(flags & EscapeSequenceScanningFlags.RegularExpression) !== 0 &&
|
|
1792
|
+
(flags & EscapeSequenceScanningFlags.AtomEscape) === 0
|
|
1793
|
+
)
|
|
1794
|
+
this.errorAt(
|
|
1795
|
+
Diagnostics.Decimal_escape_sequences_and_backreferences_are_not_allowed_in_a_character_class,
|
|
1796
|
+
start,
|
|
1797
|
+
this.pos - start,
|
|
1798
|
+
noArgs,
|
|
1799
|
+
);
|
|
1800
|
+
else
|
|
1801
|
+
this.errorAt(Diagnostics.Escape_sequence_0_is_not_allowed, start, this.pos - start, [
|
|
1802
|
+
this.text.substring(start, this.pos),
|
|
1803
|
+
]);
|
|
1804
|
+
return ch;
|
|
1805
|
+
}
|
|
1806
|
+
return EscapeValue.Raw;
|
|
1807
|
+
case CharacterCodes.b:
|
|
1808
|
+
return CharacterCodes.backspace;
|
|
1809
|
+
case CharacterCodes.t:
|
|
1810
|
+
return CharacterCodes.tab;
|
|
1811
|
+
case CharacterCodes.n:
|
|
1812
|
+
return CharacterCodes.lineFeed;
|
|
1813
|
+
case CharacterCodes.v:
|
|
1814
|
+
return CharacterCodes.verticalTab;
|
|
1815
|
+
case CharacterCodes.f:
|
|
1816
|
+
return CharacterCodes.formFeed;
|
|
1817
|
+
case CharacterCodes.r:
|
|
1818
|
+
return CharacterCodes.carriageReturn;
|
|
1819
|
+
case CharacterCodes.singleQuote:
|
|
1820
|
+
return CharacterCodes.singleQuote;
|
|
1821
|
+
case CharacterCodes.doubleQuote:
|
|
1822
|
+
return CharacterCodes.doubleQuote;
|
|
1823
|
+
case CharacterCodes.u: {
|
|
1824
|
+
// '\uDDDD' and '\u{DDDDDD}'
|
|
1825
|
+
const extended = this.char() === CharacterCodes.openBrace;
|
|
1826
|
+
this.pos = (this.pos - 2) | 0;
|
|
1827
|
+
const reportErrors = (flags & EscapeSequenceScanningFlags.ReportInvalidEscapeErrors) !== 0;
|
|
1828
|
+
const codePoint = this.scanUnicodeEscape(reportErrors);
|
|
1829
|
+
if (extended && (flags & EscapeSequenceScanningFlags.AllowExtendedUnicodeEscape) === 0) {
|
|
1830
|
+
this.tokenFlags |= TokenFlags.ContainsInvalidEscape;
|
|
1831
|
+
if (reportErrors)
|
|
1832
|
+
this.errorAt(
|
|
1833
|
+
Diagnostics.Unicode_escape_sequences_are_only_available_when_the_Unicode_u_flag_or_the_Unicode_Sets_v_flag_is_set,
|
|
1834
|
+
start,
|
|
1835
|
+
this.pos - start,
|
|
1836
|
+
noArgs,
|
|
1837
|
+
);
|
|
1838
|
+
}
|
|
1839
|
+
if (codePoint < 0) return EscapeValue.Raw;
|
|
1840
|
+
// In any-Unicode regular expressions, '\uHigh\uLow' is one code point.
|
|
1841
|
+
if (
|
|
1842
|
+
!extended &&
|
|
1843
|
+
(flags & EscapeSequenceScanningFlags.RegularExpression) !== 0 &&
|
|
1844
|
+
(flags & EscapeSequenceScanningFlags.AnyUnicodeMode) !== 0 &&
|
|
1845
|
+
codePoint >= 0xd800 &&
|
|
1846
|
+
codePoint <= 0xdbff &&
|
|
1847
|
+
this.char() === CharacterCodes.backslash &&
|
|
1848
|
+
this.peek(1) === CharacterCodes.u &&
|
|
1849
|
+
this.peek(2) !== CharacterCodes.openBrace
|
|
1850
|
+
) {
|
|
1851
|
+
const savedPos = this.pos;
|
|
1852
|
+
const low = this.scanUnicodeEscape(reportErrors);
|
|
1853
|
+
if (low >= 0xdc00 && low <= 0xdfff) return (codePoint - 0xd800) * 0x400 + (low - 0xdc00) + 0x10000;
|
|
1854
|
+
this.pos = savedPos | 0;
|
|
1855
|
+
}
|
|
1856
|
+
// In strings, a high surrogate escape joins a following low surrogate escape.
|
|
1857
|
+
if (
|
|
1858
|
+
(flags & EscapeSequenceScanningFlags.RegularExpression) === 0 &&
|
|
1859
|
+
codePoint >= 0xd800 &&
|
|
1860
|
+
codePoint <= 0xdbff
|
|
1861
|
+
) {
|
|
1862
|
+
const low = this.scanLowSurrogateEscape();
|
|
1863
|
+
if (low >= 0) return (codePoint - 0xd800) * 0x400 + (low - 0xdc00) + 0x10000;
|
|
1864
|
+
}
|
|
1865
|
+
return codePoint;
|
|
1866
|
+
}
|
|
1867
|
+
case CharacterCodes.x:
|
|
1868
|
+
// '\xDD'
|
|
1869
|
+
for (; this.pos < start + 4; this.pos = (this.pos + 1) | 0) {
|
|
1870
|
+
if (!isHexDigit(this.char())) {
|
|
1871
|
+
this.tokenFlags |= TokenFlags.ContainsInvalidEscape;
|
|
1872
|
+
if ((flags & EscapeSequenceScanningFlags.ReportInvalidEscapeErrors) !== 0)
|
|
1873
|
+
this.error(Diagnostics.Hexadecimal_digit_expected);
|
|
1874
|
+
return EscapeValue.Raw;
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
this.tokenFlags |= TokenFlags.HexEscape;
|
|
1878
|
+
return parseInt(this.text.substring(start + 2, this.pos), 16);
|
|
1879
|
+
case CharacterCodes.carriageReturn:
|
|
1880
|
+
// A line continuation is the empty code unit sequence.
|
|
1881
|
+
if (this.char() === CharacterCodes.lineFeed) this.pos = (this.pos + 1) | 0;
|
|
1882
|
+
return EscapeValue.Empty;
|
|
1883
|
+
case CharacterCodes.lineFeed:
|
|
1884
|
+
case CharacterCodes.lineSeparator:
|
|
1885
|
+
case CharacterCodes.paragraphSeparator:
|
|
1886
|
+
return EscapeValue.Empty;
|
|
1887
|
+
default:
|
|
1888
|
+
if (ch >= 0xd800 && ch <= 0xdbff) {
|
|
1889
|
+
this.pos = (this.pos - 1) | 0;
|
|
1890
|
+
ch = this.codePoint();
|
|
1891
|
+
this.pos = (this.pos + charSize(ch)) | 0;
|
|
1892
|
+
}
|
|
1893
|
+
if (
|
|
1894
|
+
(flags & EscapeSequenceScanningFlags.AnyUnicodeMode) !== 0 ||
|
|
1895
|
+
((flags & EscapeSequenceScanningFlags.RegularExpression) !== 0 &&
|
|
1896
|
+
(flags & EscapeSequenceScanningFlags.AnnexB) === 0 &&
|
|
1897
|
+
isIdentifierPart(ch))
|
|
1898
|
+
)
|
|
1899
|
+
this.errorAt(
|
|
1900
|
+
Diagnostics.This_character_cannot_be_escaped_in_a_regular_expression,
|
|
1901
|
+
start,
|
|
1902
|
+
this.pos - start,
|
|
1903
|
+
noArgs,
|
|
1904
|
+
);
|
|
1905
|
+
return ch;
|
|
1906
|
+
}
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
/** After a high surrogate escape: the low surrogate of a following `\u` escape, or -1. */
|
|
1910
|
+
private scanLowSurrogateEscape(): number {
|
|
1911
|
+
if (this.char() !== CharacterCodes.backslash || this.peek(1) !== CharacterCodes.u) return -1;
|
|
1912
|
+
const pos = this.pos;
|
|
1913
|
+
const flags = this.tokenFlags;
|
|
1914
|
+
// Errors are reported when the escape is scanned again on its own.
|
|
1915
|
+
const low = this.scanUnicodeEscape(false);
|
|
1916
|
+
if (low >= 0xdc00 && low <= 0xdfff) return low;
|
|
1917
|
+
this.pos = pos | 0;
|
|
1918
|
+
this.tokenFlags = flags;
|
|
1919
|
+
return -1;
|
|
1920
|
+
}
|
|
1921
|
+
|
|
1922
|
+
/** Scans `\uXXXX` or `\u{X…}` at `pos`; returns the code point or -1 if invalid. */
|
|
1923
|
+
private scanUnicodeEscape(shouldEmitInvalidEscapeError: boolean): number {
|
|
1924
|
+
this.pos = (this.pos + 2) | 0;
|
|
1925
|
+
const start = this.pos;
|
|
1926
|
+
const extended = this.char() === CharacterCodes.openBrace;
|
|
1927
|
+
let value: number;
|
|
1928
|
+
if (extended) {
|
|
1929
|
+
this.pos = (this.pos + 1) | 0;
|
|
1930
|
+
value = this.scanHexValue(1, true);
|
|
1931
|
+
} else {
|
|
1932
|
+
this.tokenFlags |= TokenFlags.UnicodeEscape;
|
|
1933
|
+
value = this.scanHexValue(4, false);
|
|
1934
|
+
}
|
|
1935
|
+
if (value < 0) {
|
|
1936
|
+
this.tokenFlags |= TokenFlags.ContainsInvalidEscape;
|
|
1937
|
+
if (shouldEmitInvalidEscapeError) this.error(Diagnostics.Hexadecimal_digit_expected);
|
|
1938
|
+
return -1;
|
|
1939
|
+
}
|
|
1940
|
+
if (extended) {
|
|
1941
|
+
let invalid = false;
|
|
1942
|
+
if (value > 0x10ffff) {
|
|
1943
|
+
if (shouldEmitInvalidEscapeError)
|
|
1944
|
+
this.errorAt(
|
|
1945
|
+
Diagnostics.An_extended_Unicode_escape_value_must_be_between_0x0_and_0x10FFFF_inclusive,
|
|
1946
|
+
start + 1,
|
|
1947
|
+
this.pos - start - 1,
|
|
1948
|
+
noArgs,
|
|
1949
|
+
);
|
|
1950
|
+
invalid = true;
|
|
1951
|
+
}
|
|
1952
|
+
if (this.pos >= this.end) {
|
|
1953
|
+
if (shouldEmitInvalidEscapeError) this.error(Diagnostics.Unexpected_end_of_text);
|
|
1954
|
+
invalid = true;
|
|
1955
|
+
} else if (this.char() === CharacterCodes.closeBrace) {
|
|
1956
|
+
this.pos = (this.pos + 1) | 0;
|
|
1957
|
+
} else {
|
|
1958
|
+
if (shouldEmitInvalidEscapeError) this.error(Diagnostics.Unterminated_Unicode_escape_sequence);
|
|
1959
|
+
invalid = true;
|
|
1960
|
+
}
|
|
1961
|
+
if (invalid) {
|
|
1962
|
+
this.tokenFlags |= TokenFlags.ContainsInvalidEscape;
|
|
1963
|
+
return -1;
|
|
1964
|
+
}
|
|
1965
|
+
this.tokenFlags |= TokenFlags.ExtendedUnicodeEscape;
|
|
1966
|
+
}
|
|
1967
|
+
return value;
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1970
|
+
/** At `\`: the code point of a following `\u` escape, or -1. Leaves the scanner unchanged. */
|
|
1971
|
+
private peekUnicodeEscape(): number {
|
|
1972
|
+
if (this.peek(1) !== CharacterCodes.u) return -1;
|
|
1973
|
+
const pos = this.pos;
|
|
1974
|
+
const flags = this.tokenFlags;
|
|
1975
|
+
const codePoint = this.scanUnicodeEscape(false);
|
|
1976
|
+
this.pos = pos | 0;
|
|
1977
|
+
this.tokenFlags = flags;
|
|
1978
|
+
return codePoint;
|
|
1979
|
+
}
|
|
1980
|
+
|
|
1981
|
+
/** Scans hex digits (no separators) and returns their value, or -1 if fewer than `minCount`. */
|
|
1982
|
+
private scanHexValue(minCount: number, scanAsManyAsPossible: boolean): number {
|
|
1983
|
+
let count = 0;
|
|
1984
|
+
let value = 0;
|
|
1985
|
+
while (count < minCount || scanAsManyAsPossible) {
|
|
1986
|
+
const ch = this.char();
|
|
1987
|
+
let digit: number;
|
|
1988
|
+
if (ch >= CharacterCodes._0 && ch <= CharacterCodes._9) digit = ch - CharacterCodes._0;
|
|
1989
|
+
else if (ch >= CharacterCodes.A && ch <= CharacterCodes.F) digit = ch - CharacterCodes.A + 10;
|
|
1990
|
+
else if (ch >= CharacterCodes.a && ch <= CharacterCodes.f) digit = ch - CharacterCodes.a + 10;
|
|
1991
|
+
else break;
|
|
1992
|
+
value = value * 16 + digit;
|
|
1993
|
+
count++;
|
|
1994
|
+
this.pos = (this.pos + 1) | 0;
|
|
1995
|
+
}
|
|
1996
|
+
return count < minCount ? -1 : value;
|
|
1997
|
+
}
|
|
1998
|
+
|
|
1999
|
+
/** `text[start, end)` without numeric separators. */
|
|
2000
|
+
private withoutSeparators(start: number, end: number): string {
|
|
2001
|
+
if ((this.tokenFlags & TokenFlags.ContainsSeparator) === 0) return this.text.substring(start, end);
|
|
2002
|
+
let result = '';
|
|
2003
|
+
let from = start;
|
|
2004
|
+
for (let i = start; i < end; i++) {
|
|
2005
|
+
if (this.chars[i] !== CharacterCodes._) continue;
|
|
2006
|
+
result += this.text.substring(from, i);
|
|
2007
|
+
from = i + 1;
|
|
2008
|
+
}
|
|
2009
|
+
return result + this.text.substring(from, end);
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
private scanNumber(): SyntaxKind {
|
|
2013
|
+
let start = this.pos;
|
|
2014
|
+
if (this.char() === CharacterCodes._0) {
|
|
2015
|
+
this.pos = (this.pos + 1) | 0;
|
|
2016
|
+
if (this.char() === CharacterCodes._) {
|
|
2017
|
+
this.tokenFlags |= TokenFlags.ContainsSeparator | TokenFlags.ContainsInvalidSeparator;
|
|
2018
|
+
this.errorAt(Diagnostics.Numeric_separators_are_not_allowed_here, this.pos, 1, noArgs);
|
|
2019
|
+
this.pos = start | 0;
|
|
2020
|
+
this.scanNumberFragment();
|
|
2021
|
+
} else {
|
|
2022
|
+
const digitsStart = this.pos;
|
|
2023
|
+
let isOctal = true;
|
|
2024
|
+
while (isDigit(this.char())) {
|
|
2025
|
+
if (!isOctalDigit(this.char())) isOctal = false;
|
|
2026
|
+
this.pos = (this.pos + 1) | 0;
|
|
2027
|
+
}
|
|
2028
|
+
if (this.pos > digitsStart && isOctal) {
|
|
2029
|
+
// Legacy octal literal, e.g. `0777`.
|
|
2030
|
+
const value = parseInt(this.text.substring(digitsStart, this.pos), 8);
|
|
2031
|
+
this.setValue(String(value));
|
|
2032
|
+
this.tokenFlags |= TokenFlags.Octal;
|
|
2033
|
+
const withMinus = this.token === SyntaxKind.MinusToken;
|
|
2034
|
+
const literal = (withMinus ? '-0o' : '0o') + value.toString(8);
|
|
2035
|
+
if (withMinus) start--;
|
|
2036
|
+
this.errorAt(Diagnostics.Octal_literals_are_not_allowed_Use_the_syntax_0, start, this.pos - start, [literal]);
|
|
2037
|
+
return SyntaxKind.NumericLiteral;
|
|
2038
|
+
}
|
|
2039
|
+
if (this.pos > digitsStart) this.tokenFlags |= TokenFlags.ContainsLeadingZero;
|
|
2040
|
+
}
|
|
2041
|
+
} else {
|
|
2042
|
+
this.scanNumberFragment();
|
|
2043
|
+
}
|
|
2044
|
+
const fixedPartEnd = this.pos;
|
|
2045
|
+
if (this.char() === CharacterCodes.dot) {
|
|
2046
|
+
this.pos = (this.pos + 1) | 0;
|
|
2047
|
+
this.scanNumberFragment();
|
|
2048
|
+
}
|
|
2049
|
+
let end = this.pos;
|
|
2050
|
+
if (this.char() === CharacterCodes.E || this.char() === CharacterCodes.e) {
|
|
2051
|
+
this.pos = (this.pos + 1) | 0;
|
|
2052
|
+
this.tokenFlags |= TokenFlags.Scientific;
|
|
2053
|
+
if (this.char() === CharacterCodes.plus || this.char() === CharacterCodes.minus) this.pos = (this.pos + 1) | 0;
|
|
2054
|
+
if (this.scanNumberFragment() === 0) this.error(Diagnostics.Digit_expected);
|
|
2055
|
+
else end = this.pos;
|
|
2056
|
+
}
|
|
2057
|
+
// Integers of up to 15 digits without separators are already canonical.
|
|
2058
|
+
if (
|
|
2059
|
+
fixedPartEnd === this.pos &&
|
|
2060
|
+
this.pos - start <= 15 &&
|
|
2061
|
+
(this.tokenFlags & (TokenFlags.ContainsSeparator | TokenFlags.ContainsLeadingZero)) === 0 &&
|
|
2062
|
+
this.chars[this.pos] !== CharacterCodes.n
|
|
2063
|
+
) {
|
|
2064
|
+
this.setValueSlice(start, this.pos);
|
|
2065
|
+
if (!isIdentifierStart(this.codePoint())) return SyntaxKind.NumericLiteral;
|
|
2066
|
+
}
|
|
2067
|
+
const raw = this.withoutSeparators(start, end);
|
|
2068
|
+
if ((this.tokenFlags & TokenFlags.ContainsLeadingZero) !== 0) {
|
|
2069
|
+
this.errorAt(Diagnostics.Decimals_with_leading_zeros_are_not_allowed, start, this.pos - start, noArgs);
|
|
2070
|
+
this.setValue(String(Number(raw)));
|
|
2071
|
+
return SyntaxKind.NumericLiteral;
|
|
2072
|
+
}
|
|
2073
|
+
let result: SyntaxKind;
|
|
2074
|
+
if (fixedPartEnd === this.pos) {
|
|
2075
|
+
this.setValue(raw);
|
|
2076
|
+
result = this.scanBigIntSuffix();
|
|
2077
|
+
} else {
|
|
2078
|
+
this.setValue(String(Number(raw)));
|
|
2079
|
+
result = SyntaxKind.NumericLiteral;
|
|
2080
|
+
}
|
|
2081
|
+
if (isIdentifierStart(this.codePoint())) {
|
|
2082
|
+
const idStart = this.pos;
|
|
2083
|
+
const id = this.scanIdentifierParts();
|
|
2084
|
+
if (result !== SyntaxKind.BigIntLiteral && id.length === 1 && this.chars[idStart] === CharacterCodes.n) {
|
|
2085
|
+
if ((this.tokenFlags & TokenFlags.Scientific) !== 0) {
|
|
2086
|
+
this.errorAt(Diagnostics.A_bigint_literal_cannot_use_exponential_notation, start, this.pos - start, noArgs);
|
|
2087
|
+
return result;
|
|
2088
|
+
}
|
|
2089
|
+
if (fixedPartEnd < idStart) {
|
|
2090
|
+
this.errorAt(Diagnostics.A_bigint_literal_must_be_an_integer, start, this.pos - start, noArgs);
|
|
2091
|
+
return result;
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
this.errorAt(
|
|
2095
|
+
Diagnostics.An_identifier_or_keyword_cannot_immediately_follow_a_numeric_literal,
|
|
2096
|
+
idStart,
|
|
2097
|
+
this.pos - idStart,
|
|
2098
|
+
noArgs,
|
|
2099
|
+
);
|
|
2100
|
+
this.pos = idStart | 0;
|
|
2101
|
+
}
|
|
2102
|
+
return result;
|
|
2103
|
+
}
|
|
2104
|
+
|
|
2105
|
+
/** Scans decimal digits with numeric separators; returns how many digits. */
|
|
2106
|
+
private scanNumberFragment(): number {
|
|
2107
|
+
let count = 0;
|
|
2108
|
+
let allowSeparator = false;
|
|
2109
|
+
let isPreviousTokenSeparator = false;
|
|
2110
|
+
for (;;) {
|
|
2111
|
+
const ch = this.char();
|
|
2112
|
+
if (isDigit(ch)) {
|
|
2113
|
+
allowSeparator = true;
|
|
2114
|
+
isPreviousTokenSeparator = false;
|
|
2115
|
+
count++;
|
|
2116
|
+
} else if (ch === CharacterCodes._) {
|
|
2117
|
+
this.tokenFlags |= TokenFlags.ContainsSeparator;
|
|
2118
|
+
if (allowSeparator) {
|
|
2119
|
+
allowSeparator = false;
|
|
2120
|
+
isPreviousTokenSeparator = true;
|
|
2121
|
+
} else {
|
|
2122
|
+
this.tokenFlags |= TokenFlags.ContainsInvalidSeparator;
|
|
2123
|
+
if (isPreviousTokenSeparator)
|
|
2124
|
+
this.errorAt(Diagnostics.Multiple_consecutive_numeric_separators_are_not_permitted, this.pos, 1, noArgs);
|
|
2125
|
+
else this.errorAt(Diagnostics.Numeric_separators_are_not_allowed_here, this.pos, 1, noArgs);
|
|
2126
|
+
}
|
|
2127
|
+
} else {
|
|
2128
|
+
break;
|
|
2129
|
+
}
|
|
2130
|
+
this.pos = (this.pos + 1) | 0;
|
|
2131
|
+
}
|
|
2132
|
+
if (isPreviousTokenSeparator) {
|
|
2133
|
+
this.tokenFlags |= TokenFlags.ContainsInvalidSeparator;
|
|
2134
|
+
this.errorAt(Diagnostics.Numeric_separators_are_not_allowed_here, this.pos - 1, 1, noArgs);
|
|
2135
|
+
}
|
|
2136
|
+
return count;
|
|
2137
|
+
}
|
|
2138
|
+
|
|
2139
|
+
/** Scans digits of a `0x`, `0b` or `0o` literal (allowing separators); returns how many. */
|
|
2140
|
+
private scanSpecifierDigits(base: number): number {
|
|
2141
|
+
let count = 0;
|
|
2142
|
+
let allowSeparator = false;
|
|
2143
|
+
let isPreviousTokenSeparator = false;
|
|
2144
|
+
for (;;) {
|
|
2145
|
+
const ch = this.char();
|
|
2146
|
+
if (base === 16 ? isHexDigit(ch) : isDigit(ch) && ch - CharacterCodes._0 < base) {
|
|
2147
|
+
allowSeparator = true;
|
|
2148
|
+
isPreviousTokenSeparator = false;
|
|
2149
|
+
count++;
|
|
2150
|
+
} else if (ch === CharacterCodes._) {
|
|
2151
|
+
this.tokenFlags |= TokenFlags.ContainsSeparator;
|
|
2152
|
+
if (allowSeparator) {
|
|
2153
|
+
allowSeparator = false;
|
|
2154
|
+
isPreviousTokenSeparator = true;
|
|
2155
|
+
} else if (isPreviousTokenSeparator) {
|
|
2156
|
+
this.errorAt(Diagnostics.Multiple_consecutive_numeric_separators_are_not_permitted, this.pos, 1, noArgs);
|
|
2157
|
+
} else {
|
|
2158
|
+
this.errorAt(Diagnostics.Numeric_separators_are_not_allowed_here, this.pos, 1, noArgs);
|
|
2159
|
+
}
|
|
2160
|
+
} else {
|
|
2161
|
+
break;
|
|
2162
|
+
}
|
|
2163
|
+
this.pos = (this.pos + 1) | 0;
|
|
2164
|
+
}
|
|
2165
|
+
if (isPreviousTokenSeparator)
|
|
2166
|
+
this.errorAt(Diagnostics.Numeric_separators_are_not_allowed_here, this.pos - 1, 1, noArgs);
|
|
2167
|
+
return count;
|
|
2168
|
+
}
|
|
2169
|
+
|
|
2170
|
+
private scanHexNumber(): SyntaxKind {
|
|
2171
|
+
this.pos = (this.pos + 2) | 0;
|
|
2172
|
+
const digitsStart = this.pos;
|
|
2173
|
+
let digits: string;
|
|
2174
|
+
if (this.scanSpecifierDigits(16) === 0) {
|
|
2175
|
+
this.error(Diagnostics.Hexadecimal_digit_expected);
|
|
2176
|
+
digits = '0';
|
|
2177
|
+
} else {
|
|
2178
|
+
digits = this.withoutSeparators(digitsStart, this.pos).toLowerCase();
|
|
2179
|
+
}
|
|
2180
|
+
this.setValue('0x' + digits);
|
|
2181
|
+
this.tokenFlags |= TokenFlags.HexSpecifier;
|
|
2182
|
+
return this.scanBigIntSuffix();
|
|
2183
|
+
}
|
|
2184
|
+
|
|
2185
|
+
private scanBinaryOrOctalNumber(base: number): SyntaxKind {
|
|
2186
|
+
this.pos = (this.pos + 2) | 0;
|
|
2187
|
+
const digitsStart = this.pos;
|
|
2188
|
+
let digits: string;
|
|
2189
|
+
if (this.scanSpecifierDigits(base) === 0) {
|
|
2190
|
+
this.error(base === 2 ? Diagnostics.Binary_digit_expected : Diagnostics.Octal_digit_expected);
|
|
2191
|
+
digits = '0';
|
|
2192
|
+
} else {
|
|
2193
|
+
digits = this.withoutSeparators(digitsStart, this.pos);
|
|
2194
|
+
}
|
|
2195
|
+
this.setValue((base === 2 ? '0b' : '0o') + digits);
|
|
2196
|
+
this.tokenFlags |= base === 2 ? TokenFlags.BinarySpecifier : TokenFlags.OctalSpecifier;
|
|
2197
|
+
return this.scanBigIntSuffix();
|
|
2198
|
+
}
|
|
2199
|
+
|
|
2200
|
+
/** Completes a numeric literal whose value is set: a `n` suffix makes it a bigint. */
|
|
2201
|
+
private scanBigIntSuffix(): SyntaxKind {
|
|
2202
|
+
if (this.char() === CharacterCodes.n) {
|
|
2203
|
+
if ((this.tokenFlags & TokenFlags.BinaryOrOctalSpecifier) !== 0)
|
|
2204
|
+
this.setValue(parsePseudoBigInt(this.tokenValue) + 'n');
|
|
2205
|
+
else this.setValue(this.tokenValue + 'n');
|
|
2206
|
+
this.pos = (this.pos + 1) | 0;
|
|
2207
|
+
return SyntaxKind.BigIntLiteral;
|
|
2208
|
+
}
|
|
2209
|
+
this.setValue(String(Number(this.tokenValue)));
|
|
2210
|
+
return SyntaxKind.NumericLiteral;
|
|
2211
|
+
}
|
|
2212
|
+
|
|
2213
|
+
/** Splits `<<` into `<`. */
|
|
2214
|
+
reScanLessThanToken(): SyntaxKind {
|
|
2215
|
+
if (this.token === SyntaxKind.LessThanLessThanToken) {
|
|
2216
|
+
this.pos = (this.tokenStart + 1) | 0;
|
|
2217
|
+
this.token = SyntaxKind.LessThanToken;
|
|
2218
|
+
}
|
|
2219
|
+
return this.token;
|
|
2220
|
+
}
|
|
2221
|
+
|
|
2222
|
+
/** Joins `>` with following `>`, `>=`, `>>`, `>>=` or `=`. */
|
|
2223
|
+
reScanGreaterThanToken(): SyntaxKind {
|
|
2224
|
+
if (this.token !== SyntaxKind.GreaterThanToken) return this.token;
|
|
2225
|
+
this.pos = (this.tokenStart + 1) | 0;
|
|
2226
|
+
if (this.char() === CharacterCodes.greaterThan) {
|
|
2227
|
+
if (this.peek(1) === CharacterCodes.greaterThan) {
|
|
2228
|
+
if (this.peek(2) === CharacterCodes.equals) {
|
|
2229
|
+
this.pos = (this.pos + 3) | 0;
|
|
2230
|
+
return (this.token = SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken);
|
|
2231
|
+
}
|
|
2232
|
+
this.pos = (this.pos + 2) | 0;
|
|
2233
|
+
return (this.token = SyntaxKind.GreaterThanGreaterThanGreaterThanToken);
|
|
2234
|
+
}
|
|
2235
|
+
if (this.peek(1) === CharacterCodes.equals) {
|
|
2236
|
+
this.pos = (this.pos + 2) | 0;
|
|
2237
|
+
return (this.token = SyntaxKind.GreaterThanGreaterThanEqualsToken);
|
|
2238
|
+
}
|
|
2239
|
+
this.pos = (this.pos + 1) | 0;
|
|
2240
|
+
return (this.token = SyntaxKind.GreaterThanGreaterThanToken);
|
|
2241
|
+
}
|
|
2242
|
+
if (this.char() === CharacterCodes.equals) {
|
|
2243
|
+
this.pos = (this.pos + 1) | 0;
|
|
2244
|
+
return (this.token = SyntaxKind.GreaterThanEqualsToken);
|
|
2245
|
+
}
|
|
2246
|
+
return this.token;
|
|
2247
|
+
}
|
|
2248
|
+
|
|
2249
|
+
/** Rescans a `}` as a template middle or tail. */
|
|
2250
|
+
reScanTemplateToken(isTaggedTemplate: boolean): SyntaxKind {
|
|
2251
|
+
this.pos = this.tokenStart;
|
|
2252
|
+
return (this.token = this.scanTemplateAndSetTokenValue(!isTaggedTemplate));
|
|
2253
|
+
}
|
|
2254
|
+
|
|
2255
|
+
/** Splits `*=` into `*` and `=`, returning `=`. */
|
|
2256
|
+
reScanAsteriskEqualsToken(): SyntaxKind {
|
|
2257
|
+
if (this.token !== SyntaxKind.AsteriskEqualsToken)
|
|
2258
|
+
throw new Error("'reScanAsteriskEqualsToken' should only be called on a '*='");
|
|
2259
|
+
this.pos = (this.tokenStart + 1) | 0;
|
|
2260
|
+
return (this.token = SyntaxKind.EqualsToken);
|
|
2261
|
+
}
|
|
2262
|
+
|
|
2263
|
+
/** Rescans `/` or `/=` as a regular expression literal, optionally checking its syntax. */
|
|
2264
|
+
reScanSlashToken(reportErrors = false): SyntaxKind {
|
|
2265
|
+
if (this.token !== SyntaxKind.SlashToken && this.token !== SyntaxKind.SlashEqualsToken) return this.token;
|
|
2266
|
+
const chars = this.chars;
|
|
2267
|
+
// Find the end of the body quickly so the flags are known before checking it.
|
|
2268
|
+
const bodyStart = this.tokenStart + 1;
|
|
2269
|
+
let p = bodyStart;
|
|
2270
|
+
let inEscape = false;
|
|
2271
|
+
let namedCaptureGroups = false;
|
|
2272
|
+
// A `[` inside a class does not nest here, even in Unicode Sets mode: `/[[]/` is terminated.
|
|
2273
|
+
let inCharacterClass = false;
|
|
2274
|
+
for (;;) {
|
|
2275
|
+
if (p >= this.end) {
|
|
2276
|
+
this.tokenFlags |= TokenFlags.Unterminated;
|
|
2277
|
+
break;
|
|
2278
|
+
}
|
|
2279
|
+
const ch = chars[p];
|
|
2280
|
+
if (isLineBreak(ch)) {
|
|
2281
|
+
this.tokenFlags |= TokenFlags.Unterminated;
|
|
2282
|
+
break;
|
|
2283
|
+
}
|
|
2284
|
+
if (inEscape) {
|
|
2285
|
+
inEscape = false;
|
|
2286
|
+
} else if (ch === CharacterCodes.slash && !inCharacterClass) {
|
|
2287
|
+
break;
|
|
2288
|
+
} else if (ch === CharacterCodes.openBracket) {
|
|
2289
|
+
inCharacterClass = true;
|
|
2290
|
+
} else if (ch === CharacterCodes.backslash) {
|
|
2291
|
+
inEscape = true;
|
|
2292
|
+
} else if (ch === CharacterCodes.closeBracket) {
|
|
2293
|
+
inCharacterClass = false;
|
|
2294
|
+
} else if (
|
|
2295
|
+
!inCharacterClass &&
|
|
2296
|
+
ch === CharacterCodes.openParen &&
|
|
2297
|
+
p + 2 < this.end &&
|
|
2298
|
+
chars[p + 1] === CharacterCodes.question &&
|
|
2299
|
+
chars[p + 2] === CharacterCodes.lessThan &&
|
|
2300
|
+
(p + 3 >= this.end || (chars[p + 3] !== CharacterCodes.equals && chars[p + 3] !== CharacterCodes.exclamation))
|
|
2301
|
+
) {
|
|
2302
|
+
namedCaptureGroups = true;
|
|
2303
|
+
}
|
|
2304
|
+
p++;
|
|
2305
|
+
}
|
|
2306
|
+
const bodyEnd = p;
|
|
2307
|
+
if ((this.tokenFlags & TokenFlags.Unterminated) !== 0) {
|
|
2308
|
+
// Recover at the nearest unbalanced bracket, counting nested classes.
|
|
2309
|
+
p = bodyStart;
|
|
2310
|
+
inEscape = false;
|
|
2311
|
+
let classDepth = 0;
|
|
2312
|
+
let inDecimalQuantifier = false;
|
|
2313
|
+
let groupDepth = 0;
|
|
2314
|
+
while (p < bodyEnd) {
|
|
2315
|
+
const ch = chars[p];
|
|
2316
|
+
if (inEscape) {
|
|
2317
|
+
inEscape = false;
|
|
2318
|
+
} else if (ch === CharacterCodes.backslash) {
|
|
2319
|
+
inEscape = true;
|
|
2320
|
+
} else if (ch === CharacterCodes.openBracket) {
|
|
2321
|
+
classDepth++;
|
|
2322
|
+
} else if (ch === CharacterCodes.closeBracket && classDepth !== 0) {
|
|
2323
|
+
classDepth--;
|
|
2324
|
+
} else if (classDepth === 0) {
|
|
2325
|
+
if (ch === CharacterCodes.openBrace) {
|
|
2326
|
+
inDecimalQuantifier = true;
|
|
2327
|
+
} else if (ch === CharacterCodes.closeBrace && inDecimalQuantifier) {
|
|
2328
|
+
inDecimalQuantifier = false;
|
|
2329
|
+
} else if (!inDecimalQuantifier) {
|
|
2330
|
+
if (ch === CharacterCodes.openParen) groupDepth++;
|
|
2331
|
+
else if (ch === CharacterCodes.closeParen && groupDepth !== 0) groupDepth--;
|
|
2332
|
+
else if (
|
|
2333
|
+
ch === CharacterCodes.closeParen ||
|
|
2334
|
+
ch === CharacterCodes.closeBracket ||
|
|
2335
|
+
ch === CharacterCodes.closeBrace
|
|
2336
|
+
)
|
|
2337
|
+
break;
|
|
2338
|
+
}
|
|
2339
|
+
}
|
|
2340
|
+
p++;
|
|
2341
|
+
}
|
|
2342
|
+
// Trailing whitespace and semicolons are unlikely to belong to the regex.
|
|
2343
|
+
while (p > bodyStart) {
|
|
2344
|
+
const ch = chars[p - 1];
|
|
2345
|
+
if (!isWhiteSpaceLike(ch) && ch !== CharacterCodes.semicolon) break;
|
|
2346
|
+
p--;
|
|
2347
|
+
}
|
|
2348
|
+
this.errorAt(Diagnostics.Unterminated_regular_expression_literal, this.tokenStart, p - this.tokenStart, noArgs);
|
|
2349
|
+
} else {
|
|
2350
|
+
p++; // the closing slash
|
|
2351
|
+
let flags = RegularExpressionFlags.None;
|
|
2352
|
+
while (p < this.end) {
|
|
2353
|
+
const ch = this.codePointAt(p, this.end);
|
|
2354
|
+
if (ch === CharacterCodes.replacementCharacter || !isIdentifierPart(ch)) break;
|
|
2355
|
+
const size = charSize(ch);
|
|
2356
|
+
if (reportErrors) {
|
|
2357
|
+
const flag = regularExpressionFlag(ch);
|
|
2358
|
+
if (flag === RegularExpressionFlags.None)
|
|
2359
|
+
this.errorAt(Diagnostics.Unknown_regular_expression_flag, p, size, noArgs);
|
|
2360
|
+
else if ((flags & flag) !== 0) this.errorAt(Diagnostics.Duplicate_regular_expression_flag, p, size, noArgs);
|
|
2361
|
+
else if (((flags | flag) & RegularExpressionFlags.AnyUnicodeMode) === RegularExpressionFlags.AnyUnicodeMode)
|
|
2362
|
+
this.errorAt(
|
|
2363
|
+
Diagnostics.The_Unicode_u_flag_and_the_Unicode_Sets_v_flag_cannot_be_set_simultaneously,
|
|
2364
|
+
p,
|
|
2365
|
+
size,
|
|
2366
|
+
noArgs,
|
|
2367
|
+
);
|
|
2368
|
+
else {
|
|
2369
|
+
flags |= flag;
|
|
2370
|
+
this.checkRegularExpressionFlagAvailability(flag, p, size);
|
|
2371
|
+
}
|
|
2372
|
+
}
|
|
2373
|
+
p += size;
|
|
2374
|
+
}
|
|
2375
|
+
if (reportErrors) {
|
|
2376
|
+
const savedEnd = this.end;
|
|
2377
|
+
const savedTokenStart = this.tokenStart;
|
|
2378
|
+
const savedTokenFlags = this.tokenFlags;
|
|
2379
|
+
this.pos = bodyStart | 0;
|
|
2380
|
+
this.end = bodyEnd | 0;
|
|
2381
|
+
checkRegularExpression(this, bodyEnd, flags, namedCaptureGroups);
|
|
2382
|
+
this.end = savedEnd;
|
|
2383
|
+
this.tokenStart = savedTokenStart;
|
|
2384
|
+
this.tokenFlags = savedTokenFlags;
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
this.pos = p | 0;
|
|
2388
|
+
this.setValueSlice(this.tokenStart, p);
|
|
2389
|
+
return (this.token = SyntaxKind.RegularExpressionLiteral);
|
|
2390
|
+
}
|
|
2391
|
+
|
|
2392
|
+
/** @internal Reports a regular expression flag unavailable at the current target. */
|
|
2393
|
+
checkRegularExpressionFlagAvailability(flag: RegularExpressionFlags, pos: number, size: number): void {
|
|
2394
|
+
let availableFrom: ScriptTarget;
|
|
2395
|
+
if (flag === RegularExpressionFlags.HasIndices) availableFrom = ScriptTarget.ES2022;
|
|
2396
|
+
else if (flag === RegularExpressionFlags.DotAll) availableFrom = ScriptTarget.ES2018;
|
|
2397
|
+
else if (flag === RegularExpressionFlags.UnicodeSets) availableFrom = ScriptTarget.ES2024;
|
|
2398
|
+
else return;
|
|
2399
|
+
if (this.languageVersion() < availableFrom)
|
|
2400
|
+
this.errorAt(Diagnostics.This_regular_expression_flag_is_only_available_when_targeting_0_or_later, pos, size, [
|
|
2401
|
+
regularExpressionFlagName(availableFrom),
|
|
2402
|
+
]);
|
|
2403
|
+
}
|
|
2404
|
+
|
|
2405
|
+
/** Rescans from the token's full start as JSX text or a JSX token. */
|
|
2406
|
+
reScanJsxToken(allowMultilineJsxText = true): SyntaxKind {
|
|
2407
|
+
this.pos = this.fullStartPos;
|
|
2408
|
+
this.tokenStart = this.fullStartPos;
|
|
2409
|
+
return (this.token = this.scanJsxToken(allowMultilineJsxText));
|
|
2410
|
+
}
|
|
2411
|
+
|
|
2412
|
+
/** Splits a private identifier into `#` and the name. */
|
|
2413
|
+
reScanHashToken(): SyntaxKind {
|
|
2414
|
+
if (this.token === SyntaxKind.PrivateIdentifier) {
|
|
2415
|
+
this.pos = (this.tokenStart + 1) | 0;
|
|
2416
|
+
this.token = SyntaxKind.HashToken;
|
|
2417
|
+
}
|
|
2418
|
+
return this.token;
|
|
2419
|
+
}
|
|
2420
|
+
|
|
2421
|
+
/** Splits `??` into `?`. */
|
|
2422
|
+
reScanQuestionToken(): SyntaxKind {
|
|
2423
|
+
if (this.token !== SyntaxKind.QuestionQuestionToken)
|
|
2424
|
+
throw new Error("'reScanQuestionToken' should only be called on a '??'");
|
|
2425
|
+
this.pos = (this.tokenStart + 1) | 0;
|
|
2426
|
+
return (this.token = SyntaxKind.QuestionToken);
|
|
2427
|
+
}
|
|
2428
|
+
|
|
2429
|
+
/** Scans JSX children: text, `<`, `</` or `{`. */
|
|
2430
|
+
scanJsxToken(allowMultilineJsxText = true): SyntaxKind {
|
|
2431
|
+
this.fullStartPos = this.pos | 0;
|
|
2432
|
+
this.tokenStart = this.pos | 0;
|
|
2433
|
+
const ch = this.char();
|
|
2434
|
+
if (ch < 0) return (this.token = SyntaxKind.EndOfFile);
|
|
2435
|
+
if (ch === CharacterCodes.lessThan) {
|
|
2436
|
+
if (this.peek(1) === CharacterCodes.slash) {
|
|
2437
|
+
this.pos = (this.pos + 2) | 0;
|
|
2438
|
+
return (this.token = SyntaxKind.LessThanSlashToken);
|
|
2439
|
+
}
|
|
2440
|
+
this.pos = (this.pos + 1) | 0;
|
|
2441
|
+
return (this.token = SyntaxKind.LessThanToken);
|
|
2442
|
+
}
|
|
2443
|
+
if (ch === CharacterCodes.openBrace) {
|
|
2444
|
+
this.pos = (this.pos + 1) | 0;
|
|
2445
|
+
return (this.token = SyntaxKind.OpenBraceToken);
|
|
2446
|
+
}
|
|
2447
|
+
// 0: only whitespace so far; -1: only whitespace and a line break, which is ignored.
|
|
2448
|
+
let firstNonWhitespace = 0;
|
|
2449
|
+
while (this.pos < this.end) {
|
|
2450
|
+
const c = this.chars[this.pos] | 0;
|
|
2451
|
+
if (c === CharacterCodes.openBrace) break;
|
|
2452
|
+
if (c === CharacterCodes.lessThan) {
|
|
2453
|
+
if (isConflictMarkerTrivia(this.text, this.pos)) {
|
|
2454
|
+
this.pos = scanConflictMarkerTrivia(this.text, this.pos, this) | 0;
|
|
2455
|
+
return (this.token = SyntaxKind.ConflictMarkerTrivia);
|
|
2456
|
+
}
|
|
2457
|
+
break;
|
|
2458
|
+
}
|
|
2459
|
+
if (c === CharacterCodes.greaterThan)
|
|
2460
|
+
this.errorAt(Diagnostics.Unexpected_token_Did_you_mean_or_gt, this.pos, 1, noArgs);
|
|
2461
|
+
else if (c === CharacterCodes.closeBrace)
|
|
2462
|
+
this.errorAt(Diagnostics.Unexpected_token_Did_you_mean_or_rbrace, this.pos, 1, noArgs);
|
|
2463
|
+
if (isLineBreak(c) && firstNonWhitespace === 0) firstNonWhitespace = -1;
|
|
2464
|
+
else if (!allowMultilineJsxText && isLineBreak(c) && firstNonWhitespace > 0) break;
|
|
2465
|
+
else if (!isWhiteSpaceLike(c)) firstNonWhitespace = this.pos;
|
|
2466
|
+
this.pos = (this.pos + 1) | 0;
|
|
2467
|
+
}
|
|
2468
|
+
this.setValueSlice(this.fullStartPos, this.pos);
|
|
2469
|
+
return (this.token = firstNonWhitespace === -1 ? SyntaxKind.JsxTextAllWhiteSpaces : SyntaxKind.JsxText);
|
|
2470
|
+
}
|
|
2471
|
+
|
|
2472
|
+
/** Extends an identifier or keyword with `-` and further parts, as JSX names allow. */
|
|
2473
|
+
scanJsxIdentifier(): SyntaxKind {
|
|
2474
|
+
if (!tokenIsIdentifierOrKeyword(this.token)) return this.token;
|
|
2475
|
+
let value = this.getTokenValue();
|
|
2476
|
+
while (this.pos < this.end) {
|
|
2477
|
+
if (this.char() === CharacterCodes.minus) {
|
|
2478
|
+
value += '-';
|
|
2479
|
+
this.pos = (this.pos + 1) | 0;
|
|
2480
|
+
continue;
|
|
2481
|
+
}
|
|
2482
|
+
const pos = this.pos;
|
|
2483
|
+
value += this.scanIdentifierParts();
|
|
2484
|
+
if (this.pos === pos) break;
|
|
2485
|
+
}
|
|
2486
|
+
this.setValue(value);
|
|
2487
|
+
return (this.token = getIdentifierToken(value));
|
|
2488
|
+
}
|
|
2489
|
+
|
|
2490
|
+
/** Scans a JSX attribute value after `=`: a string, or any other token. */
|
|
2491
|
+
scanJsxAttributeValue(): SyntaxKind {
|
|
2492
|
+
this.fullStartPos = this.pos | 0;
|
|
2493
|
+
while (this.pos < this.end && isWhiteSpaceLike(this.chars[this.pos] | 0)) this.pos = (this.pos + 1) | 0;
|
|
2494
|
+
this.tokenStart = this.pos | 0;
|
|
2495
|
+
const ch = this.char();
|
|
2496
|
+
if (ch === CharacterCodes.doubleQuote || ch === CharacterCodes.singleQuote) {
|
|
2497
|
+
this.scanString(true);
|
|
2498
|
+
return (this.token = SyntaxKind.StringLiteral);
|
|
2499
|
+
}
|
|
2500
|
+
return this.scan();
|
|
2501
|
+
}
|
|
2502
|
+
|
|
2503
|
+
reScanJsxAttributeValue(): SyntaxKind {
|
|
2504
|
+
this.pos = this.fullStartPos;
|
|
2505
|
+
this.tokenStart = this.fullStartPos;
|
|
2506
|
+
return this.scanJsxAttributeValue();
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
/** Scans JSDoc comment text up to a line break, backtick, `{` or tag; falls back to `scanJSDocToken`. */
|
|
2510
|
+
scanJSDocCommentTextToken(inBackticks: boolean): SyntaxKind {
|
|
2511
|
+
this.fullStartPos = this.pos | 0;
|
|
2512
|
+
this.tokenFlags = TokenFlags.None;
|
|
2513
|
+
if (this.pos >= this.end) return (this.token = SyntaxKind.EndOfFile);
|
|
2514
|
+
this.tokenStart = this.pos | 0;
|
|
2515
|
+
while (this.pos < this.end) {
|
|
2516
|
+
// Fast path: an ASCII unit that ends no text run.
|
|
2517
|
+
const unit = this.chars[this.pos] | 0;
|
|
2518
|
+
if (
|
|
2519
|
+
unit < 0x80 &&
|
|
2520
|
+
unit !== CharacterCodes.lineFeed &&
|
|
2521
|
+
unit !== CharacterCodes.carriageReturn &&
|
|
2522
|
+
unit !== CharacterCodes.backtick &&
|
|
2523
|
+
unit !== CharacterCodes.openBrace &&
|
|
2524
|
+
unit !== CharacterCodes.at
|
|
2525
|
+
) {
|
|
2526
|
+
this.pos = (this.pos + 1) | 0;
|
|
2527
|
+
continue;
|
|
2528
|
+
}
|
|
2529
|
+
const ch = this.codePointAt(this.pos, this.end);
|
|
2530
|
+
if (isLineBreak(ch) || ch === CharacterCodes.backtick) break;
|
|
2531
|
+
const size = charSize(ch);
|
|
2532
|
+
if (!inBackticks) {
|
|
2533
|
+
if (ch === CharacterCodes.openBrace) break;
|
|
2534
|
+
// Outside backticks, `@` starts a tag after whitespace and before an identifier.
|
|
2535
|
+
if (
|
|
2536
|
+
ch === CharacterCodes.at &&
|
|
2537
|
+
isWhiteSpaceSingleLine(this.codePointBefore(this.pos)) &&
|
|
2538
|
+
isIdentifierStart(this.codePointAt((this.pos + size) | 0, this.end))
|
|
2539
|
+
)
|
|
2540
|
+
break;
|
|
2541
|
+
}
|
|
2542
|
+
this.pos = (this.pos + size) | 0;
|
|
2543
|
+
}
|
|
2544
|
+
if (this.pos === this.tokenStart) return this.scanJSDocToken();
|
|
2545
|
+
this.setValueSlice(this.tokenStart, this.pos);
|
|
2546
|
+
return (this.token = SyntaxKind.JSDocCommentTextToken);
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2549
|
+
/** After `@`: whether a tag name (or an incomplete tag) can follow. */
|
|
2550
|
+
canFollowJSDocAt(): boolean {
|
|
2551
|
+
if (this.pos >= this.end) return true;
|
|
2552
|
+
const ch = this.codePointAt(this.pos, this.end);
|
|
2553
|
+
return isIdentifierStart(ch) || isWhiteSpaceSingleLine(ch) || isLineBreak(ch);
|
|
2554
|
+
}
|
|
2555
|
+
|
|
2556
|
+
scanJSDocToken(): SyntaxKind {
|
|
2557
|
+
this.fullStartPos = this.pos | 0;
|
|
2558
|
+
this.tokenFlags = TokenFlags.None;
|
|
2559
|
+
const text = this.text;
|
|
2560
|
+
const chars = this.chars;
|
|
2561
|
+
if (this.pos >= this.end) return (this.token = SyntaxKind.EndOfFile);
|
|
2562
|
+
this.tokenStart = this.pos | 0;
|
|
2563
|
+
const ch = this.codePointAt(this.pos, this.end);
|
|
2564
|
+
this.pos = (this.pos + charSize(ch)) | 0;
|
|
2565
|
+
switch (ch) {
|
|
2566
|
+
case CharacterCodes.tab:
|
|
2567
|
+
case CharacterCodes.verticalTab:
|
|
2568
|
+
case CharacterCodes.formFeed:
|
|
2569
|
+
case CharacterCodes.space:
|
|
2570
|
+
while (this.pos < this.end && isWhiteSpaceSingleLine(chars[this.pos] | 0)) this.pos = (this.pos + 1) | 0;
|
|
2571
|
+
return (this.token = SyntaxKind.WhitespaceTrivia);
|
|
2572
|
+
case CharacterCodes.at:
|
|
2573
|
+
return (this.token = SyntaxKind.AtToken);
|
|
2574
|
+
case CharacterCodes.carriageReturn:
|
|
2575
|
+
case CharacterCodes.lineFeed:
|
|
2576
|
+
if (ch === CharacterCodes.carriageReturn && this.char() === CharacterCodes.lineFeed)
|
|
2577
|
+
this.pos = (this.pos + 1) | 0;
|
|
2578
|
+
this.tokenFlags |= TokenFlags.PrecedingLineBreak;
|
|
2579
|
+
return (this.token = SyntaxKind.NewLineTrivia);
|
|
2580
|
+
case CharacterCodes.asterisk:
|
|
2581
|
+
return (this.token = SyntaxKind.AsteriskToken);
|
|
2582
|
+
case CharacterCodes.openBrace:
|
|
2583
|
+
return (this.token = SyntaxKind.OpenBraceToken);
|
|
2584
|
+
case CharacterCodes.closeBrace:
|
|
2585
|
+
return (this.token = SyntaxKind.CloseBraceToken);
|
|
2586
|
+
case CharacterCodes.openBracket:
|
|
2587
|
+
return (this.token = SyntaxKind.OpenBracketToken);
|
|
2588
|
+
case CharacterCodes.closeBracket:
|
|
2589
|
+
return (this.token = SyntaxKind.CloseBracketToken);
|
|
2590
|
+
case CharacterCodes.openParen:
|
|
2591
|
+
return (this.token = SyntaxKind.OpenParenToken);
|
|
2592
|
+
case CharacterCodes.closeParen:
|
|
2593
|
+
return (this.token = SyntaxKind.CloseParenToken);
|
|
2594
|
+
case CharacterCodes.lessThan:
|
|
2595
|
+
return (this.token = SyntaxKind.LessThanToken);
|
|
2596
|
+
case CharacterCodes.greaterThan:
|
|
2597
|
+
return (this.token = SyntaxKind.GreaterThanToken);
|
|
2598
|
+
case CharacterCodes.equals:
|
|
2599
|
+
return (this.token = SyntaxKind.EqualsToken);
|
|
2600
|
+
case CharacterCodes.comma:
|
|
2601
|
+
return (this.token = SyntaxKind.CommaToken);
|
|
2602
|
+
case CharacterCodes.dot:
|
|
2603
|
+
return (this.token = SyntaxKind.DotToken);
|
|
2604
|
+
case CharacterCodes.backtick:
|
|
2605
|
+
return (this.token = SyntaxKind.BacktickToken);
|
|
2606
|
+
case CharacterCodes.hash:
|
|
2607
|
+
return (this.token = SyntaxKind.HashToken);
|
|
2608
|
+
case CharacterCodes.backslash: {
|
|
2609
|
+
this.pos = (this.pos - 1) | 0;
|
|
2610
|
+
const codePoint = this.peekUnicodeEscape();
|
|
2611
|
+
if (codePoint >= 0 && isIdentifierStart(codePoint)) {
|
|
2612
|
+
const head = String.fromCodePoint(this.scanUnicodeEscape(true));
|
|
2613
|
+
this.setValue(head + this.scanIdentifierParts());
|
|
2614
|
+
return (this.token = getIdentifierToken(this.tokenValue));
|
|
2615
|
+
}
|
|
2616
|
+
this.pos = (this.pos + 1) | 0;
|
|
2617
|
+
return (this.token = SyntaxKind.Unknown);
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
if (!isIdentifierStart(ch)) return (this.token = SyntaxKind.Unknown);
|
|
2621
|
+
let last = ch;
|
|
2622
|
+
while (this.pos < this.end) {
|
|
2623
|
+
const unit = this.chars[this.pos] | 0;
|
|
2624
|
+
if (unit < 0x80) {
|
|
2625
|
+
last = unit;
|
|
2626
|
+
if (!isASCIIIdentifierPart(unit) && unit !== CharacterCodes.minus) break;
|
|
2627
|
+
this.pos = (this.pos + 1) | 0;
|
|
2628
|
+
continue;
|
|
2629
|
+
}
|
|
2630
|
+
last = this.codePointAt(this.pos, this.end);
|
|
2631
|
+
if (!isIdentifierPart(last) && last !== CharacterCodes.minus) break;
|
|
2632
|
+
this.pos = (this.pos + charSize(last)) | 0;
|
|
2633
|
+
}
|
|
2634
|
+
if (last === CharacterCodes.backslash)
|
|
2635
|
+
this.setValue(text.substring(this.tokenStart, this.pos) + this.scanIdentifierParts());
|
|
2636
|
+
else this.setValueSlice(this.tokenStart, this.pos);
|
|
2637
|
+
return (this.token = this.identifierKind());
|
|
2638
|
+
}
|
|
2639
|
+
}
|
|
2640
|
+
|
|
2641
|
+
const mergeConflictMarkerLength = 7;
|
|
2642
|
+
|
|
2643
|
+
function utf8Length(ch: number): number {
|
|
2644
|
+
return ch < 0x80 ? 1 : ch < 0x800 ? 2 : ch >= 0xd800 && ch <= 0xdfff ? 4 : 3;
|
|
2645
|
+
}
|
|
2646
|
+
|
|
2647
|
+
// Whether a conflict marker at `pos` is at a line start, as TypeScript 7 decides it:
|
|
2648
|
+
// after a CR or LF, or after a line terminator followed by two bytes of UTF-8
|
|
2649
|
+
// (two ASCII characters or one two-byte character).
|
|
2650
|
+
function isConflictMarkerLineStart(text: string, pos: number): boolean {
|
|
2651
|
+
if (pos === 0) return true;
|
|
2652
|
+
const previous = text.charCodeAt(pos - 1);
|
|
2653
|
+
if (previous === CharacterCodes.lineFeed || previous === CharacterCodes.carriageReturn) return true;
|
|
2654
|
+
const length = utf8Length(previous);
|
|
2655
|
+
if (length === 2) return pos >= 2 && isLineBreak(text.charCodeAt(pos - 2));
|
|
2656
|
+
if (length === 1 && pos >= 3 && text.charCodeAt(pos - 2) < 0x80) return isLineBreak(text.charCodeAt(pos - 3));
|
|
2657
|
+
return false;
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
/** Whether `text` has a `<<<<<<<`, `|||||||`, `=======` or `>>>>>>>` marker at `pos`. */
|
|
2661
|
+
export function isConflictMarkerTrivia(text: string, pos: number): boolean {
|
|
2662
|
+
if (pos + 1 >= text.length || text.charCodeAt(pos + 1) !== text.charCodeAt(pos)) return false;
|
|
2663
|
+
if (!isConflictMarkerLineStart(text, pos) || pos + mergeConflictMarkerLength >= text.length) return false;
|
|
2664
|
+
const ch = text.charCodeAt(pos);
|
|
2665
|
+
for (let i = 2; i < mergeConflictMarkerLength; i++) if (text.charCodeAt(pos + i) !== ch) return false;
|
|
2666
|
+
return ch === CharacterCodes.equals || text.charCodeAt(pos + mergeConflictMarkerLength) === CharacterCodes.space;
|
|
2667
|
+
}
|
|
2668
|
+
|
|
2669
|
+
/** Skips a conflict marker and returns the position after it; reports it if `scanner` is given. */
|
|
2670
|
+
function scanConflictMarkerTrivia(text: string, pos: number, scanner: Scanner | undefined): number {
|
|
2671
|
+
if (scanner !== undefined)
|
|
2672
|
+
scanner.errorAt(Diagnostics.Merge_conflict_marker_encountered, pos, mergeConflictMarkerLength, noArgs);
|
|
2673
|
+
const ch = text.charCodeAt(pos);
|
|
2674
|
+
const length = text.length;
|
|
2675
|
+
if (ch === CharacterCodes.lessThan || ch === CharacterCodes.greaterThan) {
|
|
2676
|
+
while (pos < length && !isLineBreak(text.charCodeAt(pos))) pos++;
|
|
2677
|
+
return pos;
|
|
2678
|
+
}
|
|
2679
|
+
// Consume from a ||||||| or ======= marker to the next ======= or >>>>>>> marker.
|
|
2680
|
+
while (pos < length) {
|
|
2681
|
+
const current = text.charCodeAt(pos);
|
|
2682
|
+
if (
|
|
2683
|
+
(current === CharacterCodes.equals || current === CharacterCodes.greaterThan) &&
|
|
2684
|
+
current !== ch &&
|
|
2685
|
+
isConflictMarkerTrivia(text, pos)
|
|
2686
|
+
)
|
|
2687
|
+
break;
|
|
2688
|
+
pos++;
|
|
2689
|
+
}
|
|
2690
|
+
return pos;
|
|
2691
|
+
}
|
|
2692
|
+
|
|
2693
|
+
function scanShebangTrivia(text: string, pos: number): number {
|
|
2694
|
+
pos += 2;
|
|
2695
|
+
while (pos < text.length && !isLineBreak(text.charCodeAt(pos))) pos++;
|
|
2696
|
+
return pos;
|
|
2697
|
+
}
|
|
2698
|
+
|
|
2699
|
+
function isShebangTrivia(text: string): boolean {
|
|
2700
|
+
return (
|
|
2701
|
+
text.length >= 2 && text.charCodeAt(0) === CharacterCodes.hash && text.charCodeAt(1) === CharacterCodes.exclamation
|
|
2702
|
+
);
|
|
2703
|
+
}
|
|
2704
|
+
|
|
2705
|
+
/** The `#!` line at the start of `text`, or `''`. */
|
|
2706
|
+
export function getShebang(text: string): string {
|
|
2707
|
+
return isShebangTrivia(text) ? text.substring(0, scanShebangTrivia(text, 0)) : '';
|
|
2708
|
+
}
|
|
2709
|
+
|
|
2710
|
+
/** Whether trivia could start at `pos`; a fast pre-check for `skipTrivia`. */
|
|
2711
|
+
export function couldStartTrivia(text: string, pos: number): boolean {
|
|
2712
|
+
const ch = text.charCodeAt(pos);
|
|
2713
|
+
switch (ch) {
|
|
2714
|
+
case CharacterCodes.carriageReturn:
|
|
2715
|
+
case CharacterCodes.lineFeed:
|
|
2716
|
+
case CharacterCodes.tab:
|
|
2717
|
+
case CharacterCodes.verticalTab:
|
|
2718
|
+
case CharacterCodes.formFeed:
|
|
2719
|
+
case CharacterCodes.space:
|
|
2720
|
+
case CharacterCodes.slash:
|
|
2721
|
+
case CharacterCodes.lessThan:
|
|
2722
|
+
case CharacterCodes.bar:
|
|
2723
|
+
case CharacterCodes.equals:
|
|
2724
|
+
case CharacterCodes.greaterThan:
|
|
2725
|
+
return true;
|
|
2726
|
+
case CharacterCodes.hash:
|
|
2727
|
+
return pos === 0;
|
|
2728
|
+
default:
|
|
2729
|
+
return ch > CharacterCodes.maxAsciiCharacter;
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
/** Returns the position after whitespace, comments, conflict markers and a leading shebang. */
|
|
2734
|
+
export function skipTrivia(
|
|
2735
|
+
text: string,
|
|
2736
|
+
pos: number,
|
|
2737
|
+
stopAfterLineBreak = false,
|
|
2738
|
+
stopAtComments = false,
|
|
2739
|
+
inJSDoc = false,
|
|
2740
|
+
): number {
|
|
2741
|
+
if (pos < 0) return pos;
|
|
2742
|
+
const length = text.length;
|
|
2743
|
+
let canConsumeStar = false;
|
|
2744
|
+
for (;;) {
|
|
2745
|
+
if (pos >= length) return pos;
|
|
2746
|
+
const ch = text.charCodeAt(pos);
|
|
2747
|
+
switch (ch) {
|
|
2748
|
+
case CharacterCodes.carriageReturn:
|
|
2749
|
+
case CharacterCodes.lineFeed:
|
|
2750
|
+
if (
|
|
2751
|
+
ch === CharacterCodes.carriageReturn &&
|
|
2752
|
+
pos + 1 < length &&
|
|
2753
|
+
text.charCodeAt(pos + 1) === CharacterCodes.lineFeed
|
|
2754
|
+
)
|
|
2755
|
+
pos++;
|
|
2756
|
+
pos++;
|
|
2757
|
+
if (stopAfterLineBreak) return pos;
|
|
2758
|
+
canConsumeStar = inJSDoc;
|
|
2759
|
+
continue;
|
|
2760
|
+
case CharacterCodes.tab:
|
|
2761
|
+
case CharacterCodes.verticalTab:
|
|
2762
|
+
case CharacterCodes.formFeed:
|
|
2763
|
+
case CharacterCodes.space:
|
|
2764
|
+
pos++;
|
|
2765
|
+
continue;
|
|
2766
|
+
case CharacterCodes.slash:
|
|
2767
|
+
if (stopAtComments || pos + 1 >= length) return pos;
|
|
2768
|
+
if (text.charCodeAt(pos + 1) === CharacterCodes.slash) {
|
|
2769
|
+
pos += 2;
|
|
2770
|
+
while (pos < length && !isLineBreak(text.charCodeAt(pos))) pos++;
|
|
2771
|
+
canConsumeStar = false;
|
|
2772
|
+
continue;
|
|
2773
|
+
}
|
|
2774
|
+
if (text.charCodeAt(pos + 1) === CharacterCodes.asterisk) {
|
|
2775
|
+
const close = text.indexOf('*/', pos + 2);
|
|
2776
|
+
pos = close < 0 ? length : close + 2;
|
|
2777
|
+
canConsumeStar = false;
|
|
2778
|
+
continue;
|
|
2779
|
+
}
|
|
2780
|
+
return pos;
|
|
2781
|
+
case CharacterCodes.lessThan:
|
|
2782
|
+
case CharacterCodes.bar:
|
|
2783
|
+
case CharacterCodes.equals:
|
|
2784
|
+
case CharacterCodes.greaterThan:
|
|
2785
|
+
if (isConflictMarkerTrivia(text, pos)) {
|
|
2786
|
+
pos = scanConflictMarkerTrivia(text, pos, undefined);
|
|
2787
|
+
canConsumeStar = false;
|
|
2788
|
+
continue;
|
|
2789
|
+
}
|
|
2790
|
+
return pos;
|
|
2791
|
+
case CharacterCodes.hash:
|
|
2792
|
+
if (pos === 0 && isShebangTrivia(text)) {
|
|
2793
|
+
pos = scanShebangTrivia(text, pos);
|
|
2794
|
+
canConsumeStar = false;
|
|
2795
|
+
continue;
|
|
2796
|
+
}
|
|
2797
|
+
return pos;
|
|
2798
|
+
case CharacterCodes.asterisk:
|
|
2799
|
+
if (canConsumeStar) {
|
|
2800
|
+
pos++;
|
|
2801
|
+
canConsumeStar = false;
|
|
2802
|
+
continue;
|
|
2803
|
+
}
|
|
2804
|
+
return pos;
|
|
2805
|
+
default:
|
|
2806
|
+
if (ch > CharacterCodes.maxAsciiCharacter && isWhiteSpaceLike(ch)) {
|
|
2807
|
+
pos++;
|
|
2808
|
+
continue;
|
|
2809
|
+
}
|
|
2810
|
+
return pos;
|
|
2811
|
+
}
|
|
2812
|
+
}
|
|
2813
|
+
}
|
|
2814
|
+
|
|
2815
|
+
/** Comments before the next token at `pos`; those on the first line are skipped unless `pos` is 0. */
|
|
2816
|
+
export function getLeadingCommentRanges(text: string, pos: number): CommentRange[] | undefined {
|
|
2817
|
+
return collectCommentRanges(text, pos, false);
|
|
2818
|
+
}
|
|
2819
|
+
|
|
2820
|
+
/** Comments after `pos` up to the next line break. */
|
|
2821
|
+
export function getTrailingCommentRanges(text: string, pos: number): CommentRange[] | undefined {
|
|
2822
|
+
return collectCommentRanges(text, pos, true);
|
|
2823
|
+
}
|
|
2824
|
+
|
|
2825
|
+
function collectCommentRanges(text: string, pos: number, trailing: boolean): CommentRange[] | undefined {
|
|
2826
|
+
let result: CommentRange[] | undefined;
|
|
2827
|
+
let pendingPos = 0;
|
|
2828
|
+
let pendingEnd = 0;
|
|
2829
|
+
let pendingKind = SyntaxKind.Unknown;
|
|
2830
|
+
let pendingHasTrailingNewLine = false;
|
|
2831
|
+
let hasPending = false;
|
|
2832
|
+
let collecting = trailing;
|
|
2833
|
+
if (pos === 0) {
|
|
2834
|
+
collecting = true;
|
|
2835
|
+
if (isShebangTrivia(text)) pos = scanShebangTrivia(text, pos);
|
|
2836
|
+
}
|
|
2837
|
+
const length = text.length;
|
|
2838
|
+
scan: while (pos >= 0 && pos < length) {
|
|
2839
|
+
const ch = text.charCodeAt(pos);
|
|
2840
|
+
switch (ch) {
|
|
2841
|
+
case CharacterCodes.carriageReturn:
|
|
2842
|
+
case CharacterCodes.lineFeed:
|
|
2843
|
+
if (
|
|
2844
|
+
ch === CharacterCodes.carriageReturn &&
|
|
2845
|
+
pos + 1 < length &&
|
|
2846
|
+
text.charCodeAt(pos + 1) === CharacterCodes.lineFeed
|
|
2847
|
+
)
|
|
2848
|
+
pos++;
|
|
2849
|
+
pos++;
|
|
2850
|
+
if (trailing) break scan;
|
|
2851
|
+
collecting = true;
|
|
2852
|
+
if (hasPending) pendingHasTrailingNewLine = true;
|
|
2853
|
+
continue;
|
|
2854
|
+
case CharacterCodes.tab:
|
|
2855
|
+
case CharacterCodes.verticalTab:
|
|
2856
|
+
case CharacterCodes.formFeed:
|
|
2857
|
+
case CharacterCodes.space:
|
|
2858
|
+
pos++;
|
|
2859
|
+
continue;
|
|
2860
|
+
case CharacterCodes.slash: {
|
|
2861
|
+
const next = pos + 1 < length ? text.charCodeAt(pos + 1) : 0;
|
|
2862
|
+
if (next !== CharacterCodes.slash && next !== CharacterCodes.asterisk) break scan;
|
|
2863
|
+
const kind =
|
|
2864
|
+
next === CharacterCodes.slash ? SyntaxKind.SingleLineCommentTrivia : SyntaxKind.MultiLineCommentTrivia;
|
|
2865
|
+
const start = pos;
|
|
2866
|
+
let hasTrailingNewLine = false;
|
|
2867
|
+
pos += 2;
|
|
2868
|
+
if (next === CharacterCodes.slash) {
|
|
2869
|
+
while (pos < length) {
|
|
2870
|
+
if (isLineBreak(text.charCodeAt(pos))) {
|
|
2871
|
+
hasTrailingNewLine = true;
|
|
2872
|
+
break;
|
|
2873
|
+
}
|
|
2874
|
+
pos++;
|
|
2875
|
+
}
|
|
2876
|
+
} else {
|
|
2877
|
+
const close = text.indexOf('*/', pos);
|
|
2878
|
+
pos = close < 0 ? length : close + 2;
|
|
2879
|
+
}
|
|
2880
|
+
if (collecting) {
|
|
2881
|
+
if (hasPending) {
|
|
2882
|
+
if (result === undefined) result = [];
|
|
2883
|
+
result.push(new CommentRange(pendingPos, pendingEnd, pendingKind, pendingHasTrailingNewLine));
|
|
2884
|
+
}
|
|
2885
|
+
pendingPos = start;
|
|
2886
|
+
pendingEnd = pos;
|
|
2887
|
+
pendingKind = kind;
|
|
2888
|
+
pendingHasTrailingNewLine = hasTrailingNewLine;
|
|
2889
|
+
hasPending = true;
|
|
2890
|
+
}
|
|
2891
|
+
continue;
|
|
2892
|
+
}
|
|
2893
|
+
default:
|
|
2894
|
+
if (ch > CharacterCodes.maxAsciiCharacter && isWhiteSpaceLike(ch)) {
|
|
2895
|
+
if (hasPending && isLineBreak(ch)) pendingHasTrailingNewLine = true;
|
|
2896
|
+
pos++;
|
|
2897
|
+
continue;
|
|
2898
|
+
}
|
|
2899
|
+
break scan;
|
|
2900
|
+
}
|
|
2901
|
+
}
|
|
2902
|
+
if (hasPending) {
|
|
2903
|
+
if (result === undefined) result = [];
|
|
2904
|
+
result.push(new CommentRange(pendingPos, pendingEnd, pendingKind, pendingHasTrailingNewLine));
|
|
2905
|
+
}
|
|
2906
|
+
return result;
|
|
2907
|
+
}
|
|
2908
|
+
|
|
2909
|
+
/** Start positions of each line, split at CR, LF, CRLF, LS and PS. */
|
|
2910
|
+
export function computeLineStarts(text: string): number[] {
|
|
2911
|
+
// Most texts break lines at LF only, which a search finds fastest.
|
|
2912
|
+
if (text.indexOf('\r') < 0 && text.indexOf('\u2028') < 0 && text.indexOf('\u2029') < 0) {
|
|
2913
|
+
const starts = [0];
|
|
2914
|
+
for (let i = text.indexOf('\n'); i >= 0; i = text.indexOf('\n', i + 1)) starts.push(i + 1);
|
|
2915
|
+
return starts;
|
|
2916
|
+
}
|
|
2917
|
+
const result: number[] = [];
|
|
2918
|
+
let lineStart = 0;
|
|
2919
|
+
let pos = 0;
|
|
2920
|
+
while (pos < text.length) {
|
|
2921
|
+
const ch = text.charCodeAt(pos);
|
|
2922
|
+
pos++;
|
|
2923
|
+
if (ch === CharacterCodes.carriageReturn) {
|
|
2924
|
+
if (pos < text.length && text.charCodeAt(pos) === CharacterCodes.lineFeed) pos++;
|
|
2925
|
+
} else if (
|
|
2926
|
+
ch !== CharacterCodes.lineFeed &&
|
|
2927
|
+
ch !== CharacterCodes.lineSeparator &&
|
|
2928
|
+
ch !== CharacterCodes.paragraphSeparator
|
|
2929
|
+
) {
|
|
2930
|
+
continue;
|
|
2931
|
+
}
|
|
2932
|
+
result.push(lineStart);
|
|
2933
|
+
lineStart = pos;
|
|
2934
|
+
}
|
|
2935
|
+
result.push(lineStart);
|
|
2936
|
+
return result;
|
|
2937
|
+
}
|
|
2938
|
+
|
|
2939
|
+
/** The zero-based line containing `pos`. */
|
|
2940
|
+
export function computeLineOfPosition(lineStarts: readonly number[], pos: number): number {
|
|
2941
|
+
let low = 0;
|
|
2942
|
+
let high = lineStarts.length - 1;
|
|
2943
|
+
while (low <= high) {
|
|
2944
|
+
const middle = low + ((high - low) >> 1);
|
|
2945
|
+
const value = lineStarts[middle]!;
|
|
2946
|
+
if (value < pos) low = middle + 1;
|
|
2947
|
+
else if (value > pos) high = middle - 1;
|
|
2948
|
+
else return middle;
|
|
2949
|
+
}
|
|
2950
|
+
return low - 1;
|
|
2951
|
+
}
|