mirror of
https://github.com/microsoft/TypeScript.git
synced 2025-11-18 17:21:48 +00:00
Merge pull request #51387 from jakebailey/typeformer-2
Closes https://github.com/microsoft/TypeScript/issues/35210 Closes https://github.com/microsoft/TypeScript/issues/39247 Closes https://github.com/microsoft/TypeScript/issues/49037 Closes https://github.com/microsoft/TypeScript/issues/49332 Closes https://github.com/microsoft/TypeScript/issues/50758
This commit is contained in:
@@ -4,4 +4,4 @@
|
||||
ARG VARIANT="14-buster"
|
||||
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:0-${VARIANT}
|
||||
|
||||
RUN sudo -u node npm install -g gulp-cli
|
||||
RUN sudo -u node npm install -g hereby
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
**/node_modules/**
|
||||
/built/local/**
|
||||
/built/**
|
||||
/tests/**
|
||||
/lib/**
|
||||
/src/lib/*.generated.d.ts
|
||||
|
||||
+1
-1
@@ -87,7 +87,7 @@
|
||||
"local/simple-indent": "error",
|
||||
"local/debug-assert": "error",
|
||||
"local/no-keywords": "error",
|
||||
"local/one-namespace-per-file": "error",
|
||||
"local/jsdoc-format": "error",
|
||||
|
||||
// eslint-plugin-import
|
||||
"import/no-extraneous-dependencies": ["error", { "optionalDependencies": false }],
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Generated module conversion step - inlineImports
|
||||
07758c08ab72481885e662c98d67a0e3a071b032
|
||||
# Generated module conversion step - stripNamespaces
|
||||
b6c053882696af8ddd94a600429f30584d303d7f
|
||||
# Generated module conversion step - explicitify
|
||||
9a0b85ce2a3f85f498ab2c05474b4c0b96b111c9
|
||||
# Generated module conversion step - unindent
|
||||
94724a8c2e68a4c7e267072ca79971f317c45e4a
|
||||
@@ -6,3 +6,29 @@ paths:
|
||||
- Gulpfile.mjs
|
||||
paths-ignore:
|
||||
- src/lib
|
||||
|
||||
# These queries appear to time out after the module conversion.
|
||||
# https://github.com/github/codeql/issues/10937
|
||||
query-filters:
|
||||
- exclude:
|
||||
id: js/path-injection # TaintedPath.ql
|
||||
- exclude:
|
||||
id: js/command-line-injection # CommandInjection.ql
|
||||
- exclude:
|
||||
id: js/code-injection # CodeInjection.ql
|
||||
- exclude:
|
||||
id: js/bad-code-sanitization # ImproperCodeSanitization.ql
|
||||
- exclude:
|
||||
id: js/unsafe-dynamic-method-access # UnsafeDynamicMethodAccess.ql
|
||||
- exclude:
|
||||
id: js/clear-text-logging # CleartextLogging.ql
|
||||
- exclude:
|
||||
id: js/regex-injection # RegExpInjection.ql
|
||||
- exclude:
|
||||
id: js/unvalidated-dynamic-method-call # UnvalidatedDynamicMethodCall.ql
|
||||
- exclude:
|
||||
id: js/insecure-download # InsecureDownload.ql
|
||||
- exclude:
|
||||
id: js/prototype-polluting-assignment # PrototypePollutingAssignment.ql
|
||||
- exclude:
|
||||
id: js/request-forgery # RequestForgery.ql
|
||||
|
||||
@@ -4,7 +4,7 @@ Thank you for submitting a pull request!
|
||||
Please verify that:
|
||||
* [ ] There is an associated issue in the `Backlog` milestone (**required**)
|
||||
* [ ] Code is up-to-date with the `main` branch
|
||||
* [ ] You've successfully run `gulp runtests` locally
|
||||
* [ ] You've successfully run `hereby runtests` locally
|
||||
* [ ] There are new or updated unit tests validating the change
|
||||
|
||||
Refer to CONTRIBUTING.MD for more details.
|
||||
|
||||
@@ -17,8 +17,8 @@ jobs:
|
||||
git config user.name "TypeScript Bot"
|
||||
npm install
|
||||
git rm -r --quiet tests/baselines/reference :^tests/baselines/reference/docker :^tests/baselines/reference/user
|
||||
gulp runtests-parallel --ci --fix || true
|
||||
gulp baseline-accept
|
||||
npx hereby runtests-parallel --ci --fix || true
|
||||
npx hereby baseline-accept
|
||||
git add ./src
|
||||
git add ./tests/baselines/reference
|
||||
git diff --cached
|
||||
|
||||
@@ -21,6 +21,13 @@ jobs:
|
||||
- "*"
|
||||
- lts/*
|
||||
- lts/-1
|
||||
bundle:
|
||||
- "true"
|
||||
include:
|
||||
- node-version: "*"
|
||||
bundle: "false"
|
||||
|
||||
name: Test Node ${{ matrix.node-version }} with --bundle=${{ matrix.bundle }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -32,7 +39,7 @@ jobs:
|
||||
- run: npm ci
|
||||
|
||||
- name: Tests
|
||||
run: npm test
|
||||
run: npm run test -- --bundle=${{ matrix.bundle }}
|
||||
|
||||
lint:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -62,11 +69,23 @@ jobs:
|
||||
- name: Adding playwright
|
||||
run: npm install --no-save --no-package-lock playwright
|
||||
|
||||
- name: Build local
|
||||
run: gulp local
|
||||
|
||||
- name: Validate the browser can import TypeScript
|
||||
run: gulp test-browser-integration
|
||||
run: npx hereby test-browser-integration
|
||||
|
||||
typecheck:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "*"
|
||||
check-latest: true
|
||||
- run: npm ci
|
||||
|
||||
- name: Build src
|
||||
run: npx hereby build-src
|
||||
|
||||
|
||||
misc:
|
||||
runs-on: ubuntu-latest
|
||||
@@ -80,7 +99,27 @@ jobs:
|
||||
- run: npm ci
|
||||
|
||||
- name: Build scripts
|
||||
run: gulp scripts
|
||||
run: npx hereby scripts
|
||||
|
||||
- name: ESLint tests
|
||||
run: gulp run-eslint-rules-tests
|
||||
run: npx hereby run-eslint-rules-tests
|
||||
|
||||
self-check:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "*"
|
||||
check-latest: true
|
||||
- run: npm ci
|
||||
|
||||
- name: Build tsc
|
||||
run: npx hereby tsc
|
||||
|
||||
- name: Clean
|
||||
run: npx hereby clean-src
|
||||
|
||||
- name: Self build
|
||||
run: npx hereby build-src --built
|
||||
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ github.event.client_payload.core_major_minor }}"/g' tests/baselines/reference/api/tsserverlibrary.d.ts
|
||||
sed -i -e 's/const version\(: string\)\{0,1\} = `${versionMajorMinor}.0-.*`/const version = `${versionMajorMinor}.0-${{ github.event.client_payload.core_tag || 'dev' }}`/g' src/compiler/corePublic.ts
|
||||
npm ci
|
||||
gulp LKG
|
||||
npx hereby LKG
|
||||
npm test
|
||||
git diff
|
||||
git add package.json
|
||||
|
||||
@@ -23,10 +23,10 @@ jobs:
|
||||
run: |
|
||||
npm whoami
|
||||
npm ci
|
||||
gulp configure-nightly
|
||||
gulp LKG
|
||||
gulp runtests-parallel
|
||||
gulp clean
|
||||
npx hereby configure-nightly
|
||||
npx hereby LKG
|
||||
npx hereby runtests-parallel
|
||||
npx hereby clean
|
||||
npm publish --tag next
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
|
||||
|
||||
@@ -19,11 +19,11 @@ jobs:
|
||||
- name: Adding playwright
|
||||
run: npm install --no-save --no-package-lock playwright
|
||||
- name: Validate the browser can import TypeScript
|
||||
run: gulp test-browser-integration
|
||||
run: npx hereby test-browser-integration
|
||||
- name: LKG, clean, and pack
|
||||
run: |
|
||||
gulp LKG
|
||||
gulp clean
|
||||
npx hereby LKG
|
||||
npx hereby clean
|
||||
npm pack ./
|
||||
mv typescript-*.tgz typescript.tgz
|
||||
- name: Upload built tarfile
|
||||
|
||||
@@ -27,7 +27,7 @@ jobs:
|
||||
sed -i -e 's/const versionMajorMinor = ".*"/const versionMajorMinor = "${{ github.event.client_payload.core_major_minor }}"/g' tests/baselines/reference/api/tsserverlibrary.d.ts
|
||||
sed -i -e 's/const version\(: string\)\{0,1\} = .*;/const version = "${{ github.event.client_payload.package_version }}" as string;/g' src/compiler/corePublic.ts
|
||||
npm ci
|
||||
gulp LKG
|
||||
npx hereby LKG
|
||||
npm test
|
||||
git diff
|
||||
git add package.json
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
git config user.email "typescriptbot@microsoft.com"
|
||||
git config user.name "TypeScript Bot"
|
||||
npm ci
|
||||
gulp LKG
|
||||
npx hereby LKG
|
||||
npm test
|
||||
git diff
|
||||
git add ./lib
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
const cp = require("child_process");
|
||||
const path = require("path");
|
||||
const chalk = require("chalk");
|
||||
|
||||
const argv = process.argv.slice(2);
|
||||
|
||||
// --tasks-simple is used by VS Code to infer a task list; try and keep that working.
|
||||
if (!argv.includes("--tasks-simple")) {
|
||||
console.error(chalk.yellowBright("Warning: using gulp shim; please consider running hereby directly."));
|
||||
}
|
||||
|
||||
const args = [
|
||||
...process.execArgv,
|
||||
path.join(__dirname, "node_modules", "hereby", "bin", "hereby.js"),
|
||||
...argv,
|
||||
];
|
||||
|
||||
const { status } = cp.spawnSync(process.execPath, args, { stdio: "inherit" });
|
||||
process.exit(status ?? 1);
|
||||
Vendored
+3
-7
@@ -20,7 +20,6 @@
|
||||
"configurations": [
|
||||
{
|
||||
"type": "node",
|
||||
"protocol": "inspector",
|
||||
"request": "launch",
|
||||
"name": "Mocha Tests (currently opened test)",
|
||||
"runtimeArgs": ["--nolazy"],
|
||||
@@ -43,12 +42,9 @@
|
||||
},
|
||||
"sourceMaps": true,
|
||||
"smartStep": true,
|
||||
"preLaunchTask": "gulp: tests",
|
||||
"preLaunchTask": "npm: build:tests",
|
||||
"console": "integratedTerminal",
|
||||
"outFiles": [
|
||||
"${workspaceRoot}/built/local/run.js"
|
||||
],
|
||||
"customDescriptionGenerator": "'__tsDebuggerDisplay' in this ? this.__tsDebuggerDisplay(defaultValue) : defaultValue",
|
||||
"customDescriptionGenerator": "'__tsDebuggerDisplay' in this ? this.__tsDebuggerDisplay(defaultValue) : defaultValue"
|
||||
},
|
||||
{
|
||||
// See: https://github.com/microsoft/TypeScript/wiki/Debugging-Language-Service-in-VS-Code
|
||||
@@ -56,7 +52,7 @@
|
||||
"request": "attach",
|
||||
"name": "Attach to VS Code TS Server via Port",
|
||||
"processId": "${command:PickProcess}",
|
||||
"customDescriptionGenerator": "'__tsDebuggerDisplay' in this ? this.__tsDebuggerDisplay(defaultValue) : defaultValue",
|
||||
"customDescriptionGenerator": "'__tsDebuggerDisplay' in this ? this.__tsDebuggerDisplay(defaultValue) : defaultValue"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Vendored
+14
@@ -6,4 +6,18 @@
|
||||
|
||||
// To use the locally built compiler, after 'npm run build':
|
||||
// "typescript.tsdk": "built/local"
|
||||
|
||||
// To ignore commits listed in .git-blame-ignore-revs in GitLens:
|
||||
// "gitlens.advanced.blame.customArguments": [
|
||||
// "--ignore-revs-file",
|
||||
// ".git-blame-ignore-revs"
|
||||
// ]
|
||||
|
||||
// These options search the repo recursively and slow down
|
||||
// the build task menu. We define our own in tasks.json.
|
||||
"typescript.tsc.autoDetect": "off",
|
||||
"npm.autoDetect": "off",
|
||||
"grunt.autoDetect": "off",
|
||||
"jake.autoDetect": "off",
|
||||
"gulp.autoDetect": "off"
|
||||
}
|
||||
|
||||
Vendored
+38
-29
@@ -4,42 +4,51 @@
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"type": "gulp",
|
||||
"label": "gulp: local",
|
||||
"task": "local",
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "gulp",
|
||||
"label": "gulp: tsc",
|
||||
"task": "tsc",
|
||||
"group": "build",
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "gulp",
|
||||
// Kept for backwards compat for old launch.json files so it's
|
||||
// less annoying if moving up to the new build or going back to
|
||||
// the old build.
|
||||
//
|
||||
// This is first because the acutal "npm: build:tests" task
|
||||
// below has the same script value, and VS Code ignores labels
|
||||
// and deduplicates them.
|
||||
// https://github.com/microsoft/vscode/issues/93001
|
||||
"label": "gulp: tests",
|
||||
"task": "tests",
|
||||
"type": "npm",
|
||||
"script": "build:tests",
|
||||
"group": "build",
|
||||
"hide": true,
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "tsc: watch ./src",
|
||||
"type": "shell",
|
||||
"command": "node",
|
||||
"args": ["${workspaceFolder}/lib/tsc.js", "--build", "${workspaceFolder}/src", "--watch"],
|
||||
"group": "build",
|
||||
"isBackground": true,
|
||||
"problemMatcher": [
|
||||
"$tsc-watch"
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "npm: build:compiler",
|
||||
"type": "npm",
|
||||
"script": "build:compiler",
|
||||
"group": "build",
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
]
|
||||
},
|
||||
{
|
||||
"type": "gulp",
|
||||
"task": "services",
|
||||
"label": "gulp: services",
|
||||
"label": "npm: build:tests",
|
||||
"type": "npm",
|
||||
"script": "build:tests",
|
||||
"group": "build",
|
||||
"problemMatcher": [
|
||||
"$tsc"
|
||||
],
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+33
-33
@@ -54,42 +54,42 @@ In general, things we find useful when reviewing suggestions are:
|
||||
2. A copy of the TypeScript code. See the next steps for instructions.
|
||||
3. [Node](https://nodejs.org), which runs JavaScript locally. Current or LTS will both work.
|
||||
4. An editor. [VS Code](https://code.visualstudio.com) is the best place to start for TypeScript.
|
||||
5. The gulp command line tool, for building and testing changes. See the next steps for how to install it.
|
||||
5. The hereby command line tool, for building and testing changes. See the next steps for how to install it.
|
||||
|
||||
## Get Started
|
||||
|
||||
1. Install node using the version you downloaded from [nodejs.org](https://nodejs.org).
|
||||
2. Open a terminal.
|
||||
3. Make a fork—your own copy—of TypeScript on your GitHub account, then make a clone—a local copy—on your computer. ([Here are some step-by-step instructions](https://github.com/anitab-org/mentorship-android/wiki/Fork%2C-Clone-%26-Remote)). Add `--depth=1` to the end of the `git clone` command to save time.
|
||||
4. Install the gulp command line tool: `npm install -g gulp-cli`
|
||||
4. Install the hereby command line tool: `npm install -g hereby`
|
||||
5. Change to the TypeScript folder you made: `cd TypeScript`
|
||||
6. Install dependencies: `npm ci`
|
||||
7. Make sure everything builds and tests pass: `gulp runtests-parallel`
|
||||
7. Make sure everything builds and tests pass: `hereby runtests-parallel`
|
||||
8. Open the TypeScript folder in your editor.
|
||||
9. Follow the directions below to add and debug a test.
|
||||
|
||||
## Helpful tasks
|
||||
|
||||
Running `gulp --tasks --depth 1` provides the full listing, but here are a few common tasks you might use.
|
||||
Running `hereby --tasks` provides the full listing, but here are a few common tasks you might use.
|
||||
|
||||
```
|
||||
gulp local # Build the compiler into built/local.
|
||||
gulp clean # Delete the built compiler.
|
||||
gulp LKG # Replace the last known good with the built one.
|
||||
# Bootstrapping step to be executed when the built compiler reaches a stable state.
|
||||
gulp tests # Build the test infrastructure using the built compiler.
|
||||
gulp runtests # Run tests using the built compiler and test infrastructure.
|
||||
# You can override the specific suite runner used or specify a test for this command.
|
||||
# Use --tests=<testPath> for a specific test and/or --runner=<runnerName> for a specific suite.
|
||||
# Valid runners include conformance, compiler, fourslash, project, user, and docker
|
||||
# The user and docker runners are extended test suite runners - the user runner
|
||||
# works on disk in the tests/cases/user directory, while the docker runner works in containers.
|
||||
# You'll need to have the docker executable in your system path for the docker runner to work.
|
||||
gulp runtests-parallel # Like runtests, but split across multiple threads. Uses a number of threads equal to the system
|
||||
# core count by default. Use --workers=<number> to adjust this.
|
||||
gulp baseline-accept # This replaces the baseline test results with the results obtained from gulp runtests.
|
||||
gulp lint # Runs eslint on the TypeScript source.
|
||||
gulp help # List the above commands.
|
||||
hereby local # Build the compiler into built/local.
|
||||
hereby clean # Delete the built compiler.
|
||||
hereby LKG # Replace the last known good with the built one.
|
||||
# Bootstrapping step to be executed when the built compiler reaches a stable state.
|
||||
hereby tests # Build the test infrastructure using the built compiler.
|
||||
hereby runtests # Run tests using the built compiler and test infrastructure.
|
||||
# You can override the specific suite runner used or specify a test for this command.
|
||||
# Use --tests=<testPath> for a specific test and/or --runner=<runnerName> for a specific suite.
|
||||
# Valid runners include conformance, compiler, fourslash, project, user, and docker
|
||||
# The user and docker runners are extended test suite runners - the user runner
|
||||
# works on disk in the tests/cases/user directory, while the docker runner works in containers.
|
||||
# You'll need to have the docker executable in your system path for the docker runner to work.
|
||||
hereby runtests-parallel # Like runtests, but split across multiple threads. Uses a number of threads equal to the system
|
||||
# core count by default. Use --workers=<number> to adjust this.
|
||||
hereby baseline-accept # This replaces the baseline test results with the results obtained from hereby runtests.
|
||||
hereby lint # Runs eslint on the TypeScript source.
|
||||
hereby help # List the above commands.
|
||||
```
|
||||
|
||||
## Tips
|
||||
@@ -111,7 +111,7 @@ You might need to run `git config --global core.longpaths true` before cloning T
|
||||
|
||||
### Using local builds
|
||||
|
||||
Run `gulp` to build a version of the compiler/language service that reflects changes you've made. You can then run `node <repo-root>/built/local/tsc.js` in place of `tsc` in your project. For example, to run `tsc --watch` from within the root of the repository on a file called `test.ts`, you can run `node ./built/local/tsc.js --watch test.ts`.
|
||||
Run `hereby` to build a version of the compiler/language service that reflects changes you've made. You can then run `node <repo-root>/built/local/tsc.js` in place of `tsc` in your project. For example, to run `tsc --watch` from within the root of the repository on a file called `test.ts`, you can run `node ./built/local/tsc.js --watch test.ts`.
|
||||
|
||||
## Contributing bug fixes
|
||||
|
||||
@@ -163,7 +163,7 @@ Any changes should be made to [src/lib](https://github.com/Microsoft/TypeScript/
|
||||
Library files in `built/local/` are updated automatically by running the standard build task:
|
||||
|
||||
```sh
|
||||
gulp
|
||||
hereby
|
||||
```
|
||||
|
||||
The files in `lib/` are used to bootstrap compilation and usually **should not** be updated unless publishing a new version or updating the LKG.
|
||||
@@ -178,36 +178,36 @@ If you need a head start understanding how the compiler works, or how the code i
|
||||
|
||||
## Running the Tests
|
||||
|
||||
To run all tests, invoke the `runtests-parallel` target using gulp:
|
||||
To run all tests, invoke the `runtests-parallel` target using hereby:
|
||||
|
||||
```Shell
|
||||
gulp runtests-parallel
|
||||
hereby runtests-parallel
|
||||
```
|
||||
|
||||
This will run all tests; to run only a specific subset of tests, use:
|
||||
|
||||
```Shell
|
||||
gulp runtests --tests=<regex>
|
||||
hereby runtests --tests=<regex>
|
||||
```
|
||||
|
||||
e.g. to run all compiler baseline tests:
|
||||
|
||||
```Shell
|
||||
gulp runtests --tests=compiler
|
||||
hereby runtests --tests=compiler
|
||||
```
|
||||
|
||||
or to run a specific test: `tests\cases\compiler\2dArrays.ts`
|
||||
|
||||
```Shell
|
||||
gulp runtests --tests=2dArrays
|
||||
hereby runtests --tests=2dArrays
|
||||
```
|
||||
|
||||
## Debugging the tests
|
||||
|
||||
You can debug with VS Code or Node instead with `gulp runtests -i`:
|
||||
You can debug with VS Code or Node instead with `hereby runtests -i`:
|
||||
|
||||
```Shell
|
||||
gulp runtests --tests=2dArrays -i
|
||||
hereby runtests --tests=2dArrays -i
|
||||
```
|
||||
|
||||
You can also use the [provided VS Code launch configuration](./.vscode/launch.template.json) to launch a debug session for an open test file. Rename the file 'launch.json', open the test file of interest, and launch the debugger from the debug panel (or press F5).
|
||||
@@ -257,12 +257,12 @@ When a change in the baselines is detected, the test will fail. To inspect chang
|
||||
git diff --diff-filter=AM --no-index ./tests/baselines/reference ./tests/baselines/local
|
||||
```
|
||||
|
||||
Alternatively, you can set the `DIFF` environment variable and run `gulp diff`, or manually run your favorite folder diffing tool between `tests/baselines/reference` and `tests/baselines/local`. Our team largely uses Beyond Compare and WinMerge.
|
||||
Alternatively, you can set the `DIFF` environment variable and run `hereby diff`, or manually run your favorite folder diffing tool between `tests/baselines/reference` and `tests/baselines/local`. Our team largely uses Beyond Compare and WinMerge.
|
||||
|
||||
After verifying that the changes in the baselines are correct, run
|
||||
|
||||
```Shell
|
||||
gulp baseline-accept
|
||||
hereby baseline-accept
|
||||
```
|
||||
|
||||
This will change the files in `tests\baselines\reference`, which should be included as part of your commit.
|
||||
@@ -271,6 +271,6 @@ Be sure to validate the changes carefully -- apparently unrelated changes to bas
|
||||
## Localization
|
||||
|
||||
All strings the user may see are stored in [`diagnosticMessages.json`](./src/compiler/diagnosticMessages.json).
|
||||
If you make changes to it, run `gulp generate-diagnostics` to push them to the `Diagnostic` interface in `diagnosticInformationMap.generated.ts`.
|
||||
If you make changes to it, run `hereby generate-diagnostics` to push them to the `Diagnostic` interface in `diagnosticInformationMap.generated.ts`.
|
||||
|
||||
See [coding guidelines on diagnostic messages](https://github.com/Microsoft/TypeScript/wiki/Coding-guidelines#diagnostic-messages).
|
||||
|
||||
+1
-2
@@ -3,5 +3,4 @@ FROM node:current
|
||||
COPY . /typescript
|
||||
WORKDIR /typescript
|
||||
RUN npm ci
|
||||
RUN npm i -g gulp-cli
|
||||
RUN gulp configure-insiders && gulp LKG && gulp clean && npm pack .
|
||||
RUN npx hereby configure-insiders && npx hereby LKG && npx hereby clean && npm pack .
|
||||
|
||||
-588
@@ -1,588 +0,0 @@
|
||||
// @ts-check
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import log from "fancy-log";
|
||||
import newer from "gulp-newer";
|
||||
import sourcemaps from "gulp-sourcemaps";
|
||||
import del from "del";
|
||||
import rename from "gulp-rename";
|
||||
import concat from "gulp-concat";
|
||||
import merge2 from "merge2";
|
||||
import gulp from "gulp";
|
||||
import { append, transform } from "gulp-insert";
|
||||
import { prependFile } from "./scripts/build/prepend.mjs";
|
||||
import { exec, readJson, needsUpdate, getDiffTool, getDirSize, rm } from "./scripts/build/utils.mjs";
|
||||
import { runConsoleTests, refBaseline, localBaseline, refRwcBaseline, localRwcBaseline } from "./scripts/build/tests.mjs";
|
||||
import { buildProject, cleanProject, watchProject } from "./scripts/build/projects.mjs";
|
||||
import cmdLineOptions from "./scripts/build/options.mjs";
|
||||
|
||||
const { src, dest, task, parallel, series, watch } = gulp;
|
||||
|
||||
const copyright = "CopyrightNotice.txt";
|
||||
const cleanTasks = [];
|
||||
|
||||
const buildScripts = () => buildProject("scripts");
|
||||
task("scripts", buildScripts);
|
||||
task("scripts").description = "Builds files in the 'scripts' folder.";
|
||||
|
||||
/** @type {{ libs: string[]; paths: Record<string, string | undefined>; }} */
|
||||
const libraries = readJson("./src/lib/libs.json");
|
||||
const libs = libraries.libs.map(lib => {
|
||||
const relativeSources = ["header.d.ts", lib + ".d.ts"];
|
||||
const relativeTarget = libraries.paths && libraries.paths[lib] || ("lib." + lib + ".d.ts");
|
||||
const sources = relativeSources.map(s => path.posix.join("src/lib", s));
|
||||
const target = `built/local/${relativeTarget}`;
|
||||
return { target, relativeTarget, sources };
|
||||
});
|
||||
|
||||
const generateLibs = () => {
|
||||
return merge2(libs.map(({ sources, target, relativeTarget }) =>
|
||||
src([copyright, ...sources])
|
||||
.pipe(newer(target))
|
||||
.pipe(concat(relativeTarget, { newLine: "\n\n" }))
|
||||
.pipe(dest("built/local"))));
|
||||
};
|
||||
task("lib", generateLibs);
|
||||
task("lib").description = "Builds the library targets";
|
||||
|
||||
const cleanLib = () => del(libs.map(lib => lib.target));
|
||||
cleanTasks.push(cleanLib);
|
||||
|
||||
const watchLib = () => watch(["src/lib/**/*"], generateLibs);
|
||||
|
||||
const diagnosticInformationMapTs = "src/compiler/diagnosticInformationMap.generated.ts";
|
||||
const diagnosticMessagesJson = "src/compiler/diagnosticMessages.json";
|
||||
const diagnosticMessagesGeneratedJson = "src/compiler/diagnosticMessages.generated.json";
|
||||
const generateDiagnostics = async () => {
|
||||
if (needsUpdate(diagnosticMessagesJson, [diagnosticMessagesGeneratedJson, diagnosticInformationMapTs])) {
|
||||
await exec(process.execPath, ["scripts/processDiagnosticMessages.mjs", diagnosticMessagesJson]);
|
||||
}
|
||||
};
|
||||
task("generate-diagnostics", generateDiagnostics);
|
||||
task("generate-diagnostics").description = "Generates a diagnostic file in TypeScript based on an input JSON file";
|
||||
|
||||
const cleanDiagnostics = () => del([diagnosticInformationMapTs, diagnosticMessagesGeneratedJson]);
|
||||
cleanTasks.push(cleanDiagnostics);
|
||||
|
||||
const watchDiagnostics = () => watch(["src/compiler/diagnosticMessages.json"], task("generate-diagnostics"));
|
||||
|
||||
// Localize diagnostics
|
||||
/**
|
||||
* .lcg file is what localization team uses to know what messages to localize.
|
||||
* The file is always generated in 'enu/diagnosticMessages.generated.json.lcg'
|
||||
*/
|
||||
const generatedLCGFile = "built/local/enu/diagnosticMessages.generated.json.lcg";
|
||||
|
||||
/**
|
||||
* The localization target produces the two following transformations:
|
||||
* 1. 'src\loc\lcl\<locale>\diagnosticMessages.generated.json.lcl' => 'built\local\<locale>\diagnosticMessages.generated.json'
|
||||
* convert localized resources into a .json file the compiler can understand
|
||||
* 2. 'src\compiler\diagnosticMessages.generated.json' => 'built\local\ENU\diagnosticMessages.generated.json.lcg'
|
||||
* generate the lcg file (source of messages to localize) from the diagnosticMessages.generated.json
|
||||
*/
|
||||
const localizationTargets = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-br", "ru", "tr", "zh-cn", "zh-tw"]
|
||||
.map(f => f.toLowerCase())
|
||||
.map(f => `built/local/${f}/diagnosticMessages.generated.json`)
|
||||
.concat(generatedLCGFile);
|
||||
|
||||
const localize = async () => {
|
||||
if (needsUpdate(diagnosticMessagesGeneratedJson, generatedLCGFile)) {
|
||||
return exec(process.execPath, ["scripts/generateLocalizedDiagnosticMessages.mjs", "src/loc/lcl", "built/local", diagnosticMessagesGeneratedJson], { ignoreExitCode: true });
|
||||
}
|
||||
};
|
||||
|
||||
const buildDebugTools = () => buildProject("src/debug");
|
||||
const cleanDebugTools = () => cleanProject("src/debug");
|
||||
cleanTasks.push(cleanDebugTools);
|
||||
|
||||
// Pre-build steps when targeting the LKG compiler
|
||||
const lkgPreBuild = parallel(generateLibs, series(generateDiagnostics, buildDebugTools));
|
||||
|
||||
const buildTsc = () => buildProject("src/tsc");
|
||||
task("tsc", series(lkgPreBuild, buildTsc));
|
||||
task("tsc").description = "Builds the command-line compiler";
|
||||
|
||||
const cleanTsc = () => cleanProject("src/tsc");
|
||||
cleanTasks.push(cleanTsc);
|
||||
task("clean-tsc", cleanTsc);
|
||||
task("clean-tsc").description = "Cleans outputs for the command-line compiler";
|
||||
|
||||
const watchTsc = () => watchProject("src/tsc");
|
||||
task("watch-tsc", series(lkgPreBuild, parallel(watchLib, watchDiagnostics, watchTsc)));
|
||||
task("watch-tsc").description = "Watch for changes and rebuild the command-line compiler only.";
|
||||
|
||||
// Pre-build steps when targeting the built/local compiler.
|
||||
const localPreBuild = parallel(generateLibs, series(generateDiagnostics, buildDebugTools, buildTsc));
|
||||
|
||||
// Pre-build steps to use based on supplied options.
|
||||
const preBuild = cmdLineOptions.lkg ? lkgPreBuild : localPreBuild;
|
||||
|
||||
const buildServices = (() => {
|
||||
// build typescriptServices.out.js
|
||||
const buildTypescriptServicesOut = () => buildProject("src/typescriptServices/tsconfig.json", cmdLineOptions);
|
||||
|
||||
// create typescriptServices.js
|
||||
const createTypescriptServicesJs = () => src("built/local/typescriptServices.out.js")
|
||||
.pipe(newer("built/local/typescriptServices.js"))
|
||||
.pipe(sourcemaps.init({ loadMaps: true }))
|
||||
.pipe(prependFile(copyright))
|
||||
.pipe(rename("typescriptServices.js"))
|
||||
.pipe(sourcemaps.write(".", { includeContent: false, destPath: "built/local" }))
|
||||
.pipe(dest("built/local"));
|
||||
|
||||
// create typescriptServices.d.ts
|
||||
const createTypescriptServicesDts = () => src("built/local/typescriptServices.out.d.ts")
|
||||
.pipe(newer("built/local/typescriptServices.d.ts"))
|
||||
.pipe(prependFile(copyright))
|
||||
.pipe(transform(content => content.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, "$1$2enum $3 {$4")))
|
||||
.pipe(rename("typescriptServices.d.ts"))
|
||||
.pipe(dest("built/local"));
|
||||
|
||||
// create typescript.js
|
||||
const createTypescriptJs = () => src("built/local/typescriptServices.js")
|
||||
.pipe(newer("built/local/typescript.js"))
|
||||
.pipe(sourcemaps.init({ loadMaps: true }))
|
||||
.pipe(rename("typescript.js"))
|
||||
.pipe(sourcemaps.write(".", { includeContent: false, destPath: "built/local" }))
|
||||
.pipe(dest("built/local"));
|
||||
|
||||
// create typescript.d.ts
|
||||
const createTypescriptDts = () => src("built/local/typescriptServices.d.ts")
|
||||
.pipe(newer("built/local/typescript.d.ts"))
|
||||
.pipe(append("\nexport = ts;"))
|
||||
.pipe(rename("typescript.d.ts"))
|
||||
.pipe(dest("built/local"));
|
||||
|
||||
// create typescript_standalone.d.ts
|
||||
const createTypescriptStandaloneDts = () => src("built/local/typescriptServices.d.ts")
|
||||
.pipe(newer("built/local/typescript_standalone.d.ts"))
|
||||
.pipe(transform(content => content.replace(/declare (namespace|module) ts/g, 'declare module "typescript"')))
|
||||
.pipe(rename("typescript_standalone.d.ts"))
|
||||
.pipe(dest("built/local"));
|
||||
|
||||
return series(
|
||||
buildTypescriptServicesOut,
|
||||
createTypescriptServicesJs,
|
||||
createTypescriptServicesDts,
|
||||
createTypescriptJs,
|
||||
createTypescriptDts,
|
||||
createTypescriptStandaloneDts,
|
||||
);
|
||||
})();
|
||||
task("services", series(preBuild, buildServices));
|
||||
task("services").description = "Builds the language service";
|
||||
task("services").flags = {
|
||||
" --built": "Compile using the built version of the compiler."
|
||||
};
|
||||
|
||||
const cleanServices = async () => {
|
||||
if (fs.existsSync("built/local/typescriptServices.tsconfig.json")) {
|
||||
await cleanProject("built/local/typescriptServices.tsconfig.json");
|
||||
}
|
||||
await del([
|
||||
"built/local/typescriptServices.out.js",
|
||||
"built/local/typescriptServices.out.d.ts",
|
||||
"built/local/typescriptServices.out.tsbuildinfo",
|
||||
"built/local/typescriptServices.js",
|
||||
"built/local/typescript.js",
|
||||
"built/local/typescript.d.ts",
|
||||
"built/local/typescript_standalone.d.ts"
|
||||
]);
|
||||
};
|
||||
cleanTasks.push(cleanServices);
|
||||
task("clean-services", cleanServices);
|
||||
task("clean-services").description = "Cleans outputs for the language service";
|
||||
|
||||
const watchServices = () => watch([
|
||||
"src/compiler/tsconfig.json",
|
||||
"src/compiler/**/*.ts",
|
||||
"src/jsTyping/tsconfig.json",
|
||||
"src/jsTyping/**/*.ts",
|
||||
"src/services/tsconfig.json",
|
||||
"src/services/**/*.ts",
|
||||
], series(preBuild, buildServices));
|
||||
task("watch-services", series(preBuild, parallel(watchLib, watchDiagnostics, watchServices)));
|
||||
task("watch-services").description = "Watches for changes and rebuild language service only";
|
||||
task("watch-services").flags = {
|
||||
" --built": "Compile using the built version of the compiler."
|
||||
};
|
||||
|
||||
const buildDynamicImportCompat = () => buildProject("src/dynamicImportCompat", cmdLineOptions);
|
||||
task("dynamicImportCompat", buildDynamicImportCompat);
|
||||
|
||||
const buildServerMain = () => buildProject("src/tsserver", cmdLineOptions);
|
||||
const buildServer = series(buildDynamicImportCompat, buildServerMain);
|
||||
buildServer.displayName = "buildServer";
|
||||
task("tsserver", series(preBuild, buildServer));
|
||||
task("tsserver").description = "Builds the language server";
|
||||
task("tsserver").flags = {
|
||||
" --built": "Compile using the built version of the compiler."
|
||||
};
|
||||
|
||||
const cleanDynamicImportCompat = () => cleanProject("src/dynamicImportCompat");
|
||||
const cleanServerMain = () => cleanProject("src/tsserver");
|
||||
const cleanServer = series(cleanDynamicImportCompat, cleanServerMain);
|
||||
cleanServer.displayName = "cleanServer";
|
||||
cleanTasks.push(cleanServer);
|
||||
task("clean-tsserver", cleanServer);
|
||||
task("clean-tsserver").description = "Cleans outputs for the language server";
|
||||
|
||||
const watchDynamicImportCompat = () => watchProject("src/dynamicImportCompat", cmdLineOptions);
|
||||
const watchServer = () => watchProject("src/tsserver", cmdLineOptions);
|
||||
task("watch-tsserver", series(preBuild, parallel(watchLib, watchDiagnostics, watchDynamicImportCompat, watchServer)));
|
||||
task("watch-tsserver").description = "Watch for changes and rebuild the language server only";
|
||||
task("watch-tsserver").flags = {
|
||||
" --built": "Compile using the built version of the compiler."
|
||||
};
|
||||
|
||||
task("min", series(preBuild, parallel(buildTsc, buildServer)));
|
||||
task("min").description = "Builds only tsc and tsserver";
|
||||
task("min").flags = {
|
||||
" --built": "Compile using the built version of the compiler."
|
||||
};
|
||||
|
||||
task("clean-min", series(cleanTsc, cleanServer));
|
||||
task("clean-min").description = "Cleans outputs for tsc and tsserver";
|
||||
|
||||
task("watch-min", series(preBuild, parallel(watchLib, watchDiagnostics, watchTsc, watchServer)));
|
||||
task("watch-min").description = "Watches for changes to a tsc and tsserver only";
|
||||
task("watch-min").flags = {
|
||||
" --built": "Compile using the built version of the compiler."
|
||||
};
|
||||
|
||||
const buildLssl = (() => {
|
||||
// build tsserverlibrary.out.js
|
||||
const buildServerLibraryOut = () => buildProject("src/tsserverlibrary/tsconfig.json", cmdLineOptions);
|
||||
|
||||
// create tsserverlibrary.js
|
||||
const createServerLibraryJs = () => src("built/local/tsserverlibrary.out.js")
|
||||
.pipe(newer("built/local/tsserverlibrary.js"))
|
||||
.pipe(sourcemaps.init({ loadMaps: true }))
|
||||
.pipe(prependFile(copyright))
|
||||
.pipe(rename("tsserverlibrary.js"))
|
||||
.pipe(sourcemaps.write(".", { includeContent: false, destPath: "built/local" }))
|
||||
.pipe(dest("built/local"));
|
||||
|
||||
// create tsserverlibrary.d.ts
|
||||
const createServerLibraryDts = () => src("built/local/tsserverlibrary.out.d.ts")
|
||||
.pipe(newer("built/local/tsserverlibrary.d.ts"))
|
||||
.pipe(prependFile(copyright))
|
||||
.pipe(transform(content => content.replace(/^(\s*)(export )?const enum (\S+) {(\s*)$/gm, "$1$2enum $3 {$4")))
|
||||
.pipe(append("\nexport = ts;\nexport as namespace ts;"))
|
||||
.pipe(rename("tsserverlibrary.d.ts"))
|
||||
.pipe(dest("built/local"));
|
||||
|
||||
return series(
|
||||
buildServerLibraryOut,
|
||||
createServerLibraryJs,
|
||||
createServerLibraryDts,
|
||||
);
|
||||
})();
|
||||
task("lssl", series(preBuild, buildLssl));
|
||||
task("lssl").description = "Builds language service server library";
|
||||
task("lssl").flags = {
|
||||
" --built": "Compile using the built version of the compiler."
|
||||
};
|
||||
|
||||
const cleanLssl = async () => {
|
||||
if (fs.existsSync("built/local/tsserverlibrary.tsconfig.json")) {
|
||||
await cleanProject("built/local/tsserverlibrary.tsconfig.json");
|
||||
}
|
||||
await del([
|
||||
"built/local/tsserverlibrary.out.js",
|
||||
"built/local/tsserverlibrary.out.d.ts",
|
||||
"built/local/tsserverlibrary.out.tsbuildinfo",
|
||||
"built/local/tsserverlibrary.js",
|
||||
"built/local/tsserverlibrary.d.ts",
|
||||
]);
|
||||
};
|
||||
cleanTasks.push(cleanLssl);
|
||||
task("clean-lssl", cleanLssl);
|
||||
task("clean-lssl").description = "Clean outputs for the language service server library";
|
||||
|
||||
const watchLssl = () => watch([
|
||||
"src/compiler/tsconfig.json",
|
||||
"src/compiler/**/*.ts",
|
||||
"src/jsTyping/tsconfig.json",
|
||||
"src/jsTyping/**/*.ts",
|
||||
"src/services/tsconfig.json",
|
||||
"src/services/**/*.ts",
|
||||
"src/server/tsconfig.json",
|
||||
"src/server/**/*.ts",
|
||||
"src/webServer/tsconfig.json",
|
||||
"src/webServer/**/*.ts",
|
||||
"src/tsserver/tsconfig.json",
|
||||
"src/tsserver/**/*.ts",
|
||||
], buildLssl);
|
||||
task("watch-lssl", series(preBuild, parallel(watchLib, watchDiagnostics, watchLssl)));
|
||||
task("watch-lssl").description = "Watch for changes and rebuild tsserverlibrary only";
|
||||
task("watch-lssl").flags = {
|
||||
" --built": "Compile using the built version of the compiler."
|
||||
};
|
||||
|
||||
const buildTests = () => buildProject("src/testRunner");
|
||||
task("tests", series(preBuild, parallel(buildLssl, buildTests)));
|
||||
task("tests").description = "Builds the test infrastructure";
|
||||
task("tests").flags = {
|
||||
" --built": "Compile using the built version of the compiler."
|
||||
};
|
||||
|
||||
const cleanTests = () => cleanProject("src/testRunner");
|
||||
cleanTasks.push(cleanTests);
|
||||
task("clean-tests", cleanTests);
|
||||
task("clean-tests").description = "Cleans the outputs for the test infrastructure";
|
||||
|
||||
const watchTests = () => watchProject("src/testRunner", cmdLineOptions);
|
||||
|
||||
const runEslintRulesTests = () => runConsoleTests("scripts/eslint/tests", "mocha-fivemat-progress-reporter", /*runInParallel*/ false, /*watchMode*/ false);
|
||||
task("run-eslint-rules-tests", runEslintRulesTests);
|
||||
task("run-eslint-rules-tests").description = "Runs the eslint rule tests";
|
||||
|
||||
/** @type { (folder: string) => { (): Promise<any>; displayName?: string } } */
|
||||
const eslint = (folder) => async () => {
|
||||
const formatter = cmdLineOptions.ci ? "stylish" : "autolinkable-stylish";
|
||||
const args = [
|
||||
"node_modules/eslint/bin/eslint",
|
||||
"--cache",
|
||||
"--cache-location", `${folder}/.eslintcache`,
|
||||
"--format", formatter,
|
||||
];
|
||||
|
||||
if (cmdLineOptions.fix) {
|
||||
args.push("--fix");
|
||||
}
|
||||
|
||||
args.push(folder);
|
||||
|
||||
log(`Linting: ${args.join(" ")}`);
|
||||
return exec(process.execPath, args);
|
||||
};
|
||||
|
||||
const lint = eslint(".");
|
||||
lint.displayName = "lint";
|
||||
task("lint", lint);
|
||||
task("lint").description = "Runs eslint on the compiler and scripts sources.";
|
||||
|
||||
const buildCancellationToken = () => buildProject("src/cancellationToken");
|
||||
const cleanCancellationToken = () => cleanProject("src/cancellationToken");
|
||||
cleanTasks.push(cleanCancellationToken);
|
||||
|
||||
const buildTypingsInstaller = () => buildProject("src/typingsInstaller");
|
||||
const cleanTypingsInstaller = () => cleanProject("src/typingsInstaller");
|
||||
cleanTasks.push(cleanTypingsInstaller);
|
||||
|
||||
const buildWatchGuard = () => buildProject("src/watchGuard");
|
||||
const cleanWatchGuard = () => cleanProject("src/watchGuard");
|
||||
cleanTasks.push(cleanWatchGuard);
|
||||
|
||||
const generateTypesMap = () => src("src/server/typesMap.json")
|
||||
.pipe(newer("built/local/typesMap.json"))
|
||||
.pipe(transform(contents => (JSON.parse(contents), contents))) // validates typesMap.json is valid JSON
|
||||
.pipe(dest("built/local"));
|
||||
task("generate-types-map", generateTypesMap);
|
||||
|
||||
const cleanTypesMap = () => del("built/local/typesMap.json");
|
||||
cleanTasks.push(cleanTypesMap);
|
||||
|
||||
// Drop a copy of diagnosticMessages.generated.json into the built/local folder. This allows
|
||||
// it to be synced to the Azure DevOps repo, so that it can get picked up by the build
|
||||
// pipeline that generates the localization artifacts that are then fed into the translation process.
|
||||
const builtLocalDiagnosticMessagesGeneratedJson = "built/local/diagnosticMessages.generated.json";
|
||||
const copyBuiltLocalDiagnosticMessages = () => src(diagnosticMessagesGeneratedJson)
|
||||
.pipe(newer(builtLocalDiagnosticMessagesGeneratedJson))
|
||||
.pipe(dest("built/local"));
|
||||
|
||||
const cleanBuiltLocalDiagnosticMessages = () => del(builtLocalDiagnosticMessagesGeneratedJson);
|
||||
cleanTasks.push(cleanBuiltLocalDiagnosticMessages);
|
||||
|
||||
const buildOtherOutputs = parallel(buildCancellationToken, buildTypingsInstaller, buildWatchGuard, generateTypesMap, copyBuiltLocalDiagnosticMessages);
|
||||
task("other-outputs", series(preBuild, buildOtherOutputs));
|
||||
task("other-outputs").description = "Builds miscelaneous scripts and documents distributed with the LKG";
|
||||
|
||||
task("local", series(preBuild, parallel(localize, buildTsc, buildServer, buildServices, buildLssl, buildOtherOutputs)));
|
||||
task("local").description = "Builds the full compiler and services";
|
||||
task("local").flags = {
|
||||
" --built": "Compile using the built version of the compiler."
|
||||
};
|
||||
|
||||
task("watch-local", series(preBuild, parallel(watchLib, watchDiagnostics, watchTsc, watchServices, watchServer, watchLssl)));
|
||||
task("watch-local").description = "Watches for changes to projects in src/ (but does not execute tests).";
|
||||
task("watch-local").flags = {
|
||||
" --built": "Compile using the built version of the compiler."
|
||||
};
|
||||
|
||||
const preTest = parallel(buildTsc, buildTests, buildServices, buildLssl);
|
||||
preTest.displayName = "preTest";
|
||||
|
||||
const runTests = () => runConsoleTests("built/local/run.js", "mocha-fivemat-progress-reporter", /*runInParallel*/ false, /*watchMode*/ false);
|
||||
task("runtests", series(preBuild, preTest, runTests));
|
||||
task("runtests").description = "Runs the tests using the built run.js file.";
|
||||
task("runtests").flags = {
|
||||
"-t --tests=<regex>": "Pattern for tests to run.",
|
||||
" --failed": "Runs tests listed in '.failed-tests'.",
|
||||
"-r --reporter=<reporter>": "The mocha reporter to use.",
|
||||
"-i --break": "Runs tests in inspector mode (NodeJS 8 and later)",
|
||||
" --keepFailed": "Keep tests in .failed-tests even if they pass",
|
||||
" --light": "Run tests in light mode (fewer verifications, but tests run faster)",
|
||||
" --dirty": "Run tests without first cleaning test output directories",
|
||||
" --stackTraceLimit=<limit>": "Sets the maximum number of stack frames to display. Use 'full' to show all frames.",
|
||||
" --no-color": "Disables color",
|
||||
" --timeout=<ms>": "Overrides the default test timeout.",
|
||||
" --built": "Compile using the built version of the compiler.",
|
||||
" --shards": "Total number of shards running tests (default: 1)",
|
||||
" --shardId": "1-based ID of this shard (default: 1)",
|
||||
};
|
||||
|
||||
const runTestsParallel = () => runConsoleTests("built/local/run.js", "min", /*runInParallel*/ cmdLineOptions.workers > 1, /*watchMode*/ false);
|
||||
task("runtests-parallel", series(preBuild, preTest, runTestsParallel));
|
||||
task("runtests-parallel").description = "Runs all the tests in parallel using the built run.js file.";
|
||||
task("runtests-parallel").flags = {
|
||||
" --light": "Run tests in light mode (fewer verifications, but tests run faster).",
|
||||
" --keepFailed": "Keep tests in .failed-tests even if they pass.",
|
||||
" --dirty": "Run tests without first cleaning test output directories.",
|
||||
" --stackTraceLimit=<limit>": "Sets the maximum number of stack frames to display. Use 'full' to show all frames.",
|
||||
" --workers=<number>": "The number of parallel workers to use.",
|
||||
" --timeout=<ms>": "Overrides the default test timeout.",
|
||||
" --built": "Compile using the built version of the compiler.",
|
||||
" --shards": "Total number of shards running tests (default: 1)",
|
||||
" --shardId": "1-based ID of this shard (default: 1)",
|
||||
};
|
||||
|
||||
|
||||
task("test-browser-integration", () => exec(process.execPath, ["scripts/browserIntegrationTest.mjs"]));
|
||||
task("test-browser-integration").description = "Runs scripts/browserIntegrationTest.mjs which tests that typescript.js loads in a browser";
|
||||
|
||||
|
||||
task("diff", () => exec(getDiffTool(), [refBaseline, localBaseline], { ignoreExitCode: true, waitForExit: false }));
|
||||
task("diff").description = "Diffs the compiler baselines using the diff tool specified by the 'DIFF' environment variable";
|
||||
|
||||
task("diff-rwc", () => exec(getDiffTool(), [refRwcBaseline, localRwcBaseline], { ignoreExitCode: true, waitForExit: false }));
|
||||
task("diff-rwc").description = "Diffs the RWC baselines using the diff tool specified by the 'DIFF' environment variable";
|
||||
|
||||
/**
|
||||
* @param {string} localBaseline Path to the local copy of the baselines
|
||||
* @param {string} refBaseline Path to the reference copy of the baselines
|
||||
*/
|
||||
const baselineAccept = (localBaseline, refBaseline) => merge2(
|
||||
src([`${localBaseline}/**`, `!${localBaseline}/**/*.delete`], { base: localBaseline })
|
||||
.pipe(dest(refBaseline)),
|
||||
src([`${localBaseline}/**/*.delete`], { base: localBaseline, read: false })
|
||||
.pipe(rm())
|
||||
.pipe(rename({ extname: "" }))
|
||||
.pipe(rm(refBaseline)));
|
||||
task("baseline-accept", () => baselineAccept(localBaseline, refBaseline));
|
||||
task("baseline-accept").description = "Makes the most recent test results the new baseline, overwriting the old baseline";
|
||||
|
||||
task("baseline-accept-rwc", () => baselineAccept(localRwcBaseline, refRwcBaseline));
|
||||
task("baseline-accept-rwc").description = "Makes the most recent rwc test results the new baseline, overwriting the old baseline";
|
||||
|
||||
// TODO(rbuckton): Determine if we still need this task. Depending on a relative
|
||||
// path here seems like a bad idea.
|
||||
const updateSublime = () => src(["built/local/tsserver.js", "built/local/tsserver.js.map"])
|
||||
.pipe(dest("../TypeScript-Sublime-Plugin/tsserver/"));
|
||||
task("update-sublime", updateSublime);
|
||||
task("update-sublime").description = "Updates the sublime plugin's tsserver";
|
||||
|
||||
// TODO(rbuckton): Should the path to DefinitelyTyped be configurable via an environment variable?
|
||||
const importDefinitelyTypedTests = () => exec(process.execPath, ["scripts/importDefinitelyTypedTests.mjs", "./", "../DefinitelyTyped"]);
|
||||
task("importDefinitelyTypedTests", importDefinitelyTypedTests);
|
||||
task("importDefinitelyTypedTests").description = "Runs the importDefinitelyTypedTests script to copy DT's tests to the TS-internal RWC tests";
|
||||
|
||||
const buildReleaseTsc = () => buildProject("src/tsc/tsconfig.release.json");
|
||||
const cleanReleaseTsc = () => cleanProject("src/tsc/tsconfig.release.json");
|
||||
cleanTasks.push(cleanReleaseTsc);
|
||||
|
||||
const cleanBuilt = () => del("built");
|
||||
|
||||
const produceLKG = async () => {
|
||||
const expectedFiles = [
|
||||
"built/local/tsc.release.js",
|
||||
"built/local/typescriptServices.js",
|
||||
"built/local/typescriptServices.d.ts",
|
||||
"built/local/tsserver.js",
|
||||
"built/local/dynamicImportCompat.js",
|
||||
"built/local/typescript.js",
|
||||
"built/local/typescript.d.ts",
|
||||
"built/local/tsserverlibrary.js",
|
||||
"built/local/tsserverlibrary.d.ts",
|
||||
"built/local/typingsInstaller.js",
|
||||
"built/local/cancellationToken.js"
|
||||
].concat(libs.map(lib => lib.target));
|
||||
const missingFiles = expectedFiles
|
||||
.concat(localizationTargets)
|
||||
.filter(f => !fs.existsSync(f));
|
||||
if (missingFiles.length > 0) {
|
||||
throw new Error("Cannot replace the LKG unless all built targets are present in directory 'built/local/'. The following files are missing:\n" + missingFiles.join("\n"));
|
||||
}
|
||||
const sizeBefore = getDirSize("lib");
|
||||
await exec(process.execPath, ["scripts/produceLKG.mjs"]);
|
||||
const sizeAfter = getDirSize("lib");
|
||||
if (sizeAfter > (sizeBefore * 1.10)) {
|
||||
throw new Error("The lib folder increased by 10% or more. This likely indicates a bug.");
|
||||
}
|
||||
};
|
||||
|
||||
task("LKG", series(lkgPreBuild, parallel(localize, buildTsc, buildServer, buildServices, buildLssl, buildOtherOutputs, buildReleaseTsc), produceLKG));
|
||||
task("LKG").description = "Makes a new LKG out of the built js files";
|
||||
task("LKG").flags = {
|
||||
" --built": "Compile using the built version of the compiler.",
|
||||
};
|
||||
task("lkg", series("LKG"));
|
||||
|
||||
const generateSpec = () => exec("cscript", ["//nologo", "scripts/word2md.mjs", path.resolve("doc/TypeScript Language Specification - ARCHIVED.docx"), path.resolve("doc/spec-ARCHIVED.md")]);
|
||||
task("generate-spec", generateSpec);
|
||||
task("generate-spec").description = "Generates a Markdown version of the Language Specification";
|
||||
|
||||
task("clean", series(parallel(cleanTasks), cleanBuilt));
|
||||
task("clean").description = "Cleans build outputs";
|
||||
|
||||
const configureNightly = () => exec(process.execPath, ["scripts/configurePrerelease.mjs", "dev", "package.json", "src/compiler/corePublic.ts"]);
|
||||
task("configure-nightly", series(buildScripts, configureNightly));
|
||||
task("configure-nightly").description = "Runs scripts/configurePrerelease.ts to prepare a build for nightly publishing";
|
||||
|
||||
const configureInsiders = () => exec(process.execPath, ["scripts/configurePrerelease.mjs", "insiders", "package.json", "src/compiler/corePublic.ts"]);
|
||||
task("configure-insiders", configureInsiders);
|
||||
task("configure-insiders").description = "Runs scripts/configurePrerelease.mjs to prepare a build for insiders publishing";
|
||||
|
||||
const configureExperimental = () => exec(process.execPath, ["scripts/configurePrerelease.mjs", "experimental", "package.json", "src/compiler/corePublic.ts"]);
|
||||
task("configure-experimental", configureExperimental);
|
||||
task("configure-experimental").description = "Runs scripts/configurePrerelease.mjs to prepare a build for experimental publishing";
|
||||
|
||||
const publishNightly = () => exec("npm", ["publish", "--tag", "next"]);
|
||||
task("publish-nightly", series(task("clean"), task("LKG"), task("clean"), task("runtests-parallel"), publishNightly));
|
||||
task("publish-nightly").description = "Runs `npm publish --tag next` to create a new nightly build on npm";
|
||||
|
||||
// TODO(rbuckton): The problem with watching in this way is that a change in compiler/ will result
|
||||
// in cascading changes in other projects that may take differing amounts of times to complete. As
|
||||
// a result, the watch may accidentally trigger early, so we have to set a significant delay. An
|
||||
// alternative approach would be to leverage a builder API, or to have 'tsc -b' have an option to
|
||||
// write some kind of trigger file that indicates build completion that we could listen for instead.
|
||||
const watchRuntests = () => watch(["built/local/*.js", "tests/cases/**/*.ts", "tests/cases/**/tsconfig.json"], { delay: 5000 }, async () => {
|
||||
if (cmdLineOptions.tests || cmdLineOptions.failed) {
|
||||
await runConsoleTests("built/local/run.js", "mocha-fivemat-progress-reporter", /*runInParallel*/ false, /*watchMode*/ true);
|
||||
}
|
||||
else {
|
||||
await runConsoleTests("built/local/run.js", "min", /*runInParallel*/ true, /*watchMode*/ true);
|
||||
}
|
||||
});
|
||||
task("watch", series(preBuild, preTest, parallel(watchLib, watchDiagnostics, watchServices, watchLssl, watchTests, watchRuntests)));
|
||||
task("watch").description = "Watches for changes and rebuilds and runs tests in parallel.";
|
||||
task("watch").flags = {
|
||||
"-t --tests=<regex>": "Pattern for tests to run. Forces tests to be run in a single worker.",
|
||||
" --failed": "Runs tests listed in '.failed-tests'. Forces tests to be run in a single worker.",
|
||||
"-r --reporter=<reporter>": "The mocha reporter to use.",
|
||||
" --keepFailed": "Keep tests in .failed-tests even if they pass",
|
||||
" --light": "Run tests in light mode (fewer verifications, but tests run faster)",
|
||||
" --dirty": "Run tests without first cleaning test output directories",
|
||||
" --stackTraceLimit=<limit>": "Sets the maximum number of stack frames to display. Use 'full' to show all frames.",
|
||||
" --no-color": "Disables color",
|
||||
" --timeout=<ms>": "Overrides the default test timeout.",
|
||||
" --workers=<number>": "The number of parallel workers to use.",
|
||||
" --built": "Compile using the built version of the compiler.",
|
||||
};
|
||||
|
||||
task("default", series("local"));
|
||||
task("default").description = "Runs 'local'";
|
||||
|
||||
task("help", () => exec("gulp", ["--tasks", "--depth", "1", "--sort-tasks"], { hidePrompt: true }));
|
||||
task("help").description = "Prints the top-level tasks.";
|
||||
+798
@@ -0,0 +1,798 @@
|
||||
// @ts-check
|
||||
import path from "path";
|
||||
import fs from "fs";
|
||||
import del from "del";
|
||||
import { task } from "hereby";
|
||||
import _glob from "glob";
|
||||
import util from "util";
|
||||
import chalk from "chalk";
|
||||
import { exec, readJson, getDiffTool, getDirSize, memoize, needsUpdate } from "./scripts/build/utils.mjs";
|
||||
import { runConsoleTests, refBaseline, localBaseline, refRwcBaseline, localRwcBaseline } from "./scripts/build/tests.mjs";
|
||||
import { buildProject as realBuildProject, cleanProject, watchProject } from "./scripts/build/projects.mjs";
|
||||
import { localizationDirectories } from "./scripts/build/localization.mjs";
|
||||
import cmdLineOptions from "./scripts/build/options.mjs";
|
||||
import esbuild from "esbuild";
|
||||
|
||||
const glob = util.promisify(_glob);
|
||||
|
||||
/** @typedef {ReturnType<typeof task>} Task */
|
||||
void 0;
|
||||
|
||||
const copyrightFilename = "CopyrightNotice.txt";
|
||||
const copyright = memoize(async () => {
|
||||
const contents = await fs.promises.readFile(copyrightFilename, "utf-8");
|
||||
return contents.replace(/\r\n/g, "\n");
|
||||
});
|
||||
|
||||
|
||||
// TODO(jakebailey): This is really gross. If the build is cancelled (i.e. Ctrl+C), the modification will persist.
|
||||
// Waiting on: https://github.com/microsoft/TypeScript/issues/51164
|
||||
let currentlyBuilding = 0;
|
||||
let oldTsconfigBase;
|
||||
|
||||
/** @type {typeof realBuildProject} */
|
||||
const buildProjectWithEmit = async (...args) => {
|
||||
const tsconfigBasePath = "./src/tsconfig-base.json";
|
||||
|
||||
// Not using fs.promises here, to ensure we are synchronous until running the real build.
|
||||
|
||||
if (currentlyBuilding === 0) {
|
||||
oldTsconfigBase = fs.readFileSync(tsconfigBasePath, "utf-8");
|
||||
fs.writeFileSync(tsconfigBasePath, oldTsconfigBase.replace(`"emitDeclarationOnly": true,`, `"emitDeclarationOnly": false, // DO NOT COMMIT`));
|
||||
}
|
||||
|
||||
currentlyBuilding++;
|
||||
|
||||
await realBuildProject(...args);
|
||||
|
||||
currentlyBuilding--;
|
||||
|
||||
if (currentlyBuilding === 0) {
|
||||
fs.writeFileSync(tsconfigBasePath, oldTsconfigBase);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const buildProject = cmdLineOptions.bundle ? realBuildProject : buildProjectWithEmit;
|
||||
|
||||
|
||||
export const buildScripts = task({
|
||||
name: "scripts",
|
||||
description: "Builds files in the 'scripts' folder.",
|
||||
run: () => buildProject("scripts")
|
||||
});
|
||||
|
||||
const libs = memoize(() => {
|
||||
/** @type {{ libs: string[]; paths: Record<string, string | undefined>; }} */
|
||||
const libraries = readJson("./src/lib/libs.json");
|
||||
const libs = libraries.libs.map(lib => {
|
||||
const relativeSources = ["header.d.ts", lib + ".d.ts"];
|
||||
const relativeTarget = libraries.paths && libraries.paths[lib] || ("lib." + lib + ".d.ts");
|
||||
const sources = relativeSources.map(s => path.posix.join("src/lib", s));
|
||||
const target = `built/local/${relativeTarget}`;
|
||||
return { target, sources };
|
||||
});
|
||||
return libs;
|
||||
});
|
||||
|
||||
|
||||
export const generateLibs = task({
|
||||
name: "lib",
|
||||
description: "Builds the library targets",
|
||||
run: async () => {
|
||||
await fs.promises.mkdir("./built/local", { recursive: true });
|
||||
for (const lib of libs()) {
|
||||
let output = await copyright();
|
||||
|
||||
for (const source of lib.sources) {
|
||||
const contents = await fs.promises.readFile(source, "utf-8");
|
||||
// TODO(jakebailey): "\n\n" is for compatibility with our current tests; our test baselines
|
||||
// are sensitive to the positions of things in the lib files. Eventually remove this,
|
||||
// or remove lib.d.ts line numbers from our baselines.
|
||||
output += "\n\n" + contents.replace(/\r\n/g, "\n");
|
||||
}
|
||||
|
||||
await fs.promises.writeFile(lib.target, output);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
const diagnosticInformationMapTs = "src/compiler/diagnosticInformationMap.generated.ts";
|
||||
const diagnosticMessagesJson = "src/compiler/diagnosticMessages.json";
|
||||
const diagnosticMessagesGeneratedJson = "src/compiler/diagnosticMessages.generated.json";
|
||||
|
||||
export const generateDiagnostics = task({
|
||||
name: "generate-diagnostics",
|
||||
description: "Generates a diagnostic file in TypeScript based on an input JSON file",
|
||||
run: async () => {
|
||||
await exec(process.execPath, ["scripts/processDiagnosticMessages.mjs", diagnosticMessagesJson]);
|
||||
}
|
||||
});
|
||||
|
||||
const cleanDiagnostics = task({
|
||||
name: "clean-diagnostics",
|
||||
description: "Generates a diagnostic file in TypeScript based on an input JSON file",
|
||||
hiddenFromTaskList: true,
|
||||
run: () => del([diagnosticInformationMapTs, diagnosticMessagesGeneratedJson]),
|
||||
});
|
||||
|
||||
|
||||
// Localize diagnostics
|
||||
/**
|
||||
* .lcg file is what localization team uses to know what messages to localize.
|
||||
* The file is always generated in 'enu/diagnosticMessages.generated.json.lcg'
|
||||
*/
|
||||
const generatedLCGFile = "built/local/enu/diagnosticMessages.generated.json.lcg";
|
||||
|
||||
/**
|
||||
* The localization target produces the two following transformations:
|
||||
* 1. 'src\loc\lcl\<locale>\diagnosticMessages.generated.json.lcl' => 'built\local\<locale>\diagnosticMessages.generated.json'
|
||||
* convert localized resources into a .json file the compiler can understand
|
||||
* 2. 'src\compiler\diagnosticMessages.generated.json' => 'built\local\ENU\diagnosticMessages.generated.json.lcg'
|
||||
* generate the lcg file (source of messages to localize) from the diagnosticMessages.generated.json
|
||||
*/
|
||||
const localizationTargets = localizationDirectories
|
||||
.map(f => `built/local/${f}/diagnosticMessages.generated.json`)
|
||||
.concat(generatedLCGFile);
|
||||
|
||||
const localize = task({
|
||||
name: "localize",
|
||||
dependencies: [generateDiagnostics],
|
||||
run: async () => {
|
||||
if (needsUpdate(diagnosticMessagesGeneratedJson, generatedLCGFile)) {
|
||||
return exec(process.execPath, ["scripts/generateLocalizedDiagnosticMessages.mjs", "src/loc/lcl", "built/local", diagnosticMessagesGeneratedJson], { ignoreExitCode: true });
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const buildSrc = task({
|
||||
name: "build-src",
|
||||
description: "Builds the src project (all code)",
|
||||
dependencies: [generateDiagnostics],
|
||||
run: () => buildProject("src"),
|
||||
});
|
||||
|
||||
export const watchSrc = task({
|
||||
name: "watch-src",
|
||||
description: "Watches the src project (all code)",
|
||||
hiddenFromTaskList: true,
|
||||
dependencies: [generateDiagnostics],
|
||||
run: () => watchProject("src"),
|
||||
});
|
||||
|
||||
export const cleanSrc = task({
|
||||
name: "clean-src",
|
||||
hiddenFromTaskList: true,
|
||||
run: () => cleanProject("src"),
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {string} entrypoint
|
||||
* @param {string} output
|
||||
*/
|
||||
async function runDtsBundler(entrypoint, output) {
|
||||
await exec(process.execPath, [
|
||||
"./scripts/dtsBundler.mjs",
|
||||
"--entrypoint",
|
||||
entrypoint,
|
||||
"--output",
|
||||
output,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} entrypoint
|
||||
* @param {string} outfile
|
||||
* @param {BundlerTaskOptions} [taskOptions]
|
||||
*
|
||||
* @typedef BundlerTaskOptions
|
||||
* @property {string[]} [external]
|
||||
* @property {boolean} [exportIsTsObject]
|
||||
* @property {boolean} [treeShaking]
|
||||
*/
|
||||
function createBundler(entrypoint, outfile, taskOptions = {}) {
|
||||
const getOptions = memoize(async () => {
|
||||
/** @type {esbuild.BuildOptions} */
|
||||
const options = {
|
||||
entryPoints: [entrypoint],
|
||||
banner: { js: await copyright() },
|
||||
bundle: true,
|
||||
outfile,
|
||||
platform: "node",
|
||||
target: "es2018",
|
||||
format: "cjs",
|
||||
sourcemap: "linked",
|
||||
sourcesContent: false,
|
||||
treeShaking: taskOptions.treeShaking,
|
||||
external: [
|
||||
...(taskOptions.external ?? []),
|
||||
"source-map-support",
|
||||
],
|
||||
logLevel: "warning",
|
||||
// legalComments: "none", // If we add copyright headers to the source files, uncomment.
|
||||
plugins: [
|
||||
{
|
||||
name: "no-node-modules",
|
||||
setup: (build) => {
|
||||
build.onLoad({ filter: /[\\/]node_modules[\\/]/ }, () => {
|
||||
// Ideally, we'd use "--external:./node_modules/*" here, but that doesn't work; we
|
||||
// will instead end up with paths to node_modules rather than the package names.
|
||||
// Instead, we'll return a load error when we see that we're trying to bundle from
|
||||
// node_modules, then explicitly declare which external dependencies we rely on, which
|
||||
// ensures that the correct module specifier is kept in the output (the non-wildcard
|
||||
// form works properly). It also helps us keep tabs on what external dependencies we
|
||||
// may be importing, which is handy.
|
||||
//
|
||||
// See: https://github.com/evanw/esbuild/issues/1958
|
||||
return {
|
||||
errors: [{ text: 'Attempted to bundle from node_modules; ensure "external" is set correctly.' }]
|
||||
};
|
||||
});
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "fix-require",
|
||||
setup: (build) => {
|
||||
build.onEnd(async () => {
|
||||
// esbuild converts calls to "require" to "__require"; this function
|
||||
// calls the real require if it exists, or throws if it does not (rather than
|
||||
// throwing an error like "require not defined"). But, since we want typescript
|
||||
// to be consumable by other bundlers, we need to convert these calls back to
|
||||
// require so our imports are visible again.
|
||||
//
|
||||
// The leading spaces are to keep the offsets the same within the files to keep
|
||||
// source maps working (though this only really matters for the line the require is on).
|
||||
//
|
||||
// See: https://github.com/evanw/esbuild/issues/1905
|
||||
let contents = await fs.promises.readFile(outfile, "utf-8");
|
||||
contents = contents.replace(/__require\(/g, " require(");
|
||||
await fs.promises.writeFile(outfile, contents);
|
||||
});
|
||||
},
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
if (taskOptions.exportIsTsObject) {
|
||||
// We use an IIFE so we can inject the footer, and so that "ts" is global if not loaded as a module.
|
||||
options.format = "iife";
|
||||
// Name the variable ts, matching our old big bundle and so we can use the code below.
|
||||
options.globalName = "ts";
|
||||
// If we are in a CJS context, export the ts namespace.
|
||||
options.footer = { js: `\nif (typeof module !== "undefined" && module.exports) { module.exports = ts; }` };
|
||||
}
|
||||
|
||||
return options;
|
||||
});
|
||||
|
||||
return {
|
||||
build: async () => esbuild.build(await getOptions()),
|
||||
watch: async () => esbuild.build({ ...await getOptions(), watch: true, logLevel: "info" }),
|
||||
};
|
||||
}
|
||||
|
||||
let printedWatchWarning = false;
|
||||
|
||||
/**
|
||||
* @param {object} options
|
||||
* @param {string} options.name
|
||||
* @param {string} [options.description]
|
||||
* @param {Task[]} [options.buildDeps]
|
||||
* @param {string} options.project
|
||||
* @param {string} options.srcEntrypoint
|
||||
* @param {string} options.builtEntrypoint
|
||||
* @param {string} options.output
|
||||
* @param {Task[]} [options.mainDeps]
|
||||
* @param {BundlerTaskOptions} [options.bundlerOptions]
|
||||
*/
|
||||
function entrypointBuildTask(options) {
|
||||
const build = task({
|
||||
name: `build-${options.name}`,
|
||||
dependencies: options.buildDeps,
|
||||
run: () => buildProject(options.project),
|
||||
});
|
||||
|
||||
const bundler = createBundler(options.srcEntrypoint, options.output, options.bundlerOptions);
|
||||
|
||||
// If we ever need to bundle our own output, change this to depend on build
|
||||
// and run esbuild on builtEntrypoint.
|
||||
const bundle = task({
|
||||
name: `bundle-${options.name}`,
|
||||
dependencies: options.buildDeps,
|
||||
run: () => bundler.build(),
|
||||
});
|
||||
|
||||
/**
|
||||
* Writes a CJS module that reexports another CJS file. E.g. given
|
||||
* `options.builtEntrypoint = "./built/local/tsc/tsc.js"` and
|
||||
* `options.output = "./built/local/tsc.js"`, this will create a file
|
||||
* named "./built/local/tsc.js" containing:
|
||||
*
|
||||
* ```
|
||||
* module.exports = require("./tsc/tsc.js")
|
||||
* ```
|
||||
*/
|
||||
const shim = task({
|
||||
name: `shim-${options.name}`,
|
||||
run: async () => {
|
||||
const outDir = path.dirname(options.output);
|
||||
await fs.promises.mkdir(outDir, { recursive: true });
|
||||
const moduleSpecifier = path.relative(outDir, options.builtEntrypoint);
|
||||
await fs.promises.writeFile(options.output, `module.exports = require("./${moduleSpecifier}")`);
|
||||
},
|
||||
});
|
||||
|
||||
const main = task({
|
||||
name: options.name,
|
||||
description: options.description,
|
||||
dependencies: (options.mainDeps ?? []).concat(cmdLineOptions.bundle ? [bundle] : [build, shim]),
|
||||
});
|
||||
|
||||
const watch = task({
|
||||
name: `watch-${options.name}`,
|
||||
hiddenFromTaskList: true, // This is best effort.
|
||||
dependencies: (options.buildDeps ?? []).concat(options.mainDeps ?? []).concat(cmdLineOptions.bundle ? [] : [shim]),
|
||||
run: () => {
|
||||
// These watch functions return promises that resolve once watch mode has started,
|
||||
// allowing them to operate as regular tasks, while creating unresolved promises
|
||||
// in the background that keep the process running after all tasks have exited.
|
||||
if (!printedWatchWarning) {
|
||||
console.error(chalk.yellowBright("Warning: watch mode is incomplete and may not work as expected. Use at your own risk."));
|
||||
printedWatchWarning = true;
|
||||
}
|
||||
|
||||
if (!cmdLineOptions.bundle) {
|
||||
return watchProject(options.project);
|
||||
}
|
||||
return bundler.watch();
|
||||
}
|
||||
});
|
||||
|
||||
return { build, bundle, shim, main, watch };
|
||||
}
|
||||
|
||||
|
||||
const { main: tsc, watch: watchTsc } = entrypointBuildTask({
|
||||
name: "tsc",
|
||||
description: "Builds the command-line compiler",
|
||||
buildDeps: [generateDiagnostics],
|
||||
project: "src/tsc",
|
||||
srcEntrypoint: "./src/tsc/tsc.ts",
|
||||
builtEntrypoint: "./built/local/tsc/tsc.js",
|
||||
output: "./built/local/tsc.js",
|
||||
mainDeps: [generateLibs],
|
||||
});
|
||||
export { tsc, watchTsc };
|
||||
|
||||
|
||||
const { main: services, build: buildServices, watch: watchServices } = entrypointBuildTask({
|
||||
name: "services",
|
||||
description: "Builds the typescript.js library",
|
||||
buildDeps: [generateDiagnostics],
|
||||
project: "src/typescript",
|
||||
srcEntrypoint: "./src/typescript/typescript.ts",
|
||||
builtEntrypoint: "./built/local/typescript/typescript.js",
|
||||
output: "./built/local/typescript.js",
|
||||
mainDeps: [generateLibs],
|
||||
bundlerOptions: { exportIsTsObject: true },
|
||||
});
|
||||
export { services, watchServices };
|
||||
|
||||
export const dtsServices = task({
|
||||
name: "dts-services",
|
||||
description: "Bundles typescript.d.ts",
|
||||
dependencies: [buildServices],
|
||||
run: async () => {
|
||||
if (needsUpdate("./built/local/typescript/tsconfig.tsbuildinfo", ["./built/local/typescript.d.ts", "./built/local/typescript.internal.d.ts"])) {
|
||||
runDtsBundler("./built/local/typescript/typescript.d.ts", "./built/local/typescript.d.ts");
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
const { main: tsserver, watch: watchTsserver } = entrypointBuildTask({
|
||||
name: "tsserver",
|
||||
description: "Builds the language server",
|
||||
buildDeps: [generateDiagnostics],
|
||||
project: "src/tsserver",
|
||||
srcEntrypoint: "./src/tsserver/server.ts",
|
||||
builtEntrypoint: "./built/local/tsserver/server.js",
|
||||
output: "./built/local/tsserver.js",
|
||||
mainDeps: [generateLibs],
|
||||
// Even though this seems like an exectuable, so could be the default CJS,
|
||||
// this is used in the browser too. Do the same thing that we do for our
|
||||
// libraries and generate an IIFE with name `ts`, as to not pollute the global
|
||||
// scope.
|
||||
bundlerOptions: { exportIsTsObject: true },
|
||||
});
|
||||
export { tsserver, watchTsserver };
|
||||
|
||||
|
||||
export const min = task({
|
||||
name: "min",
|
||||
description: "Builds only tsc and tsserver",
|
||||
dependencies: [tsc, tsserver],
|
||||
});
|
||||
|
||||
export const watchMin = task({
|
||||
name: "watch-min",
|
||||
description: "Watches only tsc and tsserver",
|
||||
hiddenFromTaskList: true,
|
||||
dependencies: [watchTsc, watchTsserver],
|
||||
});
|
||||
|
||||
|
||||
|
||||
const { main: lssl, build: buildLssl, watch: watchLssl } = entrypointBuildTask({
|
||||
name: "lssl",
|
||||
description: "Builds language service server library",
|
||||
buildDeps: [generateDiagnostics],
|
||||
project: "src/tsserverlibrary",
|
||||
srcEntrypoint: "./src/tsserverlibrary/tsserverlibrary.ts",
|
||||
builtEntrypoint: "./built/local/tsserverlibrary/tsserverlibrary.js",
|
||||
output: "./built/local/tsserverlibrary.js",
|
||||
mainDeps: [generateLibs],
|
||||
bundlerOptions: { exportIsTsObject: true },
|
||||
});
|
||||
export { lssl, watchLssl };
|
||||
|
||||
export const dtsLssl = task({
|
||||
name: "dts-lssl",
|
||||
description: "Bundles tsserverlibrary.d.ts",
|
||||
dependencies: [buildLssl],
|
||||
run: async () => {
|
||||
if (needsUpdate("./built/local/tsserverlibrary/tsconfig.tsbuildinfo", ["./built/local/tsserverlibrary.d.ts", "./built/local/tsserverlibrary.internal.d.ts"])) {
|
||||
await runDtsBundler("./built/local/tsserverlibrary/tsserverlibrary.d.ts", "./built/local/tsserverlibrary.d.ts");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const dts = task({
|
||||
name: "dts",
|
||||
dependencies: [dtsServices, dtsLssl],
|
||||
});
|
||||
|
||||
|
||||
const testRunner = "./built/local/run.js";
|
||||
|
||||
const { main: tests, watch: watchTests } = entrypointBuildTask({
|
||||
name: "tests",
|
||||
description: "Builds the test infrastructure",
|
||||
buildDeps: [generateDiagnostics],
|
||||
project: "src/testRunner",
|
||||
srcEntrypoint: "./src/testRunner/_namespaces/Harness.ts",
|
||||
builtEntrypoint: "./built/local/testRunner/runner.js",
|
||||
output: testRunner,
|
||||
mainDeps: [generateLibs],
|
||||
bundlerOptions: {
|
||||
// Ensure we never drop any dead code, which might be helpful while debugging.
|
||||
treeShaking: false,
|
||||
// These are directly imported via import statements and should not be bundled.
|
||||
external: [
|
||||
"chai",
|
||||
"del",
|
||||
"diff",
|
||||
"mocha",
|
||||
"ms",
|
||||
],
|
||||
},
|
||||
});
|
||||
export { tests, watchTests };
|
||||
|
||||
|
||||
export const runEslintRulesTests = task({
|
||||
name: "run-eslint-rules-tests",
|
||||
description: "Runs the eslint rule tests",
|
||||
run: () => runConsoleTests("scripts/eslint/tests", "mocha-fivemat-progress-reporter", /*runInParallel*/ false),
|
||||
});
|
||||
|
||||
export const lint = task({
|
||||
name: "lint",
|
||||
description: "Runs eslint on the compiler and scripts sources.",
|
||||
run: async () => {
|
||||
const folder = ".";
|
||||
const formatter = cmdLineOptions.ci ? "stylish" : "autolinkable-stylish";
|
||||
const args = [
|
||||
"node_modules/eslint/bin/eslint",
|
||||
"--cache",
|
||||
"--cache-location", `${folder}/.eslintcache`,
|
||||
"--format", formatter,
|
||||
];
|
||||
|
||||
if (cmdLineOptions.fix) {
|
||||
args.push("--fix");
|
||||
}
|
||||
|
||||
args.push(folder);
|
||||
|
||||
console.log(`Linting: ${args.join(" ")}`);
|
||||
return exec(process.execPath, args);
|
||||
}
|
||||
});
|
||||
|
||||
const { main: cancellationToken, watch: watchCancellationToken } = entrypointBuildTask({
|
||||
name: "cancellation-token",
|
||||
project: "src/cancellationToken",
|
||||
srcEntrypoint: "./src/cancellationToken/cancellationToken.ts",
|
||||
builtEntrypoint: "./built/local/cancellationToken/cancellationToken.js",
|
||||
output: "./built/local/cancellationToken.js",
|
||||
});
|
||||
|
||||
const { main: typingsInstaller, watch: watchTypingsInstaller } = entrypointBuildTask({
|
||||
name: "typings-installer",
|
||||
buildDeps: [generateDiagnostics],
|
||||
project: "src/typingsInstaller",
|
||||
srcEntrypoint: "./src/typingsInstaller/nodeTypingsInstaller.ts",
|
||||
builtEntrypoint: "./built/local/typingsInstaller/nodeTypingsInstaller.js",
|
||||
output: "./built/local/typingsInstaller.js",
|
||||
});
|
||||
|
||||
const { main: watchGuard, watch: watchWatchGuard } = entrypointBuildTask({
|
||||
name: "watch-guard",
|
||||
project: "src/watchGuard",
|
||||
srcEntrypoint: "./src/watchGuard/watchGuard.ts",
|
||||
builtEntrypoint: "./built/local/watchGuard/watchGuard.js",
|
||||
output: "./built/local/watchGuard.js",
|
||||
});
|
||||
|
||||
export const generateTypesMap = task({
|
||||
name: "generate-types-map",
|
||||
run: async () => {
|
||||
const source = "src/server/typesMap.json";
|
||||
const target = "built/local/typesMap.json";
|
||||
const contents = await fs.promises.readFile(source, "utf-8");
|
||||
JSON.parse(contents); // Validates that the JSON parses.
|
||||
await fs.promises.writeFile(target, contents);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Drop a copy of diagnosticMessages.generated.json into the built/local folder. This allows
|
||||
// it to be synced to the Azure DevOps repo, so that it can get picked up by the build
|
||||
// pipeline that generates the localization artifacts that are then fed into the translation process.
|
||||
const builtLocalDiagnosticMessagesGeneratedJson = "built/local/diagnosticMessages.generated.json";
|
||||
const copyBuiltLocalDiagnosticMessages = task({
|
||||
name: "copy-built-local-diagnostic-messages",
|
||||
dependencies: [generateDiagnostics],
|
||||
run: async () => {
|
||||
const contents = await fs.promises.readFile(diagnosticMessagesGeneratedJson, "utf-8");
|
||||
JSON.parse(contents); // Validates that the JSON parses.
|
||||
await fs.promises.writeFile(builtLocalDiagnosticMessagesGeneratedJson, contents);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
export const otherOutputs = task({
|
||||
name: "other-outputs",
|
||||
description: "Builds miscelaneous scripts and documents distributed with the LKG",
|
||||
dependencies: [cancellationToken, typingsInstaller, watchGuard, generateTypesMap, copyBuiltLocalDiagnosticMessages],
|
||||
});
|
||||
|
||||
export const watchOtherOutputs = task({
|
||||
name: "watch-other-outputs",
|
||||
description: "Builds miscelaneous scripts and documents distributed with the LKG",
|
||||
hiddenFromTaskList: true,
|
||||
dependencies: [watchCancellationToken, watchTypingsInstaller, watchWatchGuard, generateTypesMap, copyBuiltLocalDiagnosticMessages],
|
||||
});
|
||||
|
||||
export const local = task({
|
||||
name: "local",
|
||||
description: "Builds the full compiler and services",
|
||||
dependencies: [localize, tsc, tsserver, services, lssl, otherOutputs, dts],
|
||||
});
|
||||
export default local;
|
||||
|
||||
export const watchLocal = task({
|
||||
name: "watch-local",
|
||||
description: "Watches the full compiler and services",
|
||||
hiddenFromTaskList: true,
|
||||
dependencies: [localize, watchTsc, watchTsserver, watchServices, watchLssl, watchOtherOutputs, dts],
|
||||
});
|
||||
|
||||
|
||||
export const runTests = task({
|
||||
name: "runtests",
|
||||
description: "Runs the tests using the built run.js file.",
|
||||
dependencies: [tests, generateLibs, dts],
|
||||
run: () => runConsoleTests(testRunner, "mocha-fivemat-progress-reporter", /*runInParallel*/ false),
|
||||
});
|
||||
// task("runtests").flags = {
|
||||
// "-t --tests=<regex>": "Pattern for tests to run.",
|
||||
// " --failed": "Runs tests listed in '.failed-tests'.",
|
||||
// "-r --reporter=<reporter>": "The mocha reporter to use.",
|
||||
// "-i --break": "Runs tests in inspector mode (NodeJS 8 and later)",
|
||||
// " --keepFailed": "Keep tests in .failed-tests even if they pass",
|
||||
// " --light": "Run tests in light mode (fewer verifications, but tests run faster)",
|
||||
// " --dirty": "Run tests without first cleaning test output directories",
|
||||
// " --stackTraceLimit=<limit>": "Sets the maximum number of stack frames to display. Use 'full' to show all frames.",
|
||||
// " --no-color": "Disables color",
|
||||
// " --timeout=<ms>": "Overrides the default test timeout.",
|
||||
// " --built": "Compile using the built version of the compiler.",
|
||||
// " --shards": "Total number of shards running tests (default: 1)",
|
||||
// " --shardId": "1-based ID of this shard (default: 1)",
|
||||
// };
|
||||
|
||||
export const runTestsParallel = task({
|
||||
name: "runtests-parallel",
|
||||
description: "Runs all the tests in parallel using the built run.js file.",
|
||||
dependencies: [tests, generateLibs, dts],
|
||||
run: () => runConsoleTests(testRunner, "min", /*runInParallel*/ cmdLineOptions.workers > 1),
|
||||
});
|
||||
// task("runtests-parallel").flags = {
|
||||
// " --light": "Run tests in light mode (fewer verifications, but tests run faster).",
|
||||
// " --keepFailed": "Keep tests in .failed-tests even if they pass.",
|
||||
// " --dirty": "Run tests without first cleaning test output directories.",
|
||||
// " --stackTraceLimit=<limit>": "Sets the maximum number of stack frames to display. Use 'full' to show all frames.",
|
||||
// " --workers=<number>": "The number of parallel workers to use.",
|
||||
// " --timeout=<ms>": "Overrides the default test timeout.",
|
||||
// " --built": "Compile using the built version of the compiler.",
|
||||
// " --shards": "Total number of shards running tests (default: 1)",
|
||||
// " --shardId": "1-based ID of this shard (default: 1)",
|
||||
// };
|
||||
|
||||
export const testBrowserIntegration = task({
|
||||
name: "test-browser-integration",
|
||||
description: "Runs scripts/browserIntegrationTest.mjs which tests that typescript.js loads in a browser",
|
||||
dependencies: [services],
|
||||
run: () => exec(process.execPath, ["scripts/browserIntegrationTest.mjs"]),
|
||||
});
|
||||
|
||||
export const diff = task({
|
||||
name: "diff",
|
||||
description: "Diffs the compiler baselines using the diff tool specified by the 'DIFF' environment variable",
|
||||
run: () => exec(getDiffTool(), [refBaseline, localBaseline], { ignoreExitCode: true, waitForExit: false }),
|
||||
});
|
||||
|
||||
export const diffRwc = task({
|
||||
name: "diff-rwc",
|
||||
description: "Diffs the RWC baselines using the diff tool specified by the 'DIFF' environment variable",
|
||||
run: () => exec(getDiffTool(), [refRwcBaseline, localRwcBaseline], { ignoreExitCode: true, waitForExit: false }),
|
||||
});
|
||||
|
||||
/**
|
||||
* @param {string} localBaseline Path to the local copy of the baselines
|
||||
* @param {string} refBaseline Path to the reference copy of the baselines
|
||||
*/
|
||||
function baselineAcceptTask(localBaseline, refBaseline) {
|
||||
/**
|
||||
* @param {string} p
|
||||
*/
|
||||
function localPathToRefPath(p) {
|
||||
const relative = path.relative(localBaseline, p);
|
||||
return path.join(refBaseline, relative);
|
||||
}
|
||||
|
||||
return async () => {
|
||||
const toCopy = await glob(`${localBaseline}/**`, { nodir: true, ignore: `${localBaseline}/**/*.delete` });
|
||||
for (const p of toCopy) {
|
||||
const out = localPathToRefPath(p);
|
||||
await fs.promises.mkdir(path.dirname(out), { recursive: true });
|
||||
await fs.promises.copyFile(p, out);
|
||||
}
|
||||
const toDelete = await glob(`${localBaseline}/**/*.delete`, { nodir: true });
|
||||
for (const p of toDelete) {
|
||||
const out = localPathToRefPath(p);
|
||||
await fs.promises.rm(out);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const baselineAccept = task({
|
||||
name: "baseline-accept",
|
||||
description: "Makes the most recent test results the new baseline, overwriting the old baseline",
|
||||
run: baselineAcceptTask(localBaseline, refBaseline),
|
||||
});
|
||||
|
||||
export const baselineAcceptRwc = task({
|
||||
name: "baseline-accept-rwc",
|
||||
description: "Makes the most recent rwc test results the new baseline, overwriting the old baseline",
|
||||
run: baselineAcceptTask(localRwcBaseline, refRwcBaseline),
|
||||
});
|
||||
|
||||
// TODO(rbuckton): Determine if we still need this task. Depending on a relative
|
||||
// path here seems like a bad idea.
|
||||
export const updateSublime = task({
|
||||
name: "update-sublime",
|
||||
description: "Updates the sublime plugin's tsserver",
|
||||
dependencies: [tsserver],
|
||||
run: async () => {
|
||||
for (const file of ["built/local/tsserver.js", "built/local/tsserver.js.map"]) {
|
||||
await fs.promises.copyFile(file, path.resolve("../TypeScript-Sublime-Plugin/tsserver/", path.basename(file)));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// TODO(rbuckton): Should the path to DefinitelyTyped be configurable via an environment variable?
|
||||
export const importDefinitelyTypedTests = task({
|
||||
name: "importDefinitelyTypedTests",
|
||||
description: "Runs the importDefinitelyTypedTests script to copy DT's tests to the TS-internal RWC tests",
|
||||
run: () => exec(process.execPath, ["scripts/importDefinitelyTypedTests.mjs", "./", "../DefinitelyTyped"]),
|
||||
});
|
||||
|
||||
|
||||
export const produceLKG = task({
|
||||
name: "LKG",
|
||||
description: "Makes a new LKG out of the built js files",
|
||||
dependencies: [localize, tsc, tsserver, services, lssl, otherOutputs, dts],
|
||||
run: async () => {
|
||||
if (!cmdLineOptions.bundle) {
|
||||
throw new Error("LKG cannot be created when --bundle=false");
|
||||
}
|
||||
|
||||
const expectedFiles = [
|
||||
"built/local/cancellationToken.js",
|
||||
"built/local/tsc.js",
|
||||
"built/local/tsserver.js",
|
||||
"built/local/tsserverlibrary.js",
|
||||
"built/local/tsserverlibrary.d.ts",
|
||||
"built/local/typescript.js",
|
||||
"built/local/typescript.d.ts",
|
||||
"built/local/typingsInstaller.js",
|
||||
"built/local/watchGuard.js",
|
||||
].concat(libs().map(lib => lib.target));
|
||||
const missingFiles = expectedFiles
|
||||
.concat(localizationTargets)
|
||||
.filter(f => !fs.existsSync(f));
|
||||
if (missingFiles.length > 0) {
|
||||
throw new Error("Cannot replace the LKG unless all built targets are present in directory 'built/local/'. The following files are missing:\n" + missingFiles.join("\n"));
|
||||
}
|
||||
const sizeBefore = getDirSize("lib");
|
||||
await exec(process.execPath, ["scripts/produceLKG.mjs"]);
|
||||
const sizeAfter = getDirSize("lib");
|
||||
if (sizeAfter > (sizeBefore * 1.10)) {
|
||||
throw new Error("The lib folder increased by 10% or more. This likely indicates a bug.");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export const lkg = task({
|
||||
name: "lkg",
|
||||
hiddenFromTaskList: true,
|
||||
dependencies: [produceLKG],
|
||||
});
|
||||
|
||||
export const generateSpec = task({
|
||||
name: "generate-spec",
|
||||
description: "Generates a Markdown version of the Language Specification",
|
||||
hiddenFromTaskList: true,
|
||||
run: () => exec("cscript", ["//nologo", "scripts/word2md.mjs", path.resolve("doc/TypeScript Language Specification - ARCHIVED.docx"), path.resolve("doc/spec-ARCHIVED.md")]),
|
||||
});
|
||||
|
||||
export const cleanBuilt = task({
|
||||
name: "clean-built",
|
||||
hiddenFromTaskList: true,
|
||||
run: () => del("built"),
|
||||
});
|
||||
|
||||
export const clean = task({
|
||||
name: "clean",
|
||||
description: "Cleans build outputs",
|
||||
dependencies: [cleanBuilt, cleanDiagnostics],
|
||||
});
|
||||
|
||||
export const configureNightly = task({
|
||||
name: "configure-nightly",
|
||||
description: "Runs scripts/configurePrerelease.mjs to prepare a build for nightly publishing",
|
||||
run: () => exec(process.execPath, ["scripts/configurePrerelease.mjs", "dev", "package.json", "src/compiler/corePublic.ts"]),
|
||||
});
|
||||
|
||||
export const configureInsiders = task({
|
||||
name: "configure-insiders",
|
||||
description: "Runs scripts/configurePrerelease.mjs to prepare a build for insiders publishing",
|
||||
run: () => exec(process.execPath, ["scripts/configurePrerelease.mjs", "insiders", "package.json", "src/compiler/corePublic.ts"]),
|
||||
});
|
||||
|
||||
export const configureExperimental = task({
|
||||
name: "configure-experimental",
|
||||
description: "Runs scripts/configurePrerelease.mjs to prepare a build for experimental publishing",
|
||||
run: () => exec(process.execPath, ["scripts/configurePrerelease.mjs", "experimental", "package.json", "src/compiler/corePublic.ts"]),
|
||||
});
|
||||
|
||||
export const help = task({
|
||||
name: "help",
|
||||
description: "Prints the top-level tasks.",
|
||||
hiddenFromTaskList: true,
|
||||
run: () => exec("hereby", ["--tasks"], { hidePrompt: true }),
|
||||
});
|
||||
+1
-1
@@ -2,4 +2,4 @@
|
||||
|
||||
**These files are not meant to be edited by hand.**
|
||||
If you need to make modifications, the respective files should be changed within the repository's top-level `src` directory.
|
||||
Running `gulp LKG` will then appropriately update the files in this directory.
|
||||
Running `hereby LKG` will then appropriately update the files in this directory.
|
||||
|
||||
Generated
+1106
-8877
File diff suppressed because it is too large
Load Diff
+12
-31
@@ -41,24 +41,15 @@
|
||||
"devDependencies": {
|
||||
"@octokit/rest": "latest",
|
||||
"@types/chai": "latest",
|
||||
"@types/fancy-log": "^2.0.0",
|
||||
"@types/fs-extra": "^9.0.13",
|
||||
"@types/glob": "latest",
|
||||
"@types/gulp": "^4.0.9",
|
||||
"@types/gulp-concat": "latest",
|
||||
"@types/gulp-newer": "latest",
|
||||
"@types/gulp-rename": "latest",
|
||||
"@types/gulp-sourcemaps": "latest",
|
||||
"@types/merge2": "latest",
|
||||
"@types/microsoft__typescript-etw": "latest",
|
||||
"@types/minimist": "latest",
|
||||
"@types/mkdirp": "latest",
|
||||
"@types/mocha": "latest",
|
||||
"@types/ms": "latest",
|
||||
"@types/node": "latest",
|
||||
"@types/source-map-support": "latest",
|
||||
"@types/which": "^2.0.1",
|
||||
"@types/xml2js": "^0.4.11",
|
||||
"@typescript-eslint/eslint-plugin": "^5.33.1",
|
||||
"@typescript-eslint/parser": "^5.33.1",
|
||||
"@typescript-eslint/utils": "^5.33.1",
|
||||
@@ -67,47 +58,37 @@
|
||||
"chalk": "^4.1.2",
|
||||
"del": "^6.1.1",
|
||||
"diff": "^5.1.0",
|
||||
"esbuild": "^0.15.13",
|
||||
"eslint": "^8.22.0",
|
||||
"eslint-formatter-autolinkable-stylish": "^1.2.0",
|
||||
"eslint-plugin-import": "^2.26.0",
|
||||
"eslint-plugin-jsdoc": "^39.3.6",
|
||||
"eslint-plugin-local": "^1.0.0",
|
||||
"eslint-plugin-no-null": "^1.0.2",
|
||||
"fancy-log": "latest",
|
||||
"fast-xml-parser": "^4.0.11",
|
||||
"fs-extra": "^9.1.0",
|
||||
"glob": "latest",
|
||||
"gulp": "^4.0.2",
|
||||
"gulp-concat": "latest",
|
||||
"gulp-insert": "latest",
|
||||
"gulp-newer": "latest",
|
||||
"gulp-rename": "latest",
|
||||
"gulp-sourcemaps": "latest",
|
||||
"merge2": "latest",
|
||||
"hereby": "^1.6.4",
|
||||
"jsonc-parser": "^3.2.0",
|
||||
"minimist": "latest",
|
||||
"mkdirp": "latest",
|
||||
"mocha": "latest",
|
||||
"mocha-fivemat-progress-reporter": "latest",
|
||||
"ms": "^2.1.3",
|
||||
"node-fetch": "^3.2.10",
|
||||
"source-map-support": "latest",
|
||||
"typescript": "^4.8.4",
|
||||
"vinyl": "latest",
|
||||
"which": "^2.0.2",
|
||||
"xml2js": "^0.4.23"
|
||||
},
|
||||
"overrides": {
|
||||
"es5-ext": "0.10.53"
|
||||
"which": "^2.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "gulp runtests-parallel --light=false",
|
||||
"test:eslint-rules": "gulp run-eslint-rules-tests",
|
||||
"test": "hereby runtests-parallel --light=false",
|
||||
"test:eslint-rules": "hereby run-eslint-rules-tests",
|
||||
"build": "npm run build:compiler && npm run build:tests",
|
||||
"build:compiler": "gulp local",
|
||||
"build:tests": "gulp tests",
|
||||
"build:compiler": "hereby local",
|
||||
"build:tests": "hereby tests",
|
||||
"start": "node lib/tsc",
|
||||
"clean": "gulp clean",
|
||||
"gulp": "gulp",
|
||||
"lint": "gulp lint",
|
||||
"clean": "hereby clean",
|
||||
"gulp": "hereby",
|
||||
"lint": "hereby lint",
|
||||
"setup-hooks": "node scripts/link-hooks.mjs"
|
||||
},
|
||||
"browser": {
|
||||
|
||||
@@ -26,4 +26,4 @@ export function findUpFile(name) {
|
||||
/** @type {string | undefined} */
|
||||
let findUpRootCache;
|
||||
|
||||
export const findUpRoot = () => findUpRootCache || (findUpRootCache = dirname(findUpFile("Gulpfile.mjs")));
|
||||
export const findUpRoot = () => findUpRootCache || (findUpRootCache = dirname(findUpFile("Herebyfile.mjs")));
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export const localizationDirectories = ["cs", "de", "es", "fr", "it", "ja", "ko", "pl", "pt-br", "ru", "tr", "zh-cn", "zh-tw"].map(f => f.toLowerCase());
|
||||
@@ -4,7 +4,7 @@ import os from "os";
|
||||
const ci = ["1", "true"].includes(process.env.CI ?? "");
|
||||
|
||||
const parsed = minimist(process.argv.slice(2), {
|
||||
boolean: ["dirty", "light", "colors", "lkg", "soft", "fix", "failed", "keepFailed", "force", "built", "ci"],
|
||||
boolean: ["dirty", "light", "colors", "lkg", "soft", "fix", "failed", "keepFailed", "force", "built", "ci", "bundle"],
|
||||
string: ["browser", "tests", "break", "host", "reporter", "stackTraceLimit", "timeout", "shards", "shardId"],
|
||||
alias: {
|
||||
/* eslint-disable quote-props */
|
||||
@@ -39,6 +39,7 @@ const parsed = minimist(process.argv.slice(2), {
|
||||
dirty: false,
|
||||
built: false,
|
||||
ci,
|
||||
bundle: true
|
||||
}
|
||||
});
|
||||
|
||||
@@ -77,5 +78,7 @@ export default options;
|
||||
* @property {boolean} ci
|
||||
* @property {string} shards
|
||||
* @property {string} shardId
|
||||
* @property {string} break
|
||||
* @property {boolean} bundle
|
||||
*/
|
||||
void 0;
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
import stream from "stream";
|
||||
import ts from "../../lib/typescript.js";
|
||||
import fs from "fs";
|
||||
import { base64VLQFormatEncode } from "./sourcemaps.mjs";
|
||||
|
||||
/**
|
||||
* @param {string | ((file: import("vinyl")) => string)} data
|
||||
*/
|
||||
export function prepend(data) {
|
||||
return new stream.Transform({
|
||||
objectMode: true,
|
||||
/**
|
||||
* @param {string | Buffer | import("vinyl")} input
|
||||
* @param {(error: Error | null, data?: any) => void} cb
|
||||
*/
|
||||
transform(input, _, cb) {
|
||||
if (typeof input === "string" || Buffer.isBuffer(input)) return cb(new Error("Only Vinyl files are supported."));
|
||||
if (!input.isBuffer()) return cb(new Error("Streams not supported."));
|
||||
try {
|
||||
const output = input.clone();
|
||||
const prependContent = typeof data === "function" ? data(input) : data;
|
||||
output.contents = Buffer.concat([Buffer.from(prependContent, "utf8"), input.contents]);
|
||||
if (input.sourceMap) {
|
||||
if (typeof input.sourceMap === "string") input.sourceMap = /**@type {import("./sourcemaps.mjs").RawSourceMap}*/(JSON.parse(input.sourceMap));
|
||||
const lineStarts = /**@type {*}*/(ts).computeLineStarts(prependContent);
|
||||
let prependMappings = "";
|
||||
for (let i = 1; i < lineStarts.length; i++) {
|
||||
prependMappings += ";";
|
||||
}
|
||||
const offset = prependContent.length - lineStarts[lineStarts.length - 1];
|
||||
if (offset > 0) {
|
||||
prependMappings += base64VLQFormatEncode(offset) + ",";
|
||||
}
|
||||
output.sourceMap = {
|
||||
version: input.sourceMap.version,
|
||||
file: input.sourceMap.file,
|
||||
sources: input.sourceMap.sources,
|
||||
sourceRoot: input.sourceMap.sourceRoot,
|
||||
mappings: prependMappings + input.sourceMap.mappings,
|
||||
names: input.names,
|
||||
sourcesContent: input.sourcesContent
|
||||
};
|
||||
}
|
||||
// eslint-disable-next-line local/boolean-trivia, no-null/no-null
|
||||
return cb(null, output);
|
||||
}
|
||||
catch (e) {
|
||||
return cb(/** @type {Error} */(e));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | ((file: import("vinyl")) => string)} file
|
||||
*/
|
||||
export function prependFile(file) {
|
||||
const data = typeof file === "string" ? fs.readFileSync(file, "utf8") :
|
||||
(/** @type {import("vinyl")} */ vinyl) => fs.readFileSync(file(vinyl), "utf8");
|
||||
return prepend(data);
|
||||
}
|
||||
+22
-34
@@ -1,69 +1,57 @@
|
||||
import { exec, Debouncer } from "./utils.mjs";
|
||||
import { resolve } from "path";
|
||||
import { findUpRoot } from "./findUpDir.mjs";
|
||||
import assert from "assert";
|
||||
import cmdLineOptions from "./options.mjs";
|
||||
|
||||
class ProjectQueue {
|
||||
/**
|
||||
* @param {(projects: string[], lkg: boolean, force: boolean) => Promise<any>} action
|
||||
* @param {(projects: string[]) => Promise<any>} action
|
||||
*/
|
||||
constructor(action) {
|
||||
/** @type {{ lkg: boolean, force: boolean, projects?: string[], debouncer: Debouncer }[]} */
|
||||
this._debouncers = [];
|
||||
this._action = action;
|
||||
/** @type {string[] | undefined} */
|
||||
this._projects = undefined;
|
||||
this._debouncer = new Debouncer(100, async () => {
|
||||
const projects = this._projects;
|
||||
if (projects) {
|
||||
this._projects = undefined;
|
||||
await action(projects);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} project
|
||||
* @param {{ lkg?: boolean; force?: boolean; }} options
|
||||
*/
|
||||
enqueue(project, { lkg = true, force = false } = {}) {
|
||||
let entry = this._debouncers.find(entry => entry.lkg === lkg && entry.force === force);
|
||||
if (!entry) {
|
||||
const debouncer = new Debouncer(100, async () => {
|
||||
assert(entry);
|
||||
const projects = entry.projects;
|
||||
if (projects) {
|
||||
entry.projects = undefined;
|
||||
await this._action(projects, lkg, force);
|
||||
}
|
||||
});
|
||||
this._debouncers.push(entry = { lkg, force, debouncer });
|
||||
}
|
||||
if (!entry.projects) entry.projects = [];
|
||||
entry.projects.push(project);
|
||||
return entry.debouncer.enqueue();
|
||||
enqueue(project) {
|
||||
if (!this._projects) this._projects = [];
|
||||
this._projects.push(project);
|
||||
return this._debouncer.enqueue();
|
||||
}
|
||||
}
|
||||
|
||||
const execTsc = (/** @type {boolean} */ lkg, /** @type {string[]} */ ...args) =>
|
||||
const execTsc = (/** @type {string[]} */ ...args) =>
|
||||
exec(process.execPath,
|
||||
[resolve(findUpRoot(), lkg ? "./lib/tsc" : "./built/local/tsc"),
|
||||
[resolve(findUpRoot(), cmdLineOptions.lkg ? "./lib/tsc.js" : "./built/local/tsc.js"),
|
||||
"-b", ...args],
|
||||
{ hidePrompt: true });
|
||||
|
||||
const projectBuilder = new ProjectQueue((projects, lkg, force) => execTsc(lkg, ...(force ? ["--force"] : []), ...projects));
|
||||
const projectBuilder = new ProjectQueue((projects) => execTsc(...projects));
|
||||
|
||||
/**
|
||||
* @param {string} project
|
||||
* @param {object} options
|
||||
* @param {boolean} [options.lkg=true]
|
||||
* @param {boolean} [options.force=false]
|
||||
*/
|
||||
export const buildProject = (project, { lkg, force } = {}) => projectBuilder.enqueue(project, { lkg, force });
|
||||
export const buildProject = (project) => projectBuilder.enqueue(project);
|
||||
|
||||
const projectCleaner = new ProjectQueue((projects, lkg) => execTsc(lkg, "--clean", ...projects));
|
||||
const projectCleaner = new ProjectQueue((projects) => execTsc("--clean", ...projects));
|
||||
|
||||
/**
|
||||
* @param {string} project
|
||||
*/
|
||||
export const cleanProject = (project) => projectCleaner.enqueue(project);
|
||||
|
||||
const projectWatcher = new ProjectQueue((projects) => execTsc(/*lkg*/ true, "--watch", ...projects));
|
||||
const projectWatcher = new ProjectQueue((projects) => execTsc("--watch", "--preserveWatchOutput", ...projects));
|
||||
|
||||
/**
|
||||
* @param {string} project
|
||||
* @param {object} options
|
||||
* @param {boolean} [options.lkg=true]
|
||||
*/
|
||||
export const watchProject = (project, { lkg } = {}) => projectWatcher.enqueue(project, { lkg });
|
||||
export const watchProject = (project) => projectWatcher.enqueue(project);
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
/**
|
||||
* @param {string} message
|
||||
* @returns {never}
|
||||
*/
|
||||
function fail(message) {
|
||||
throw new Error(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} value
|
||||
*/
|
||||
function base64FormatEncode(value) {
|
||||
return value < 0 ? fail("Invalid value") :
|
||||
value < 26 ? 0x41 /*A*/ + value :
|
||||
value < 52 ? 0x61 /*a*/ + value - 26 :
|
||||
value < 62 ? 0x30 /*0*/ + value - 52 :
|
||||
value === 62 ? 0x2B /*+*/ :
|
||||
value === 63 ? 0x2F /*/*/ :
|
||||
fail("Invalid value");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} value
|
||||
*/
|
||||
export function base64VLQFormatEncode(value) {
|
||||
if (value < 0) {
|
||||
value = ((-value) << 1) + 1;
|
||||
}
|
||||
else {
|
||||
value = value << 1;
|
||||
}
|
||||
|
||||
// Encode 5 bits at a time starting from least significant bits
|
||||
let result = "";
|
||||
do {
|
||||
let currentDigit = value & 31; // 11111
|
||||
value = value >> 5;
|
||||
if (value > 0) {
|
||||
// There are still more digits to decode, set the msb (6th bit)
|
||||
currentDigit = currentDigit | 32;
|
||||
}
|
||||
result += String.fromCharCode(base64FormatEncode(currentDigit));
|
||||
} while (value > 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/** @typedef {object} RawSourceMap */
|
||||
+5
-19
@@ -2,8 +2,6 @@ import del from "del";
|
||||
import fs from "fs";
|
||||
import os from "os";
|
||||
import path from "path";
|
||||
import mkdirP from "mkdirp";
|
||||
import log from "fancy-log";
|
||||
import cmdLineOptions from "./options.mjs";
|
||||
import { exec } from "./utils.mjs";
|
||||
import { findUpFile, findUpRoot } from "./findUpDir.mjs";
|
||||
@@ -19,9 +17,8 @@ export const localTest262Baseline = "internal/baselines/test262/local";
|
||||
* @param {string} runJs
|
||||
* @param {string} defaultReporter
|
||||
* @param {boolean} runInParallel
|
||||
* @param {boolean} _watchMode
|
||||
*/
|
||||
export async function runConsoleTests(runJs, defaultReporter, runInParallel, _watchMode) {
|
||||
export async function runConsoleTests(runJs, defaultReporter, runInParallel) {
|
||||
let testTimeout = cmdLineOptions.timeout;
|
||||
const tests = cmdLineOptions.tests;
|
||||
const inspect = cmdLineOptions.break || cmdLineOptions.inspect;
|
||||
@@ -122,17 +119,6 @@ export async function runConsoleTests(runJs, defaultReporter, runInParallel, _wa
|
||||
errorStatus = exitCode;
|
||||
error = new Error(`Process exited with status code ${errorStatus}.`);
|
||||
}
|
||||
else if (cmdLineOptions.ci && runJs.startsWith("built")) {
|
||||
// finally, do a sanity check and build the compiler with the built version of itself
|
||||
log.info("Starting sanity check build...");
|
||||
// Cleanup everything except lint rules (we'll need those later and would rather not waste time rebuilding them)
|
||||
await exec("gulp", ["clean-tsc", "clean-services", "clean-tsserver", "clean-lssl", "clean-tests"]);
|
||||
const { exitCode } = await exec("gulp", ["local", "--lkg=false"]);
|
||||
if (exitCode !== 0) {
|
||||
errorStatus = exitCode;
|
||||
error = new Error(`Sanity check build process exited with status code ${errorStatus}.`);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
errorStatus = undefined;
|
||||
@@ -153,12 +139,12 @@ export async function runConsoleTests(runJs, defaultReporter, runInParallel, _wa
|
||||
|
||||
export async function cleanTestDirs() {
|
||||
await del([localBaseline, localRwcBaseline]);
|
||||
mkdirP.sync(localRwcBaseline);
|
||||
mkdirP.sync(localBaseline);
|
||||
await fs.promises.mkdir(localRwcBaseline, { recursive: true });
|
||||
await fs.promises.mkdir(localBaseline, { recursive: true });
|
||||
}
|
||||
|
||||
/**
|
||||
* used to pass data from gulp command line directly to run.js
|
||||
* used to pass data from command line directly to run.js
|
||||
* @param {string} tests
|
||||
* @param {string} runners
|
||||
* @param {boolean} light
|
||||
@@ -184,7 +170,7 @@ export function writeTestConfigFile(tests, runners, light, taskConfigsFolder, wo
|
||||
shards,
|
||||
shardId
|
||||
});
|
||||
log.info("Running tests with config: " + testConfigContents);
|
||||
console.info("Running tests with config: " + testConfigContents);
|
||||
fs.writeFileSync("test.config", testConfigContents);
|
||||
}
|
||||
|
||||
|
||||
+21
-121
@@ -1,18 +1,12 @@
|
||||
/* eslint-disable no-restricted-globals */
|
||||
// eslint-disable-next-line @typescript-eslint/triple-slash-reference
|
||||
/// <reference path="../types/ambient.d.ts" />
|
||||
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import log from "fancy-log";
|
||||
import del from "del";
|
||||
import File from "vinyl";
|
||||
import ts from "../../lib/typescript.js";
|
||||
import chalk from "chalk";
|
||||
import which from "which";
|
||||
import { spawn } from "child_process";
|
||||
import { Duplex } from "stream";
|
||||
import assert from "assert";
|
||||
import JSONC from "jsonc-parser";
|
||||
|
||||
/**
|
||||
* Executes the provided command once with the supplied arguments.
|
||||
@@ -29,7 +23,7 @@ export async function exec(cmd, args, options = {}) {
|
||||
return /**@type {Promise<{exitCode?: number}>}*/(new Promise((resolve, reject) => {
|
||||
const { ignoreExitCode, waitForExit = true } = options;
|
||||
|
||||
if (!options.hidePrompt) log(`> ${chalk.green(cmd)} ${args.join(" ")}`);
|
||||
if (!options.hidePrompt) console.log(`> ${chalk.green(cmd)} ${args.join(" ")}`);
|
||||
const proc = spawn(which.sync(cmd), args, { stdio: waitForExit ? "inherit" : "ignore" });
|
||||
if (waitForExit) {
|
||||
proc.on("exit", exitCode => {
|
||||
@@ -52,48 +46,13 @@ export async function exec(cmd, args, options = {}) {
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ts.Diagnostic[]} diagnostics
|
||||
* @param {{ cwd?: string, pretty?: boolean }} [options]
|
||||
*/
|
||||
function formatDiagnostics(diagnostics, options) {
|
||||
return options && options.pretty
|
||||
? ts.formatDiagnosticsWithColorAndContext(diagnostics, getFormatDiagnosticsHost(options && options.cwd))
|
||||
: ts.formatDiagnostics(diagnostics, getFormatDiagnosticsHost(options && options.cwd));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ts.Diagnostic[]} diagnostics
|
||||
* @param {{ cwd?: string }} [options]
|
||||
*/
|
||||
function reportDiagnostics(diagnostics, options) {
|
||||
log(formatDiagnostics(diagnostics, { cwd: options && options.cwd, pretty: process.stdout.isTTY }));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | undefined} cwd
|
||||
* @returns {ts.FormatDiagnosticsHost}
|
||||
*/
|
||||
function getFormatDiagnosticsHost(cwd) {
|
||||
return {
|
||||
getCanonicalFileName: fileName => fileName,
|
||||
getCurrentDirectory: () => cwd ?? process.cwd(),
|
||||
getNewLine: () => ts.sys.newLine,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads JSON data with optional comments using the LKG TypeScript compiler
|
||||
* @param {string} jsonPath
|
||||
*/
|
||||
export function readJson(jsonPath) {
|
||||
const jsonText = fs.readFileSync(jsonPath, "utf8");
|
||||
const result = ts.parseConfigFileTextToJson(jsonPath, jsonText);
|
||||
if (result.error) {
|
||||
reportDiagnostics([result.error]);
|
||||
throw new Error("An error occurred during parse.");
|
||||
}
|
||||
return result.config;
|
||||
return JSONC.parse(jsonText);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,7 +126,7 @@ export function needsUpdate(source, dest) {
|
||||
export function getDiffTool() {
|
||||
const program = process.env.DIFF;
|
||||
if (!program) {
|
||||
log.warn("Add the 'DIFF' environment variable to the path of the program you want to use.");
|
||||
console.warn("Add the 'DIFF' environment variable to the path of the program you want to use.");
|
||||
process.exit(1);
|
||||
}
|
||||
return program;
|
||||
@@ -191,82 +150,6 @@ export function getDirSize(root) {
|
||||
.reduce((acc, num) => acc + num, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string | ((file: File) => string) | { cwd?: string }} [dest]
|
||||
* @param {{ cwd?: string }} [opts]
|
||||
*/
|
||||
export function rm(dest, opts) {
|
||||
if (dest && typeof dest === "object") {
|
||||
opts = dest;
|
||||
dest = undefined;
|
||||
}
|
||||
let failed = false;
|
||||
|
||||
const cwd = path.resolve(opts && opts.cwd || process.cwd());
|
||||
|
||||
/** @type {{ file: File, deleted: boolean, promise: Promise<any>, cb: Function }[]} */
|
||||
const pending = [];
|
||||
|
||||
const processDeleted = () => {
|
||||
if (failed) return;
|
||||
while (pending.length && pending[0].deleted) {
|
||||
const fileAndCallback = pending.shift();
|
||||
assert(fileAndCallback);
|
||||
const { file, cb } = fileAndCallback;
|
||||
duplex.push(file);
|
||||
cb();
|
||||
}
|
||||
};
|
||||
|
||||
const duplex = new Duplex({
|
||||
objectMode: true,
|
||||
/**
|
||||
* @param {string|Buffer|File} file
|
||||
*/
|
||||
write(file, _, cb) {
|
||||
if (failed) return;
|
||||
if (typeof file === "string" || Buffer.isBuffer(file)) return cb(new Error("Only Vinyl files are supported."));
|
||||
const basePath = typeof dest === "string" ? path.resolve(cwd, dest) :
|
||||
typeof dest === "function" ? path.resolve(cwd, dest(file)) :
|
||||
file.base;
|
||||
const filePath = path.resolve(basePath, file.relative);
|
||||
file.cwd = cwd;
|
||||
file.base = basePath;
|
||||
file.path = filePath;
|
||||
const entry = {
|
||||
file,
|
||||
deleted: false,
|
||||
cb,
|
||||
promise: del(file.path).then(() => {
|
||||
entry.deleted = true;
|
||||
processDeleted();
|
||||
}, err => {
|
||||
failed = true;
|
||||
pending.length = 0;
|
||||
cb(err);
|
||||
})
|
||||
};
|
||||
pending.push(entry);
|
||||
},
|
||||
final(cb) {
|
||||
// eslint-disable-next-line no-null/no-null
|
||||
const endThenCb = () => (duplex.push(null), cb()); // signal end of read queue
|
||||
processDeleted();
|
||||
if (pending.length) {
|
||||
Promise
|
||||
.all(pending.map(entry => entry.promise))
|
||||
.then(() => processDeleted())
|
||||
.then(() => endThenCb(), endThenCb);
|
||||
return;
|
||||
}
|
||||
endThenCb();
|
||||
},
|
||||
read() {
|
||||
}
|
||||
});
|
||||
return duplex;
|
||||
}
|
||||
|
||||
class Deferred {
|
||||
constructor() {
|
||||
this.promise = new Promise((resolve, reject) => {
|
||||
@@ -317,3 +200,20 @@ export class Debouncer {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const unset = Symbol();
|
||||
/**
|
||||
* @template T
|
||||
* @param {() => T} fn
|
||||
* @returns {() => T}
|
||||
*/
|
||||
export function memoize(fn) {
|
||||
/** @type {T | unset} */
|
||||
let value = unset;
|
||||
return () => {
|
||||
if (value === unset) {
|
||||
value = fn();
|
||||
}
|
||||
return value;
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,260 +0,0 @@
|
||||
import ts from "../lib/typescript.js";
|
||||
import path from "path";
|
||||
import assert from "assert";
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} s
|
||||
* @param {string} suffix
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function endsWith(s, suffix) {
|
||||
return s.lastIndexOf(suffix, s.length - suffix.length) !== -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ts.EnumDeclaration} declaration
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isStringEnum(declaration) {
|
||||
return !!declaration.members.length && declaration.members.every(m => !!m.initializer && m.initializer.kind === ts.SyntaxKind.StringLiteral);
|
||||
}
|
||||
|
||||
class DeclarationsWalker {
|
||||
/**
|
||||
* @type {ts.Type[]}
|
||||
* @private
|
||||
*/
|
||||
visitedTypes = [];
|
||||
/**
|
||||
* @type {string}
|
||||
* @private
|
||||
*/
|
||||
text = "";
|
||||
/**
|
||||
* @type {ts.Type[]}
|
||||
* @private
|
||||
*/
|
||||
removedTypes = [];
|
||||
|
||||
/**
|
||||
* @param {ts.TypeChecker} typeChecker
|
||||
* @param {ts.SourceFile} protocolFile
|
||||
* @private
|
||||
*/
|
||||
constructor(typeChecker, protocolFile) {
|
||||
this.typeChecker = typeChecker;
|
||||
this.protocolFile = protocolFile;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {ts.TypeChecker} typeChecker
|
||||
* @param {ts.SourceFile} protocolFile
|
||||
* @returns {string}
|
||||
*/
|
||||
static getExtraDeclarations(typeChecker, protocolFile) {
|
||||
const walker = new DeclarationsWalker(typeChecker, protocolFile);
|
||||
walker.visitTypeNodes(protocolFile);
|
||||
let text = walker.text
|
||||
? `declare namespace ts.server.protocol {\n${walker.text}}`
|
||||
: "";
|
||||
if (walker.removedTypes) {
|
||||
text += "\ndeclare namespace ts {\n";
|
||||
text += " // these types are empty stubs for types from services and should not be used directly\n";
|
||||
for (const type of walker.removedTypes) {
|
||||
text += ` export type ${type.symbol.name} = never;\n`;
|
||||
}
|
||||
text += "}";
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ts.Type} type
|
||||
* @returns {void}
|
||||
* @private
|
||||
*/
|
||||
processType(type) {
|
||||
if (this.visitedTypes.indexOf(type) >= 0) {
|
||||
return;
|
||||
}
|
||||
this.visitedTypes.push(type);
|
||||
const s = type.aliasSymbol || type.getSymbol();
|
||||
if (!s) {
|
||||
return;
|
||||
}
|
||||
if (s.name === "Array" || s.name === "ReadOnlyArray") {
|
||||
// we should process type argument instead
|
||||
return this.processType(/** @type {any} */(type).typeArguments[0]);
|
||||
}
|
||||
else {
|
||||
const declarations = s.getDeclarations();
|
||||
if (declarations) {
|
||||
for (const decl of declarations) {
|
||||
const sourceFile = decl.getSourceFile();
|
||||
if (sourceFile === this.protocolFile || /lib(\..+)?\.d.ts/.test(path.basename(sourceFile.fileName))) {
|
||||
return;
|
||||
}
|
||||
if (ts.isEnumDeclaration(decl) && !isStringEnum(decl)) {
|
||||
this.removedTypes.push(type);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
// splice declaration in final d.ts file
|
||||
const text = decl.getFullText();
|
||||
this.text += `${text}\n`;
|
||||
// recursively pull all dependencies into result dts file
|
||||
|
||||
this.visitTypeNodes(decl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ts.Node} node
|
||||
* @private
|
||||
*/
|
||||
visitTypeNodes(node) {
|
||||
if (node.parent) {
|
||||
switch (node.parent.kind) {
|
||||
case ts.SyntaxKind.VariableDeclaration:
|
||||
case ts.SyntaxKind.MethodDeclaration:
|
||||
case ts.SyntaxKind.MethodSignature:
|
||||
case ts.SyntaxKind.PropertyDeclaration:
|
||||
case ts.SyntaxKind.PropertySignature:
|
||||
case ts.SyntaxKind.Parameter:
|
||||
case ts.SyntaxKind.IndexSignature:
|
||||
const parent = /** @type {ts.VariableDeclaration | ts.MethodDeclaration | ts.PropertyDeclaration | ts.ParameterDeclaration | ts.PropertySignature | ts.MethodSignature | ts.IndexSignatureDeclaration} */ (node.parent);
|
||||
if (parent.type === node) {
|
||||
this.processTypeOfNode(node);
|
||||
}
|
||||
break;
|
||||
case ts.SyntaxKind.InterfaceDeclaration:
|
||||
const heritageClauses = /** @type {ts.InterfaceDeclaration} */ (node.parent).heritageClauses;
|
||||
if (heritageClauses) {
|
||||
if (heritageClauses[0].token !== ts.SyntaxKind.ExtendsKeyword) {
|
||||
throw new Error(`Unexpected kind of heritage clause: ${ts.SyntaxKind[heritageClauses[0].kind]}`);
|
||||
}
|
||||
for (const type of heritageClauses[0].types) {
|
||||
this.processTypeOfNode(type);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
ts.forEachChild(node, n => this.visitTypeNodes(n));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ts.Node} node
|
||||
* @private
|
||||
*/
|
||||
processTypeOfNode(node) {
|
||||
if (node.kind === ts.SyntaxKind.UnionType) {
|
||||
for (const t of /** @type {ts.UnionTypeNode} */ (node).types) {
|
||||
this.processTypeOfNode(t);
|
||||
}
|
||||
}
|
||||
else {
|
||||
const type = this.typeChecker.getTypeAtLocation(node);
|
||||
if (type && !(type.flags & (ts.TypeFlags.TypeParameter))) {
|
||||
this.processType(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} outputFile
|
||||
* @param {string} protocolTs
|
||||
* @param {string} typeScriptServicesDts
|
||||
*/
|
||||
function writeProtocolFile(outputFile, protocolTs, typeScriptServicesDts) {
|
||||
/** @type {ts.CompilerOptions} */
|
||||
const options = { target: ts.ScriptTarget.ES5, declaration: true, noResolve: false, types: [], stripInternal: true };
|
||||
|
||||
/**
|
||||
* 1st pass - generate a program from protocol.ts and typescriptservices.d.ts and emit core version of protocol.d.ts with all internal members stripped
|
||||
* @return text of protocol.d.t.s
|
||||
*/
|
||||
function getInitialDtsFileForProtocol() {
|
||||
const program = ts.createProgram([protocolTs, typeScriptServicesDts, path.join(typeScriptServicesDts, "../lib.es5.d.ts")], options);
|
||||
|
||||
/** @type {string | undefined} */
|
||||
let protocolDts;
|
||||
const emitResult = program.emit(program.getSourceFile(protocolTs), (file, content) => {
|
||||
if (endsWith(file, ".d.ts")) {
|
||||
protocolDts = content;
|
||||
}
|
||||
});
|
||||
|
||||
if (protocolDts === undefined) {
|
||||
/** @type {ts.FormatDiagnosticsHost} */
|
||||
const diagHost = {
|
||||
getCanonicalFileName(f) { return f; },
|
||||
getCurrentDirectory() { return "."; },
|
||||
getNewLine() { return "\r\n"; }
|
||||
};
|
||||
const diags = emitResult.diagnostics.map(d => ts.formatDiagnostic(d, diagHost)).join("\r\n");
|
||||
throw new Error(`Declaration file for protocol.ts is not generated:\r\n${diags}`);
|
||||
}
|
||||
return protocolDts;
|
||||
}
|
||||
|
||||
const protocolFileName = "protocol.d.ts";
|
||||
/**
|
||||
* Second pass - generate a program from protocol.d.ts and typescriptservices.d.ts, then augment core protocol.d.ts with extra types from typescriptservices.d.ts
|
||||
* @param {string} protocolDts
|
||||
* @param {boolean} includeTypeScriptServices
|
||||
*/
|
||||
function getProgramWithProtocolText(protocolDts, includeTypeScriptServices) {
|
||||
const host = ts.createCompilerHost(options);
|
||||
const originalGetSourceFile = host.getSourceFile;
|
||||
host.getSourceFile = (fileName) => {
|
||||
if (fileName === protocolFileName) {
|
||||
assert(options.target !== undefined);
|
||||
return ts.createSourceFile(fileName, protocolDts, options.target);
|
||||
}
|
||||
return originalGetSourceFile.apply(host, [fileName, ts.ScriptTarget.Latest]);
|
||||
};
|
||||
const rootFiles = includeTypeScriptServices ? [protocolFileName, typeScriptServicesDts] : [protocolFileName];
|
||||
return ts.createProgram(rootFiles, options, host);
|
||||
}
|
||||
|
||||
let protocolDts = getInitialDtsFileForProtocol();
|
||||
const program = getProgramWithProtocolText(protocolDts, /*includeTypeScriptServices*/ true);
|
||||
|
||||
const protocolFile = program.getSourceFile("protocol.d.ts");
|
||||
assert(protocolFile);
|
||||
const extraDeclarations = DeclarationsWalker.getExtraDeclarations(program.getTypeChecker(), protocolFile);
|
||||
if (extraDeclarations) {
|
||||
protocolDts += extraDeclarations;
|
||||
}
|
||||
protocolDts += "\nimport protocol = ts.server.protocol;";
|
||||
protocolDts += "\nexport = protocol;";
|
||||
protocolDts += "\nexport as namespace protocol;";
|
||||
|
||||
// do sanity check and try to compile generated text as standalone program
|
||||
const sanityCheckProgram = getProgramWithProtocolText(protocolDts, /*includeTypeScriptServices*/ false);
|
||||
const diagnostics = [...sanityCheckProgram.getSyntacticDiagnostics(), ...sanityCheckProgram.getSemanticDiagnostics(), ...sanityCheckProgram.getGlobalDiagnostics()];
|
||||
|
||||
ts.sys.writeFile(outputFile, protocolDts);
|
||||
|
||||
if (diagnostics.length) {
|
||||
const flattenedDiagnostics = diagnostics.map(d => `${ts.flattenDiagnosticMessageText(d.messageText, "\n")} at ${d.file ? d.file.fileName : "<unknown>"} line ${d.start}`).join("\n");
|
||||
throw new Error(`Unexpected errors during sanity check: ${flattenedDiagnostics}`);
|
||||
}
|
||||
}
|
||||
|
||||
if (process.argv.length < 5) {
|
||||
console.log(`Expected 3 arguments: path to 'protocol.ts', path to 'typescriptservices.d.ts' and path to output file`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
const protocolTs = process.argv[2];
|
||||
const typeScriptServicesDts = process.argv[3];
|
||||
const outputFile = process.argv[4];
|
||||
writeProtocolFile(outputFile, protocolTs, typeScriptServicesDts);
|
||||
@@ -0,0 +1,413 @@
|
||||
/**
|
||||
* WARNING: this is a very, very rudimentary d.ts bundler; it only works
|
||||
* in the TS project thanks to our history using namespaces, which has
|
||||
* prevented us from duplicating names across files, and allows us to
|
||||
* bundle as namespaces again, even though the project is modules.
|
||||
*/
|
||||
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import minimist from "minimist";
|
||||
import url from "url";
|
||||
import ts from "../lib/typescript.js";
|
||||
import assert, { fail } from "assert";
|
||||
|
||||
const __filename = url.fileURLToPath(new URL(import.meta.url));
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
// /** @type {any} */ (ts).Debug.enableDebugInfo();
|
||||
|
||||
const dotDts = ".d.ts";
|
||||
|
||||
const options = minimist(process.argv.slice(2), {
|
||||
string: ["project", "entrypoint", "output"],
|
||||
});
|
||||
|
||||
const entrypoint = options.entrypoint;
|
||||
const output = options.output;
|
||||
|
||||
assert(typeof entrypoint === "string" && entrypoint);
|
||||
assert(typeof output === "string" && output);
|
||||
assert(output.endsWith(dotDts));
|
||||
|
||||
const internalOutput = output.substring(0, output.length - dotDts.length) + ".internal" + dotDts;
|
||||
|
||||
console.log(`Bundling ${entrypoint} to ${output} and ${internalOutput}`);
|
||||
|
||||
const newLineKind = ts.NewLineKind.LineFeed;
|
||||
const newLine = newLineKind === ts.NewLineKind.LineFeed ? "\n" : "\r\n";
|
||||
|
||||
/** @type {(node: ts.Node) => node is ts.DeclarationStatement} */
|
||||
function isDeclarationStatement(node) {
|
||||
return /** @type {any} */ (ts).isDeclarationStatement(node);
|
||||
}
|
||||
|
||||
/** @type {(node: ts.Node) => boolean} */
|
||||
function isInternalDeclaration(node) {
|
||||
return /** @type {any} */ (ts).isInternalDeclaration(node, node.getSourceFile());
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {ts.VariableDeclaration} node
|
||||
* @returns {ts.VariableStatement}
|
||||
*/
|
||||
function getParentVariableStatement(node) {
|
||||
const declarationList = node.parent;
|
||||
assert(ts.isVariableDeclarationList(declarationList), `expected VariableDeclarationList at ${nodeToLocation(node)}`);
|
||||
assert(declarationList.declarations.length === 1, `expected VariableDeclarationList of length 1 at ${nodeToLocation(node)}`);
|
||||
const variableStatement = declarationList.parent;
|
||||
assert(ts.isVariableStatement(variableStatement), `expected VariableStatement at ${nodeToLocation(node)}`);
|
||||
return variableStatement;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {ts.Declaration} node
|
||||
* @returns {ts.Statement | undefined}
|
||||
*/
|
||||
function getDeclarationStatement(node) {
|
||||
if (ts.isVariableDeclaration(node)) {
|
||||
return getParentVariableStatement(node);
|
||||
}
|
||||
else if (isDeclarationStatement(node)) {
|
||||
return node;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** @type {ts.TransformationContext} */
|
||||
const nullTransformationContext = /** @type {any} */ (ts).nullTransformationContext;
|
||||
|
||||
const program = ts.createProgram([entrypoint], { target: ts.ScriptTarget.ES5 });
|
||||
|
||||
const typeChecker = program.getTypeChecker();
|
||||
|
||||
const sourceFile = program.getSourceFile(entrypoint);
|
||||
assert(sourceFile, "Failed to load source file");
|
||||
const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
|
||||
assert(moduleSymbol, "Failed to get module's symbol");
|
||||
|
||||
const printer = ts.createPrinter({ newLine: newLineKind });
|
||||
|
||||
/** @type {string[]} */
|
||||
const publicLines = [];
|
||||
/** @type {string[]} */
|
||||
const internalLines = [];
|
||||
|
||||
const indent = " ";
|
||||
let currentIndent = "";
|
||||
|
||||
function increaseIndent() {
|
||||
currentIndent += indent;
|
||||
}
|
||||
|
||||
function decreaseIndent() {
|
||||
currentIndent = currentIndent.slice(indent.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* @enum {number}
|
||||
*/
|
||||
const WriteTarget = {
|
||||
Public: 1 << 0,
|
||||
Internal: 1 << 1,
|
||||
Both: (1 << 0) | (1 << 1),
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} s
|
||||
* @param {WriteTarget} target
|
||||
*/
|
||||
function write(s, target) {
|
||||
if (!target) {
|
||||
return;
|
||||
}
|
||||
|
||||
const toPush = !s ? [""] : s.split(/\r?\n/).filter(line => line).map(line => (currentIndent + line).trimEnd());
|
||||
|
||||
if (target & WriteTarget.Public) {
|
||||
publicLines.push(...toPush);
|
||||
}
|
||||
if (target & WriteTarget.Internal) {
|
||||
internalLines.push(...toPush);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ts.Node} node
|
||||
* @param {ts.SourceFile} sourceFile
|
||||
* @param {WriteTarget} target
|
||||
*/
|
||||
function writeNode(node, sourceFile, target) {
|
||||
write(printer.printNode(ts.EmitHint.Unspecified, node, sourceFile), target);
|
||||
}
|
||||
|
||||
/** @type {Map<ts.Symbol, boolean>} */
|
||||
const containsPublicAPICache = new Map();
|
||||
|
||||
/**
|
||||
* @param {ts.Symbol} symbol
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function containsPublicAPI(symbol) {
|
||||
const cached = containsPublicAPICache.get(symbol);
|
||||
if (cached !== undefined) {
|
||||
return cached;
|
||||
}
|
||||
|
||||
const result = containsPublicAPIWorker();
|
||||
containsPublicAPICache.set(symbol, result);
|
||||
return result;
|
||||
|
||||
function containsPublicAPIWorker() {
|
||||
if (!symbol.declarations?.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (symbol.flags & ts.SymbolFlags.Alias) {
|
||||
const resolved = typeChecker.getAliasedSymbol(symbol);
|
||||
return containsPublicAPI(resolved);
|
||||
}
|
||||
|
||||
// Namespace barrel; actual namespaces are checked below.
|
||||
if (symbol.flags & ts.SymbolFlags.ValueModule && symbol.valueDeclaration?.kind === ts.SyntaxKind.SourceFile) {
|
||||
for (const me of typeChecker.getExportsOfModule(symbol)) {
|
||||
if (containsPublicAPI(me)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const decl of symbol.declarations) {
|
||||
const statement = getDeclarationStatement(decl);
|
||||
if (statement && !isInternalDeclaration(statement)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ts.Node} node
|
||||
*/
|
||||
function nodeToLocation(node) {
|
||||
const sourceFile = node.getSourceFile();
|
||||
const lc = sourceFile.getLineAndCharacterOfPosition(node.pos);
|
||||
return `${sourceFile.fileName}:${lc.line+1}:${lc.character+1}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ts.Node} node
|
||||
* @returns {ts.Node | undefined}
|
||||
*/
|
||||
function removeDeclareConstExport(node) {
|
||||
switch (node.kind) {
|
||||
case ts.SyntaxKind.DeclareKeyword: // No need to emit this in d.ts files.
|
||||
case ts.SyntaxKind.ConstKeyword: // Remove const from const enums.
|
||||
case ts.SyntaxKind.ExportKeyword: // No export modifier; we are already in the namespace.
|
||||
return undefined;
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/** @type {Map<string, ts.Symbol>[]} */
|
||||
const scopeStack = [];
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
function findInScope(name) {
|
||||
for (let i = scopeStack.length-1; i >= 0; i--) {
|
||||
const scope = scopeStack[i];
|
||||
const symbol = scope.get(name);
|
||||
if (symbol) {
|
||||
return symbol;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/** @type {(symbol: ts.Symbol | undefined, excludes?: ts.SymbolFlags) => boolean} */
|
||||
function isNonLocalAlias(symbol, excludes = ts.SymbolFlags.Value | ts.SymbolFlags.Type | ts.SymbolFlags.Namespace) {
|
||||
if (!symbol) return false;
|
||||
return (symbol.flags & (ts.SymbolFlags.Alias | excludes)) === ts.SymbolFlags.Alias || !!(symbol.flags & ts.SymbolFlags.Alias && symbol.flags & ts.SymbolFlags.Assignment);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ts.Symbol} symbol
|
||||
*/
|
||||
function resolveAlias(symbol) {
|
||||
return typeChecker.getAliasedSymbol(symbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ts.Symbol} symbol
|
||||
* @param {boolean | undefined} [dontResolveAlias]
|
||||
*/
|
||||
function resolveSymbol(symbol, dontResolveAlias = undefined) {
|
||||
return !dontResolveAlias && isNonLocalAlias(symbol) ? resolveAlias(symbol) : symbol;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ts.Symbol} symbol
|
||||
* @returns {ts.Symbol}
|
||||
*/
|
||||
function getMergedSymbol(symbol) {
|
||||
return /** @type {any} */ (typeChecker).getMergedSymbol(symbol);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ts.Symbol} s1
|
||||
* @param {ts.Symbol} s2
|
||||
*/
|
||||
function symbolsConflict(s1, s2) {
|
||||
// See getSymbolIfSameReference in checker.ts
|
||||
s1 = getMergedSymbol(resolveSymbol(getMergedSymbol(s1)));
|
||||
s2 = getMergedSymbol(resolveSymbol(getMergedSymbol(s2)));
|
||||
if (s1 === s2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const s1Flags = s1.flags & (ts.SymbolFlags.Type | ts.SymbolFlags.Value);
|
||||
const s2Flags = s2.flags & (ts.SymbolFlags.Type | ts.SymbolFlags.Value);
|
||||
|
||||
// If the two symbols differ by type/value space, ignore.
|
||||
if (!(s1Flags & s2Flags)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ts.Node} node
|
||||
* @returns {boolean}
|
||||
*/
|
||||
function isPartOfTypeNode(node) {
|
||||
return /** @type {any} */ (ts).isPartOfTypeNode(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ts.Statement} decl
|
||||
*/
|
||||
function verifyMatchingSymbols(decl) {
|
||||
ts.visitEachChild(decl, /** @type {(node: ts.Node) => ts.Node} */ function visit(node) {
|
||||
if (ts.isIdentifier(node) && isPartOfTypeNode(node)) {
|
||||
if (ts.isQualifiedName(node.parent) && node !== node.parent.left) {
|
||||
return node;
|
||||
}
|
||||
if (ts.isParameter(node.parent) && node === node.parent.name) {
|
||||
return node;
|
||||
}
|
||||
if (ts.isNamedTupleMember(node.parent) && node === node.parent.name) {
|
||||
return node;
|
||||
}
|
||||
|
||||
const symbolOfNode = typeChecker.getSymbolAtLocation(node);
|
||||
if (!symbolOfNode) {
|
||||
fail(`No symbol for node at ${nodeToLocation(node)}`);
|
||||
}
|
||||
const symbolInScope = findInScope(symbolOfNode.name);
|
||||
if (!symbolInScope) {
|
||||
// We didn't find the symbol in scope at all. Just allow it and we'll fail at test time.
|
||||
return node;
|
||||
}
|
||||
|
||||
if (symbolsConflict(symbolOfNode, symbolInScope)) {
|
||||
fail(`Declaration at ${nodeToLocation(decl)}\n references ${symbolOfNode.name} at ${symbolOfNode.declarations && nodeToLocation(symbolOfNode.declarations[0])},\n but containing scope contains a symbol with the same name declared at ${symbolInScope.declarations && nodeToLocation(symbolInScope.declarations[0])}`);
|
||||
}
|
||||
}
|
||||
|
||||
return ts.visitEachChild(node, visit, nullTransformationContext);
|
||||
}, nullTransformationContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
* @param {ts.Symbol} moduleSymbol
|
||||
*/
|
||||
function emitAsNamespace(name, moduleSymbol) {
|
||||
assert(moduleSymbol.flags & ts.SymbolFlags.ValueModule, "moduleSymbol is not a module");
|
||||
|
||||
scopeStack.push(new Map());
|
||||
const currentScope = scopeStack[scopeStack.length-1];
|
||||
|
||||
const target = containsPublicAPI(moduleSymbol) ? WriteTarget.Both : WriteTarget.Internal;
|
||||
|
||||
if (name === "ts") {
|
||||
// We will write `export = ts` at the end.
|
||||
write(`declare namespace ${name} {`, target);
|
||||
}
|
||||
else {
|
||||
// No export modifier; we are already in the namespace.
|
||||
write(`namespace ${name} {`, target);
|
||||
}
|
||||
increaseIndent();
|
||||
|
||||
const moduleExports = typeChecker.getExportsOfModule(moduleSymbol);
|
||||
for (const me of moduleExports) {
|
||||
currentScope.set(me.name, me);
|
||||
}
|
||||
|
||||
for (const me of moduleExports) {
|
||||
assert(me.declarations?.length);
|
||||
|
||||
if (me.flags & ts.SymbolFlags.Alias) {
|
||||
const resolved = typeChecker.getAliasedSymbol(me);
|
||||
emitAsNamespace(me.name, resolved);
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const decl of me.declarations) {
|
||||
const statement = getDeclarationStatement(decl);
|
||||
const sourceFile = decl.getSourceFile();
|
||||
|
||||
if (!statement) {
|
||||
fail(`Unhandled declaration for ${me.name} at ${nodeToLocation(decl)}`);
|
||||
}
|
||||
|
||||
verifyMatchingSymbols(statement);
|
||||
|
||||
const isInternal = isInternalDeclaration(statement);
|
||||
if (!isInternal) {
|
||||
const publicStatement = ts.visitEachChild(statement, (node) => {
|
||||
// No @internal comments in the public API.
|
||||
if (isInternalDeclaration(node)) {
|
||||
return undefined;
|
||||
}
|
||||
return removeDeclareConstExport(node);
|
||||
}, nullTransformationContext);
|
||||
|
||||
writeNode(publicStatement, sourceFile, WriteTarget.Public);
|
||||
}
|
||||
|
||||
const internalStatement = ts.visitEachChild(statement, removeDeclareConstExport, nullTransformationContext);
|
||||
|
||||
writeNode(internalStatement, sourceFile, WriteTarget.Internal);
|
||||
}
|
||||
}
|
||||
|
||||
scopeStack.pop();
|
||||
|
||||
decreaseIndent();
|
||||
write(`}`, target);
|
||||
}
|
||||
|
||||
emitAsNamespace("ts", moduleSymbol);
|
||||
|
||||
write("export = ts;", WriteTarget.Both);
|
||||
|
||||
const copyrightNotice = fs.readFileSync(path.join(__dirname, "..", "CopyrightNotice.txt"), "utf-8");
|
||||
const publicContents = copyrightNotice + publicLines.join(newLine);
|
||||
const internalContents = copyrightNotice + internalLines.join(newLine);
|
||||
|
||||
if (publicContents.includes("@internal")) {
|
||||
console.error("Output includes untrimmed @internal nodes!");
|
||||
}
|
||||
|
||||
fs.writeFileSync(output, publicContents);
|
||||
fs.writeFileSync(internalOutput, internalContents);
|
||||
@@ -0,0 +1,110 @@
|
||||
const { TSESTree } = require("@typescript-eslint/utils");
|
||||
const { createRule } = require("./utils.cjs");
|
||||
|
||||
module.exports = createRule({
|
||||
name: "jsdoc-format",
|
||||
meta: {
|
||||
docs: {
|
||||
description: ``,
|
||||
recommended: "error",
|
||||
},
|
||||
messages: {
|
||||
internalCommentInNonJSDocError: `@internal should not appear in non-JSDoc comment for declaration.`,
|
||||
internalCommentNotLastError: `@internal should only appear in final JSDoc comment for declaration.`,
|
||||
multipleJSDocError: `Declaration has multiple JSDoc comments.`,
|
||||
internalCommentOnParameterProperty: `@internal cannot appear on a JSDoc comment; use a declared property and an assignment in the constructor instead.`,
|
||||
},
|
||||
schema: [],
|
||||
type: "problem",
|
||||
},
|
||||
defaultOptions: [],
|
||||
|
||||
create(context) {
|
||||
const sourceCode = context.getSourceCode();
|
||||
const atInternal = "@internal";
|
||||
const jsdocStart = "/**";
|
||||
|
||||
/** @type {(c: TSESTree.Comment, indexInComment: number) => TSESTree.SourceLocation} */
|
||||
const getAtInternalLoc = (c, indexInComment) => {
|
||||
const line = c.loc.start.line;
|
||||
return {
|
||||
start: {
|
||||
line,
|
||||
column: c.loc.start.column + indexInComment,
|
||||
},
|
||||
end: {
|
||||
line,
|
||||
column: c.loc.start.column + indexInComment + atInternal.length,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/** @type {(c: TSESTree.Comment) => TSESTree.SourceLocation} */
|
||||
const getJSDocStartLoc = (c) => {
|
||||
return {
|
||||
start: c.loc.start,
|
||||
end: {
|
||||
line: c.loc.start.line,
|
||||
column: c.loc.start.column + jsdocStart.length,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
/** @type {(node: TSESTree.Node) => void} */
|
||||
const checkJSDocFormat = (node) => {
|
||||
const blockComments = sourceCode.getCommentsBefore(node).filter(c => c.type === "Block");
|
||||
if (blockComments.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const last = blockComments.length - 1;
|
||||
let seenJSDoc = false;
|
||||
for (let i = 0; i < blockComments.length; i++) {
|
||||
const c = blockComments[i];
|
||||
const rawComment = sourceCode.getText(c);
|
||||
|
||||
const isJSDoc = rawComment.startsWith(jsdocStart);
|
||||
if (isJSDoc && seenJSDoc) {
|
||||
context.report({ messageId: "multipleJSDocError", node: c, loc: getJSDocStartLoc(c) });
|
||||
}
|
||||
seenJSDoc = seenJSDoc || isJSDoc;
|
||||
|
||||
const indexInComment = rawComment.indexOf(atInternal);
|
||||
if (indexInComment === -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isJSDoc) {
|
||||
context.report({ messageId: "internalCommentInNonJSDocError", node: c, loc: getAtInternalLoc(c, indexInComment) });
|
||||
}
|
||||
else if (i !== last) {
|
||||
context.report({ messageId: "internalCommentNotLastError", node: c, loc: getAtInternalLoc(c, indexInComment) });
|
||||
}
|
||||
else if (node.type === "TSParameterProperty") {
|
||||
context.report({ messageId: "internalCommentOnParameterProperty", node: c, loc: getAtInternalLoc(c, indexInComment) });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
ClassDeclaration: checkJSDocFormat,
|
||||
FunctionDeclaration: checkJSDocFormat,
|
||||
TSEnumDeclaration: checkJSDocFormat,
|
||||
TSModuleDeclaration: checkJSDocFormat,
|
||||
VariableDeclaration: checkJSDocFormat,
|
||||
TSInterfaceDeclaration: checkJSDocFormat,
|
||||
TSTypeAliasDeclaration: checkJSDocFormat,
|
||||
TSCallSignatureDeclaration: checkJSDocFormat,
|
||||
ExportAllDeclaration: checkJSDocFormat,
|
||||
ExportNamedDeclaration: checkJSDocFormat,
|
||||
TSImportEqualsDeclaration: checkJSDocFormat,
|
||||
TSNamespaceExportDeclaration: checkJSDocFormat,
|
||||
TSConstructSignatureDeclaration: checkJSDocFormat,
|
||||
ExportDefaultDeclaration: checkJSDocFormat,
|
||||
TSPropertySignature: checkJSDocFormat,
|
||||
TSIndexSignature: checkJSDocFormat,
|
||||
TSMethodSignature: checkJSDocFormat,
|
||||
TSParameterProperty: checkJSDocFormat,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -1,45 +0,0 @@
|
||||
const { AST_NODE_TYPES, TSESTree } = require("@typescript-eslint/utils");
|
||||
const { createRule } = require("./utils.cjs");
|
||||
|
||||
module.exports = createRule({
|
||||
name: "one-namespace-per-file",
|
||||
meta: {
|
||||
docs: {
|
||||
description: `Limits each file to having at most one top-level namespace declaration`,
|
||||
recommended: "error",
|
||||
},
|
||||
messages: {
|
||||
excessNamespaceError: `All but one of these namespaces should be moved into separate files.`,
|
||||
},
|
||||
schema: [],
|
||||
type: "problem",
|
||||
},
|
||||
defaultOptions: [],
|
||||
|
||||
create(context) {
|
||||
/** @type {(node: TSESTree.Node) => node is TSESTree.TSModuleDeclaration} */
|
||||
const isNamespaceDeclaration = (node) => node.type === AST_NODE_TYPES.TSModuleDeclaration;
|
||||
|
||||
/** @type {(node: TSESTree.Program) => void} */
|
||||
const checkSourceFile = (node) => {
|
||||
if (context.getFilename().endsWith(".d.ts")) {
|
||||
return;
|
||||
}
|
||||
const members = node.body;
|
||||
const namespaces = members.filter(isNamespaceDeclaration);
|
||||
if (namespaces.length <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
namespaces.forEach(n => {
|
||||
context.report({
|
||||
messageId: "excessNamespaceError", node: n
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
return {
|
||||
Program: checkSourceFile,
|
||||
};
|
||||
},
|
||||
});
|
||||
@@ -10,6 +10,7 @@ const os = require("os");
|
||||
reporter?: Mocha.ReporterConstructor | keyof Mocha.reporters;
|
||||
reporterOptions?: any; // TODO(jakebailey): what?
|
||||
}} ReporterOptions */
|
||||
void 0;
|
||||
|
||||
/**
|
||||
* .failed-tests reporter
|
||||
|
||||
@@ -1,8 +1,28 @@
|
||||
import fs from "fs";
|
||||
import path from "path";
|
||||
import xml2js from "xml2js";
|
||||
import { XMLParser } from "fast-xml-parser";
|
||||
|
||||
function main() {
|
||||
/** @typedef {{
|
||||
LCX: {
|
||||
$_TgtCul: string;
|
||||
Item: {
|
||||
Item: {
|
||||
Item: {
|
||||
$_ItemId: string;
|
||||
Str: {
|
||||
Val: string;
|
||||
Tgt: {
|
||||
Val: string;
|
||||
};
|
||||
};
|
||||
}[];
|
||||
};
|
||||
};
|
||||
}
|
||||
}} ParsedLCL */
|
||||
void 0;
|
||||
|
||||
async function main() {
|
||||
const args = process.argv.slice(2);
|
||||
if (args.length !== 3) {
|
||||
console.log("Usage:");
|
||||
@@ -15,38 +35,33 @@ function main() {
|
||||
const diagnosticsMapFilePath = args[2];
|
||||
|
||||
// generate the lcg file for enu
|
||||
generateLCGFile();
|
||||
await generateLCGFile();
|
||||
|
||||
// generate other langs
|
||||
fs.readdir(inputPath, (err, files) => {
|
||||
handleError(err);
|
||||
files.forEach(visitDirectory);
|
||||
});
|
||||
const files = await fs.promises.readdir(inputPath);
|
||||
await Promise.all(files.map(visitDirectory));
|
||||
|
||||
return;
|
||||
|
||||
/**
|
||||
* @param {string} name
|
||||
*/
|
||||
function visitDirectory(name) {
|
||||
async function visitDirectory(name) {
|
||||
const inputFilePath = path.join(inputPath, name, "diagnosticMessages", "diagnosticMessages.generated.json.lcl");
|
||||
|
||||
fs.readFile(inputFilePath, (err, data) => {
|
||||
handleError(err);
|
||||
xml2js.parseString(data.toString(), (err, result) => {
|
||||
handleError(err);
|
||||
if (!result || !result.LCX || !result.LCX.$ || !result.LCX.$.TgtCul) {
|
||||
console.error("Unexpected XML file structure. Expected to find result.LCX.$.TgtCul.");
|
||||
process.exit(1);
|
||||
}
|
||||
const outputDirectoryName = getPreferredLocaleName(result.LCX.$.TgtCul).toLowerCase();
|
||||
if (!outputDirectoryName) {
|
||||
console.error(`Invalid output locale name for '${result.LCX.$.TgtCul}'.`);
|
||||
process.exit(1);
|
||||
}
|
||||
writeFile(path.join(outputPath, outputDirectoryName, "diagnosticMessages.generated.json"), xmlObjectToString(result));
|
||||
});
|
||||
});
|
||||
const contents = await fs.promises.readFile(inputFilePath);
|
||||
/** @type {ParsedLCL} */
|
||||
// eslint-disable-next-line local/object-literal-surrounding-space
|
||||
const result = new XMLParser({ ignoreAttributes: false, attributeNamePrefix: "$_"}).parse(contents);
|
||||
if (!result || !result.LCX || !result.LCX.$_TgtCul) {
|
||||
console.error("Unexpected XML file structure. Expected to find result.LCX.$_TgtCul.");
|
||||
process.exit(1);
|
||||
}
|
||||
const outputDirectoryName = getPreferredLocaleName(result.LCX.$_TgtCul).toLowerCase();
|
||||
if (!outputDirectoryName) {
|
||||
console.error(`Invalid output locale name for '${result.LCX.$_TgtCul}'.`);
|
||||
process.exit(1);
|
||||
}
|
||||
await writeFile(path.join(outputPath, outputDirectoryName, "diagnosticMessages.generated.json"), xmlObjectToString(result));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -81,24 +96,14 @@ function main() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {null | object} err
|
||||
*/
|
||||
function handleError(err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {any} o
|
||||
* @param {ParsedLCL} o
|
||||
*/
|
||||
function xmlObjectToString(o) {
|
||||
/** @type {any} */
|
||||
const out = {};
|
||||
for (const item of o.LCX.Item[0].Item[0].Item) {
|
||||
let ItemId = item.$.ItemId;
|
||||
let val = item.Str[0].Tgt ? item.Str[0].Tgt[0].Val[0] : item.Str[0].Val[0];
|
||||
for (const item of o.LCX.Item.Item.Item) {
|
||||
let ItemId = item.$_ItemId;
|
||||
let val = item.Str.Tgt ? item.Str.Tgt.Val : item.Str.Val;
|
||||
|
||||
if (typeof ItemId !== "string" || typeof val !== "string") {
|
||||
console.error("Unexpected XML file structure");
|
||||
@@ -115,55 +120,26 @@ function main() {
|
||||
return JSON.stringify(out, undefined, 2);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} directoryPath
|
||||
* @param {() => void} action
|
||||
*/
|
||||
function ensureDirectoryExists(directoryPath, action) {
|
||||
fs.exists(directoryPath, exists => {
|
||||
if (!exists) {
|
||||
const basePath = path.dirname(directoryPath);
|
||||
if (basePath !== directoryPath) {
|
||||
return ensureDirectoryExists(basePath, () => fs.mkdir(directoryPath, action));
|
||||
}
|
||||
}
|
||||
action();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} fileName
|
||||
* @param {string} contents
|
||||
*/
|
||||
function writeFile(fileName, contents) {
|
||||
ensureDirectoryExists(path.dirname(fileName), () => {
|
||||
fs.writeFile(fileName, contents, handleError);
|
||||
});
|
||||
async function writeFile(fileName, contents) {
|
||||
await fs.promises.mkdir(path.dirname(fileName), { recursive: true });
|
||||
await fs.promises.writeFile(fileName, contents);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Record<string, string>} o
|
||||
*/
|
||||
function objectToList(o) {
|
||||
const list = [];
|
||||
for (const key in o) {
|
||||
list.push({ key, value: o[key] });
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
function generateLCGFile() {
|
||||
return fs.readFile(diagnosticsMapFilePath, (err, data) => {
|
||||
handleError(err);
|
||||
writeFile(
|
||||
path.join(outputPath, "enu", "diagnosticMessages.generated.json.lcg"),
|
||||
getLCGFileXML(
|
||||
objectToList(JSON.parse(data.toString()))
|
||||
.sort((a, b) => a.key > b.key ? 1 : -1) // lcg sorted by property keys
|
||||
.reduce((s, { key, value }) => s + getItemXML(key, value), "")
|
||||
));
|
||||
});
|
||||
async function generateLCGFile() {
|
||||
const contents = await fs.promises.readFile(diagnosticsMapFilePath, "utf-8");
|
||||
await writeFile(
|
||||
path.join(outputPath, "enu", "diagnosticMessages.generated.json.lcg"),
|
||||
getLCGFileXML(
|
||||
Object.entries(JSON.parse(contents))
|
||||
.sort((a, b) => a[0] > b[0] ? 1 : -1) // lcg sorted by property keys
|
||||
.reduce((s, [key, value]) => s + getItemXML(key, value), "")
|
||||
),
|
||||
);
|
||||
return;
|
||||
|
||||
/**
|
||||
* @param {string} key
|
||||
@@ -204,4 +180,4 @@ function main() {
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
await main();
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
#!/bin/sh
|
||||
npm run gulp -- generate-diagnostics
|
||||
npm run npx hereby -- generate-diagnostics
|
||||
|
||||
@@ -71,7 +71,7 @@ ${logText.trim()}`;
|
||||
]);
|
||||
if (produceLKG) {
|
||||
runSequence([
|
||||
["gulp", ["LKG"]],
|
||||
["node", ["./node_modules/hereby/dist/cli.js", "LKG"]],
|
||||
["git", ["add", "lib"]],
|
||||
["git", ["commit", "-m", `"Update LKG"`]]
|
||||
]);
|
||||
|
||||
@@ -15,7 +15,7 @@ runSequence([
|
||||
["git", ["checkout", "."]], // reset any changes
|
||||
["git", ["fetch", baseRef === "main" ? "origin" : "fork", baseRef]], // fetch target ref in case it's not present locally
|
||||
["git", ["checkout", baseRef]], // move head to target
|
||||
["node", ["./node_modules/gulp/bin/gulp.js", "baseline-accept"]], // accept baselines
|
||||
["node", ["./node_modules/hereby/dist/cli.js", "baseline-accept"]], // accept baselines
|
||||
["git", ["checkout", "-b", branchName]], // create a branch
|
||||
["git", ["add", "."]], // Add all changes
|
||||
["git", ["commit", "-m", `"Update user baselines${+(process.env.SOURCE_ISSUE ?? 0) === 33716 ? " +cc @sandersn" : ""}"`]], // Commit all changes (ping nathan if we would post to CI thread)
|
||||
|
||||
@@ -9,10 +9,11 @@ import fs from "fs";
|
||||
isEarly?: boolean;
|
||||
elidedInCompatabilityPyramid?: boolean;
|
||||
}} DiagnosticDetails */
|
||||
void 0;
|
||||
|
||||
/** @typedef {Map<string, DiagnosticDetails>} InputDiagnosticMessageTable */
|
||||
|
||||
function main() {
|
||||
async function main() {
|
||||
if (process.argv.length < 3) {
|
||||
console.log("Usage:");
|
||||
console.log("\tnode processDiagnosticMessages.mjs <diagnostic-json-input-file>");
|
||||
@@ -23,15 +24,24 @@ function main() {
|
||||
* @param {string} fileName
|
||||
* @param {string} contents
|
||||
*/
|
||||
function writeFile(fileName, contents) {
|
||||
fs.writeFile(path.join(path.dirname(inputFilePath), fileName), contents, { encoding: "utf-8" }, err => {
|
||||
if (err) throw err;
|
||||
});
|
||||
async function writeFile(fileName, contents) {
|
||||
const filePath = path.join(path.dirname(inputFilePath), fileName);
|
||||
try {
|
||||
const existingContents = await fs.promises.readFile(filePath, "utf-8");
|
||||
if (existingContents === contents) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch {
|
||||
// Just write the file.
|
||||
}
|
||||
|
||||
await fs.promises.writeFile(filePath, contents, { encoding: "utf-8" });
|
||||
}
|
||||
|
||||
const inputFilePath = process.argv[2].replace(/\\/g, "/");
|
||||
console.log(`Reading diagnostics from ${inputFilePath}`);
|
||||
const inputStr = fs.readFileSync(inputFilePath, { encoding: "utf-8" });
|
||||
const inputStr = await fs.promises.readFile(inputFilePath, { encoding: "utf-8" });
|
||||
|
||||
/** @type {{ [key: string]: DiagnosticDetails }} */
|
||||
const diagnosticMessagesJson = JSON.parse(inputStr);
|
||||
@@ -44,15 +54,12 @@ function main() {
|
||||
}
|
||||
}
|
||||
|
||||
const outputFilesDir = path.dirname(inputFilePath);
|
||||
const thisFilePathRel = path.relative(process.cwd(), outputFilesDir);
|
||||
|
||||
const infoFileOutput = buildInfoFileOutput(diagnosticMessages, `./${path.basename(inputFilePath)}`, thisFilePathRel);
|
||||
const infoFileOutput = buildInfoFileOutput(diagnosticMessages, inputFilePath);
|
||||
checkForUniqueCodes(diagnosticMessages);
|
||||
writeFile("diagnosticInformationMap.generated.ts", infoFileOutput);
|
||||
await writeFile("diagnosticInformationMap.generated.ts", infoFileOutput);
|
||||
|
||||
const messageOutput = buildDiagnosticMessageOutput(diagnosticMessages);
|
||||
writeFile("diagnosticMessages.generated.json", messageOutput);
|
||||
await writeFile("diagnosticMessages.generated.json", messageOutput);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,31 +79,34 @@ function checkForUniqueCodes(diagnosticTable) {
|
||||
/**
|
||||
* @param {InputDiagnosticMessageTable} messageTable
|
||||
* @param {string} inputFilePathRel
|
||||
* @param {string} thisFilePathRel
|
||||
* @returns {string}
|
||||
*/
|
||||
function buildInfoFileOutput(messageTable, inputFilePathRel, thisFilePathRel) {
|
||||
let result =
|
||||
"// <auto-generated />\r\n" +
|
||||
"// generated from '" + inputFilePathRel + "' in '" + thisFilePathRel.replace(/\\/g, "/") + "'\r\n" +
|
||||
"/* @internal */\r\n" +
|
||||
"namespace ts {\r\n" +
|
||||
" function diag(code: number, category: DiagnosticCategory, key: string, message: string, reportsUnnecessary?: {}, elidedInCompatabilityPyramid?: boolean, reportsDeprecated?: {}): DiagnosticMessage {\r\n" +
|
||||
" return { code, category, key, message, reportsUnnecessary, elidedInCompatabilityPyramid, reportsDeprecated };\r\n" +
|
||||
" }\r\n" +
|
||||
" export const Diagnostics = {\r\n";
|
||||
function buildInfoFileOutput(messageTable, inputFilePathRel) {
|
||||
const result = [
|
||||
"// <auto-generated />",
|
||||
`// generated from '${inputFilePathRel}'`,
|
||||
"",
|
||||
"import { DiagnosticCategory, DiagnosticMessage } from \"./types\";",
|
||||
"",
|
||||
"function diag(code: number, category: DiagnosticCategory, key: string, message: string, reportsUnnecessary?: {}, elidedInCompatabilityPyramid?: boolean, reportsDeprecated?: {}): DiagnosticMessage {",
|
||||
" return { code, category, key, message, reportsUnnecessary, elidedInCompatabilityPyramid, reportsDeprecated };",
|
||||
"}",
|
||||
"",
|
||||
"/** @internal */",
|
||||
"export const Diagnostics = {",
|
||||
];
|
||||
messageTable.forEach(({ code, category, reportsUnnecessary, elidedInCompatabilityPyramid, reportsDeprecated }, name) => {
|
||||
const propName = convertPropertyName(name);
|
||||
const argReportsUnnecessary = reportsUnnecessary ? `, /*reportsUnnecessary*/ ${reportsUnnecessary}` : "";
|
||||
const argElidedInCompatabilityPyramid = elidedInCompatabilityPyramid ? `${!reportsUnnecessary ? ", /*reportsUnnecessary*/ undefined" : ""}, /*elidedInCompatabilityPyramid*/ ${elidedInCompatabilityPyramid}` : "";
|
||||
const argReportsDeprecated = reportsDeprecated ? `${!argElidedInCompatabilityPyramid ? ", /*reportsUnnecessary*/ undefined, /*elidedInCompatabilityPyramid*/ undefined" : ""}, /*reportsDeprecated*/ ${reportsDeprecated}` : "";
|
||||
|
||||
result += ` ${propName}: diag(${code}, DiagnosticCategory.${category}, "${createKey(propName, code)}", ${JSON.stringify(name)}${argReportsUnnecessary}${argElidedInCompatabilityPyramid}${argReportsDeprecated}),\r\n`;
|
||||
result.push(` ${propName}: diag(${code}, DiagnosticCategory.${category}, "${createKey(propName, code)}", ${JSON.stringify(name)}${argReportsUnnecessary}${argElidedInCompatabilityPyramid}${argReportsDeprecated}),`);
|
||||
});
|
||||
|
||||
result += " };\r\n}";
|
||||
result.push("};");
|
||||
|
||||
return result;
|
||||
return result.join("\r\n");
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+15
-56
@@ -1,8 +1,9 @@
|
||||
import childProcess from "child_process";
|
||||
import fs from "fs-extra";
|
||||
import path from "path";
|
||||
import glob from "glob";
|
||||
import url from "url";
|
||||
import del from "del";
|
||||
import { localizationDirectories } from "./build/localization.mjs";
|
||||
|
||||
const __filename = url.fileURLToPath(new URL(import.meta.url));
|
||||
const __dirname = path.dirname(__filename);
|
||||
@@ -10,16 +11,16 @@ const __dirname = path.dirname(__filename);
|
||||
const root = path.join(__dirname, "..");
|
||||
const source = path.join(root, "built/local");
|
||||
const dest = path.join(root, "lib");
|
||||
const copyright = fs.readFileSync(path.join(__dirname, "../CopyrightNotice.txt"), "utf-8");
|
||||
|
||||
async function produceLKG() {
|
||||
console.log(`Building LKG from ${source} to ${dest}`);
|
||||
await del(`${dest.replace(/\\/g, "/")}/**`, { ignore: ["**/README.md"] });
|
||||
await fs.mkdirp(dest);
|
||||
await copyLibFiles();
|
||||
await copyLocalizedDiagnostics();
|
||||
await copyTypesMap();
|
||||
await copyScriptOutputs();
|
||||
await copyDeclarationOutputs();
|
||||
await buildProtocol();
|
||||
await writeGitAttributes();
|
||||
}
|
||||
|
||||
@@ -28,15 +29,9 @@ async function copyLibFiles() {
|
||||
}
|
||||
|
||||
async function copyLocalizedDiagnostics() {
|
||||
const dir = await fs.readdir(source);
|
||||
const ignoredFolders = ["enu"];
|
||||
|
||||
for (const d of dir) {
|
||||
for (const d of localizationDirectories) {
|
||||
const fileName = path.join(source, d);
|
||||
if (
|
||||
fs.statSync(fileName).isDirectory() &&
|
||||
ignoredFolders.indexOf(d) < 0
|
||||
) {
|
||||
if (fs.statSync(fileName).isDirectory()) {
|
||||
await fs.copy(fileName, path.join(dest, d));
|
||||
}
|
||||
}
|
||||
@@ -46,51 +41,25 @@ async function copyTypesMap() {
|
||||
await copyFromBuiltLocal("typesMap.json"); // Cannot accommodate copyright header
|
||||
}
|
||||
|
||||
async function buildProtocol() {
|
||||
const protocolScript = path.join(__dirname, "buildProtocol.mjs");
|
||||
if (!fs.existsSync(protocolScript)) {
|
||||
throw new Error(`Expected protocol script ${protocolScript} to exist`);
|
||||
}
|
||||
|
||||
const protocolInput = path.join(__dirname, "../src/server/protocol.ts");
|
||||
const protocolServices = path.join(source, "typescriptServices.d.ts");
|
||||
const protocolOutput = path.join(dest, "protocol.d.ts");
|
||||
|
||||
console.log(`Building ${protocolOutput}...`);
|
||||
await exec(protocolScript, [protocolInput, protocolServices, protocolOutput]);
|
||||
}
|
||||
|
||||
async function copyScriptOutputs() {
|
||||
await copyWithCopyright("cancellationToken.js");
|
||||
await copyWithCopyright("tsc.release.js", "tsc.js");
|
||||
await copyWithCopyright("tsserver.js");
|
||||
await copyWithCopyright("dynamicImportCompat.js");
|
||||
await copyFromBuiltLocal("tsserverlibrary.js"); // copyright added by build
|
||||
await copyFromBuiltLocal("typescript.js"); // copyright added by build
|
||||
await copyFromBuiltLocal("typescriptServices.js"); // copyright added by build
|
||||
await copyWithCopyright("typingsInstaller.js");
|
||||
await copyWithCopyright("watchGuard.js");
|
||||
await copyFromBuiltLocal("cancellationToken.js");
|
||||
await copyFromBuiltLocal("tsc.js");
|
||||
await copyFromBuiltLocal("tsserver.js");
|
||||
await copyFromBuiltLocal("tsserverlibrary.js");
|
||||
await copyFromBuiltLocal("typescript.js");
|
||||
await copyFromBuiltLocal("typingsInstaller.js");
|
||||
await copyFromBuiltLocal("watchGuard.js");
|
||||
}
|
||||
|
||||
async function copyDeclarationOutputs() {
|
||||
await copyFromBuiltLocal("tsserverlibrary.d.ts"); // copyright added by build
|
||||
await copyFromBuiltLocal("typescript.d.ts"); // copyright added by build
|
||||
await copyFromBuiltLocal("typescriptServices.d.ts"); // copyright added by build
|
||||
await copyFromBuiltLocal("tsserverlibrary.d.ts");
|
||||
await copyFromBuiltLocal("typescript.d.ts");
|
||||
}
|
||||
|
||||
async function writeGitAttributes() {
|
||||
await fs.writeFile(path.join(dest, ".gitattributes"), `* text eol=lf`, "utf-8");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} fileName
|
||||
* @param {string} destName
|
||||
*/
|
||||
async function copyWithCopyright(fileName, destName = fileName) {
|
||||
const content = await fs.readFile(path.join(source, fileName), "utf-8");
|
||||
await fs.writeFile(path.join(dest, destName), copyright + "\n" + content);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} fileName
|
||||
*/
|
||||
@@ -109,16 +78,6 @@ async function copyFilesWithGlob(pattern) {
|
||||
console.log(`Copied ${files.length} files matching pattern ${pattern}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} path
|
||||
* @param {string[]} args
|
||||
*/
|
||||
async function exec(path, args = []) {
|
||||
const cmdLine = ["node", path, ...args].join(" ");
|
||||
console.log(cmdLine);
|
||||
childProcess.execSync(cmdLine);
|
||||
}
|
||||
|
||||
process.on("unhandledRejection", err => {
|
||||
throw err;
|
||||
});
|
||||
|
||||
Vendored
-90
@@ -1,90 +0,0 @@
|
||||
import { TaskFunction } from "gulp";
|
||||
|
||||
declare module "gulp-insert" {
|
||||
export function append(text: string | Buffer): NodeJS.ReadWriteStream;
|
||||
export function prepend(text: string | Buffer): NodeJS.ReadWriteStream;
|
||||
export function wrap(text: string | Buffer, tail: string | Buffer): NodeJS.ReadWriteStream;
|
||||
export function transform(cb: (contents: string, file: {path: string, relative: string}) => string): NodeJS.ReadWriteStream; // file is a vinyl file
|
||||
}
|
||||
|
||||
declare module "sorcery";
|
||||
|
||||
declare module "vinyl" {
|
||||
// NOTE: This makes it possible to correctly type vinyl Files under @ts-check.
|
||||
export = File;
|
||||
|
||||
declare class File<T extends File.Contents = File.Contents> {
|
||||
constructor(options?: File.VinylOptions<T>);
|
||||
|
||||
cwd: string;
|
||||
base: string;
|
||||
path: string;
|
||||
readonly history: readonly string[];
|
||||
contents: T;
|
||||
relative: string;
|
||||
dirname: string;
|
||||
basename: string;
|
||||
stem: string;
|
||||
extname: string;
|
||||
symlink: string | null;
|
||||
stat: import("fs").Stats | null;
|
||||
sourceMap?: import("./sourcemaps").RawSourceMap | string;
|
||||
|
||||
[custom: string]: any;
|
||||
|
||||
isBuffer(): this is T extends Buffer ? File<Buffer> : never;
|
||||
isStream(): this is T extends NodeJS.ReadableStream ? File<NodeJS.ReadableStream> : never;
|
||||
isNull(): this is T extends null ? File<null> : never;
|
||||
isDirectory(): this is T extends null ? File.Directory : never;
|
||||
isSymbolic(): this is T extends null ? File.Symbolic : never;
|
||||
clone(opts?: { contents?: boolean, deep?: boolean }): this;
|
||||
}
|
||||
|
||||
namespace File {
|
||||
export interface VinylOptions<T extends Contents = Contents> {
|
||||
cwd?: string;
|
||||
base?: string;
|
||||
path?: string;
|
||||
history?: readonly string[];
|
||||
stat?: import("fs").Stats;
|
||||
contents?: T;
|
||||
sourceMap?: import("./sourcemaps").RawSourceMap | string;
|
||||
[custom: string]: any;
|
||||
}
|
||||
|
||||
export type Contents = Buffer | NodeJS.ReadableStream | null;
|
||||
export type File = import("./vinyl");
|
||||
export type NullFile = File<null>;
|
||||
export type BufferFile = File<Buffer>;
|
||||
export type StreamFile = File<NodeJS.ReadableStream>;
|
||||
|
||||
export interface Directory extends NullFile {
|
||||
isNull(): true;
|
||||
isDirectory(): true;
|
||||
isSymbolic(): this is never;
|
||||
}
|
||||
|
||||
export interface Symbolic extends NullFile {
|
||||
isNull(): true;
|
||||
isDirectory(): this is never;
|
||||
isSymbolic(): true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declare module "undertaker" {
|
||||
interface TaskFunctionParams {
|
||||
flags?: Record<string, string>;
|
||||
}
|
||||
interface TaskFunctionWrapped {
|
||||
description: string
|
||||
flags: { [name: string]: string }
|
||||
}
|
||||
}
|
||||
|
||||
declare module "gulp-sourcemaps" {
|
||||
interface WriteOptions {
|
||||
destPath?: string;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -60,6 +60,7 @@ const sys = (() => {
|
||||
subscript?: boolean;
|
||||
};
|
||||
}} FindReplaceOptions */
|
||||
void 0;
|
||||
|
||||
/**
|
||||
* @param {Word.Document} doc
|
||||
|
||||
+23
-2
@@ -6,7 +6,21 @@
|
||||
},
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unnecessary-qualifier": "error",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error"
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||
"no-restricted-globals": ["error",
|
||||
{ "name": "setTimeout" },
|
||||
{ "name": "clearTimeout" },
|
||||
{ "name": "setInterval" },
|
||||
{ "name": "clearInterval" },
|
||||
{ "name": "setImmediate" },
|
||||
{ "name": "clearImmediate" },
|
||||
{ "name": "performance" },
|
||||
{ "name": "Iterator" },
|
||||
{ "name": "Map" },
|
||||
{ "name": "ReadonlyMap" },
|
||||
{ "name": "Set" },
|
||||
{ "name": "ReadonlySet" }
|
||||
]
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
@@ -20,7 +34,8 @@
|
||||
"local/no-keywords": "off",
|
||||
|
||||
// eslint
|
||||
"no-var": "off"
|
||||
"no-var": "off",
|
||||
"no-restricted-globals": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
@@ -28,6 +43,12 @@
|
||||
"rules": {
|
||||
"@typescript-eslint/array-type": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": ["debug/**", "harness/**", "testRunner/**"],
|
||||
"rules": {
|
||||
"no-restricted-globals": "off"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
/// <reference types="node"/>
|
||||
|
||||
import fs = require("fs");
|
||||
import * as fs from "fs";
|
||||
|
||||
interface ServerCancellationToken {
|
||||
isCancellationRequested(): boolean;
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
{
|
||||
"extends": "../tsconfig-noncomposite-base",
|
||||
"extends": "../tsconfig-base",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../built/local/",
|
||||
"rootDir": ".",
|
||||
"composite": false,
|
||||
"declaration": false,
|
||||
"declarationMap": false,
|
||||
"removeComments": true,
|
||||
"incremental": false,
|
||||
"module": "commonjs",
|
||||
"types": [
|
||||
"node"
|
||||
@@ -16,7 +9,5 @@
|
||||
"es6"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"cancellationToken.ts"
|
||||
]
|
||||
"include": ["**/*"]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
/* Generated file to emulate the ts.moduleSpecifiers namespace. */
|
||||
|
||||
export * from "../moduleSpecifiers";
|
||||
@@ -0,0 +1,3 @@
|
||||
/* Generated file to emulate the ts.performance namespace. */
|
||||
|
||||
export * from "../performance";
|
||||
@@ -0,0 +1,74 @@
|
||||
/* Generated file to emulate the ts namespace. */
|
||||
|
||||
export * from "../corePublic";
|
||||
export * from "../core";
|
||||
export * from "../debug";
|
||||
export * from "../semver";
|
||||
export * from "../performanceCore";
|
||||
export * from "../perfLogger";
|
||||
export * from "../tracing";
|
||||
export * from "../types";
|
||||
export * from "../sys";
|
||||
export * from "../path";
|
||||
export * from "../diagnosticInformationMap.generated";
|
||||
export * from "../scanner";
|
||||
export * from "../utilitiesPublic";
|
||||
export * from "../utilities";
|
||||
export * from "../factory/baseNodeFactory";
|
||||
export * from "../factory/parenthesizerRules";
|
||||
export * from "../factory/nodeConverters";
|
||||
export * from "../factory/nodeFactory";
|
||||
export * from "../factory/emitNode";
|
||||
export * from "../factory/emitHelpers";
|
||||
export * from "../factory/nodeTests";
|
||||
export * from "../factory/utilities";
|
||||
export * from "../factory/utilitiesPublic";
|
||||
export * from "../parser";
|
||||
export * from "../commandLineParser";
|
||||
export * from "../moduleNameResolver";
|
||||
export * from "../binder";
|
||||
export * from "../symbolWalker";
|
||||
export * from "../checker";
|
||||
export * from "../visitorPublic";
|
||||
export * from "../sourcemap";
|
||||
export * from "../transformers/utilities";
|
||||
export * from "../transformers/destructuring";
|
||||
export * from "../transformers/taggedTemplate";
|
||||
export * from "../transformers/ts";
|
||||
export * from "../transformers/classFields";
|
||||
export * from "../transformers/typeSerializer";
|
||||
export * from "../transformers/legacyDecorators";
|
||||
export * from "../transformers/es2017";
|
||||
export * from "../transformers/es2018";
|
||||
export * from "../transformers/es2019";
|
||||
export * from "../transformers/es2020";
|
||||
export * from "../transformers/es2021";
|
||||
export * from "../transformers/esnext";
|
||||
export * from "../transformers/jsx";
|
||||
export * from "../transformers/es2016";
|
||||
export * from "../transformers/es2015";
|
||||
export * from "../transformers/es5";
|
||||
export * from "../transformers/generators";
|
||||
export * from "../transformers/module/module";
|
||||
export * from "../transformers/module/system";
|
||||
export * from "../transformers/module/esnextAnd2015";
|
||||
export * from "../transformers/module/node";
|
||||
export * from "../transformers/declarations/diagnostics";
|
||||
export * from "../transformers/declarations";
|
||||
export * from "../transformer";
|
||||
export * from "../emitter";
|
||||
export * from "../watchUtilities";
|
||||
export * from "../program";
|
||||
export * from "../builderStatePublic";
|
||||
export * from "../builderState";
|
||||
export * from "../builder";
|
||||
export * from "../builderPublic";
|
||||
export * from "../resolutionCache";
|
||||
export * from "../watch";
|
||||
export * from "../watchPublic";
|
||||
export * from "../tsbuild";
|
||||
export * from "../tsbuildPublic";
|
||||
import * as moduleSpecifiers from "./ts.moduleSpecifiers";
|
||||
export { moduleSpecifiers };
|
||||
import * as performance from "./ts.performance";
|
||||
export { performance };
|
||||
+3314
-3252
File diff suppressed because it is too large
Load Diff
+1644
-1576
File diff suppressed because it is too large
Load Diff
+176
-166
@@ -1,181 +1,191 @@
|
||||
namespace ts {
|
||||
export type AffectedFileResult<T> = { result: T; affected: SourceFile | Program; } | undefined;
|
||||
import {
|
||||
BuilderProgramKind, CancellationToken, CompilerHost, CompilerOptions, createBuilderProgram,
|
||||
createRedirectedBuilderProgram, CustomTransformers, Diagnostic, DiagnosticWithLocation, EmitResult,
|
||||
getBuilderCreationParameters, Program, ProjectReference, ReusableBuilderProgramState, SavedBuildProgramEmitState,
|
||||
SourceFile, WriteFileCallback,
|
||||
} from "./_namespaces/ts";
|
||||
|
||||
export interface BuilderProgramHost {
|
||||
/**
|
||||
* return true if file names are treated with case sensitivity
|
||||
*/
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
/**
|
||||
* If provided this would be used this hash instead of actual file shape text for detecting changes
|
||||
*/
|
||||
createHash?: (data: string) => string;
|
||||
/**
|
||||
* When emit or emitNextAffectedFile are called without writeFile,
|
||||
* this callback if present would be used to write files
|
||||
*/
|
||||
writeFile?: WriteFileCallback;
|
||||
/**
|
||||
* disable using source file version as signature for testing
|
||||
*/
|
||||
/*@internal*/
|
||||
disableUseFileVersionAsSignature?: boolean;
|
||||
/**
|
||||
* Store the list of files that update signature during the emit
|
||||
*/
|
||||
/*@internal*/
|
||||
storeFilesChangingSignatureDuringEmit?: boolean;
|
||||
/**
|
||||
* Gets the current time
|
||||
*/
|
||||
/*@internal*/
|
||||
now?(): Date;
|
||||
}
|
||||
export type AffectedFileResult<T> = { result: T; affected: SourceFile | Program; } | undefined;
|
||||
|
||||
export interface BuilderProgramHost {
|
||||
/**
|
||||
* Builder to manage the program state changes
|
||||
* return true if file names are treated with case sensitivity
|
||||
*/
|
||||
export interface BuilderProgram {
|
||||
/*@internal*/
|
||||
getState(): ReusableBuilderProgramState;
|
||||
/*@internal*/
|
||||
saveEmitState(): SavedBuildProgramEmitState;
|
||||
/*@internal*/
|
||||
restoreEmitState(saved: SavedBuildProgramEmitState): void;
|
||||
/*@internal*/
|
||||
hasChangedEmitSignature?(): boolean;
|
||||
/**
|
||||
* Returns current program
|
||||
*/
|
||||
getProgram(): Program;
|
||||
/**
|
||||
* Returns current program that could be undefined if the program was released
|
||||
*/
|
||||
/*@internal*/
|
||||
getProgramOrUndefined(): Program | undefined;
|
||||
/**
|
||||
* Releases reference to the program, making all the other operations that need program to fail.
|
||||
*/
|
||||
/*@internal*/
|
||||
releaseProgram(): void;
|
||||
/**
|
||||
* Get compiler options of the program
|
||||
*/
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
/**
|
||||
* Get the source file in the program with file name
|
||||
*/
|
||||
getSourceFile(fileName: string): SourceFile | undefined;
|
||||
/**
|
||||
* Get a list of files in the program
|
||||
*/
|
||||
getSourceFiles(): readonly SourceFile[];
|
||||
/**
|
||||
* Get the diagnostics for compiler options
|
||||
*/
|
||||
getOptionsDiagnostics(cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
/**
|
||||
* Get the diagnostics that dont belong to any file
|
||||
*/
|
||||
getGlobalDiagnostics(cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
/**
|
||||
* Get the diagnostics from config file parsing
|
||||
*/
|
||||
getConfigFileParsingDiagnostics(): readonly Diagnostic[];
|
||||
/**
|
||||
* Get the syntax diagnostics, for all source files if source file is not supplied
|
||||
*/
|
||||
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
/**
|
||||
* Get the declaration diagnostics, for all source files if source file is not supplied
|
||||
*/
|
||||
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[];
|
||||
/**
|
||||
* Get all the dependencies of the file
|
||||
*/
|
||||
getAllDependencies(sourceFile: SourceFile): readonly string[];
|
||||
|
||||
/**
|
||||
* Gets the semantic diagnostics from the program corresponding to this state of file (if provided) or whole program
|
||||
* The semantic diagnostics are cached and managed here
|
||||
* Note that it is assumed that when asked about semantic diagnostics through this API,
|
||||
* the file has been taken out of affected files so it is safe to use cache or get from program and cache the diagnostics
|
||||
* In case of SemanticDiagnosticsBuilderProgram if the source file is not provided,
|
||||
* it will iterate through all the affected files, to ensure that cache stays valid and yet provide a way to get all semantic diagnostics
|
||||
*/
|
||||
getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
/**
|
||||
* Emits the JavaScript and declaration files.
|
||||
* When targetSource file is specified, emits the files corresponding to that source file,
|
||||
* otherwise for the whole program.
|
||||
* In case of EmitAndSemanticDiagnosticsBuilderProgram, when targetSourceFile is specified,
|
||||
* it is assumed that that file is handled from affected file list. If targetSourceFile is not specified,
|
||||
* it will only emit all the affected files instead of whole program
|
||||
*
|
||||
* The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host
|
||||
* in that order would be used to write the files
|
||||
*/
|
||||
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult;
|
||||
/*@internal*/
|
||||
emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult;
|
||||
/**
|
||||
* Get the current directory of the program
|
||||
*/
|
||||
getCurrentDirectory(): string;
|
||||
/*@internal*/
|
||||
close(): void;
|
||||
}
|
||||
|
||||
useCaseSensitiveFileNames(): boolean;
|
||||
/**
|
||||
* The builder that caches the semantic diagnostics for the program and handles the changed files and affected files
|
||||
* If provided this would be used this hash instead of actual file shape text for detecting changes
|
||||
*/
|
||||
export interface SemanticDiagnosticsBuilderProgram extends BuilderProgram {
|
||||
/**
|
||||
* Gets the semantic diagnostics from the program for the next affected file and caches it
|
||||
* Returns undefined if the iteration is complete
|
||||
*/
|
||||
getSemanticDiagnosticsOfNextAffectedFile(cancellationToken?: CancellationToken, ignoreSourceFile?: (sourceFile: SourceFile) => boolean): AffectedFileResult<readonly Diagnostic[]>;
|
||||
}
|
||||
|
||||
createHash?: (data: string) => string;
|
||||
/**
|
||||
* The builder that can handle the changes in program and iterate through changed file to emit the files
|
||||
* The semantic diagnostics are cached per file and managed by clearing for the changed/affected files
|
||||
* When emit or emitNextAffectedFile are called without writeFile,
|
||||
* this callback if present would be used to write files
|
||||
*/
|
||||
export interface EmitAndSemanticDiagnosticsBuilderProgram extends SemanticDiagnosticsBuilderProgram {
|
||||
/**
|
||||
* Emits the next affected file's emit result (EmitResult and sourceFiles emitted) or returns undefined if iteration is complete
|
||||
* The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host
|
||||
* in that order would be used to write the files
|
||||
*/
|
||||
emitNextAffectedFile(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): AffectedFileResult<EmitResult>;
|
||||
}
|
||||
|
||||
writeFile?: WriteFileCallback;
|
||||
/**
|
||||
* Create the builder to manage semantic diagnostics and cache them
|
||||
* disable using source file version as signature for testing
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[]): SemanticDiagnosticsBuilderProgram;
|
||||
export function createSemanticDiagnosticsBuilderProgram(rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): SemanticDiagnosticsBuilderProgram;
|
||||
export function createSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | readonly string[] | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]) {
|
||||
return createBuilderProgram(BuilderProgramKind.SemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences));
|
||||
}
|
||||
|
||||
disableUseFileVersionAsSignature?: boolean;
|
||||
/**
|
||||
* Create the builder that can handle the changes in program and iterate through changed files
|
||||
* to emit the those files and manage semantic diagnostics cache as well
|
||||
* Store the list of files that update signature during the emit
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[]): EmitAndSemanticDiagnosticsBuilderProgram;
|
||||
export function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): EmitAndSemanticDiagnosticsBuilderProgram;
|
||||
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | readonly string[] | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]) {
|
||||
return createBuilderProgram(BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences));
|
||||
}
|
||||
|
||||
storeFilesChangingSignatureDuringEmit?: boolean;
|
||||
/**
|
||||
* Creates a builder thats just abstraction over program and can be used with watch
|
||||
* Gets the current time
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[]): BuilderProgram;
|
||||
export function createAbstractBuilder(rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): BuilderProgram;
|
||||
export function createAbstractBuilder(newProgramOrRootNames: Program | readonly string[] | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | BuilderProgram, configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | BuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): BuilderProgram {
|
||||
const { newProgram, configFileParsingDiagnostics: newConfigFileParsingDiagnostics } = getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences);
|
||||
return createRedirectedBuilderProgram(() => ({ program: newProgram, compilerOptions: newProgram.getCompilerOptions() }), newConfigFileParsingDiagnostics);
|
||||
}
|
||||
now?(): Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builder to manage the program state changes
|
||||
*/
|
||||
export interface BuilderProgram {
|
||||
/** @internal */
|
||||
getState(): ReusableBuilderProgramState;
|
||||
/** @internal */
|
||||
saveEmitState(): SavedBuildProgramEmitState;
|
||||
/** @internal */
|
||||
restoreEmitState(saved: SavedBuildProgramEmitState): void;
|
||||
/** @internal */
|
||||
hasChangedEmitSignature?(): boolean;
|
||||
/**
|
||||
* Returns current program
|
||||
*/
|
||||
getProgram(): Program;
|
||||
/**
|
||||
* Returns current program that could be undefined if the program was released
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
getProgramOrUndefined(): Program | undefined;
|
||||
/**
|
||||
* Releases reference to the program, making all the other operations that need program to fail.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
releaseProgram(): void;
|
||||
/**
|
||||
* Get compiler options of the program
|
||||
*/
|
||||
getCompilerOptions(): CompilerOptions;
|
||||
/**
|
||||
* Get the source file in the program with file name
|
||||
*/
|
||||
getSourceFile(fileName: string): SourceFile | undefined;
|
||||
/**
|
||||
* Get a list of files in the program
|
||||
*/
|
||||
getSourceFiles(): readonly SourceFile[];
|
||||
/**
|
||||
* Get the diagnostics for compiler options
|
||||
*/
|
||||
getOptionsDiagnostics(cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
/**
|
||||
* Get the diagnostics that dont belong to any file
|
||||
*/
|
||||
getGlobalDiagnostics(cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
/**
|
||||
* Get the diagnostics from config file parsing
|
||||
*/
|
||||
getConfigFileParsingDiagnostics(): readonly Diagnostic[];
|
||||
/**
|
||||
* Get the syntax diagnostics, for all source files if source file is not supplied
|
||||
*/
|
||||
getSyntacticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
/**
|
||||
* Get the declaration diagnostics, for all source files if source file is not supplied
|
||||
*/
|
||||
getDeclarationDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly DiagnosticWithLocation[];
|
||||
/**
|
||||
* Get all the dependencies of the file
|
||||
*/
|
||||
getAllDependencies(sourceFile: SourceFile): readonly string[];
|
||||
|
||||
/**
|
||||
* Gets the semantic diagnostics from the program corresponding to this state of file (if provided) or whole program
|
||||
* The semantic diagnostics are cached and managed here
|
||||
* Note that it is assumed that when asked about semantic diagnostics through this API,
|
||||
* the file has been taken out of affected files so it is safe to use cache or get from program and cache the diagnostics
|
||||
* In case of SemanticDiagnosticsBuilderProgram if the source file is not provided,
|
||||
* it will iterate through all the affected files, to ensure that cache stays valid and yet provide a way to get all semantic diagnostics
|
||||
*/
|
||||
getSemanticDiagnostics(sourceFile?: SourceFile, cancellationToken?: CancellationToken): readonly Diagnostic[];
|
||||
/**
|
||||
* Emits the JavaScript and declaration files.
|
||||
* When targetSource file is specified, emits the files corresponding to that source file,
|
||||
* otherwise for the whole program.
|
||||
* In case of EmitAndSemanticDiagnosticsBuilderProgram, when targetSourceFile is specified,
|
||||
* it is assumed that that file is handled from affected file list. If targetSourceFile is not specified,
|
||||
* it will only emit all the affected files instead of whole program
|
||||
*
|
||||
* The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host
|
||||
* in that order would be used to write the files
|
||||
*/
|
||||
emit(targetSourceFile?: SourceFile, writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): EmitResult;
|
||||
/** @internal */
|
||||
emitBuildInfo(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken): EmitResult;
|
||||
/**
|
||||
* Get the current directory of the program
|
||||
*/
|
||||
getCurrentDirectory(): string;
|
||||
/** @internal */
|
||||
close(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* The builder that caches the semantic diagnostics for the program and handles the changed files and affected files
|
||||
*/
|
||||
export interface SemanticDiagnosticsBuilderProgram extends BuilderProgram {
|
||||
/**
|
||||
* Gets the semantic diagnostics from the program for the next affected file and caches it
|
||||
* Returns undefined if the iteration is complete
|
||||
*/
|
||||
getSemanticDiagnosticsOfNextAffectedFile(cancellationToken?: CancellationToken, ignoreSourceFile?: (sourceFile: SourceFile) => boolean): AffectedFileResult<readonly Diagnostic[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
* The builder that can handle the changes in program and iterate through changed file to emit the files
|
||||
* The semantic diagnostics are cached per file and managed by clearing for the changed/affected files
|
||||
*/
|
||||
export interface EmitAndSemanticDiagnosticsBuilderProgram extends SemanticDiagnosticsBuilderProgram {
|
||||
/**
|
||||
* Emits the next affected file's emit result (EmitResult and sourceFiles emitted) or returns undefined if iteration is complete
|
||||
* The first of writeFile if provided, writeFile of BuilderProgramHost if provided, writeFile of compiler host
|
||||
* in that order would be used to write the files
|
||||
*/
|
||||
emitNextAffectedFile(writeFile?: WriteFileCallback, cancellationToken?: CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: CustomTransformers): AffectedFileResult<EmitResult>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the builder to manage semantic diagnostics and cache them
|
||||
*/
|
||||
export function createSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[]): SemanticDiagnosticsBuilderProgram;
|
||||
export function createSemanticDiagnosticsBuilderProgram(rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): SemanticDiagnosticsBuilderProgram;
|
||||
export function createSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | readonly string[] | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | SemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]) {
|
||||
return createBuilderProgram(BuilderProgramKind.SemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the builder that can handle the changes in program and iterate through changed files
|
||||
* to emit the those files and manage semantic diagnostics cache as well
|
||||
*/
|
||||
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgram: Program, host: BuilderProgramHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[]): EmitAndSemanticDiagnosticsBuilderProgram;
|
||||
export function createEmitAndSemanticDiagnosticsBuilderProgram(rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): EmitAndSemanticDiagnosticsBuilderProgram;
|
||||
export function createEmitAndSemanticDiagnosticsBuilderProgram(newProgramOrRootNames: Program | readonly string[] | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | EmitAndSemanticDiagnosticsBuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]) {
|
||||
return createBuilderProgram(BuilderProgramKind.EmitAndSemanticDiagnosticsBuilderProgram, getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences));
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a builder thats just abstraction over program and can be used with watch
|
||||
*/
|
||||
export function createAbstractBuilder(newProgram: Program, host: BuilderProgramHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[]): BuilderProgram;
|
||||
export function createAbstractBuilder(rootNames: readonly string[] | undefined, options: CompilerOptions | undefined, host?: CompilerHost, oldProgram?: BuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): BuilderProgram;
|
||||
export function createAbstractBuilder(newProgramOrRootNames: Program | readonly string[] | undefined, hostOrOptions: BuilderProgramHost | CompilerOptions | undefined, oldProgramOrHost?: CompilerHost | BuilderProgram, configFileParsingDiagnosticsOrOldProgram?: readonly Diagnostic[] | BuilderProgram, configFileParsingDiagnostics?: readonly Diagnostic[], projectReferences?: readonly ProjectReference[]): BuilderProgram {
|
||||
const { newProgram, configFileParsingDiagnostics: newConfigFileParsingDiagnostics } = getBuilderCreationParameters(newProgramOrRootNames, hostOrOptions, oldProgramOrHost, configFileParsingDiagnosticsOrOldProgram, configFileParsingDiagnostics, projectReferences);
|
||||
return createRedirectedBuilderProgram(() => ({ program: newProgram, compilerOptions: newProgram.getCompilerOptions() }), newConfigFileParsingDiagnostics);
|
||||
}
|
||||
|
||||
+596
-587
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,14 @@
|
||||
namespace ts {
|
||||
export interface EmitOutput {
|
||||
outputFiles: OutputFile[];
|
||||
emitSkipped: boolean;
|
||||
/* @internal */ diagnostics: readonly Diagnostic[];
|
||||
}
|
||||
import { Diagnostic, WriteFileCallbackData } from "./_namespaces/ts";
|
||||
|
||||
export interface OutputFile {
|
||||
name: string;
|
||||
writeByteOrderMark: boolean;
|
||||
text: string;
|
||||
/* @internal */ data?: WriteFileCallbackData;
|
||||
}
|
||||
export interface EmitOutput {
|
||||
outputFiles: OutputFile[];
|
||||
emitSkipped: boolean;
|
||||
/** @internal */ diagnostics: readonly Diagnostic[];
|
||||
}
|
||||
|
||||
export interface OutputFile {
|
||||
name: string;
|
||||
writeByteOrderMark: boolean;
|
||||
text: string;
|
||||
/** @internal */ data?: WriteFileCallbackData;
|
||||
}
|
||||
|
||||
+44898
-44690
File diff suppressed because it is too large
Load Diff
+3614
-3586
File diff suppressed because it is too large
Load Diff
+2748
-2351
File diff suppressed because it is too large
Load Diff
+153
-155
@@ -1,157 +1,155 @@
|
||||
namespace ts {
|
||||
// WARNING: The script `configurePrerelease.ts` uses a regexp to parse out these values.
|
||||
// If changing the text in this section, be sure to test `configurePrerelease` too.
|
||||
export const versionMajorMinor = "5.0";
|
||||
// The following is baselined as a literal template type without intervention
|
||||
/** The version of the TypeScript compiler release */
|
||||
// eslint-disable-next-line @typescript-eslint/no-inferrable-types
|
||||
export const version: string = `${versionMajorMinor}.0-dev`;
|
||||
// WARNING: The script `configurePrerelease.ts` uses a regexp to parse out these values.
|
||||
// If changing the text in this section, be sure to test `configurePrerelease` too.
|
||||
export const versionMajorMinor = "5.0";
|
||||
// The following is baselined as a literal template type without intervention
|
||||
/** The version of the TypeScript compiler release */
|
||||
// eslint-disable-next-line @typescript-eslint/no-inferrable-types
|
||||
export const version: string = `${versionMajorMinor}.0-dev`;
|
||||
|
||||
/**
|
||||
* Type of objects whose values are all of the same type.
|
||||
* The `in` and `for-in` operators can *not* be safely used,
|
||||
* since `Object.prototype` may be modified by outside code.
|
||||
*/
|
||||
export interface MapLike<T> {
|
||||
[index: string]: T;
|
||||
}
|
||||
|
||||
export interface SortedReadonlyArray<T> extends ReadonlyArray<T> {
|
||||
" __sortedArrayBrand": any;
|
||||
}
|
||||
|
||||
export interface SortedArray<T> extends Array<T> {
|
||||
" __sortedArrayBrand": any;
|
||||
}
|
||||
|
||||
/** Common read methods for ES6 Map/Set. */
|
||||
export interface ReadonlyCollection<K> {
|
||||
readonly size: number;
|
||||
has(key: K): boolean;
|
||||
keys(): Iterator<K>;
|
||||
}
|
||||
|
||||
/** Common write methods for ES6 Map/Set. */
|
||||
export interface Collection<K> extends ReadonlyCollection<K> {
|
||||
delete(key: K): boolean;
|
||||
clear(): void;
|
||||
}
|
||||
|
||||
/** ES6 Map interface, only read methods included. */
|
||||
export interface ReadonlyESMap<K, V> extends ReadonlyCollection<K> {
|
||||
get(key: K): V | undefined;
|
||||
values(): Iterator<V>;
|
||||
entries(): Iterator<[K, V]>;
|
||||
forEach(action: (value: V, key: K) => void): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* ES6 Map interface, only read methods included.
|
||||
*/
|
||||
export interface ReadonlyMap<T> extends ReadonlyESMap<string, T> {
|
||||
}
|
||||
|
||||
/** ES6 Map interface. */
|
||||
export interface ESMap<K, V> extends ReadonlyESMap<K, V>, Collection<K> {
|
||||
set(key: K, value: V): this;
|
||||
}
|
||||
|
||||
/**
|
||||
* ES6 Map interface.
|
||||
*/
|
||||
export interface Map<T> extends ESMap<string, T> {
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface MapConstructor {
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-function-type
|
||||
new <K, V>(iterable?: readonly (readonly [K, V])[] | ReadonlyESMap<K, V>): ESMap<K, V>;
|
||||
}
|
||||
|
||||
/** ES6 Set interface, only read methods included. */
|
||||
export interface ReadonlySet<T> extends ReadonlyCollection<T> {
|
||||
has(value: T): boolean;
|
||||
values(): Iterator<T>;
|
||||
entries(): Iterator<[T, T]>;
|
||||
forEach(action: (value: T, key: T) => void): void;
|
||||
}
|
||||
|
||||
/** ES6 Set interface. */
|
||||
export interface Set<T> extends ReadonlySet<T>, Collection<T> {
|
||||
add(value: T): this;
|
||||
delete(value: T): boolean;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export interface SetConstructor {
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-function-type
|
||||
new <T>(iterable?: readonly T[] | ReadonlySet<T>): Set<T>;
|
||||
}
|
||||
|
||||
/** ES6 Iterator type. */
|
||||
export interface Iterator<T> {
|
||||
next(): { value: T, done?: false } | { value: void, done: true };
|
||||
}
|
||||
|
||||
/** Array that is only intended to be pushed to, never read. */
|
||||
export interface Push<T> {
|
||||
push(...values: T[]): void;
|
||||
/* @internal*/ readonly length: number;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export type EqualityComparer<T> = (a: T, b: T) => boolean;
|
||||
|
||||
/* @internal */
|
||||
export type Comparer<T> = (a: T, b: T) => Comparison;
|
||||
|
||||
/* @internal */
|
||||
export const enum Comparison {
|
||||
LessThan = -1,
|
||||
EqualTo = 0,
|
||||
GreaterThan = 1
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
namespace NativeCollections {
|
||||
declare const self: any;
|
||||
|
||||
const globals = typeof globalThis !== "undefined" ? globalThis :
|
||||
typeof global !== "undefined" ? global :
|
||||
typeof self !== "undefined" ? self :
|
||||
undefined;
|
||||
|
||||
/**
|
||||
* Returns the native Map implementation if it is available and compatible (i.e. supports iteration).
|
||||
*/
|
||||
export function tryGetNativeMap(): MapConstructor {
|
||||
// Internet Explorer's Map doesn't support iteration, so don't use it.
|
||||
const gMap = globals?.Map;
|
||||
// eslint-disable-next-line local/no-in-operator
|
||||
const constructor = typeof gMap !== "undefined" && "entries" in gMap.prototype && new gMap([[0, 0]]).size === 1 ? gMap : undefined;
|
||||
if (!constructor) {
|
||||
throw new Error("No compatible Map implementation found.");
|
||||
}
|
||||
return constructor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the native Set implementation if it is available and compatible (i.e. supports iteration).
|
||||
*/
|
||||
export function tryGetNativeSet(): SetConstructor {
|
||||
// Internet Explorer's Set doesn't support iteration, so don't use it.
|
||||
const gSet = globals?.Set;
|
||||
// eslint-disable-next-line local/no-in-operator
|
||||
const constructor = typeof gSet !== "undefined" && "entries" in gSet.prototype && new gSet([0]).size === 1 ? gSet : undefined;
|
||||
if (!constructor) {
|
||||
throw new Error("No compatible Set implementation found.");
|
||||
}
|
||||
return constructor;
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export const Map = NativeCollections.tryGetNativeMap();
|
||||
/* @internal */
|
||||
export const Set = NativeCollections.tryGetNativeSet();
|
||||
/**
|
||||
* Type of objects whose values are all of the same type.
|
||||
* The `in` and `for-in` operators can *not* be safely used,
|
||||
* since `Object.prototype` may be modified by outside code.
|
||||
*/
|
||||
export interface MapLike<T> {
|
||||
[index: string]: T;
|
||||
}
|
||||
|
||||
export interface SortedReadonlyArray<T> extends ReadonlyArray<T> {
|
||||
" __sortedArrayBrand": any;
|
||||
}
|
||||
|
||||
export interface SortedArray<T> extends Array<T> {
|
||||
" __sortedArrayBrand": any;
|
||||
}
|
||||
|
||||
/** Common read methods for ES6 Map/Set. */
|
||||
export interface ReadonlyCollection<K> {
|
||||
readonly size: number;
|
||||
has(key: K): boolean;
|
||||
keys(): Iterator<K>;
|
||||
}
|
||||
|
||||
/** Common write methods for ES6 Map/Set. */
|
||||
export interface Collection<K> extends ReadonlyCollection<K> {
|
||||
delete(key: K): boolean;
|
||||
clear(): void;
|
||||
}
|
||||
|
||||
/** ES6 Map interface, only read methods included. */
|
||||
export interface ReadonlyESMap<K, V> extends ReadonlyCollection<K> {
|
||||
get(key: K): V | undefined;
|
||||
values(): Iterator<V>;
|
||||
entries(): Iterator<[K, V]>;
|
||||
forEach(action: (value: V, key: K) => void): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* ES6 Map interface, only read methods included.
|
||||
*/
|
||||
export interface ReadonlyMap<T> extends ReadonlyESMap<string, T> {
|
||||
}
|
||||
|
||||
/** ES6 Map interface. */
|
||||
export interface ESMap<K, V> extends ReadonlyESMap<K, V>, Collection<K> {
|
||||
set(key: K, value: V): this;
|
||||
}
|
||||
|
||||
/**
|
||||
* ES6 Map interface.
|
||||
*/
|
||||
export interface Map<T> extends ESMap<string, T> {
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface MapConstructor {
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-function-type
|
||||
new <K, V>(iterable?: readonly (readonly [K, V])[] | ReadonlyESMap<K, V>): ESMap<K, V>;
|
||||
}
|
||||
|
||||
/** ES6 Set interface, only read methods included. */
|
||||
export interface ReadonlySet<T> extends ReadonlyCollection<T> {
|
||||
has(value: T): boolean;
|
||||
values(): Iterator<T>;
|
||||
entries(): Iterator<[T, T]>;
|
||||
forEach(action: (value: T, key: T) => void): void;
|
||||
}
|
||||
|
||||
/** ES6 Set interface. */
|
||||
export interface Set<T> extends ReadonlySet<T>, Collection<T> {
|
||||
add(value: T): this;
|
||||
delete(value: T): boolean;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface SetConstructor {
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-function-type
|
||||
new <T>(iterable?: readonly T[] | ReadonlySet<T>): Set<T>;
|
||||
}
|
||||
|
||||
/** ES6 Iterator type. */
|
||||
export interface Iterator<T> {
|
||||
next(): { value: T, done?: false } | { value: void, done: true };
|
||||
}
|
||||
|
||||
/** Array that is only intended to be pushed to, never read. */
|
||||
export interface Push<T> {
|
||||
push(...values: T[]): void;
|
||||
/** @internal */ readonly length: number;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export type EqualityComparer<T> = (a: T, b: T) => boolean;
|
||||
|
||||
/** @internal */
|
||||
export type Comparer<T> = (a: T, b: T) => Comparison;
|
||||
|
||||
/** @internal */
|
||||
export const enum Comparison {
|
||||
LessThan = -1,
|
||||
EqualTo = 0,
|
||||
GreaterThan = 1
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
namespace NativeCollections {
|
||||
declare const self: any;
|
||||
|
||||
const globals = typeof globalThis !== "undefined" ? globalThis :
|
||||
typeof global !== "undefined" ? global :
|
||||
typeof self !== "undefined" ? self :
|
||||
undefined;
|
||||
|
||||
/**
|
||||
* Returns the native Map implementation if it is available and compatible (i.e. supports iteration).
|
||||
*/
|
||||
export function tryGetNativeMap(): MapConstructor {
|
||||
// Internet Explorer's Map doesn't support iteration, so don't use it.
|
||||
const gMap = globals?.Map;
|
||||
// eslint-disable-next-line local/no-in-operator
|
||||
const constructor = typeof gMap !== "undefined" && "entries" in gMap.prototype && new gMap([[0, 0]]).size === 1 ? gMap : undefined;
|
||||
if (!constructor) {
|
||||
throw new Error("No compatible Map implementation found.");
|
||||
}
|
||||
return constructor;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the native Set implementation if it is available and compatible (i.e. supports iteration).
|
||||
*/
|
||||
export function tryGetNativeSet(): SetConstructor {
|
||||
// Internet Explorer's Set doesn't support iteration, so don't use it.
|
||||
const gSet = globals?.Set;
|
||||
// eslint-disable-next-line local/no-in-operator
|
||||
const constructor = typeof gSet !== "undefined" && "entries" in gSet.prototype && new gSet([0]).size === 1 ? gSet : undefined;
|
||||
if (!constructor) {
|
||||
throw new Error("No compatible Set implementation found.");
|
||||
}
|
||||
return constructor;
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export const Map = NativeCollections.tryGetNativeMap();
|
||||
/** @internal */
|
||||
export const Set = NativeCollections.tryGetNativeSet();
|
||||
|
||||
+1116
-753
File diff suppressed because it is too large
Load Diff
+5794
-5709
File diff suppressed because it is too large
Load Diff
@@ -1,54 +1,56 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
/**
|
||||
* A `BaseNodeFactory` is an abstraction over an `ObjectAllocator` that handles caching `Node` constructors
|
||||
* and allocating `Node` instances based on a set of predefined types.
|
||||
*/
|
||||
/* @internal */
|
||||
export interface BaseNodeFactory {
|
||||
createBaseSourceFileNode(kind: SyntaxKind): Node;
|
||||
createBaseIdentifierNode(kind: SyntaxKind): Node;
|
||||
createBasePrivateIdentifierNode(kind: SyntaxKind): Node;
|
||||
createBaseTokenNode(kind: SyntaxKind): Node;
|
||||
createBaseNode(kind: SyntaxKind): Node;
|
||||
import { Node, objectAllocator, SyntaxKind } from "../_namespaces/ts";
|
||||
|
||||
/**
|
||||
* A `BaseNodeFactory` is an abstraction over an `ObjectAllocator` that handles caching `Node` constructors
|
||||
* and allocating `Node` instances based on a set of predefined types.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export interface BaseNodeFactory {
|
||||
createBaseSourceFileNode(kind: SyntaxKind): Node;
|
||||
createBaseIdentifierNode(kind: SyntaxKind): Node;
|
||||
createBasePrivateIdentifierNode(kind: SyntaxKind): Node;
|
||||
createBaseTokenNode(kind: SyntaxKind): Node;
|
||||
createBaseNode(kind: SyntaxKind): Node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a `BaseNodeFactory` which can be used to create `Node` instances from the constructors provided by the object allocator.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function createBaseNodeFactory(): BaseNodeFactory {
|
||||
let NodeConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
|
||||
let TokenConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
|
||||
let IdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
|
||||
let PrivateIdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
|
||||
let SourceFileConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
|
||||
|
||||
return {
|
||||
createBaseSourceFileNode,
|
||||
createBaseIdentifierNode,
|
||||
createBasePrivateIdentifierNode,
|
||||
createBaseTokenNode,
|
||||
createBaseNode
|
||||
};
|
||||
|
||||
function createBaseSourceFileNode(kind: SyntaxKind): Node {
|
||||
return new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, /*pos*/ -1, /*end*/ -1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a `BaseNodeFactory` which can be used to create `Node` instances from the constructors provided by the object allocator.
|
||||
*/
|
||||
export function createBaseNodeFactory(): BaseNodeFactory {
|
||||
let NodeConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
|
||||
let TokenConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
|
||||
let IdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
|
||||
let PrivateIdentifierConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
|
||||
let SourceFileConstructor: new (kind: SyntaxKind, pos?: number, end?: number) => Node;
|
||||
function createBaseIdentifierNode(kind: SyntaxKind): Node {
|
||||
return new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, /*pos*/ -1, /*end*/ -1);
|
||||
}
|
||||
|
||||
return {
|
||||
createBaseSourceFileNode,
|
||||
createBaseIdentifierNode,
|
||||
createBasePrivateIdentifierNode,
|
||||
createBaseTokenNode,
|
||||
createBaseNode
|
||||
};
|
||||
function createBasePrivateIdentifierNode(kind: SyntaxKind): Node {
|
||||
return new (PrivateIdentifierConstructor || (PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor()))(kind, /*pos*/ -1, /*end*/ -1);
|
||||
}
|
||||
|
||||
function createBaseSourceFileNode(kind: SyntaxKind): Node {
|
||||
return new (SourceFileConstructor || (SourceFileConstructor = objectAllocator.getSourceFileConstructor()))(kind, /*pos*/ -1, /*end*/ -1);
|
||||
}
|
||||
function createBaseTokenNode(kind: SyntaxKind): Node {
|
||||
return new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, /*pos*/ -1, /*end*/ -1);
|
||||
}
|
||||
|
||||
function createBaseIdentifierNode(kind: SyntaxKind): Node {
|
||||
return new (IdentifierConstructor || (IdentifierConstructor = objectAllocator.getIdentifierConstructor()))(kind, /*pos*/ -1, /*end*/ -1);
|
||||
}
|
||||
|
||||
function createBasePrivateIdentifierNode(kind: SyntaxKind): Node {
|
||||
return new (PrivateIdentifierConstructor || (PrivateIdentifierConstructor = objectAllocator.getPrivateIdentifierConstructor()))(kind, /*pos*/ -1, /*end*/ -1);
|
||||
}
|
||||
|
||||
function createBaseTokenNode(kind: SyntaxKind): Node {
|
||||
return new (TokenConstructor || (TokenConstructor = objectAllocator.getTokenConstructor()))(kind, /*pos*/ -1, /*end*/ -1);
|
||||
}
|
||||
|
||||
function createBaseNode(kind: SyntaxKind): Node {
|
||||
return new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, /*pos*/ -1, /*end*/ -1);
|
||||
}
|
||||
function createBaseNode(kind: SyntaxKind): Node {
|
||||
return new (NodeConstructor || (NodeConstructor = objectAllocator.getNodeConstructor()))(kind, /*pos*/ -1, /*end*/ -1);
|
||||
}
|
||||
}
|
||||
|
||||
+843
-802
File diff suppressed because it is too large
Load Diff
+285
-276
@@ -1,294 +1,303 @@
|
||||
namespace ts {
|
||||
/**
|
||||
* Associates a node with the current transformation, initializing
|
||||
* various transient transformation properties.
|
||||
* @internal
|
||||
*/
|
||||
export function getOrCreateEmitNode(node: Node): EmitNode {
|
||||
if (!node.emitNode) {
|
||||
if (isParseTreeNode(node)) {
|
||||
// To avoid holding onto transformation artifacts, we keep track of any
|
||||
// parse tree node we are annotating. This allows us to clean them up after
|
||||
// all transformations have completed.
|
||||
if (node.kind === SyntaxKind.SourceFile) {
|
||||
return node.emitNode = { annotatedNodes: [node] } as EmitNode;
|
||||
}
|
||||
import {
|
||||
AccessExpression, append, appendIfUnique, Debug, EmitFlags, EmitHelper, EmitNode, getParseTreeNode,
|
||||
getSourceFileOfNode, isParseTreeNode, Node, orderedRemoveItem, SnippetElement, some, SourceFile, SourceMapRange,
|
||||
SyntaxKind, SynthesizedComment, TextRange, TypeNode,
|
||||
} from "../_namespaces/ts";
|
||||
|
||||
const sourceFile = getSourceFileOfNode(getParseTreeNode(getSourceFileOfNode(node))) ?? Debug.fail("Could not determine parsed source file.");
|
||||
getOrCreateEmitNode(sourceFile).annotatedNodes!.push(node);
|
||||
/**
|
||||
* Associates a node with the current transformation, initializing
|
||||
* various transient transformation properties.
|
||||
* @internal
|
||||
*/
|
||||
export function getOrCreateEmitNode(node: Node): EmitNode {
|
||||
if (!node.emitNode) {
|
||||
if (isParseTreeNode(node)) {
|
||||
// To avoid holding onto transformation artifacts, we keep track of any
|
||||
// parse tree node we are annotating. This allows us to clean them up after
|
||||
// all transformations have completed.
|
||||
if (node.kind === SyntaxKind.SourceFile) {
|
||||
return node.emitNode = { annotatedNodes: [node] } as EmitNode;
|
||||
}
|
||||
|
||||
node.emitNode = {} as EmitNode;
|
||||
}
|
||||
else {
|
||||
Debug.assert(!(node.emitNode.flags & EmitFlags.Immutable), "Invalid attempt to mutate an immutable node.");
|
||||
}
|
||||
return node.emitNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears any `EmitNode` entries from parse-tree nodes.
|
||||
* @param sourceFile A source file.
|
||||
*/
|
||||
export function disposeEmitNodes(sourceFile: SourceFile | undefined) {
|
||||
// During transformation we may need to annotate a parse tree node with transient
|
||||
// transformation properties. As parse tree nodes live longer than transformation
|
||||
// nodes, we need to make sure we reclaim any memory allocated for custom ranges
|
||||
// from these nodes to ensure we do not hold onto entire subtrees just for position
|
||||
// information. We also need to reset these nodes to a pre-transformation state
|
||||
// for incremental parsing scenarios so that we do not impact later emit.
|
||||
const annotatedNodes = getSourceFileOfNode(getParseTreeNode(sourceFile))?.emitNode?.annotatedNodes;
|
||||
if (annotatedNodes) {
|
||||
for (const node of annotatedNodes) {
|
||||
node.emitNode = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets `EmitFlags.NoComments` on a node and removes any leading and trailing synthetic comments.
|
||||
* @internal
|
||||
*/
|
||||
export function removeAllComments<T extends Node>(node: T): T {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
emitNode.flags |= EmitFlags.NoComments;
|
||||
emitNode.leadingComments = undefined;
|
||||
emitNode.trailingComments = undefined;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets flags that control emit behavior of a node.
|
||||
*/
|
||||
export function setEmitFlags<T extends Node>(node: T, emitFlags: EmitFlags) {
|
||||
getOrCreateEmitNode(node).flags = emitFlags;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets flags that control emit behavior of a node.
|
||||
*/
|
||||
/* @internal */
|
||||
export function addEmitFlags<T extends Node>(node: T, emitFlags: EmitFlags) {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
emitNode.flags = emitNode.flags | emitFlags;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a custom text range to use when emitting source maps.
|
||||
*/
|
||||
export function getSourceMapRange(node: Node): SourceMapRange {
|
||||
return node.emitNode?.sourceMapRange ?? node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom text range to use when emitting source maps.
|
||||
*/
|
||||
export function setSourceMapRange<T extends Node>(node: T, range: SourceMapRange | undefined) {
|
||||
getOrCreateEmitNode(node).sourceMapRange = range;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the TextRange to use for source maps for a token of a node.
|
||||
*/
|
||||
export function getTokenSourceMapRange(node: Node, token: SyntaxKind): SourceMapRange | undefined {
|
||||
return node.emitNode?.tokenSourceMapRanges?.[token];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the TextRange to use for source maps for a token of a node.
|
||||
*/
|
||||
export function setTokenSourceMapRange<T extends Node>(node: T, token: SyntaxKind, range: SourceMapRange | undefined) {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
const tokenSourceMapRanges = emitNode.tokenSourceMapRanges ?? (emitNode.tokenSourceMapRanges = []);
|
||||
tokenSourceMapRanges[token] = range;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a custom text range to use when emitting comments.
|
||||
*/
|
||||
/*@internal*/
|
||||
export function getStartsOnNewLine(node: Node) {
|
||||
return node.emitNode?.startsOnNewLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom text range to use when emitting comments.
|
||||
*/
|
||||
/*@internal*/
|
||||
export function setStartsOnNewLine<T extends Node>(node: T, newLine: boolean) {
|
||||
getOrCreateEmitNode(node).startsOnNewLine = newLine;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a custom text range to use when emitting comments.
|
||||
*/
|
||||
export function getCommentRange(node: Node): TextRange {
|
||||
return node.emitNode?.commentRange ?? node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom text range to use when emitting comments.
|
||||
*/
|
||||
export function setCommentRange<T extends Node>(node: T, range: TextRange) {
|
||||
getOrCreateEmitNode(node).commentRange = range;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function getSyntheticLeadingComments(node: Node): SynthesizedComment[] | undefined {
|
||||
return node.emitNode?.leadingComments;
|
||||
}
|
||||
|
||||
export function setSyntheticLeadingComments<T extends Node>(node: T, comments: SynthesizedComment[] | undefined) {
|
||||
getOrCreateEmitNode(node).leadingComments = comments;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function addSyntheticLeadingComment<T extends Node>(node: T, kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, text: string, hasTrailingNewLine?: boolean) {
|
||||
return setSyntheticLeadingComments(node, append<SynthesizedComment>(getSyntheticLeadingComments(node), { kind, pos: -1, end: -1, hasTrailingNewLine, text }));
|
||||
}
|
||||
|
||||
export function getSyntheticTrailingComments(node: Node): SynthesizedComment[] | undefined {
|
||||
return node.emitNode?.trailingComments;
|
||||
}
|
||||
|
||||
export function setSyntheticTrailingComments<T extends Node>(node: T, comments: SynthesizedComment[] | undefined) {
|
||||
getOrCreateEmitNode(node).trailingComments = comments;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function addSyntheticTrailingComment<T extends Node>(node: T, kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, text: string, hasTrailingNewLine?: boolean) {
|
||||
return setSyntheticTrailingComments(node, append<SynthesizedComment>(getSyntheticTrailingComments(node), { kind, pos: -1, end: -1, hasTrailingNewLine, text }));
|
||||
}
|
||||
|
||||
export function moveSyntheticComments<T extends Node>(node: T, original: Node): T {
|
||||
setSyntheticLeadingComments(node, getSyntheticLeadingComments(original));
|
||||
setSyntheticTrailingComments(node, getSyntheticTrailingComments(original));
|
||||
const emit = getOrCreateEmitNode(original);
|
||||
emit.leadingComments = undefined;
|
||||
emit.trailingComments = undefined;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the constant value to emit for an expression representing an enum.
|
||||
*/
|
||||
export function getConstantValue(node: AccessExpression): string | number | undefined {
|
||||
return node.emitNode?.constantValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the constant value to emit for an expression.
|
||||
*/
|
||||
export function setConstantValue(node: AccessExpression, value: string | number): AccessExpression {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
emitNode.constantValue = value;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an EmitHelper to a node.
|
||||
*/
|
||||
export function addEmitHelper<T extends Node>(node: T, helper: EmitHelper): T {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
emitNode.helpers = append(emitNode.helpers, helper);
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add EmitHelpers to a node.
|
||||
*/
|
||||
export function addEmitHelpers<T extends Node>(node: T, helpers: EmitHelper[] | undefined): T {
|
||||
if (some(helpers)) {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
for (const helper of helpers) {
|
||||
emitNode.helpers = appendIfUnique(emitNode.helpers, helper);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes an EmitHelper from a node.
|
||||
*/
|
||||
export function removeEmitHelper(node: Node, helper: EmitHelper): boolean {
|
||||
const helpers = node.emitNode?.helpers;
|
||||
if (helpers) {
|
||||
return orderedRemoveItem(helpers, helper);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the EmitHelpers of a node.
|
||||
*/
|
||||
export function getEmitHelpers(node: Node): EmitHelper[] | undefined {
|
||||
return node.emitNode?.helpers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Moves matching emit helpers from a source node to a target node.
|
||||
*/
|
||||
export function moveEmitHelpers(source: Node, target: Node, predicate: (helper: EmitHelper) => boolean) {
|
||||
const sourceEmitNode = source.emitNode;
|
||||
const sourceEmitHelpers = sourceEmitNode && sourceEmitNode.helpers;
|
||||
if (!some(sourceEmitHelpers)) return;
|
||||
|
||||
const targetEmitNode = getOrCreateEmitNode(target);
|
||||
let helpersRemoved = 0;
|
||||
for (let i = 0; i < sourceEmitHelpers.length; i++) {
|
||||
const helper = sourceEmitHelpers[i];
|
||||
if (predicate(helper)) {
|
||||
helpersRemoved++;
|
||||
targetEmitNode.helpers = appendIfUnique(targetEmitNode.helpers, helper);
|
||||
}
|
||||
else if (helpersRemoved > 0) {
|
||||
sourceEmitHelpers[i - helpersRemoved] = helper;
|
||||
}
|
||||
const sourceFile = getSourceFileOfNode(getParseTreeNode(getSourceFileOfNode(node))) ?? Debug.fail("Could not determine parsed source file.");
|
||||
getOrCreateEmitNode(sourceFile).annotatedNodes!.push(node);
|
||||
}
|
||||
|
||||
if (helpersRemoved > 0) {
|
||||
sourceEmitHelpers.length -= helpersRemoved;
|
||||
node.emitNode = {} as EmitNode;
|
||||
}
|
||||
else {
|
||||
Debug.assert(!(node.emitNode.flags & EmitFlags.Immutable), "Invalid attempt to mutate an immutable node.");
|
||||
}
|
||||
return node.emitNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clears any `EmitNode` entries from parse-tree nodes.
|
||||
* @param sourceFile A source file.
|
||||
*/
|
||||
export function disposeEmitNodes(sourceFile: SourceFile | undefined) {
|
||||
// During transformation we may need to annotate a parse tree node with transient
|
||||
// transformation properties. As parse tree nodes live longer than transformation
|
||||
// nodes, we need to make sure we reclaim any memory allocated for custom ranges
|
||||
// from these nodes to ensure we do not hold onto entire subtrees just for position
|
||||
// information. We also need to reset these nodes to a pre-transformation state
|
||||
// for incremental parsing scenarios so that we do not impact later emit.
|
||||
const annotatedNodes = getSourceFileOfNode(getParseTreeNode(sourceFile))?.emitNode?.annotatedNodes;
|
||||
if (annotatedNodes) {
|
||||
for (const node of annotatedNodes) {
|
||||
node.emitNode = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SnippetElement of a node.
|
||||
*/
|
||||
/* @internal */
|
||||
export function getSnippetElement(node: Node): SnippetElement | undefined {
|
||||
return node.emitNode?.snippetElement;
|
||||
}
|
||||
/**
|
||||
* Sets `EmitFlags.NoComments` on a node and removes any leading and trailing synthetic comments.
|
||||
* @internal
|
||||
*/
|
||||
export function removeAllComments<T extends Node>(node: T): T {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
emitNode.flags |= EmitFlags.NoComments;
|
||||
emitNode.leadingComments = undefined;
|
||||
emitNode.trailingComments = undefined;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets flags that control emit behavior of a node.
|
||||
*/
|
||||
export function setEmitFlags<T extends Node>(node: T, emitFlags: EmitFlags) {
|
||||
getOrCreateEmitNode(node).flags = emitFlags;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets flags that control emit behavior of a node.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function addEmitFlags<T extends Node>(node: T, emitFlags: EmitFlags) {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
emitNode.flags = emitNode.flags | emitFlags;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a custom text range to use when emitting source maps.
|
||||
*/
|
||||
export function getSourceMapRange(node: Node): SourceMapRange {
|
||||
return node.emitNode?.sourceMapRange ?? node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom text range to use when emitting source maps.
|
||||
*/
|
||||
export function setSourceMapRange<T extends Node>(node: T, range: SourceMapRange | undefined) {
|
||||
getOrCreateEmitNode(node).sourceMapRange = range;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the TextRange to use for source maps for a token of a node.
|
||||
*/
|
||||
export function getTokenSourceMapRange(node: Node, token: SyntaxKind): SourceMapRange | undefined {
|
||||
return node.emitNode?.tokenSourceMapRanges?.[token];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the TextRange to use for source maps for a token of a node.
|
||||
*/
|
||||
export function setTokenSourceMapRange<T extends Node>(node: T, token: SyntaxKind, range: SourceMapRange | undefined) {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
const tokenSourceMapRanges = emitNode.tokenSourceMapRanges ?? (emitNode.tokenSourceMapRanges = []);
|
||||
tokenSourceMapRanges[token] = range;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a custom text range to use when emitting comments.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function getStartsOnNewLine(node: Node) {
|
||||
return node.emitNode?.startsOnNewLine;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom text range to use when emitting comments.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function setStartsOnNewLine<T extends Node>(node: T, newLine: boolean) {
|
||||
getOrCreateEmitNode(node).startsOnNewLine = newLine;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a custom text range to use when emitting comments.
|
||||
*/
|
||||
export function getCommentRange(node: Node): TextRange {
|
||||
return node.emitNode?.commentRange ?? node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a custom text range to use when emitting comments.
|
||||
*/
|
||||
export function setCommentRange<T extends Node>(node: T, range: TextRange) {
|
||||
getOrCreateEmitNode(node).commentRange = range;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function getSyntheticLeadingComments(node: Node): SynthesizedComment[] | undefined {
|
||||
return node.emitNode?.leadingComments;
|
||||
}
|
||||
|
||||
export function setSyntheticLeadingComments<T extends Node>(node: T, comments: SynthesizedComment[] | undefined) {
|
||||
getOrCreateEmitNode(node).leadingComments = comments;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function addSyntheticLeadingComment<T extends Node>(node: T, kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, text: string, hasTrailingNewLine?: boolean) {
|
||||
return setSyntheticLeadingComments(node, append<SynthesizedComment>(getSyntheticLeadingComments(node), { kind, pos: -1, end: -1, hasTrailingNewLine, text }));
|
||||
}
|
||||
|
||||
export function getSyntheticTrailingComments(node: Node): SynthesizedComment[] | undefined {
|
||||
return node.emitNode?.trailingComments;
|
||||
}
|
||||
|
||||
export function setSyntheticTrailingComments<T extends Node>(node: T, comments: SynthesizedComment[] | undefined) {
|
||||
getOrCreateEmitNode(node).trailingComments = comments;
|
||||
return node;
|
||||
}
|
||||
|
||||
export function addSyntheticTrailingComment<T extends Node>(node: T, kind: SyntaxKind.SingleLineCommentTrivia | SyntaxKind.MultiLineCommentTrivia, text: string, hasTrailingNewLine?: boolean) {
|
||||
return setSyntheticTrailingComments(node, append<SynthesizedComment>(getSyntheticTrailingComments(node), { kind, pos: -1, end: -1, hasTrailingNewLine, text }));
|
||||
}
|
||||
|
||||
export function moveSyntheticComments<T extends Node>(node: T, original: Node): T {
|
||||
setSyntheticLeadingComments(node, getSyntheticLeadingComments(original));
|
||||
setSyntheticTrailingComments(node, getSyntheticTrailingComments(original));
|
||||
const emit = getOrCreateEmitNode(original);
|
||||
emit.leadingComments = undefined;
|
||||
emit.trailingComments = undefined;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the constant value to emit for an expression representing an enum.
|
||||
*/
|
||||
export function getConstantValue(node: AccessExpression): string | number | undefined {
|
||||
return node.emitNode?.constantValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the constant value to emit for an expression.
|
||||
*/
|
||||
export function setConstantValue(node: AccessExpression, value: string | number): AccessExpression {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
emitNode.constantValue = value;
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an EmitHelper to a node.
|
||||
*/
|
||||
export function addEmitHelper<T extends Node>(node: T, helper: EmitHelper): T {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
emitNode.helpers = append(emitNode.helpers, helper);
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SnippetElement of a node.
|
||||
*/
|
||||
/* @internal */
|
||||
export function setSnippetElement<T extends Node>(node: T, snippet: SnippetElement): T {
|
||||
/**
|
||||
* Add EmitHelpers to a node.
|
||||
*/
|
||||
export function addEmitHelpers<T extends Node>(node: T, helpers: EmitHelper[] | undefined): T {
|
||||
if (some(helpers)) {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
emitNode.snippetElement = snippet;
|
||||
return node;
|
||||
for (const helper of helpers) {
|
||||
emitNode.helpers = appendIfUnique(emitNode.helpers, helper);
|
||||
}
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function ignoreSourceNewlines<T extends Node>(node: T): T {
|
||||
getOrCreateEmitNode(node).flags |= EmitFlags.IgnoreSourceNewlines;
|
||||
return node;
|
||||
/**
|
||||
* Removes an EmitHelper from a node.
|
||||
*/
|
||||
export function removeEmitHelper(node: Node, helper: EmitHelper): boolean {
|
||||
const helpers = node.emitNode?.helpers;
|
||||
if (helpers) {
|
||||
return orderedRemoveItem(helpers, helper);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the EmitHelpers of a node.
|
||||
*/
|
||||
export function getEmitHelpers(node: Node): EmitHelper[] | undefined {
|
||||
return node.emitNode?.helpers;
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function setTypeNode<T extends Node>(node: T, type: TypeNode): T {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
emitNode.typeNode = type;
|
||||
return node;
|
||||
/**
|
||||
* Moves matching emit helpers from a source node to a target node.
|
||||
*/
|
||||
export function moveEmitHelpers(source: Node, target: Node, predicate: (helper: EmitHelper) => boolean) {
|
||||
const sourceEmitNode = source.emitNode;
|
||||
const sourceEmitHelpers = sourceEmitNode && sourceEmitNode.helpers;
|
||||
if (!some(sourceEmitHelpers)) return;
|
||||
|
||||
const targetEmitNode = getOrCreateEmitNode(target);
|
||||
let helpersRemoved = 0;
|
||||
for (let i = 0; i < sourceEmitHelpers.length; i++) {
|
||||
const helper = sourceEmitHelpers[i];
|
||||
if (predicate(helper)) {
|
||||
helpersRemoved++;
|
||||
targetEmitNode.helpers = appendIfUnique(targetEmitNode.helpers, helper);
|
||||
}
|
||||
else if (helpersRemoved > 0) {
|
||||
sourceEmitHelpers[i - helpersRemoved] = helper;
|
||||
}
|
||||
}
|
||||
|
||||
/* @internal */
|
||||
export function getTypeNode<T extends Node>(node: T): TypeNode | undefined {
|
||||
return node.emitNode?.typeNode;
|
||||
if (helpersRemoved > 0) {
|
||||
sourceEmitHelpers.length -= helpersRemoved;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SnippetElement of a node.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function getSnippetElement(node: Node): SnippetElement | undefined {
|
||||
return node.emitNode?.snippetElement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the SnippetElement of a node.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function setSnippetElement<T extends Node>(node: T, snippet: SnippetElement): T {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
emitNode.snippetElement = snippet;
|
||||
return node;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function ignoreSourceNewlines<T extends Node>(node: T): T {
|
||||
getOrCreateEmitNode(node).flags |= EmitFlags.IgnoreSourceNewlines;
|
||||
return node;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function setTypeNode<T extends Node>(node: T, type: TypeNode): T {
|
||||
const emitNode = getOrCreateEmitNode(node);
|
||||
emitNode.typeNode = type;
|
||||
return node;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function getTypeNode<T extends Node>(node: T): TypeNode | undefined {
|
||||
return node.emitNode?.typeNode;
|
||||
}
|
||||
|
||||
@@ -1,137 +1,145 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export function createNodeConverters(factory: NodeFactory): NodeConverters {
|
||||
return {
|
||||
convertToFunctionBlock,
|
||||
convertToFunctionExpression,
|
||||
convertToArrayAssignmentElement,
|
||||
convertToObjectAssignmentElement,
|
||||
convertToAssignmentPattern,
|
||||
convertToObjectAssignmentPattern,
|
||||
convertToArrayAssignmentPattern,
|
||||
convertToAssignmentElementTarget,
|
||||
};
|
||||
import {
|
||||
ArrayBindingOrAssignmentElement, ArrayBindingOrAssignmentPattern, AssignmentPattern,
|
||||
BindingOrAssignmentElementTarget, BindingOrAssignmentPattern, Block, cast, ConciseBody, Debug, Expression,
|
||||
FunctionDeclaration, getStartsOnNewLine, isArrayBindingPattern, isArrayLiteralExpression, isBindingElement,
|
||||
isBindingPattern, isBlock, isExpression, isIdentifier, isObjectBindingPattern, isObjectLiteralElementLike,
|
||||
isObjectLiteralExpression, map, NodeConverters, NodeFactory, notImplemented, ObjectBindingOrAssignmentElement,
|
||||
ObjectBindingOrAssignmentPattern, setOriginalNode, setStartsOnNewLine, setTextRange, SyntaxKind,
|
||||
} from "../_namespaces/ts";
|
||||
|
||||
function convertToFunctionBlock(node: ConciseBody, multiLine?: boolean): Block {
|
||||
if (isBlock(node)) return node;
|
||||
const returnStatement = factory.createReturnStatement(node);
|
||||
setTextRange(returnStatement, node);
|
||||
const body = factory.createBlock([returnStatement], multiLine);
|
||||
setTextRange(body, node);
|
||||
return body;
|
||||
/** @internal */
|
||||
export function createNodeConverters(factory: NodeFactory): NodeConverters {
|
||||
return {
|
||||
convertToFunctionBlock,
|
||||
convertToFunctionExpression,
|
||||
convertToArrayAssignmentElement,
|
||||
convertToObjectAssignmentElement,
|
||||
convertToAssignmentPattern,
|
||||
convertToObjectAssignmentPattern,
|
||||
convertToArrayAssignmentPattern,
|
||||
convertToAssignmentElementTarget,
|
||||
};
|
||||
|
||||
function convertToFunctionBlock(node: ConciseBody, multiLine?: boolean): Block {
|
||||
if (isBlock(node)) return node;
|
||||
const returnStatement = factory.createReturnStatement(node);
|
||||
setTextRange(returnStatement, node);
|
||||
const body = factory.createBlock([returnStatement], multiLine);
|
||||
setTextRange(body, node);
|
||||
return body;
|
||||
}
|
||||
|
||||
function convertToFunctionExpression(node: FunctionDeclaration) {
|
||||
if (!node.body) return Debug.fail(`Cannot convert a FunctionDeclaration without a body`);
|
||||
const updated = factory.createFunctionExpression(
|
||||
node.modifiers,
|
||||
node.asteriskToken,
|
||||
node.name,
|
||||
node.typeParameters,
|
||||
node.parameters,
|
||||
node.type,
|
||||
node.body
|
||||
);
|
||||
setOriginalNode(updated, node);
|
||||
setTextRange(updated, node);
|
||||
if (getStartsOnNewLine(node)) {
|
||||
setStartsOnNewLine(updated, /*newLine*/ true);
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
function convertToFunctionExpression(node: FunctionDeclaration) {
|
||||
if (!node.body) return Debug.fail(`Cannot convert a FunctionDeclaration without a body`);
|
||||
const updated = factory.createFunctionExpression(
|
||||
node.modifiers,
|
||||
node.asteriskToken,
|
||||
node.name,
|
||||
node.typeParameters,
|
||||
node.parameters,
|
||||
node.type,
|
||||
node.body
|
||||
);
|
||||
setOriginalNode(updated, node);
|
||||
setTextRange(updated, node);
|
||||
if (getStartsOnNewLine(node)) {
|
||||
setStartsOnNewLine(updated, /*newLine*/ true);
|
||||
}
|
||||
return updated;
|
||||
}
|
||||
|
||||
function convertToArrayAssignmentElement(element: ArrayBindingOrAssignmentElement) {
|
||||
if (isBindingElement(element)) {
|
||||
if (element.dotDotDotToken) {
|
||||
Debug.assertNode(element.name, isIdentifier);
|
||||
return setOriginalNode(setTextRange(factory.createSpreadElement(element.name), element), element);
|
||||
}
|
||||
const expression = convertToAssignmentElementTarget(element.name);
|
||||
return element.initializer
|
||||
? setOriginalNode(
|
||||
setTextRange(
|
||||
factory.createAssignment(expression, element.initializer),
|
||||
element
|
||||
),
|
||||
element
|
||||
)
|
||||
: expression;
|
||||
}
|
||||
return cast(element, isExpression);
|
||||
}
|
||||
|
||||
function convertToObjectAssignmentElement(element: ObjectBindingOrAssignmentElement) {
|
||||
if (isBindingElement(element)) {
|
||||
if (element.dotDotDotToken) {
|
||||
Debug.assertNode(element.name, isIdentifier);
|
||||
return setOriginalNode(setTextRange(factory.createSpreadAssignment(element.name), element), element);
|
||||
}
|
||||
if (element.propertyName) {
|
||||
const expression = convertToAssignmentElementTarget(element.name);
|
||||
return setOriginalNode(setTextRange(factory.createPropertyAssignment(element.propertyName, element.initializer ? factory.createAssignment(expression, element.initializer) : expression), element), element);
|
||||
}
|
||||
function convertToArrayAssignmentElement(element: ArrayBindingOrAssignmentElement) {
|
||||
if (isBindingElement(element)) {
|
||||
if (element.dotDotDotToken) {
|
||||
Debug.assertNode(element.name, isIdentifier);
|
||||
return setOriginalNode(setTextRange(factory.createShorthandPropertyAssignment(element.name, element.initializer), element), element);
|
||||
return setOriginalNode(setTextRange(factory.createSpreadElement(element.name), element), element);
|
||||
}
|
||||
|
||||
return cast(element, isObjectLiteralElementLike);
|
||||
}
|
||||
|
||||
function convertToAssignmentPattern(node: BindingOrAssignmentPattern): AssignmentPattern {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ArrayBindingPattern:
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
return convertToArrayAssignmentPattern(node);
|
||||
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
return convertToObjectAssignmentPattern(node);
|
||||
}
|
||||
}
|
||||
|
||||
function convertToObjectAssignmentPattern(node: ObjectBindingOrAssignmentPattern) {
|
||||
if (isObjectBindingPattern(node)) {
|
||||
return setOriginalNode(
|
||||
const expression = convertToAssignmentElementTarget(element.name);
|
||||
return element.initializer
|
||||
? setOriginalNode(
|
||||
setTextRange(
|
||||
factory.createObjectLiteralExpression(map(node.elements, convertToObjectAssignmentElement)),
|
||||
node
|
||||
factory.createAssignment(expression, element.initializer),
|
||||
element
|
||||
),
|
||||
node
|
||||
);
|
||||
element
|
||||
)
|
||||
: expression;
|
||||
}
|
||||
return cast(element, isExpression);
|
||||
}
|
||||
|
||||
function convertToObjectAssignmentElement(element: ObjectBindingOrAssignmentElement) {
|
||||
if (isBindingElement(element)) {
|
||||
if (element.dotDotDotToken) {
|
||||
Debug.assertNode(element.name, isIdentifier);
|
||||
return setOriginalNode(setTextRange(factory.createSpreadAssignment(element.name), element), element);
|
||||
}
|
||||
return cast(node, isObjectLiteralExpression);
|
||||
if (element.propertyName) {
|
||||
const expression = convertToAssignmentElementTarget(element.name);
|
||||
return setOriginalNode(setTextRange(factory.createPropertyAssignment(element.propertyName, element.initializer ? factory.createAssignment(expression, element.initializer) : expression), element), element);
|
||||
}
|
||||
Debug.assertNode(element.name, isIdentifier);
|
||||
return setOriginalNode(setTextRange(factory.createShorthandPropertyAssignment(element.name, element.initializer), element), element);
|
||||
}
|
||||
|
||||
function convertToArrayAssignmentPattern(node: ArrayBindingOrAssignmentPattern) {
|
||||
if (isArrayBindingPattern(node)) {
|
||||
return setOriginalNode(
|
||||
setTextRange(
|
||||
factory.createArrayLiteralExpression(map(node.elements, convertToArrayAssignmentElement)),
|
||||
node
|
||||
),
|
||||
node
|
||||
);
|
||||
}
|
||||
return cast(node, isArrayLiteralExpression);
|
||||
}
|
||||
return cast(element, isObjectLiteralElementLike);
|
||||
}
|
||||
|
||||
function convertToAssignmentElementTarget(node: BindingOrAssignmentElementTarget): Expression {
|
||||
if (isBindingPattern(node)) {
|
||||
return convertToAssignmentPattern(node);
|
||||
}
|
||||
function convertToAssignmentPattern(node: BindingOrAssignmentPattern): AssignmentPattern {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ArrayBindingPattern:
|
||||
case SyntaxKind.ArrayLiteralExpression:
|
||||
return convertToArrayAssignmentPattern(node);
|
||||
|
||||
return cast(node, isExpression);
|
||||
case SyntaxKind.ObjectBindingPattern:
|
||||
case SyntaxKind.ObjectLiteralExpression:
|
||||
return convertToObjectAssignmentPattern(node);
|
||||
}
|
||||
}
|
||||
|
||||
export const nullNodeConverters: NodeConverters = {
|
||||
convertToFunctionBlock: notImplemented,
|
||||
convertToFunctionExpression: notImplemented,
|
||||
convertToArrayAssignmentElement: notImplemented,
|
||||
convertToObjectAssignmentElement: notImplemented,
|
||||
convertToAssignmentPattern: notImplemented,
|
||||
convertToObjectAssignmentPattern: notImplemented,
|
||||
convertToArrayAssignmentPattern: notImplemented,
|
||||
convertToAssignmentElementTarget: notImplemented,
|
||||
};
|
||||
}
|
||||
function convertToObjectAssignmentPattern(node: ObjectBindingOrAssignmentPattern) {
|
||||
if (isObjectBindingPattern(node)) {
|
||||
return setOriginalNode(
|
||||
setTextRange(
|
||||
factory.createObjectLiteralExpression(map(node.elements, convertToObjectAssignmentElement)),
|
||||
node
|
||||
),
|
||||
node
|
||||
);
|
||||
}
|
||||
return cast(node, isObjectLiteralExpression);
|
||||
}
|
||||
|
||||
function convertToArrayAssignmentPattern(node: ArrayBindingOrAssignmentPattern) {
|
||||
if (isArrayBindingPattern(node)) {
|
||||
return setOriginalNode(
|
||||
setTextRange(
|
||||
factory.createArrayLiteralExpression(map(node.elements, convertToArrayAssignmentElement)),
|
||||
node
|
||||
),
|
||||
node
|
||||
);
|
||||
}
|
||||
return cast(node, isArrayLiteralExpression);
|
||||
}
|
||||
|
||||
function convertToAssignmentElementTarget(node: BindingOrAssignmentElementTarget): Expression {
|
||||
if (isBindingPattern(node)) {
|
||||
return convertToAssignmentPattern(node);
|
||||
}
|
||||
|
||||
return cast(node, isExpression);
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export const nullNodeConverters: NodeConverters = {
|
||||
convertToFunctionBlock: notImplemented,
|
||||
convertToFunctionExpression: notImplemented,
|
||||
convertToArrayAssignmentElement: notImplemented,
|
||||
convertToObjectAssignmentElement: notImplemented,
|
||||
convertToAssignmentPattern: notImplemented,
|
||||
convertToObjectAssignmentPattern: notImplemented,
|
||||
convertToArrayAssignmentPattern: notImplemented,
|
||||
convertToAssignmentElementTarget: notImplemented,
|
||||
};
|
||||
|
||||
+6865
-6774
File diff suppressed because it is too large
Load Diff
+793
-754
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
+1356
-1237
File diff suppressed because it is too large
Load Diff
@@ -1,45 +1,45 @@
|
||||
namespace ts {
|
||||
export function setTextRange<T extends TextRange>(range: T, location: TextRange | undefined): T {
|
||||
return location ? setTextRangePosEnd(range, location.pos, location.end) : range;
|
||||
}
|
||||
import { HasDecorators, HasModifiers, Node, setTextRangePosEnd, SyntaxKind, TextRange } from "../_namespaces/ts";
|
||||
|
||||
export function canHaveModifiers(node: Node): node is HasModifiers {
|
||||
const kind = node.kind;
|
||||
return kind === SyntaxKind.TypeParameter
|
||||
|| kind === SyntaxKind.Parameter
|
||||
|| kind === SyntaxKind.PropertySignature
|
||||
|| kind === SyntaxKind.PropertyDeclaration
|
||||
|| kind === SyntaxKind.MethodSignature
|
||||
|| kind === SyntaxKind.MethodDeclaration
|
||||
|| kind === SyntaxKind.Constructor
|
||||
|| kind === SyntaxKind.GetAccessor
|
||||
|| kind === SyntaxKind.SetAccessor
|
||||
|| kind === SyntaxKind.IndexSignature
|
||||
|| kind === SyntaxKind.ConstructorType
|
||||
|| kind === SyntaxKind.FunctionExpression
|
||||
|| kind === SyntaxKind.ArrowFunction
|
||||
|| kind === SyntaxKind.ClassExpression
|
||||
|| kind === SyntaxKind.VariableStatement
|
||||
|| kind === SyntaxKind.FunctionDeclaration
|
||||
|| kind === SyntaxKind.ClassDeclaration
|
||||
|| kind === SyntaxKind.InterfaceDeclaration
|
||||
|| kind === SyntaxKind.TypeAliasDeclaration
|
||||
|| kind === SyntaxKind.EnumDeclaration
|
||||
|| kind === SyntaxKind.ModuleDeclaration
|
||||
|| kind === SyntaxKind.ImportEqualsDeclaration
|
||||
|| kind === SyntaxKind.ImportDeclaration
|
||||
|| kind === SyntaxKind.ExportAssignment
|
||||
|| kind === SyntaxKind.ExportDeclaration;
|
||||
}
|
||||
export function setTextRange<T extends TextRange>(range: T, location: TextRange | undefined): T {
|
||||
return location ? setTextRangePosEnd(range, location.pos, location.end) : range;
|
||||
}
|
||||
|
||||
export function canHaveDecorators(node: Node): node is HasDecorators {
|
||||
const kind = node.kind;
|
||||
return kind === SyntaxKind.Parameter
|
||||
|| kind === SyntaxKind.PropertyDeclaration
|
||||
|| kind === SyntaxKind.MethodDeclaration
|
||||
|| kind === SyntaxKind.GetAccessor
|
||||
|| kind === SyntaxKind.SetAccessor
|
||||
|| kind === SyntaxKind.ClassExpression
|
||||
|| kind === SyntaxKind.ClassDeclaration;
|
||||
}
|
||||
export function canHaveModifiers(node: Node): node is HasModifiers {
|
||||
const kind = node.kind;
|
||||
return kind === SyntaxKind.TypeParameter
|
||||
|| kind === SyntaxKind.Parameter
|
||||
|| kind === SyntaxKind.PropertySignature
|
||||
|| kind === SyntaxKind.PropertyDeclaration
|
||||
|| kind === SyntaxKind.MethodSignature
|
||||
|| kind === SyntaxKind.MethodDeclaration
|
||||
|| kind === SyntaxKind.Constructor
|
||||
|| kind === SyntaxKind.GetAccessor
|
||||
|| kind === SyntaxKind.SetAccessor
|
||||
|| kind === SyntaxKind.IndexSignature
|
||||
|| kind === SyntaxKind.ConstructorType
|
||||
|| kind === SyntaxKind.FunctionExpression
|
||||
|| kind === SyntaxKind.ArrowFunction
|
||||
|| kind === SyntaxKind.ClassExpression
|
||||
|| kind === SyntaxKind.VariableStatement
|
||||
|| kind === SyntaxKind.FunctionDeclaration
|
||||
|| kind === SyntaxKind.ClassDeclaration
|
||||
|| kind === SyntaxKind.InterfaceDeclaration
|
||||
|| kind === SyntaxKind.TypeAliasDeclaration
|
||||
|| kind === SyntaxKind.EnumDeclaration
|
||||
|| kind === SyntaxKind.ModuleDeclaration
|
||||
|| kind === SyntaxKind.ImportEqualsDeclaration
|
||||
|| kind === SyntaxKind.ImportDeclaration
|
||||
|| kind === SyntaxKind.ExportAssignment
|
||||
|| kind === SyntaxKind.ExportDeclaration;
|
||||
}
|
||||
|
||||
export function canHaveDecorators(node: Node): node is HasDecorators {
|
||||
const kind = node.kind;
|
||||
return kind === SyntaxKind.Parameter
|
||||
|| kind === SyntaxKind.PropertyDeclaration
|
||||
|| kind === SyntaxKind.MethodDeclaration
|
||||
|| kind === SyntaxKind.GetAccessor
|
||||
|| kind === SyntaxKind.SetAccessor
|
||||
|| kind === SyntaxKind.ClassExpression
|
||||
|| kind === SyntaxKind.ClassDeclaration;
|
||||
}
|
||||
+2507
-2482
File diff suppressed because it is too large
Load Diff
+923
-892
File diff suppressed because it is too large
Load Diff
+9662
-9593
File diff suppressed because it is too large
Load Diff
+895
-791
File diff suppressed because it is too large
Load Diff
+67
-41
@@ -1,43 +1,69 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
type PerfLogger = typeof import("@microsoft/typescript-etw");
|
||||
const nullLogger: PerfLogger = {
|
||||
logEvent: noop,
|
||||
logErrEvent: noop,
|
||||
logPerfEvent: noop,
|
||||
logInfoEvent: noop,
|
||||
logStartCommand: noop,
|
||||
logStopCommand: noop,
|
||||
logStartUpdateProgram: noop,
|
||||
logStopUpdateProgram: noop,
|
||||
logStartUpdateGraph: noop,
|
||||
logStopUpdateGraph: noop,
|
||||
logStartResolveModule: noop,
|
||||
logStopResolveModule: noop,
|
||||
logStartParseSourceFile: noop,
|
||||
logStopParseSourceFile: noop,
|
||||
logStartReadFile: noop,
|
||||
logStopReadFile: noop,
|
||||
logStartBindFile: noop,
|
||||
logStopBindFile: noop,
|
||||
logStartScheduledOperation: noop,
|
||||
logStopScheduledOperation: noop,
|
||||
};
|
||||
import { noop } from "./_namespaces/ts";
|
||||
|
||||
// Load optional module to enable Event Tracing for Windows
|
||||
// See https://github.com/microsoft/typescript-etw for more information
|
||||
let etwModule;
|
||||
try {
|
||||
const etwModulePath = process.env.TS_ETW_MODULE_PATH ?? "./node_modules/@microsoft/typescript-etw";
|
||||
|
||||
// require() will throw an exception if the module is not found
|
||||
// It may also return undefined if not installed properly
|
||||
etwModule = require(etwModulePath);
|
||||
}
|
||||
catch (e) {
|
||||
etwModule = undefined;
|
||||
}
|
||||
|
||||
/** Performance logger that will generate ETW events if possible - check for `logEvent` member, as `etwModule` will be `{}` when browserified */
|
||||
export const perfLogger: PerfLogger = etwModule && etwModule.logEvent ? etwModule : nullLogger;
|
||||
/** @internal */
|
||||
export interface PerfLogger {
|
||||
logEvent(msg: string): void;
|
||||
logErrEvent(msg: string): void;
|
||||
logPerfEvent(msg: string): void;
|
||||
logInfoEvent(msg: string): void;
|
||||
logStartCommand(command: string, msg: string): void;
|
||||
logStopCommand(command: string, msg: string): void;
|
||||
logStartUpdateProgram(msg: string): void;
|
||||
logStopUpdateProgram(msg: string): void;
|
||||
logStartUpdateGraph(): void;
|
||||
logStopUpdateGraph(): void;
|
||||
logStartResolveModule(name: string): void;
|
||||
logStopResolveModule(success: string): void;
|
||||
logStartParseSourceFile(filename: string): void;
|
||||
logStopParseSourceFile(): void;
|
||||
logStartReadFile(filename: string): void;
|
||||
logStopReadFile(): void;
|
||||
logStartBindFile(filename: string): void;
|
||||
logStopBindFile(): void;
|
||||
logStartScheduledOperation(operationId: string): void;
|
||||
logStopScheduledOperation(): void;
|
||||
}
|
||||
|
||||
const nullLogger: PerfLogger = {
|
||||
logEvent: noop,
|
||||
logErrEvent: noop,
|
||||
logPerfEvent: noop,
|
||||
logInfoEvent: noop,
|
||||
logStartCommand: noop,
|
||||
logStopCommand: noop,
|
||||
logStartUpdateProgram: noop,
|
||||
logStopUpdateProgram: noop,
|
||||
logStartUpdateGraph: noop,
|
||||
logStopUpdateGraph: noop,
|
||||
logStartResolveModule: noop,
|
||||
logStopResolveModule: noop,
|
||||
logStartParseSourceFile: noop,
|
||||
logStopParseSourceFile: noop,
|
||||
logStartReadFile: noop,
|
||||
logStopReadFile: noop,
|
||||
logStartBindFile: noop,
|
||||
logStopBindFile: noop,
|
||||
logStartScheduledOperation: noop,
|
||||
logStopScheduledOperation: noop,
|
||||
};
|
||||
|
||||
// Load optional module to enable Event Tracing for Windows
|
||||
// See https://github.com/microsoft/typescript-etw for more information
|
||||
let etwModule: typeof import("@microsoft/typescript-etw") | undefined;
|
||||
try {
|
||||
const etwModulePath = process.env.TS_ETW_MODULE_PATH ?? "./node_modules/@microsoft/typescript-etw";
|
||||
|
||||
// require() will throw an exception if the module is not found
|
||||
// It may also return undefined if not installed properly
|
||||
etwModule = require(etwModulePath);
|
||||
}
|
||||
catch (e) {
|
||||
etwModule = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Performance logger that will generate ETW events if possible - check for `logEvent` member, as `etwModule` will be `{}` when browserified
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export const perfLogger: PerfLogger = etwModule?.logEvent ? etwModule : nullLogger;
|
||||
|
||||
+184
-155
@@ -1,168 +1,197 @@
|
||||
/*@internal*/
|
||||
import {
|
||||
Debug, Map, noop, Performance, PerformanceHooks, sys, System, timestamp, tryGetNativePerformanceHooks,
|
||||
} from "./_namespaces/ts";
|
||||
|
||||
/** Performance measurements for the compiler. */
|
||||
namespace ts.performance {
|
||||
let perfHooks: PerformanceHooks | undefined;
|
||||
// when set, indicates the implementation of `Performance` to use for user timing.
|
||||
// when unset, indicates user timing is unavailable or disabled.
|
||||
let performanceImpl: Performance | undefined;
|
||||
|
||||
export interface Timer {
|
||||
enter(): void;
|
||||
exit(): void;
|
||||
}
|
||||
let perfHooks: PerformanceHooks | undefined;
|
||||
// when set, indicates the implementation of `Performance` to use for user timing.
|
||||
// when unset, indicates user timing is unavailable or disabled.
|
||||
let performanceImpl: Performance | undefined;
|
||||
|
||||
export function createTimerIf(condition: boolean, measureName: string, startMarkName: string, endMarkName: string) {
|
||||
return condition ? createTimer(measureName, startMarkName, endMarkName) : nullTimer;
|
||||
}
|
||||
/** @internal */
|
||||
export interface Timer {
|
||||
enter(): void;
|
||||
exit(): void;
|
||||
}
|
||||
|
||||
export function createTimer(measureName: string, startMarkName: string, endMarkName: string): Timer {
|
||||
let enterCount = 0;
|
||||
return {
|
||||
enter,
|
||||
exit
|
||||
};
|
||||
/** @internal */
|
||||
export function createTimerIf(condition: boolean, measureName: string, startMarkName: string, endMarkName: string) {
|
||||
return condition ? createTimer(measureName, startMarkName, endMarkName) : nullTimer;
|
||||
}
|
||||
|
||||
function enter() {
|
||||
if (++enterCount === 1) {
|
||||
mark(startMarkName);
|
||||
}
|
||||
}
|
||||
/** @internal */
|
||||
export function createTimer(measureName: string, startMarkName: string, endMarkName: string): Timer {
|
||||
let enterCount = 0;
|
||||
return {
|
||||
enter,
|
||||
exit
|
||||
};
|
||||
|
||||
function exit() {
|
||||
if (--enterCount === 0) {
|
||||
mark(endMarkName);
|
||||
measure(measureName, startMarkName, endMarkName);
|
||||
}
|
||||
else if (enterCount < 0) {
|
||||
Debug.fail("enter/exit count does not match.");
|
||||
}
|
||||
function enter() {
|
||||
if (++enterCount === 1) {
|
||||
mark(startMarkName);
|
||||
}
|
||||
}
|
||||
|
||||
export const nullTimer: Timer = { enter: noop, exit: noop };
|
||||
|
||||
let enabled = false;
|
||||
let timeorigin = timestamp();
|
||||
const marks = new Map<string, number>();
|
||||
const counts = new Map<string, number>();
|
||||
const durations = new Map<string, number>();
|
||||
|
||||
/**
|
||||
* Marks a performance event.
|
||||
*
|
||||
* @param markName The name of the mark.
|
||||
*/
|
||||
export function mark(markName: string) {
|
||||
if (enabled) {
|
||||
const count = counts.get(markName) ?? 0;
|
||||
counts.set(markName, count + 1);
|
||||
marks.set(markName, timestamp());
|
||||
performanceImpl?.mark(markName);
|
||||
function exit() {
|
||||
if (--enterCount === 0) {
|
||||
mark(endMarkName);
|
||||
measure(measureName, startMarkName, endMarkName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a performance measurement with the specified name.
|
||||
*
|
||||
* @param measureName The name of the performance measurement.
|
||||
* @param startMarkName The name of the starting mark. If not supplied, the point at which the
|
||||
* profiler was enabled is used.
|
||||
* @param endMarkName The name of the ending mark. If not supplied, the current timestamp is
|
||||
* used.
|
||||
*/
|
||||
export function measure(measureName: string, startMarkName?: string, endMarkName?: string) {
|
||||
if (enabled) {
|
||||
const end = (endMarkName !== undefined ? marks.get(endMarkName) : undefined) ?? timestamp();
|
||||
const start = (startMarkName !== undefined ? marks.get(startMarkName) : undefined) ?? timeorigin;
|
||||
const previousDuration = durations.get(measureName) || 0;
|
||||
durations.set(measureName, previousDuration + (end - start));
|
||||
performanceImpl?.measure(measureName, startMarkName, endMarkName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of times a marker was encountered.
|
||||
*
|
||||
* @param markName The name of the mark.
|
||||
*/
|
||||
export function getCount(markName: string) {
|
||||
return counts.get(markName) || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total duration of all measurements with the supplied name.
|
||||
*
|
||||
* @param measureName The name of the measure whose durations should be accumulated.
|
||||
*/
|
||||
export function getDuration(measureName: string) {
|
||||
return durations.get(measureName) || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over each measure, performing some action
|
||||
*
|
||||
* @param cb The action to perform for each measure
|
||||
*/
|
||||
export function forEachMeasure(cb: (measureName: string, duration: number) => void) {
|
||||
durations.forEach((duration, measureName) => cb(measureName, duration));
|
||||
}
|
||||
|
||||
export function forEachMark(cb: (markName: string) => void) {
|
||||
marks.forEach((_time, markName) => cb(markName));
|
||||
}
|
||||
|
||||
export function clearMeasures(name?: string) {
|
||||
if (name !== undefined) durations.delete(name);
|
||||
else durations.clear();
|
||||
performanceImpl?.clearMeasures(name);
|
||||
}
|
||||
|
||||
export function clearMarks(name?: string) {
|
||||
if (name !== undefined) {
|
||||
counts.delete(name);
|
||||
marks.delete(name);
|
||||
}
|
||||
else {
|
||||
counts.clear();
|
||||
marks.clear();
|
||||
}
|
||||
performanceImpl?.clearMarks(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the performance API is enabled.
|
||||
*/
|
||||
export function isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/** Enables (and resets) performance measurements for the compiler. */
|
||||
export function enable(system: System = sys) {
|
||||
if (!enabled) {
|
||||
enabled = true;
|
||||
perfHooks ||= tryGetNativePerformanceHooks();
|
||||
if (perfHooks) {
|
||||
timeorigin = perfHooks.performance.timeOrigin;
|
||||
// NodeJS's Web Performance API is currently slower than expected, but we'd still like
|
||||
// to be able to leverage native trace events when node is run with either `--cpu-prof`
|
||||
// or `--prof`, if we're running with our own `--generateCpuProfile` flag, or when
|
||||
// running in debug mode (since its possible to generate a cpu profile while debugging).
|
||||
if (perfHooks.shouldWriteNativeEvents || system?.cpuProfilingEnabled?.() || system?.debugMode) {
|
||||
performanceImpl = perfHooks.performance;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** Disables performance measurements for the compiler. */
|
||||
export function disable() {
|
||||
if (enabled) {
|
||||
marks.clear();
|
||||
counts.clear();
|
||||
durations.clear();
|
||||
performanceImpl = undefined;
|
||||
enabled = false;
|
||||
else if (enterCount < 0) {
|
||||
Debug.fail("enter/exit count does not match.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export const nullTimer: Timer = { enter: noop, exit: noop };
|
||||
|
||||
let enabled = false;
|
||||
let timeorigin = timestamp();
|
||||
const marks = new Map<string, number>();
|
||||
const counts = new Map<string, number>();
|
||||
const durations = new Map<string, number>();
|
||||
|
||||
/**
|
||||
* Marks a performance event.
|
||||
*
|
||||
* @param markName The name of the mark.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function mark(markName: string) {
|
||||
if (enabled) {
|
||||
const count = counts.get(markName) ?? 0;
|
||||
counts.set(markName, count + 1);
|
||||
marks.set(markName, timestamp());
|
||||
performanceImpl?.mark(markName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a performance measurement with the specified name.
|
||||
*
|
||||
* @param measureName The name of the performance measurement.
|
||||
* @param startMarkName The name of the starting mark. If not supplied, the point at which the
|
||||
* profiler was enabled is used.
|
||||
* @param endMarkName The name of the ending mark. If not supplied, the current timestamp is
|
||||
* used.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function measure(measureName: string, startMarkName?: string, endMarkName?: string) {
|
||||
if (enabled) {
|
||||
const end = (endMarkName !== undefined ? marks.get(endMarkName) : undefined) ?? timestamp();
|
||||
const start = (startMarkName !== undefined ? marks.get(startMarkName) : undefined) ?? timeorigin;
|
||||
const previousDuration = durations.get(measureName) || 0;
|
||||
durations.set(measureName, previousDuration + (end - start));
|
||||
performanceImpl?.measure(measureName, startMarkName, endMarkName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of times a marker was encountered.
|
||||
*
|
||||
* @param markName The name of the mark.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function getCount(markName: string) {
|
||||
return counts.get(markName) || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the total duration of all measurements with the supplied name.
|
||||
*
|
||||
* @param measureName The name of the measure whose durations should be accumulated.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function getDuration(measureName: string) {
|
||||
return durations.get(measureName) || 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over each measure, performing some action
|
||||
*
|
||||
* @param cb The action to perform for each measure
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function forEachMeasure(cb: (measureName: string, duration: number) => void) {
|
||||
durations.forEach((duration, measureName) => cb(measureName, duration));
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function forEachMark(cb: (markName: string) => void) {
|
||||
marks.forEach((_time, markName) => cb(markName));
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function clearMeasures(name?: string) {
|
||||
if (name !== undefined) durations.delete(name);
|
||||
else durations.clear();
|
||||
performanceImpl?.clearMeasures(name);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function clearMarks(name?: string) {
|
||||
if (name !== undefined) {
|
||||
counts.delete(name);
|
||||
marks.delete(name);
|
||||
}
|
||||
else {
|
||||
counts.clear();
|
||||
marks.clear();
|
||||
}
|
||||
performanceImpl?.clearMarks(name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether the performance API is enabled.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function isEnabled() {
|
||||
return enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables (and resets) performance measurements for the compiler.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function enable(system: System = sys) {
|
||||
if (!enabled) {
|
||||
enabled = true;
|
||||
perfHooks ||= tryGetNativePerformanceHooks();
|
||||
if (perfHooks) {
|
||||
timeorigin = perfHooks.performance.timeOrigin;
|
||||
// NodeJS's Web Performance API is currently slower than expected, but we'd still like
|
||||
// to be able to leverage native trace events when node is run with either `--cpu-prof`
|
||||
// or `--prof`, if we're running with our own `--generateCpuProfile` flag, or when
|
||||
// running in debug mode (since its possible to generate a cpu profile while debugging).
|
||||
if (perfHooks.shouldWriteNativeEvents || system?.cpuProfilingEnabled?.() || system?.debugMode) {
|
||||
performanceImpl = perfHooks.performance;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Disables performance measurements for the compiler.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function disable() {
|
||||
if (enabled) {
|
||||
marks.clear();
|
||||
counts.clear();
|
||||
durations.clear();
|
||||
performanceImpl = undefined;
|
||||
enabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
+135
-124
@@ -1,135 +1,146 @@
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
// The following definitions provide the minimum compatible support for the Web Performance User Timings API
|
||||
// between browsers and NodeJS:
|
||||
import { isNodeLikeSystem, Version, VersionRange } from "./_namespaces/ts";
|
||||
|
||||
export interface PerformanceHooks {
|
||||
/** Indicates whether we should write native performance events */
|
||||
shouldWriteNativeEvents: boolean;
|
||||
performance: Performance;
|
||||
PerformanceObserver: PerformanceObserverConstructor;
|
||||
// The following definitions provide the minimum compatible support for the Web Performance User Timings API
|
||||
// between browsers and NodeJS:
|
||||
|
||||
/** @internal */
|
||||
export interface PerformanceHooks {
|
||||
/** Indicates whether we should write native performance events */
|
||||
shouldWriteNativeEvents: boolean;
|
||||
performance: Performance;
|
||||
PerformanceObserver: PerformanceObserverConstructor;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface Performance {
|
||||
mark(name: string): void;
|
||||
measure(name: string, startMark?: string, endMark?: string): void;
|
||||
clearMeasures(name?: string): void;
|
||||
clearMarks(name?: string): void;
|
||||
now(): number;
|
||||
timeOrigin: number;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface PerformanceEntry {
|
||||
name: string;
|
||||
entryType: string;
|
||||
startTime: number;
|
||||
duration: number;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface PerformanceObserverEntryList {
|
||||
getEntries(): PerformanceEntryList;
|
||||
getEntriesByName(name: string, type?: string): PerformanceEntryList;
|
||||
getEntriesByType(type: string): PerformanceEntryList;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export interface PerformanceObserver {
|
||||
disconnect(): void;
|
||||
observe(options: { entryTypes: readonly ("mark" | "measure")[] }): void;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export type PerformanceObserverConstructor = new (callback: (list: PerformanceObserverEntryList, observer: PerformanceObserver) => void) => PerformanceObserver;
|
||||
/** @internal */
|
||||
export type PerformanceEntryList = PerformanceEntry[];
|
||||
|
||||
// Browser globals for the Web Performance User Timings API
|
||||
declare const process: any;
|
||||
declare const performance: Performance | undefined;
|
||||
declare const PerformanceObserver: PerformanceObserverConstructor | undefined;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
function hasRequiredAPI(performance: Performance | undefined, PerformanceObserver: PerformanceObserverConstructor | undefined) {
|
||||
return typeof performance === "object" &&
|
||||
typeof performance.timeOrigin === "number" &&
|
||||
typeof performance.mark === "function" &&
|
||||
typeof performance.measure === "function" &&
|
||||
typeof performance.now === "function" &&
|
||||
typeof performance.clearMarks === "function" &&
|
||||
typeof performance.clearMeasures === "function" &&
|
||||
typeof PerformanceObserver === "function";
|
||||
}
|
||||
|
||||
function tryGetWebPerformanceHooks(): PerformanceHooks | undefined {
|
||||
if (typeof performance === "object" &&
|
||||
typeof PerformanceObserver === "function" &&
|
||||
hasRequiredAPI(performance, PerformanceObserver)) {
|
||||
return {
|
||||
// For now we always write native performance events when running in the browser. We may
|
||||
// make this conditional in the future if we find that native web performance hooks
|
||||
// in the browser also slow down compilation.
|
||||
shouldWriteNativeEvents: true,
|
||||
performance,
|
||||
PerformanceObserver
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export interface Performance {
|
||||
mark(name: string): void;
|
||||
measure(name: string, startMark?: string, endMark?: string): void;
|
||||
clearMeasures(name?: string): void;
|
||||
clearMarks(name?: string): void;
|
||||
now(): number;
|
||||
timeOrigin: number;
|
||||
}
|
||||
|
||||
export interface PerformanceEntry {
|
||||
name: string;
|
||||
entryType: string;
|
||||
startTime: number;
|
||||
duration: number;
|
||||
}
|
||||
|
||||
export interface PerformanceObserverEntryList {
|
||||
getEntries(): PerformanceEntryList;
|
||||
getEntriesByName(name: string, type?: string): PerformanceEntryList;
|
||||
getEntriesByType(type: string): PerformanceEntryList;
|
||||
}
|
||||
|
||||
export interface PerformanceObserver {
|
||||
disconnect(): void;
|
||||
observe(options: { entryTypes: readonly ("mark" | "measure")[] }): void;
|
||||
}
|
||||
|
||||
export type PerformanceObserverConstructor = new (callback: (list: PerformanceObserverEntryList, observer: PerformanceObserver) => void) => PerformanceObserver;
|
||||
export type PerformanceEntryList = PerformanceEntry[];
|
||||
|
||||
// Browser globals for the Web Performance User Timings API
|
||||
declare const process: any;
|
||||
declare const performance: Performance | undefined;
|
||||
declare const PerformanceObserver: PerformanceObserverConstructor | undefined;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/naming-convention
|
||||
function hasRequiredAPI(performance: Performance | undefined, PerformanceObserver: PerformanceObserverConstructor | undefined) {
|
||||
return typeof performance === "object" &&
|
||||
typeof performance.timeOrigin === "number" &&
|
||||
typeof performance.mark === "function" &&
|
||||
typeof performance.measure === "function" &&
|
||||
typeof performance.now === "function" &&
|
||||
typeof performance.clearMarks === "function" &&
|
||||
typeof performance.clearMeasures === "function" &&
|
||||
typeof PerformanceObserver === "function";
|
||||
}
|
||||
|
||||
function tryGetWebPerformanceHooks(): PerformanceHooks | undefined {
|
||||
if (typeof performance === "object" &&
|
||||
typeof PerformanceObserver === "function" &&
|
||||
hasRequiredAPI(performance, PerformanceObserver)) {
|
||||
return {
|
||||
// For now we always write native performance events when running in the browser. We may
|
||||
// make this conditional in the future if we find that native web performance hooks
|
||||
// in the browser also slow down compilation.
|
||||
shouldWriteNativeEvents: true,
|
||||
performance,
|
||||
PerformanceObserver
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function tryGetNodePerformanceHooks(): PerformanceHooks | undefined {
|
||||
if (typeof process !== "undefined" && process.nextTick && !process.browser && typeof module === "object" && typeof require === "function") {
|
||||
try {
|
||||
let performance: Performance;
|
||||
const { performance: nodePerformance, PerformanceObserver } = require("perf_hooks") as typeof import("perf_hooks");
|
||||
if (hasRequiredAPI(nodePerformance as unknown as Performance, PerformanceObserver)) {
|
||||
performance = nodePerformance as unknown as Performance;
|
||||
// There is a bug in Node's performance.measure prior to 12.16.3/13.13.0 that does not
|
||||
// match the Web Performance API specification. Node's implementation did not allow
|
||||
// optional `start` and `end` arguments for `performance.measure`.
|
||||
// See https://github.com/nodejs/node/pull/32651 for more information.
|
||||
const version = new Version(process.versions.node);
|
||||
const range = new VersionRange("<12.16.3 || 13 <13.13");
|
||||
if (range.test(version)) {
|
||||
performance = {
|
||||
get timeOrigin() { return nodePerformance.timeOrigin; },
|
||||
now() { return nodePerformance.now(); },
|
||||
mark(name) { return nodePerformance.mark(name); },
|
||||
measure(name, start = "nodeStart", end?) {
|
||||
if (end === undefined) {
|
||||
end = "__performance.measure-fix__";
|
||||
nodePerformance.mark(end);
|
||||
}
|
||||
nodePerformance.measure(name, start, end);
|
||||
if (end === "__performance.measure-fix__") {
|
||||
nodePerformance.clearMarks("__performance.measure-fix__");
|
||||
}
|
||||
},
|
||||
clearMarks(name) { return nodePerformance.clearMarks(name); },
|
||||
clearMeasures(name) { return (nodePerformance as unknown as Performance).clearMeasures(name); },
|
||||
};
|
||||
}
|
||||
return {
|
||||
// By default, only write native events when generating a cpu profile or using the v8 profiler.
|
||||
shouldWriteNativeEvents: false,
|
||||
performance,
|
||||
PerformanceObserver
|
||||
function tryGetNodePerformanceHooks(): PerformanceHooks | undefined {
|
||||
if (isNodeLikeSystem()) {
|
||||
try {
|
||||
let performance: Performance;
|
||||
const { performance: nodePerformance, PerformanceObserver } = require("perf_hooks") as typeof import("perf_hooks");
|
||||
if (hasRequiredAPI(nodePerformance as unknown as Performance, PerformanceObserver)) {
|
||||
performance = nodePerformance as unknown as Performance;
|
||||
// There is a bug in Node's performance.measure prior to 12.16.3/13.13.0 that does not
|
||||
// match the Web Performance API specification. Node's implementation did not allow
|
||||
// optional `start` and `end` arguments for `performance.measure`.
|
||||
// See https://github.com/nodejs/node/pull/32651 for more information.
|
||||
const version = new Version(process.versions.node);
|
||||
const range = new VersionRange("<12.16.3 || 13 <13.13");
|
||||
if (range.test(version)) {
|
||||
performance = {
|
||||
get timeOrigin() { return nodePerformance.timeOrigin; },
|
||||
now() { return nodePerformance.now(); },
|
||||
mark(name) { return nodePerformance.mark(name); },
|
||||
measure(name, start = "nodeStart", end?) {
|
||||
if (end === undefined) {
|
||||
end = "__performance.measure-fix__";
|
||||
nodePerformance.mark(end);
|
||||
}
|
||||
nodePerformance.measure(name, start, end);
|
||||
if (end === "__performance.measure-fix__") {
|
||||
nodePerformance.clearMarks("__performance.measure-fix__");
|
||||
}
|
||||
},
|
||||
clearMarks(name) { return nodePerformance.clearMarks(name); },
|
||||
clearMeasures(name) { return (nodePerformance as unknown as Performance).clearMeasures(name); },
|
||||
};
|
||||
}
|
||||
}
|
||||
catch {
|
||||
// ignore errors
|
||||
return {
|
||||
// By default, only write native events when generating a cpu profile or using the v8 profiler.
|
||||
shouldWriteNativeEvents: false,
|
||||
performance,
|
||||
PerformanceObserver
|
||||
};
|
||||
}
|
||||
}
|
||||
catch {
|
||||
// ignore errors
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unlike with the native Map/Set 'tryGet' functions in corePublic.ts, we eagerly evaluate these
|
||||
// since we will need them for `timestamp`, below.
|
||||
const nativePerformanceHooks = tryGetWebPerformanceHooks() || tryGetNodePerformanceHooks();
|
||||
const nativePerformance = nativePerformanceHooks?.performance;
|
||||
// Unlike with the native Map/Set 'tryGet' functions in corePublic.ts, we eagerly evaluate these
|
||||
// since we will need them for `timestamp`, below.
|
||||
const nativePerformanceHooks = tryGetWebPerformanceHooks() || tryGetNodePerformanceHooks();
|
||||
const nativePerformance = nativePerformanceHooks?.performance;
|
||||
|
||||
export function tryGetNativePerformanceHooks() {
|
||||
return nativePerformanceHooks;
|
||||
}
|
||||
/** @internal */
|
||||
export function tryGetNativePerformanceHooks() {
|
||||
return nativePerformanceHooks;
|
||||
}
|
||||
|
||||
/** Gets a timestamp with (at least) ms resolution */
|
||||
export const timestamp =
|
||||
nativePerformance ? () => nativePerformance.now() :
|
||||
Date.now ? Date.now :
|
||||
() => +(new Date());
|
||||
}
|
||||
/**
|
||||
* Gets a timestamp with (at least) ms resolution
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export const timestamp =
|
||||
nativePerformance ? () => nativePerformance.now() :
|
||||
Date.now ? Date.now :
|
||||
() => +(new Date());
|
||||
|
||||
+4203
-4139
File diff suppressed because it is too large
Load Diff
+1058
-1030
File diff suppressed because it is too large
Load Diff
+2457
-2452
File diff suppressed because one or more lines are too long
+368
-363
@@ -1,416 +1,421 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
// https://semver.org/#spec-item-2
|
||||
// > A normal version number MUST take the form X.Y.Z where X, Y, and Z are non-negative
|
||||
// > integers, and MUST NOT contain leading zeroes. X is the major version, Y is the minor
|
||||
// > version, and Z is the patch version. Each element MUST increase numerically.
|
||||
//
|
||||
// NOTE: We differ here in that we allow X and X.Y, with missing parts having the default
|
||||
// value of `0`.
|
||||
const versionRegExp = /^(0|[1-9]\d*)(?:\.(0|[1-9]\d*)(?:\.(0|[1-9]\d*)(?:\-([a-z0-9-.]+))?(?:\+([a-z0-9-.]+))?)?)?$/i;
|
||||
import {
|
||||
compareStringsCaseSensitive, compareValues, Comparison, Debug, emptyArray, every, isArray, map, some, trimString,
|
||||
} from "./_namespaces/ts";
|
||||
|
||||
// https://semver.org/#spec-item-9
|
||||
// > A pre-release version MAY be denoted by appending a hyphen and a series of dot separated
|
||||
// > identifiers immediately following the patch version. Identifiers MUST comprise only ASCII
|
||||
// > alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty. Numeric identifiers
|
||||
// > MUST NOT include leading zeroes.
|
||||
const prereleaseRegExp = /^(?:0|[1-9]\d*|[a-z-][a-z0-9-]*)(?:\.(?:0|[1-9]\d*|[a-z-][a-z0-9-]*))*$/i;
|
||||
const prereleasePartRegExp = /^(?:0|[1-9]\d*|[a-z-][a-z0-9-]*)$/i;
|
||||
// https://semver.org/#spec-item-2
|
||||
// > A normal version number MUST take the form X.Y.Z where X, Y, and Z are non-negative
|
||||
// > integers, and MUST NOT contain leading zeroes. X is the major version, Y is the minor
|
||||
// > version, and Z is the patch version. Each element MUST increase numerically.
|
||||
//
|
||||
// NOTE: We differ here in that we allow X and X.Y, with missing parts having the default
|
||||
// value of `0`.
|
||||
const versionRegExp = /^(0|[1-9]\d*)(?:\.(0|[1-9]\d*)(?:\.(0|[1-9]\d*)(?:\-([a-z0-9-.]+))?(?:\+([a-z0-9-.]+))?)?)?$/i;
|
||||
|
||||
// https://semver.org/#spec-item-10
|
||||
// > Build metadata MAY be denoted by appending a plus sign and a series of dot separated
|
||||
// > identifiers immediately following the patch or pre-release version. Identifiers MUST
|
||||
// > comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty.
|
||||
const buildRegExp = /^[a-z0-9-]+(?:\.[a-z0-9-]+)*$/i;
|
||||
const buildPartRegExp = /^[a-z0-9-]+$/i;
|
||||
// https://semver.org/#spec-item-9
|
||||
// > A pre-release version MAY be denoted by appending a hyphen and a series of dot separated
|
||||
// > identifiers immediately following the patch version. Identifiers MUST comprise only ASCII
|
||||
// > alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty. Numeric identifiers
|
||||
// > MUST NOT include leading zeroes.
|
||||
const prereleaseRegExp = /^(?:0|[1-9]\d*|[a-z-][a-z0-9-]*)(?:\.(?:0|[1-9]\d*|[a-z-][a-z0-9-]*))*$/i;
|
||||
const prereleasePartRegExp = /^(?:0|[1-9]\d*|[a-z-][a-z0-9-]*)$/i;
|
||||
|
||||
// https://semver.org/#spec-item-9
|
||||
// > Numeric identifiers MUST NOT include leading zeroes.
|
||||
const numericIdentifierRegExp = /^(0|[1-9]\d*)$/;
|
||||
// https://semver.org/#spec-item-10
|
||||
// > Build metadata MAY be denoted by appending a plus sign and a series of dot separated
|
||||
// > identifiers immediately following the patch or pre-release version. Identifiers MUST
|
||||
// > comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-]. Identifiers MUST NOT be empty.
|
||||
const buildRegExp = /^[a-z0-9-]+(?:\.[a-z0-9-]+)*$/i;
|
||||
const buildPartRegExp = /^[a-z0-9-]+$/i;
|
||||
|
||||
/**
|
||||
* Describes a precise semantic version number, https://semver.org
|
||||
*/
|
||||
export class Version {
|
||||
static readonly zero = new Version(0, 0, 0, ["0"]);
|
||||
// https://semver.org/#spec-item-9
|
||||
// > Numeric identifiers MUST NOT include leading zeroes.
|
||||
const numericIdentifierRegExp = /^(0|[1-9]\d*)$/;
|
||||
|
||||
readonly major: number;
|
||||
readonly minor: number;
|
||||
readonly patch: number;
|
||||
readonly prerelease: readonly string[];
|
||||
readonly build: readonly string[];
|
||||
/**
|
||||
* Describes a precise semantic version number, https://semver.org
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export class Version {
|
||||
static readonly zero = new Version(0, 0, 0, ["0"]);
|
||||
|
||||
constructor(text: string);
|
||||
constructor(major: number, minor?: number, patch?: number, prerelease?: string | readonly string[], build?: string | readonly string[]);
|
||||
constructor(major: number | string, minor = 0, patch = 0, prerelease: string | readonly string[] = "", build: string | readonly string[] = "") {
|
||||
if (typeof major === "string") {
|
||||
const result = Debug.checkDefined(tryParseComponents(major), "Invalid version");
|
||||
({ major, minor, patch, prerelease, build } = result);
|
||||
}
|
||||
readonly major: number;
|
||||
readonly minor: number;
|
||||
readonly patch: number;
|
||||
readonly prerelease: readonly string[];
|
||||
readonly build: readonly string[];
|
||||
|
||||
Debug.assert(major >= 0, "Invalid argument: major");
|
||||
Debug.assert(minor >= 0, "Invalid argument: minor");
|
||||
Debug.assert(patch >= 0, "Invalid argument: patch");
|
||||
|
||||
const prereleaseArray = prerelease ? isArray(prerelease) ? prerelease : prerelease.split(".") : emptyArray;
|
||||
const buildArray = build ? isArray(build) ? build : build.split(".") : emptyArray;
|
||||
|
||||
Debug.assert(every(prereleaseArray, s => prereleasePartRegExp.test(s)), "Invalid argument: prerelease");
|
||||
Debug.assert(every(buildArray, s => buildPartRegExp.test(s)), "Invalid argument: build");
|
||||
|
||||
this.major = major;
|
||||
this.minor = minor;
|
||||
this.patch = patch;
|
||||
this.prerelease = prereleaseArray;
|
||||
this.build = buildArray;
|
||||
constructor(text: string);
|
||||
constructor(major: number, minor?: number, patch?: number, prerelease?: string | readonly string[], build?: string | readonly string[]);
|
||||
constructor(major: number | string, minor = 0, patch = 0, prerelease: string | readonly string[] = "", build: string | readonly string[] = "") {
|
||||
if (typeof major === "string") {
|
||||
const result = Debug.checkDefined(tryParseComponents(major), "Invalid version");
|
||||
({ major, minor, patch, prerelease, build } = result);
|
||||
}
|
||||
|
||||
static tryParse(text: string) {
|
||||
const result = tryParseComponents(text);
|
||||
if (!result) return undefined;
|
||||
Debug.assert(major >= 0, "Invalid argument: major");
|
||||
Debug.assert(minor >= 0, "Invalid argument: minor");
|
||||
Debug.assert(patch >= 0, "Invalid argument: patch");
|
||||
|
||||
const { major, minor, patch, prerelease, build } = result;
|
||||
return new Version(major, minor, patch, prerelease, build);
|
||||
}
|
||||
const prereleaseArray = prerelease ? isArray(prerelease) ? prerelease : prerelease.split(".") : emptyArray;
|
||||
const buildArray = build ? isArray(build) ? build : build.split(".") : emptyArray;
|
||||
|
||||
compareTo(other: Version | undefined) {
|
||||
// https://semver.org/#spec-item-11
|
||||
// > Precedence is determined by the first difference when comparing each of these
|
||||
// > identifiers from left to right as follows: Major, minor, and patch versions are
|
||||
// > always compared numerically.
|
||||
//
|
||||
// https://semver.org/#spec-item-11
|
||||
// > Precedence for two pre-release versions with the same major, minor, and patch version
|
||||
// > MUST be determined by comparing each dot separated identifier from left to right until
|
||||
// > a difference is found [...]
|
||||
//
|
||||
// https://semver.org/#spec-item-11
|
||||
// > Build metadata does not figure into precedence
|
||||
if (this === other) return Comparison.EqualTo;
|
||||
if (other === undefined) return Comparison.GreaterThan;
|
||||
return compareValues(this.major, other.major)
|
||||
|| compareValues(this.minor, other.minor)
|
||||
|| compareValues(this.patch, other.patch)
|
||||
|| comparePrereleaseIdentifiers(this.prerelease, other.prerelease);
|
||||
}
|
||||
Debug.assert(every(prereleaseArray, s => prereleasePartRegExp.test(s)), "Invalid argument: prerelease");
|
||||
Debug.assert(every(buildArray, s => buildPartRegExp.test(s)), "Invalid argument: build");
|
||||
|
||||
increment(field: "major" | "minor" | "patch") {
|
||||
switch (field) {
|
||||
case "major": return new Version(this.major + 1, 0, 0);
|
||||
case "minor": return new Version(this.major, this.minor + 1, 0);
|
||||
case "patch": return new Version(this.major, this.minor, this.patch + 1);
|
||||
default: return Debug.assertNever(field);
|
||||
}
|
||||
}
|
||||
|
||||
with(fields: { major?: number, minor?: number, patch?: number, prerelease?: string | readonly string[], build?: string | readonly string[] }) {
|
||||
const {
|
||||
major = this.major,
|
||||
minor = this.minor,
|
||||
patch = this.patch,
|
||||
prerelease = this.prerelease,
|
||||
build = this.build
|
||||
} = fields;
|
||||
return new Version(major, minor, patch, prerelease, build);
|
||||
}
|
||||
|
||||
toString() {
|
||||
let result = `${this.major}.${this.minor}.${this.patch}`;
|
||||
if (some(this.prerelease)) result += `-${this.prerelease.join(".")}`;
|
||||
if (some(this.build)) result += `+${this.build.join(".")}`;
|
||||
return result;
|
||||
}
|
||||
this.major = major;
|
||||
this.minor = minor;
|
||||
this.patch = patch;
|
||||
this.prerelease = prereleaseArray;
|
||||
this.build = buildArray;
|
||||
}
|
||||
|
||||
function tryParseComponents(text: string) {
|
||||
const match = versionRegExp.exec(text);
|
||||
if (!match) return undefined;
|
||||
static tryParse(text: string) {
|
||||
const result = tryParseComponents(text);
|
||||
if (!result) return undefined;
|
||||
|
||||
const [, major, minor = "0", patch = "0", prerelease = "", build = ""] = match;
|
||||
if (prerelease && !prereleaseRegExp.test(prerelease)) return undefined;
|
||||
if (build && !buildRegExp.test(build)) return undefined;
|
||||
return {
|
||||
major: parseInt(major, 10),
|
||||
minor: parseInt(minor, 10),
|
||||
patch: parseInt(patch, 10),
|
||||
prerelease,
|
||||
build
|
||||
};
|
||||
const { major, minor, patch, prerelease, build } = result;
|
||||
return new Version(major, minor, patch, prerelease, build);
|
||||
}
|
||||
|
||||
function comparePrereleaseIdentifiers(left: readonly string[], right: readonly string[]) {
|
||||
compareTo(other: Version | undefined) {
|
||||
// https://semver.org/#spec-item-11
|
||||
// > When major, minor, and patch are equal, a pre-release version has lower precedence
|
||||
// > than a normal version.
|
||||
if (left === right) return Comparison.EqualTo;
|
||||
if (left.length === 0) return right.length === 0 ? Comparison.EqualTo : Comparison.GreaterThan;
|
||||
if (right.length === 0) return Comparison.LessThan;
|
||||
|
||||
// > Precedence is determined by the first difference when comparing each of these
|
||||
// > identifiers from left to right as follows: Major, minor, and patch versions are
|
||||
// > always compared numerically.
|
||||
//
|
||||
// https://semver.org/#spec-item-11
|
||||
// > Precedence for two pre-release versions with the same major, minor, and patch version
|
||||
// > MUST be determined by comparing each dot separated identifier from left to right until
|
||||
// > a difference is found [...]
|
||||
const length = Math.min(left.length, right.length);
|
||||
for (let i = 0; i < length; i++) {
|
||||
const leftIdentifier = left[i];
|
||||
const rightIdentifier = right[i];
|
||||
if (leftIdentifier === rightIdentifier) continue;
|
||||
|
||||
const leftIsNumeric = numericIdentifierRegExp.test(leftIdentifier);
|
||||
const rightIsNumeric = numericIdentifierRegExp.test(rightIdentifier);
|
||||
if (leftIsNumeric || rightIsNumeric) {
|
||||
// https://semver.org/#spec-item-11
|
||||
// > Numeric identifiers always have lower precedence than non-numeric identifiers.
|
||||
if (leftIsNumeric !== rightIsNumeric) return leftIsNumeric ? Comparison.LessThan : Comparison.GreaterThan;
|
||||
|
||||
// https://semver.org/#spec-item-11
|
||||
// > identifiers consisting of only digits are compared numerically
|
||||
const result = compareValues(+leftIdentifier, +rightIdentifier);
|
||||
if (result) return result;
|
||||
}
|
||||
else {
|
||||
// https://semver.org/#spec-item-11
|
||||
// > identifiers with letters or hyphens are compared lexically in ASCII sort order.
|
||||
const result = compareStringsCaseSensitive(leftIdentifier, rightIdentifier);
|
||||
if (result) return result;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// https://semver.org/#spec-item-11
|
||||
// > A larger set of pre-release fields has a higher precedence than a smaller set, if all
|
||||
// > of the preceding identifiers are equal.
|
||||
return compareValues(left.length, right.length);
|
||||
// > Build metadata does not figure into precedence
|
||||
if (this === other) return Comparison.EqualTo;
|
||||
if (other === undefined) return Comparison.GreaterThan;
|
||||
return compareValues(this.major, other.major)
|
||||
|| compareValues(this.minor, other.minor)
|
||||
|| compareValues(this.patch, other.patch)
|
||||
|| comparePrereleaseIdentifiers(this.prerelease, other.prerelease);
|
||||
}
|
||||
|
||||
increment(field: "major" | "minor" | "patch") {
|
||||
switch (field) {
|
||||
case "major": return new Version(this.major + 1, 0, 0);
|
||||
case "minor": return new Version(this.major, this.minor + 1, 0);
|
||||
case "patch": return new Version(this.major, this.minor, this.patch + 1);
|
||||
default: return Debug.assertNever(field);
|
||||
}
|
||||
}
|
||||
|
||||
with(fields: { major?: number, minor?: number, patch?: number, prerelease?: string | readonly string[], build?: string | readonly string[] }) {
|
||||
const {
|
||||
major = this.major,
|
||||
minor = this.minor,
|
||||
patch = this.patch,
|
||||
prerelease = this.prerelease,
|
||||
build = this.build
|
||||
} = fields;
|
||||
return new Version(major, minor, patch, prerelease, build);
|
||||
}
|
||||
|
||||
toString() {
|
||||
let result = `${this.major}.${this.minor}.${this.patch}`;
|
||||
if (some(this.prerelease)) result += `-${this.prerelease.join(".")}`;
|
||||
if (some(this.build)) result += `+${this.build.join(".")}`;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function tryParseComponents(text: string) {
|
||||
const match = versionRegExp.exec(text);
|
||||
if (!match) return undefined;
|
||||
|
||||
const [, major, minor = "0", patch = "0", prerelease = "", build = ""] = match;
|
||||
if (prerelease && !prereleaseRegExp.test(prerelease)) return undefined;
|
||||
if (build && !buildRegExp.test(build)) return undefined;
|
||||
return {
|
||||
major: parseInt(major, 10),
|
||||
minor: parseInt(minor, 10),
|
||||
patch: parseInt(patch, 10),
|
||||
prerelease,
|
||||
build
|
||||
};
|
||||
}
|
||||
|
||||
function comparePrereleaseIdentifiers(left: readonly string[], right: readonly string[]) {
|
||||
// https://semver.org/#spec-item-11
|
||||
// > When major, minor, and patch are equal, a pre-release version has lower precedence
|
||||
// > than a normal version.
|
||||
if (left === right) return Comparison.EqualTo;
|
||||
if (left.length === 0) return right.length === 0 ? Comparison.EqualTo : Comparison.GreaterThan;
|
||||
if (right.length === 0) return Comparison.LessThan;
|
||||
|
||||
// https://semver.org/#spec-item-11
|
||||
// > Precedence for two pre-release versions with the same major, minor, and patch version
|
||||
// > MUST be determined by comparing each dot separated identifier from left to right until
|
||||
// > a difference is found [...]
|
||||
const length = Math.min(left.length, right.length);
|
||||
for (let i = 0; i < length; i++) {
|
||||
const leftIdentifier = left[i];
|
||||
const rightIdentifier = right[i];
|
||||
if (leftIdentifier === rightIdentifier) continue;
|
||||
|
||||
const leftIsNumeric = numericIdentifierRegExp.test(leftIdentifier);
|
||||
const rightIsNumeric = numericIdentifierRegExp.test(rightIdentifier);
|
||||
if (leftIsNumeric || rightIsNumeric) {
|
||||
// https://semver.org/#spec-item-11
|
||||
// > Numeric identifiers always have lower precedence than non-numeric identifiers.
|
||||
if (leftIsNumeric !== rightIsNumeric) return leftIsNumeric ? Comparison.LessThan : Comparison.GreaterThan;
|
||||
|
||||
// https://semver.org/#spec-item-11
|
||||
// > identifiers consisting of only digits are compared numerically
|
||||
const result = compareValues(+leftIdentifier, +rightIdentifier);
|
||||
if (result) return result;
|
||||
}
|
||||
else {
|
||||
// https://semver.org/#spec-item-11
|
||||
// > identifiers with letters or hyphens are compared lexically in ASCII sort order.
|
||||
const result = compareStringsCaseSensitive(leftIdentifier, rightIdentifier);
|
||||
if (result) return result;
|
||||
}
|
||||
}
|
||||
|
||||
// https://semver.org/#spec-item-11
|
||||
// > A larger set of pre-release fields has a higher precedence than a smaller set, if all
|
||||
// > of the preceding identifiers are equal.
|
||||
return compareValues(left.length, right.length);
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a semantic version range, per https://github.com/npm/node-semver#ranges
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export class VersionRange {
|
||||
private _alternatives: readonly (readonly Comparator[])[];
|
||||
|
||||
constructor(spec: string) {
|
||||
this._alternatives = spec ? Debug.checkDefined(parseRange(spec), "Invalid range spec.") : emptyArray;
|
||||
}
|
||||
|
||||
static tryParse(text: string) {
|
||||
const sets = parseRange(text);
|
||||
if (sets) {
|
||||
const range = new VersionRange("");
|
||||
range._alternatives = sets;
|
||||
return range;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes a semantic version range, per https://github.com/npm/node-semver#ranges
|
||||
* Tests whether a version matches the range. This is equivalent to `satisfies(version, range, { includePrerelease: true })`.
|
||||
* in `node-semver`.
|
||||
*/
|
||||
export class VersionRange {
|
||||
private _alternatives: readonly (readonly Comparator[])[];
|
||||
|
||||
constructor(spec: string) {
|
||||
this._alternatives = spec ? Debug.checkDefined(parseRange(spec), "Invalid range spec.") : emptyArray;
|
||||
}
|
||||
|
||||
static tryParse(text: string) {
|
||||
const sets = parseRange(text);
|
||||
if (sets) {
|
||||
const range = new VersionRange("");
|
||||
range._alternatives = sets;
|
||||
return range;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests whether a version matches the range. This is equivalent to `satisfies(version, range, { includePrerelease: true })`.
|
||||
* in `node-semver`.
|
||||
*/
|
||||
test(version: Version | string) {
|
||||
if (typeof version === "string") version = new Version(version);
|
||||
return testDisjunction(version, this._alternatives);
|
||||
}
|
||||
|
||||
toString() {
|
||||
return formatDisjunction(this._alternatives);
|
||||
}
|
||||
test(version: Version | string) {
|
||||
if (typeof version === "string") version = new Version(version);
|
||||
return testDisjunction(version, this._alternatives);
|
||||
}
|
||||
|
||||
interface Comparator {
|
||||
readonly operator: "<" | "<=" | ">" | ">=" | "=";
|
||||
readonly operand: Version;
|
||||
toString() {
|
||||
return formatDisjunction(this._alternatives);
|
||||
}
|
||||
}
|
||||
|
||||
// https://github.com/npm/node-semver#range-grammar
|
||||
//
|
||||
// range-set ::= range ( logical-or range ) *
|
||||
// range ::= hyphen | simple ( ' ' simple ) * | ''
|
||||
// logical-or ::= ( ' ' ) * '||' ( ' ' ) *
|
||||
const logicalOrRegExp = /\|\|/g;
|
||||
const whitespaceRegExp = /\s+/g;
|
||||
interface Comparator {
|
||||
readonly operator: "<" | "<=" | ">" | ">=" | "=";
|
||||
readonly operand: Version;
|
||||
}
|
||||
|
||||
// https://github.com/npm/node-semver#range-grammar
|
||||
//
|
||||
// partial ::= xr ( '.' xr ( '.' xr qualifier ? )? )?
|
||||
// xr ::= 'x' | 'X' | '*' | nr
|
||||
// nr ::= '0' | ['1'-'9'] ( ['0'-'9'] ) *
|
||||
// qualifier ::= ( '-' pre )? ( '+' build )?
|
||||
// pre ::= parts
|
||||
// build ::= parts
|
||||
// parts ::= part ( '.' part ) *
|
||||
// part ::= nr | [-0-9A-Za-z]+
|
||||
const partialRegExp = /^([xX*0]|[1-9]\d*)(?:\.([xX*0]|[1-9]\d*)(?:\.([xX*0]|[1-9]\d*)(?:-([a-z0-9-.]+))?(?:\+([a-z0-9-.]+))?)?)?$/i;
|
||||
// https://github.com/npm/node-semver#range-grammar
|
||||
//
|
||||
// range-set ::= range ( logical-or range ) *
|
||||
// range ::= hyphen | simple ( ' ' simple ) * | ''
|
||||
// logical-or ::= ( ' ' ) * '||' ( ' ' ) *
|
||||
const logicalOrRegExp = /\|\|/g;
|
||||
const whitespaceRegExp = /\s+/g;
|
||||
|
||||
// https://github.com/npm/node-semver#range-grammar
|
||||
//
|
||||
// hyphen ::= partial ' - ' partial
|
||||
const hyphenRegExp = /^\s*([a-z0-9-+.*]+)\s+-\s+([a-z0-9-+.*]+)\s*$/i;
|
||||
// https://github.com/npm/node-semver#range-grammar
|
||||
//
|
||||
// partial ::= xr ( '.' xr ( '.' xr qualifier ? )? )?
|
||||
// xr ::= 'x' | 'X' | '*' | nr
|
||||
// nr ::= '0' | ['1'-'9'] ( ['0'-'9'] ) *
|
||||
// qualifier ::= ( '-' pre )? ( '+' build )?
|
||||
// pre ::= parts
|
||||
// build ::= parts
|
||||
// parts ::= part ( '.' part ) *
|
||||
// part ::= nr | [-0-9A-Za-z]+
|
||||
const partialRegExp = /^([xX*0]|[1-9]\d*)(?:\.([xX*0]|[1-9]\d*)(?:\.([xX*0]|[1-9]\d*)(?:-([a-z0-9-.]+))?(?:\+([a-z0-9-.]+))?)?)?$/i;
|
||||
|
||||
// https://github.com/npm/node-semver#range-grammar
|
||||
//
|
||||
// simple ::= primitive | partial | tilde | caret
|
||||
// primitive ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial
|
||||
// tilde ::= '~' partial
|
||||
// caret ::= '^' partial
|
||||
const rangeRegExp = /^(~|\^|<|<=|>|>=|=)?\s*([a-z0-9-+.*]+)$/i;
|
||||
// https://github.com/npm/node-semver#range-grammar
|
||||
//
|
||||
// hyphen ::= partial ' - ' partial
|
||||
const hyphenRegExp = /^\s*([a-z0-9-+.*]+)\s+-\s+([a-z0-9-+.*]+)\s*$/i;
|
||||
|
||||
function parseRange(text: string) {
|
||||
const alternatives: Comparator[][] = [];
|
||||
for (let range of trimString(text).split(logicalOrRegExp)) {
|
||||
if (!range) continue;
|
||||
const comparators: Comparator[] = [];
|
||||
range = trimString(range);
|
||||
const match = hyphenRegExp.exec(range);
|
||||
if (match) {
|
||||
if (!parseHyphen(match[1], match[2], comparators)) return undefined;
|
||||
}
|
||||
else {
|
||||
for (const simple of range.split(whitespaceRegExp)) {
|
||||
const match = rangeRegExp.exec(trimString(simple));
|
||||
if (!match || !parseComparator(match[1], match[2], comparators)) return undefined;
|
||||
}
|
||||
}
|
||||
alternatives.push(comparators);
|
||||
// https://github.com/npm/node-semver#range-grammar
|
||||
//
|
||||
// simple ::= primitive | partial | tilde | caret
|
||||
// primitive ::= ( '<' | '>' | '>=' | '<=' | '=' ) partial
|
||||
// tilde ::= '~' partial
|
||||
// caret ::= '^' partial
|
||||
const rangeRegExp = /^(~|\^|<|<=|>|>=|=)?\s*([a-z0-9-+.*]+)$/i;
|
||||
|
||||
function parseRange(text: string) {
|
||||
const alternatives: Comparator[][] = [];
|
||||
for (let range of trimString(text).split(logicalOrRegExp)) {
|
||||
if (!range) continue;
|
||||
const comparators: Comparator[] = [];
|
||||
range = trimString(range);
|
||||
const match = hyphenRegExp.exec(range);
|
||||
if (match) {
|
||||
if (!parseHyphen(match[1], match[2], comparators)) return undefined;
|
||||
}
|
||||
return alternatives;
|
||||
}
|
||||
|
||||
function parsePartial(text: string) {
|
||||
const match = partialRegExp.exec(text);
|
||||
if (!match) return undefined;
|
||||
|
||||
const [, major, minor = "*", patch = "*", prerelease, build] = match;
|
||||
const version = new Version(
|
||||
isWildcard(major) ? 0 : parseInt(major, 10),
|
||||
isWildcard(major) || isWildcard(minor) ? 0 : parseInt(minor, 10),
|
||||
isWildcard(major) || isWildcard(minor) || isWildcard(patch) ? 0 : parseInt(patch, 10),
|
||||
prerelease,
|
||||
build);
|
||||
|
||||
return { version, major, minor, patch };
|
||||
}
|
||||
|
||||
function parseHyphen(left: string, right: string, comparators: Comparator[]) {
|
||||
const leftResult = parsePartial(left);
|
||||
if (!leftResult) return false;
|
||||
|
||||
const rightResult = parsePartial(right);
|
||||
if (!rightResult) return false;
|
||||
|
||||
if (!isWildcard(leftResult.major)) {
|
||||
comparators.push(createComparator(">=", leftResult.version));
|
||||
}
|
||||
|
||||
if (!isWildcard(rightResult.major)) {
|
||||
comparators.push(
|
||||
isWildcard(rightResult.minor) ? createComparator("<", rightResult.version.increment("major")) :
|
||||
isWildcard(rightResult.patch) ? createComparator("<", rightResult.version.increment("minor")) :
|
||||
createComparator("<=", rightResult.version));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function parseComparator(operator: string, text: string, comparators: Comparator[]) {
|
||||
const result = parsePartial(text);
|
||||
if (!result) return false;
|
||||
|
||||
const { version, major, minor, patch } = result;
|
||||
if (!isWildcard(major)) {
|
||||
switch (operator) {
|
||||
case "~":
|
||||
comparators.push(createComparator(">=", version));
|
||||
comparators.push(createComparator("<", version.increment(
|
||||
isWildcard(minor) ? "major" :
|
||||
"minor")));
|
||||
break;
|
||||
case "^":
|
||||
comparators.push(createComparator(">=", version));
|
||||
comparators.push(createComparator("<", version.increment(
|
||||
version.major > 0 || isWildcard(minor) ? "major" :
|
||||
version.minor > 0 || isWildcard(patch) ? "minor" :
|
||||
"patch")));
|
||||
break;
|
||||
case "<":
|
||||
case ">=":
|
||||
comparators.push(
|
||||
isWildcard(minor) || isWildcard(patch) ? createComparator(operator, version.with({ prerelease: "0" })) :
|
||||
createComparator(operator, version));
|
||||
break;
|
||||
case "<=":
|
||||
case ">":
|
||||
comparators.push(
|
||||
isWildcard(minor) ? createComparator(operator === "<=" ? "<" : ">=", version.increment("major").with({ prerelease: "0" })) :
|
||||
isWildcard(patch) ? createComparator(operator === "<=" ? "<" : ">=", version.increment("minor").with({ prerelease: "0" })) :
|
||||
createComparator(operator, version));
|
||||
break;
|
||||
case "=":
|
||||
case undefined:
|
||||
if (isWildcard(minor) || isWildcard(patch)) {
|
||||
comparators.push(createComparator(">=", version.with({ prerelease: "0" })));
|
||||
comparators.push(createComparator("<", version.increment(isWildcard(minor) ? "major" : "minor").with({ prerelease: "0" })));
|
||||
}
|
||||
else {
|
||||
comparators.push(createComparator("=", version));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// unrecognized
|
||||
return false;
|
||||
else {
|
||||
for (const simple of range.split(whitespaceRegExp)) {
|
||||
const match = rangeRegExp.exec(trimString(simple));
|
||||
if (!match || !parseComparator(match[1], match[2], comparators)) return undefined;
|
||||
}
|
||||
}
|
||||
else if (operator === "<" || operator === ">") {
|
||||
comparators.push(createComparator("<", Version.zero));
|
||||
}
|
||||
alternatives.push(comparators);
|
||||
}
|
||||
return alternatives;
|
||||
}
|
||||
|
||||
return true;
|
||||
function parsePartial(text: string) {
|
||||
const match = partialRegExp.exec(text);
|
||||
if (!match) return undefined;
|
||||
|
||||
const [, major, minor = "*", patch = "*", prerelease, build] = match;
|
||||
const version = new Version(
|
||||
isWildcard(major) ? 0 : parseInt(major, 10),
|
||||
isWildcard(major) || isWildcard(minor) ? 0 : parseInt(minor, 10),
|
||||
isWildcard(major) || isWildcard(minor) || isWildcard(patch) ? 0 : parseInt(patch, 10),
|
||||
prerelease,
|
||||
build);
|
||||
|
||||
return { version, major, minor, patch };
|
||||
}
|
||||
|
||||
function parseHyphen(left: string, right: string, comparators: Comparator[]) {
|
||||
const leftResult = parsePartial(left);
|
||||
if (!leftResult) return false;
|
||||
|
||||
const rightResult = parsePartial(right);
|
||||
if (!rightResult) return false;
|
||||
|
||||
if (!isWildcard(leftResult.major)) {
|
||||
comparators.push(createComparator(">=", leftResult.version));
|
||||
}
|
||||
|
||||
function isWildcard(part: string) {
|
||||
return part === "*" || part === "x" || part === "X";
|
||||
if (!isWildcard(rightResult.major)) {
|
||||
comparators.push(
|
||||
isWildcard(rightResult.minor) ? createComparator("<", rightResult.version.increment("major")) :
|
||||
isWildcard(rightResult.patch) ? createComparator("<", rightResult.version.increment("minor")) :
|
||||
createComparator("<=", rightResult.version));
|
||||
}
|
||||
|
||||
function createComparator(operator: Comparator["operator"], operand: Version) {
|
||||
return { operator, operand };
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function testDisjunction(version: Version, alternatives: readonly (readonly Comparator[])[]) {
|
||||
// an empty disjunction is treated as "*" (all versions)
|
||||
if (alternatives.length === 0) return true;
|
||||
for (const alternative of alternatives) {
|
||||
if (testAlternative(version, alternative)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function parseComparator(operator: string, text: string, comparators: Comparator[]) {
|
||||
const result = parsePartial(text);
|
||||
if (!result) return false;
|
||||
|
||||
function testAlternative(version: Version, comparators: readonly Comparator[]) {
|
||||
for (const comparator of comparators) {
|
||||
if (!testComparator(version, comparator.operator, comparator.operand)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function testComparator(version: Version, operator: Comparator["operator"], operand: Version) {
|
||||
const cmp = version.compareTo(operand);
|
||||
const { version, major, minor, patch } = result;
|
||||
if (!isWildcard(major)) {
|
||||
switch (operator) {
|
||||
case "<": return cmp < 0;
|
||||
case "<=": return cmp <= 0;
|
||||
case ">": return cmp > 0;
|
||||
case ">=": return cmp >= 0;
|
||||
case "=": return cmp === 0;
|
||||
default: return Debug.assertNever(operator);
|
||||
case "~":
|
||||
comparators.push(createComparator(">=", version));
|
||||
comparators.push(createComparator("<", version.increment(
|
||||
isWildcard(minor) ? "major" :
|
||||
"minor")));
|
||||
break;
|
||||
case "^":
|
||||
comparators.push(createComparator(">=", version));
|
||||
comparators.push(createComparator("<", version.increment(
|
||||
version.major > 0 || isWildcard(minor) ? "major" :
|
||||
version.minor > 0 || isWildcard(patch) ? "minor" :
|
||||
"patch")));
|
||||
break;
|
||||
case "<":
|
||||
case ">=":
|
||||
comparators.push(
|
||||
isWildcard(minor) || isWildcard(patch) ? createComparator(operator, version.with({ prerelease: "0" })) :
|
||||
createComparator(operator, version));
|
||||
break;
|
||||
case "<=":
|
||||
case ">":
|
||||
comparators.push(
|
||||
isWildcard(minor) ? createComparator(operator === "<=" ? "<" : ">=", version.increment("major").with({ prerelease: "0" })) :
|
||||
isWildcard(patch) ? createComparator(operator === "<=" ? "<" : ">=", version.increment("minor").with({ prerelease: "0" })) :
|
||||
createComparator(operator, version));
|
||||
break;
|
||||
case "=":
|
||||
case undefined:
|
||||
if (isWildcard(minor) || isWildcard(patch)) {
|
||||
comparators.push(createComparator(">=", version.with({ prerelease: "0" })));
|
||||
comparators.push(createComparator("<", version.increment(isWildcard(minor) ? "major" : "minor").with({ prerelease: "0" })));
|
||||
}
|
||||
else {
|
||||
comparators.push(createComparator("=", version));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// unrecognized
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function formatDisjunction(alternatives: readonly (readonly Comparator[])[]) {
|
||||
return map(alternatives, formatAlternative).join(" || ") || "*";
|
||||
else if (operator === "<" || operator === ">") {
|
||||
comparators.push(createComparator("<", Version.zero));
|
||||
}
|
||||
|
||||
function formatAlternative(comparators: readonly Comparator[]) {
|
||||
return map(comparators, formatComparator).join(" ");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function formatComparator(comparator: Comparator) {
|
||||
return `${comparator.operator}${comparator.operand}`;
|
||||
function isWildcard(part: string) {
|
||||
return part === "*" || part === "x" || part === "X";
|
||||
}
|
||||
|
||||
function createComparator(operator: Comparator["operator"], operand: Version) {
|
||||
return { operator, operand };
|
||||
}
|
||||
|
||||
function testDisjunction(version: Version, alternatives: readonly (readonly Comparator[])[]) {
|
||||
// an empty disjunction is treated as "*" (all versions)
|
||||
if (alternatives.length === 0) return true;
|
||||
for (const alternative of alternatives) {
|
||||
if (testAlternative(version, alternative)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function testAlternative(version: Version, comparators: readonly Comparator[]) {
|
||||
for (const comparator of comparators) {
|
||||
if (!testComparator(version, comparator.operator, comparator.operand)) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
function testComparator(version: Version, operator: Comparator["operator"], operand: Version) {
|
||||
const cmp = version.compareTo(operand);
|
||||
switch (operator) {
|
||||
case "<": return cmp < 0;
|
||||
case "<=": return cmp <= 0;
|
||||
case ">": return cmp > 0;
|
||||
case ">=": return cmp >= 0;
|
||||
case "=": return cmp === 0;
|
||||
default: return Debug.assertNever(operator);
|
||||
}
|
||||
}
|
||||
|
||||
function formatDisjunction(alternatives: readonly (readonly Comparator[])[]) {
|
||||
return map(alternatives, formatAlternative).join(" || ") || "*";
|
||||
}
|
||||
|
||||
function formatAlternative(comparators: readonly Comparator[]) {
|
||||
return map(comparators, formatComparator).join(" ");
|
||||
}
|
||||
|
||||
function formatComparator(comparator: Comparator) {
|
||||
return `${comparator.operator}${comparator.operand}`;
|
||||
}
|
||||
+742
-717
File diff suppressed because it is too large
Load Diff
+176
-172
@@ -1,190 +1,194 @@
|
||||
import {
|
||||
clear, EntityNameOrEntityNameExpression, forEach, getOwnValues, getSymbolId, Identifier, IndexedAccessType,
|
||||
IndexType, InterfaceType, MappedType, Node, ObjectFlags, ObjectType, ResolvedType, Signature, Symbol, SymbolWalker,
|
||||
SyntaxKind, Type, TypeFlags, TypeParameter, TypePredicate, TypeQueryNode, TypeReference, UnionOrIntersectionType,
|
||||
} from "./_namespaces/ts";
|
||||
|
||||
/** @internal */
|
||||
namespace ts {
|
||||
export function createGetSymbolWalker(
|
||||
getRestTypeOfSignature: (sig: Signature) => Type,
|
||||
getTypePredicateOfSignature: (sig: Signature) => TypePredicate | undefined,
|
||||
getReturnTypeOfSignature: (sig: Signature) => Type,
|
||||
getBaseTypes: (type: Type) => Type[],
|
||||
resolveStructuredTypeMembers: (type: ObjectType) => ResolvedType,
|
||||
getTypeOfSymbol: (sym: Symbol) => Type,
|
||||
getResolvedSymbol: (node: Node) => Symbol,
|
||||
getConstraintOfTypeParameter: (typeParameter: TypeParameter) => Type | undefined,
|
||||
getFirstIdentifier: (node: EntityNameOrEntityNameExpression) => Identifier,
|
||||
getTypeArguments: (type: TypeReference) => readonly Type[]) {
|
||||
export function createGetSymbolWalker(
|
||||
getRestTypeOfSignature: (sig: Signature) => Type,
|
||||
getTypePredicateOfSignature: (sig: Signature) => TypePredicate | undefined,
|
||||
getReturnTypeOfSignature: (sig: Signature) => Type,
|
||||
getBaseTypes: (type: Type) => Type[],
|
||||
resolveStructuredTypeMembers: (type: ObjectType) => ResolvedType,
|
||||
getTypeOfSymbol: (sym: Symbol) => Type,
|
||||
getResolvedSymbol: (node: Node) => Symbol,
|
||||
getConstraintOfTypeParameter: (typeParameter: TypeParameter) => Type | undefined,
|
||||
getFirstIdentifier: (node: EntityNameOrEntityNameExpression) => Identifier,
|
||||
getTypeArguments: (type: TypeReference) => readonly Type[]) {
|
||||
|
||||
return getSymbolWalker;
|
||||
return getSymbolWalker;
|
||||
|
||||
function getSymbolWalker(accept: (symbol: Symbol) => boolean = () => true): SymbolWalker {
|
||||
const visitedTypes: Type[] = []; // Sparse array from id to type
|
||||
const visitedSymbols: Symbol[] = []; // Sparse array from id to symbol
|
||||
function getSymbolWalker(accept: (symbol: Symbol) => boolean = () => true): SymbolWalker {
|
||||
const visitedTypes: Type[] = []; // Sparse array from id to type
|
||||
const visitedSymbols: Symbol[] = []; // Sparse array from id to symbol
|
||||
|
||||
return {
|
||||
walkType: type => {
|
||||
try {
|
||||
visitType(type);
|
||||
return { visitedTypes: getOwnValues(visitedTypes), visitedSymbols: getOwnValues(visitedSymbols) };
|
||||
}
|
||||
finally {
|
||||
clear(visitedTypes);
|
||||
clear(visitedSymbols);
|
||||
}
|
||||
},
|
||||
walkSymbol: symbol => {
|
||||
try {
|
||||
visitSymbol(symbol);
|
||||
return { visitedTypes: getOwnValues(visitedTypes), visitedSymbols: getOwnValues(visitedSymbols) };
|
||||
}
|
||||
finally {
|
||||
clear(visitedTypes);
|
||||
clear(visitedSymbols);
|
||||
}
|
||||
},
|
||||
};
|
||||
return {
|
||||
walkType: type => {
|
||||
try {
|
||||
visitType(type);
|
||||
return { visitedTypes: getOwnValues(visitedTypes), visitedSymbols: getOwnValues(visitedSymbols) };
|
||||
}
|
||||
finally {
|
||||
clear(visitedTypes);
|
||||
clear(visitedSymbols);
|
||||
}
|
||||
},
|
||||
walkSymbol: symbol => {
|
||||
try {
|
||||
visitSymbol(symbol);
|
||||
return { visitedTypes: getOwnValues(visitedTypes), visitedSymbols: getOwnValues(visitedSymbols) };
|
||||
}
|
||||
finally {
|
||||
clear(visitedTypes);
|
||||
clear(visitedSymbols);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
function visitType(type: Type | undefined): void {
|
||||
if (!type) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (visitedTypes[type.id]) {
|
||||
return;
|
||||
}
|
||||
visitedTypes[type.id] = type;
|
||||
|
||||
// Reuse visitSymbol to visit the type's symbol,
|
||||
// but be sure to bail on recuring into the type if accept declines the symbol.
|
||||
const shouldBail = visitSymbol(type.symbol);
|
||||
if (shouldBail) return;
|
||||
|
||||
// Visit the type's related types, if any
|
||||
if (type.flags & TypeFlags.Object) {
|
||||
const objectType = type as ObjectType;
|
||||
const objectFlags = objectType.objectFlags;
|
||||
if (objectFlags & ObjectFlags.Reference) {
|
||||
visitTypeReference(type as TypeReference);
|
||||
}
|
||||
if (objectFlags & ObjectFlags.Mapped) {
|
||||
visitMappedType(type as MappedType);
|
||||
}
|
||||
if (objectFlags & (ObjectFlags.Class | ObjectFlags.Interface)) {
|
||||
visitInterfaceType(type as InterfaceType);
|
||||
}
|
||||
if (objectFlags & (ObjectFlags.Tuple | ObjectFlags.Anonymous)) {
|
||||
visitObjectType(objectType);
|
||||
}
|
||||
}
|
||||
if (type.flags & TypeFlags.TypeParameter) {
|
||||
visitTypeParameter(type as TypeParameter);
|
||||
}
|
||||
if (type.flags & TypeFlags.UnionOrIntersection) {
|
||||
visitUnionOrIntersectionType(type as UnionOrIntersectionType);
|
||||
}
|
||||
if (type.flags & TypeFlags.Index) {
|
||||
visitIndexType(type as IndexType);
|
||||
}
|
||||
if (type.flags & TypeFlags.IndexedAccess) {
|
||||
visitIndexedAccessType(type as IndexedAccessType);
|
||||
}
|
||||
function visitType(type: Type | undefined): void {
|
||||
if (!type) {
|
||||
return;
|
||||
}
|
||||
|
||||
function visitTypeReference(type: TypeReference): void {
|
||||
visitType(type.target);
|
||||
forEach(getTypeArguments(type), visitType);
|
||||
if (visitedTypes[type.id]) {
|
||||
return;
|
||||
}
|
||||
visitedTypes[type.id] = type;
|
||||
|
||||
function visitTypeParameter(type: TypeParameter): void {
|
||||
visitType(getConstraintOfTypeParameter(type));
|
||||
}
|
||||
// Reuse visitSymbol to visit the type's symbol,
|
||||
// but be sure to bail on recuring into the type if accept declines the symbol.
|
||||
const shouldBail = visitSymbol(type.symbol);
|
||||
if (shouldBail) return;
|
||||
|
||||
function visitUnionOrIntersectionType(type: UnionOrIntersectionType): void {
|
||||
forEach(type.types, visitType);
|
||||
}
|
||||
|
||||
function visitIndexType(type: IndexType): void {
|
||||
visitType(type.type);
|
||||
}
|
||||
|
||||
function visitIndexedAccessType(type: IndexedAccessType): void {
|
||||
visitType(type.objectType);
|
||||
visitType(type.indexType);
|
||||
visitType(type.constraint);
|
||||
}
|
||||
|
||||
function visitMappedType(type: MappedType): void {
|
||||
visitType(type.typeParameter);
|
||||
visitType(type.constraintType);
|
||||
visitType(type.templateType);
|
||||
visitType(type.modifiersType);
|
||||
}
|
||||
|
||||
function visitSignature(signature: Signature): void {
|
||||
const typePredicate = getTypePredicateOfSignature(signature);
|
||||
if (typePredicate) {
|
||||
visitType(typePredicate.type);
|
||||
// Visit the type's related types, if any
|
||||
if (type.flags & TypeFlags.Object) {
|
||||
const objectType = type as ObjectType;
|
||||
const objectFlags = objectType.objectFlags;
|
||||
if (objectFlags & ObjectFlags.Reference) {
|
||||
visitTypeReference(type as TypeReference);
|
||||
}
|
||||
forEach(signature.typeParameters, visitType);
|
||||
|
||||
for (const parameter of signature.parameters) {
|
||||
visitSymbol(parameter);
|
||||
if (objectFlags & ObjectFlags.Mapped) {
|
||||
visitMappedType(type as MappedType);
|
||||
}
|
||||
visitType(getRestTypeOfSignature(signature));
|
||||
visitType(getReturnTypeOfSignature(signature));
|
||||
}
|
||||
|
||||
function visitInterfaceType(interfaceT: InterfaceType): void {
|
||||
visitObjectType(interfaceT);
|
||||
forEach(interfaceT.typeParameters, visitType);
|
||||
forEach(getBaseTypes(interfaceT), visitType);
|
||||
visitType(interfaceT.thisType);
|
||||
}
|
||||
|
||||
function visitObjectType(type: ObjectType): void {
|
||||
const resolved = resolveStructuredTypeMembers(type);
|
||||
for (const info of resolved.indexInfos) {
|
||||
visitType(info.keyType);
|
||||
visitType(info.type);
|
||||
if (objectFlags & (ObjectFlags.Class | ObjectFlags.Interface)) {
|
||||
visitInterfaceType(type as InterfaceType);
|
||||
}
|
||||
for (const signature of resolved.callSignatures) {
|
||||
visitSignature(signature);
|
||||
}
|
||||
for (const signature of resolved.constructSignatures) {
|
||||
visitSignature(signature);
|
||||
}
|
||||
for (const p of resolved.properties) {
|
||||
visitSymbol(p);
|
||||
if (objectFlags & (ObjectFlags.Tuple | ObjectFlags.Anonymous)) {
|
||||
visitObjectType(objectType);
|
||||
}
|
||||
}
|
||||
|
||||
function visitSymbol(symbol: Symbol | undefined): boolean {
|
||||
if (!symbol) {
|
||||
return false;
|
||||
}
|
||||
const symbolId = getSymbolId(symbol);
|
||||
if (visitedSymbols[symbolId]) {
|
||||
return false;
|
||||
}
|
||||
visitedSymbols[symbolId] = symbol;
|
||||
if (!accept(symbol)) {
|
||||
return true;
|
||||
}
|
||||
const t = getTypeOfSymbol(symbol);
|
||||
visitType(t); // Should handle members on classes and such
|
||||
if (symbol.exports) {
|
||||
symbol.exports.forEach(visitSymbol);
|
||||
}
|
||||
forEach(symbol.declarations, d => {
|
||||
// Type queries are too far resolved when we just visit the symbol's type
|
||||
// (their type resolved directly to the member deeply referenced)
|
||||
// So to get the intervening symbols, we need to check if there's a type
|
||||
// query node on any of the symbol's declarations and get symbols there
|
||||
if ((d as any).type && (d as any).type.kind === SyntaxKind.TypeQuery) {
|
||||
const query = (d as any).type as TypeQueryNode;
|
||||
const entity = getResolvedSymbol(getFirstIdentifier(query.exprName));
|
||||
visitSymbol(entity);
|
||||
}
|
||||
});
|
||||
return false;
|
||||
if (type.flags & TypeFlags.TypeParameter) {
|
||||
visitTypeParameter(type as TypeParameter);
|
||||
}
|
||||
if (type.flags & TypeFlags.UnionOrIntersection) {
|
||||
visitUnionOrIntersectionType(type as UnionOrIntersectionType);
|
||||
}
|
||||
if (type.flags & TypeFlags.Index) {
|
||||
visitIndexType(type as IndexType);
|
||||
}
|
||||
if (type.flags & TypeFlags.IndexedAccess) {
|
||||
visitIndexedAccessType(type as IndexedAccessType);
|
||||
}
|
||||
}
|
||||
|
||||
function visitTypeReference(type: TypeReference): void {
|
||||
visitType(type.target);
|
||||
forEach(getTypeArguments(type), visitType);
|
||||
}
|
||||
|
||||
function visitTypeParameter(type: TypeParameter): void {
|
||||
visitType(getConstraintOfTypeParameter(type));
|
||||
}
|
||||
|
||||
function visitUnionOrIntersectionType(type: UnionOrIntersectionType): void {
|
||||
forEach(type.types, visitType);
|
||||
}
|
||||
|
||||
function visitIndexType(type: IndexType): void {
|
||||
visitType(type.type);
|
||||
}
|
||||
|
||||
function visitIndexedAccessType(type: IndexedAccessType): void {
|
||||
visitType(type.objectType);
|
||||
visitType(type.indexType);
|
||||
visitType(type.constraint);
|
||||
}
|
||||
|
||||
function visitMappedType(type: MappedType): void {
|
||||
visitType(type.typeParameter);
|
||||
visitType(type.constraintType);
|
||||
visitType(type.templateType);
|
||||
visitType(type.modifiersType);
|
||||
}
|
||||
|
||||
function visitSignature(signature: Signature): void {
|
||||
const typePredicate = getTypePredicateOfSignature(signature);
|
||||
if (typePredicate) {
|
||||
visitType(typePredicate.type);
|
||||
}
|
||||
forEach(signature.typeParameters, visitType);
|
||||
|
||||
for (const parameter of signature.parameters) {
|
||||
visitSymbol(parameter);
|
||||
}
|
||||
visitType(getRestTypeOfSignature(signature));
|
||||
visitType(getReturnTypeOfSignature(signature));
|
||||
}
|
||||
|
||||
function visitInterfaceType(interfaceT: InterfaceType): void {
|
||||
visitObjectType(interfaceT);
|
||||
forEach(interfaceT.typeParameters, visitType);
|
||||
forEach(getBaseTypes(interfaceT), visitType);
|
||||
visitType(interfaceT.thisType);
|
||||
}
|
||||
|
||||
function visitObjectType(type: ObjectType): void {
|
||||
const resolved = resolveStructuredTypeMembers(type);
|
||||
for (const info of resolved.indexInfos) {
|
||||
visitType(info.keyType);
|
||||
visitType(info.type);
|
||||
}
|
||||
for (const signature of resolved.callSignatures) {
|
||||
visitSignature(signature);
|
||||
}
|
||||
for (const signature of resolved.constructSignatures) {
|
||||
visitSignature(signature);
|
||||
}
|
||||
for (const p of resolved.properties) {
|
||||
visitSymbol(p);
|
||||
}
|
||||
}
|
||||
|
||||
function visitSymbol(symbol: Symbol | undefined): boolean {
|
||||
if (!symbol) {
|
||||
return false;
|
||||
}
|
||||
const symbolId = getSymbolId(symbol);
|
||||
if (visitedSymbols[symbolId]) {
|
||||
return false;
|
||||
}
|
||||
visitedSymbols[symbolId] = symbol;
|
||||
if (!accept(symbol)) {
|
||||
return true;
|
||||
}
|
||||
const t = getTypeOfSymbol(symbol);
|
||||
visitType(t); // Should handle members on classes and such
|
||||
if (symbol.exports) {
|
||||
symbol.exports.forEach(visitSymbol);
|
||||
}
|
||||
forEach(symbol.declarations, d => {
|
||||
// Type queries are too far resolved when we just visit the symbol's type
|
||||
// (their type resolved directly to the member deeply referenced)
|
||||
// So to get the intervening symbols, we need to check if there's a type
|
||||
// query node on any of the symbol's declarations and get symbols there
|
||||
if ((d as any).type && (d as any).type.kind === SyntaxKind.TypeQuery) {
|
||||
const query = (d as any).type as TypeQueryNode;
|
||||
const entity = getResolvedSymbol(getFirstIdentifier(query.exprName));
|
||||
visitSymbol(entity);
|
||||
}
|
||||
});
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1855
-1839
File diff suppressed because it is too large
Load Diff
+334
-323
@@ -1,349 +1,360 @@
|
||||
import {
|
||||
combinePaths, ConditionalType, Debug, EvolvingArrayType, getLineAndCharacterOfPosition, getSourceFileOfNode,
|
||||
IndexedAccessType, IndexType, IntersectionType, LineAndCharacter, Map, Node, ObjectFlags, Path, ReverseMappedType,
|
||||
SubstitutionType, timestamp, Type, TypeFlags, TypeReference, unescapeLeadingUnderscores, UnionType,
|
||||
} from "./_namespaces/ts";
|
||||
import * as performance from "./_namespaces/ts.performance";
|
||||
|
||||
/* Tracing events for the compiler. */
|
||||
|
||||
/*@internal*/
|
||||
namespace ts { // eslint-disable-line local/one-namespace-per-file
|
||||
// should be used as tracing?.___
|
||||
export let tracing: typeof tracingEnabled | undefined;
|
||||
// enable the above using startTracing()
|
||||
// should be used as tracing?.___
|
||||
/** @internal */
|
||||
export let tracing: typeof tracingEnabled | undefined;
|
||||
// enable the above using startTracing()
|
||||
|
||||
// `tracingEnabled` should never be used directly, only through the above
|
||||
namespace tracingEnabled { // eslint-disable-line local/one-namespace-per-file
|
||||
type Mode = "project" | "build" | "server";
|
||||
/**
|
||||
* Do not use this directly; instead @see {tracing}.
|
||||
* @internal
|
||||
*/
|
||||
export namespace tracingEnabled {
|
||||
type Mode = "project" | "build" | "server";
|
||||
|
||||
let fs: typeof import("fs");
|
||||
let fs: typeof import("fs");
|
||||
|
||||
let traceCount = 0;
|
||||
let traceFd = 0;
|
||||
let traceCount = 0;
|
||||
let traceFd = 0;
|
||||
|
||||
let mode: Mode;
|
||||
let mode: Mode;
|
||||
|
||||
const typeCatalog: Type[] = []; // NB: id is index + 1
|
||||
const typeCatalog: Type[] = []; // NB: id is index + 1
|
||||
|
||||
let legendPath: string | undefined;
|
||||
const legend: TraceRecord[] = [];
|
||||
let legendPath: string | undefined;
|
||||
const legend: TraceRecord[] = [];
|
||||
|
||||
// The actual constraint is that JSON.stringify be able to serialize it without throwing.
|
||||
interface Args {
|
||||
[key: string]: string | number | boolean | null | undefined | Args | readonly (string | number | boolean | null | undefined | Args)[];
|
||||
}
|
||||
// The actual constraint is that JSON.stringify be able to serialize it without throwing.
|
||||
interface Args {
|
||||
[key: string]: string | number | boolean | null | undefined | Args | readonly (string | number | boolean | null | undefined | Args)[];
|
||||
}
|
||||
|
||||
/** Starts tracing for the given project. */
|
||||
export function startTracing(tracingMode: Mode, traceDir: string, configFilePath?: string) {
|
||||
Debug.assert(!tracing, "Tracing already started");
|
||||
/** Starts tracing for the given project. */
|
||||
export function startTracing(tracingMode: Mode, traceDir: string, configFilePath?: string) {
|
||||
Debug.assert(!tracing, "Tracing already started");
|
||||
|
||||
if (fs === undefined) {
|
||||
try {
|
||||
fs = require("fs");
|
||||
}
|
||||
catch (e) {
|
||||
throw new Error(`tracing requires having fs\n(original error: ${e.message || e})`);
|
||||
}
|
||||
if (fs === undefined) {
|
||||
try {
|
||||
fs = require("fs");
|
||||
}
|
||||
|
||||
mode = tracingMode;
|
||||
typeCatalog.length = 0;
|
||||
|
||||
if (legendPath === undefined) {
|
||||
legendPath = combinePaths(traceDir, "legend.json");
|
||||
}
|
||||
|
||||
// Note that writing will fail later on if it exists and is not a directory
|
||||
if (!fs.existsSync(traceDir)) {
|
||||
fs.mkdirSync(traceDir, { recursive: true });
|
||||
}
|
||||
|
||||
const countPart =
|
||||
mode === "build" ? `.${process.pid}-${++traceCount}`
|
||||
: mode === "server" ? `.${process.pid}`
|
||||
: ``;
|
||||
const tracePath = combinePaths(traceDir, `trace${countPart}.json`);
|
||||
const typesPath = combinePaths(traceDir, `types${countPart}.json`);
|
||||
|
||||
legend.push({
|
||||
configFilePath,
|
||||
tracePath,
|
||||
typesPath,
|
||||
});
|
||||
|
||||
traceFd = fs.openSync(tracePath, "w");
|
||||
tracing = tracingEnabled; // only when traceFd is properly set
|
||||
|
||||
// Start with a prefix that contains some metadata that the devtools profiler expects (also avoids a warning on import)
|
||||
const meta = { cat: "__metadata", ph: "M", ts: 1000 * timestamp(), pid: 1, tid: 1 };
|
||||
fs.writeSync(traceFd,
|
||||
"[\n"
|
||||
+ [{ name: "process_name", args: { name: "tsc" }, ...meta },
|
||||
{ name: "thread_name", args: { name: "Main" }, ...meta },
|
||||
{ name: "TracingStartedInBrowser", ...meta, cat: "disabled-by-default-devtools.timeline" }]
|
||||
.map(v => JSON.stringify(v)).join(",\n"));
|
||||
}
|
||||
|
||||
/** Stops tracing for the in-progress project and dumps the type catalog. */
|
||||
export function stopTracing() {
|
||||
Debug.assert(tracing, "Tracing is not in progress");
|
||||
Debug.assert(!!typeCatalog.length === (mode !== "server")); // Have a type catalog iff not in server mode
|
||||
|
||||
fs.writeSync(traceFd, `\n]\n`);
|
||||
fs.closeSync(traceFd);
|
||||
tracing = undefined;
|
||||
|
||||
if (typeCatalog.length) {
|
||||
dumpTypes(typeCatalog);
|
||||
}
|
||||
else {
|
||||
// We pre-computed this path for convenience, but clear it
|
||||
// now that the file won't be created.
|
||||
legend[legend.length - 1].typesPath = undefined;
|
||||
catch (e) {
|
||||
throw new Error(`tracing requires having fs\n(original error: ${e.message || e})`);
|
||||
}
|
||||
}
|
||||
|
||||
export function recordType(type: Type): void {
|
||||
if (mode !== "server") {
|
||||
typeCatalog.push(type);
|
||||
}
|
||||
mode = tracingMode;
|
||||
typeCatalog.length = 0;
|
||||
|
||||
if (legendPath === undefined) {
|
||||
legendPath = combinePaths(traceDir, "legend.json");
|
||||
}
|
||||
|
||||
export const enum Phase {
|
||||
Parse = "parse",
|
||||
Program = "program",
|
||||
Bind = "bind",
|
||||
Check = "check", // Before we get into checking types (e.g. checkSourceFile)
|
||||
CheckTypes = "checkTypes",
|
||||
Emit = "emit",
|
||||
Session = "session",
|
||||
// Note that writing will fail later on if it exists and is not a directory
|
||||
if (!fs.existsSync(traceDir)) {
|
||||
fs.mkdirSync(traceDir, { recursive: true });
|
||||
}
|
||||
|
||||
export function instant(phase: Phase, name: string, args?: Args) {
|
||||
writeEvent("I", phase, name, args, `"s":"g"`);
|
||||
const countPart =
|
||||
mode === "build" ? `.${process.pid}-${++traceCount}`
|
||||
: mode === "server" ? `.${process.pid}`
|
||||
: ``;
|
||||
const tracePath = combinePaths(traceDir, `trace${countPart}.json`);
|
||||
const typesPath = combinePaths(traceDir, `types${countPart}.json`);
|
||||
|
||||
legend.push({
|
||||
configFilePath,
|
||||
tracePath,
|
||||
typesPath,
|
||||
});
|
||||
|
||||
traceFd = fs.openSync(tracePath, "w");
|
||||
tracing = tracingEnabled; // only when traceFd is properly set
|
||||
|
||||
// Start with a prefix that contains some metadata that the devtools profiler expects (also avoids a warning on import)
|
||||
const meta = { cat: "__metadata", ph: "M", ts: 1000 * timestamp(), pid: 1, tid: 1 };
|
||||
fs.writeSync(traceFd,
|
||||
"[\n"
|
||||
+ [{ name: "process_name", args: { name: "tsc" }, ...meta },
|
||||
{ name: "thread_name", args: { name: "Main" }, ...meta },
|
||||
{ name: "TracingStartedInBrowser", ...meta, cat: "disabled-by-default-devtools.timeline" }]
|
||||
.map(v => JSON.stringify(v)).join(",\n"));
|
||||
}
|
||||
|
||||
/** Stops tracing for the in-progress project and dumps the type catalog. */
|
||||
export function stopTracing() {
|
||||
Debug.assert(tracing, "Tracing is not in progress");
|
||||
Debug.assert(!!typeCatalog.length === (mode !== "server")); // Have a type catalog iff not in server mode
|
||||
|
||||
fs.writeSync(traceFd, `\n]\n`);
|
||||
fs.closeSync(traceFd);
|
||||
tracing = undefined;
|
||||
|
||||
if (typeCatalog.length) {
|
||||
dumpTypes(typeCatalog);
|
||||
}
|
||||
|
||||
const eventStack: { phase: Phase, name: string, args?: Args, time: number, separateBeginAndEnd: boolean }[] = [];
|
||||
|
||||
/**
|
||||
* @param separateBeginAndEnd - used for special cases where we need the trace point even if the event
|
||||
* never terminates (typically for reducing a scenario too big to trace to one that can be completed).
|
||||
* In the future we might implement an exit handler to dump unfinished events which would deprecate
|
||||
* these operations.
|
||||
*/
|
||||
export function push(phase: Phase, name: string, args?: Args, separateBeginAndEnd = false) {
|
||||
if (separateBeginAndEnd) {
|
||||
writeEvent("B", phase, name, args);
|
||||
}
|
||||
eventStack.push({ phase, name, args, time: 1000 * timestamp(), separateBeginAndEnd });
|
||||
}
|
||||
export function pop(results?: Args) {
|
||||
Debug.assert(eventStack.length > 0);
|
||||
writeStackEvent(eventStack.length - 1, 1000 * timestamp(), results);
|
||||
eventStack.length--;
|
||||
}
|
||||
export function popAll() {
|
||||
const endTime = 1000 * timestamp();
|
||||
for (let i = eventStack.length - 1; i >= 0; i--) {
|
||||
writeStackEvent(i, endTime);
|
||||
}
|
||||
eventStack.length = 0;
|
||||
}
|
||||
// sample every 10ms
|
||||
const sampleInterval = 1000 * 10;
|
||||
function writeStackEvent(index: number, endTime: number, results?: Args) {
|
||||
const { phase, name, args, time, separateBeginAndEnd } = eventStack[index];
|
||||
if (separateBeginAndEnd) {
|
||||
Debug.assert(!results, "`results` are not supported for events with `separateBeginAndEnd`");
|
||||
writeEvent("E", phase, name, args, /*extras*/ undefined, endTime);
|
||||
}
|
||||
// test if [time,endTime) straddles a sampling point
|
||||
else if (sampleInterval - (time % sampleInterval) <= endTime - time) {
|
||||
writeEvent("X", phase, name, { ...args, results }, `"dur":${endTime - time}`, time);
|
||||
}
|
||||
}
|
||||
|
||||
function writeEvent(eventType: string, phase: Phase, name: string, args: Args | undefined, extras?: string,
|
||||
time: number = 1000 * timestamp()) {
|
||||
|
||||
// In server mode, there's no easy way to dump type information, so we drop events that would require it.
|
||||
if (mode === "server" && phase === Phase.CheckTypes) return;
|
||||
|
||||
performance.mark("beginTracing");
|
||||
fs.writeSync(traceFd, `,\n{"pid":1,"tid":1,"ph":"${eventType}","cat":"${phase}","ts":${time},"name":"${name}"`);
|
||||
if (extras) fs.writeSync(traceFd, `,${extras}`);
|
||||
if (args) fs.writeSync(traceFd, `,"args":${JSON.stringify(args)}`);
|
||||
fs.writeSync(traceFd, `}`);
|
||||
performance.mark("endTracing");
|
||||
performance.measure("Tracing", "beginTracing", "endTracing");
|
||||
}
|
||||
|
||||
function getLocation(node: Node | undefined) {
|
||||
const file = getSourceFileOfNode(node);
|
||||
return !file
|
||||
? undefined
|
||||
: {
|
||||
path: file.path,
|
||||
start: indexFromOne(getLineAndCharacterOfPosition(file, node!.pos)),
|
||||
end: indexFromOne(getLineAndCharacterOfPosition(file, node!.end)),
|
||||
};
|
||||
|
||||
function indexFromOne(lc: LineAndCharacter): LineAndCharacter {
|
||||
return {
|
||||
line: lc.line + 1,
|
||||
character: lc.character + 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function dumpTypes(types: readonly Type[]) {
|
||||
performance.mark("beginDumpTypes");
|
||||
|
||||
const typesPath = legend[legend.length - 1].typesPath!;
|
||||
const typesFd = fs.openSync(typesPath, "w");
|
||||
|
||||
const recursionIdentityMap = new Map<object, number>();
|
||||
|
||||
// Cleverness: no line break here so that the type ID will match the line number
|
||||
fs.writeSync(typesFd, "[");
|
||||
|
||||
const numTypes = types.length;
|
||||
for (let i = 0; i < numTypes; i++) {
|
||||
const type = types[i];
|
||||
const objectFlags = (type as any).objectFlags;
|
||||
const symbol = type.aliasSymbol ?? type.symbol;
|
||||
|
||||
// It's slow to compute the display text, so skip it unless it's really valuable (or cheap)
|
||||
let display: string | undefined;
|
||||
if ((objectFlags & ObjectFlags.Anonymous) | (type.flags & TypeFlags.Literal)) {
|
||||
try {
|
||||
display = type.checker?.typeToString(type);
|
||||
}
|
||||
catch {
|
||||
display = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
let indexedAccessProperties: object = {};
|
||||
if (type.flags & TypeFlags.IndexedAccess) {
|
||||
const indexedAccessType = type as IndexedAccessType;
|
||||
indexedAccessProperties = {
|
||||
indexedAccessObjectType: indexedAccessType.objectType?.id,
|
||||
indexedAccessIndexType: indexedAccessType.indexType?.id,
|
||||
};
|
||||
}
|
||||
|
||||
let referenceProperties: object = {};
|
||||
if (objectFlags & ObjectFlags.Reference) {
|
||||
const referenceType = type as TypeReference;
|
||||
referenceProperties = {
|
||||
instantiatedType: referenceType.target?.id,
|
||||
typeArguments: referenceType.resolvedTypeArguments?.map(t => t.id),
|
||||
referenceLocation: getLocation(referenceType.node),
|
||||
};
|
||||
}
|
||||
|
||||
let conditionalProperties: object = {};
|
||||
if (type.flags & TypeFlags.Conditional) {
|
||||
const conditionalType = type as ConditionalType;
|
||||
conditionalProperties = {
|
||||
conditionalCheckType: conditionalType.checkType?.id,
|
||||
conditionalExtendsType: conditionalType.extendsType?.id,
|
||||
conditionalTrueType: conditionalType.resolvedTrueType?.id ?? -1,
|
||||
conditionalFalseType: conditionalType.resolvedFalseType?.id ?? -1,
|
||||
};
|
||||
}
|
||||
|
||||
let substitutionProperties: object = {};
|
||||
if (type.flags & TypeFlags.Substitution) {
|
||||
const substitutionType = type as SubstitutionType;
|
||||
substitutionProperties = {
|
||||
substitutionBaseType: substitutionType.baseType?.id,
|
||||
constraintType: substitutionType.constraint?.id,
|
||||
};
|
||||
}
|
||||
|
||||
let reverseMappedProperties: object = {};
|
||||
if (objectFlags & ObjectFlags.ReverseMapped) {
|
||||
const reverseMappedType = type as ReverseMappedType;
|
||||
reverseMappedProperties = {
|
||||
reverseMappedSourceType: reverseMappedType.source?.id,
|
||||
reverseMappedMappedType: reverseMappedType.mappedType?.id,
|
||||
reverseMappedConstraintType: reverseMappedType.constraintType?.id,
|
||||
};
|
||||
}
|
||||
|
||||
let evolvingArrayProperties: object = {};
|
||||
if (objectFlags & ObjectFlags.EvolvingArray) {
|
||||
const evolvingArrayType = type as EvolvingArrayType;
|
||||
evolvingArrayProperties = {
|
||||
evolvingArrayElementType: evolvingArrayType.elementType.id,
|
||||
evolvingArrayFinalType: evolvingArrayType.finalArrayType?.id,
|
||||
};
|
||||
}
|
||||
|
||||
// We can't print out an arbitrary object, so just assign each one a unique number.
|
||||
// Don't call it an "id" so people don't treat it as a type id.
|
||||
let recursionToken: number | undefined;
|
||||
const recursionIdentity = type.checker.getRecursionIdentity(type);
|
||||
if (recursionIdentity) {
|
||||
recursionToken = recursionIdentityMap.get(recursionIdentity);
|
||||
if (!recursionToken) {
|
||||
recursionToken = recursionIdentityMap.size;
|
||||
recursionIdentityMap.set(recursionIdentity, recursionToken);
|
||||
}
|
||||
}
|
||||
|
||||
const descriptor = {
|
||||
id: type.id,
|
||||
intrinsicName: (type as any).intrinsicName,
|
||||
symbolName: symbol?.escapedName && unescapeLeadingUnderscores(symbol.escapedName),
|
||||
recursionId: recursionToken,
|
||||
isTuple: objectFlags & ObjectFlags.Tuple ? true : undefined,
|
||||
unionTypes: (type.flags & TypeFlags.Union) ? (type as UnionType).types?.map(t => t.id) : undefined,
|
||||
intersectionTypes: (type.flags & TypeFlags.Intersection) ? (type as IntersectionType).types.map(t => t.id) : undefined,
|
||||
aliasTypeArguments: type.aliasTypeArguments?.map(t => t.id),
|
||||
keyofType: (type.flags & TypeFlags.Index) ? (type as IndexType).type?.id : undefined,
|
||||
...indexedAccessProperties,
|
||||
...referenceProperties,
|
||||
...conditionalProperties,
|
||||
...substitutionProperties,
|
||||
...reverseMappedProperties,
|
||||
...evolvingArrayProperties,
|
||||
destructuringPattern: getLocation(type.pattern),
|
||||
firstDeclaration: getLocation(symbol?.declarations?.[0]),
|
||||
flags: Debug.formatTypeFlags(type.flags).split("|"),
|
||||
display,
|
||||
};
|
||||
|
||||
fs.writeSync(typesFd, JSON.stringify(descriptor));
|
||||
if (i < numTypes - 1) {
|
||||
fs.writeSync(typesFd, ",\n");
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeSync(typesFd, "]\n");
|
||||
|
||||
fs.closeSync(typesFd);
|
||||
|
||||
performance.mark("endDumpTypes");
|
||||
performance.measure("Dump types", "beginDumpTypes", "endDumpTypes");
|
||||
}
|
||||
|
||||
export function dumpLegend() {
|
||||
if (!legendPath) {
|
||||
return;
|
||||
}
|
||||
|
||||
fs.writeFileSync(legendPath, JSON.stringify(legend));
|
||||
}
|
||||
|
||||
interface TraceRecord {
|
||||
configFilePath?: string;
|
||||
tracePath: string;
|
||||
typesPath?: string;
|
||||
else {
|
||||
// We pre-computed this path for convenience, but clear it
|
||||
// now that the file won't be created.
|
||||
legend[legend.length - 1].typesPath = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
// define after tracingEnabled is initialized
|
||||
export const startTracing = tracingEnabled.startTracing;
|
||||
export const dumpTracingLegend = tracingEnabled.dumpLegend;
|
||||
export function recordType(type: Type): void {
|
||||
if (mode !== "server") {
|
||||
typeCatalog.push(type);
|
||||
}
|
||||
}
|
||||
|
||||
export interface TracingNode {
|
||||
tracingPath?: Path;
|
||||
export const enum Phase {
|
||||
Parse = "parse",
|
||||
Program = "program",
|
||||
Bind = "bind",
|
||||
Check = "check", // Before we get into checking types (e.g. checkSourceFile)
|
||||
CheckTypes = "checkTypes",
|
||||
Emit = "emit",
|
||||
Session = "session",
|
||||
}
|
||||
|
||||
export function instant(phase: Phase, name: string, args?: Args) {
|
||||
writeEvent("I", phase, name, args, `"s":"g"`);
|
||||
}
|
||||
|
||||
const eventStack: { phase: Phase, name: string, args?: Args, time: number, separateBeginAndEnd: boolean }[] = [];
|
||||
|
||||
/**
|
||||
* @param separateBeginAndEnd - used for special cases where we need the trace point even if the event
|
||||
* never terminates (typically for reducing a scenario too big to trace to one that can be completed).
|
||||
* In the future we might implement an exit handler to dump unfinished events which would deprecate
|
||||
* these operations.
|
||||
*/
|
||||
export function push(phase: Phase, name: string, args?: Args, separateBeginAndEnd = false) {
|
||||
if (separateBeginAndEnd) {
|
||||
writeEvent("B", phase, name, args);
|
||||
}
|
||||
eventStack.push({ phase, name, args, time: 1000 * timestamp(), separateBeginAndEnd });
|
||||
}
|
||||
export function pop(results?: Args) {
|
||||
Debug.assert(eventStack.length > 0);
|
||||
writeStackEvent(eventStack.length - 1, 1000 * timestamp(), results);
|
||||
eventStack.length--;
|
||||
}
|
||||
export function popAll() {
|
||||
const endTime = 1000 * timestamp();
|
||||
for (let i = eventStack.length - 1; i >= 0; i--) {
|
||||
writeStackEvent(i, endTime);
|
||||
}
|
||||
eventStack.length = 0;
|
||||
}
|
||||
// sample every 10ms
|
||||
const sampleInterval = 1000 * 10;
|
||||
function writeStackEvent(index: number, endTime: number, results?: Args) {
|
||||
const { phase, name, args, time, separateBeginAndEnd } = eventStack[index];
|
||||
if (separateBeginAndEnd) {
|
||||
Debug.assert(!results, "`results` are not supported for events with `separateBeginAndEnd`");
|
||||
writeEvent("E", phase, name, args, /*extras*/ undefined, endTime);
|
||||
}
|
||||
// test if [time,endTime) straddles a sampling point
|
||||
else if (sampleInterval - (time % sampleInterval) <= endTime - time) {
|
||||
writeEvent("X", phase, name, { ...args, results }, `"dur":${endTime - time}`, time);
|
||||
}
|
||||
}
|
||||
|
||||
function writeEvent(eventType: string, phase: Phase, name: string, args: Args | undefined, extras?: string,
|
||||
time: number = 1000 * timestamp()) {
|
||||
|
||||
// In server mode, there's no easy way to dump type information, so we drop events that would require it.
|
||||
if (mode === "server" && phase === Phase.CheckTypes) return;
|
||||
|
||||
performance.mark("beginTracing");
|
||||
fs.writeSync(traceFd, `,\n{"pid":1,"tid":1,"ph":"${eventType}","cat":"${phase}","ts":${time},"name":"${name}"`);
|
||||
if (extras) fs.writeSync(traceFd, `,${extras}`);
|
||||
if (args) fs.writeSync(traceFd, `,"args":${JSON.stringify(args)}`);
|
||||
fs.writeSync(traceFd, `}`);
|
||||
performance.mark("endTracing");
|
||||
performance.measure("Tracing", "beginTracing", "endTracing");
|
||||
}
|
||||
|
||||
function getLocation(node: Node | undefined) {
|
||||
const file = getSourceFileOfNode(node);
|
||||
return !file
|
||||
? undefined
|
||||
: {
|
||||
path: file.path,
|
||||
start: indexFromOne(getLineAndCharacterOfPosition(file, node!.pos)),
|
||||
end: indexFromOne(getLineAndCharacterOfPosition(file, node!.end)),
|
||||
};
|
||||
|
||||
function indexFromOne(lc: LineAndCharacter): LineAndCharacter {
|
||||
return {
|
||||
line: lc.line + 1,
|
||||
character: lc.character + 1,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
function dumpTypes(types: readonly Type[]) {
|
||||
performance.mark("beginDumpTypes");
|
||||
|
||||
const typesPath = legend[legend.length - 1].typesPath!;
|
||||
const typesFd = fs.openSync(typesPath, "w");
|
||||
|
||||
const recursionIdentityMap = new Map<object, number>();
|
||||
|
||||
// Cleverness: no line break here so that the type ID will match the line number
|
||||
fs.writeSync(typesFd, "[");
|
||||
|
||||
const numTypes = types.length;
|
||||
for (let i = 0; i < numTypes; i++) {
|
||||
const type = types[i];
|
||||
const objectFlags = (type as any).objectFlags;
|
||||
const symbol = type.aliasSymbol ?? type.symbol;
|
||||
|
||||
// It's slow to compute the display text, so skip it unless it's really valuable (or cheap)
|
||||
let display: string | undefined;
|
||||
if ((objectFlags & ObjectFlags.Anonymous) | (type.flags & TypeFlags.Literal)) {
|
||||
try {
|
||||
display = type.checker?.typeToString(type);
|
||||
}
|
||||
catch {
|
||||
display = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
let indexedAccessProperties: object = {};
|
||||
if (type.flags & TypeFlags.IndexedAccess) {
|
||||
const indexedAccessType = type as IndexedAccessType;
|
||||
indexedAccessProperties = {
|
||||
indexedAccessObjectType: indexedAccessType.objectType?.id,
|
||||
indexedAccessIndexType: indexedAccessType.indexType?.id,
|
||||
};
|
||||
}
|
||||
|
||||
let referenceProperties: object = {};
|
||||
if (objectFlags & ObjectFlags.Reference) {
|
||||
const referenceType = type as TypeReference;
|
||||
referenceProperties = {
|
||||
instantiatedType: referenceType.target?.id,
|
||||
typeArguments: referenceType.resolvedTypeArguments?.map(t => t.id),
|
||||
referenceLocation: getLocation(referenceType.node),
|
||||
};
|
||||
}
|
||||
|
||||
let conditionalProperties: object = {};
|
||||
if (type.flags & TypeFlags.Conditional) {
|
||||
const conditionalType = type as ConditionalType;
|
||||
conditionalProperties = {
|
||||
conditionalCheckType: conditionalType.checkType?.id,
|
||||
conditionalExtendsType: conditionalType.extendsType?.id,
|
||||
conditionalTrueType: conditionalType.resolvedTrueType?.id ?? -1,
|
||||
conditionalFalseType: conditionalType.resolvedFalseType?.id ?? -1,
|
||||
};
|
||||
}
|
||||
|
||||
let substitutionProperties: object = {};
|
||||
if (type.flags & TypeFlags.Substitution) {
|
||||
const substitutionType = type as SubstitutionType;
|
||||
substitutionProperties = {
|
||||
substitutionBaseType: substitutionType.baseType?.id,
|
||||
constraintType: substitutionType.constraint?.id,
|
||||
};
|
||||
}
|
||||
|
||||
let reverseMappedProperties: object = {};
|
||||
if (objectFlags & ObjectFlags.ReverseMapped) {
|
||||
const reverseMappedType = type as ReverseMappedType;
|
||||
reverseMappedProperties = {
|
||||
reverseMappedSourceType: reverseMappedType.source?.id,
|
||||
reverseMappedMappedType: reverseMappedType.mappedType?.id,
|
||||
reverseMappedConstraintType: reverseMappedType.constraintType?.id,
|
||||
};
|
||||
}
|
||||
|
||||
let evolvingArrayProperties: object = {};
|
||||
if (objectFlags & ObjectFlags.EvolvingArray) {
|
||||
const evolvingArrayType = type as EvolvingArrayType;
|
||||
evolvingArrayProperties = {
|
||||
evolvingArrayElementType: evolvingArrayType.elementType.id,
|
||||
evolvingArrayFinalType: evolvingArrayType.finalArrayType?.id,
|
||||
};
|
||||
}
|
||||
|
||||
// We can't print out an arbitrary object, so just assign each one a unique number.
|
||||
// Don't call it an "id" so people don't treat it as a type id.
|
||||
let recursionToken: number | undefined;
|
||||
const recursionIdentity = type.checker.getRecursionIdentity(type);
|
||||
if (recursionIdentity) {
|
||||
recursionToken = recursionIdentityMap.get(recursionIdentity);
|
||||
if (!recursionToken) {
|
||||
recursionToken = recursionIdentityMap.size;
|
||||
recursionIdentityMap.set(recursionIdentity, recursionToken);
|
||||
}
|
||||
}
|
||||
|
||||
const descriptor = {
|
||||
id: type.id,
|
||||
intrinsicName: (type as any).intrinsicName,
|
||||
symbolName: symbol?.escapedName && unescapeLeadingUnderscores(symbol.escapedName),
|
||||
recursionId: recursionToken,
|
||||
isTuple: objectFlags & ObjectFlags.Tuple ? true : undefined,
|
||||
unionTypes: (type.flags & TypeFlags.Union) ? (type as UnionType).types?.map(t => t.id) : undefined,
|
||||
intersectionTypes: (type.flags & TypeFlags.Intersection) ? (type as IntersectionType).types.map(t => t.id) : undefined,
|
||||
aliasTypeArguments: type.aliasTypeArguments?.map(t => t.id),
|
||||
keyofType: (type.flags & TypeFlags.Index) ? (type as IndexType).type?.id : undefined,
|
||||
...indexedAccessProperties,
|
||||
...referenceProperties,
|
||||
...conditionalProperties,
|
||||
...substitutionProperties,
|
||||
...reverseMappedProperties,
|
||||
...evolvingArrayProperties,
|
||||
destructuringPattern: getLocation(type.pattern),
|
||||
firstDeclaration: getLocation(symbol?.declarations?.[0]),
|
||||
flags: Debug.formatTypeFlags(type.flags).split("|"),
|
||||
display,
|
||||
};
|
||||
|
||||
fs.writeSync(typesFd, JSON.stringify(descriptor));
|
||||
if (i < numTypes - 1) {
|
||||
fs.writeSync(typesFd, ",\n");
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeSync(typesFd, "]\n");
|
||||
|
||||
fs.closeSync(typesFd);
|
||||
|
||||
performance.mark("endDumpTypes");
|
||||
performance.measure("Dump types", "beginDumpTypes", "endDumpTypes");
|
||||
}
|
||||
|
||||
export function dumpLegend() {
|
||||
if (!legendPath) {
|
||||
return;
|
||||
}
|
||||
|
||||
fs.writeFileSync(legendPath, JSON.stringify(legend));
|
||||
}
|
||||
|
||||
interface TraceRecord {
|
||||
configFilePath?: string;
|
||||
tracePath: string;
|
||||
typesPath?: string;
|
||||
}
|
||||
}
|
||||
|
||||
// define after tracingEnabled is initialized
|
||||
/** @internal */
|
||||
export const startTracing = tracingEnabled.startTracing;
|
||||
/** @internal */
|
||||
export const dumpTracingLegend = tracingEnabled.dumpLegend;
|
||||
|
||||
/** @internal */
|
||||
export interface TracingNode {
|
||||
tracingPath?: Path;
|
||||
}
|
||||
|
||||
+613
-594
File diff suppressed because it is too large
Load Diff
+2361
-2323
File diff suppressed because it is too large
Load Diff
+1711
-1667
File diff suppressed because it is too large
Load Diff
@@ -1,80 +1,198 @@
|
||||
/* @internal */
|
||||
namespace ts {
|
||||
export type GetSymbolAccessibilityDiagnostic = (symbolAccessibilityResult: SymbolAccessibilityResult) => (SymbolAccessibilityDiagnostic | undefined);
|
||||
import {
|
||||
BindingElement, CallSignatureDeclaration, ConstructorDeclaration, ConstructSignatureDeclaration, Debug, Declaration,
|
||||
DeclarationName, DiagnosticMessage, Diagnostics, ExpressionWithTypeArguments, FunctionDeclaration,
|
||||
GetAccessorDeclaration, getNameOfDeclaration, hasSyntacticModifier, ImportEqualsDeclaration,
|
||||
IndexSignatureDeclaration, isBindingElement, isCallSignatureDeclaration, isClassDeclaration,
|
||||
isConstructorDeclaration, isConstructSignatureDeclaration, isExpressionWithTypeArguments, isFunctionDeclaration,
|
||||
isGetAccessor, isHeritageClause, isImportEqualsDeclaration, isIndexSignatureDeclaration, isJSDocTypeAlias,
|
||||
isMethodDeclaration, isMethodSignature, isParameter, isParameterPropertyDeclaration, isPropertyAccessExpression,
|
||||
isPropertyDeclaration, isPropertySignature, isSetAccessor, isStatic, isTypeAliasDeclaration,
|
||||
isTypeParameterDeclaration, isVariableDeclaration, JSDocCallbackTag, JSDocEnumTag, JSDocTypedefTag,
|
||||
MethodDeclaration, MethodSignature, ModifierFlags, NamedDeclaration, Node, ParameterDeclaration,
|
||||
PropertyAccessExpression, PropertyDeclaration, PropertySignature, QualifiedName, SetAccessorDeclaration,
|
||||
SymbolAccessibility, SymbolAccessibilityResult, SyntaxKind, TypeAliasDeclaration, TypeParameterDeclaration,
|
||||
VariableDeclaration,
|
||||
} from "../../_namespaces/ts";
|
||||
|
||||
export interface SymbolAccessibilityDiagnostic {
|
||||
errorNode: Node;
|
||||
diagnosticMessage: DiagnosticMessage;
|
||||
typeName?: DeclarationName | QualifiedName;
|
||||
/** @internal */
|
||||
export type GetSymbolAccessibilityDiagnostic = (symbolAccessibilityResult: SymbolAccessibilityResult) => (SymbolAccessibilityDiagnostic | undefined);
|
||||
|
||||
/** @internal */
|
||||
export interface SymbolAccessibilityDiagnostic {
|
||||
errorNode: Node;
|
||||
diagnosticMessage: DiagnosticMessage;
|
||||
typeName?: DeclarationName | QualifiedName;
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export type DeclarationDiagnosticProducing =
|
||||
| VariableDeclaration
|
||||
| PropertyDeclaration
|
||||
| PropertySignature
|
||||
| BindingElement
|
||||
| SetAccessorDeclaration
|
||||
| GetAccessorDeclaration
|
||||
| ConstructSignatureDeclaration
|
||||
| CallSignatureDeclaration
|
||||
| MethodDeclaration
|
||||
| MethodSignature
|
||||
| FunctionDeclaration
|
||||
| ParameterDeclaration
|
||||
| TypeParameterDeclaration
|
||||
| ExpressionWithTypeArguments
|
||||
| ImportEqualsDeclaration
|
||||
| TypeAliasDeclaration
|
||||
| ConstructorDeclaration
|
||||
| IndexSignatureDeclaration
|
||||
| PropertyAccessExpression
|
||||
| JSDocTypedefTag
|
||||
| JSDocCallbackTag
|
||||
| JSDocEnumTag;
|
||||
|
||||
/** @internal */
|
||||
export function canProduceDiagnostics(node: Node): node is DeclarationDiagnosticProducing {
|
||||
return isVariableDeclaration(node) ||
|
||||
isPropertyDeclaration(node) ||
|
||||
isPropertySignature(node) ||
|
||||
isBindingElement(node) ||
|
||||
isSetAccessor(node) ||
|
||||
isGetAccessor(node) ||
|
||||
isConstructSignatureDeclaration(node) ||
|
||||
isCallSignatureDeclaration(node) ||
|
||||
isMethodDeclaration(node) ||
|
||||
isMethodSignature(node) ||
|
||||
isFunctionDeclaration(node) ||
|
||||
isParameter(node) ||
|
||||
isTypeParameterDeclaration(node) ||
|
||||
isExpressionWithTypeArguments(node) ||
|
||||
isImportEqualsDeclaration(node) ||
|
||||
isTypeAliasDeclaration(node) ||
|
||||
isConstructorDeclaration(node) ||
|
||||
isIndexSignatureDeclaration(node) ||
|
||||
isPropertyAccessExpression(node) ||
|
||||
isJSDocTypeAlias(node);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function createGetSymbolAccessibilityDiagnosticForNodeName(node: DeclarationDiagnosticProducing) {
|
||||
if (isSetAccessor(node) || isGetAccessor(node)) {
|
||||
return getAccessorNameVisibilityError;
|
||||
}
|
||||
else if (isMethodSignature(node) || isMethodDeclaration(node)) {
|
||||
return getMethodNameVisibilityError;
|
||||
}
|
||||
else {
|
||||
return createGetSymbolAccessibilityDiagnosticForNode(node);
|
||||
}
|
||||
function getAccessorNameVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult) {
|
||||
const diagnosticMessage = getAccessorNameVisibilityDiagnosticMessage(symbolAccessibilityResult);
|
||||
return diagnosticMessage !== undefined ? {
|
||||
diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: (node as NamedDeclaration).name
|
||||
} : undefined;
|
||||
}
|
||||
|
||||
export type DeclarationDiagnosticProducing =
|
||||
| VariableDeclaration
|
||||
| PropertyDeclaration
|
||||
| PropertySignature
|
||||
| BindingElement
|
||||
| SetAccessorDeclaration
|
||||
| GetAccessorDeclaration
|
||||
| ConstructSignatureDeclaration
|
||||
| CallSignatureDeclaration
|
||||
| MethodDeclaration
|
||||
| MethodSignature
|
||||
| FunctionDeclaration
|
||||
| ParameterDeclaration
|
||||
| TypeParameterDeclaration
|
||||
| ExpressionWithTypeArguments
|
||||
| ImportEqualsDeclaration
|
||||
| TypeAliasDeclaration
|
||||
| ConstructorDeclaration
|
||||
| IndexSignatureDeclaration
|
||||
| PropertyAccessExpression
|
||||
| JSDocTypedefTag
|
||||
| JSDocCallbackTag
|
||||
| JSDocEnumTag;
|
||||
|
||||
export function canProduceDiagnostics(node: Node): node is DeclarationDiagnosticProducing {
|
||||
return isVariableDeclaration(node) ||
|
||||
isPropertyDeclaration(node) ||
|
||||
isPropertySignature(node) ||
|
||||
isBindingElement(node) ||
|
||||
isSetAccessor(node) ||
|
||||
isGetAccessor(node) ||
|
||||
isConstructSignatureDeclaration(node) ||
|
||||
isCallSignatureDeclaration(node) ||
|
||||
isMethodDeclaration(node) ||
|
||||
isMethodSignature(node) ||
|
||||
isFunctionDeclaration(node) ||
|
||||
isParameter(node) ||
|
||||
isTypeParameterDeclaration(node) ||
|
||||
isExpressionWithTypeArguments(node) ||
|
||||
isImportEqualsDeclaration(node) ||
|
||||
isTypeAliasDeclaration(node) ||
|
||||
isConstructorDeclaration(node) ||
|
||||
isIndexSignatureDeclaration(node) ||
|
||||
isPropertyAccessExpression(node) ||
|
||||
isJSDocTypeAlias(node);
|
||||
}
|
||||
|
||||
export function createGetSymbolAccessibilityDiagnosticForNodeName(node: DeclarationDiagnosticProducing) {
|
||||
if (isSetAccessor(node) || isGetAccessor(node)) {
|
||||
return getAccessorNameVisibilityError;
|
||||
function getAccessorNameVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult) {
|
||||
if (isStatic(node)) {
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else if (isMethodSignature(node) || isMethodDeclaration(node)) {
|
||||
return getMethodNameVisibilityError;
|
||||
else if (node.parent.kind === SyntaxKind.ClassDeclaration) {
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else {
|
||||
return createGetSymbolAccessibilityDiagnosticForNode(node);
|
||||
}
|
||||
function getAccessorNameVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult) {
|
||||
const diagnosticMessage = getAccessorNameVisibilityDiagnosticMessage(symbolAccessibilityResult);
|
||||
return diagnosticMessage !== undefined ? {
|
||||
diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: (node as NamedDeclaration).name
|
||||
} : undefined;
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1;
|
||||
}
|
||||
}
|
||||
|
||||
function getAccessorNameVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult) {
|
||||
function getMethodNameVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic | undefined {
|
||||
const diagnosticMessage = getMethodNameVisibilityDiagnosticMessage(symbolAccessibilityResult);
|
||||
return diagnosticMessage !== undefined ? {
|
||||
diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: (node as NamedDeclaration).name
|
||||
} : undefined;
|
||||
}
|
||||
|
||||
function getMethodNameVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult) {
|
||||
if (isStatic(node)) {
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else if (node.parent.kind === SyntaxKind.ClassDeclaration) {
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Public_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Public_method_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Public_method_0_of_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else {
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Method_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Method_0_of_exported_interface_has_or_is_using_private_name_1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationDiagnosticProducing): GetSymbolAccessibilityDiagnostic {
|
||||
if (isVariableDeclaration(node) || isPropertyDeclaration(node) || isPropertySignature(node) || isPropertyAccessExpression(node) || isBindingElement(node) || isConstructorDeclaration(node)) {
|
||||
return getVariableDeclarationTypeVisibilityError;
|
||||
}
|
||||
else if (isSetAccessor(node) || isGetAccessor(node)) {
|
||||
return getAccessorDeclarationTypeVisibilityError;
|
||||
}
|
||||
else if (isConstructSignatureDeclaration(node) || isCallSignatureDeclaration(node) || isMethodDeclaration(node) || isMethodSignature(node) || isFunctionDeclaration(node) || isIndexSignatureDeclaration(node)) {
|
||||
return getReturnTypeVisibilityError;
|
||||
}
|
||||
else if (isParameter(node)) {
|
||||
if (isParameterPropertyDeclaration(node, node.parent) && hasSyntacticModifier(node.parent, ModifierFlags.Private)) {
|
||||
return getVariableDeclarationTypeVisibilityError;
|
||||
}
|
||||
return getParameterDeclarationTypeVisibilityError;
|
||||
}
|
||||
else if (isTypeParameterDeclaration(node)) {
|
||||
return getTypeParameterConstraintVisibilityError;
|
||||
}
|
||||
else if (isExpressionWithTypeArguments(node)) {
|
||||
return getHeritageClauseVisibilityError;
|
||||
}
|
||||
else if (isImportEqualsDeclaration(node)) {
|
||||
return getImportEntityNameVisibilityError;
|
||||
}
|
||||
else if (isTypeAliasDeclaration(node) || isJSDocTypeAlias(node)) {
|
||||
return getTypeAliasDeclarationVisibilityError;
|
||||
}
|
||||
else {
|
||||
return Debug.assertNever(node, `Attempted to set a declaration diagnostic context for unhandled node kind: ${Debug.formatSyntaxKind((node as Node).kind)}`);
|
||||
}
|
||||
|
||||
function getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult) {
|
||||
if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) {
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Exported_variable_0_has_or_is_using_private_name_1;
|
||||
}
|
||||
// This check is to ensure we don't report error on constructor parameter property as that error would be reported during parameter emit
|
||||
// The only exception here is if the constructor was marked as private. we are not emitting the constructor parameters at all.
|
||||
else if (node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertyAccessExpression || node.kind === SyntaxKind.PropertySignature ||
|
||||
(node.kind === SyntaxKind.Parameter && hasSyntacticModifier(node.parent, ModifierFlags.Private))) {
|
||||
// TODO(jfreeman): Deal with computed properties in error reporting.
|
||||
if (isStatic(node)) {
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
@@ -82,7 +200,7 @@ namespace ts {
|
||||
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else if (node.parent.kind === SyntaxKind.ClassDeclaration) {
|
||||
else if (node.parent.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.Parameter) {
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
@@ -90,402 +208,303 @@ namespace ts {
|
||||
Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else {
|
||||
// Interfaces cannot have types that cannot be named
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1;
|
||||
}
|
||||
}
|
||||
|
||||
function getMethodNameVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic | undefined {
|
||||
const diagnosticMessage = getMethodNameVisibilityDiagnosticMessage(symbolAccessibilityResult);
|
||||
return diagnosticMessage !== undefined ? {
|
||||
diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: (node as NamedDeclaration).name
|
||||
} : undefined;
|
||||
}
|
||||
|
||||
function getMethodNameVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult) {
|
||||
if (isStatic(node)) {
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Public_static_method_0_of_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else if (node.parent.kind === SyntaxKind.ClassDeclaration) {
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Public_method_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Public_method_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Public_method_0_of_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else {
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Method_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Method_0_of_exported_interface_has_or_is_using_private_name_1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function createGetSymbolAccessibilityDiagnosticForNode(node: DeclarationDiagnosticProducing): GetSymbolAccessibilityDiagnostic {
|
||||
if (isVariableDeclaration(node) || isPropertyDeclaration(node) || isPropertySignature(node) || isPropertyAccessExpression(node) || isBindingElement(node) || isConstructorDeclaration(node)) {
|
||||
return getVariableDeclarationTypeVisibilityError;
|
||||
}
|
||||
else if (isSetAccessor(node) || isGetAccessor(node)) {
|
||||
return getAccessorDeclarationTypeVisibilityError;
|
||||
}
|
||||
else if (isConstructSignatureDeclaration(node) || isCallSignatureDeclaration(node) || isMethodDeclaration(node) || isMethodSignature(node) || isFunctionDeclaration(node) || isIndexSignatureDeclaration(node)) {
|
||||
return getReturnTypeVisibilityError;
|
||||
}
|
||||
else if (isParameter(node)) {
|
||||
if (isParameterPropertyDeclaration(node, node.parent) && hasSyntacticModifier(node.parent, ModifierFlags.Private)) {
|
||||
return getVariableDeclarationTypeVisibilityError;
|
||||
function getVariableDeclarationTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic | undefined {
|
||||
const diagnosticMessage = getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccessibilityResult);
|
||||
return diagnosticMessage !== undefined ? {
|
||||
diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: (node as NamedDeclaration).name
|
||||
} : undefined;
|
||||
}
|
||||
|
||||
function getAccessorDeclarationTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic {
|
||||
let diagnosticMessage: DiagnosticMessage;
|
||||
if (node.kind === SyntaxKind.SetAccessor) {
|
||||
// Getters can infer the return type from the returned expression, but setters cannot, so the
|
||||
// "_from_external_module_1_but_cannot_be_named" case cannot occur.
|
||||
if (isStatic(node)) {
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else {
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Parameter_type_of_public_setter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_type_of_public_setter_0_from_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
return getParameterDeclarationTypeVisibilityError;
|
||||
}
|
||||
else if (isTypeParameterDeclaration(node)) {
|
||||
return getTypeParameterConstraintVisibilityError;
|
||||
}
|
||||
else if (isExpressionWithTypeArguments(node)) {
|
||||
return getHeritageClauseVisibilityError;
|
||||
}
|
||||
else if (isImportEqualsDeclaration(node)) {
|
||||
return getImportEntityNameVisibilityError;
|
||||
}
|
||||
else if (isTypeAliasDeclaration(node) || isJSDocTypeAlias(node)) {
|
||||
return getTypeAliasDeclarationVisibilityError;
|
||||
}
|
||||
else {
|
||||
return Debug.assertNever(node, `Attempted to set a declaration diagnostic context for unhandled node kind: ${Debug.formatSyntaxKind((node as Node).kind)}`);
|
||||
if (isStatic(node)) {
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else {
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
}
|
||||
return {
|
||||
diagnosticMessage,
|
||||
errorNode: (node as NamedDeclaration).name!,
|
||||
typeName: (node as NamedDeclaration).name
|
||||
};
|
||||
}
|
||||
|
||||
function getReturnTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic {
|
||||
let diagnosticMessage: DiagnosticMessage;
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ConstructSignature:
|
||||
// Interfaces cannot have return types that cannot be named
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
|
||||
Diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_0;
|
||||
break;
|
||||
|
||||
case SyntaxKind.CallSignature:
|
||||
// Interfaces cannot have return types that cannot be named
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
|
||||
Diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_private_name_0;
|
||||
break;
|
||||
|
||||
case SyntaxKind.IndexSignature:
|
||||
// Interfaces cannot have return types that cannot be named
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
|
||||
Diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_private_name_0;
|
||||
break;
|
||||
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
if (isStatic(node)) {
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
|
||||
Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
|
||||
Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_name_0;
|
||||
}
|
||||
else if (node.parent.kind === SyntaxKind.ClassDeclaration) {
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
|
||||
Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
|
||||
Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_private_name_0;
|
||||
}
|
||||
else {
|
||||
// Interfaces cannot have return types that cannot be named
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
|
||||
Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_private_name_0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
|
||||
Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_private_module_1 :
|
||||
Diagnostics.Return_type_of_exported_function_has_or_is_using_private_name_0;
|
||||
break;
|
||||
|
||||
default:
|
||||
return Debug.fail("This is unknown kind for signature: " + node.kind);
|
||||
}
|
||||
|
||||
function getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult) {
|
||||
if (node.kind === SyntaxKind.VariableDeclaration || node.kind === SyntaxKind.BindingElement) {
|
||||
return {
|
||||
diagnosticMessage,
|
||||
errorNode: (node as NamedDeclaration).name || node
|
||||
};
|
||||
}
|
||||
|
||||
function getParameterDeclarationTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic | undefined {
|
||||
const diagnosticMessage: DiagnosticMessage = getParameterDeclarationTypeVisibilityDiagnosticMessage(symbolAccessibilityResult);
|
||||
return diagnosticMessage !== undefined ? {
|
||||
diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: (node as NamedDeclaration).name
|
||||
} : undefined;
|
||||
}
|
||||
|
||||
function getParameterDeclarationTypeVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult): DiagnosticMessage {
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Exported_variable_0_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Exported_variable_0_has_or_is_using_private_name_1;
|
||||
}
|
||||
// This check is to ensure we don't report error on constructor parameter property as that error would be reported during parameter emit
|
||||
// The only exception here is if the constructor was marked as private. we are not emitting the constructor parameters at all.
|
||||
else if (node.kind === SyntaxKind.PropertyDeclaration || node.kind === SyntaxKind.PropertyAccessExpression || node.kind === SyntaxKind.PropertySignature ||
|
||||
(node.kind === SyntaxKind.Parameter && hasSyntacticModifier(node.parent, ModifierFlags.Private))) {
|
||||
// TODO(jfreeman): Deal with computed properties in error reporting.
|
||||
if (isStatic(node)) {
|
||||
Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_name_1;
|
||||
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.ConstructorType:
|
||||
// Interfaces cannot have parameter types that cannot be named
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1;
|
||||
|
||||
case SyntaxKind.CallSignature:
|
||||
// Interfaces cannot have parameter types that cannot be named
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1;
|
||||
|
||||
case SyntaxKind.IndexSignature:
|
||||
// Interfaces cannot have parameter types that cannot be named
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Parameter_0_of_index_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_index_signature_from_exported_interface_has_or_is_using_private_name_1;
|
||||
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
if (isStatic(node.parent)) {
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Public_static_property_0_of_exported_class_has_or_is_using_private_name_1;
|
||||
Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else if (node.parent.kind === SyntaxKind.ClassDeclaration || node.kind === SyntaxKind.Parameter) {
|
||||
else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Public_property_0_of_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Public_property_0_of_exported_class_has_or_is_using_private_name_1;
|
||||
Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else {
|
||||
// Interfaces cannot have types that cannot be named
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Property_0_of_exported_interface_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Property_0_of_exported_interface_has_or_is_using_private_name_1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getVariableDeclarationTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic | undefined {
|
||||
const diagnosticMessage = getVariableDeclarationTypeVisibilityDiagnosticMessage(symbolAccessibilityResult);
|
||||
return diagnosticMessage !== undefined ? {
|
||||
diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: (node as NamedDeclaration).name
|
||||
} : undefined;
|
||||
}
|
||||
|
||||
function getAccessorDeclarationTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic {
|
||||
let diagnosticMessage: DiagnosticMessage;
|
||||
if (node.kind === SyntaxKind.SetAccessor) {
|
||||
// Getters can infer the return type from the returned expression, but setters cannot, so the
|
||||
// "_from_external_module_1_but_cannot_be_named" case cannot occur.
|
||||
if (isStatic(node)) {
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_type_of_public_static_setter_0_from_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else {
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Parameter_type_of_public_setter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_type_of_public_setter_0_from_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (isStatic(node)) {
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Return_type_of_public_static_getter_0_from_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else {
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Return_type_of_public_getter_0_from_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
}
|
||||
return {
|
||||
diagnosticMessage,
|
||||
errorNode: (node as NamedDeclaration).name!,
|
||||
typeName: (node as NamedDeclaration).name
|
||||
};
|
||||
}
|
||||
|
||||
function getReturnTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic {
|
||||
let diagnosticMessage: DiagnosticMessage;
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ConstructSignature:
|
||||
// Interfaces cannot have return types that cannot be named
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
|
||||
Diagnostics.Return_type_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_0;
|
||||
break;
|
||||
|
||||
case SyntaxKind.CallSignature:
|
||||
// Interfaces cannot have return types that cannot be named
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
|
||||
Diagnostics.Return_type_of_call_signature_from_exported_interface_has_or_is_using_private_name_0;
|
||||
break;
|
||||
|
||||
case SyntaxKind.IndexSignature:
|
||||
// Interfaces cannot have return types that cannot be named
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
|
||||
Diagnostics.Return_type_of_index_signature_from_exported_interface_has_or_is_using_private_name_0;
|
||||
break;
|
||||
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
if (isStatic(node)) {
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
|
||||
Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
|
||||
Diagnostics.Return_type_of_public_static_method_from_exported_class_has_or_is_using_private_name_0;
|
||||
}
|
||||
else if (node.parent.kind === SyntaxKind.ClassDeclaration) {
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
|
||||
Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_name_0_from_private_module_1 :
|
||||
Diagnostics.Return_type_of_public_method_from_exported_class_has_or_is_using_private_name_0;
|
||||
}
|
||||
else {
|
||||
// Interfaces cannot have return types that cannot be named
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_name_0_from_private_module_1 :
|
||||
Diagnostics.Return_type_of_method_from_exported_interface_has_or_is_using_private_name_0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
diagnosticMessage = symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_external_module_1_but_cannot_be_named :
|
||||
Diagnostics.Return_type_of_exported_function_has_or_is_using_name_0_from_private_module_1 :
|
||||
Diagnostics.Return_type_of_exported_function_has_or_is_using_private_name_0;
|
||||
break;
|
||||
|
||||
default:
|
||||
return Debug.fail("This is unknown kind for signature: " + node.kind);
|
||||
}
|
||||
|
||||
return {
|
||||
diagnosticMessage,
|
||||
errorNode: (node as NamedDeclaration).name || node
|
||||
};
|
||||
}
|
||||
|
||||
function getParameterDeclarationTypeVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic | undefined {
|
||||
const diagnosticMessage: DiagnosticMessage = getParameterDeclarationTypeVisibilityDiagnosticMessage(symbolAccessibilityResult);
|
||||
return diagnosticMessage !== undefined ? {
|
||||
diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: (node as NamedDeclaration).name
|
||||
} : undefined;
|
||||
}
|
||||
|
||||
function getParameterDeclarationTypeVisibilityDiagnosticMessage(symbolAccessibilityResult: SymbolAccessibilityResult): DiagnosticMessage {
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.Constructor:
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_constructor_from_exported_class_has_or_is_using_private_name_1;
|
||||
|
||||
case SyntaxKind.ConstructSignature:
|
||||
case SyntaxKind.ConstructorType:
|
||||
// Interfaces cannot have parameter types that cannot be named
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1;
|
||||
Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1;
|
||||
}
|
||||
|
||||
case SyntaxKind.CallSignature:
|
||||
// Interfaces cannot have parameter types that cannot be named
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1;
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionType:
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_exported_function_has_or_is_using_private_name_1;
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.GetAccessor:
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Parameter_0_of_accessor_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Parameter_0_of_accessor_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_accessor_has_or_is_using_private_name_1;
|
||||
|
||||
case SyntaxKind.IndexSignature:
|
||||
// Interfaces cannot have parameter types that cannot be named
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Parameter_0_of_index_signature_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_index_signature_from_exported_interface_has_or_is_using_private_name_1;
|
||||
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
if (isStatic(node.parent)) {
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else {
|
||||
// Interfaces cannot have parameter types that cannot be named
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1;
|
||||
}
|
||||
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
case SyntaxKind.FunctionType:
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Parameter_0_of_exported_function_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_exported_function_has_or_is_using_private_name_1;
|
||||
case SyntaxKind.SetAccessor:
|
||||
case SyntaxKind.GetAccessor:
|
||||
return symbolAccessibilityResult.errorModuleName ?
|
||||
symbolAccessibilityResult.accessibility === SymbolAccessibility.CannotBeNamed ?
|
||||
Diagnostics.Parameter_0_of_accessor_has_or_is_using_name_1_from_external_module_2_but_cannot_be_named :
|
||||
Diagnostics.Parameter_0_of_accessor_has_or_is_using_name_1_from_private_module_2 :
|
||||
Diagnostics.Parameter_0_of_accessor_has_or_is_using_private_name_1;
|
||||
|
||||
default:
|
||||
return Debug.fail(`Unknown parent for parameter: ${Debug.formatSyntaxKind(node.parent.kind)}`);
|
||||
}
|
||||
}
|
||||
|
||||
function getTypeParameterConstraintVisibilityError(): SymbolAccessibilityDiagnostic {
|
||||
// Type parameter constraints are named by user so we should always be able to name it
|
||||
let diagnosticMessage: DiagnosticMessage;
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_class_has_or_is_using_private_name_1;
|
||||
break;
|
||||
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1;
|
||||
break;
|
||||
|
||||
case SyntaxKind.MappedType:
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_mapped_object_type_is_using_private_name_1;
|
||||
break;
|
||||
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1;
|
||||
break;
|
||||
|
||||
case SyntaxKind.CallSignature:
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1;
|
||||
break;
|
||||
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
if (isStatic(node.parent)) {
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else {
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1;
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_function_has_or_is_using_private_name_1;
|
||||
break;
|
||||
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_type_alias_has_or_is_using_private_name_1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return Debug.fail("This is unknown parent for type parameter: " + node.parent.kind);
|
||||
}
|
||||
|
||||
return {
|
||||
diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: (node as NamedDeclaration).name
|
||||
};
|
||||
}
|
||||
|
||||
function getHeritageClauseVisibilityError(): SymbolAccessibilityDiagnostic {
|
||||
let diagnosticMessage: DiagnosticMessage;
|
||||
// Heritage clause is written by user so it can always be named
|
||||
if (isClassDeclaration(node.parent.parent)) {
|
||||
// Class or Interface implemented/extended is inaccessible
|
||||
diagnosticMessage = isHeritageClause(node.parent) && node.parent.token === SyntaxKind.ImplementsKeyword ?
|
||||
Diagnostics.Implements_clause_of_exported_class_0_has_or_is_using_private_name_1 :
|
||||
node.parent.parent.name ? Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1 :
|
||||
Diagnostics.extends_clause_of_exported_class_has_or_is_using_private_name_0;
|
||||
}
|
||||
else {
|
||||
// interface is inaccessible
|
||||
diagnosticMessage = Diagnostics.extends_clause_of_exported_interface_0_has_or_is_using_private_name_1;
|
||||
}
|
||||
|
||||
return {
|
||||
diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: getNameOfDeclaration(node.parent.parent as Declaration)
|
||||
};
|
||||
}
|
||||
|
||||
function getImportEntityNameVisibilityError(): SymbolAccessibilityDiagnostic {
|
||||
return {
|
||||
diagnosticMessage: Diagnostics.Import_declaration_0_is_using_private_name_1,
|
||||
errorNode: node,
|
||||
typeName: (node as NamedDeclaration).name
|
||||
};
|
||||
}
|
||||
|
||||
function getTypeAliasDeclarationVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic {
|
||||
return {
|
||||
diagnosticMessage: symbolAccessibilityResult.errorModuleName
|
||||
? Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1_from_module_2
|
||||
: Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1,
|
||||
errorNode: isJSDocTypeAlias(node) ? Debug.checkDefined(node.typeExpression) : (node as TypeAliasDeclaration).type,
|
||||
typeName: isJSDocTypeAlias(node) ? getNameOfDeclaration(node) : (node as TypeAliasDeclaration).name,
|
||||
};
|
||||
default:
|
||||
return Debug.fail(`Unknown parent for parameter: ${Debug.formatSyntaxKind(node.parent.kind)}`);
|
||||
}
|
||||
}
|
||||
|
||||
function getTypeParameterConstraintVisibilityError(): SymbolAccessibilityDiagnostic {
|
||||
// Type parameter constraints are named by user so we should always be able to name it
|
||||
let diagnosticMessage: DiagnosticMessage;
|
||||
switch (node.parent.kind) {
|
||||
case SyntaxKind.ClassDeclaration:
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_class_has_or_is_using_private_name_1;
|
||||
break;
|
||||
|
||||
case SyntaxKind.InterfaceDeclaration:
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_interface_has_or_is_using_private_name_1;
|
||||
break;
|
||||
|
||||
case SyntaxKind.MappedType:
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_mapped_object_type_is_using_private_name_1;
|
||||
break;
|
||||
|
||||
case SyntaxKind.ConstructorType:
|
||||
case SyntaxKind.ConstructSignature:
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_constructor_signature_from_exported_interface_has_or_is_using_private_name_1;
|
||||
break;
|
||||
|
||||
case SyntaxKind.CallSignature:
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_call_signature_from_exported_interface_has_or_is_using_private_name_1;
|
||||
break;
|
||||
|
||||
case SyntaxKind.MethodDeclaration:
|
||||
case SyntaxKind.MethodSignature:
|
||||
if (isStatic(node.parent)) {
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_public_static_method_from_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else if (node.parent.parent.kind === SyntaxKind.ClassDeclaration) {
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_public_method_from_exported_class_has_or_is_using_private_name_1;
|
||||
}
|
||||
else {
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_method_from_exported_interface_has_or_is_using_private_name_1;
|
||||
}
|
||||
break;
|
||||
|
||||
case SyntaxKind.FunctionType:
|
||||
case SyntaxKind.FunctionDeclaration:
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_function_has_or_is_using_private_name_1;
|
||||
break;
|
||||
|
||||
case SyntaxKind.TypeAliasDeclaration:
|
||||
diagnosticMessage = Diagnostics.Type_parameter_0_of_exported_type_alias_has_or_is_using_private_name_1;
|
||||
break;
|
||||
|
||||
default:
|
||||
return Debug.fail("This is unknown parent for type parameter: " + node.parent.kind);
|
||||
}
|
||||
|
||||
return {
|
||||
diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: (node as NamedDeclaration).name
|
||||
};
|
||||
}
|
||||
|
||||
function getHeritageClauseVisibilityError(): SymbolAccessibilityDiagnostic {
|
||||
let diagnosticMessage: DiagnosticMessage;
|
||||
// Heritage clause is written by user so it can always be named
|
||||
if (isClassDeclaration(node.parent.parent)) {
|
||||
// Class or Interface implemented/extended is inaccessible
|
||||
diagnosticMessage = isHeritageClause(node.parent) && node.parent.token === SyntaxKind.ImplementsKeyword ?
|
||||
Diagnostics.Implements_clause_of_exported_class_0_has_or_is_using_private_name_1 :
|
||||
node.parent.parent.name ? Diagnostics.extends_clause_of_exported_class_0_has_or_is_using_private_name_1 :
|
||||
Diagnostics.extends_clause_of_exported_class_has_or_is_using_private_name_0;
|
||||
}
|
||||
else {
|
||||
// interface is inaccessible
|
||||
diagnosticMessage = Diagnostics.extends_clause_of_exported_interface_0_has_or_is_using_private_name_1;
|
||||
}
|
||||
|
||||
return {
|
||||
diagnosticMessage,
|
||||
errorNode: node,
|
||||
typeName: getNameOfDeclaration(node.parent.parent as Declaration)
|
||||
};
|
||||
}
|
||||
|
||||
function getImportEntityNameVisibilityError(): SymbolAccessibilityDiagnostic {
|
||||
return {
|
||||
diagnosticMessage: Diagnostics.Import_declaration_0_is_using_private_name_1,
|
||||
errorNode: node,
|
||||
typeName: (node as NamedDeclaration).name
|
||||
};
|
||||
}
|
||||
|
||||
function getTypeAliasDeclarationVisibilityError(symbolAccessibilityResult: SymbolAccessibilityResult): SymbolAccessibilityDiagnostic {
|
||||
return {
|
||||
diagnosticMessage: symbolAccessibilityResult.errorModuleName
|
||||
? Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1_from_module_2
|
||||
: Diagnostics.Exported_type_alias_0_has_or_is_using_private_name_1,
|
||||
errorNode: isJSDocTypeAlias(node) ? Debug.checkDefined(node.typeExpression) : (node as TypeAliasDeclaration).type,
|
||||
typeName: isJSDocTypeAlias(node) ? getNameOfDeclaration(node) : (node as TypeAliasDeclaration).name,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+4233
-4197
File diff suppressed because it is too large
Load Diff
@@ -1,105 +1,109 @@
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
export function transformES2016(context: TransformationContext) {
|
||||
const {
|
||||
factory,
|
||||
hoistVariableDeclaration
|
||||
} = context;
|
||||
import {
|
||||
BinaryExpression, Bundle, chainBundle, Expression, isElementAccessExpression, isExpression, isPropertyAccessExpression,
|
||||
Node, setTextRange, SourceFile, SyntaxKind, TransformationContext, TransformFlags, visitEachChild, visitNode,
|
||||
VisitResult,
|
||||
} from "../_namespaces/ts";
|
||||
|
||||
return chainBundle(context, transformSourceFile);
|
||||
/** @internal */
|
||||
export function transformES2016(context: TransformationContext): (x: SourceFile | Bundle) => SourceFile | Bundle {
|
||||
const {
|
||||
factory,
|
||||
hoistVariableDeclaration
|
||||
} = context;
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
if (node.isDeclarationFile) {
|
||||
return node;
|
||||
}
|
||||
return chainBundle(context, transformSourceFile);
|
||||
|
||||
return visitEachChild(node, visitor, context);
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
if (node.isDeclarationFile) {
|
||||
return node;
|
||||
}
|
||||
|
||||
function visitor(node: Node): VisitResult<Node> {
|
||||
if ((node.transformFlags & TransformFlags.ContainsES2016) === 0) {
|
||||
return node;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.BinaryExpression:
|
||||
return visitBinaryExpression(node as BinaryExpression);
|
||||
default:
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitBinaryExpression(node: BinaryExpression): Expression {
|
||||
switch (node.operatorToken.kind) {
|
||||
case SyntaxKind.AsteriskAsteriskEqualsToken:
|
||||
return visitExponentiationAssignmentExpression(node);
|
||||
case SyntaxKind.AsteriskAsteriskToken:
|
||||
return visitExponentiationExpression(node);
|
||||
default:
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
function visitor(node: Node): VisitResult<Node> {
|
||||
if ((node.transformFlags & TransformFlags.ContainsES2016) === 0) {
|
||||
return node;
|
||||
}
|
||||
|
||||
function visitExponentiationAssignmentExpression(node: BinaryExpression) {
|
||||
let target: Expression;
|
||||
let value: Expression;
|
||||
const left = visitNode(node.left, visitor, isExpression);
|
||||
const right = visitNode(node.right, visitor, isExpression);
|
||||
if (isElementAccessExpression(left)) {
|
||||
// Transforms `a[x] **= b` into `(_a = a)[_x = x] = Math.pow(_a[_x], b)`
|
||||
const expressionTemp = factory.createTempVariable(hoistVariableDeclaration);
|
||||
const argumentExpressionTemp = factory.createTempVariable(hoistVariableDeclaration);
|
||||
target = setTextRange(
|
||||
factory.createElementAccessExpression(
|
||||
setTextRange(factory.createAssignment(expressionTemp, left.expression), left.expression),
|
||||
setTextRange(factory.createAssignment(argumentExpressionTemp, left.argumentExpression), left.argumentExpression)
|
||||
),
|
||||
left
|
||||
);
|
||||
value = setTextRange(
|
||||
factory.createElementAccessExpression(
|
||||
expressionTemp,
|
||||
argumentExpressionTemp
|
||||
),
|
||||
left
|
||||
);
|
||||
}
|
||||
else if (isPropertyAccessExpression(left)) {
|
||||
// Transforms `a.x **= b` into `(_a = a).x = Math.pow(_a.x, b)`
|
||||
const expressionTemp = factory.createTempVariable(hoistVariableDeclaration);
|
||||
target = setTextRange(
|
||||
factory.createPropertyAccessExpression(
|
||||
setTextRange(factory.createAssignment(expressionTemp, left.expression), left.expression),
|
||||
left.name
|
||||
),
|
||||
left
|
||||
);
|
||||
value = setTextRange(
|
||||
factory.createPropertyAccessExpression(
|
||||
expressionTemp,
|
||||
left.name
|
||||
),
|
||||
left
|
||||
);
|
||||
}
|
||||
else {
|
||||
// Transforms `a **= b` into `a = Math.pow(a, b)`
|
||||
target = left;
|
||||
value = left;
|
||||
}
|
||||
return setTextRange(
|
||||
factory.createAssignment(
|
||||
target,
|
||||
setTextRange(factory.createGlobalMethodCall("Math", "pow", [value, right]), node)
|
||||
),
|
||||
node
|
||||
);
|
||||
}
|
||||
|
||||
function visitExponentiationExpression(node: BinaryExpression) {
|
||||
// Transforms `a ** b` into `Math.pow(a, b)`
|
||||
const left = visitNode(node.left, visitor, isExpression);
|
||||
const right = visitNode(node.right, visitor, isExpression);
|
||||
return setTextRange(factory.createGlobalMethodCall("Math", "pow", [left, right]), node);
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.BinaryExpression:
|
||||
return visitBinaryExpression(node as BinaryExpression);
|
||||
default:
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
}
|
||||
|
||||
function visitBinaryExpression(node: BinaryExpression): Expression {
|
||||
switch (node.operatorToken.kind) {
|
||||
case SyntaxKind.AsteriskAsteriskEqualsToken:
|
||||
return visitExponentiationAssignmentExpression(node);
|
||||
case SyntaxKind.AsteriskAsteriskToken:
|
||||
return visitExponentiationExpression(node);
|
||||
default:
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
}
|
||||
|
||||
function visitExponentiationAssignmentExpression(node: BinaryExpression) {
|
||||
let target: Expression;
|
||||
let value: Expression;
|
||||
const left = visitNode(node.left, visitor, isExpression);
|
||||
const right = visitNode(node.right, visitor, isExpression);
|
||||
if (isElementAccessExpression(left)) {
|
||||
// Transforms `a[x] **= b` into `(_a = a)[_x = x] = Math.pow(_a[_x], b)`
|
||||
const expressionTemp = factory.createTempVariable(hoistVariableDeclaration);
|
||||
const argumentExpressionTemp = factory.createTempVariable(hoistVariableDeclaration);
|
||||
target = setTextRange(
|
||||
factory.createElementAccessExpression(
|
||||
setTextRange(factory.createAssignment(expressionTemp, left.expression), left.expression),
|
||||
setTextRange(factory.createAssignment(argumentExpressionTemp, left.argumentExpression), left.argumentExpression)
|
||||
),
|
||||
left
|
||||
);
|
||||
value = setTextRange(
|
||||
factory.createElementAccessExpression(
|
||||
expressionTemp,
|
||||
argumentExpressionTemp
|
||||
),
|
||||
left
|
||||
);
|
||||
}
|
||||
else if (isPropertyAccessExpression(left)) {
|
||||
// Transforms `a.x **= b` into `(_a = a).x = Math.pow(_a.x, b)`
|
||||
const expressionTemp = factory.createTempVariable(hoistVariableDeclaration);
|
||||
target = setTextRange(
|
||||
factory.createPropertyAccessExpression(
|
||||
setTextRange(factory.createAssignment(expressionTemp, left.expression), left.expression),
|
||||
left.name
|
||||
),
|
||||
left
|
||||
);
|
||||
value = setTextRange(
|
||||
factory.createPropertyAccessExpression(
|
||||
expressionTemp,
|
||||
left.name
|
||||
),
|
||||
left
|
||||
);
|
||||
}
|
||||
else {
|
||||
// Transforms `a **= b` into `a = Math.pow(a, b)`
|
||||
target = left;
|
||||
value = left;
|
||||
}
|
||||
return setTextRange(
|
||||
factory.createAssignment(
|
||||
target,
|
||||
setTextRange(factory.createGlobalMethodCall("Math", "pow", [value, right]), node)
|
||||
),
|
||||
node
|
||||
);
|
||||
}
|
||||
|
||||
function visitExponentiationExpression(node: BinaryExpression) {
|
||||
// Transforms `a ** b` into `Math.pow(a, b)`
|
||||
const left = visitNode(node.left, visitor, isExpression);
|
||||
const right = visitNode(node.right, visitor, isExpression);
|
||||
return setTextRange(factory.createGlobalMethodCall("Math", "pow", [left, right]), node);
|
||||
}
|
||||
}
|
||||
|
||||
+830
-809
File diff suppressed because it is too large
Load Diff
+1246
-1226
File diff suppressed because it is too large
Load Diff
@@ -1,38 +1,42 @@
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
export function transformES2019(context: TransformationContext) {
|
||||
const factory = context.factory;
|
||||
return chainBundle(context, transformSourceFile);
|
||||
import {
|
||||
Bundle,
|
||||
CatchClause, chainBundle, isBlock, Node, SourceFile, SyntaxKind, TransformationContext, TransformFlags,
|
||||
visitEachChild, visitNode, VisitResult,
|
||||
} from "../_namespaces/ts";
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
if (node.isDeclarationFile) {
|
||||
return node;
|
||||
}
|
||||
/** @internal */
|
||||
export function transformES2019(context: TransformationContext): (x: SourceFile | Bundle) => SourceFile | Bundle {
|
||||
const factory = context.factory;
|
||||
return chainBundle(context, transformSourceFile);
|
||||
|
||||
return visitEachChild(node, visitor, context);
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
if (node.isDeclarationFile) {
|
||||
return node;
|
||||
}
|
||||
|
||||
function visitor(node: Node): VisitResult<Node> {
|
||||
if ((node.transformFlags & TransformFlags.ContainsES2019) === 0) {
|
||||
return node;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.CatchClause:
|
||||
return visitCatchClause(node as CatchClause);
|
||||
default:
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitCatchClause(node: CatchClause): CatchClause {
|
||||
if (!node.variableDeclaration) {
|
||||
return factory.updateCatchClause(
|
||||
node,
|
||||
factory.createVariableDeclaration(factory.createTempVariable(/*recordTempVariable*/ undefined)),
|
||||
visitNode(node.block, visitor, isBlock)
|
||||
);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
function visitor(node: Node): VisitResult<Node> {
|
||||
if ((node.transformFlags & TransformFlags.ContainsES2019) === 0) {
|
||||
return node;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.CatchClause:
|
||||
return visitCatchClause(node as CatchClause);
|
||||
default:
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
}
|
||||
|
||||
function visitCatchClause(node: CatchClause): CatchClause {
|
||||
if (!node.variableDeclaration) {
|
||||
return factory.updateCatchClause(
|
||||
node,
|
||||
factory.createVariableDeclaration(factory.createTempVariable(/*recordTempVariable*/ undefined)),
|
||||
visitNode(node.block, visitor, isBlock)
|
||||
);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
}
|
||||
|
||||
+216
-209
@@ -1,222 +1,229 @@
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
export function transformES2020(context: TransformationContext) {
|
||||
const {
|
||||
factory,
|
||||
hoistVariableDeclaration,
|
||||
} = context;
|
||||
import {
|
||||
AccessExpression, addEmitFlags, BinaryExpression, Bundle, CallExpression, cast, chainBundle, Debug, DeleteExpression,
|
||||
EmitFlags, Expression, isCallChain, isExpression, isGeneratedIdentifier, isIdentifier, isNonNullChain,
|
||||
isOptionalChain, isParenthesizedExpression, isSimpleCopiableExpression, isSyntheticReference,
|
||||
isTaggedTemplateExpression, Node, OptionalChain, OuterExpressionKinds, ParenthesizedExpression, setOriginalNode,
|
||||
setTextRange, skipParentheses, skipPartiallyEmittedExpressions, SourceFile, SyntaxKind, TransformationContext,
|
||||
TransformFlags, visitEachChild, visitNode, visitNodes, VisitResult,
|
||||
} from "../_namespaces/ts";
|
||||
|
||||
return chainBundle(context, transformSourceFile);
|
||||
/** @internal */
|
||||
export function transformES2020(context: TransformationContext): (x: SourceFile | Bundle) => SourceFile | Bundle {
|
||||
const {
|
||||
factory,
|
||||
hoistVariableDeclaration,
|
||||
} = context;
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
if (node.isDeclarationFile) {
|
||||
return node;
|
||||
}
|
||||
return chainBundle(context, transformSourceFile);
|
||||
|
||||
return visitEachChild(node, visitor, context);
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
if (node.isDeclarationFile) {
|
||||
return node;
|
||||
}
|
||||
|
||||
function visitor(node: Node): VisitResult<Node> {
|
||||
if ((node.transformFlags & TransformFlags.ContainsES2020) === 0) {
|
||||
return node;
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitor(node: Node): VisitResult<Node> {
|
||||
if ((node.transformFlags & TransformFlags.ContainsES2020) === 0) {
|
||||
return node;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.CallExpression: {
|
||||
const updated = visitNonOptionalCallExpression(node as CallExpression, /*captureThisArg*/ false);
|
||||
Debug.assertNotNode(updated, isSyntheticReference);
|
||||
return updated;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.CallExpression: {
|
||||
const updated = visitNonOptionalCallExpression(node as CallExpression, /*captureThisArg*/ false);
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
if (isOptionalChain(node)) {
|
||||
const updated = visitOptionalExpression(node, /*captureThisArg*/ false, /*isDelete*/ false);
|
||||
Debug.assertNotNode(updated, isSyntheticReference);
|
||||
return updated;
|
||||
}
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
if (isOptionalChain(node)) {
|
||||
const updated = visitOptionalExpression(node, /*captureThisArg*/ false, /*isDelete*/ false);
|
||||
Debug.assertNotNode(updated, isSyntheticReference);
|
||||
return updated;
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
case SyntaxKind.BinaryExpression:
|
||||
if ((node as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken) {
|
||||
return transformNullishCoalescingExpression(node as BinaryExpression);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
case SyntaxKind.DeleteExpression:
|
||||
return visitDeleteExpression(node as DeleteExpression);
|
||||
default:
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
}
|
||||
|
||||
function flattenChain(chain: OptionalChain) {
|
||||
Debug.assertNotNode(chain, isNonNullChain);
|
||||
const links: OptionalChain[] = [chain];
|
||||
while (!chain.questionDotToken && !isTaggedTemplateExpression(chain)) {
|
||||
chain = cast(skipPartiallyEmittedExpressions(chain.expression), isOptionalChain);
|
||||
Debug.assertNotNode(chain, isNonNullChain);
|
||||
links.unshift(chain);
|
||||
}
|
||||
return { expression: chain.expression, chain: links };
|
||||
}
|
||||
|
||||
function visitNonOptionalParenthesizedExpression(node: ParenthesizedExpression, captureThisArg: boolean, isDelete: boolean): Expression {
|
||||
const expression = visitNonOptionalExpression(node.expression, captureThisArg, isDelete);
|
||||
if (isSyntheticReference(expression)) {
|
||||
// `(a.b)` -> { expression `((_a = a).b)`, thisArg: `_a` }
|
||||
// `(a[b])` -> { expression `((_a = a)[b])`, thisArg: `_a` }
|
||||
return factory.createSyntheticReferenceExpression(factory.updateParenthesizedExpression(node, expression.expression), expression.thisArg);
|
||||
}
|
||||
return factory.updateParenthesizedExpression(node, expression);
|
||||
}
|
||||
|
||||
function visitNonOptionalPropertyOrElementAccessExpression(node: AccessExpression, captureThisArg: boolean, isDelete: boolean): Expression {
|
||||
if (isOptionalChain(node)) {
|
||||
// If `node` is an optional chain, then it is the outermost chain of an optional expression.
|
||||
return visitOptionalExpression(node, captureThisArg, isDelete);
|
||||
}
|
||||
|
||||
let expression: Expression = visitNode(node.expression, visitor, isExpression);
|
||||
Debug.assertNotNode(expression, isSyntheticReference);
|
||||
|
||||
let thisArg: Expression | undefined;
|
||||
if (captureThisArg) {
|
||||
if (!isSimpleCopiableExpression(expression)) {
|
||||
thisArg = factory.createTempVariable(hoistVariableDeclaration);
|
||||
expression = factory.createAssignment(thisArg, expression);
|
||||
return visitEachChild(node, visitor, context);
|
||||
case SyntaxKind.BinaryExpression:
|
||||
if ((node as BinaryExpression).operatorToken.kind === SyntaxKind.QuestionQuestionToken) {
|
||||
return transformNullishCoalescingExpression(node as BinaryExpression);
|
||||
}
|
||||
else {
|
||||
thisArg = expression;
|
||||
}
|
||||
}
|
||||
|
||||
expression = node.kind === SyntaxKind.PropertyAccessExpression
|
||||
? factory.updatePropertyAccessExpression(node, expression, visitNode(node.name, visitor, isIdentifier))
|
||||
: factory.updateElementAccessExpression(node, expression, visitNode(node.argumentExpression, visitor, isExpression));
|
||||
return thisArg ? factory.createSyntheticReferenceExpression(expression, thisArg) : expression;
|
||||
}
|
||||
|
||||
function visitNonOptionalCallExpression(node: CallExpression, captureThisArg: boolean): Expression {
|
||||
if (isOptionalChain(node)) {
|
||||
// If `node` is an optional chain, then it is the outermost chain of an optional expression.
|
||||
return visitOptionalExpression(node, captureThisArg, /*isDelete*/ false);
|
||||
}
|
||||
if (isParenthesizedExpression(node.expression) && isOptionalChain(skipParentheses(node.expression))) {
|
||||
// capture thisArg for calls of parenthesized optional chains like `(foo?.bar)()`
|
||||
const expression = visitNonOptionalParenthesizedExpression(node.expression, /*captureThisArg*/ true, /*isDelete*/ false);
|
||||
const args = visitNodes(node.arguments, visitor, isExpression);
|
||||
if (isSyntheticReference(expression)) {
|
||||
return setTextRange(factory.createFunctionCallCall(expression.expression, expression.thisArg, args), node);
|
||||
}
|
||||
return factory.updateCallExpression(node, expression, /*typeArguments*/ undefined, args);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitNonOptionalExpression(node: Expression, captureThisArg: boolean, isDelete: boolean): Expression {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ParenthesizedExpression: return visitNonOptionalParenthesizedExpression(node as ParenthesizedExpression, captureThisArg, isDelete);
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ElementAccessExpression: return visitNonOptionalPropertyOrElementAccessExpression(node as AccessExpression, captureThisArg, isDelete);
|
||||
case SyntaxKind.CallExpression: return visitNonOptionalCallExpression(node as CallExpression, captureThisArg);
|
||||
default: return visitNode(node, visitor, isExpression);
|
||||
}
|
||||
}
|
||||
|
||||
function visitOptionalExpression(node: OptionalChain, captureThisArg: boolean, isDelete: boolean): Expression {
|
||||
const { expression, chain } = flattenChain(node);
|
||||
const left = visitNonOptionalExpression(skipPartiallyEmittedExpressions(expression), isCallChain(chain[0]), /*isDelete*/ false);
|
||||
let leftThisArg = isSyntheticReference(left) ? left.thisArg : undefined;
|
||||
let capturedLeft = isSyntheticReference(left) ? left.expression : left;
|
||||
let leftExpression = factory.restoreOuterExpressions(expression, capturedLeft, OuterExpressionKinds.PartiallyEmittedExpressions);
|
||||
if (!isSimpleCopiableExpression(capturedLeft)) {
|
||||
capturedLeft = factory.createTempVariable(hoistVariableDeclaration);
|
||||
leftExpression = factory.createAssignment(capturedLeft, leftExpression);
|
||||
}
|
||||
let rightExpression = capturedLeft;
|
||||
let thisArg: Expression | undefined;
|
||||
for (let i = 0; i < chain.length; i++) {
|
||||
const segment = chain[i];
|
||||
switch (segment.kind) {
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
if (i === chain.length - 1 && captureThisArg) {
|
||||
if (!isSimpleCopiableExpression(rightExpression)) {
|
||||
thisArg = factory.createTempVariable(hoistVariableDeclaration);
|
||||
rightExpression = factory.createAssignment(thisArg, rightExpression);
|
||||
}
|
||||
else {
|
||||
thisArg = rightExpression;
|
||||
}
|
||||
}
|
||||
rightExpression = segment.kind === SyntaxKind.PropertyAccessExpression
|
||||
? factory.createPropertyAccessExpression(rightExpression, visitNode(segment.name, visitor, isIdentifier))
|
||||
: factory.createElementAccessExpression(rightExpression, visitNode(segment.argumentExpression, visitor, isExpression));
|
||||
break;
|
||||
case SyntaxKind.CallExpression:
|
||||
if (i === 0 && leftThisArg) {
|
||||
if (!isGeneratedIdentifier(leftThisArg)) {
|
||||
leftThisArg = factory.cloneNode(leftThisArg);
|
||||
addEmitFlags(leftThisArg, EmitFlags.NoComments);
|
||||
}
|
||||
rightExpression = factory.createFunctionCallCall(
|
||||
rightExpression,
|
||||
leftThisArg.kind === SyntaxKind.SuperKeyword ? factory.createThis() : leftThisArg,
|
||||
visitNodes(segment.arguments, visitor, isExpression)
|
||||
);
|
||||
}
|
||||
else {
|
||||
rightExpression = factory.createCallExpression(
|
||||
rightExpression,
|
||||
/*typeArguments*/ undefined,
|
||||
visitNodes(segment.arguments, visitor, isExpression)
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
setOriginalNode(rightExpression, segment);
|
||||
}
|
||||
|
||||
const target = isDelete
|
||||
? factory.createConditionalExpression(createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true), /*questionToken*/ undefined, factory.createTrue(), /*colonToken*/ undefined, factory.createDeleteExpression(rightExpression))
|
||||
: factory.createConditionalExpression(createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true), /*questionToken*/ undefined, factory.createVoidZero(), /*colonToken*/ undefined, rightExpression);
|
||||
setTextRange(target, node);
|
||||
return thisArg ? factory.createSyntheticReferenceExpression(target, thisArg) : target;
|
||||
}
|
||||
|
||||
function createNotNullCondition(left: Expression, right: Expression, invert?: boolean) {
|
||||
return factory.createBinaryExpression(
|
||||
factory.createBinaryExpression(
|
||||
left,
|
||||
factory.createToken(invert ? SyntaxKind.EqualsEqualsEqualsToken : SyntaxKind.ExclamationEqualsEqualsToken),
|
||||
factory.createNull()
|
||||
),
|
||||
factory.createToken(invert ? SyntaxKind.BarBarToken : SyntaxKind.AmpersandAmpersandToken),
|
||||
factory.createBinaryExpression(
|
||||
right,
|
||||
factory.createToken(invert ? SyntaxKind.EqualsEqualsEqualsToken : SyntaxKind.ExclamationEqualsEqualsToken),
|
||||
factory.createVoidZero()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function transformNullishCoalescingExpression(node: BinaryExpression) {
|
||||
let left = visitNode(node.left, visitor, isExpression);
|
||||
let right = left;
|
||||
if (!isSimpleCopiableExpression(left)) {
|
||||
right = factory.createTempVariable(hoistVariableDeclaration);
|
||||
left = factory.createAssignment(right, left);
|
||||
}
|
||||
return setTextRange(factory.createConditionalExpression(
|
||||
createNotNullCondition(left, right),
|
||||
/*questionToken*/ undefined,
|
||||
right,
|
||||
/*colonToken*/ undefined,
|
||||
visitNode(node.right, visitor, isExpression),
|
||||
), node);
|
||||
}
|
||||
|
||||
function visitDeleteExpression(node: DeleteExpression) {
|
||||
return isOptionalChain(skipParentheses(node.expression))
|
||||
? setOriginalNode(visitNonOptionalExpression(node.expression, /*captureThisArg*/ false, /*isDelete*/ true), node)
|
||||
: factory.updateDeleteExpression(node, visitNode(node.expression, visitor, isExpression));
|
||||
return visitEachChild(node, visitor, context);
|
||||
case SyntaxKind.DeleteExpression:
|
||||
return visitDeleteExpression(node as DeleteExpression);
|
||||
default:
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
}
|
||||
|
||||
function flattenChain(chain: OptionalChain) {
|
||||
Debug.assertNotNode(chain, isNonNullChain);
|
||||
const links: OptionalChain[] = [chain];
|
||||
while (!chain.questionDotToken && !isTaggedTemplateExpression(chain)) {
|
||||
chain = cast(skipPartiallyEmittedExpressions(chain.expression), isOptionalChain);
|
||||
Debug.assertNotNode(chain, isNonNullChain);
|
||||
links.unshift(chain);
|
||||
}
|
||||
return { expression: chain.expression, chain: links };
|
||||
}
|
||||
|
||||
function visitNonOptionalParenthesizedExpression(node: ParenthesizedExpression, captureThisArg: boolean, isDelete: boolean): Expression {
|
||||
const expression = visitNonOptionalExpression(node.expression, captureThisArg, isDelete);
|
||||
if (isSyntheticReference(expression)) {
|
||||
// `(a.b)` -> { expression `((_a = a).b)`, thisArg: `_a` }
|
||||
// `(a[b])` -> { expression `((_a = a)[b])`, thisArg: `_a` }
|
||||
return factory.createSyntheticReferenceExpression(factory.updateParenthesizedExpression(node, expression.expression), expression.thisArg);
|
||||
}
|
||||
return factory.updateParenthesizedExpression(node, expression);
|
||||
}
|
||||
|
||||
function visitNonOptionalPropertyOrElementAccessExpression(node: AccessExpression, captureThisArg: boolean, isDelete: boolean): Expression {
|
||||
if (isOptionalChain(node)) {
|
||||
// If `node` is an optional chain, then it is the outermost chain of an optional expression.
|
||||
return visitOptionalExpression(node, captureThisArg, isDelete);
|
||||
}
|
||||
|
||||
let expression: Expression = visitNode(node.expression, visitor, isExpression);
|
||||
Debug.assertNotNode(expression, isSyntheticReference);
|
||||
|
||||
let thisArg: Expression | undefined;
|
||||
if (captureThisArg) {
|
||||
if (!isSimpleCopiableExpression(expression)) {
|
||||
thisArg = factory.createTempVariable(hoistVariableDeclaration);
|
||||
expression = factory.createAssignment(thisArg, expression);
|
||||
}
|
||||
else {
|
||||
thisArg = expression;
|
||||
}
|
||||
}
|
||||
|
||||
expression = node.kind === SyntaxKind.PropertyAccessExpression
|
||||
? factory.updatePropertyAccessExpression(node, expression, visitNode(node.name, visitor, isIdentifier))
|
||||
: factory.updateElementAccessExpression(node, expression, visitNode(node.argumentExpression, visitor, isExpression));
|
||||
return thisArg ? factory.createSyntheticReferenceExpression(expression, thisArg) : expression;
|
||||
}
|
||||
|
||||
function visitNonOptionalCallExpression(node: CallExpression, captureThisArg: boolean): Expression {
|
||||
if (isOptionalChain(node)) {
|
||||
// If `node` is an optional chain, then it is the outermost chain of an optional expression.
|
||||
return visitOptionalExpression(node, captureThisArg, /*isDelete*/ false);
|
||||
}
|
||||
if (isParenthesizedExpression(node.expression) && isOptionalChain(skipParentheses(node.expression))) {
|
||||
// capture thisArg for calls of parenthesized optional chains like `(foo?.bar)()`
|
||||
const expression = visitNonOptionalParenthesizedExpression(node.expression, /*captureThisArg*/ true, /*isDelete*/ false);
|
||||
const args = visitNodes(node.arguments, visitor, isExpression);
|
||||
if (isSyntheticReference(expression)) {
|
||||
return setTextRange(factory.createFunctionCallCall(expression.expression, expression.thisArg, args), node);
|
||||
}
|
||||
return factory.updateCallExpression(node, expression, /*typeArguments*/ undefined, args);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitNonOptionalExpression(node: Expression, captureThisArg: boolean, isDelete: boolean): Expression {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.ParenthesizedExpression: return visitNonOptionalParenthesizedExpression(node as ParenthesizedExpression, captureThisArg, isDelete);
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ElementAccessExpression: return visitNonOptionalPropertyOrElementAccessExpression(node as AccessExpression, captureThisArg, isDelete);
|
||||
case SyntaxKind.CallExpression: return visitNonOptionalCallExpression(node as CallExpression, captureThisArg);
|
||||
default: return visitNode(node, visitor, isExpression);
|
||||
}
|
||||
}
|
||||
|
||||
function visitOptionalExpression(node: OptionalChain, captureThisArg: boolean, isDelete: boolean): Expression {
|
||||
const { expression, chain } = flattenChain(node);
|
||||
const left = visitNonOptionalExpression(skipPartiallyEmittedExpressions(expression), isCallChain(chain[0]), /*isDelete*/ false);
|
||||
let leftThisArg = isSyntheticReference(left) ? left.thisArg : undefined;
|
||||
let capturedLeft = isSyntheticReference(left) ? left.expression : left;
|
||||
let leftExpression = factory.restoreOuterExpressions(expression, capturedLeft, OuterExpressionKinds.PartiallyEmittedExpressions);
|
||||
if (!isSimpleCopiableExpression(capturedLeft)) {
|
||||
capturedLeft = factory.createTempVariable(hoistVariableDeclaration);
|
||||
leftExpression = factory.createAssignment(capturedLeft, leftExpression);
|
||||
}
|
||||
let rightExpression = capturedLeft;
|
||||
let thisArg: Expression | undefined;
|
||||
for (let i = 0; i < chain.length; i++) {
|
||||
const segment = chain[i];
|
||||
switch (segment.kind) {
|
||||
case SyntaxKind.PropertyAccessExpression:
|
||||
case SyntaxKind.ElementAccessExpression:
|
||||
if (i === chain.length - 1 && captureThisArg) {
|
||||
if (!isSimpleCopiableExpression(rightExpression)) {
|
||||
thisArg = factory.createTempVariable(hoistVariableDeclaration);
|
||||
rightExpression = factory.createAssignment(thisArg, rightExpression);
|
||||
}
|
||||
else {
|
||||
thisArg = rightExpression;
|
||||
}
|
||||
}
|
||||
rightExpression = segment.kind === SyntaxKind.PropertyAccessExpression
|
||||
? factory.createPropertyAccessExpression(rightExpression, visitNode(segment.name, visitor, isIdentifier))
|
||||
: factory.createElementAccessExpression(rightExpression, visitNode(segment.argumentExpression, visitor, isExpression));
|
||||
break;
|
||||
case SyntaxKind.CallExpression:
|
||||
if (i === 0 && leftThisArg) {
|
||||
if (!isGeneratedIdentifier(leftThisArg)) {
|
||||
leftThisArg = factory.cloneNode(leftThisArg);
|
||||
addEmitFlags(leftThisArg, EmitFlags.NoComments);
|
||||
}
|
||||
rightExpression = factory.createFunctionCallCall(
|
||||
rightExpression,
|
||||
leftThisArg.kind === SyntaxKind.SuperKeyword ? factory.createThis() : leftThisArg,
|
||||
visitNodes(segment.arguments, visitor, isExpression)
|
||||
);
|
||||
}
|
||||
else {
|
||||
rightExpression = factory.createCallExpression(
|
||||
rightExpression,
|
||||
/*typeArguments*/ undefined,
|
||||
visitNodes(segment.arguments, visitor, isExpression)
|
||||
);
|
||||
}
|
||||
break;
|
||||
}
|
||||
setOriginalNode(rightExpression, segment);
|
||||
}
|
||||
|
||||
const target = isDelete
|
||||
? factory.createConditionalExpression(createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true), /*questionToken*/ undefined, factory.createTrue(), /*colonToken*/ undefined, factory.createDeleteExpression(rightExpression))
|
||||
: factory.createConditionalExpression(createNotNullCondition(leftExpression, capturedLeft, /*invert*/ true), /*questionToken*/ undefined, factory.createVoidZero(), /*colonToken*/ undefined, rightExpression);
|
||||
setTextRange(target, node);
|
||||
return thisArg ? factory.createSyntheticReferenceExpression(target, thisArg) : target;
|
||||
}
|
||||
|
||||
function createNotNullCondition(left: Expression, right: Expression, invert?: boolean) {
|
||||
return factory.createBinaryExpression(
|
||||
factory.createBinaryExpression(
|
||||
left,
|
||||
factory.createToken(invert ? SyntaxKind.EqualsEqualsEqualsToken : SyntaxKind.ExclamationEqualsEqualsToken),
|
||||
factory.createNull()
|
||||
),
|
||||
factory.createToken(invert ? SyntaxKind.BarBarToken : SyntaxKind.AmpersandAmpersandToken),
|
||||
factory.createBinaryExpression(
|
||||
right,
|
||||
factory.createToken(invert ? SyntaxKind.EqualsEqualsEqualsToken : SyntaxKind.ExclamationEqualsEqualsToken),
|
||||
factory.createVoidZero()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function transformNullishCoalescingExpression(node: BinaryExpression) {
|
||||
let left = visitNode(node.left, visitor, isExpression);
|
||||
let right = left;
|
||||
if (!isSimpleCopiableExpression(left)) {
|
||||
right = factory.createTempVariable(hoistVariableDeclaration);
|
||||
left = factory.createAssignment(right, left);
|
||||
}
|
||||
return setTextRange(factory.createConditionalExpression(
|
||||
createNotNullCondition(left, right),
|
||||
/*questionToken*/ undefined,
|
||||
right,
|
||||
/*colonToken*/ undefined,
|
||||
visitNode(node.right, visitor, isExpression),
|
||||
), node);
|
||||
}
|
||||
|
||||
function visitDeleteExpression(node: DeleteExpression) {
|
||||
return isOptionalChain(skipParentheses(node.expression))
|
||||
? setOriginalNode(visitNonOptionalExpression(node.expression, /*captureThisArg*/ false, /*isDelete*/ true), node)
|
||||
: factory.updateDeleteExpression(node, visitNode(node.expression, visitor, isExpression));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,91 +1,97 @@
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
export function transformES2021(context: TransformationContext) {
|
||||
const {
|
||||
hoistVariableDeclaration,
|
||||
factory
|
||||
} = context;
|
||||
return chainBundle(context, transformSourceFile);
|
||||
import {
|
||||
AssignmentExpression, BinaryExpression, Bundle, chainBundle, getNonAssignmentOperatorForCompoundAssignment,
|
||||
isAccessExpression, isExpression, isLeftHandSideExpression, isLogicalOrCoalescingAssignmentExpression,
|
||||
isPropertyAccessExpression, isSimpleCopiableExpression, LogicalOrCoalescingAssignmentOperator, Node,
|
||||
skipParentheses, SourceFile, SyntaxKind, Token, TransformationContext, TransformFlags, visitEachChild, visitNode,
|
||||
VisitResult,
|
||||
} from "../_namespaces/ts";
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
if (node.isDeclarationFile) {
|
||||
return node;
|
||||
}
|
||||
/** @internal */
|
||||
export function transformES2021(context: TransformationContext): (x: SourceFile | Bundle) => SourceFile | Bundle {
|
||||
const {
|
||||
hoistVariableDeclaration,
|
||||
factory
|
||||
} = context;
|
||||
return chainBundle(context, transformSourceFile);
|
||||
|
||||
return visitEachChild(node, visitor, context);
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
if (node.isDeclarationFile) {
|
||||
return node;
|
||||
}
|
||||
|
||||
function visitor(node: Node): VisitResult<Node> {
|
||||
if ((node.transformFlags & TransformFlags.ContainsES2021) === 0) {
|
||||
return node;
|
||||
}
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.BinaryExpression:
|
||||
const binaryExpression = node as BinaryExpression;
|
||||
if (isLogicalOrCoalescingAssignmentExpression(binaryExpression)) {
|
||||
return transformLogicalAssignment(binaryExpression);
|
||||
}
|
||||
// falls through
|
||||
default:
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitor(node: Node): VisitResult<Node> {
|
||||
if ((node.transformFlags & TransformFlags.ContainsES2021) === 0) {
|
||||
return node;
|
||||
}
|
||||
|
||||
function transformLogicalAssignment(binaryExpression: AssignmentExpression<Token<LogicalOrCoalescingAssignmentOperator>>): VisitResult<Node> {
|
||||
const operator = binaryExpression.operatorToken;
|
||||
const nonAssignmentOperator = getNonAssignmentOperatorForCompoundAssignment(operator.kind);
|
||||
let left = skipParentheses(visitNode(binaryExpression.left, visitor, isLeftHandSideExpression));
|
||||
let assignmentTarget = left;
|
||||
const right = skipParentheses(visitNode(binaryExpression.right, visitor, isExpression));
|
||||
|
||||
if (isAccessExpression(left)) {
|
||||
const propertyAccessTargetSimpleCopiable = isSimpleCopiableExpression(left.expression);
|
||||
const propertyAccessTarget = propertyAccessTargetSimpleCopiable ? left.expression :
|
||||
factory.createTempVariable(hoistVariableDeclaration);
|
||||
const propertyAccessTargetAssignment = propertyAccessTargetSimpleCopiable ? left.expression : factory.createAssignment(
|
||||
propertyAccessTarget,
|
||||
left.expression
|
||||
);
|
||||
|
||||
if (isPropertyAccessExpression(left)) {
|
||||
assignmentTarget = factory.createPropertyAccessExpression(
|
||||
propertyAccessTarget,
|
||||
left.name
|
||||
);
|
||||
left = factory.createPropertyAccessExpression(
|
||||
propertyAccessTargetAssignment,
|
||||
left.name
|
||||
);
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.BinaryExpression:
|
||||
const binaryExpression = node as BinaryExpression;
|
||||
if (isLogicalOrCoalescingAssignmentExpression(binaryExpression)) {
|
||||
return transformLogicalAssignment(binaryExpression);
|
||||
}
|
||||
else {
|
||||
const elementAccessArgumentSimpleCopiable = isSimpleCopiableExpression(left.argumentExpression);
|
||||
const elementAccessArgument = elementAccessArgumentSimpleCopiable ? left.argumentExpression :
|
||||
factory.createTempVariable(hoistVariableDeclaration);
|
||||
|
||||
assignmentTarget = factory.createElementAccessExpression(
|
||||
propertyAccessTarget,
|
||||
elementAccessArgument
|
||||
);
|
||||
left = factory.createElementAccessExpression(
|
||||
propertyAccessTargetAssignment,
|
||||
elementAccessArgumentSimpleCopiable ? left.argumentExpression : factory.createAssignment(
|
||||
elementAccessArgument,
|
||||
left.argumentExpression
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return factory.createBinaryExpression(
|
||||
left,
|
||||
nonAssignmentOperator,
|
||||
factory.createParenthesizedExpression(
|
||||
factory.createAssignment(
|
||||
assignmentTarget,
|
||||
right
|
||||
)
|
||||
)
|
||||
);
|
||||
// falls through
|
||||
default:
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
}
|
||||
|
||||
function transformLogicalAssignment(binaryExpression: AssignmentExpression<Token<LogicalOrCoalescingAssignmentOperator>>): VisitResult<Node> {
|
||||
const operator = binaryExpression.operatorToken;
|
||||
const nonAssignmentOperator = getNonAssignmentOperatorForCompoundAssignment(operator.kind);
|
||||
let left = skipParentheses(visitNode(binaryExpression.left, visitor, isLeftHandSideExpression));
|
||||
let assignmentTarget = left;
|
||||
const right = skipParentheses(visitNode(binaryExpression.right, visitor, isExpression));
|
||||
|
||||
if (isAccessExpression(left)) {
|
||||
const propertyAccessTargetSimpleCopiable = isSimpleCopiableExpression(left.expression);
|
||||
const propertyAccessTarget = propertyAccessTargetSimpleCopiable ? left.expression :
|
||||
factory.createTempVariable(hoistVariableDeclaration);
|
||||
const propertyAccessTargetAssignment = propertyAccessTargetSimpleCopiable ? left.expression : factory.createAssignment(
|
||||
propertyAccessTarget,
|
||||
left.expression
|
||||
);
|
||||
|
||||
if (isPropertyAccessExpression(left)) {
|
||||
assignmentTarget = factory.createPropertyAccessExpression(
|
||||
propertyAccessTarget,
|
||||
left.name
|
||||
);
|
||||
left = factory.createPropertyAccessExpression(
|
||||
propertyAccessTargetAssignment,
|
||||
left.name
|
||||
);
|
||||
}
|
||||
else {
|
||||
const elementAccessArgumentSimpleCopiable = isSimpleCopiableExpression(left.argumentExpression);
|
||||
const elementAccessArgument = elementAccessArgumentSimpleCopiable ? left.argumentExpression :
|
||||
factory.createTempVariable(hoistVariableDeclaration);
|
||||
|
||||
assignmentTarget = factory.createElementAccessExpression(
|
||||
propertyAccessTarget,
|
||||
elementAccessArgument
|
||||
);
|
||||
left = factory.createElementAccessExpression(
|
||||
propertyAccessTargetAssignment,
|
||||
elementAccessArgumentSimpleCopiable ? left.argumentExpression : factory.createAssignment(
|
||||
elementAccessArgument,
|
||||
left.argumentExpression
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return factory.createBinaryExpression(
|
||||
left,
|
||||
nonAssignmentOperator,
|
||||
factory.createParenthesizedExpression(
|
||||
factory.createAssignment(
|
||||
assignmentTarget,
|
||||
right
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
+113
-106
@@ -1,122 +1,129 @@
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
import {
|
||||
Bundle,
|
||||
chainBundle, EmitHint, Expression, getOriginalNodeId, Identifier, idText, isIdentifier, isPrivateIdentifier,
|
||||
isPropertyAccessExpression, isPropertyAssignment, JsxClosingElement, JsxEmit, JsxOpeningElement,
|
||||
JsxSelfClosingElement, Node, nodeIsSynthesized, PropertyAccessExpression, PropertyAssignment, setTextRange,
|
||||
SourceFile, stringToToken, SyntaxKind, TransformationContext,
|
||||
} from "../_namespaces/ts";
|
||||
|
||||
/**
|
||||
* Transforms ES5 syntax into ES3 syntax.
|
||||
*
|
||||
* @param context Context and state information for the transformation.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
export function transformES5(context: TransformationContext): (x: SourceFile | Bundle) => SourceFile | Bundle {
|
||||
const { factory } = context;
|
||||
const compilerOptions = context.getCompilerOptions();
|
||||
|
||||
// enable emit notification only if using --jsx preserve or react-native
|
||||
let previousOnEmitNode: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
|
||||
let noSubstitution: boolean[];
|
||||
if (compilerOptions.jsx === JsxEmit.Preserve || compilerOptions.jsx === JsxEmit.ReactNative) {
|
||||
previousOnEmitNode = context.onEmitNode;
|
||||
context.onEmitNode = onEmitNode;
|
||||
context.enableEmitNotification(SyntaxKind.JsxOpeningElement);
|
||||
context.enableEmitNotification(SyntaxKind.JsxClosingElement);
|
||||
context.enableEmitNotification(SyntaxKind.JsxSelfClosingElement);
|
||||
noSubstitution = [];
|
||||
}
|
||||
|
||||
const previousOnSubstituteNode = context.onSubstituteNode;
|
||||
context.onSubstituteNode = onSubstituteNode;
|
||||
context.enableSubstitution(SyntaxKind.PropertyAccessExpression);
|
||||
context.enableSubstitution(SyntaxKind.PropertyAssignment);
|
||||
return chainBundle(context, transformSourceFile);
|
||||
|
||||
/**
|
||||
* Transforms ES5 syntax into ES3 syntax.
|
||||
* Transforms an ES5 source file to ES3.
|
||||
*
|
||||
* @param context Context and state information for the transformation.
|
||||
* @param node A SourceFile
|
||||
*/
|
||||
export function transformES5(context: TransformationContext) {
|
||||
const { factory } = context;
|
||||
const compilerOptions = context.getCompilerOptions();
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
return node;
|
||||
}
|
||||
|
||||
// enable emit notification only if using --jsx preserve or react-native
|
||||
let previousOnEmitNode: (hint: EmitHint, node: Node, emitCallback: (hint: EmitHint, node: Node) => void) => void;
|
||||
let noSubstitution: boolean[];
|
||||
if (compilerOptions.jsx === JsxEmit.Preserve || compilerOptions.jsx === JsxEmit.ReactNative) {
|
||||
previousOnEmitNode = context.onEmitNode;
|
||||
context.onEmitNode = onEmitNode;
|
||||
context.enableEmitNotification(SyntaxKind.JsxOpeningElement);
|
||||
context.enableEmitNotification(SyntaxKind.JsxClosingElement);
|
||||
context.enableEmitNotification(SyntaxKind.JsxSelfClosingElement);
|
||||
noSubstitution = [];
|
||||
/**
|
||||
* Called by the printer just before a node is printed.
|
||||
*
|
||||
* @param hint A hint as to the intended usage of the node.
|
||||
* @param node The node to emit.
|
||||
* @param emitCallback A callback used to emit the node.
|
||||
*/
|
||||
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (emitContext: EmitHint, node: Node) => void) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.JsxOpeningElement:
|
||||
case SyntaxKind.JsxClosingElement:
|
||||
case SyntaxKind.JsxSelfClosingElement:
|
||||
const tagName = (node as JsxOpeningElement | JsxClosingElement | JsxSelfClosingElement).tagName;
|
||||
noSubstitution[getOriginalNodeId(tagName)] = true;
|
||||
break;
|
||||
}
|
||||
|
||||
const previousOnSubstituteNode = context.onSubstituteNode;
|
||||
context.onSubstituteNode = onSubstituteNode;
|
||||
context.enableSubstitution(SyntaxKind.PropertyAccessExpression);
|
||||
context.enableSubstitution(SyntaxKind.PropertyAssignment);
|
||||
return chainBundle(context, transformSourceFile);
|
||||
previousOnEmitNode(hint, node, emitCallback);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms an ES5 source file to ES3.
|
||||
*
|
||||
* @param node A SourceFile
|
||||
*/
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
/**
|
||||
* Hooks node substitutions.
|
||||
*
|
||||
* @param hint A hint as to the intended usage of the node.
|
||||
* @param node The node to substitute.
|
||||
*/
|
||||
function onSubstituteNode(hint: EmitHint, node: Node) {
|
||||
if (node.id && noSubstitution && noSubstitution[node.id]) {
|
||||
return previousOnSubstituteNode(hint, node);
|
||||
}
|
||||
|
||||
node = previousOnSubstituteNode(hint, node);
|
||||
if (isPropertyAccessExpression(node)) {
|
||||
return substitutePropertyAccessExpression(node);
|
||||
}
|
||||
else if (isPropertyAssignment(node)) {
|
||||
return substitutePropertyAssignment(node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes a PropertyAccessExpression whose name is a reserved word.
|
||||
*
|
||||
* @param node A PropertyAccessExpression
|
||||
*/
|
||||
function substitutePropertyAccessExpression(node: PropertyAccessExpression): Expression {
|
||||
if (isPrivateIdentifier(node.name)) {
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called by the printer just before a node is printed.
|
||||
*
|
||||
* @param hint A hint as to the intended usage of the node.
|
||||
* @param node The node to emit.
|
||||
* @param emitCallback A callback used to emit the node.
|
||||
*/
|
||||
function onEmitNode(hint: EmitHint, node: Node, emitCallback: (emitContext: EmitHint, node: Node) => void) {
|
||||
switch (node.kind) {
|
||||
case SyntaxKind.JsxOpeningElement:
|
||||
case SyntaxKind.JsxClosingElement:
|
||||
case SyntaxKind.JsxSelfClosingElement:
|
||||
const tagName = (node as JsxOpeningElement | JsxClosingElement | JsxSelfClosingElement).tagName;
|
||||
noSubstitution[getOriginalNodeId(tagName)] = true;
|
||||
break;
|
||||
}
|
||||
|
||||
previousOnEmitNode(hint, node, emitCallback);
|
||||
const literalName = trySubstituteReservedName(node.name);
|
||||
if (literalName) {
|
||||
return setTextRange(factory.createElementAccessExpression(node.expression, literalName), node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooks node substitutions.
|
||||
*
|
||||
* @param hint A hint as to the intended usage of the node.
|
||||
* @param node The node to substitute.
|
||||
*/
|
||||
function onSubstituteNode(hint: EmitHint, node: Node) {
|
||||
if (node.id && noSubstitution && noSubstitution[node.id]) {
|
||||
return previousOnSubstituteNode(hint, node);
|
||||
}
|
||||
|
||||
node = previousOnSubstituteNode(hint, node);
|
||||
if (isPropertyAccessExpression(node)) {
|
||||
return substitutePropertyAccessExpression(node);
|
||||
}
|
||||
else if (isPropertyAssignment(node)) {
|
||||
return substitutePropertyAssignment(node);
|
||||
}
|
||||
return node;
|
||||
/**
|
||||
* Substitutes a PropertyAssignment whose name is a reserved word.
|
||||
*
|
||||
* @param node A PropertyAssignment
|
||||
*/
|
||||
function substitutePropertyAssignment(node: PropertyAssignment): PropertyAssignment {
|
||||
const literalName = isIdentifier(node.name) && trySubstituteReservedName(node.name);
|
||||
if (literalName) {
|
||||
return factory.updatePropertyAssignment(node, literalName, node.initializer);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes a PropertyAccessExpression whose name is a reserved word.
|
||||
*
|
||||
* @param node A PropertyAccessExpression
|
||||
*/
|
||||
function substitutePropertyAccessExpression(node: PropertyAccessExpression): Expression {
|
||||
if (isPrivateIdentifier(node.name)) {
|
||||
return node;
|
||||
}
|
||||
const literalName = trySubstituteReservedName(node.name);
|
||||
if (literalName) {
|
||||
return setTextRange(factory.createElementAccessExpression(node.expression, literalName), node);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* Substitutes a PropertyAssignment whose name is a reserved word.
|
||||
*
|
||||
* @param node A PropertyAssignment
|
||||
*/
|
||||
function substitutePropertyAssignment(node: PropertyAssignment): PropertyAssignment {
|
||||
const literalName = isIdentifier(node.name) && trySubstituteReservedName(node.name);
|
||||
if (literalName) {
|
||||
return factory.updatePropertyAssignment(node, literalName, node.initializer);
|
||||
}
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
* If an identifier name is a reserved word, returns a string literal for the name.
|
||||
*
|
||||
* @param name An Identifier
|
||||
*/
|
||||
function trySubstituteReservedName(name: Identifier) {
|
||||
const token = name.originalKeywordKind || (nodeIsSynthesized(name) ? stringToToken(idText(name)) : undefined);
|
||||
if (token !== undefined && token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord) {
|
||||
return setTextRange(factory.createStringLiteralFromNode(name), name);
|
||||
}
|
||||
return undefined;
|
||||
/**
|
||||
* If an identifier name is a reserved word, returns a string literal for the name.
|
||||
*
|
||||
* @param name An Identifier
|
||||
*/
|
||||
function trySubstituteReservedName(name: Identifier) {
|
||||
const token = name.originalKeywordKind || (nodeIsSynthesized(name) ? stringToToken(idText(name)) : undefined);
|
||||
if (token !== undefined && token >= SyntaxKind.FirstReservedWord && token <= SyntaxKind.LastReservedWord) {
|
||||
return setTextRange(factory.createStringLiteralFromNode(name), name);
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,27 @@
|
||||
/*@internal*/
|
||||
namespace ts {
|
||||
export function transformESNext(context: TransformationContext) {
|
||||
return chainBundle(context, transformSourceFile);
|
||||
import {
|
||||
Bundle,
|
||||
chainBundle, Node, SourceFile, TransformationContext, TransformFlags, visitEachChild, VisitResult,
|
||||
} from "../_namespaces/ts";
|
||||
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
if (node.isDeclarationFile) {
|
||||
return node;
|
||||
}
|
||||
/** @internal */
|
||||
export function transformESNext(context: TransformationContext): (x: SourceFile | Bundle) => SourceFile | Bundle {
|
||||
return chainBundle(context, transformSourceFile);
|
||||
|
||||
return visitEachChild(node, visitor, context);
|
||||
function transformSourceFile(node: SourceFile) {
|
||||
if (node.isDeclarationFile) {
|
||||
return node;
|
||||
}
|
||||
|
||||
function visitor(node: Node): VisitResult<Node> {
|
||||
if ((node.transformFlags & TransformFlags.ContainsESNext) === 0) {
|
||||
return node;
|
||||
}
|
||||
switch (node.kind) {
|
||||
default:
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
|
||||
function visitor(node: Node): VisitResult<Node> {
|
||||
if ((node.transformFlags & TransformFlags.ContainsESNext) === 0) {
|
||||
return node;
|
||||
}
|
||||
switch (node.kind) {
|
||||
default:
|
||||
return visitEachChild(node, visitor, context);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user