diff --git a/.github/workflows/alpha-publish.yml b/.github/workflows/alpha-publish.yml new file mode 100644 index 0000000..dda2ff5 --- /dev/null +++ b/.github/workflows/alpha-publish.yml @@ -0,0 +1,45 @@ +name: publish + +on: + push: + branches: + - alpha +env: + REPOSITORY_PATH: https://${{secrets.ACCESS_TOKEN}}@github.com/ + # GITHUB_TOKEN: ${{secrets.ACCESS_TOKEN}} +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: init + run: | + git config --global user.name "${GITHUB_ACTOR}" + git config --global user.email "${GITHUB_ACTOR}@gmail.com" + - name: pull-code + uses: actions/checkout@v2 + - name: install-node + uses: actions/setup-node@v1 + with: + node-version: 20.x + - name: install-dependencies + run: | + yarn + - name: test + run: | + yarn test + - name: build + run: | + yarn build + - id: publish + name: publish + uses: JS-DevTools/npm-publish@v3.1 + with: + token: ${{ secrets.NPM_PUBLISH_TOKEN }} + package: ./dist/package.json + tag: alpha + - if: steps.publish.outputs.old-version != steps.publish.outputs.version + run: | + echo "[${{ steps.publish.outputs.type }}]Version changed: ${{ steps.publish.outputs.old-version }} => ${{ steps.publish.outputs.version }}" + git tag v${{steps.publish.outputs.version}} + git push origin v${{steps.publish.outputs.version}} diff --git a/jest.import.config.ts b/jest.import.config.ts index 0d89fa2..a2401c2 100644 --- a/jest.import.config.ts +++ b/jest.import.config.ts @@ -176,9 +176,7 @@ const config: JestConfigWithTsJest = { 'ts-jest', { tsconfig: 'tsconfig.spec.json', - astTransformers: { - before: ['./test/util/jest-test-transformer-loader.js'], - }, + }, ], }, diff --git a/jest.transform.config.ts b/jest.transform.config.ts deleted file mode 100644 index c2e093a..0000000 --- a/jest.transform.config.ts +++ /dev/null @@ -1,207 +0,0 @@ -import type { JestConfigWithTsJest } from 'ts-jest/dist/types'; -/* - * For a detailed explanation regarding each configuration property and type check, visit: - * https://jestjs.io/docs/configuration - */ - -const config: JestConfigWithTsJest = { - // All imported modules in your tests should be mocked automatically - // automock: false, - - // Stop running tests after `n` failures - // bail: 0, - - // The directory where Jest should store its cached dependency information - // cacheDirectory: "C:\\Users\\chen\\AppData\\Local\\Temp\\jest", - - // Automatically clear mock calls and instances between every test - clearMocks: true, - - // Indicates whether the coverage information should be collected while executing the test - collectCoverage: true, - - // An array of glob patterns indicating a set of files for which coverage information should be collected - // collectCoverageFrom: undefined, - - // The directory where Jest should output its coverage files - coverageDirectory: 'coverage', - - // An array of regexp pattern strings used to skip coverage collection - // coveragePathIgnorePatterns: [ - // "\\\\node_modules\\\\" - // ], - - // Indicates which provider should be used to instrument code for coverage - coverageProvider: 'v8', - - // A list of reporter names that Jest uses when writing coverage reports - // coverageReporters: [ - // "json", - // "text", - // "lcov", - // "clover" - // ], - - // An object that configures minimum threshold enforcement for coverage results - // coverageThreshold: undefined, - - // A path to a custom dependency extractor - // dependencyExtractor: undefined, - - // Make calling deprecated APIs throw helpful error messages - // errorOnDeprecated: false, - - // Force coverage collection from ignored files using an array of glob patterns - // forceCoverageMatch: [], - - // A path to a module which exports an async function that is triggered once before all test suites - // globalSetup: undefined, - - // A path to a module which exports an async function that is triggered once after all test suites - // globalTeardown: undefined, - - // A set of global variables that need to be available in all test environments - // globals: {}, - - // The maximum amount of workers used to run your tests. Can be specified as % or a number. E.g. maxWorkers: 10% will use 10% of your CPU amount + 1 as the maximum worker number. maxWorkers: 2 will use a maximum of 2 workers. - // maxWorkers: "50%", - - // An array of directory names to be searched recursively up from the requiring module's location - // moduleDirectories: [ - // "node_modules" - // ], - - // An array of file extensions your modules use - moduleFileExtensions: [ - 'js', - // "jsx", - 'ts', - // "tsx", - // "json", - // "node" - ], - - // A map from regular expressions to module names or to arrays of module names that allow to stub out resources with a single module - moduleNameMapper: { - '^static-injector/transform/compiler$': - '/src/transform/compiler/index', - }, - - // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader - // modulePathIgnorePatterns: [], - - // Activates notifications for test results - // notify: false, - - // An enum that specifies notification mode. Requires { notify: true } - // notifyMode: "failure-change", - - // A preset that is used as a base for Jest's configuration - // preset: undefined, - - // Run tests from one or more projects - // projects: undefined, - - // Use this configuration option to add custom reporters to Jest - // reporters: undefined, - - // Automatically reset mock state between every test - // resetMocks: false, - - // Reset the module registry before running each individual test - // resetModules: false, - - // A path to a custom resolver - // resolver: undefined, - - // Automatically restore mock state between every test - // restoreMocks: false, - - // The root directory that Jest should scan for tests and modules within - // rootDir: 'test', - - // A list of paths to directories that Jest should use to search for files in - // roots: [ - // "" - // ], - - // Allows you to use a custom runner instead of Jest's default test runner - // runner: "jest-runner", - - // The paths to modules that run some code to configure or set up the testing environment before each test - // setupFiles: [], - - // A list of paths to modules that run some code to configure or set up the testing framework before each test - // setupFilesAfterEnv: [], - - // The number of seconds after which a test is considered as slow and reported as such in the results. - // slowTestThreshold: 5, - - // A list of paths to snapshot serializer modules Jest should use for snapshot testing - // snapshotSerializers: [], - - // The test environment that will be used for testing - // testEnvironment: "jest-environment-node", - - // Options that will be passed to the testEnvironment - // testEnvironmentOptions: {}, - - // Adds a location field to test results - // testLocationInResults: false, - - // The glob patterns Jest uses to detect test files - testMatch: [ - // "**/__tests__/**/*.[jt]s?(x)", - // "**/?(*.)+(spec|test).[tj]s?(x)" - '**/test/transform/**/*.spec.ts', - ], - - // An array of regexp pattern strings that are matched against all test paths, matched tests are skipped - // testPathIgnorePatterns: [ - // "\\\\node_modules\\\\" - // ], - - // The regexp pattern or array of patterns that Jest uses to detect test files - // testRegex: ['.*\\.spec\\.ts$'], - - // This option allows the use of a custom results processor - // testResultsProcessor: undefined, - - // This option allows use of a custom test runner - // testRunner: "jest-circus/runner", - - // This option sets the URL for the jsdom environment. It is reflected in properties such as location.href - // testURL: "http://localhost", - - // Setting this value to "fake" allows the use of fake timers for functions such as "setTimeout" - // timers: "real", - - // A map from regular expressions to paths to transformers - // transform: undefined, - transform: { - '^.+\\.(t|j)s$': [ - 'ts-jest', - { - tsconfig: 'tsconfig.spec.json', - }, - ], - }, - // An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation - // transformIgnorePatterns: [ - // "\\\\node_modules\\\\", - // "\\.pnp\\.[^\\\\]+$" - // ], - - // An array of regexp pattern strings that are matched against all modules before the module loader will automatically return a mock for them - // unmockedModulePathPatterns: undefined, - - // Indicates whether each individual test should be reported during the run - // verbose: undefined, - - // An array of regexp patterns that are matched against all source file paths before re-running tests in watch mode - // watchPathIgnorePatterns: [], - - // Whether to use watchman for file crawling - // watchman: true, -}; -export default config; diff --git a/package-lock.json b/package-lock.json index a786aea..12925bc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,9 +8,6 @@ "name": "static-injector", "version": "0.0.0", "license": "MIT", - "dependencies": { - "cross-env": "^7.0.3" - }, "devDependencies": { "@code-recycle/cli": "1.3.10", "@commitlint/cli": "^12.1.4", @@ -18,19 +15,20 @@ "@types/jest": "^29.5.12", "@types/node": "^20.11.30", "cpx": "^1.5.0", + "cross-env": "^7.0.3", "husky": "^7.0.1", "jest": "^29.7.0", "prettier": "^3.2.5", "pretty-quick": "^4.0.0", "rimraf": "^5.0.5", - "rollup": "~4.13.0", + "rollup": "~4.17.1", "ts-jest": "^29.1.2", - "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", - "typescript": "5.4.2" + "tsx": "^4.7.3", + "typescript": "5.4.5" }, "peerDependencies": { - "typescript": "5.4.2" + "typescript": ">=5.4.2" } }, "node_modules/@ampproject/remapping": { @@ -716,139 +714,6 @@ } } }, - "node_modules/@code-recycle/cli/node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@code-recycle/cli/node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/@code-recycle/cli/node_modules/binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@code-recycle/cli/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/@code-recycle/cli/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@code-recycle/cli/node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@code-recycle/cli/node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@code-recycle/cli/node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@code-recycle/cli/node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@code-recycle/cli/node_modules/picomatch": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", @@ -861,34 +726,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@code-recycle/cli/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "optional": true, - "peer": true, - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/@code-recycle/cli/node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "optional": true, - "peer": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/@code-recycle/cli/node_modules/source-map": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", @@ -1926,9 +1763,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz", - "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.1.tgz", + "integrity": "sha512-P6Wg856Ou/DLpR+O0ZLneNmrv7QpqBg+hK4wE05ijbC/t349BRfMfx+UFj5Ha3fCFopIa6iSZlpdaB4agkWp2Q==", "cpu": [ "arm" ], @@ -1939,9 +1776,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz", - "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.1.tgz", + "integrity": "sha512-piwZDjuW2WiHr05djVdUkrG5JbjnGbtx8BXQchYCMfib/nhjzWoiScelZ+s5IJI7lecrwSxHCzW026MWBL+oJQ==", "cpu": [ "arm64" ], @@ -1952,9 +1789,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz", - "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.1.tgz", + "integrity": "sha512-LsZXXIsN5Q460cKDT4Y+bzoPDhBmO5DTr7wP80d+2EnYlxSgkwdPfE3hbE+Fk8dtya+8092N9srjBTJ0di8RIA==", "cpu": [ "arm64" ], @@ -1965,9 +1802,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz", - "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.1.tgz", + "integrity": "sha512-S7TYNQpWXB9APkxu/SLmYHezWwCoZRA9QLgrDeml+SR2A1LLPD2DBUdUlvmCF7FUpRMKvbeeWky+iizQj65Etw==", "cpu": [ "x64" ], @@ -1978,9 +1815,22 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz", - "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.1.tgz", + "integrity": "sha512-Lq2JR5a5jsA5um2ZoLiXXEaOagnVyCpCW7xvlcqHC7y46tLwTEgUSTM3a2TfmmTMmdqv+jknUioWXlmxYxE9Yw==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.1.tgz", + "integrity": "sha512-9BfzwyPNV0IizQoR+5HTNBGkh1KXE8BqU0DBkqMngmyFW7BfuIZyMjQ0s6igJEiPSBvT3ZcnIFohZ19OqjhDPg==", "cpu": [ "arm" ], @@ -1991,9 +1841,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz", - "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.1.tgz", + "integrity": "sha512-e2uWaoxo/rtzA52OifrTSXTvJhAXb0XeRkz4CdHBK2KtxrFmuU/uNd544Ogkpu938BzEfvmWs8NZ8Axhw33FDw==", "cpu": [ "arm64" ], @@ -2004,9 +1854,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz", - "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.1.tgz", + "integrity": "sha512-ekggix/Bc/d/60H1Mi4YeYb/7dbal1kEDZ6sIFVAE8pUSx7PiWeEh+NWbL7bGu0X68BBIkgF3ibRJe1oFTksQQ==", "cpu": [ "arm64" ], @@ -2016,10 +1866,23 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.1.tgz", + "integrity": "sha512-UGV0dUo/xCv4pkr/C8KY7XLFwBNnvladt8q+VmdKrw/3RUd3rD0TptwjisvE2TTnnlENtuY4/PZuoOYRiGp8Gw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz", - "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.1.tgz", + "integrity": "sha512-gEYmYYHaehdvX46mwXrU49vD6Euf1Bxhq9pPb82cbUU9UT2NV+RSckQ5tKWOnNXZixKsy8/cPGtiUWqzPuAcXQ==", "cpu": [ "riscv64" ], @@ -2029,10 +1892,23 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.1.tgz", + "integrity": "sha512-xeae5pMAxHFp6yX5vajInG2toST5lsCTrckSRUFwNgzYqnUjNBcQyqk1bXUxX5yhjWFl2Mnz3F8vQjl+2FRIcw==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz", - "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.1.tgz", + "integrity": "sha512-AsdnINQoDWfKpBzCPqQWxSPdAWzSgnYbrJYtn6W0H2E9It5bZss99PiLA8CgmDRfvKygt20UpZ3xkhFlIfX9zQ==", "cpu": [ "x64" ], @@ -2043,9 +1919,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz", - "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.1.tgz", + "integrity": "sha512-KoB4fyKXTR+wYENkIG3fFF+5G6N4GFvzYx8Jax8BR4vmddtuqSb5oQmYu2Uu067vT/Fod7gxeQYKupm8gAcMSQ==", "cpu": [ "x64" ], @@ -2056,9 +1932,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz", - "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.1.tgz", + "integrity": "sha512-J0d3NVNf7wBL9t4blCNat+d0PYqAx8wOoY+/9Q5cujnafbX7BmtYk3XvzkqLmFECaWvXGLuHmKj/wrILUinmQg==", "cpu": [ "arm64" ], @@ -2069,9 +1945,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz", - "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.1.tgz", + "integrity": "sha512-xjgkWUwlq7IbgJSIxvl516FJ2iuC/7ttjsAxSPpC9kkI5iQQFHKyEN5BjbhvJ/IXIZ3yIBcW5QDlWAyrA+TFag==", "cpu": [ "ia32" ], @@ -2082,9 +1958,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", - "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.1.tgz", + "integrity": "sha512-0QbCkfk6cnnVKWqqlC0cUrrUMDMfu5ffvYMTUHf+qMN2uAb3MKP31LPcwiMXBNsvoFGs/kYdFOsuLmvppCopXA==", "cpu": [ "x64" ], @@ -3315,6 +3191,7 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, "license": "MIT", "dependencies": { "cross-spawn": "^7.0.1" @@ -3333,6 +3210,7 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -4127,6 +4005,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/get-tsconfig": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", + "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -4788,6 +4678,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true, "license": "ISC" }, "node_modules/isobject": { @@ -6417,6 +6308,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7466,6 +7358,15 @@ "node": ">=8" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, "node_modules/resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -7567,9 +7468,9 @@ } }, "node_modules/rollup": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", - "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.17.1.tgz", + "integrity": "sha512-0gG94inrUtg25sB2V/pApwiv1lUb0bQ25FPNuzO89Baa+B+c0ccaaBKM5zkZV/12pUUdH+lWCSm9wmHqyocuVQ==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -7582,19 +7483,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.13.0", - "@rollup/rollup-android-arm64": "4.13.0", - "@rollup/rollup-darwin-arm64": "4.13.0", - "@rollup/rollup-darwin-x64": "4.13.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", - "@rollup/rollup-linux-arm64-gnu": "4.13.0", - "@rollup/rollup-linux-arm64-musl": "4.13.0", - "@rollup/rollup-linux-riscv64-gnu": "4.13.0", - "@rollup/rollup-linux-x64-gnu": "4.13.0", - "@rollup/rollup-linux-x64-musl": "4.13.0", - "@rollup/rollup-win32-arm64-msvc": "4.13.0", - "@rollup/rollup-win32-ia32-msvc": "4.13.0", - "@rollup/rollup-win32-x64-msvc": "4.13.0", + "@rollup/rollup-android-arm-eabi": "4.17.1", + "@rollup/rollup-android-arm64": "4.17.1", + "@rollup/rollup-darwin-arm64": "4.17.1", + "@rollup/rollup-darwin-x64": "4.17.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.17.1", + "@rollup/rollup-linux-arm-musleabihf": "4.17.1", + "@rollup/rollup-linux-arm64-gnu": "4.17.1", + "@rollup/rollup-linux-arm64-musl": "4.17.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.17.1", + "@rollup/rollup-linux-riscv64-gnu": "4.17.1", + "@rollup/rollup-linux-s390x-gnu": "4.17.1", + "@rollup/rollup-linux-x64-gnu": "4.17.1", + "@rollup/rollup-linux-x64-musl": "4.17.1", + "@rollup/rollup-win32-arm64-msvc": "4.17.1", + "@rollup/rollup-win32-ia32-msvc": "4.17.1", + "@rollup/rollup-win32-x64-msvc": "4.17.1", "fsevents": "~2.3.2" } }, @@ -7676,6 +7580,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -7688,6 +7593,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8475,88 +8381,513 @@ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, - "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "node_modules/tsx": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.3.tgz", + "integrity": "sha512-+fQnMqIp/jxZEXLcj6WzYy9FhcS5/Dfk8y4AtzJ6ejKcKqmfTF8Gso/jtrzDggCF2zTU20gJa6n8XqPYwDAUYQ==", "dev": true, + "dependencies": { + "esbuild": "~0.19.10", + "get-tsconfig": "^4.7.2" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, "engines": { - "node": ">=4" + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" } }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "node_modules/tsx/node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], "dev": true, + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/typescript": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", - "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", + "node_modules/tsx/node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=14.17" + "node": ">=12" } }, - "node_modules/uglify-js": { - "version": "3.17.4", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", - "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "node_modules/tsx/node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], "dev": true, "optional": true, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, + "os": [ + "android" + ], "engines": { - "node": ">=0.8.0" + "node": ">=12" } }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "node_modules/tsx/node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "node_modules/universalify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", - "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "node_modules/tsx/node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">= 10.0.0" + "node": ">=12" } }, - "node_modules/unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "node_modules/tsx/node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/tsx/node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "dev": true, + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typescript": { + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uglify-js": { + "version": "3.17.4", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", + "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "dev": true + }, + "node_modules/union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", "dev": true, "license": "MIT", @@ -8720,6 +9051,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -9385,130 +9717,12 @@ "source-map": "0.7.4" } }, - "anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "dependencies": { - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "optional": true, - "peer": true - } - } - }, - "binary-extensions": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", - "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", - "dev": true, - "optional": true, - "peer": true - }, - "chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "is-glob": "^4.0.1" - } - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "optional": true, - "peer": true - }, - "is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "is-extglob": "^2.1.1" - } - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "dev": true, - "optional": true, - "peer": true - }, "picomatch": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==", "dev": true }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "optional": true, - "peer": true, - "requires": { - "picomatch": "^2.2.1" - }, - "dependencies": { - "picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "optional": true, - "peer": true - } - } - }, "source-map": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", @@ -10317,93 +10531,114 @@ "optional": true }, "@rollup/rollup-android-arm-eabi": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz", - "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.1.tgz", + "integrity": "sha512-P6Wg856Ou/DLpR+O0ZLneNmrv7QpqBg+hK4wE05ijbC/t349BRfMfx+UFj5Ha3fCFopIa6iSZlpdaB4agkWp2Q==", "dev": true, "optional": true }, "@rollup/rollup-android-arm64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz", - "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.1.tgz", + "integrity": "sha512-piwZDjuW2WiHr05djVdUkrG5JbjnGbtx8BXQchYCMfib/nhjzWoiScelZ+s5IJI7lecrwSxHCzW026MWBL+oJQ==", "dev": true, "optional": true }, "@rollup/rollup-darwin-arm64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz", - "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.1.tgz", + "integrity": "sha512-LsZXXIsN5Q460cKDT4Y+bzoPDhBmO5DTr7wP80d+2EnYlxSgkwdPfE3hbE+Fk8dtya+8092N9srjBTJ0di8RIA==", "dev": true, "optional": true }, "@rollup/rollup-darwin-x64": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz", - "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.1.tgz", + "integrity": "sha512-S7TYNQpWXB9APkxu/SLmYHezWwCoZRA9QLgrDeml+SR2A1LLPD2DBUdUlvmCF7FUpRMKvbeeWky+iizQj65Etw==", "dev": true, "optional": true }, "@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz", - "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.1.tgz", + "integrity": "sha512-Lq2JR5a5jsA5um2ZoLiXXEaOagnVyCpCW7xvlcqHC7y46tLwTEgUSTM3a2TfmmTMmdqv+jknUioWXlmxYxE9Yw==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-arm-musleabihf": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.1.tgz", + "integrity": "sha512-9BfzwyPNV0IizQoR+5HTNBGkh1KXE8BqU0DBkqMngmyFW7BfuIZyMjQ0s6igJEiPSBvT3ZcnIFohZ19OqjhDPg==", "dev": true, "optional": true }, "@rollup/rollup-linux-arm64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz", - "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.1.tgz", + "integrity": "sha512-e2uWaoxo/rtzA52OifrTSXTvJhAXb0XeRkz4CdHBK2KtxrFmuU/uNd544Ogkpu938BzEfvmWs8NZ8Axhw33FDw==", "dev": true, "optional": true }, "@rollup/rollup-linux-arm64-musl": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz", - "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.1.tgz", + "integrity": "sha512-ekggix/Bc/d/60H1Mi4YeYb/7dbal1kEDZ6sIFVAE8pUSx7PiWeEh+NWbL7bGu0X68BBIkgF3ibRJe1oFTksQQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.1.tgz", + "integrity": "sha512-UGV0dUo/xCv4pkr/C8KY7XLFwBNnvladt8q+VmdKrw/3RUd3rD0TptwjisvE2TTnnlENtuY4/PZuoOYRiGp8Gw==", "dev": true, "optional": true }, "@rollup/rollup-linux-riscv64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz", - "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.1.tgz", + "integrity": "sha512-gEYmYYHaehdvX46mwXrU49vD6Euf1Bxhq9pPb82cbUU9UT2NV+RSckQ5tKWOnNXZixKsy8/cPGtiUWqzPuAcXQ==", + "dev": true, + "optional": true + }, + "@rollup/rollup-linux-s390x-gnu": { + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.1.tgz", + "integrity": "sha512-xeae5pMAxHFp6yX5vajInG2toST5lsCTrckSRUFwNgzYqnUjNBcQyqk1bXUxX5yhjWFl2Mnz3F8vQjl+2FRIcw==", "dev": true, "optional": true }, "@rollup/rollup-linux-x64-gnu": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz", - "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.1.tgz", + "integrity": "sha512-AsdnINQoDWfKpBzCPqQWxSPdAWzSgnYbrJYtn6W0H2E9It5bZss99PiLA8CgmDRfvKygt20UpZ3xkhFlIfX9zQ==", "dev": true, "optional": true }, "@rollup/rollup-linux-x64-musl": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz", - "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.1.tgz", + "integrity": "sha512-KoB4fyKXTR+wYENkIG3fFF+5G6N4GFvzYx8Jax8BR4vmddtuqSb5oQmYu2Uu067vT/Fod7gxeQYKupm8gAcMSQ==", "dev": true, "optional": true }, "@rollup/rollup-win32-arm64-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz", - "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.1.tgz", + "integrity": "sha512-J0d3NVNf7wBL9t4blCNat+d0PYqAx8wOoY+/9Q5cujnafbX7BmtYk3XvzkqLmFECaWvXGLuHmKj/wrILUinmQg==", "dev": true, "optional": true }, "@rollup/rollup-win32-ia32-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz", - "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.1.tgz", + "integrity": "sha512-xjgkWUwlq7IbgJSIxvl516FJ2iuC/7ttjsAxSPpC9kkI5iQQFHKyEN5BjbhvJ/IXIZ3yIBcW5QDlWAyrA+TFag==", "dev": true, "optional": true }, "@rollup/rollup-win32-x64-msvc": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", - "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.1.tgz", + "integrity": "sha512-0QbCkfk6cnnVKWqqlC0cUrrUMDMfu5ffvYMTUHf+qMN2uAb3MKP31LPcwiMXBNsvoFGs/kYdFOsuLmvppCopXA==", "dev": true, "optional": true }, @@ -11327,6 +11562,7 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, "requires": { "cross-spawn": "^7.0.1" } @@ -11335,6 +11571,7 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, "requires": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -11382,8 +11619,7 @@ "version": "1.5.1", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.5.1.tgz", "integrity": "sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg==", - "dev": true, - "requires": {} + "dev": true }, "deepmerge": { "version": "4.3.1", @@ -11902,6 +12138,15 @@ "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "dev": true }, + "get-tsconfig": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.3.tgz", + "integrity": "sha512-ZvkrzoUA0PQZM6fy6+/Hce561s+faD1rsNwhnO5FelNjyy7EMGJ3Rz1AQ8GYDWjhRs/7dBLOEJvhK8MiEJOAFg==", + "dev": true, + "requires": { + "resolve-pkg-maps": "^1.0.0" + } + }, "get-value": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", @@ -12356,7 +12601,8 @@ "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true }, "isobject": { "version": "3.0.1", @@ -12736,8 +12982,7 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", - "dev": true, - "requires": {} + "dev": true }, "jest-regex-util": { "version": "29.6.3", @@ -13559,7 +13804,8 @@ "path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true }, "path-parse": { "version": "1.0.7", @@ -14299,6 +14545,12 @@ "global-dirs": "^0.1.1" } }, + "resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true + }, "resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -14366,24 +14618,27 @@ } }, "rollup": { - "version": "4.13.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", - "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", - "dev": true, - "requires": { - "@rollup/rollup-android-arm-eabi": "4.13.0", - "@rollup/rollup-android-arm64": "4.13.0", - "@rollup/rollup-darwin-arm64": "4.13.0", - "@rollup/rollup-darwin-x64": "4.13.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", - "@rollup/rollup-linux-arm64-gnu": "4.13.0", - "@rollup/rollup-linux-arm64-musl": "4.13.0", - "@rollup/rollup-linux-riscv64-gnu": "4.13.0", - "@rollup/rollup-linux-x64-gnu": "4.13.0", - "@rollup/rollup-linux-x64-musl": "4.13.0", - "@rollup/rollup-win32-arm64-msvc": "4.13.0", - "@rollup/rollup-win32-ia32-msvc": "4.13.0", - "@rollup/rollup-win32-x64-msvc": "4.13.0", + "version": "4.17.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.17.1.tgz", + "integrity": "sha512-0gG94inrUtg25sB2V/pApwiv1lUb0bQ25FPNuzO89Baa+B+c0ccaaBKM5zkZV/12pUUdH+lWCSm9wmHqyocuVQ==", + "dev": true, + "requires": { + "@rollup/rollup-android-arm-eabi": "4.17.1", + "@rollup/rollup-android-arm64": "4.17.1", + "@rollup/rollup-darwin-arm64": "4.17.1", + "@rollup/rollup-darwin-x64": "4.17.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.17.1", + "@rollup/rollup-linux-arm-musleabihf": "4.17.1", + "@rollup/rollup-linux-arm64-gnu": "4.17.1", + "@rollup/rollup-linux-arm64-musl": "4.17.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.17.1", + "@rollup/rollup-linux-riscv64-gnu": "4.17.1", + "@rollup/rollup-linux-s390x-gnu": "4.17.1", + "@rollup/rollup-linux-x64-gnu": "4.17.1", + "@rollup/rollup-linux-x64-musl": "4.17.1", + "@rollup/rollup-win32-arm64-msvc": "4.17.1", + "@rollup/rollup-win32-ia32-msvc": "4.17.1", + "@rollup/rollup-win32-x64-msvc": "4.17.1", "@types/estree": "1.0.5", "fsevents": "~2.3.2" } @@ -14443,6 +14698,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "requires": { "shebang-regex": "^3.0.0" } @@ -14450,7 +14706,8 @@ "shebang-regex": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true }, "shell-quote": { "version": "1.7.2", @@ -14697,8 +14954,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/static-injector/-/static-injector-3.0.0.tgz", "integrity": "sha512-7MOCjQh4NUH6irggWuso7bB4joKnEOF9tbJOVq/6Bx5FZbU6Ssim0OtUC4GGBSy1q68u4QKRim3tVqWG2X417g==", - "dev": true, - "requires": {} + "dev": true }, "string_decoder": { "version": "1.3.0", @@ -15016,6 +15272,211 @@ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", "dev": true }, + "tsx": { + "version": "4.7.3", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.7.3.tgz", + "integrity": "sha512-+fQnMqIp/jxZEXLcj6WzYy9FhcS5/Dfk8y4AtzJ6ejKcKqmfTF8Gso/jtrzDggCF2zTU20gJa6n8XqPYwDAUYQ==", + "dev": true, + "requires": { + "esbuild": "~0.19.10", + "fsevents": "~2.3.3", + "get-tsconfig": "^4.7.2" + }, + "dependencies": { + "@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "dev": true, + "optional": true + }, + "esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "dev": true, + "requires": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + } + } + }, "type-detect": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", @@ -15029,9 +15490,9 @@ "dev": true }, "typescript": { - "version": "5.4.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz", - "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==", + "version": "5.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", + "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", "dev": true }, "uglify-js": { @@ -15188,6 +15649,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "requires": { "isexe": "^2.0.0" } diff --git a/package.json b/package.json index 852821b..a3e051f 100644 --- a/package.json +++ b/package.json @@ -5,17 +5,15 @@ "private": true, "scripts": { "sync": "code-recycle ./script/sync/index.ts --cwd ./src && prettier ./src --write", - "test": "npm run test:transform && npm run test:import", - "test:transform": "jest --config ./jest.transform.config.ts", + "test": " npm run test:import", "test:import": "cross-env TS_NODE_PROJECT=./tsconfig.spec.json jest --config ./jest.import.config.ts", - "build": "rimraf dist&& cpx ./src/package.json ./dist && cpx -v ./readme.md ./dist&& npm run build:transform && npm run build:import", - "build:transform": "tsc -p ./tsconfig.transform.json", - "build:import": "tsc -p ./tsconfig.import.json && ts-node ./script/build" + "build": "rimraf dist&& cpx ./src/package.json ./dist && cpx -v ./readme.md ./dist && npm run build:import", + "build:import": "tsc -p ./tsconfig.import.json && tsx ./script/build" }, "author": "wszgrcy", "license": "MIT", "peerDependencies": { - "typescript": "5.4.2" + "typescript": ">=5.4.2" }, "devDependencies": { "@code-recycle/cli": "1.3.10", @@ -24,18 +22,16 @@ "@types/jest": "^29.5.12", "@types/node": "^20.11.30", "cpx": "^1.5.0", + "cross-env": "^7.0.3", "husky": "^7.0.1", "jest": "^29.7.0", "prettier": "^3.2.5", "pretty-quick": "^4.0.0", "rimraf": "^5.0.5", - "rollup": "~4.13.0", + "rollup": "~4.17.1", "ts-jest": "^29.1.2", - "ts-node": "^10.9.2", "tsconfig-paths": "^4.2.0", - "typescript": "5.4.2" - }, - "dependencies": { - "cross-env": "^7.0.3" + "tsx": "^4.7.3", + "typescript": "5.4.5" } } diff --git a/readme.md b/readme.md index 9aec3da..f23a29a 100644 --- a/readme.md +++ b/readme.md @@ -1,41 +1,61 @@ | [中文](https://github.com/wszgrcy/static-injector/blob/main/readme.zh-Hans.md) | [English](./readme.md) | -|-|-| +| ------------------------------------------------------------------------------ | ---------------------- | # Introduction - Angular dependency injection standalone version - The usage method is completely consistent with Angular's dependency injection +- No transformer required +- 0 dependencies +- Remove Decorator +> `@Injectable()`=>`static injectOptions={}` +> `@Inject() xx`=>`xx=inject()` +> `@Optional()`=>`xx=inject(token,{optional:true})` +- `JS`/`TS` Support # Source -- Angular 17.3.1 -# dependency -- ts 5.4.2 +- Angular 17.3.6 # Usage - Create a first level dependency injector with `Injector.create` -- Declare as a dependency injection class using the `@Injectable` decorator +```ts +import { Injector } from 'static-injector'; + +export class FirstClass { + constructor() {} + hello() { + return 'hello'; + } +} + +let injector = Injector.create({ + providers: [{ provide: FirstClass }], +}); +let instance = injector.get(FirstClass); +console.log(instance.hello()); + +``` # Different from `injection-js` - `injection-js` belongs to dynamic dependency injection and is a version used before Angular5. After Angular5, it has been converted to static dependency injection - In theory, it would be faster than `injection-js` (otherwise Angular wouldn't do the replacement...), but there was no benchmark done -- Need to use `typescript` to call the transformer for conversion/use webpack's ts loader to pass in the converter/roll up/ts node/other conversion tools support typescript and custom converters that support typescript - The two are basically interchangeable (the details need to be adjusted) - Support the use of `inject` during construction +# No Decorator + +- The original use of `@Injectable()` to pass parameters has been changed to `static injectOptions={}`. If there are no parameters, there is no need to set them +- Originally, `@Optional`, `@SkipSelf`, `@Self`, please use the second pass parameter of `inject` instead + # Test - Partially conducted unit testing to ensure that most functions are functioning properly - Because most of the code itself is extracted from Angular, stability is definitely guaranteed # Sync -- Currently, the synchronization logic has been refactored and modified using `@code recycle/cli` to ensure consistency with the official version of `angular` -# Template - -- [Used under typescript (using Typescript Compiler API)](https://github.com/wszgrcy/static-injector-typescript-template) -- [Used under webpack](https://github.com/wszgrcy/static-injector-webpack-template) -- [Using Rollup](https://github.com/wszgrcy/static-injector-rollup-template) +- Currently, the synchronization logic has been refactored and modified using `@code recycle/cli` to ensure consistency with the official version of `angular` diff --git a/readme.zh-Hans.md b/readme.zh-Hans.md index 254bd4f..858114a 100644 --- a/readme.zh-Hans.md +++ b/readme.zh-Hans.md @@ -2,26 +2,53 @@ |-|-| # 简介 -- Angualr 依赖注入的独立版本 +- Angular 依赖注入的独立版本 - 使用方法与 Angular 的依赖注入完全一致 +- 不需要任何转换器,引入即可使用 +- 0依赖 +- 移除装饰器 +> `@Injectable()`=>`static injectOptions={}` +> `@Inject() xx`=>`xx=inject()` +> `@Optional()`=>`xx=inject(token,{optional:true})` +- `JS`/`TS`支持 # 来源 -- Angular 17.3.1 -# 依赖 -- ts 5.4.2 +- Angular 17.3.6 + # 使用方法 - 以`Injector.create`创建第一级依赖注入器 -- 使用`@Injectable`装饰器声明为依赖注入类 + +```ts +import { Injector } from 'static-injector'; + +export class FirstClass { + constructor() {} + hello() { + return 'hello'; + } +} + +let injector = Injector.create({ + providers: [{ provide: FirstClass }], +}); +let instance = injector.get(FirstClass); +console.log(instance.hello()); + +``` # 与`injection-js`的不同 - `injection-js`属于动态依赖注入,是 Angular5 之前使用的版本,Angular5 之后转为静态依赖注入 - 理论上会比`injection-js`快一些(否则 Angular 也不会做替换...),但是没有做 Benchmark -- 需要会使用`typescript`调用转换器进行转换,或者使用 webpack 的 ts-loader 传入转换器,或者其他转换工具支持 typescript 并且支持 typescript 的自定义转换器 - 两者基本上可以互换(细节部分需要调整) - 支持构造时期使用`inject` +# 无装饰器 +- 原来使用`@Injectable()`传参改为`static injectOptions={}`.如果没有参数即不需要设置 +- 原来`@Optional`,`@SkipSelf`,`@Self`,请使用`inject`的第二个传参代替 + + # 测试 - 做了一部分的单元测试.保证大部分功能正常使用 @@ -30,8 +57,3 @@ # 同步 - 目前重构了同步逻辑,使用`@code-recycle/cli`进行修改,保证与`angular`官方版本一致 -# 模板 - -- [typescript 下使用(使用 Typescript Compiler API)](https://github.com/wszgrcy/static-injector-typescript-template) -- [webpack 下使用](https://github.com/wszgrcy/static-injector-webpack-template) -- [rollup 下使用](https://github.com/wszgrcy/static-injector-rollup-template) diff --git a/script/build.ts b/script/build.ts index 50e3731..0ae3b97 100644 --- a/script/build.ts +++ b/script/build.ts @@ -1,22 +1,16 @@ import * as rollup from 'rollup'; -interface BuildOptions { - output: string; - format: rollup.ModuleFormat; -} + async function bundleImport() { let bundle = await rollup.rollup({ - input: './dist/import/es2022/index.js', - treeshake: false, + input: './dist/es2022/index.js', + treeshake: true, + }); + + await bundle.write({ file: './dist/commonjs/index.js', format: 'commonjs' }); + await bundle.write({ + file: './dist/fesm2022/index.js', + format: 'module', }); - for (const item of [ - { output: './dist/import/commonjs/index.js', format: 'commonjs' }, - { output: './dist/import/fesm2022/index.js', format: 'esm' }, - ] as BuildOptions[]) { - await bundle.write({ - file: item.output, - format: item.format, - }); - } } bundleImport(); diff --git a/script/sync/copy.json b/script/sync/copy.json index f1c48e1..daf326c 100644 --- a/script/sync/copy.json +++ b/script/sync/copy.json @@ -1,55 +1,4 @@ [ - { - "source": "compiler", - "target":"./transform/compiler", - "fileList": [ - "/src/output/output_ast.ts", - "/src/render3/partial/api.ts", - "/src/render3/view/util.ts", - "/src/render3/r3_factory.ts", - "/src/render3/r3_identifiers.ts", - "/src/render3/util.ts", - "/src/core.ts", - "/src/injectable_compiler_2.ts", - "/src/parse_util.ts", - "/index.ts", - "/compiler.ts", - "/public_api.ts", - "/src/compiler.ts" - ] - }, - { - "source": "compiler-cli", - "target":"./transform/compiler-cli", - "fileList": [ - "/src/ngtsc/annotations/common/src/util.ts", - "/src/ngtsc/annotations/src/injectable.ts", - "/src/ngtsc/diagnostics/index.ts", - "/src/ngtsc/imports/index.ts", - "/src/ngtsc/imports/src/core.ts", - "/src/ngtsc/reflection/index.ts", - "/src/ngtsc/reflection/src/host.ts", - "/src/ngtsc/reflection/src/typescript.ts", - "/src/ngtsc/reflection/src/type_to_value.ts", - "/src/ngtsc/reflection/src/util.ts", - "/src/ngtsc/transform/index.ts", - "/src/ngtsc/transform/src/api.ts", - "/src/ngtsc/transform/src/utils.ts", - "/src/ngtsc/translator/index.ts", - "/src/ngtsc/translator/src/import_manager.ts", - "/src/ngtsc/translator/src/translator.ts", - "/src/ngtsc/translator/src/typescript_ast_factory.ts", - "/src/ngtsc/translator/src/typescript_translator.ts", - "/src/ngtsc/translator/src/api/ast_factory.ts", - "/src/ngtsc/translator/src/api/import_generator.ts", - "/src/ngtsc/util/src/typescript.ts", - "/src/ngtsc/annotations/common/index.ts", - "/src/ngtsc/annotations/common/src/di.ts", - "/src/ngtsc/annotations/common/src/factory.ts", - "/src/ngtsc/imports/src/default.ts", - "/src/ngtsc/translator/src/ts_util.ts" - ] - }, { "source": "core/src", "target":"./import", @@ -79,19 +28,16 @@ "/interface/lifecycle_hooks.ts", "/interface/type.ts", "/render3/definition_factory.ts", - "/render3/di.ts", "/render3/errors_di.ts", "/render3/fields.ts", "/render3/instructions/di.ts", "/render3/util/stringify_utils.ts", - "/util/array_utils.ts", "/util/closure.ts", "/util/decorators.ts", "/util/empty.ts", "/util/property.ts", "/util/stringify.ts", - "/errors.ts", - "/error_details_base_url.ts" + "/errors.ts" ] } ] \ No newline at end of file diff --git a/script/sync/extra.json b/script/sync/extra.json index 598efa9..b9e00e8 100644 --- a/script/sync/extra.json +++ b/script/sync/extra.json @@ -1,7 +1,7 @@ [ { "glob": true, - "fileName": "./import/**/*.ts", + "fileName": "./import/**/*[!definition_factory]*.ts", "rules": [ { "type": "custom", @@ -55,1201 +55,6 @@ } ] }, - { - "fileName": "./transform/compiler/src/output/output_ast.ts", - "rules": [ - { - "type": "class", - "change": "remove", - "values": { - "excludes": [ - "TaggedTemplateExpr", - "PlaceholderPiece", - "LocalizedString", - "RecursiveAstVisitor" - ] - } - }, - { - "type": "type", - "change": "remove", - "values": { - "excludes": [ - "MessagePiece" - ] - } - }, - { - "type": "class-method", - "change": "remove", - "values": { - "excludes": [ - "instantiate", - "conditional", - "equals", - "notEquals", - "identical", - "notIdentical", - "minus", - "plus", - "divide", - "multiply", - "modulo", - "and", - "bitwiseAnd", - "or", - "lower", - "lowerEquals", - "bigger", - "biggerEquals", - "isBlank", - "nullishCoalesce" - ] - } - }, - { - "type": "function", - "change": "remove", - "values": { - "excludes": [ - "taggedTemplate", - "localizedString" - ] - } - }, - { - "type": "interface-method", - "change": "remove", - "values": { - "excludes": [ - "visitTaggedTemplateExpr", - "visitLocalizedString" - ] - } - }, - { - "type": "variable", - "change": "remove", - "values": { - "excludes": [ - "MEANING_SEPARATOR", - "ID_SEPARATOR", - "LEGACY_ID_INDICATOR" - ] - } - }, - { - "type": "import", - "change": "remove", - "values": { - "excludes": [ - "computeMsgId", - "Message", - "I18nMeta" - ] - } - } - ] - }, - { - "fileName": "./transform/compiler/src/render3/partial/api.ts", - "rules": [ - { - "type": "interface", - "change": "remove", - "values": { - "excludes": [ - "R3DeclareDirectiveMetadata", - "R3DeclareComponentMetadata", - "R3DeclareDirectiveDependencyMetadata", - "R3DeclarePipeDependencyMetadata", - "R3DeclareNgModuleDependencyMetadata", - "R3DeclareQueryMetadata", - "R3DeclareNgModuleMetadata", - "R3DeclarePipeMetadata", - "R3DeclareHostDirectiveMetadata" - ] - } - }, - { - "type": "type", - "change": "remove", - "values": { - "excludes": [ - "R3DeclareTemplateDependencyMetadata" - ] - } - }, - { - "type": "import", - "change": "remove", - "values": { - "excludes": [ - "ChangeDetectionStrategy" - ] - } - }, - { - "type": "custom", - "change": "remove", - "values": { - "selector": "InterfaceDeclaration:has(>::name[value=R3DeclareDependencyMetadata]) PropertySignature:has(>::name[value=host])", - "removeComment": true - } - } - ] - }, - { - "fileName": "./transform/compiler/src/render3/view/util.ts", - "rules": [ - { - "type": "variable", - "change": "remove", - "values": { - "excludes": [ - "UNSAFE_OBJECT_KEY_NAME_REGEXP", - "TEMPORARY_NAME", - "CONTEXT_NAME", - "RENDER_FLAGS", - "REFERENCE_PREFIX", - "IMPLICIT_REFERENCE", - "NON_BINDABLE_ATTR", - "RESTORED_VIEW_CONTEXT_NAME", - "MAX_CHAIN_LENGTH", - "CHAINABLE_INSTRUCTIONS" - ] - } - }, - { - "type": "type", - "change": "remove", - "values": { - "excludes": [ - "InstructionParams" - ] - } - }, - { - "type": "interface", - "change": "remove", - "values": { - "excludes": [ - "Instruction" - ] - } - }, - { - "type": "function", - "change": "remove", - "values": { - "excludes": [ - "invokeInstruction", - "temporaryAllocator", - "invalid", - "asLiteral", - "conditionallyCreateMapObjectLiteral", - "mapToExpression", - "trimTrailingNulls", - "getQueryPredicate", - "getAttrsForDirectiveMatching", - "getInterpolationArgsLength", - "getInstructionStatements", - "conditionallyCreateDirectiveBindingLiteral", - "createCssSelectorFromNode", - "getInputFlagExpr", - "bitwiseOrInputFlagsExpr" - ] - } - }, - { - "type": "import", - "change": "remove", - "values": { - "excludes": [ - "ConstantPool", - "Interpolation", - "ParseSourceSpan", - "splitAtColon", - "R3", - "ForwardRefHandling", - "R3QueryMetadata", - "isI18nAttribute", - "splitNsName", - "CssSelector" - ] - } - }, - { - "type": "import", - "change": "remove", - "values": { - "namespaces": [ - "t" - ] - } - } - ] - }, - { - "fileName": "./transform/compiler/src/render3/r3_factory.ts", - "rules": [ - { - "type": "custom", - "change": "remove", - "values": { - "selector": "InterfaceDeclaration:has(>::name[value=R3DependencyMetadata]) PropertySignature:has(>::name[value=host])", - "removeComment": true - } - }, - { - "type": "custom", - "change": "change", - "values": { - "selector": "FunctionDeclaration:has(>::name[value=compileInjectDependency]) BinaryExpression:has(>::right[value=\"FactoryTarget.Pipe\"])::name[value=compileInjectDependency]) ConditionalExpression:has(>[value*=\"InjectFlags.Host\"])::name[value=compileInjectDependency]) PropertyAccessExpression:has(>::name[value=injectAttribute]):has(>::expression[value=R3])::name[value=createCtorDepType]) IfStatement:has(>::expression[value=\"dep.attributeNameType !== null\"]),FunctionDeclaration:has(>::name[value=createCtorDepType]) IfStatement:has(>::expression[value=\"dep.host\"])", - "replaceComment": true - } - } - ] - }, - { - "fileName": "./transform/compiler/src/render3/r3_identifiers.ts", - "rules": [ - { - "type": "custom", - "change": "remove", - "values": { - "selector": "ClassDeclaration:has(>::name[value=Identifiers]) PropertyDeclaration:not(:has(>::name:is([value=inject],[value=directiveInject],[value=invalidFactory],[value=invalidFactoryDep],[value=invalidFactoryDep],[value=forwardRef],[value=resolveForwardRef],[value=ɵɵdefineInjectable],[value=InjectableDeclaration],[value=FactoryDeclaration],[value=getInheritedFactory])))", - "removeComment": true - } - }, - { - "type": "custom", - "change": "change", - "values": { - "selector": "VariableDeclaration:has(>::name[value=CORE]) StringLiteral", - "content": "'static-injector'" - } - } - ] - }, - { - "fileName": "./transform/compiler/src/render3/util.ts", - "rules": [ - { - "type": "import", - "change": "remove", - "values": { - "excludes": [ - "escapeIdentifier" - ] - } - }, - { - "type": "function", - "change": "remove", - "values": { - "excludes": [ - "prepareSyntheticPropertyName", - "prepareSyntheticListenerName", - "getSafePropertyAccessString", - "prepareSyntheticListenerFunctionName", - "jitOnlyGuardedExpression", - "devOnlyGuardedExpression", - "guardedExpression", - "wrapReference", - "refsToArray" - ] - } - }, - { - "type": "variable", - "change": "remove", - "values": { - "excludes": [ - "ANIMATE_SYMBOL_PREFIX" - ] - } - } - ] - }, - { - "fileName": "./transform/compiler/src/core.ts", - "rules": [ - { - "type": "custom", - "change": "remove", - "values": { - "selector": "EnumDeclaration:has(>::name[value=InjectFlags]) EnumMember:has(>::name:is([value=Host],[value=ForPipe])):use(*,+CommaToken)", - "removeComment": true - } - }, - { - "type": "variable", - "change": "remove", - "values": { - "excludes": [ - "emitDistinctChangesOnlyDefaultValue", - "CUSTOM_ELEMENTS_SCHEMA", - "NO_ERRORS_SCHEMA", - "Type" - ] - } - }, - { - "type": "type", - "change": "remove", - "values": { - "excludes": [ - "R3CssSelectorList", - "R3CssSelector", - "parserSelectorToR3Selector", - "parseSelectorToR3Selector" - ] - } - }, - { - "type": "function", - "change": "remove", - "values": { - "excludes": [ - "parserSelectorToNegativeSelector", - "parserSelectorToSimpleSelector", - "parserSelectorToR3Selector", - "parseSelectorToR3Selector" - ] - } - }, - { - "type": "enum", - "change": "remove", - "values": { - "excludes": [ - "ViewEncapsulation", - "ChangeDetectionStrategy", - "SecurityContext", - "MissingTranslationStrategy", - "SelectorFlags", - "RenderFlags", - "AttributeMarker" - ] - } - }, - { - "type": "interface", - "change": "remove", - "values": { - "excludes": [ - "Input", - "Output", - "HostBinding", - "HostListener", - "SchemaMetadata", - "Type", - "guardedExpression", - "wrapReference", - "refsToArray" - ] - } - }, - { - "type": "import", - "change": "remove", - "values": { - "all": true - } - } - ] - }, - { - "fileName": "./transform/compiler/src/parse_util.ts", - "rules": [ - { - "type": "variable", - "change": "remove", - "values": { - "excludes": [ - "_anonymousTypeIndex" - ] - } - }, - { - "type": "class", - "change": "remove", - "values": { - "excludes": [ - "ParseError" - ] - } - }, - { - "type": "enum", - "change": "remove", - "values": { - "excludes": [ - "ParseErrorLevel" - ] - } - }, - { - "type": "interface", - "change": "remove", - "values": { - "excludes": [ - "CompileIdentifierMetadata" - ] - } - }, - { - "type": "function", - "change": "remove", - "values": { - "excludes": [ - "r3JitTypeSourceSpan", - "identifierName", - "sanitizeIdentifier" - ] - } - }, - { - "type": "import", - "change": "remove", - "values": { - "all": true - } - }, - { - "type": "custom", - "change": "remove", - "values": { - "selector": "ClassDeclaration:has(>::name[value=ParseLocation]) MethodDeclaration", - "removeComment": true - } - } - ] - }, - { - "fileName": "./transform/compiler/src/compiler.ts", - "rules": [ - { - "type": "custom", - "change": "change", - "values": { - "selector": "SourceFile", - "content": "export * from './injectable_compiler_2';\nexport * from './render3/r3_factory';\nexport * from './output/output_ast';\nexport * from './render3/util';\nexport * from './parse_util';" - } - } - ] - }, - { - "fileName": "./transform/compiler/src/compiler.ts", - "rules": [] - }, - { - "fileName": "./transform/compiler/src/core.ts", - "rules": [] - }, - { - "fileName": "./transform/compiler/src/injectable_compiler_2.ts", - "rules": [] - }, - { - "fileName": "./transform/compiler/src/parse_util.ts", - "rules": [] - }, - { - "fileName": "./transform/compiler/src/output/output_ast.ts", - "rules": [] - }, - { - "fileName": "./transform/compiler/src/render3/r3_factory.ts", - "rules": [] - }, - { - "fileName": "./transform/compiler/src/render3/r3_identifiers.ts", - "rules": [] - }, - { - "fileName": "./transform/compiler/src/render3/util.ts", - "rules": [] - }, - { - "fileName": "./transform/compiler/src/render3/partial/api.ts", - "rules": [] - }, - { - "fileName": "./transform/compiler/src/render3/view/util.ts", - "rules": [] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/annotations/common/src/util.ts", - "rules": [ - { - "change": "change", - "type": "custom", - "values": { - "selector": "ImportDeclaration:has(>StringLiteral[value=\"'@angular/compiler'\"]) StringLiteral", - "content": "'static-injector/transform/compiler'" - } - }, - { - "change": "change", - "type": "custom", - "values": { - "selector": "StringLiteral[value=\"'@angular/core'\"]", - "content": "'static-injector'" - } - }, - { - "type": "function", - "values": { - "excludes": [ - "getOriginNodeForDiagnostics", - "resolveImportedFile", - "compileResults", - "createSourceSpan", - "resolveProvidersRequiringFactory", - "readBaseClass", - "isWrappedTsNodeExpr", - "isExpressionForwardReference", - "combineResolvers", - "isAngularCoreReference", - "toR3Reference" - ] - } - }, - { - "type": "variable", - "values": { - "excludes": [ - "forwardRefResolver" - ] - } - }, - { - "type": "import", - "values": { - "excludes": [ - "DynamicValue", - "CompileResult", - "assertSuccessfulReferenceEmit", - "ForeignFunctionResolver" - ] - } - }, - { - "type": "custom", - "values": { - "selector": "IfStatement:has(>::expression[value=\"valueRef.defaultImportStatement !== null\"])" - } - } - ] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/annotations/src/injectable.ts", - "rules": [ - { - "change": "change", - "type": "custom", - "values": { - "selector": "ImportDeclaration:has(>StringLiteral[value=\"'@angular/compiler'\"]) StringLiteral", - "content": "'static-injector/transform/compiler'" - } - }, - { - "change": "change", - "type": "custom", - "values": { - "selector": "StringLiteral[value=\"'@angular/core'\"]", - "content": "'static-injector'" - } - }, - { - "type": "custom", - "values": { - "selector": "InterfaceDeclaration:has(>::name[value=InjectableHandlerData]) PropertySignature:has(>::name[value=classMetadata]),InterfaceDeclaration:has(>::name[value=InjectableHandlerData]) PropertySignature:has(>::name[value=needsFactory])" - } - }, - { - "type": "custom", - "values": { - "selector": "ClassDeclaration:has(>::name[value=InjectableDecoratorHandler]) PropertyDeclaration:has(>::name[value=precedence]),ClassDeclaration:has(>::name[value=InjectableDecoratorHandler]) PropertyDeclaration:has(>::name[value=name])" - } - }, - { - "type": "custom", - "values": { - "selector": "ClassDeclaration:has(>::name[value=InjectableDecoratorHandler]) Constructor Parameter:has(>::name:is([value=injectableRegistry],[value=perf])):use(*,+CommaToken)" - } - }, - { - "type": "custom", - "values": { - "selector": "PropertyAccessExpression:has(>::name[value=perf]):has(>::expression[value=this])::name[value=analyze]) PropertyAssignment:has(>::name:is([value=classMetadata],[value=needsFactory])):use(*,+CommaToken)" - } - }, - { - "type": "custom", - "values": { - "selector": "ClassDeclaration:has(>::name[value=InjectableDecoratorHandler]) MethodDeclaration:has(>::name[value=symbol]),ClassDeclaration:has(>::name[value=InjectableDecoratorHandler]) MethodDeclaration:has(>::name[value=register]),ClassDeclaration:has(>::name[value=InjectableDecoratorHandler]) MethodDeclaration:has(>::name[value=resolve]),ClassDeclaration:has(>::name[value=InjectableDecoratorHandler]) MethodDeclaration:has(>::name[value=compilePartial]),ClassDeclaration:has(>::name[value=InjectableDecoratorHandler]) MethodDeclaration:has(>::name[value=compileLocal])" - } - }, - { - "type": "custom", - "change": "change", - "values": { - "selector": "MethodDeclaration:has(>::name[value=compile]) IfStatement PropertyAccessExpression:has(>::name[value=needsFactory]):has(>::expression[value=analysis])", - "content": "true" - } - }, - { - "type": "custom", - "values": { - "selector": "MethodDeclaration:has(>::name[value=compile]) IfStatement:has(>::expression[value=\"analysis.classMetadata !== null\"])" - } - }, - { - "type": "custom", - "values": { - "selector": "*:has(>::name[value=getDep]) PropertyAssignment:has(>::name[value=host]):use(*,+CommaToken)" - } - }, - { - "type": "custom", - "values": { - "selector": "*:has(>::name[value=compileFull]) Identifier[value=compileClassMetadata]:use(*,+CommaToken)" - } - }, - { - "type": "custom", - "values": { - "selector": "*:has(>::name[value=compile]) Parameter:has(>::name[value=compileClassMetadataFn]):use(*,+CommaToken)" - } - }, - { - "type": "custom", - "values": { - "selector": "*:has(>::name[value=InjectableDecoratorHandler]) Parameter:has(>::name[value=evaluator]):use(*,+CommaToken)" - } - }, - { - "type": "import", - "values": { - "namedImports": [ - "compileClassMetadata", - "CompileClassMetadataFn", - "compileDeclareClassMetadata", - "compileDeclareInjectableFromMetadata", - "R3ClassMetadata", - "InjectableClassRegistry", - "checkInheritanceOfInjectable", - "extractClassMetadata", - "HandlerPrecedence", - "ResolveResult", - "compileDeclareFactory" - ] - } - }, - { - "type": "import", - "values": { - "excludes": [ - "PartialEvaluator", - "PerfEvent" - ] - } - }, - { - "type": "custom", - "values": { - "selector": "*:has(>::name[value=InjectableDecoratorHandler]) HeritageClause LiteralType:use(*,+CommaToken)" - } - } - ] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/imports/src/core.ts", - "rules": [ - { - "type": "variable", - "values": { - "excludes": [ - "CORE_SUPPORTED_SYMBOLS", - "CORE_MODULE" - ] - } - }, - { - "type": "class", - "values": { - "excludes": [ - "R3SymbolsImportRewriter", - "CORE_MODULE" - ] - } - }, - { - "type": "function", - "values": { - "excludes": [ - "validateAndRewriteCoreSymbol" - ] - } - }, - { - "type": "import", - "values": { - "excludes": [ - "relativePathBetween" - ] - } - } - ] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/reflection/src/host.ts", - "rules": [ - { - "type": "interface-method", - "values": { - "selector": "*:has(>::name[value=ReflectionHost])", - "excludes": [ - "getDefinitionOfFunction", - "getDeclarationOfIdentifier", - "getExportsOfModule", - "getVariableValue", - "isStaticallyExported" - ] - } - } - ] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/reflection/src/typescript.ts", - "rules": [ - { - "type": "class-method", - "values": { - "selector": "*:has(>::name[value=TypeScriptReflectionHost])", - "excludes": [ - "getExportsOfModule", - "getDeclarationOfIdentifier", - "getDefinitionOfFunction", - "getVariableValue", - "isStaticallyExported", - "getDeclarationOfSymbol", - "getLocalExportedDeclarationsOfSourceFile" - ] - } - }, - { - "type": "function", - "values": { - "excludes": [ - "reflectNameOfDeclaration", - "reflectIdentifierOfDeclaration", - "reflectTypeEntityToDeclaration", - "filterToMembersWithDecorator", - "findMember" - ] - } - }, - { - "type": "import", - "values": { - "namedImports": [ - "Declaration", - "DeclarationKind", - "FunctionDefinition" - ] - } - } - ] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/transform/index.ts", - "rules": [ - { - "type": "custom", - "change": "change", - "values": { - "selector": "SourceFile", - "content": "export * from './src/api';\nexport * from './src/utils';" - } - } - ] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/transform/src/api.ts", - "rules": [ - { - "change": "change", - "type": "custom", - "values": { - "selector": "ImportDeclaration:has(>StringLiteral[value=\"'@angular/compiler'\"]) StringLiteral", - "content": "'static-injector/transform/compiler'" - } - }, - { - "type": "enum", - "values": { - "excludes": [ - "HandlerPrecedence" - ] - } - }, - { - "type": "interface", - "values": { - "excludes": [ - "ResolveResult", - "DtsTransform" - ] - } - }, - { - "type": "interface-property", - "values": { - "selector": "*:has(>::name[value=DecoratorHandler])", - "excludes": [ - "precedence", - "name" - ] - } - }, - { - "type": "interface-method", - "values": { - "excludes": [ - "updateResources", - "symbol", - "register", - "index", - "resolve", - "xi18n", - "typeCheck", - "extendedTemplateCheck", - "templateSemanticsCheck", - "compilePartial", - "compileLocal" - ] - } - }, - { - "type": "custom", - "values": { - "selector": "*:has(>::name[value=DecoratorHandler]) *:has(>::name[value=compileFull]) Parameter:has(>::name:is([value=resolution],[value=constantPool])):use(*,+CommaToken)" - } - }, - { - "type": "import", - "values": { - "namedImports": [ - "ConstantPool" - ] - } - }, - { - "type": "import", - "values": { - "excludes": [ - "IndexingContext", - "TypeCheckContext", - "ExtendedTemplateChecker", - "Xi18nContext", - "SemanticSymbol", - "ImportManager", - "Reexport", - "TemplateSemanticsChecker" - ] - } - }, - { - "type": "custom", - "values": { - "selector": "InterfaceDeclaration SyntaxList TypeParameter:has(>::name[value=S]):use(*,+CommaToken)" - } - } - ] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/transform/src/utils.ts", - "rules": [] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/translator/src/translator.ts", - "rules": [ - { - "change": "change", - "type": "custom", - "values": { - "selector": "ImportDeclaration:has(>StringLiteral[value=\"'@angular/compiler'\"]) StringLiteral", - "content": "'static-injector/transform/compiler'" - } - }, - { - "type": "class-method", - "values": { - "selector": "*:has(>::name[value=ExpressionTranslatorVisitor])", - "excludes": [ - "visitTaggedTemplateExpr", - "visitLocalizedString", - "createTaggedTemplateExpression", - "createES5TaggedTemplateFunctionCall" - ] - } - }, - { - "type": "function", - "values": { - "excludes": [ - "createTemplateElement" - ] - } - } - ] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/translator/src/typescript_translator.ts", - "rules": [ - { - "change": "change", - "type": "custom", - "values": { - "selector": "ImportDeclaration:has(>StringLiteral[value=\"'@angular/compiler'\"]) StringLiteral", - "content": "'static-injector/transform/compiler'" - } - } - ] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/translator/src/api/ast_factory.ts", - "rules": [] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/util/src/typescript.ts", - "rules": [ - { - "type": "function", - "values": { - "includes": [ - "identifierOfNode" - ] - } - }, - { - "type": "type", - "values": { - "includes": [] - } - }, - { - "type": "interface", - "values": { - "includes": [] - } - }, - { - "type": "import", - "values": { - "excludes": [ - "AbsoluteFsPath", - "DeclarationNode" - ] - } - }, - { - "type": "variable", - "values": { - "excludes": [ - "TS", - "D_TS" - ] - } - } - ] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/annotations/common/src/di.ts", - "rules": [ - { - "change": "change", - "type": "custom", - "values": { - "selector": "ImportDeclaration:has(>StringLiteral[value=\"'@angular/compiler'\"]) StringLiteral", - "content": "'static-injector/transform/compiler'" - } - }, - { - "type": "custom", - "values": { - "selector": "*:has(>::name[value=getConstructorDependencies]) IfStatement CallExpression:has(>::expression[value=deps.push]) ShorthandPropertyAssignment:has(>::name[value=host])" - } - }, - { - "type": "custom", - "change": "change", - "values": { - "selector": "*:has(>::name[value=getConstructorDependencies]) IfStatement:has(>::expression:is([value=\"name === 'Host'\"],[value=\"name === 'Attribute'\"]))>CloseParenToken+Block", - "content": "{}" - } - } - ] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/annotations/common/src/factory.ts", - "rules": [ - { - "change": "change", - "type": "custom", - "values": { - "selector": "ImportDeclaration:has(>StringLiteral[value=\"'@angular/compiler'\"]) StringLiteral", - "content": "'static-injector/transform/compiler'" - } - }, - { - "type": "function", - "values": { - "excludes": [ - "compileDeclareFactory" - ] - } - }, - { - "type": "import", - "values": { - "namedImports": [ - "compileDeclareFactoryFunction" - ] - } - } - ] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/imports/src/default.ts", - "rules": [ - { - "change": "change", - "type": "custom", - "values": { - "selector": "ImportDeclaration:has(>StringLiteral[value=\"'@angular/compiler'\"]) StringLiteral", - "content": "'static-injector/transform/compiler'" - } - }, - { - "type": "class", - "values": { - "excludes": [ - "DefaultImportTracker" - ] - } - }, - { - "type": "import", - "values": { - "excludes": [ - "getSourceFile", - "loadIsReferencedAliasDeclarationPatch" - ] - } - } - ] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/annotations/common/index.ts", - "rules": [ - { - "change": "change", - "type": "custom", - "values": { - "selector": "SourceFile", - "content": "export * from './src/di';\nexport * from './src/factory';\nexport * from './src/util';" - } - } - ] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/diagnostics/index.ts", - "rules": [ - { - "change": "change", - "type": "custom", - "values": { - "selector": "SourceFile", - "content": "export * from './error';\nexport * from './error_code';" - } - } - ] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/imports/index.ts", - "rules": [ - { - "change": "change", - "type": "custom", - "values": { - "selector": "SourceFile", - "content": "export * from './src/core';" - } - } - ] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/reflection/index.ts", - "rules": [ - { - "change": "change", - "type": "custom", - "values": { - "selector": "SourceFile", - "content": "export * from './src/host';\nexport * from './src/typescript';\nexport * from './src/util';" - } - } - ] - }, - { - "fileName": "./transform/compiler-cli/src/ngtsc/translator/index.ts", - "rules": [ - { - "change": "change", - "type": "custom", - "values": { - "selector": "SourceFile", - "content": "export * from './src/context';\nexport * from './src/translator';\nexport * from './src/typescript_ast_factory';\nexport * from './src/typescript_translator';\nexport * from './src/import_manager';" - } - } - ] - }, { "fileName": "./import/di/create_injector.ts", "rules": [] @@ -1288,11 +93,11 @@ } }, { - "type": "custom", - "change": "change", + "type": "variable", "values": { - "selector": "VariableDeclaration:has(>::name[value=Injectable])>CallExpression", - "content": "undefined as any" + "excludes": [ + "Injectable" + ] } } ] @@ -1433,7 +238,8 @@ "values": { "excludes": [ "getComponentDef", - "throwCyclicDependencyError" + "throwCyclicDependencyError", + "deepForEach" ] } }, @@ -1460,6 +266,7 @@ "type": "import", "values": { "excludes": [ + "newArray", "getComponentDef", "throwCyclicDependencyError", "emitInstanceCreatedByInjectorEvent", @@ -1521,7 +328,7 @@ "type": "custom", "change": "change", "values": { - "selector": "*:has(>::name[value=getInjectableDef]) Identifier[value=NG_INJECTABLE_DEF]::name[value=getInheritedInjectableDef]) ElementAccessExpression:has([value*=NG_INJECTABLE_DEF])", "content": "null" } }, @@ -1529,16 +336,16 @@ "type": "custom", "change": "change", "values": { - "selector": "*:has(>::name[value=getInheritedInjectableDef]) ElementAccessExpression:has([value*=NG_INJECTABLE_DEF])", - "content": "null" + "selector": "*:has(>::name[value=getInjectorDef]) Identifier[value=NG_INJECTOR_DEF]::name[value=getInjectorDef]) Identifier[value=NG_INJECTOR_DEF]Identifier[value=getInjectableDef])>Block", + "content": "{return getOwnDefinition(type, NG_PROV_DEF) ||{ token:type,factory:()=>new type(),...type.injectOptions}}" } } ] @@ -1599,110 +406,38 @@ }, { "fileName": "./import/render3/definition_factory.ts", - "rules": [] - }, - { - "fileName": "./import/render3/di.ts", "rules": [ { - "type": "import", - "values": { - "excludes": [ - "InjectorMarkers", - "assertDefined", - "assertDirectiveDef", - "registerPreOrderHooks", - "DirectiveDef", - "isFactory", - "AttributeMarker", - "isComponentDef", - "DECLARATION_COMPONENT_VIEW", - "assertTNodeType", - "enterDI", - "isNameOnlyAttributeMarker", - "getParentInjectorIndex", - "throwCyclicDependencyError", - "stringifyForError", - "ProviderToken", - "injectRootLimpMode", - "emitInstanceCreatedByInjectorEvent", - "InjectorProfilerContext", - "runInInjectorProfilerContext", - "setInjectorProfilerContext", - "TContainerNode" - ] - } - }, - { - "type": "import", - "values": { - "namedImports": [ - "NG_ELEMENT_ID" - ] - } - }, - { - "type": "variable", + "type": "custom", + "change": "change", "values": { - "excludes": [ - "includeViewProviders", - "BLOOM_SIZE", - "BLOOM_MASK", - "BLOOM_BUCKET_BITS", - "nextNgElementId", - "NOT_FOUND" - ] + "selector": "FunctionDeclaration:has(>Identifier[value=getFactoryDef])>Block", + "content": "{return ()=>new type()}" } - }, + } + ] + }, + { + "fileName": "./import/render3/errors_di.ts", + "rules": [ { "type": "function", "values": { - "excludes": [ - "setIncludeViewProviders", - "bloomAdd", - "getOrCreateNodeInjectorForNode", - "getInjectorIndex", - "getParentInjectorLocation", - "diPublicInInjector", - "injectAttributeImpl", - "notFoundValueOrThrow", - "lookupTokenUsingModuleInjector", - "getOrCreateInjectable", - "lookupTokenUsingNodeInjector", - "searchTokensOnInjector", - "locateDirectiveOrProvider", - "getNodeInjectable", - "bloomHashBitOrFactory", - "bloomHasToken", - "shouldSearchParent", - "NodeInjector", - "createNodeInjector", - "lookupTokenUsingEmbeddedInjector", - "getTNodeFromLView", - "insertBloom", - "getNodeInjectorLView", - "getNodeInjectorTNode" - ] - } - }, - { - "type": "class", - "values": { - "excludes": [ - "NodeInjector" + "includes": [ + "throwProviderNotFoundError" ] } } ] }, { - "fileName": "./import/render3/errors_di.ts", + "fileName": "./import/errors.ts", "rules": [ { - "type": "function", + "type": "import", "values": { - "includes": [ - "throwProviderNotFoundError" + "excludes": [ + "ERROR_DETAILS_PAGE_BASE_URL" ] } } @@ -1774,28 +509,6 @@ } ] }, - { - "fileName": "./import/util/array_utils.ts", - "rules": [ - { - "type": "import", - "values": { - "excludes": [ - "assertEqual" - ] - } - }, - { - "type": "function", - "values": { - "includes": [ - "newArray", - "deepForEach" - ] - } - } - ] - }, { "fileName": "./import/util/closure.ts", "rules": [] @@ -1820,6 +533,22 @@ "PROP_METADATA" ] } + }, + { + "type": "custom", + "change": "change", + "values": { + "comment":"装饰器已经去掉,所以这个函数如果调用,一定是通过new Self()这种方式", + "selector": "FunctionDeclaration:has(>Identifier[value=ParamDecoratorFactory])>Block", + "replaceSelector":"IfStatement Block" + } + }, + { + "type": "custom", + "change": "remove", + "values": { + "selector": "ExpressionStatement:like(ParamDecoratorFactory.prototype),ExpressionStatement:like(annotationCls)" + } } ] }, diff --git a/script/sync/index.ts b/script/sync/index.ts index 1c0cfa0..dc04801 100644 --- a/script/sync/index.ts +++ b/script/sync/index.ts @@ -13,6 +13,7 @@ const typeMap = { 'interface-property': 'PropertySignature', 'class-method': 'MethodDeclaration', 'enum-member': 'EnumMember', + 'variable':'VariableDeclaration' }; function importDeclarationByNamed(list: string[]) { let listStr = list.map((item) => `[value=${item}]`).join(','); @@ -43,8 +44,6 @@ let fn: ScriptFunction = async (util, rule, host, injector) => { let data = await rule.os.gitClone( 'https://github.com/angular/angular.git', [ - '/packages/compiler', - '/packages/compiler-cli', '/packages/core/src', '!**/*.bazel', '!**/*spec.ts', @@ -53,7 +52,7 @@ let fn: ScriptFunction = async (util, rule, host, injector) => { ], 'packages', 'branch', - '17.3.1' + '17.3.6' ); let copyData = require('./copy.json') as { source: string; diff --git a/src/import/di/injectable.ts b/src/import/di/injectable.ts index 7f0f9bf..50f10b6 100644 --- a/src/import/di/injectable.ts +++ b/src/import/di/injectable.ts @@ -96,11 +96,3 @@ export interface Injectable { */ providedIn?: Type | 'root' | 'platform' | 'any' | null; } - -/** - * Injectable decorator and metadata. - * - * @Annotation - * @publicApi - */ -export const Injectable: InjectableDecorator = undefined as any; diff --git a/src/import/di/injector_compatibility.ts b/src/import/di/injector_compatibility.ts index 28a3fc5..7841022 100644 --- a/src/import/di/injector_compatibility.ts +++ b/src/import/di/injector_compatibility.ts @@ -406,7 +406,8 @@ export function formatError( } context = `{${parts.join(', ')}}`; } - return `${injectorErrorName}${ - source ? '(' + source + ')' : '' - }[${context}]: ${text.replace(NEW_LINE, '\n ')}`; + return `${injectorErrorName}${source ? '(' + source + ')' : ''}[${context}]: ${text.replace( + NEW_LINE, + '\n ', + )}`; } diff --git a/src/import/di/interface/defs.ts b/src/import/di/interface/defs.ts index 5095c1f..d14a477 100644 --- a/src/import/di/interface/defs.ts +++ b/src/import/di/interface/defs.ts @@ -215,7 +215,13 @@ export function ɵɵdefineInjector(options: { export function getInjectableDef( type: any, ): ɵɵInjectableDeclaration | null { - return getOwnDefinition(type, NG_PROV_DEF) || null; + return ( + getOwnDefinition(type, NG_PROV_DEF) || { + token: type, + factory: () => new type(), + ...type.injectOptions, + } + ); } export function isInjectable(type: any): boolean { diff --git a/src/import/di/provider_collection.ts b/src/import/di/provider_collection.ts index e748cc7..a25fdc2 100644 --- a/src/import/di/provider_collection.ts +++ b/src/import/di/provider_collection.ts @@ -12,7 +12,7 @@ import { Type } from '../interface/type'; import { getFactoryDef } from '../render3/definition_factory'; import { stringifyForError } from '../render3/util/stringify_utils'; -import { deepForEach } from '../util/array_utils'; + import { EMPTY_ARRAY } from '../util/empty'; import { getClosureSafeProperty } from '../util/property'; import { stringify } from '../util/stringify'; diff --git a/src/import/di/r3_injector.ts b/src/import/di/r3_injector.ts index 13ba3ee..fa35b44 100644 --- a/src/import/di/r3_injector.ts +++ b/src/import/di/r3_injector.ts @@ -13,7 +13,7 @@ import { Type } from '../interface/type'; import { FactoryFn, getFactoryDef } from '../render3/definition_factory'; import { NG_ENV_ID } from '../render3/fields'; -import { newArray } from '../util/array_utils'; + import { EMPTY_ARRAY } from '../util/empty'; import { stringify } from '../util/stringify'; diff --git a/src/import/error_details_base_url.ts b/src/import/error_details_base_url.ts deleted file mode 100644 index 417f681..0000000 --- a/src/import/error_details_base_url.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -/** - * Base URL for the error details page. - * - * Keep this constant in sync across: - * - packages/compiler-cli/src/ngtsc/diagnostics/src/error_details_base_url.ts - * - packages/core/src/error_details_base_url.ts - */ -export const ERROR_DETAILS_PAGE_BASE_URL = 'https://angular.io/errors'; - -/** - * URL for the XSS security documentation. - */ -export const XSS_SECURITY_URL = 'https://g.co/ng/security#xss'; diff --git a/src/import/errors.ts b/src/import/errors.ts index 717ae0d..8c67c53 100644 --- a/src/import/errors.ts +++ b/src/import/errors.ts @@ -6,8 +6,6 @@ * found in the LICENSE file at https://angular.io/license */ -import { ERROR_DETAILS_PAGE_BASE_URL } from './error_details_base_url'; - /** * The list of error codes used in runtime code of the `core` package. * Reserved error code range: 100-999. diff --git a/src/import/index.ts b/src/import/index.ts index 61a583d..2790bb7 100644 --- a/src/import/index.ts +++ b/src/import/index.ts @@ -9,4 +9,3 @@ export * from './di/injector'; export * from './di/interface/injector'; export * from './di/scope'; export * from './render3/instructions/di'; -export * from './render3/di'; diff --git a/src/import/render3/definition_factory.ts b/src/import/render3/definition_factory.ts index 23bd833..db4e543 100644 --- a/src/import/render3/definition_factory.ts +++ b/src/import/render3/definition_factory.ts @@ -32,8 +32,5 @@ export function getFactoryDef( type: any, throwNotFound?: boolean, ): FactoryFn | null { - const hasFactoryDef = type.hasOwnProperty(NG_FACTORY_DEF); - if (false) { - } - return hasFactoryDef ? type[NG_FACTORY_DEF] : null; + return () => new type(); } diff --git a/src/import/render3/di.ts b/src/import/render3/di.ts deleted file mode 100644 index 303ba58..0000000 --- a/src/import/render3/di.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { isForwardRef, resolveForwardRef } from '../di/forward_ref'; - -import { Injector } from '../di/injector'; -import { convertToBitFlags } from '../di/injector_compatibility'; - -import { InjectFlags, InjectOptions } from '../di/interface/injector'; - -import { Type } from '../interface/type'; - -import { noSideEffects } from '../util/closure'; - -import { getFactoryDef } from './definition_factory'; - -import { NG_FACTORY_DEF } from './fields'; - -/** - * @codeGenApi - */ -export function ɵɵgetInheritedFactory( - type: Type, -): (type: Type) => T { - return noSideEffects(() => { - const ownConstructor = type.prototype.constructor; - const ownFactory = - ownConstructor[NG_FACTORY_DEF] || getFactoryOf(ownConstructor); - const objectPrototype = Object.prototype; - let parent = Object.getPrototypeOf(type.prototype).constructor; - - // Go up the prototype until we hit `Object`. - while (parent && parent !== objectPrototype) { - const factory = parent[NG_FACTORY_DEF] || getFactoryOf(parent); - - // If we hit something that has a factory and the factory isn't the same as the type, - // we've found the inherited factory. Note the check that the factory isn't the type's - // own factory is redundant in most cases, but if the user has custom decorators on the - // class, this lookup will start one level down in the prototype chain, causing us to - // find the own factory first and potentially triggering an infinite loop downstream. - if (factory && factory !== ownFactory) { - return factory; - } - - parent = Object.getPrototypeOf(parent); - } - - // There is no factory defined. Either this was improper usage of inheritance - // (no Angular decorator on the superclass) or there is no constructor at all - // in the inheritance chain. Since the two cases cannot be distinguished, the - // latter has to be assumed. - return (t: Type) => new t(); - }); -} - -function getFactoryOf( - type: Type, -): ((type?: Type) => T | null) | null { - if (isForwardRef(type)) { - return () => { - const factory = getFactoryOf(resolveForwardRef(type)); - return factory && factory(); - }; - } - return getFactoryDef(type); -} diff --git a/src/import/render3/error_code.ts b/src/import/render3/error_code.ts deleted file mode 100644 index 4b2c237..0000000 --- a/src/import/render3/error_code.ts +++ /dev/null @@ -1,70 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -// Base URL for the error details page. -// Keep this value in sync with a similar const in -// `packages/compiler-cli/src/ngtsc/diagnostics/src/error_code.ts`. - -export const enum RuntimeErrorCode { - // Internal Errors - - // Change Detection Errors - EXPRESSION_CHANGED_AFTER_CHECKED = '100', - - // Dependency Injection Errors - CYCLIC_DI_DEPENDENCY = '200', - PROVIDER_NOT_FOUND = '201', - - // Template Errors - MULTIPLE_COMPONENTS_MATCH = '300', - EXPORT_NOT_FOUND = '301', - PIPE_NOT_FOUND = '302', - UNKNOWN_BINDING = '303', - UNKNOWN_ELEMENT = '304', - TEMPLATE_STRUCTURE_ERROR = '305', - - // Styling Errors - - // Declarations Errors - - // i18n Errors - - // Compilation Errors -} - -export class RuntimeError extends Error { - constructor( - public code: RuntimeErrorCode, - message: string, - ) { - super(formatRuntimeError(code, message)); - } -} - -/* tslint:enable:no-toplevel-property-access */ - -/** Called to format a runtime error */ -export function formatRuntimeError( - code: RuntimeErrorCode, - message: string, -): string { - const fullCode = code ? `NG0${code}: ` : ''; - - let errorMessage = `${fullCode}${message}`; - - // Some runtime errors are still thrown without `ngDevMode` (for example - // `throwProviderNotFoundError`), so we add `ngDevMode` check here to avoid pulling - // `RUNTIME_ERRORS_WITH_GUIDES` symbol into prod bundles. - // TODO: revisit all instances where `RuntimeError` is thrown and see if `ngDevMode` can be added - // there instead to tree-shake more devmode-only code (and eventually remove `ngDevMode` check - // from this code). - // if (ngDevMode && RUNTIME_ERRORS_WITH_GUIDES.has(code)) { - // errorMessage = `${errorMessage}. Find more at ${ERROR_DETAILS_PAGE_BASE_URL}/NG0${code}`; - // } - return errorMessage; -} diff --git a/src/import/util/array_utils.ts b/src/import/util/array_utils.ts deleted file mode 100644 index 3d773fe..0000000 --- a/src/import/util/array_utils.ts +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -export function deepForEach( - input: (T | any[])[], - fn: (value: T) => void, -): void { - input.forEach((value) => - Array.isArray(value) ? deepForEach(value, fn) : fn(value), - ); -} - -export function newArray(size: number): T[]; -export function newArray(size: number, value: T): T[]; -export function newArray(size: number, value?: T): T[] { - const list: T[] = []; - for (let i = 0; i < size; i++) { - list.push(value!); - } - return list; -} - -/** - * `KeyValueArray` is an array where even positions contain keys and odd positions contain values. - * - * `KeyValueArray` provides a very efficient way of iterating over its contents. For small - * sets (~10) the cost of binary searching an `KeyValueArray` has about the same performance - * characteristics that of a `Map` with significantly better memory footprint. - * - * If used as a `Map` the keys are stored in alphabetical order so that they can be binary searched - * for retrieval. - * - * See: `keyValueArraySet`, `keyValueArrayGet`, `keyValueArrayIndexOf`, `keyValueArrayDelete`. - */ -export interface KeyValueArray extends Array { - __brand__: 'array-map'; -} diff --git a/src/import/util/decorators.ts b/src/import/util/decorators.ts index 39b36af..92478dc 100644 --- a/src/import/util/decorators.ts +++ b/src/import/util/decorators.ts @@ -64,37 +64,12 @@ export function makeParamDecorator( this: unknown | typeof ParamDecoratorFactory, ...args: any[] ): any { - if (this instanceof ParamDecoratorFactory) { - metaCtor.apply(this, args); - return this; - } - const annotationInstance = new (ParamDecoratorFactory)(...args); - - (ParamDecorator).annotation = annotationInstance; - return ParamDecorator; - - function ParamDecorator(cls: any, unusedKey: any, index: number): any { - // Use of Object.defineProperty is important since it creates non-enumerable property which - // prevents the property is copied during subclassing. - const parameters = cls.hasOwnProperty(PARAMETERS) - ? (cls as any)[PARAMETERS] - : Object.defineProperty(cls, PARAMETERS, { value: [] })[PARAMETERS]; - - // there might be gaps if some in between parameters do not have annotations. - // we pad with nulls. - while (parameters.length <= index) { - parameters.push(null); - } - - (parameters[index] = parameters[index] || []).push(annotationInstance); - return cls; - } + metaCtor.apply(this, args); + return this; } if (parentClass) { - ParamDecoratorFactory.prototype = Object.create(parentClass.prototype); } - ParamDecoratorFactory.prototype.ngMetadataName = name; - (ParamDecoratorFactory).annotationCls = ParamDecoratorFactory; + return ParamDecoratorFactory; }); } diff --git a/src/package.json b/src/package.json index 1f33cb9..f89f745 100644 --- a/src/package.json +++ b/src/package.json @@ -1,17 +1,22 @@ { "name": "static-injector", - "version": "4.0.2", + "version": "5.0.0-alpha.0", "description": "Angular 依赖注入独立版本;Angular dependency injection standalone version", "keywords": [ "angular", - "angular 17.3.1", + "angular 17.3.6", "injector", "typescript", - "typescript 5.4.2", "injectable", "static-inject", "dependency injection", - "injection-js" + "injection-js", + "dependency inversion", + "di", + "inversion of control container", + "ioc", + "javascript", + "node" ], "repository": { "type": "git", @@ -21,19 +26,17 @@ "url": "https://github.com/wszgrcy/static-injector/issues" }, "homepage": "https://github.com/wszgrcy/static-injector#readme", - "main": "import/commonjs/index.js", - "es2022": "import/fesm2022/index.js", - "fesm2022": "import/fesm2022/index.js", - "esm2022": "import/esm2022/index.js", - "module": "import/fesm2022/index.js", - "typings": "import/typings/index.d.ts", + "main": "commonjs/index.js", + "es2022": "fesm2022/index.js", + "fesm2022": "fesm2022/index.js", + "esm2022": "esm2022/index.js", + "module": "fesm2022/index.js", + "typings": "typings/index.d.ts", "private": false, "scripts": {}, "author": "wszgrcy", "license": "MIT", - "peerDependencies": { - "typescript": ">=5.0.0" - }, + "peerDependencies": {}, "devDependencies": {}, "sideEffects": false -} \ No newline at end of file +} diff --git a/src/transform/compiler-cli/src/ngtsc/annotations/common/index.ts b/src/transform/compiler-cli/src/ngtsc/annotations/common/index.ts deleted file mode 100644 index a2d2e6f..0000000 --- a/src/transform/compiler-cli/src/ngtsc/annotations/common/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './src/di'; -export * from './src/factory'; -export * from './src/util'; diff --git a/src/transform/compiler-cli/src/ngtsc/annotations/common/src/di.ts b/src/transform/compiler-cli/src/ngtsc/annotations/common/src/di.ts deleted file mode 100644 index e0a0f3e..0000000 --- a/src/transform/compiler-cli/src/ngtsc/annotations/common/src/di.ts +++ /dev/null @@ -1,283 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { - Expression, - LiteralExpr, - R3DependencyMetadata, - WrappedNodeExpr, -} from 'static-injector/transform/compiler'; -import ts from 'typescript'; - -import { - ErrorCode, - FatalDiagnosticError, - makeRelatedInformation, -} from '../../../diagnostics'; -import { - ClassDeclaration, - CtorParameter, - ReflectionHost, - TypeValueReferenceKind, - UnavailableValue, - ValueUnavailableKind, -} from '../../../reflection'; - -import { isAngularCore, valueReferenceToExpression } from './util'; - -export type ConstructorDeps = - | { - deps: R3DependencyMetadata[]; - } - | { - deps: null; - errors: ConstructorDepError[]; - }; - -export interface ConstructorDepError { - index: number; - param: CtorParameter; - reason: UnavailableValue; -} - -export function getConstructorDependencies( - clazz: ClassDeclaration, - reflector: ReflectionHost, - isCore: boolean, -): ConstructorDeps | null { - const deps: R3DependencyMetadata[] = []; - const errors: ConstructorDepError[] = []; - let ctorParams = reflector.getConstructorParameters(clazz); - if (ctorParams === null) { - if (reflector.hasBaseClass(clazz)) { - return null; - } else { - ctorParams = []; - } - } - ctorParams.forEach((param, idx) => { - let token = valueReferenceToExpression(param.typeValueReference); - - let attributeNameType: Expression | null = null; - let optional = false, - self = false, - skipSelf = false, - host = false; - - (param.decorators || []) - .filter((dec) => isCore || isAngularCore(dec)) - .forEach((dec) => { - const name = - isCore || dec.import === null ? dec.name : dec.import!.name; - if (name === 'Inject') { - if (dec.args === null || dec.args.length !== 1) { - throw new FatalDiagnosticError( - ErrorCode.DECORATOR_ARITY_WRONG, - dec.node, - `Unexpected number of arguments to @Inject().`, - ); - } - token = new WrappedNodeExpr(dec.args[0]); - } else if (name === 'Optional') { - optional = true; - } else if (name === 'SkipSelf') { - skipSelf = true; - } else if (name === 'Self') { - self = true; - } else if (name === 'Host') { - } else if (name === 'Attribute') { - } else { - throw new FatalDiagnosticError( - ErrorCode.DECORATOR_UNEXPECTED, - dec.node, - `Unexpected decorator ${name} on parameter.`, - ); - } - }); - - if (token === null) { - if ( - param.typeValueReference.kind !== TypeValueReferenceKind.UNAVAILABLE - ) { - throw new Error( - 'Illegal state: expected value reference to be unavailable if no token is present', - ); - } - errors.push({ - index: idx, - param, - reason: param.typeValueReference.reason, - }); - } else { - deps.push({ token, attributeNameType, optional, self, skipSelf }); - } - }); - - if (errors.length === 0) { - return { deps }; - } else { - return { deps: null, errors }; - } -} - -/** - * Convert `ConstructorDeps` into the `R3DependencyMetadata` array for those deps if they're valid, - * or into an `'invalid'` signal if they're not. - * - * This is a companion function to `validateConstructorDependencies` which accepts invalid deps. - */ -export function unwrapConstructorDependencies( - deps: ConstructorDeps | null, -): R3DependencyMetadata[] | 'invalid' | null { - if (deps === null) { - return null; - } else if (deps.deps !== null) { - // These constructor dependencies are valid. - return deps.deps; - } else { - // These deps are invalid. - return 'invalid'; - } -} - -export function getValidConstructorDependencies( - clazz: ClassDeclaration, - reflector: ReflectionHost, - isCore: boolean, -): R3DependencyMetadata[] | null { - return validateConstructorDependencies( - clazz, - getConstructorDependencies(clazz, reflector, isCore), - ); -} - -/** - * Validate that `ConstructorDeps` does not have any invalid dependencies and convert them into the - * `R3DependencyMetadata` array if so, or raise a diagnostic if some deps are invalid. - * - * This is a companion function to `unwrapConstructorDependencies` which does not accept invalid - * deps. - */ -export function validateConstructorDependencies( - clazz: ClassDeclaration, - deps: ConstructorDeps | null, -): R3DependencyMetadata[] | null { - if (deps === null) { - return null; - } else if (deps.deps !== null) { - return deps.deps; - } else { - // There is at least one error. - const error = deps.errors[0]; - throw createUnsuitableInjectionTokenError(clazz, error); - } -} - -/** - * Creates a fatal error with diagnostic for an invalid injection token. - * @param clazz The class for which the injection token was unavailable. - * @param error The reason why no valid injection token is available. - */ -function createUnsuitableInjectionTokenError( - clazz: ClassDeclaration, - error: ConstructorDepError, -): FatalDiagnosticError { - const { param, index, reason } = error; - let chainMessage: string | undefined = undefined; - let hints: ts.DiagnosticRelatedInformation[] | undefined = undefined; - switch (reason.kind) { - case ValueUnavailableKind.UNSUPPORTED: - chainMessage = - 'Consider using the @Inject decorator to specify an injection token.'; - hints = [ - makeRelatedInformation( - reason.typeNode, - 'This type is not supported as injection token.', - ), - ]; - break; - case ValueUnavailableKind.NO_VALUE_DECLARATION: - chainMessage = - 'Consider using the @Inject decorator to specify an injection token.'; - hints = [ - makeRelatedInformation( - reason.typeNode, - 'This type does not have a value, so it cannot be used as injection token.', - ), - ]; - if (reason.decl !== null) { - hints.push( - makeRelatedInformation(reason.decl, 'The type is declared here.'), - ); - } - break; - case ValueUnavailableKind.TYPE_ONLY_IMPORT: - chainMessage = - 'Consider changing the type-only import to a regular import, or use the @Inject decorator to specify an injection token.'; - hints = [ - makeRelatedInformation( - reason.typeNode, - 'This type is imported using a type-only import, which prevents it from being usable as an injection token.', - ), - makeRelatedInformation( - reason.node, - 'The type-only import occurs here.', - ), - ]; - break; - case ValueUnavailableKind.NAMESPACE: - chainMessage = - 'Consider using the @Inject decorator to specify an injection token.'; - hints = [ - makeRelatedInformation( - reason.typeNode, - 'This type corresponds with a namespace, which cannot be used as injection token.', - ), - makeRelatedInformation( - reason.importClause, - 'The namespace import occurs here.', - ), - ]; - break; - case ValueUnavailableKind.UNKNOWN_REFERENCE: - chainMessage = 'The type should reference a known declaration.'; - hints = [ - makeRelatedInformation( - reason.typeNode, - 'This type could not be resolved.', - ), - ]; - break; - case ValueUnavailableKind.MISSING_TYPE: - chainMessage = - 'Consider adding a type to the parameter or use the @Inject decorator to specify an injection token.'; - break; - } - - const chain: ts.DiagnosticMessageChain = { - messageText: `No suitable injection token for parameter '${ - param.name || index - }' of class '${clazz.name.text}'.`, - category: ts.DiagnosticCategory.Error, - code: 0, - next: [ - { - messageText: chainMessage, - category: ts.DiagnosticCategory.Message, - code: 0, - }, - ], - }; - - return new FatalDiagnosticError( - ErrorCode.PARAM_MISSING_TOKEN, - param.nameNode, - chain, - hints, - ); -} diff --git a/src/transform/compiler-cli/src/ngtsc/annotations/common/src/factory.ts b/src/transform/compiler-cli/src/ngtsc/annotations/common/src/factory.ts deleted file mode 100644 index e634176..0000000 --- a/src/transform/compiler-cli/src/ngtsc/annotations/common/src/factory.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { - compileFactoryFunction, - R3FactoryMetadata, -} from 'static-injector/transform/compiler'; - -import { CompileResult } from '../../../transform'; - -export type CompileFactoryFn = (metadata: R3FactoryMetadata) => CompileResult; - -export function compileNgFactoryDefField( - metadata: R3FactoryMetadata, -): CompileResult { - const res = compileFactoryFunction(metadata); - return { - name: 'ɵfac', - initializer: res.expression, - statements: res.statements, - type: res.type, - deferrableImports: null, - }; -} diff --git a/src/transform/compiler-cli/src/ngtsc/annotations/common/src/util.ts b/src/transform/compiler-cli/src/ngtsc/annotations/common/src/util.ts deleted file mode 100644 index 6781a11..0000000 --- a/src/transform/compiler-cli/src/ngtsc/annotations/common/src/util.ts +++ /dev/null @@ -1,261 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { - Expression, - ExternalExpr, - FactoryTarget, - ParseLocation, - ParseSourceFile, - ParseSourceSpan, - R3CompiledExpression, - R3FactoryMetadata, - R3Reference, - ReadPropExpr, - Statement, - WrappedNodeExpr, -} from 'static-injector/transform/compiler'; -import ts from 'typescript'; - -import { attachDefaultImportDeclaration } from '../../../imports/src/default'; - -import { - ClassDeclaration, - Decorator, - Import, - ImportedTypeValueReference, - LocalTypeValueReference, - ReflectionHost, - TypeValueReference, - TypeValueReferenceKind, -} from '../../../reflection'; - -/** Module name of the framework core. */ -export const CORE_MODULE = 'static-injector'; - -/** - * Convert a `TypeValueReference` to an `Expression` which refers to the type as a value. - * - * Local references are converted to a `WrappedNodeExpr` of the TypeScript expression, and non-local - * references are converted to an `ExternalExpr`. Note that this is only valid in the context of the - * file in which the `TypeValueReference` originated. - */ -export function valueReferenceToExpression( - valueRef: LocalTypeValueReference | ImportedTypeValueReference, -): Expression; -export function valueReferenceToExpression( - valueRef: TypeValueReference, -): Expression | null; -export function valueReferenceToExpression( - valueRef: TypeValueReference, -): Expression | null { - if (valueRef.kind === TypeValueReferenceKind.UNAVAILABLE) { - return null; - } else if (valueRef.kind === TypeValueReferenceKind.LOCAL) { - const expr = new WrappedNodeExpr(valueRef.expression); - - return expr; - } else { - let importExpr: Expression = new ExternalExpr({ - moduleName: valueRef.moduleName, - name: valueRef.importedName, - }); - if (valueRef.nestedPath !== null) { - for (const property of valueRef.nestedPath) { - importExpr = new ReadPropExpr(importExpr, property); - } - } - return importExpr; - } -} - -export function isAngularCore( - decorator: Decorator, -): decorator is Decorator & { import: Import } { - return decorator.import !== null && decorator.import.from === CORE_MODULE; -} - -export function findAngularDecorator( - decorators: Decorator[], - name: string, - isCore: boolean, -): Decorator | undefined { - return decorators.find((decorator) => - isAngularDecorator(decorator, name, isCore), - ); -} - -export function isAngularDecorator( - decorator: Decorator, - name: string, - isCore: boolean, -): boolean { - if (isCore) { - return decorator.name === name; - } else if (isAngularCore(decorator)) { - return decorator.import.name === name; - } - return false; -} - -export function getAngularDecorators( - decorators: Decorator[], - names: readonly string[], - isCore: boolean, -) { - return decorators.filter((decorator) => { - const name = isCore ? decorator.name : decorator.import?.name; - if (name === undefined || !names.includes(name)) { - return false; - } - return isCore || isAngularCore(decorator); - }); -} - -/** - * Unwrap a `ts.Expression`, removing outer type-casts or parentheses until the expression is in its - * lowest level form. - * - * For example, the expression "(foo as Type)" unwraps to "foo". - */ -export function unwrapExpression(node: ts.Expression): ts.Expression { - while (ts.isAsExpression(node) || ts.isParenthesizedExpression(node)) { - node = node.expression; - } - return node; -} - -function expandForwardRef(arg: ts.Expression): ts.Expression | null { - arg = unwrapExpression(arg); - if (!ts.isArrowFunction(arg) && !ts.isFunctionExpression(arg)) { - return null; - } - - const body = arg.body; - // Either the body is a ts.Expression directly, or a block with a single return statement. - if (ts.isBlock(body)) { - // Block body - look for a single return statement. - if (body.statements.length !== 1) { - return null; - } - const stmt = body.statements[0]; - if (!ts.isReturnStatement(stmt) || stmt.expression === undefined) { - return null; - } - return stmt.expression; - } else { - // Shorthand body - return as an expression. - return body; - } -} - -/** - * If the given `node` is a forwardRef() expression then resolve its inner value, otherwise return - * `null`. - * - * @param node the forwardRef() expression to resolve - * @param reflector a ReflectionHost - * @returns the resolved expression, if the original expression was a forwardRef(), or `null` - * otherwise. - */ -export function tryUnwrapForwardRef( - node: ts.Expression, - reflector: ReflectionHost, -): ts.Expression | null { - node = unwrapExpression(node); - if (!ts.isCallExpression(node) || node.arguments.length !== 1) { - return null; - } - - const fn = ts.isPropertyAccessExpression(node.expression) - ? node.expression.name - : node.expression; - if (!ts.isIdentifier(fn)) { - return null; - } - - const expr = expandForwardRef(node.arguments[0]); - if (expr === null) { - return null; - } - - const imp = reflector.getImportOfIdentifier(fn); - if ( - imp === null || - imp.from !== 'static-injector' || - imp.name !== 'forwardRef' - ) { - return null; - } - - return expr; -} - -const parensWrapperTransformerFactory: ts.TransformerFactory = ( - context: ts.TransformationContext, -) => { - const visitor: ts.Visitor = (node: ts.Node): ts.Node => { - const visited = ts.visitEachChild(node, visitor, context); - if (ts.isArrowFunction(visited) || ts.isFunctionExpression(visited)) { - return ts.factory.createParenthesizedExpression(visited); - } - return visited; - }; - return (node: ts.Expression) => ts.visitEachChild(node, visitor, context); -}; - -/** - * Wraps all functions in a given expression in parentheses. This is needed to avoid problems - * where Tsickle annotations added between analyse and transform phases in Angular may trigger - * automatic semicolon insertion, e.g. if a function is the expression in a `return` statement. - * More - * info can be found in Tsickle source code here: - * https://github.com/angular/tsickle/blob/d7974262571c8a17d684e5ba07680e1b1993afdd/src/jsdoc_transformer.ts#L1021 - * - * @param expression Expression where functions should be wrapped in parentheses - */ -export function wrapFunctionExpressionsInParens( - expression: ts.Expression, -): ts.Expression { - return ts.transform(expression, [parensWrapperTransformerFactory]) - .transformed[0]; -} - -/** - * Create an R3Reference for a class. - * - * The `value` is the exported declaration of the class from its source file. - * The `type` is an expression that would be used in the typings (.d.ts) files. - */ -export function wrapTypeReference( - reflector: ReflectionHost, - clazz: ClassDeclaration, -): R3Reference { - const value = new WrappedNodeExpr(clazz.name); - const type = value; - return { value, type }; -} - -export function toFactoryMetadata( - meta: Omit, - target: FactoryTarget, -): R3FactoryMetadata { - return { - name: meta.name, - type: meta.type, - typeArgumentCount: meta.typeArgumentCount, - deps: meta.deps, - target, - }; -} - -export function isAbstractClassDeclaration(clazz: ClassDeclaration): boolean { - return ts.canHaveModifiers(clazz) && clazz.modifiers !== undefined - ? clazz.modifiers.some((mod) => mod.kind === ts.SyntaxKind.AbstractKeyword) - : false; -} diff --git a/src/transform/compiler-cli/src/ngtsc/annotations/src/injectable.ts b/src/transform/compiler-cli/src/ngtsc/annotations/src/injectable.ts deleted file mode 100644 index e0c55df..0000000 --- a/src/transform/compiler-cli/src/ngtsc/annotations/src/injectable.ts +++ /dev/null @@ -1,428 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { - compileInjectable, - createMayBeForwardRefExpression, - FactoryTarget, - ForwardRefHandling, - LiteralExpr, - MaybeForwardRefExpression, - R3CompiledExpression, - R3DependencyMetadata, - R3InjectableMetadata, - WrappedNodeExpr, -} from 'static-injector/transform/compiler'; -import ts from 'typescript'; - -import { isAbstractClassDeclaration } from '../../annotations/common'; -import { ErrorCode, FatalDiagnosticError } from '../../diagnostics'; - -import { - ClassDeclaration, - Decorator, - ReflectionHost, - reflectObjectLiteral, -} from '../../reflection'; -import { - AnalysisOutput, - CompilationMode, - CompileResult, - DecoratorHandler, - DetectResult, -} from '../../transform'; -import { - CompileFactoryFn, - compileNgFactoryDefField, - findAngularDecorator, - getConstructorDependencies, - getValidConstructorDependencies, - isAngularCore, - toFactoryMetadata, - tryUnwrapForwardRef, - unwrapConstructorDependencies, - validateConstructorDependencies, - wrapTypeReference, -} from '../common'; - -export interface InjectableHandlerData { - meta: R3InjectableMetadata; - - ctorDeps: R3DependencyMetadata[] | 'invalid' | null; -} - -/** - * Adapts the `compileInjectable` compiler for `@Injectable` decorators to the Ivy compiler. - */ -export class InjectableDecoratorHandler - implements DecoratorHandler -{ - constructor( - private reflector: ReflectionHost, - private isCore: boolean, - private strictCtorDeps: boolean, - - private includeClassMetadata: boolean, - private readonly compilationMode: CompilationMode, - /** - * What to do if the injectable already contains a ɵprov property. - * - * If true then an error diagnostic is reported. - * If false then there is no error and a new ɵprov property is not added. - */ - private errorOnDuplicateProv = true, - ) {} - - detect( - node: ClassDeclaration, - decorators: Decorator[] | null, - ): DetectResult | undefined { - if (!decorators) { - return undefined; - } - const decorator = findAngularDecorator( - decorators, - 'Injectable', - this.isCore, - ); - if (decorator !== undefined) { - return { - trigger: decorator.node, - decorator: decorator, - metadata: decorator, - }; - } else { - return undefined; - } - } - - analyze( - node: ClassDeclaration, - decorator: Readonly, - ): AnalysisOutput { - const meta = extractInjectableMetadata(node, decorator, this.reflector); - - return { - analysis: { - meta, - ctorDeps: extractInjectableCtorDeps( - node, - meta, - decorator, - this.reflector, - this.isCore, - this.strictCtorDeps, - ), - - // Avoid generating multiple factories if a class has - // more Angular decorators, apart from Injectable. - }, - }; - } - - compileFull( - node: ClassDeclaration, - analysis: Readonly, - ): CompileResult[] { - return this.compile( - compileNgFactoryDefField, - (meta) => compileInjectable(meta, false), - node, - analysis, - ); - } - - private compile( - compileFactoryFn: CompileFactoryFn, - compileInjectableFn: (meta: R3InjectableMetadata) => R3CompiledExpression, - node: ClassDeclaration, - analysis: Readonly, - ): CompileResult[] { - const results: CompileResult[] = []; - - if (true) { - const meta = analysis.meta; - const factoryRes = compileFactoryFn( - toFactoryMetadata( - { ...meta, deps: analysis.ctorDeps }, - FactoryTarget.Injectable, - ), - ); - - results.push(factoryRes); - } - - const ɵprov = this.reflector - .getMembersOfClass(node) - .find((member) => member.name === 'ɵprov'); - if (ɵprov !== undefined && this.errorOnDuplicateProv) { - throw new FatalDiagnosticError( - ErrorCode.INJECTABLE_DUPLICATE_PROV, - ɵprov.nameNode || ɵprov.node || node, - 'Injectables cannot contain a static ɵprov property, because the compiler is going to generate one.', - ); - } - - if (ɵprov === undefined) { - // Only add a new ɵprov if there is not one already - const res = compileInjectableFn(analysis.meta); - results.push({ - name: 'ɵprov', - initializer: res.expression, - statements: res.statements, - type: res.type, - deferrableImports: null, - }); - } - - return results; - } -} - -/** - * Read metadata from the `@Injectable` decorator and produce the `IvyInjectableMetadata`, the - * input metadata needed to run `compileInjectable`. - * - * A `null` return value indicates this is @Injectable has invalid data. - */ -function extractInjectableMetadata( - clazz: ClassDeclaration, - decorator: Decorator, - reflector: ReflectionHost, -): R3InjectableMetadata { - const name = clazz.name.text; - const type = wrapTypeReference(reflector, clazz); - const typeArgumentCount = reflector.getGenericArityOfClass(clazz) || 0; - if (decorator.args === null) { - throw new FatalDiagnosticError( - ErrorCode.DECORATOR_NOT_CALLED, - decorator.node, - '@Injectable must be called', - ); - } - if (decorator.args.length === 0) { - return { - name, - type, - typeArgumentCount, - providedIn: createMayBeForwardRefExpression( - new LiteralExpr(null), - ForwardRefHandling.None, - ), - }; - } else if (decorator.args.length === 1) { - const metaNode = decorator.args[0]; - // Firstly make sure the decorator argument is an inline literal - if not, it's illegal to - // transport references from one location to another. This is the problem that lowering - // used to solve - if this restriction proves too undesirable we can re-implement lowering. - if (!ts.isObjectLiteralExpression(metaNode)) { - throw new FatalDiagnosticError( - ErrorCode.DECORATOR_ARG_NOT_LITERAL, - metaNode, - `@Injectable argument must be an object literal`, - ); - } - - // Resolve the fields of the literal into a map of field name to expression. - const meta = reflectObjectLiteral(metaNode); - - const providedIn = meta.has('providedIn') - ? getProviderExpression(meta.get('providedIn')!, reflector) - : createMayBeForwardRefExpression( - new LiteralExpr(null), - ForwardRefHandling.None, - ); - - let deps: R3DependencyMetadata[] | undefined = undefined; - if ((meta.has('useClass') || meta.has('useFactory')) && meta.has('deps')) { - const depsExpr = meta.get('deps')!; - if (!ts.isArrayLiteralExpression(depsExpr)) { - throw new FatalDiagnosticError( - ErrorCode.VALUE_NOT_LITERAL, - depsExpr, - `@Injectable deps metadata must be an inline array`, - ); - } - deps = depsExpr.elements.map((dep) => getDep(dep, reflector)); - } - - const result: R3InjectableMetadata = { - name, - type, - typeArgumentCount, - providedIn, - }; - if (meta.has('useValue')) { - result.useValue = getProviderExpression(meta.get('useValue')!, reflector); - } else if (meta.has('useExisting')) { - result.useExisting = getProviderExpression( - meta.get('useExisting')!, - reflector, - ); - } else if (meta.has('useClass')) { - result.useClass = getProviderExpression(meta.get('useClass')!, reflector); - result.deps = deps; - } else if (meta.has('useFactory')) { - result.useFactory = new WrappedNodeExpr(meta.get('useFactory')!); - result.deps = deps; - } - return result; - } else { - throw new FatalDiagnosticError( - ErrorCode.DECORATOR_ARITY_WRONG, - decorator.args[2], - 'Too many arguments to @Injectable', - ); - } -} - -/** - * Get the `R3ProviderExpression` for this `expression`. - * - * The `useValue`, `useExisting` and `useClass` properties might be wrapped in a `ForwardRef`, which - * needs to be unwrapped. This function will do that unwrapping and set a flag on the returned - * object to indicate whether the value needed unwrapping. - */ -function getProviderExpression( - expression: ts.Expression, - reflector: ReflectionHost, -): MaybeForwardRefExpression { - const forwardRefValue = tryUnwrapForwardRef(expression, reflector); - return createMayBeForwardRefExpression( - new WrappedNodeExpr(forwardRefValue ?? expression), - forwardRefValue !== null - ? ForwardRefHandling.Unwrapped - : ForwardRefHandling.None, - ); -} - -function extractInjectableCtorDeps( - clazz: ClassDeclaration, - meta: R3InjectableMetadata, - decorator: Decorator, - reflector: ReflectionHost, - isCore: boolean, - strictCtorDeps: boolean, -) { - if (decorator.args === null) { - throw new FatalDiagnosticError( - ErrorCode.DECORATOR_NOT_CALLED, - decorator.node, - '@Injectable must be called', - ); - } - - let ctorDeps: R3DependencyMetadata[] | 'invalid' | null = null; - - if (decorator.args.length === 0) { - // Ideally, using @Injectable() would have the same effect as using @Injectable({...}), and be - // subject to the same validation. However, existing Angular code abuses @Injectable, applying - // it to things like abstract classes with constructors that were never meant for use with - // Angular's DI. - // - // To deal with this, @Injectable() without an argument is more lenient, and if the - // constructor signature does not work for DI then a factory definition (ɵfac) that throws is - // generated. - if (strictCtorDeps && !isAbstractClassDeclaration(clazz)) { - ctorDeps = getValidConstructorDependencies(clazz, reflector, isCore); - } else { - ctorDeps = unwrapConstructorDependencies( - getConstructorDependencies(clazz, reflector, isCore), - ); - } - - return ctorDeps; - } else if (decorator.args.length === 1) { - const rawCtorDeps = getConstructorDependencies(clazz, reflector, isCore); - - if ( - strictCtorDeps && - !isAbstractClassDeclaration(clazz) && - requiresValidCtor(meta) - ) { - // Since use* was not provided for a concrete class, validate the deps according to - // strictCtorDeps. - ctorDeps = validateConstructorDependencies(clazz, rawCtorDeps); - } else { - ctorDeps = unwrapConstructorDependencies(rawCtorDeps); - } - } - - return ctorDeps; -} - -function requiresValidCtor(meta: R3InjectableMetadata): boolean { - return ( - meta.useValue === undefined && - meta.useExisting === undefined && - meta.useClass === undefined && - meta.useFactory === undefined - ); -} - -function getDep( - dep: ts.Expression, - reflector: ReflectionHost, -): R3DependencyMetadata { - const meta: R3DependencyMetadata = { - token: new WrappedNodeExpr(dep), - attributeNameType: null, - - optional: false, - self: false, - skipSelf: false, - }; - - function maybeUpdateDecorator( - dec: ts.Identifier, - reflector: ReflectionHost, - token?: ts.Expression, - ): boolean { - const source = reflector.getImportOfIdentifier(dec); - if (source === null || source.from !== 'static-injector') { - return false; - } - switch (source.name) { - case 'Inject': - if (token !== undefined) { - meta.token = new WrappedNodeExpr(token); - } - break; - case 'Optional': - meta.optional = true; - break; - case 'SkipSelf': - meta.skipSelf = true; - break; - case 'Self': - meta.self = true; - break; - default: - return false; - } - return true; - } - - if (ts.isArrayLiteralExpression(dep)) { - dep.elements.forEach((el) => { - let isDecorator = false; - if (ts.isIdentifier(el)) { - isDecorator = maybeUpdateDecorator(el, reflector); - } else if (ts.isNewExpression(el) && ts.isIdentifier(el.expression)) { - const token = - (el.arguments && el.arguments.length > 0 && el.arguments[0]) || - undefined; - isDecorator = maybeUpdateDecorator(el.expression, reflector, token); - } - if (!isDecorator) { - meta.token = new WrappedNodeExpr(el); - } - }); - } - return meta; -} diff --git a/src/transform/compiler-cli/src/ngtsc/diagnostics/error.ts b/src/transform/compiler-cli/src/ngtsc/diagnostics/error.ts deleted file mode 100644 index 6284894..0000000 --- a/src/transform/compiler-cli/src/ngtsc/diagnostics/error.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import * as ts from 'typescript'; - -import { ErrorCode, ngErrorCode } from './error_code'; - -export class FatalDiagnosticError { - constructor( - readonly code: ErrorCode, - readonly node: ts.Node, - readonly message: string | ts.DiagnosticMessageChain, - readonly relatedInformation?: ts.DiagnosticRelatedInformation[], - ) {} - - /** - * @internal - */ - _isFatalDiagnosticError = true; - - toDiagnostic(): ts.DiagnosticWithLocation { - return makeDiagnostic( - this.code, - this.node, - this.message, - this.relatedInformation, - ); - } -} - -export function makeDiagnostic( - code: ErrorCode, - node: ts.Node, - messageText: string | ts.DiagnosticMessageChain, - relatedInformation?: ts.DiagnosticRelatedInformation[], -): ts.DiagnosticWithLocation { - node = ts.getOriginalNode(node); - return { - category: ts.DiagnosticCategory.Error, - code: ngErrorCode(code), - file: ts.getOriginalNode(node).getSourceFile(), - start: node.getStart(undefined, false), - length: node.getWidth(), - messageText, - relatedInformation, - }; -} - -export function makeRelatedInformation( - node: ts.Node, - messageText: string, -): ts.DiagnosticRelatedInformation { - node = ts.getOriginalNode(node); - return { - category: ts.DiagnosticCategory.Message, - code: 0, - file: node.getSourceFile(), - start: node.getStart(), - length: node.getWidth(), - messageText, - }; -} - -export function isFatalDiagnosticError(err: any): err is FatalDiagnosticError { - return err._isFatalDiagnosticError === true; -} diff --git a/src/transform/compiler-cli/src/ngtsc/diagnostics/error_code.ts b/src/transform/compiler-cli/src/ngtsc/diagnostics/error_code.ts deleted file mode 100644 index e6dba31..0000000 --- a/src/transform/compiler-cli/src/ngtsc/diagnostics/error_code.ts +++ /dev/null @@ -1,238 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -/** - * @publicApi - */ -export enum ErrorCode { - DECORATOR_ARG_NOT_LITERAL = 1001, - DECORATOR_ARITY_WRONG = 1002, - DECORATOR_NOT_CALLED = 1003, - DECORATOR_ON_ANONYMOUS_CLASS = 1004, - DECORATOR_UNEXPECTED = 1005, - - /** - * This error code indicates that there are incompatible decorators on a type or a class field. - */ - DECORATOR_COLLISION = 1006, - - VALUE_HAS_WRONG_TYPE = 1010, - VALUE_NOT_LITERAL = 1011, - - COMPONENT_MISSING_TEMPLATE = 2001, - PIPE_MISSING_NAME = 2002, - PARAM_MISSING_TOKEN = 2003, - DIRECTIVE_MISSING_SELECTOR = 2004, - - /** Raised when an undecorated class is passed in as a provider to a module or a directive. */ - UNDECORATED_PROVIDER = 2005, - - /** - * Raised when a Directive inherits its constructor from a base class without an Angular - * decorator. - */ - DIRECTIVE_INHERITS_UNDECORATED_CTOR = 2006, - - /** - * Raised when an undecorated class that is using Angular features - * has been discovered. - */ - UNDECORATED_CLASS_USING_ANGULAR_FEATURES = 2007, - - /** - * Raised when an component cannot resolve an external resource, such as a template or a style - * sheet. - */ - COMPONENT_RESOURCE_NOT_FOUND = 2008, - - /** - * Raised when a component uses `ShadowDom` view encapsulation, but its selector - * does not match the shadow DOM tag name requirements. - */ - COMPONENT_INVALID_SHADOW_DOM_SELECTOR = 2009, - - SYMBOL_NOT_EXPORTED = 3001, - SYMBOL_EXPORTED_UNDER_DIFFERENT_NAME = 3002, - /** - * Raised when a relationship between directives and/or pipes would cause a cyclic import to be - * created that cannot be handled, such as in partial compilation mode. - */ - IMPORT_CYCLE_DETECTED = 3003, - - CONFIG_FLAT_MODULE_NO_INDEX = 4001, - CONFIG_STRICT_TEMPLATES_IMPLIES_FULL_TEMPLATE_TYPECHECK = 4002, - - /** - * Raised when a host expression has a parse error, such as a host listener or host binding - * expression containing a pipe. - */ - HOST_BINDING_PARSE_ERROR = 5001, - - /** - * Raised when the compiler cannot parse a component's template. - */ - TEMPLATE_PARSE_ERROR = 5002, - - /** - * Raised when an NgModule contains an invalid reference in `declarations`. - */ - NGMODULE_INVALID_DECLARATION = 6001, - - /** - * Raised when an NgModule contains an invalid type in `imports`. - */ - NGMODULE_INVALID_IMPORT = 6002, - - /** - * Raised when an NgModule contains an invalid type in `exports`. - */ - NGMODULE_INVALID_EXPORT = 6003, - - /** - * Raised when an NgModule contains a type in `exports` which is neither in `declarations` nor - * otherwise imported. - */ - NGMODULE_INVALID_REEXPORT = 6004, - - /** - * Raised when a `ModuleWithProviders` with a missing - * generic type argument is passed into an `NgModule`. - */ - NGMODULE_MODULE_WITH_PROVIDERS_MISSING_GENERIC = 6005, - - /** - * Raised when an NgModule exports multiple directives/pipes of the same name and the compiler - * attempts to generate private re-exports within the NgModule file. - */ - NGMODULE_REEXPORT_NAME_COLLISION = 6006, - - /** - * Raised when a directive/pipe is part of the declarations of two or more NgModules. - */ - NGMODULE_DECLARATION_NOT_UNIQUE = 6007, - - /** - * Not actually raised by the compiler, but reserved for documentation of a View Engine error when - * a View Engine build depends on an Ivy-compiled NgModule. - */ - NGMODULE_VE_DEPENDENCY_ON_IVY_LIB = 6999, - - /** - * An element name failed validation against the DOM schema. - */ - SCHEMA_INVALID_ELEMENT = 8001, - - /** - * An element's attribute name failed validation against the DOM schema. - */ - SCHEMA_INVALID_ATTRIBUTE = 8002, - - /** - * No matching directive was found for a `#ref="target"` expression. - */ - MISSING_REFERENCE_TARGET = 8003, - - /** - * No matching pipe was found for a - */ - MISSING_PIPE = 8004, - - /** - * The left-hand side of an assignment expression was a template variable. Effectively, the - * template looked like: - * - * ``` - * - * - * - * ``` - * - * Template variables are read-only. - */ - WRITE_TO_READ_ONLY_VARIABLE = 8005, - - /** - * A template variable was declared twice. For example: - * - * ```html - *
- *
- * ``` - */ - DUPLICATE_VARIABLE_DECLARATION = 8006, - - /** - * A template has a two way binding (two bindings created by a single syntactial element) - * in which the input and output are going to different places. - */ - SPLIT_TWO_WAY_BINDING = 8007, - - /** - * The template type-checking engine would need to generate an inline type check block for a - * component, but the current type-checking environment doesn't support it. - */ - INLINE_TCB_REQUIRED = 8900, - - /** - * The template type-checking engine would need to generate an inline type constructor for a - * directive or component, but the current type-checking environment doesn't support it. - */ - INLINE_TYPE_CTOR_REQUIRED = 8901, - - /** - * An injectable already has a `ɵprov` property. - */ - INJECTABLE_DUPLICATE_PROV = 9001, - - // 10XXX error codes are reserved for diagnostics with categories other than - // `ts.DiagnosticCategory.Error`. These diagnostics are generated by the compiler when configured - // to do so by a tool such as the Language Service, or by the Language Service itself. - - /** - * Suggest users to enable `strictTemplates` to make use of full capabilities - * provided by Angular language service. - */ - SUGGEST_STRICT_TEMPLATES = 10001, - - /** - * Indicates that a particular structural directive provides advanced type narrowing - * functionality, but the current template type-checking configuration does not allow its usage in - * type inference. - */ - SUGGEST_SUBOPTIMAL_TYPE_INFERENCE = 10002, -} - -/** - * @internal - * Base URL for the error details page. - * Keep this value in sync with a similar const in - * `packages/core/src/render3/error_code.ts`. - */ -export const ERROR_DETAILS_PAGE_BASE_URL = 'https://angular.io/errors'; - -/** - * @internal - * Contains a set of error messages that have detailed guides at angular.io. - * Full list of available error guides can be found at https://angular.io/errors - */ -export const COMPILER_ERRORS_WITH_GUIDES = new Set([ - ErrorCode.DECORATOR_ARG_NOT_LITERAL, - ErrorCode.IMPORT_CYCLE_DETECTED, - ErrorCode.PARAM_MISSING_TOKEN, - ErrorCode.SCHEMA_INVALID_ELEMENT, - ErrorCode.SCHEMA_INVALID_ATTRIBUTE, - ErrorCode.MISSING_REFERENCE_TARGET, - ErrorCode.COMPONENT_INVALID_SHADOW_DOM_SELECTOR, -]); - -/** - * @internal - */ -export function ngErrorCode(code: ErrorCode): number { - return parseInt('-99' + code); -} diff --git a/src/transform/compiler-cli/src/ngtsc/diagnostics/index.ts b/src/transform/compiler-cli/src/ngtsc/diagnostics/index.ts deleted file mode 100644 index 25da1d6..0000000 --- a/src/transform/compiler-cli/src/ngtsc/diagnostics/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './error'; -export * from './error_code'; diff --git a/src/transform/compiler-cli/src/ngtsc/imports/index.ts b/src/transform/compiler-cli/src/ngtsc/imports/index.ts deleted file mode 100644 index 59d36b6..0000000 --- a/src/transform/compiler-cli/src/ngtsc/imports/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './src/core'; diff --git a/src/transform/compiler-cli/src/ngtsc/imports/src/core.ts b/src/transform/compiler-cli/src/ngtsc/imports/src/core.ts deleted file mode 100644 index 11bb465..0000000 --- a/src/transform/compiler-cli/src/ngtsc/imports/src/core.ts +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -/** - * Rewrites imports of symbols being written into generated code. - */ -export interface ImportRewriter { - /** - * Should the given symbol be imported at all? - * - * If `true`, the symbol should be imported from the given specifier. If `false`, the symbol - * should be referenced directly, without an import. - */ - shouldImportSymbol(symbol: string, specifier: string): boolean; - - /** - * Optionally rewrite a reference to an imported symbol, changing either the binding prefix or the - * symbol name itself. - */ - rewriteSymbol(symbol: string, specifier: string): string; - - /** - * Optionally rewrite the given module specifier in the context of a given file. - */ - rewriteSpecifier(specifier: string, inContextOfFile: string): string; -} - -/** - * `ImportRewriter` that does no rewriting. - */ -export class NoopImportRewriter implements ImportRewriter { - shouldImportSymbol(symbol: string, specifier: string): boolean { - return true; - } - - rewriteSymbol(symbol: string, specifier: string): string { - return symbol; - } - - rewriteSpecifier(specifier: string, inContextOfFile: string): string { - return specifier; - } -} diff --git a/src/transform/compiler-cli/src/ngtsc/imports/src/default.ts b/src/transform/compiler-cli/src/ngtsc/imports/src/default.ts deleted file mode 100644 index 5fb7bf0..0000000 --- a/src/transform/compiler-cli/src/ngtsc/imports/src/default.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { WrappedNodeExpr } from 'static-injector/transform/compiler'; -import ts from 'typescript'; - -const DefaultImportDeclaration = Symbol('DefaultImportDeclaration'); - -interface WithDefaultImportDeclaration { - [DefaultImportDeclaration]?: ts.ImportDeclaration; -} - -/** - * Attaches a default import declaration to `expr` to indicate the dependency of `expr` on the - * default import. - */ -export function attachDefaultImportDeclaration( - expr: WrappedNodeExpr, - importDecl: ts.ImportDeclaration, -): void { - (expr as WithDefaultImportDeclaration)[DefaultImportDeclaration] = importDecl; -} - -/** - * Obtains the default import declaration that `expr` depends on, or `null` if there is no such - * dependency. - */ -export function getDefaultImportDeclaration( - expr: WrappedNodeExpr, -): ts.ImportDeclaration | null { - return ( - (expr as WithDefaultImportDeclaration)[DefaultImportDeclaration] ?? null - ); -} diff --git a/src/transform/compiler-cli/src/ngtsc/reflection/index.ts b/src/transform/compiler-cli/src/ngtsc/reflection/index.ts deleted file mode 100644 index 95ac68e..0000000 --- a/src/transform/compiler-cli/src/ngtsc/reflection/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './src/host'; -export * from './src/typescript'; -export * from './src/util'; diff --git a/src/transform/compiler-cli/src/ngtsc/reflection/src/host.ts b/src/transform/compiler-cli/src/ngtsc/reflection/src/host.ts deleted file mode 100644 index 06b085d..0000000 --- a/src/transform/compiler-cli/src/ngtsc/reflection/src/host.ts +++ /dev/null @@ -1,618 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import ts from 'typescript'; - -/** - * Metadata extracted from an instance of a decorator on another declaration. - */ -export interface Decorator { - /** - * Name by which the decorator was invoked in the user's code. - * - * This is distinct from the name by which the decorator was imported (though in practice they - * will usually be the same). - */ - name: string; - - /** - * Identifier which refers to the decorator in the user's code. - */ - identifier: DecoratorIdentifier; - - /** - * `Import` by which the decorator was brought into the module in which it was invoked, or `null` - * if the decorator was declared in the same module and not imported. - * - * Note: this field is declared using computed property syntax to work around a clang-format bug - * that resulted in inconsistent indentation of this comment block. - */ - ['import']: Import | null; - - /** - * TypeScript reference to the decorator itself. - */ - node: ts.Node; - - /** - * Arguments of the invocation of the decorator, if the decorator is invoked, or `null` - * otherwise. - */ - args: ts.Expression[] | null; -} - -/** - * A decorator is identified by either a simple identifier (e.g. `Decorator`) or, in some cases, - * a namespaced property access (e.g. `core.Decorator`). - */ -export type DecoratorIdentifier = ts.Identifier | NamespacedIdentifier; -export type NamespacedIdentifier = ts.PropertyAccessExpression & { - expression: ts.Identifier; - name: ts.Identifier; -}; -export function isDecoratorIdentifier( - exp: ts.Expression, -): exp is DecoratorIdentifier { - return ( - ts.isIdentifier(exp) || - (ts.isPropertyAccessExpression(exp) && - ts.isIdentifier(exp.expression) && - ts.isIdentifier(exp.name)) - ); -} - -/** - * The `ts.Declaration` of a "class". - * - * Classes are represented differently in different code formats: - * - In TS code, they are typically defined using the `class` keyword. - * - In ES2015 code, they are usually defined using the `class` keyword, but they can also be - * variable declarations, which are initialized to a class expression (e.g. - * `let Foo = Foo1 = class Foo {}`). - * - In ES5 code, they are typically defined as variable declarations being assigned the return - * value of an IIFE. The actual "class" is implemented as a constructor function inside the IIFE, - * but the outer variable declaration represents the "class" to the rest of the program. - * - * For `ReflectionHost` purposes, a class declaration should always have a `name` identifier, - * because we need to be able to reference it in other parts of the program. - */ -export type ClassDeclaration = - T & { name: ts.Identifier }; - -/** - * An enumeration of possible kinds of class members. - */ -export enum ClassMemberKind { - Constructor, - Getter, - Setter, - Property, - Method, -} - -/** - * A member of a class, such as a property, method, or constructor. - */ -export interface ClassMember { - /** - * TypeScript reference to the class member itself, or null if it is not applicable. - */ - node: ts.Node | null; - - /** - * Indication of which type of member this is (property, method, etc). - */ - kind: ClassMemberKind; - - /** - * TypeScript `ts.TypeNode` representing the type of the member, or `null` if not present or - * applicable. - */ - type: ts.TypeNode | null; - - /** - * Name of the class member. - */ - name: string; - - /** - * TypeScript `ts.Identifier` or `ts.StringLiteral` representing the name of the member, or `null` - * if no such node is present. - * - * The `nameNode` is useful in writing references to this member that will be correctly source- - * mapped back to the original file. - */ - nameNode: ts.Identifier | ts.StringLiteral | null; - - /** - * TypeScript `ts.Expression` which represents the value of the member. - * - * If the member is a property, this will be the property initializer if there is one, or null - * otherwise. - */ - value: ts.Expression | null; - - /** - * TypeScript `ts.Declaration` which represents the implementation of the member. - * - * In TypeScript code this is identical to the node, but in downleveled code this should always be - * the Declaration which actually represents the member's runtime value. - * - * For example, the TS code: - * - * ``` - * class Clazz { - * static get property(): string { - * return 'value'; - * } - * } - * ``` - * - * Downlevels to: - * - * ``` - * var Clazz = (function () { - * function Clazz() { - * } - * Object.defineProperty(Clazz, "property", { - * get: function () { - * return 'value'; - * }, - * enumerable: true, - * configurable: true - * }); - * return Clazz; - * }()); - * ``` - * - * In this example, for the property "property", the node would be the entire - * Object.defineProperty ExpressionStatement, but the implementation would be this - * FunctionDeclaration: - * - * ``` - * function () { - * return 'value'; - * }, - * ``` - */ - implementation: ts.Declaration | null; - - /** - * Whether the member is static or not. - */ - isStatic: boolean; - - /** - * Any `Decorator`s which are present on the member, or `null` if none are present. - */ - decorators: Decorator[] | null; -} - -export const enum TypeValueReferenceKind { - LOCAL, - IMPORTED, - UNAVAILABLE, -} - -/** - * A type reference that refers to any type via a `ts.Expression` that's valid within the local file - * where the type was referenced. - */ -export interface LocalTypeValueReference { - kind: TypeValueReferenceKind.LOCAL; - - /** - * The synthesized expression to reference the type in a value position. - */ - expression: ts.Expression; - - /** - * If the type originates from a default import, the import statement is captured here to be able - * to track its usages, preventing the import from being elided if it was originally only used in - * a type-position. See `DefaultImportTracker` for details. - */ - defaultImportStatement: ts.ImportDeclaration | null; -} - -/** - * A reference that refers to a type that was imported, and gives the symbol `name` and the - * `moduleName` of the import. Note that this `moduleName` may be a relative path, and thus is - * likely only valid within the context of the file which contained the original type reference. - */ -export interface ImportedTypeValueReference { - kind: TypeValueReferenceKind.IMPORTED; - - /** - * The module specifier from which the `importedName` symbol should be imported. - */ - moduleName: string; - - /** - * The name of the top-level symbol that is imported from `moduleName`. If `nestedPath` is also - * present, a nested object is being referenced from the top-level symbol. - */ - importedName: string; - - /** - * If present, represents the symbol names that are referenced from the top-level import. - * When `null` or empty, the `importedName` itself is the symbol being referenced. - */ - nestedPath: string[] | null; - - // This field can be null in local compilation mode when resolving is not possible. - valueDeclaration: DeclarationNode | null; -} - -/** - * A representation for a type value reference that is used when no value is available. This can - * occur due to various reasons, which is indicated in the `reason` field. - */ -export interface UnavailableTypeValueReference { - kind: TypeValueReferenceKind.UNAVAILABLE; - - /** - * The reason why no value reference could be determined for a type. - */ - reason: UnavailableValue; -} - -/** - * The various reasons why the compiler may be unable to synthesize a value from a type reference. - */ -export const enum ValueUnavailableKind { - /** - * No type node was available. - */ - MISSING_TYPE, - - /** - * The type does not have a value declaration, e.g. an interface. - */ - NO_VALUE_DECLARATION, - - /** - * The type is imported using a type-only imports, so it is not suitable to be used in a - * value-position. - */ - TYPE_ONLY_IMPORT, - - /** - * The type reference could not be resolved to a declaration. - */ - UNKNOWN_REFERENCE, - - /** - * The type corresponds with a namespace. - */ - NAMESPACE, - - /** - * The type is not supported in the compiler, for example union types. - */ - UNSUPPORTED, -} - -export interface UnsupportedType { - kind: ValueUnavailableKind.UNSUPPORTED; - typeNode: ts.TypeNode; -} - -export interface NoValueDeclaration { - kind: ValueUnavailableKind.NO_VALUE_DECLARATION; - typeNode: ts.TypeNode; - decl: ts.Declaration | null; -} - -export interface TypeOnlyImport { - kind: ValueUnavailableKind.TYPE_ONLY_IMPORT; - typeNode: ts.TypeNode; - node: ts.ImportClause | ts.ImportSpecifier; -} - -export interface NamespaceImport { - kind: ValueUnavailableKind.NAMESPACE; - typeNode: ts.TypeNode; - importClause: ts.ImportClause; -} - -export interface UnknownReference { - kind: ValueUnavailableKind.UNKNOWN_REFERENCE; - typeNode: ts.TypeNode; -} - -export interface MissingType { - kind: ValueUnavailableKind.MISSING_TYPE; -} - -/** - * The various reasons why a type node may not be referred to as a value. - */ -export type UnavailableValue = - | UnsupportedType - | NoValueDeclaration - | TypeOnlyImport - | NamespaceImport - | UnknownReference - | MissingType; - -/** - * A reference to a value that originated from a type position. - * - * For example, a constructor parameter could be declared as `foo: Foo`. A `TypeValueReference` - * extracted from this would refer to the value of the class `Foo` (assuming it was actually a - * type). - * - * See the individual types for additional information. - */ -export type TypeValueReference = - | LocalTypeValueReference - | ImportedTypeValueReference - | UnavailableTypeValueReference; - -/** - * A parameter to a constructor. - */ -export interface CtorParameter { - /** - * Name of the parameter, if available. - * - * Some parameters don't have a simple string name (for example, parameters which are destructured - * into multiple variables). In these cases, `name` can be `null`. - */ - name: string | null; - - /** - * TypeScript `ts.BindingName` representing the name of the parameter. - * - * The `nameNode` is useful in writing references to this member that will be correctly source- - * mapped back to the original file. - */ - nameNode: ts.BindingName; - - /** - * Reference to the value of the parameter's type annotation, if it's possible to refer to the - * parameter's type as a value. - * - * This can either be a reference to a local value, a reference to an imported value, or no - * value if no is present or cannot be represented as an expression. - */ - typeValueReference: TypeValueReference; - - /** - * TypeScript `ts.TypeNode` representing the type node found in the type position. - * - * This field can be used for diagnostics reporting if `typeValueReference` is `null`. - * - * Can be null, if the param has no type declared. - */ - typeNode: ts.TypeNode | null; - - /** - * Any `Decorator`s which are present on the parameter, or `null` if none are present. - */ - decorators: Decorator[] | null; -} - -/** - * Definition of a function or method, including its body if present and any parameters. - * - * In TypeScript code this metadata will be a simple reflection of the declarations in the node - * itself. In ES5 code this can be more complicated, as the default values for parameters may - * be extracted from certain body statements. - */ -export interface FunctionDefinition { - /** - * A reference to the node which declares the function. - */ - node: - | ts.MethodDeclaration - | ts.FunctionDeclaration - | ts.FunctionExpression - | ts.VariableDeclaration - | ts.ArrowFunction; - - /** - * Statements of the function body, if a body is present, or null if no body is present or the - * function is identified to represent a tslib helper function, in which case `helper` will - * indicate which helper this function represents. - * - * This list may have been filtered to exclude statements which perform parameter default value - * initialization. - */ - body: ts.Statement[] | null; - - /** - * Metadata regarding the function's parameters, including possible default value expressions. - */ - parameters: Parameter[]; - - /** - * Generic type parameters of the function. - */ - typeParameters: ts.TypeParameterDeclaration[] | null; - - /** - * Number of known signatures of the function. - */ - signatureCount: number; -} - -/** - * A parameter to a function or method. - */ -export interface Parameter { - /** - * Name of the parameter, if available. - */ - name: string | null; - - /** - * Declaration which created this parameter. - */ - node: ts.ParameterDeclaration; - - /** - * Expression which represents the default value of the parameter, if any. - */ - initializer: ts.Expression | null; - - /** - * Type of the parameter. - */ - type: ts.TypeNode | null; -} - -/** - * The source of an imported symbol, including the original symbol name and the module from which it - * was imported. - */ -export interface Import { - /** - * The name of the imported symbol under which it was exported (not imported). - */ - name: string; - - /** - * The module from which the symbol was imported. - * - * This could either be an absolute module name (@angular/core for example) or a relative path. - */ - from: string; - - /** - * TypeScript node that represents this import. - */ - node: ts.ImportDeclaration; -} - -/** - * A type that is used to identify a declaration. - */ -export type DeclarationNode = ts.Declaration; - -export type AmbientImport = { - __brand: 'AmbientImport'; -}; - -/** Indicates that a declaration is referenced through an ambient type. */ -export const AmbientImport = {} as AmbientImport; - -/** - * The declaration of a symbol, along with information about how it was imported into the - * application. - */ -export interface Declaration { - /** - * The absolute module path from which the symbol was imported into the application, if the symbol - * was imported via an absolute module (even through a chain of re-exports). If the symbol is part - * of the application and was not imported from an absolute path, this will be `null`. - */ - viaModule: string | AmbientImport | null; - - /** - * TypeScript reference to the declaration itself, if one exists. - */ - node: T; -} - -/** - * Abstracts reflection operations on a TypeScript AST. - * - * Depending on the format of the code being interpreted, different concepts are represented - * with different syntactical structures. The `ReflectionHost` abstracts over those differences and - * presents a single API by which the compiler can query specific information about the AST. - * - * All operations on the `ReflectionHost` require the use of TypeScript `ts.Node`s with binding - * information already available (that is, nodes that come from a `ts.Program` that has been - * type-checked, and are not synthetically created). - */ -export interface ReflectionHost { - /** - * Examine a declaration (for example, of a class or function) and return metadata about any - * decorators present on the declaration. - * - * @param declaration a TypeScript `ts.Declaration` node representing the class or function over - * which to reflect. For example, if the intent is to reflect the decorators of a class and the - * source is in ES6 format, this will be a `ts.ClassDeclaration` node. If the source is in ES5 - * format, this might be a `ts.VariableDeclaration` as classes in ES5 are represented as the - * result of an IIFE execution. - * - * @returns an array of `Decorator` metadata if decorators are present on the declaration, or - * `null` if either no decorators were present or if the declaration is not of a decoratable type. - */ - getDecoratorsOfDeclaration(declaration: DeclarationNode): Decorator[] | null; - - /** - * Examine a declaration which should be of a class, and return metadata about the members of the - * class. - * - * @param clazz a `ClassDeclaration` representing the class over which to reflect. - * - * @returns an array of `ClassMember` metadata representing the members of the class. - * - * @throws if `declaration` does not resolve to a class declaration. - */ - getMembersOfClass(clazz: ClassDeclaration): ClassMember[]; - - /** - * Reflect over the constructor of a class and return metadata about its parameters. - * - * This method only looks at the constructor of a class directly and not at any inherited - * constructors. - * - * @param clazz a `ClassDeclaration` representing the class over which to reflect. - * - * @returns an array of `Parameter` metadata representing the parameters of the constructor, if - * a constructor exists. If the constructor exists and has 0 parameters, this array will be empty. - * If the class has no constructor, this method returns `null`. - */ - getConstructorParameters(clazz: ClassDeclaration): CtorParameter[] | null; - - /** - * Determine if an identifier was imported from another module and return `Import` metadata - * describing its origin. - * - * @param id a TypeScript `ts.Identifier` to reflect. - * - * @returns metadata about the `Import` if the identifier was imported from another module, or - * `null` if the identifier doesn't resolve to an import but instead is locally defined. - */ - getImportOfIdentifier(id: ts.Identifier): Import | null; - - /** - * Check whether the given node actually represents a class. - */ - isClass(node: ts.Node): node is ClassDeclaration; - - /** - * Determines whether the given declaration, which should be a class, has a base class. - * - * @param clazz a `ClassDeclaration` representing the class over which to reflect. - */ - hasBaseClass(clazz: ClassDeclaration): boolean; - - /** - * Get an expression representing the base class (if any) of the given `clazz`. - * - * This expression is most commonly an Identifier, but is possible to inherit from a more dynamic - * expression. - * - * @param clazz the class whose base we want to get. - */ - getBaseClassExpression(clazz: ClassDeclaration): ts.Expression | null; - - /** - * Get the number of generic type parameters of a given class. - * - * @param clazz a `ClassDeclaration` representing the class over which to reflect. - * - * @returns the number of type parameters of the class, if known, or `null` if the declaration - * is not a class or has an unknown number of type parameters. - */ - getGenericArityOfClass(clazz: ClassDeclaration): number | null; -} diff --git a/src/transform/compiler-cli/src/ngtsc/reflection/src/type_to_value.ts b/src/transform/compiler-cli/src/ngtsc/reflection/src/type_to_value.ts deleted file mode 100644 index 40e805d..0000000 --- a/src/transform/compiler-cli/src/ngtsc/reflection/src/type_to_value.ts +++ /dev/null @@ -1,324 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import ts from 'typescript'; - -import { - TypeValueReference, - TypeValueReferenceKind, - UnavailableTypeValueReference, - ValueUnavailableKind, -} from './host'; - -/** - * Potentially convert a `ts.TypeNode` to a `TypeValueReference`, which indicates how to use the - * type given in the `ts.TypeNode` in a value position. - * - * This can return `null` if the `typeNode` is `null`, if it does not refer to a symbol with a value - * declaration, or if it is not possible to statically understand. - */ -export function typeToValue( - typeNode: ts.TypeNode | null, - checker: ts.TypeChecker, - isLocalCompilation: boolean, -): TypeValueReference { - // It's not possible to get a value expression if the parameter doesn't even have a type. - if (typeNode === null) { - return missingType(); - } - - if (!ts.isTypeReferenceNode(typeNode)) { - return unsupportedType(typeNode); - } - - const symbols = resolveTypeSymbols(typeNode, checker); - if (symbols === null) { - return unknownReference(typeNode); - } - - const { local, decl } = symbols; - - // It's only valid to convert a type reference to a value reference if the type actually - // has a value declaration associated with it. Note that const enums are an exception, - // because while they do have a value declaration, they don't exist at runtime. - if ( - decl.valueDeclaration === undefined || - decl.flags & ts.SymbolFlags.ConstEnum - ) { - let typeOnlyDecl: ts.Declaration | null = null; - if (decl.declarations !== undefined && decl.declarations.length > 0) { - typeOnlyDecl = decl.declarations[0]; - } - - // In local compilation mode a declaration is considered invalid only if it is a type related - // declaration. - if ( - !isLocalCompilation || - (typeOnlyDecl && - [ - ts.SyntaxKind.TypeParameter, - ts.SyntaxKind.TypeAliasDeclaration, - ts.SyntaxKind.InterfaceDeclaration, - ].includes(typeOnlyDecl.kind)) - ) { - return noValueDeclaration(typeNode, typeOnlyDecl); - } - } - - // The type points to a valid value declaration. Rewrite the TypeReference into an - // Expression which references the value pointed to by the TypeReference, if possible. - - // Look at the local `ts.Symbol`'s declarations and see if it comes from an import - // statement. If so, extract the module specifier and the name of the imported type. - const firstDecl = local.declarations && local.declarations[0]; - if (firstDecl !== undefined) { - if (ts.isImportClause(firstDecl) && firstDecl.name !== undefined) { - // This is a default import. - // import Foo from 'foo'; - - if (firstDecl.isTypeOnly) { - // Type-only imports cannot be represented as value. - return typeOnlyImport(typeNode, firstDecl); - } - - return { - kind: TypeValueReferenceKind.LOCAL, - expression: firstDecl.name, - defaultImportStatement: firstDecl.parent, - }; - } else if (ts.isImportSpecifier(firstDecl)) { - // The symbol was imported by name - // import {Foo} from 'foo'; - // or - // import {Foo as Bar} from 'foo'; - - if (firstDecl.isTypeOnly) { - // The import specifier can't be type-only (e.g. `import {type Foo} from '...')`. - return typeOnlyImport(typeNode, firstDecl); - } - - if (firstDecl.parent.parent.isTypeOnly) { - // The import specifier can't be inside a type-only import clause - // (e.g. `import type {Foo} from '...')`. - return typeOnlyImport(typeNode, firstDecl.parent.parent); - } - - // Determine the name to import (`Foo`) from the import specifier, as the symbol names of - // the imported type could refer to a local alias (like `Bar` in the example above). - const importedName = (firstDecl.propertyName || firstDecl.name).text; - - // The first symbol name refers to the local name, which is replaced by `importedName` above. - // Any remaining symbol names make up the complete path to the value. - const [_localName, ...nestedPath] = symbols.symbolNames; - - const moduleName = extractModuleName(firstDecl.parent.parent.parent); - return { - kind: TypeValueReferenceKind.IMPORTED, - valueDeclaration: decl.valueDeclaration ?? null, - moduleName, - importedName, - nestedPath, - }; - } else if (ts.isNamespaceImport(firstDecl)) { - // The import is a namespace import - // import * as Foo from 'foo'; - - if (firstDecl.parent.isTypeOnly) { - // Type-only imports cannot be represented as value. - return typeOnlyImport(typeNode, firstDecl.parent); - } - - if (symbols.symbolNames.length === 1) { - // The type refers to the namespace itself, which cannot be represented as a value. - return namespaceImport(typeNode, firstDecl.parent); - } - - // The first symbol name refers to the local name of the namespace, which is is discarded - // as a new namespace import will be generated. This is followed by the symbol name that needs - // to be imported and any remaining names that constitute the complete path to the value. - const [_ns, importedName, ...nestedPath] = symbols.symbolNames; - - const moduleName = extractModuleName(firstDecl.parent.parent); - return { - kind: TypeValueReferenceKind.IMPORTED, - valueDeclaration: decl.valueDeclaration ?? null, - moduleName, - importedName, - nestedPath, - }; - } - } - - // If the type is not imported, the type reference can be converted into an expression as is. - const expression = typeNodeToValueExpr(typeNode); - if (expression !== null) { - return { - kind: TypeValueReferenceKind.LOCAL, - expression, - defaultImportStatement: null, - }; - } else { - return unsupportedType(typeNode); - } -} - -function unsupportedType(typeNode: ts.TypeNode): UnavailableTypeValueReference { - return { - kind: TypeValueReferenceKind.UNAVAILABLE, - reason: { kind: ValueUnavailableKind.UNSUPPORTED, typeNode }, - }; -} - -function noValueDeclaration( - typeNode: ts.TypeNode, - decl: ts.Declaration | null, -): UnavailableTypeValueReference { - return { - kind: TypeValueReferenceKind.UNAVAILABLE, - reason: { kind: ValueUnavailableKind.NO_VALUE_DECLARATION, typeNode, decl }, - }; -} - -function typeOnlyImport( - typeNode: ts.TypeNode, - node: ts.ImportClause | ts.ImportSpecifier, -): UnavailableTypeValueReference { - return { - kind: TypeValueReferenceKind.UNAVAILABLE, - reason: { kind: ValueUnavailableKind.TYPE_ONLY_IMPORT, typeNode, node }, - }; -} - -function unknownReference( - typeNode: ts.TypeNode, -): UnavailableTypeValueReference { - return { - kind: TypeValueReferenceKind.UNAVAILABLE, - reason: { kind: ValueUnavailableKind.UNKNOWN_REFERENCE, typeNode }, - }; -} - -function namespaceImport( - typeNode: ts.TypeNode, - importClause: ts.ImportClause, -): UnavailableTypeValueReference { - return { - kind: TypeValueReferenceKind.UNAVAILABLE, - reason: { kind: ValueUnavailableKind.NAMESPACE, typeNode, importClause }, - }; -} - -function missingType(): UnavailableTypeValueReference { - return { - kind: TypeValueReferenceKind.UNAVAILABLE, - reason: { kind: ValueUnavailableKind.MISSING_TYPE }, - }; -} - -/** - * Attempt to extract a `ts.Expression` that's equivalent to a `ts.TypeNode`, as the two have - * different AST shapes but can reference the same symbols. - * - * This will return `null` if an equivalent expression cannot be constructed. - */ -export function typeNodeToValueExpr(node: ts.TypeNode): ts.Expression | null { - if (ts.isTypeReferenceNode(node)) { - return entityNameToValue(node.typeName); - } else { - return null; - } -} - -/** - * Resolve a `TypeReference` node to the `ts.Symbol`s for both its declaration and its local source. - * - * In the event that the `TypeReference` refers to a locally declared symbol, these will be the - * same. If the `TypeReference` refers to an imported symbol, then `decl` will be the fully resolved - * `ts.Symbol` of the referenced symbol. `local` will be the `ts.Symbol` of the `ts.Identifier` - * which points to the import statement by which the symbol was imported. - * - * All symbol names that make up the type reference are returned left-to-right into the - * `symbolNames` array, which is guaranteed to include at least one entry. - */ -function resolveTypeSymbols( - typeRef: ts.TypeReferenceNode, - checker: ts.TypeChecker, -): { local: ts.Symbol; decl: ts.Symbol; symbolNames: string[] } | null { - const typeName = typeRef.typeName; - // typeRefSymbol is the ts.Symbol of the entire type reference. - const typeRefSymbol: ts.Symbol | undefined = - checker.getSymbolAtLocation(typeName); - if (typeRefSymbol === undefined) { - return null; - } - - // `local` is the `ts.Symbol` for the local `ts.Identifier` for the type. - // If the type is actually locally declared or is imported by name, for example: - // import {Foo} from './foo'; - // then it'll be the same as `typeRefSymbol`. - // - // If the type is imported via a namespace import, for example: - // import * as foo from './foo'; - // and then referenced as: - // constructor(f: foo.Foo) - // then `local` will be the `ts.Symbol` of `foo`, whereas `typeRefSymbol` will be the `ts.Symbol` - // of `foo.Foo`. This allows tracking of the import behind whatever type reference exists. - let local = typeRefSymbol; - - // Destructure a name like `foo.X.Y.Z` as follows: - // - in `leftMost`, the `ts.Identifier` of the left-most name (`foo`) in the qualified name. - // This identifier is used to resolve the `ts.Symbol` for `local`. - // - in `symbolNames`, all names involved in the qualified path, or a single symbol name if the - // type is not qualified. - let leftMost = typeName; - const symbolNames: string[] = []; - while (ts.isQualifiedName(leftMost)) { - symbolNames.unshift(leftMost.right.text); - leftMost = leftMost.left; - } - symbolNames.unshift(leftMost.text); - - if (leftMost !== typeName) { - const localTmp = checker.getSymbolAtLocation(leftMost); - if (localTmp !== undefined) { - local = localTmp; - } - } - - // De-alias the top-level type reference symbol to get the symbol of the actual declaration. - let decl = typeRefSymbol; - if (typeRefSymbol.flags & ts.SymbolFlags.Alias) { - decl = checker.getAliasedSymbol(typeRefSymbol); - } - return { local, decl, symbolNames }; -} - -export function entityNameToValue(node: ts.EntityName): ts.Expression | null { - if (ts.isQualifiedName(node)) { - const left = entityNameToValue(node.left); - return left !== null - ? ts.factory.createPropertyAccessExpression(left, node.right) - : null; - } else if (ts.isIdentifier(node)) { - const clone = ts.setOriginalNode( - ts.factory.createIdentifier(node.text), - node, - ); - (clone as any).parent = node.parent; - return clone; - } else { - return null; - } -} - -function extractModuleName(node: ts.ImportDeclaration): string { - if (!ts.isStringLiteral(node.moduleSpecifier)) { - throw new Error('not a module specifier'); - } - return node.moduleSpecifier.text; -} diff --git a/src/transform/compiler-cli/src/ngtsc/reflection/src/typescript.ts b/src/transform/compiler-cli/src/ngtsc/reflection/src/typescript.ts deleted file mode 100644 index 1df629e..0000000 --- a/src/transform/compiler-cli/src/ngtsc/reflection/src/typescript.ts +++ /dev/null @@ -1,510 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import ts from 'typescript'; - -import { - AmbientImport, - ClassDeclaration, - ClassMember, - ClassMemberKind, - CtorParameter, - DeclarationNode, - Decorator, - Import, - isDecoratorIdentifier, - ReflectionHost, -} from './host'; -import { typeToValue } from './type_to_value'; -import { isNamedClassDeclaration } from './util'; - -/** - * reflector.ts implements static reflection of declarations using the TypeScript `ts.TypeChecker`. - */ - -export class TypeScriptReflectionHost implements ReflectionHost { - constructor( - protected checker: ts.TypeChecker, - private readonly isLocalCompilation = false, - ) {} - - getDecoratorsOfDeclaration(declaration: DeclarationNode): Decorator[] | null { - const decorators = ts.canHaveDecorators(declaration) - ? ts.getDecorators(declaration) - : undefined; - - return decorators !== undefined && decorators.length - ? decorators - .map((decorator) => this._reflectDecorator(decorator)) - .filter((dec): dec is Decorator => dec !== null) - : null; - } - - getMembersOfClass(clazz: ClassDeclaration): ClassMember[] { - const tsClazz = castDeclarationToClassOrDie(clazz); - return tsClazz.members - .map((member) => this._reflectMember(member)) - .filter((member): member is ClassMember => member !== null); - } - - getConstructorParameters(clazz: ClassDeclaration): CtorParameter[] | null { - const tsClazz = castDeclarationToClassOrDie(clazz); - - const isDeclaration = tsClazz.getSourceFile().isDeclarationFile; - // For non-declaration files, we want to find the constructor with a `body`. The constructors - // without a `body` are overloads whereas we want the implementation since it's the one that'll - // be executed and which can have decorators. For declaration files, we take the first one that - // we get. - const ctor = tsClazz.members.find( - (member): member is ts.ConstructorDeclaration => - ts.isConstructorDeclaration(member) && - (isDeclaration || member.body !== undefined), - ); - if (ctor === undefined) { - return null; - } - - return ctor.parameters.map((node) => { - // The name of the parameter is easy. - const name = parameterName(node.name); - - const decorators = this.getDecoratorsOfDeclaration(node); - - // It may or may not be possible to write an expression that refers to the value side of the - // type named for the parameter. - - let originalTypeNode = node.type || null; - let typeNode = originalTypeNode; - - // Check if we are dealing with a simple nullable union type e.g. `foo: Foo|null` - // and extract the type. More complex union types e.g. `foo: Foo|Bar` are not supported. - // We also don't need to support `foo: Foo|undefined` because Angular's DI injects `null` for - // optional tokes that don't have providers. - if (typeNode && ts.isUnionTypeNode(typeNode)) { - let childTypeNodes = typeNode.types.filter( - (childTypeNode) => - !( - ts.isLiteralTypeNode(childTypeNode) && - childTypeNode.literal.kind === ts.SyntaxKind.NullKeyword - ), - ); - - if (childTypeNodes.length === 1) { - typeNode = childTypeNodes[0]; - } - } - - const typeValueReference = typeToValue( - typeNode, - this.checker, - this.isLocalCompilation, - ); - - return { - name, - nameNode: node.name, - typeValueReference, - typeNode: originalTypeNode, - decorators, - }; - }); - } - - getImportOfIdentifier(id: ts.Identifier): Import | null { - const directImport = this.getDirectImportOfIdentifier(id); - if (directImport !== null) { - return directImport; - } else if (ts.isQualifiedName(id.parent) && id.parent.right === id) { - return this.getImportOfNamespacedIdentifier( - id, - getQualifiedNameRoot(id.parent), - ); - } else if ( - ts.isPropertyAccessExpression(id.parent) && - id.parent.name === id - ) { - return this.getImportOfNamespacedIdentifier( - id, - getFarLeftIdentifier(id.parent), - ); - } else { - return null; - } - } - - isClass(node: ts.Node): node is ClassDeclaration { - // For our purposes, classes are "named" ts.ClassDeclarations; - // (`node.name` can be undefined in unnamed default exports: `default export class { ... }`). - return isNamedClassDeclaration(node); - } - - hasBaseClass(clazz: ClassDeclaration): boolean { - return this.getBaseClassExpression(clazz) !== null; - } - - getBaseClassExpression(clazz: ClassDeclaration): ts.Expression | null { - if ( - !(ts.isClassDeclaration(clazz) || ts.isClassExpression(clazz)) || - clazz.heritageClauses === undefined - ) { - return null; - } - const extendsClause = clazz.heritageClauses.find( - (clause) => clause.token === ts.SyntaxKind.ExtendsKeyword, - ); - if (extendsClause === undefined) { - return null; - } - const extendsType = extendsClause.types[0]; - if (extendsType === undefined) { - return null; - } - return extendsType.expression; - } - - getGenericArityOfClass(clazz: ClassDeclaration): number | null { - if (!ts.isClassDeclaration(clazz)) { - return null; - } - return clazz.typeParameters !== undefined ? clazz.typeParameters.length : 0; - } - - protected getDirectImportOfIdentifier(id: ts.Identifier): Import | null { - const symbol = this.checker.getSymbolAtLocation(id); - - if ( - symbol === undefined || - symbol.declarations === undefined || - symbol.declarations.length !== 1 - ) { - return null; - } - - const decl = symbol.declarations[0]; - const importDecl = getContainingImportDeclaration(decl); - - // Ignore declarations that are defined locally (not imported). - if (importDecl === null) { - return null; - } - - // The module specifier is guaranteed to be a string literal, so this should always pass. - if (!ts.isStringLiteral(importDecl.moduleSpecifier)) { - // Not allowed to happen in TypeScript ASTs. - return null; - } - - return { - from: importDecl.moduleSpecifier.text, - name: getExportedName(decl, id), - node: importDecl, - }; - } - - /** - * Try to get the import info for this identifier as though it is a namespaced import. - * - * For example, if the identifier is the `Directive` part of a qualified type chain like: - * - * ``` - * core.Directive - * ``` - * - * then it might be that `core` is a namespace import such as: - * - * ``` - * import * as core from 'tslib'; - * ``` - * - * @param id the TypeScript identifier to find the import info for. - * @returns The import info if this is a namespaced import or `null`. - */ - protected getImportOfNamespacedIdentifier( - id: ts.Identifier, - namespaceIdentifier: ts.Identifier | null, - ): Import | null { - if (namespaceIdentifier === null) { - return null; - } - const namespaceSymbol = - this.checker.getSymbolAtLocation(namespaceIdentifier); - if (!namespaceSymbol || namespaceSymbol.declarations === undefined) { - return null; - } - const declaration = - namespaceSymbol.declarations.length === 1 - ? namespaceSymbol.declarations[0] - : null; - if (!declaration) { - return null; - } - const namespaceDeclaration = ts.isNamespaceImport(declaration) - ? declaration - : null; - if (!namespaceDeclaration) { - return null; - } - - const importDeclaration = namespaceDeclaration.parent.parent; - if (!ts.isStringLiteral(importDeclaration.moduleSpecifier)) { - // Should not happen as this would be invalid TypesScript - return null; - } - - return { - from: importDeclaration.moduleSpecifier.text, - name: id.text, - node: namespaceDeclaration.parent.parent, - }; - } - - private _reflectDecorator(node: ts.Decorator): Decorator | null { - // Attempt to resolve the decorator expression into a reference to a concrete Identifier. The - // expression may contain a call to a function which returns the decorator function, in which - // case we want to return the arguments. - let decoratorExpr: ts.Expression = node.expression; - let args: ts.Expression[] | null = null; - - // Check for call expressions. - if (ts.isCallExpression(decoratorExpr)) { - args = Array.from(decoratorExpr.arguments); - decoratorExpr = decoratorExpr.expression; - } - - // The final resolved decorator should be a `ts.Identifier` - if it's not, then something is - // wrong and the decorator can't be resolved statically. - if (!isDecoratorIdentifier(decoratorExpr)) { - return null; - } - - const decoratorIdentifier = ts.isIdentifier(decoratorExpr) - ? decoratorExpr - : decoratorExpr.name; - const importDecl = this.getImportOfIdentifier(decoratorIdentifier); - - return { - name: decoratorIdentifier.text, - identifier: decoratorExpr, - import: importDecl, - node, - args, - }; - } - - private _reflectMember(node: ts.ClassElement): ClassMember | null { - let kind: ClassMemberKind | null = null; - let value: ts.Expression | null = null; - let name: string | null = null; - let nameNode: ts.Identifier | ts.StringLiteral | null = null; - - if (ts.isPropertyDeclaration(node)) { - kind = ClassMemberKind.Property; - value = node.initializer || null; - } else if (ts.isGetAccessorDeclaration(node)) { - kind = ClassMemberKind.Getter; - } else if (ts.isSetAccessorDeclaration(node)) { - kind = ClassMemberKind.Setter; - } else if (ts.isMethodDeclaration(node)) { - kind = ClassMemberKind.Method; - } else if (ts.isConstructorDeclaration(node)) { - kind = ClassMemberKind.Constructor; - } else { - return null; - } - - if (ts.isConstructorDeclaration(node)) { - name = 'constructor'; - } else if (ts.isIdentifier(node.name)) { - name = node.name.text; - nameNode = node.name; - } else if (ts.isStringLiteral(node.name)) { - name = node.name.text; - nameNode = node.name; - } else { - return null; - } - - const decorators = this.getDecoratorsOfDeclaration(node); - const modifiers = ts.getModifiers(node); - const isStatic = - modifiers !== undefined && - modifiers.some((mod) => mod.kind === ts.SyntaxKind.StaticKeyword); - - return { - node, - implementation: node, - kind, - type: node.type || null, - name, - nameNode, - decorators, - value, - isStatic, - }; - } - - private _viaModule( - declaration: ts.Declaration, - originalId: ts.Identifier | null, - importInfo: Import | null, - ): string | AmbientImport | null { - if ( - importInfo === null && - originalId !== null && - declaration.getSourceFile() !== originalId.getSourceFile() - ) { - return AmbientImport; - } - - return importInfo !== null && - importInfo.from !== null && - !importInfo.from.startsWith('.') - ? importInfo.from - : null; - } -} - -export function reflectObjectLiteral( - node: ts.ObjectLiteralExpression, -): Map { - const map = new Map(); - node.properties.forEach((prop) => { - if (ts.isPropertyAssignment(prop)) { - const name = propertyNameToString(prop.name); - if (name === null) { - return; - } - map.set(name, prop.initializer); - } else if (ts.isShorthandPropertyAssignment(prop)) { - map.set(prop.name.text, prop.name); - } else { - return; - } - }); - return map; -} - -function castDeclarationToClassOrDie( - declaration: ClassDeclaration, -): ClassDeclaration { - if (!ts.isClassDeclaration(declaration)) { - throw new Error( - `Reflecting on a ${ - ts.SyntaxKind[declaration.kind] - } instead of a ClassDeclaration.`, - ); - } - return declaration; -} - -function parameterName(name: ts.BindingName): string | null { - if (ts.isIdentifier(name)) { - return name.text; - } else { - return null; - } -} - -function propertyNameToString(node: ts.PropertyName): string | null { - if ( - ts.isIdentifier(node) || - ts.isStringLiteral(node) || - ts.isNumericLiteral(node) - ) { - return node.text; - } else { - return null; - } -} - -/** - * Compute the left most identifier in a qualified type chain. E.g. the `a` of `a.b.c.SomeType`. - * @param qualifiedName The starting property access expression from which we want to compute - * the left most identifier. - * @returns the left most identifier in the chain or `null` if it is not an identifier. - */ -function getQualifiedNameRoot( - qualifiedName: ts.QualifiedName, -): ts.Identifier | null { - while (ts.isQualifiedName(qualifiedName.left)) { - qualifiedName = qualifiedName.left; - } - return ts.isIdentifier(qualifiedName.left) ? qualifiedName.left : null; -} - -/** - * Compute the left most identifier in a property access chain. E.g. the `a` of `a.b.c.d`. - * @param propertyAccess The starting property access expression from which we want to compute - * the left most identifier. - * @returns the left most identifier in the chain or `null` if it is not an identifier. - */ -function getFarLeftIdentifier( - propertyAccess: ts.PropertyAccessExpression, -): ts.Identifier | null { - while (ts.isPropertyAccessExpression(propertyAccess.expression)) { - propertyAccess = propertyAccess.expression; - } - return ts.isIdentifier(propertyAccess.expression) - ? propertyAccess.expression - : null; -} - -/** - * Gets the closest ancestor `ImportDeclaration` to a node. - */ -export function getContainingImportDeclaration( - node: ts.Node, -): ts.ImportDeclaration | null { - let parent = node.parent; - - while (parent && !ts.isSourceFile(parent)) { - if (ts.isImportDeclaration(parent)) { - return parent; - } - parent = parent.parent; - } - - return null; -} - -/** - * Compute the name by which the `decl` was exported, not imported. - * If no such declaration can be found (e.g. it is a namespace import) - * then fallback to the `originalId`. - */ -function getExportedName( - decl: ts.Declaration, - originalId: ts.Identifier, -): string { - return ts.isImportSpecifier(decl) - ? (decl.propertyName !== undefined ? decl.propertyName : decl.name).text - : originalId.text; -} - -const LocalExportedDeclarations = Symbol('LocalExportedDeclarations'); - -/** - * A `ts.SourceFile` expando which includes a cached `Set` of local `ts.Declaration`s that are - * exported either directly (`export class ...`) or indirectly (via `export {...}`). - * - * This cache does not cause memory leaks as: - * - * 1. The only references cached here are local to the `ts.SourceFile`, and thus also available in - * `this.statements`. - * - * 2. The only way this `Set` could change is if the source file itself was changed, which would - * invalidate the entire `ts.SourceFile` object in favor of a new version. Thus, changing the - * source file also invalidates this cache. - */ -interface SourceFileWithCachedExports extends ts.SourceFile { - /** - * Cached `Set` of `ts.Declaration`s which are locally declared in this file and are exported - * either directly or indirectly. - */ - [LocalExportedDeclarations]?: Set; -} diff --git a/src/transform/compiler-cli/src/ngtsc/reflection/src/util.ts b/src/transform/compiler-cli/src/ngtsc/reflection/src/util.ts deleted file mode 100644 index ef01cf3..0000000 --- a/src/transform/compiler-cli/src/ngtsc/reflection/src/util.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import ts from 'typescript'; -import { ClassDeclaration } from './host'; - -export function isNamedClassDeclaration( - node: ts.Node, -): node is ClassDeclaration { - return ts.isClassDeclaration(node) && isIdentifier(node.name); -} - -export function isNamedFunctionDeclaration( - node: ts.Node, -): node is ClassDeclaration { - return ts.isFunctionDeclaration(node) && isIdentifier(node.name); -} - -export function isNamedVariableDeclaration( - node: ts.Node, -): node is ClassDeclaration { - return ts.isVariableDeclaration(node) && isIdentifier(node.name); -} - -function isIdentifier(node: ts.Node | undefined): node is ts.Identifier { - return node !== undefined && ts.isIdentifier(node); -} diff --git a/src/transform/compiler-cli/src/ngtsc/transform/index.ts b/src/transform/compiler-cli/src/ngtsc/transform/index.ts deleted file mode 100644 index 294b265..0000000 --- a/src/transform/compiler-cli/src/ngtsc/transform/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from './src/api'; -export * from './src/utils'; diff --git a/src/transform/compiler-cli/src/ngtsc/transform/src/api.ts b/src/transform/compiler-cli/src/ngtsc/transform/src/api.ts deleted file mode 100644 index 67eb18f..0000000 --- a/src/transform/compiler-cli/src/ngtsc/transform/src/api.ts +++ /dev/null @@ -1,142 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { - Expression, - Statement, - Type, -} from 'static-injector/transform/compiler'; -import ts from 'typescript'; - -import { ClassDeclaration, Decorator, ReflectionHost } from '../../reflection'; - -/** - * Specifies the compilation mode that is used for the compilation. - */ -export enum CompilationMode { - /** - * Generates fully AOT compiled code using Ivy instructions. - */ - FULL, - - /** - * Generates code using a stable, but intermediate format suitable to be published to NPM. - */ - PARTIAL, - - /** - * Generates code based on each individual source file without using its - * dependencies (suitable for local dev edit/refresh workflow). - */ - LOCAL, -} - -/** - * Provides the interface between a decorator compiler from @angular/compiler and the Typescript - * compiler/transform. - * - * The decorator compilers in @angular/compiler do not depend on Typescript. The handler is - * responsible for extracting the information required to perform compilation from the decorators - * and Typescript source, invoking the decorator compiler, and returning the result. - * - * @param `D` The type of decorator metadata produced by `detect`. - * @param `A` The type of analysis metadata produced by `analyze`. - * @param `R` The type of resolution metadata produced by `resolve`. - */ -export interface DecoratorHandler { - /** - * Scan a set of reflected decorators and determine if this handler is responsible for compilation - * of one of them. - */ - detect( - node: ClassDeclaration, - decorators: Decorator[] | null, - ): DetectResult | undefined; - - /** - * Asynchronously perform pre-analysis on the decorator/class combination. - * - * `preanalyze` is optional and is not guaranteed to be called through all compilation flows. It - * will only be called if asynchronicity is supported in the CompilerHost. - */ - preanalyze?( - node: ClassDeclaration, - metadata: Readonly, - ): Promise | undefined; - - /** - * Perform analysis on the decorator/class combination, extracting information from the class - * required for compilation. - * - * Returns analyzed metadata if successful, or an array of diagnostic messages if the analysis - * fails or the decorator isn't valid. - * - * Analysis should always be a "pure" operation, with no side effects. This is because the - * detect/analysis steps might be skipped for files which have not changed during incremental - * builds. Any side effects required for compilation (e.g. registration of metadata) should happen - * in the `register` phase, which is guaranteed to run even for incremental builds. - */ - analyze(node: ClassDeclaration, metadata: Readonly): AnalysisOutput; - - /** - * Generate a description of the field which should be added to the class, including any - * initialization code to be generated. - * - * If the compilation mode is configured as other than full but an implementation of the - * corresponding method is not provided, then this method is called as a fallback. - */ - compileFull( - node: ClassDeclaration, - analysis: Readonly, - ): CompileResult | CompileResult[]; -} - -/** - * The output of detecting a trait for a declaration as the result of the first phase of the - * compilation pipeline. - */ -export interface DetectResult { - /** - * The node that triggered the match, which is typically a decorator. - */ - trigger: ts.Node | null; - - /** - * Refers to the decorator that was recognized for this detection, if any. This can be a concrete - * decorator that is actually present in a file, or a synthetic decorator as inserted - * programmatically. - */ - decorator: Decorator | null; - - /** - * An arbitrary object to carry over from the detection phase into the analysis phase. - */ - metadata: Readonly; -} - -/** - * The output of an analysis operation, consisting of possibly an arbitrary analysis object (used as - * the input to code generation) and potentially diagnostics if there were errors uncovered during - * analysis. - */ -export interface AnalysisOutput { - analysis?: Readonly; - diagnostics?: ts.Diagnostic[]; -} - -/** - * A description of the static field to add to a class, including an initialization expression - * and a type for the .d.ts file. - */ -export interface CompileResult { - name: string; - initializer: Expression | null; - statements: Statement[]; - type: Type; - deferrableImports: Set | null; -} diff --git a/src/transform/compiler-cli/src/ngtsc/transform/src/utils.ts b/src/transform/compiler-cli/src/ngtsc/transform/src/utils.ts deleted file mode 100644 index 2264318..0000000 --- a/src/transform/compiler-cli/src/ngtsc/transform/src/utils.ts +++ /dev/null @@ -1,109 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import ts from 'typescript'; - -import { - ImportManager, - NamespaceImport, - SideEffectImport, -} from '../../translator'; - -/** - * Adds extra imports in the import manage for this source file, after the existing imports - * and before the module body. - * Can optionally add extra statements (e.g. new constants) before the body as well. - */ -export function addImports( - factory = ts.factory, - importManager: ImportManager, - sf: ts.SourceFile, - extraStatements: ts.Statement[] = [], -): ts.SourceFile { - // Generate the import statements to prepend. - const addedImports = importManager - .getAllImports(sf.fileName) - .map((i) => - i.qualifier !== null - ? createNamespaceImportDecl(i, factory) - : createSideEffectImportDecl(i, factory), - ); - - // Filter out the existing imports and the source file body. All new statements - // will be inserted between them. - const existingImports = sf.statements.filter((stmt) => - isImportStatement(stmt), - ); - const body = sf.statements.filter((stmt) => !isImportStatement(stmt)); - // Prepend imports if needed. - if (addedImports.length > 0) { - // If we prepend imports, we also prepend NotEmittedStatement to use it as an anchor - // for @fileoverview Closure annotation. If there is no @fileoverview annotations, this - // statement would be a noop. - const fileoverviewAnchorStmt = factory.createNotEmittedStatement(sf); - return factory.updateSourceFile( - sf, - factory.createNodeArray([ - fileoverviewAnchorStmt, - ...existingImports, - ...addedImports, - ...extraStatements, - ...body, - ]), - ); - } - - return sf; -} - -function createNamespaceImportDecl( - i: NamespaceImport, - factory: ts.NodeFactory, -): ts.ImportDeclaration { - const qualifier = factory.createIdentifier(i.qualifier.text); - const importClause = factory.createImportClause( - /* isTypeOnly */ false, - /* name */ undefined, - /* namedBindings */ factory.createNamespaceImport(qualifier), - ); - const decl = factory.createImportDeclaration( - /* modifiers */ undefined, - /* importClause */ importClause, - /* moduleSpecifier */ factory.createStringLiteral(i.specifier), - ); - - // Set the qualifier's original TS node to the `ts.ImportDeclaration`. This allows downstream - // transforms such as tsickle to properly process references to this import. - // - // This operation is load-bearing in g3 as some imported modules contain special metadata - // generated by clutz, which tsickle uses to transform imports and references to those imports. - // - // TODO(alxhub): add a test for this when tsickle is updated externally to depend on this - // behavior. - ts.setOriginalNode(i.qualifier, decl); - - return decl; -} - -function createSideEffectImportDecl( - i: SideEffectImport, - factory: ts.NodeFactory, -): ts.ImportDeclaration { - return factory.createImportDeclaration( - /* modifiers */ undefined, - /* importClause */ undefined, - /* moduleSpecifier */ ts.factory.createStringLiteral(i.specifier), - ); -} - -function isImportStatement(stmt: ts.Statement): boolean { - return ( - ts.isImportDeclaration(stmt) || - ts.isImportEqualsDeclaration(stmt) || - ts.isNamespaceImport(stmt) - ); -} diff --git a/src/transform/compiler-cli/src/ngtsc/translator/index.ts b/src/transform/compiler-cli/src/ngtsc/translator/index.ts deleted file mode 100644 index 241bec5..0000000 --- a/src/transform/compiler-cli/src/ngtsc/translator/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './src/context'; -export * from './src/translator'; -export * from './src/typescript_ast_factory'; -export * from './src/typescript_translator'; -export * from './src/import_manager'; diff --git a/src/transform/compiler-cli/src/ngtsc/translator/src/api/ast_factory.ts b/src/transform/compiler-cli/src/ngtsc/translator/src/api/ast_factory.ts deleted file mode 100644 index f96e508..0000000 --- a/src/transform/compiler-cli/src/ngtsc/translator/src/api/ast_factory.ts +++ /dev/null @@ -1,399 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -/** - * Used to create transpiler specific AST nodes from Angular Output AST nodes in an abstract way. - * - * Note that the `AstFactory` makes no assumptions about the target language being generated. - * It is up to the caller to do this - e.g. only call `createTaggedTemplate()` or pass `let`|`const` - * to `createVariableDeclaration()` if the final JS will allow it. - */ -export interface AstFactory { - /** - * Attach the `leadingComments` to the given `statement` node. - * - * @param statement the statement where the comments are to be attached. - * @param leadingComments the comments to attach. - */ - attachComments( - statement: TStatement, - leadingComments: LeadingComment[], - ): void; - - /** - * Create a literal array expression (e.g. `[expr1, expr2]`). - * - * @param elements a collection of the expressions to appear in each array slot. - */ - createArrayLiteral(elements: TExpression[]): TExpression; - - /** - * Create an assignment expression (e.g. `lhsExpr = rhsExpr`). - * - * @param target an expression that evaluates to the left side of the assignment. - * @param value an expression that evaluates to the right side of the assignment. - */ - createAssignment(target: TExpression, value: TExpression): TExpression; - - /** - * Create a binary expression (e.g. `lhs && rhs`). - * - * @param leftOperand an expression that will appear on the left of the operator. - * @param operator the binary operator that will be applied. - * @param rightOperand an expression that will appear on the right of the operator. - */ - createBinaryExpression( - leftOperand: TExpression, - operator: BinaryOperator, - rightOperand: TExpression, - ): TExpression; - - /** - * Create a block of statements (e.g. `{ stmt1; stmt2; }`). - * - * @param body an array of statements to be wrapped in a block. - */ - createBlock(body: TStatement[]): TStatement; - - /** - * Create an expression that is calling the `callee` with the given `args`. - * - * @param callee an expression that evaluates to a function to be called. - * @param args the arguments to be passed to the call. - * @param pure whether to mark the call as pure (having no side-effects). - */ - createCallExpression( - callee: TExpression, - args: TExpression[], - pure: boolean, - ): TExpression; - - /** - * Create a ternary expression (e.g. `testExpr ? trueExpr : falseExpr`). - * - * @param condition an expression that will be tested for truthiness. - * @param thenExpression an expression that is executed if `condition` is truthy. - * @param elseExpression an expression that is executed if `condition` is falsy. - */ - createConditional( - condition: TExpression, - thenExpression: TExpression, - elseExpression: TExpression, - ): TExpression; - - /** - * Create an element access (e.g. `obj[expr]`). - * - * @param expression an expression that evaluates to the object to be accessed. - * @param element an expression that evaluates to the element on the object. - */ - createElementAccess( - expression: TExpression, - element: TExpression, - ): TExpression; - - /** - * Create a statement that is simply executing the given `expression` (e.g. `x = 10;`). - * - * @param expression the expression to be converted to a statement. - */ - createExpressionStatement(expression: TExpression): TStatement; - - /** - * Create a statement that declares a function (e.g. `function foo(param1, param2) { stmt; }`). - * - * @param functionName the name of the function. - * @param parameters the names of the function's parameters. - * @param body a statement (or a block of statements) that are the body of the function. - */ - createFunctionDeclaration( - functionName: string, - parameters: string[], - body: TStatement, - ): TStatement; - - /** - * Create an expression that represents a function - * (e.g. `function foo(param1, param2) { stmt; }`). - * - * @param functionName the name of the function. - * @param parameters the names of the function's parameters. - * @param body a statement (or a block of statements) that are the body of the function. - */ - createFunctionExpression( - functionName: string | null, - parameters: string[], - body: TStatement, - ): TExpression; - - /** - * Create an expression that represents an arrow function - * (e.g. `(param1, param2) => body`). - * - * @param parameters the names of the function's parameters. - * @param body an expression or block of statements that are the body of the function. - */ - createArrowFunctionExpression( - parameters: string[], - body: TExpression | TStatement, - ): TExpression; - - /** - * Creates an expression that represents a dynamic import - * (e.g. `import('./some/path')`) - * - * @param url the URL that should by used in the dynamic import - */ - createDynamicImport(url: string): TExpression; - - /** - * Create an identifier. - * - * @param name the name of the identifier. - */ - createIdentifier(name: string): TExpression; - - /** - * Create an if statement (e.g. `if (testExpr) { trueStmt; } else { falseStmt; }`). - * - * @param condition an expression that will be tested for truthiness. - * @param thenStatement a statement (or block of statements) that is executed if `condition` is - * truthy. - * @param elseStatement a statement (or block of statements) that is executed if `condition` is - * falsy. - */ - createIfStatement( - condition: TExpression, - thenStatement: TStatement, - elseStatement: TStatement | null, - ): TStatement; - - /** - * Create a simple literal (e.g. `"string"`, `123`, `false`, etc). - * - * @param value the value of the literal. - */ - createLiteral( - value: string | number | boolean | null | undefined, - ): TExpression; - - /** - * Create an expression that is instantiating the `expression` as a class. - * - * @param expression an expression that evaluates to a constructor to be instantiated. - * @param args the arguments to be passed to the constructor. - */ - createNewExpression( - expression: TExpression, - args: TExpression[], - ): TExpression; - - /** - * Create a literal object expression (e.g. `{ prop1: expr1, prop2: expr2 }`). - * - * @param properties the properties (key and value) to appear in the object. - */ - createObjectLiteral( - properties: ObjectLiteralProperty[], - ): TExpression; - - /** - * Wrap an expression in parentheses. - * - * @param expression the expression to wrap in parentheses. - */ - createParenthesizedExpression(expression: TExpression): TExpression; - - /** - * Create a property access (e.g. `obj.prop`). - * - * @param expression an expression that evaluates to the object to be accessed. - * @param propertyName the name of the property to access. - */ - createPropertyAccess( - expression: TExpression, - propertyName: string, - ): TExpression; - - /** - * Create a return statement (e.g `return expr;`). - * - * @param expression the expression to be returned. - */ - createReturnStatement(expression: TExpression | null): TStatement; - - /** - * Create a tagged template literal string. E.g. - * - * ``` - * tag`str1${expr1}str2${expr2}str3` - * ``` - * - * @param tag an expression that is applied as a tag handler for this template string. - * @param template the collection of strings and expressions that constitute an interpolated - * template literal. - */ - createTaggedTemplate( - tag: TExpression, - template: TemplateLiteral, - ): TExpression; - - /** - * Create a throw statement (e.g. `throw expr;`). - * - * @param expression the expression to be thrown. - */ - createThrowStatement(expression: TExpression): TStatement; - - /** - * Create an expression that extracts the type of an expression (e.g. `typeof expr`). - * - * @param expression the expression whose type we want. - */ - createTypeOfExpression(expression: TExpression): TExpression; - - /** - * Prefix the `operand` with the given `operator` (e.g. `-expr`). - * - * @param operator the text of the operator to apply (e.g. `+`, `-` or `!`). - * @param operand the expression that the operator applies to. - */ - createUnaryExpression( - operator: UnaryOperator, - operand: TExpression, - ): TExpression; - - /** - * Create an expression that declares a new variable, possibly initialized to `initializer`. - * - * @param variableName the name of the variable. - * @param initializer if not `null` then this expression is assigned to the declared variable. - * @param type whether this variable should be declared as `var`, `let` or `const`. - */ - createVariableDeclaration( - variableName: string, - initializer: TExpression | null, - type: VariableDeclarationType, - ): TStatement; - - /** - * Attach a source map range to the given node. - * - * @param node the node to which the range should be attached. - * @param sourceMapRange the range to attach to the node, or null if there is no range to attach. - * @returns the `node` with the `sourceMapRange` attached. - */ - setSourceMapRange( - node: T, - sourceMapRange: SourceMapRange | null, - ): T; -} - -/** - * The type of a variable declaration. - */ -export type VariableDeclarationType = 'const' | 'let' | 'var'; - -/** - * The unary operators supported by the `AstFactory`. - */ -export type UnaryOperator = '+' | '-' | '!'; - -/** - * The binary operators supported by the `AstFactory`. - */ -export type BinaryOperator = - | '&&' - | '>' - | '>=' - | '&' - | '|' - | '/' - | '==' - | '===' - | '<' - | '<=' - | '-' - | '%' - | '*' - | '!=' - | '!==' - | '||' - | '+' - | '??'; - -/** - * The original location of the start or end of a node created by the `AstFactory`. - */ -export interface SourceMapLocation { - /** 0-based character position of the location in the original source file. */ - offset: number; - /** 0-based line index of the location in the original source file. */ - line: number; - /** 0-based column position of the location in the original source file. */ - column: number; -} - -/** - * The original range of a node created by the `AstFactory`. - */ -export interface SourceMapRange { - url: string; - content: string; - start: SourceMapLocation; - end: SourceMapLocation; -} - -/** - * Information used by the `AstFactory` to create a property on an object literal expression. - */ -export interface ObjectLiteralProperty { - propertyName: string; - value: TExpression; - /** - * Whether the `propertyName` should be enclosed in quotes. - */ - quoted: boolean; -} - -/** - * Information used by the `AstFactory` to create a template literal string (i.e. a back-ticked - * string with interpolations). - */ -export interface TemplateLiteral { - /** - * A collection of the static string pieces of the interpolated template literal string. - */ - elements: TemplateElement[]; - /** - * A collection of the interpolated expressions that are interleaved between the elements. - */ - expressions: TExpression[]; -} - -/** - * Information about a static string piece of an interpolated template literal string. - */ -export interface TemplateElement { - /** The raw string as it was found in the original source code. */ - raw: string; - /** The parsed string, with escape codes etc processed. */ - cooked: string; - /** The original location of this piece of the template literal string. */ - range: SourceMapRange | null; -} - -/** - * Information used by the `AstFactory` to prepend a comment to a statement that was created by the - * `AstFactory`. - */ -export interface LeadingComment { - toString(): string; - multiline: boolean; - trailingNewline: boolean; -} diff --git a/src/transform/compiler-cli/src/ngtsc/translator/src/api/import_generator.ts b/src/transform/compiler-cli/src/ngtsc/translator/src/api/import_generator.ts deleted file mode 100644 index 552f135..0000000 --- a/src/transform/compiler-cli/src/ngtsc/translator/src/api/import_generator.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -/** - * The symbol name and import namespace of an imported symbol, - * which has been registered through the ImportGenerator. - */ -export interface NamedImport { - /** The import namespace containing this imported symbol. */ - moduleImport: TExpression | null; - /** The (possibly rewritten) name of the imported symbol. */ - symbol: string; -} - -/** - * Generate import information based on the context of the code being generated. - * - * Implementations of these methods return a specific identifier that corresponds to the imported - * module. - */ -export interface ImportGenerator { - generateNamespaceImport(moduleName: string): TExpression; - generateNamedImport( - moduleName: string, - originalSymbol: string, - ): NamedImport; -} diff --git a/src/transform/compiler-cli/src/ngtsc/translator/src/context.ts b/src/transform/compiler-cli/src/ngtsc/translator/src/context.ts deleted file mode 100644 index 9e606d0..0000000 --- a/src/transform/compiler-cli/src/ngtsc/translator/src/context.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -/** - * The current context of a translator visitor as it traverses the AST tree. - * - * It tracks whether we are in the process of outputting a statement or an expression. - */ -export class Context { - constructor(readonly isStatement: boolean) {} - - get withExpressionMode(): Context { - return this.isStatement ? new Context(false) : this; - } - - get withStatementMode(): Context { - return !this.isStatement ? new Context(true) : this; - } -} diff --git a/src/transform/compiler-cli/src/ngtsc/translator/src/import_manager.ts b/src/transform/compiler-cli/src/ngtsc/translator/src/import_manager.ts deleted file mode 100644 index e76bb33..0000000 --- a/src/transform/compiler-cli/src/ngtsc/translator/src/import_manager.ts +++ /dev/null @@ -1,109 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import ts from 'typescript'; - -import { ImportRewriter, NoopImportRewriter } from '../../imports'; - -import { ImportGenerator, NamedImport } from './api/import_generator'; - -/** - * Information about a namespace import that has been added to a module. - */ -export interface NamespaceImport { - /** The name of the module that has been imported. */ - specifier: string; - - /** The `ts.Identifier` by which the imported module is known. */ - qualifier: ts.Identifier; -} - -/** - * Information about a side effect import that has been added to a module. - */ -export interface SideEffectImport { - /** The name of the module that has been imported. */ - specifier: string; - - /** - * The qualifier of a side effect import is always non-existent, and that can be used to check - * whether the import is side effect or not. - */ - qualifier: null; -} - -/** - * Information about an import that has been added to a module. - */ -export type Import = NamespaceImport | SideEffectImport; - -export class ImportManager implements ImportGenerator { - private specifierToIdentifier = new Map(); - private nextIndex = 0; - - constructor( - protected rewriter: ImportRewriter = new NoopImportRewriter(), - private prefix = 'i', - private factory = ts.factory, - ) {} - - generateNamespaceImport(moduleName: string): ts.Identifier { - // The case `specifierToIdentifier.get(moduleName) === null` is also considered to overwrite the - // side effect import since namedspace import is enough. - if ( - !this.specifierToIdentifier.has(moduleName) || - this.specifierToIdentifier.get(moduleName) === null - ) { - this.specifierToIdentifier.set( - moduleName, - this.factory.createIdentifier(`${this.prefix}${this.nextIndex++}`), - ); - } - return this.specifierToIdentifier.get(moduleName)!; - } - - generateNamedImport( - moduleName: string, - originalSymbol: string, - ): NamedImport { - // First, rewrite the symbol name. - const symbol = this.rewriter.rewriteSymbol(originalSymbol, moduleName); - - // Ask the rewriter if this symbol should be imported at all. If not, it can be referenced - // directly (moduleImport: null). - if (!this.rewriter.shouldImportSymbol(symbol, moduleName)) { - // The symbol should be referenced directly. - return { moduleImport: null, symbol }; - } - - // If not, this symbol will be imported using a generated namespace import. - const moduleImport = this.generateNamespaceImport(moduleName); - - return { moduleImport, symbol }; - } - - generateSideEffectImport(moduleName: string) { - if (!this.specifierToIdentifier.has(moduleName)) { - this.specifierToIdentifier.set(moduleName, null); - } - } - - getAllImports(contextPath: string): Import[] { - const imports: Import[] = []; - for (const [originalSpecifier, qualifier] of this.specifierToIdentifier) { - const specifier = this.rewriter.rewriteSpecifier( - originalSpecifier, - contextPath, - ); - imports.push({ - specifier, - qualifier, - }); - } - return imports; - } -} diff --git a/src/transform/compiler-cli/src/ngtsc/translator/src/translator.ts b/src/transform/compiler-cli/src/ngtsc/translator/src/translator.ts deleted file mode 100644 index 0da911b..0000000 --- a/src/transform/compiler-cli/src/ngtsc/translator/src/translator.ts +++ /dev/null @@ -1,446 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import * as o from 'static-injector/transform/compiler'; - -import { - AstFactory, - BinaryOperator, - ObjectLiteralProperty, - SourceMapRange, - TemplateElement, - TemplateLiteral, - UnaryOperator, -} from './api/ast_factory'; -import { ImportGenerator } from './api/import_generator'; -import { Context } from './context'; - -const UNARY_OPERATORS = new Map([ - [o.UnaryOperator.Minus, '-'], - [o.UnaryOperator.Plus, '+'], -]); - -const BINARY_OPERATORS = new Map([ - [o.BinaryOperator.And, '&&'], - [o.BinaryOperator.Bigger, '>'], - [o.BinaryOperator.BiggerEquals, '>='], - [o.BinaryOperator.BitwiseAnd, '&'], - [o.BinaryOperator.BitwiseOr, '|'], - [o.BinaryOperator.Divide, '/'], - [o.BinaryOperator.Equals, '=='], - [o.BinaryOperator.Identical, '==='], - [o.BinaryOperator.Lower, '<'], - [o.BinaryOperator.LowerEquals, '<='], - [o.BinaryOperator.Minus, '-'], - [o.BinaryOperator.Modulo, '%'], - [o.BinaryOperator.Multiply, '*'], - [o.BinaryOperator.NotEquals, '!='], - [o.BinaryOperator.NotIdentical, '!=='], - [o.BinaryOperator.Or, '||'], - [o.BinaryOperator.Plus, '+'], - [o.BinaryOperator.NullishCoalesce, '??'], -]); - -export type RecordWrappedNodeFn = ( - node: o.WrappedNodeExpr, -) => void; - -export interface TranslatorOptions { - downlevelTaggedTemplates?: boolean; - downlevelVariableDeclarations?: boolean; - recordWrappedNode?: RecordWrappedNodeFn; - annotateForClosureCompiler?: boolean; -} - -export class ExpressionTranslatorVisitor - implements o.ExpressionVisitor, o.StatementVisitor -{ - private downlevelTaggedTemplates: boolean; - private downlevelVariableDeclarations: boolean; - private recordWrappedNode: RecordWrappedNodeFn; - - constructor( - private factory: AstFactory, - private imports: ImportGenerator, - options: TranslatorOptions, - ) { - this.downlevelTaggedTemplates = options.downlevelTaggedTemplates === true; - this.downlevelVariableDeclarations = - options.downlevelVariableDeclarations === true; - this.recordWrappedNode = options.recordWrappedNode || (() => {}); - } - - visitDeclareVarStmt(stmt: o.DeclareVarStmt, context: Context): TStatement { - const varType = this.downlevelVariableDeclarations - ? 'var' - : stmt.hasModifier(o.StmtModifier.Final) - ? 'const' - : 'let'; - return this.attachComments( - this.factory.createVariableDeclaration( - stmt.name, - stmt.value?.visitExpression(this, context.withExpressionMode), - varType, - ), - stmt.leadingComments, - ); - } - - visitDeclareFunctionStmt( - stmt: o.DeclareFunctionStmt, - context: Context, - ): TStatement { - return this.attachComments( - this.factory.createFunctionDeclaration( - stmt.name, - stmt.params.map((param) => param.name), - this.factory.createBlock( - this.visitStatements(stmt.statements, context.withStatementMode), - ), - ), - stmt.leadingComments, - ); - } - - visitExpressionStmt( - stmt: o.ExpressionStatement, - context: Context, - ): TStatement { - return this.attachComments( - this.factory.createExpressionStatement( - stmt.expr.visitExpression(this, context.withStatementMode), - ), - stmt.leadingComments, - ); - } - - visitReturnStmt(stmt: o.ReturnStatement, context: Context): TStatement { - return this.attachComments( - this.factory.createReturnStatement( - stmt.value.visitExpression(this, context.withExpressionMode), - ), - stmt.leadingComments, - ); - } - - visitIfStmt(stmt: o.IfStmt, context: Context): TStatement { - return this.attachComments( - this.factory.createIfStatement( - stmt.condition.visitExpression(this, context), - this.factory.createBlock( - this.visitStatements(stmt.trueCase, context.withStatementMode), - ), - stmt.falseCase.length > 0 - ? this.factory.createBlock( - this.visitStatements(stmt.falseCase, context.withStatementMode), - ) - : null, - ), - stmt.leadingComments, - ); - } - - visitReadVarExpr(ast: o.ReadVarExpr, _context: Context): TExpression { - const identifier = this.factory.createIdentifier(ast.name!); - this.setSourceMapRange(identifier, ast.sourceSpan); - return identifier; - } - - visitWriteVarExpr(expr: o.WriteVarExpr, context: Context): TExpression { - const assignment = this.factory.createAssignment( - this.setSourceMapRange( - this.factory.createIdentifier(expr.name), - expr.sourceSpan, - ), - expr.value.visitExpression(this, context), - ); - return context.isStatement - ? assignment - : this.factory.createParenthesizedExpression(assignment); - } - - visitWriteKeyExpr(expr: o.WriteKeyExpr, context: Context): TExpression { - const exprContext = context.withExpressionMode; - const target = this.factory.createElementAccess( - expr.receiver.visitExpression(this, exprContext), - expr.index.visitExpression(this, exprContext), - ); - const assignment = this.factory.createAssignment( - target, - expr.value.visitExpression(this, exprContext), - ); - return context.isStatement - ? assignment - : this.factory.createParenthesizedExpression(assignment); - } - - visitWritePropExpr(expr: o.WritePropExpr, context: Context): TExpression { - const target = this.factory.createPropertyAccess( - expr.receiver.visitExpression(this, context), - expr.name, - ); - return this.factory.createAssignment( - target, - expr.value.visitExpression(this, context), - ); - } - - visitInvokeFunctionExpr( - ast: o.InvokeFunctionExpr, - context: Context, - ): TExpression { - return this.setSourceMapRange( - this.factory.createCallExpression( - ast.fn.visitExpression(this, context), - ast.args.map((arg) => arg.visitExpression(this, context)), - ast.pure, - ), - ast.sourceSpan, - ); - } - - visitInstantiateExpr(ast: o.InstantiateExpr, context: Context): TExpression { - return this.factory.createNewExpression( - ast.classExpr.visitExpression(this, context), - ast.args.map((arg) => arg.visitExpression(this, context)), - ); - } - - visitLiteralExpr(ast: o.LiteralExpr, _context: Context): TExpression { - return this.setSourceMapRange( - this.factory.createLiteral(ast.value), - ast.sourceSpan, - ); - } - - visitExternalExpr(ast: o.ExternalExpr, _context: Context): TExpression { - if (ast.value.name === null) { - if (ast.value.moduleName === null) { - throw new Error('Invalid import without name nor moduleName'); - } - return this.imports.generateNamespaceImport(ast.value.moduleName); - } - // If a moduleName is specified, this is a normal import. If there's no module name, it's a - // reference to a global/ambient symbol. - if (ast.value.moduleName !== null) { - // This is a normal import. Find the imported module. - const { moduleImport, symbol } = this.imports.generateNamedImport( - ast.value.moduleName, - ast.value.name, - ); - if (moduleImport === null) { - // The symbol was ambient after all. - return this.factory.createIdentifier(symbol); - } else { - return this.factory.createPropertyAccess(moduleImport, symbol); - } - } else { - // The symbol is ambient, so just reference it. - return this.factory.createIdentifier(ast.value.name); - } - } - - visitConditionalExpr(ast: o.ConditionalExpr, context: Context): TExpression { - let cond: TExpression = ast.condition.visitExpression(this, context); - - // Ordinarily the ternary operator is right-associative. The following are equivalent: - // `a ? b : c ? d : e` => `a ? b : (c ? d : e)` - // - // However, occasionally Angular needs to produce a left-associative conditional, such as in - // the case of a null-safe navigation production: `{{a?.b ? c : d}}`. This template produces - // a ternary of the form: - // `a == null ? null : rest of expression` - // If the rest of the expression is also a ternary though, this would produce the form: - // `a == null ? null : a.b ? c : d` - // which, if left as right-associative, would be incorrectly associated as: - // `a == null ? null : (a.b ? c : d)` - // - // In such cases, the left-associativity needs to be enforced with parentheses: - // `(a == null ? null : a.b) ? c : d` - // - // Such parentheses could always be included in the condition (guaranteeing correct behavior) in - // all cases, but this has a code size cost. Instead, parentheses are added only when a - // conditional expression is directly used as the condition of another. - // - // TODO(alxhub): investigate better logic for precendence of conditional operators - if (ast.condition instanceof o.ConditionalExpr) { - // The condition of this ternary needs to be wrapped in parentheses to maintain - // left-associativity. - cond = this.factory.createParenthesizedExpression(cond); - } - - return this.factory.createConditional( - cond, - ast.trueCase.visitExpression(this, context), - ast.falseCase!.visitExpression(this, context), - ); - } - - visitDynamicImportExpr(ast: o.DynamicImportExpr, context: any) { - return this.factory.createDynamicImport(ast.url); - } - - visitNotExpr(ast: o.NotExpr, context: Context): TExpression { - return this.factory.createUnaryExpression( - '!', - ast.condition.visitExpression(this, context), - ); - } - - visitFunctionExpr(ast: o.FunctionExpr, context: Context): TExpression { - return this.factory.createFunctionExpression( - ast.name ?? null, - ast.params.map((param) => param.name), - this.factory.createBlock(this.visitStatements(ast.statements, context)), - ); - } - - visitArrowFunctionExpr(ast: o.ArrowFunctionExpr, context: any) { - return this.factory.createArrowFunctionExpression( - ast.params.map((param) => param.name), - Array.isArray(ast.body) - ? this.factory.createBlock(this.visitStatements(ast.body, context)) - : ast.body.visitExpression(this, context), - ); - } - - visitBinaryOperatorExpr( - ast: o.BinaryOperatorExpr, - context: Context, - ): TExpression { - if (!BINARY_OPERATORS.has(ast.operator)) { - throw new Error( - `Unknown binary operator: ${o.BinaryOperator[ast.operator]}`, - ); - } - return this.factory.createBinaryExpression( - ast.lhs.visitExpression(this, context), - BINARY_OPERATORS.get(ast.operator)!, - ast.rhs.visitExpression(this, context), - ); - } - - visitReadPropExpr(ast: o.ReadPropExpr, context: Context): TExpression { - return this.factory.createPropertyAccess( - ast.receiver.visitExpression(this, context), - ast.name, - ); - } - - visitReadKeyExpr(ast: o.ReadKeyExpr, context: Context): TExpression { - return this.factory.createElementAccess( - ast.receiver.visitExpression(this, context), - ast.index.visitExpression(this, context), - ); - } - - visitLiteralArrayExpr( - ast: o.LiteralArrayExpr, - context: Context, - ): TExpression { - return this.factory.createArrayLiteral( - ast.entries.map((expr) => - this.setSourceMapRange( - expr.visitExpression(this, context), - ast.sourceSpan, - ), - ), - ); - } - - visitLiteralMapExpr(ast: o.LiteralMapExpr, context: Context): TExpression { - const properties: ObjectLiteralProperty[] = ast.entries.map( - (entry) => { - return { - propertyName: entry.key, - quoted: entry.quoted, - value: entry.value.visitExpression(this, context), - }; - }, - ); - return this.setSourceMapRange( - this.factory.createObjectLiteral(properties), - ast.sourceSpan, - ); - } - - visitCommaExpr(ast: o.CommaExpr, context: Context): never { - throw new Error('Method not implemented.'); - } - - visitWrappedNodeExpr(ast: o.WrappedNodeExpr, _context: Context): any { - this.recordWrappedNode(ast); - return ast.node; - } - - visitTypeofExpr(ast: o.TypeofExpr, context: Context): TExpression { - return this.factory.createTypeOfExpression( - ast.expr.visitExpression(this, context), - ); - } - - visitUnaryOperatorExpr( - ast: o.UnaryOperatorExpr, - context: Context, - ): TExpression { - if (!UNARY_OPERATORS.has(ast.operator)) { - throw new Error( - `Unknown unary operator: ${o.UnaryOperator[ast.operator]}`, - ); - } - return this.factory.createUnaryExpression( - UNARY_OPERATORS.get(ast.operator)!, - ast.expr.visitExpression(this, context), - ); - } - - private visitStatements( - statements: o.Statement[], - context: Context, - ): TStatement[] { - return statements - .map((stmt) => stmt.visitStatement(this, context)) - .filter((stmt) => stmt !== undefined); - } - - private setSourceMapRange( - ast: T, - span: o.ParseSourceSpan | null, - ): T { - return this.factory.setSourceMapRange(ast, createRange(span)); - } - - private attachComments( - statement: TStatement, - leadingComments: o.LeadingComment[] | undefined, - ): TStatement { - if (leadingComments !== undefined) { - this.factory.attachComments(statement, leadingComments); - } - return statement; - } -} - -/** - * Convert an OutputAST source-span into a range that can be used by the AST factories. - */ -function createRange(span: o.ParseSourceSpan | null): SourceMapRange | null { - if (span === null) { - return null; - } - const { start, end } = span; - const { url, content } = start.file; - if (!url) { - return null; - } - return { - url, - content, - start: { offset: start.offset, line: start.line, column: start.col }, - end: { offset: end.offset, line: end.line, column: end.col }, - }; -} diff --git a/src/transform/compiler-cli/src/ngtsc/translator/src/ts_util.ts b/src/transform/compiler-cli/src/ngtsc/translator/src/ts_util.ts deleted file mode 100644 index 32cfee5..0000000 --- a/src/transform/compiler-cli/src/ngtsc/translator/src/ts_util.ts +++ /dev/null @@ -1,28 +0,0 @@ -/*! - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import ts from 'typescript'; - -/** - * Creates a TypeScript node representing a numeric value. - */ -export function tsNumericExpression( - value: number, -): ts.NumericLiteral | ts.PrefixUnaryExpression { - // As of TypeScript 5.3 negative numbers are represented as `prefixUnaryOperator` and passing a - // negative number (even as a string) into `createNumericLiteral` will result in an error. - if (value < 0) { - const operand = ts.factory.createNumericLiteral(Math.abs(value)); - return ts.factory.createPrefixUnaryExpression( - ts.SyntaxKind.MinusToken, - operand, - ); - } - - return ts.factory.createNumericLiteral(value); -} diff --git a/src/transform/compiler-cli/src/ngtsc/translator/src/typescript_ast_factory.ts b/src/transform/compiler-cli/src/ngtsc/translator/src/typescript_ast_factory.ts deleted file mode 100644 index d7a6cc9..0000000 --- a/src/transform/compiler-cli/src/ngtsc/translator/src/typescript_ast_factory.ts +++ /dev/null @@ -1,455 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import ts from 'typescript'; - -import { - AstFactory, - BinaryOperator, - LeadingComment, - ObjectLiteralProperty, - SourceMapRange, - TemplateLiteral, - UnaryOperator, - VariableDeclarationType, -} from './api/ast_factory'; -import { tsNumericExpression } from './ts_util'; - -/** - * Different optimizers use different annotations on a function or method call to indicate its pure - * status. - */ -enum PureAnnotation { - /** - * Closure's annotation for purity is `@pureOrBreakMyCode`, but this needs to be in a semantic - * (jsdoc) enabled comment. Thus, the actual comment text for Closure must include the `*` that - * turns a `/*` comment into a `/**` comment, as well as surrounding whitespace. - */ - CLOSURE = '* @pureOrBreakMyCode ', - - TERSER = '@__PURE__', -} - -const UNARY_OPERATORS: Record = { - '+': ts.SyntaxKind.PlusToken, - '-': ts.SyntaxKind.MinusToken, - '!': ts.SyntaxKind.ExclamationToken, -}; - -const BINARY_OPERATORS: Record = { - '&&': ts.SyntaxKind.AmpersandAmpersandToken, - '>': ts.SyntaxKind.GreaterThanToken, - '>=': ts.SyntaxKind.GreaterThanEqualsToken, - '&': ts.SyntaxKind.AmpersandToken, - '|': ts.SyntaxKind.BarToken, - '/': ts.SyntaxKind.SlashToken, - '==': ts.SyntaxKind.EqualsEqualsToken, - '===': ts.SyntaxKind.EqualsEqualsEqualsToken, - '<': ts.SyntaxKind.LessThanToken, - '<=': ts.SyntaxKind.LessThanEqualsToken, - '-': ts.SyntaxKind.MinusToken, - '%': ts.SyntaxKind.PercentToken, - '*': ts.SyntaxKind.AsteriskToken, - '!=': ts.SyntaxKind.ExclamationEqualsToken, - '!==': ts.SyntaxKind.ExclamationEqualsEqualsToken, - '||': ts.SyntaxKind.BarBarToken, - '+': ts.SyntaxKind.PlusToken, - '??': ts.SyntaxKind.QuestionQuestionToken, -}; - -const VAR_TYPES: Record = { - const: ts.NodeFlags.Const, - let: ts.NodeFlags.Let, - var: ts.NodeFlags.None, -}; - -/** - * A TypeScript flavoured implementation of the AstFactory. - */ -export class TypeScriptAstFactory - implements AstFactory -{ - private externalSourceFiles = new Map(); - - constructor(private annotateForClosureCompiler: boolean) {} - - attachComments = attachComments; - - createArrayLiteral = ts.factory.createArrayLiteralExpression; - - createAssignment(target: ts.Expression, value: ts.Expression): ts.Expression { - return ts.factory.createBinaryExpression( - target, - ts.SyntaxKind.EqualsToken, - value, - ); - } - - createBinaryExpression( - leftOperand: ts.Expression, - operator: BinaryOperator, - rightOperand: ts.Expression, - ): ts.Expression { - return ts.factory.createBinaryExpression( - leftOperand, - BINARY_OPERATORS[operator], - rightOperand, - ); - } - - createBlock(body: ts.Statement[]): ts.Statement { - return ts.factory.createBlock(body); - } - - createCallExpression( - callee: ts.Expression, - args: ts.Expression[], - pure: boolean, - ): ts.Expression { - const call = ts.factory.createCallExpression(callee, undefined, args); - if (pure) { - ts.addSyntheticLeadingComment( - call, - ts.SyntaxKind.MultiLineCommentTrivia, - this.annotateForClosureCompiler - ? PureAnnotation.CLOSURE - : PureAnnotation.TERSER, - /* trailing newline */ false, - ); - } - return call; - } - - createConditional( - condition: ts.Expression, - whenTrue: ts.Expression, - whenFalse: ts.Expression, - ): ts.Expression { - return ts.factory.createConditionalExpression( - condition, - undefined, - whenTrue, - undefined, - whenFalse, - ); - } - - createElementAccess = ts.factory.createElementAccessExpression; - - createExpressionStatement = ts.factory.createExpressionStatement; - - createDynamicImport(url: string) { - return ts.factory.createCallExpression( - ts.factory.createToken(ts.SyntaxKind.ImportKeyword) as ts.Expression, - /* type */ undefined, - [ts.factory.createStringLiteral(url)], - ); - } - - createFunctionDeclaration( - functionName: string, - parameters: string[], - body: ts.Statement, - ): ts.Statement { - if (!ts.isBlock(body)) { - throw new Error( - `Invalid syntax, expected a block, but got ${ts.SyntaxKind[body.kind]}.`, - ); - } - return ts.factory.createFunctionDeclaration( - undefined, - undefined, - functionName, - undefined, - parameters.map((param) => - ts.factory.createParameterDeclaration(undefined, undefined, param), - ), - undefined, - body, - ); - } - - createFunctionExpression( - functionName: string | null, - parameters: string[], - body: ts.Statement, - ): ts.Expression { - if (!ts.isBlock(body)) { - throw new Error( - `Invalid syntax, expected a block, but got ${ts.SyntaxKind[body.kind]}.`, - ); - } - return ts.factory.createFunctionExpression( - undefined, - undefined, - functionName ?? undefined, - undefined, - parameters.map((param) => - ts.factory.createParameterDeclaration(undefined, undefined, param), - ), - undefined, - body, - ); - } - - createArrowFunctionExpression( - parameters: string[], - body: ts.Statement | ts.Expression, - ): ts.Expression { - if (ts.isStatement(body) && !ts.isBlock(body)) { - throw new Error( - `Invalid syntax, expected a block, but got ${ts.SyntaxKind[body.kind]}.`, - ); - } - - return ts.factory.createArrowFunction( - undefined, - undefined, - parameters.map((param) => - ts.factory.createParameterDeclaration(undefined, undefined, param), - ), - undefined, - undefined, - body, - ); - } - - createIdentifier = ts.factory.createIdentifier; - - createIfStatement( - condition: ts.Expression, - thenStatement: ts.Statement, - elseStatement: ts.Statement | null, - ): ts.Statement { - return ts.factory.createIfStatement( - condition, - thenStatement, - elseStatement ?? undefined, - ); - } - - createLiteral( - value: string | number | boolean | null | undefined, - ): ts.Expression { - if (value === undefined) { - return ts.factory.createIdentifier('undefined'); - } else if (value === null) { - return ts.factory.createNull(); - } else if (typeof value === 'boolean') { - return value ? ts.factory.createTrue() : ts.factory.createFalse(); - } else if (typeof value === 'number') { - return tsNumericExpression(value); - } else { - return ts.factory.createStringLiteral(value); - } - } - - createNewExpression( - expression: ts.Expression, - args: ts.Expression[], - ): ts.Expression { - return ts.factory.createNewExpression(expression, undefined, args); - } - - createObjectLiteral( - properties: ObjectLiteralProperty[], - ): ts.Expression { - return ts.factory.createObjectLiteralExpression( - properties.map((prop) => - ts.factory.createPropertyAssignment( - prop.quoted - ? ts.factory.createStringLiteral(prop.propertyName) - : ts.factory.createIdentifier(prop.propertyName), - prop.value, - ), - ), - ); - } - - createParenthesizedExpression = ts.factory.createParenthesizedExpression; - - createPropertyAccess = ts.factory.createPropertyAccessExpression; - - createReturnStatement(expression: ts.Expression | null): ts.Statement { - return ts.factory.createReturnStatement(expression ?? undefined); - } - - createTaggedTemplate( - tag: ts.Expression, - template: TemplateLiteral, - ): ts.Expression { - let templateLiteral: ts.TemplateLiteral; - const length = template.elements.length; - const head = template.elements[0]; - if (length === 1) { - templateLiteral = ts.factory.createNoSubstitutionTemplateLiteral( - head.cooked, - head.raw, - ); - } else { - const spans: ts.TemplateSpan[] = []; - // Create the middle parts - for (let i = 1; i < length - 1; i++) { - const { cooked, raw, range } = template.elements[i]; - const middle = createTemplateMiddle(cooked, raw); - if (range !== null) { - this.setSourceMapRange(middle, range); - } - spans.push( - ts.factory.createTemplateSpan(template.expressions[i - 1], middle), - ); - } - // Create the tail part - const resolvedExpression = template.expressions[length - 2]; - const templatePart = template.elements[length - 1]; - const templateTail = createTemplateTail( - templatePart.cooked, - templatePart.raw, - ); - if (templatePart.range !== null) { - this.setSourceMapRange(templateTail, templatePart.range); - } - spans.push( - ts.factory.createTemplateSpan(resolvedExpression, templateTail), - ); - // Put it all together - templateLiteral = ts.factory.createTemplateExpression( - ts.factory.createTemplateHead(head.cooked, head.raw), - spans, - ); - } - if (head.range !== null) { - this.setSourceMapRange(templateLiteral, head.range); - } - return ts.factory.createTaggedTemplateExpression( - tag, - undefined, - templateLiteral, - ); - } - - createThrowStatement = ts.factory.createThrowStatement; - - createTypeOfExpression = ts.factory.createTypeOfExpression; - - createUnaryExpression( - operator: UnaryOperator, - operand: ts.Expression, - ): ts.Expression { - return ts.factory.createPrefixUnaryExpression( - UNARY_OPERATORS[operator], - operand, - ); - } - - createVariableDeclaration( - variableName: string, - initializer: ts.Expression | null, - type: VariableDeclarationType, - ): ts.Statement { - return ts.factory.createVariableStatement( - undefined, - ts.factory.createVariableDeclarationList( - [ - ts.factory.createVariableDeclaration( - variableName, - undefined, - undefined, - initializer ?? undefined, - ), - ], - VAR_TYPES[type], - ), - ); - } - - setSourceMapRange( - node: T, - sourceMapRange: SourceMapRange | null, - ): T { - if (sourceMapRange === null) { - return node; - } - - const url = sourceMapRange.url; - if (!this.externalSourceFiles.has(url)) { - this.externalSourceFiles.set( - url, - ts.createSourceMapSource(url, sourceMapRange.content, (pos) => pos), - ); - } - const source = this.externalSourceFiles.get(url); - ts.setSourceMapRange(node, { - pos: sourceMapRange.start.offset, - end: sourceMapRange.end.offset, - source, - }); - return node; - } -} - -// HACK: Use this in place of `ts.createTemplateMiddle()`. -// Revert once https://github.com/microsoft/TypeScript/issues/35374 is fixed. -export function createTemplateMiddle( - cooked: string, - raw: string, -): ts.TemplateMiddle { - const node: ts.TemplateLiteralLikeNode = ts.factory.createTemplateHead( - cooked, - raw, - ); - (node.kind as ts.SyntaxKind) = ts.SyntaxKind.TemplateMiddle; - return node as ts.TemplateMiddle; -} - -// HACK: Use this in place of `ts.createTemplateTail()`. -// Revert once https://github.com/microsoft/TypeScript/issues/35374 is fixed. -export function createTemplateTail( - cooked: string, - raw: string, -): ts.TemplateTail { - const node: ts.TemplateLiteralLikeNode = ts.factory.createTemplateHead( - cooked, - raw, - ); - (node.kind as ts.SyntaxKind) = ts.SyntaxKind.TemplateTail; - return node as ts.TemplateTail; -} - -/** - * Attach the given `leadingComments` to the `statement` node. - * - * @param statement The statement that will have comments attached. - * @param leadingComments The comments to attach to the statement. - */ -export function attachComments( - statement: ts.Statement, - leadingComments: LeadingComment[], -): void { - for (const comment of leadingComments) { - const commentKind = comment.multiline - ? ts.SyntaxKind.MultiLineCommentTrivia - : ts.SyntaxKind.SingleLineCommentTrivia; - if (comment.multiline) { - ts.addSyntheticLeadingComment( - statement, - commentKind, - comment.toString(), - comment.trailingNewline, - ); - } else { - for (const line of comment.toString().split('\n')) { - ts.addSyntheticLeadingComment( - statement, - commentKind, - line, - comment.trailingNewline, - ); - } - } - } -} diff --git a/src/transform/compiler-cli/src/ngtsc/translator/src/typescript_translator.ts b/src/transform/compiler-cli/src/ngtsc/translator/src/typescript_translator.ts deleted file mode 100644 index 7f1c07b..0000000 --- a/src/transform/compiler-cli/src/ngtsc/translator/src/typescript_translator.ts +++ /dev/null @@ -1,45 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import * as o from 'static-injector/transform/compiler'; -import ts from 'typescript'; - -import { ImportGenerator } from './api/import_generator'; -import { Context } from './context'; -import { ExpressionTranslatorVisitor, TranslatorOptions } from './translator'; -import { TypeScriptAstFactory } from './typescript_ast_factory'; - -export function translateExpression( - expression: o.Expression, - imports: ImportGenerator, - options: TranslatorOptions = {}, -): ts.Expression { - return expression.visitExpression( - new ExpressionTranslatorVisitor( - new TypeScriptAstFactory(options.annotateForClosureCompiler === true), - imports, - options, - ), - new Context(false), - ); -} - -export function translateStatement( - statement: o.Statement, - imports: ImportGenerator, - options: TranslatorOptions = {}, -): ts.Statement { - return statement.visitStatement( - new ExpressionTranslatorVisitor( - new TypeScriptAstFactory(options.annotateForClosureCompiler === true), - imports, - options, - ), - new Context(true), - ); -} diff --git a/src/transform/compiler-cli/src/ngtsc/ts_compatibility/index.ts b/src/transform/compiler-cli/src/ngtsc/ts_compatibility/index.ts deleted file mode 100644 index c45d307..0000000 --- a/src/transform/compiler-cli/src/ngtsc/ts_compatibility/index.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -export * from './src/ts_cross_version_utils'; diff --git a/src/transform/compiler-cli/src/ngtsc/ts_compatibility/src/ts_cross_version_utils.ts b/src/transform/compiler-cli/src/ngtsc/ts_compatibility/src/ts_cross_version_utils.ts deleted file mode 100644 index 6c839ed..0000000 --- a/src/transform/compiler-cli/src/ngtsc/ts_compatibility/src/ts_cross_version_utils.ts +++ /dev/null @@ -1,166 +0,0 @@ -/*! - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import ts from 'typescript'; - -/** Whether the current TypeScript version is after 4.9. */ -const IS_AFTER_TS_49 = isAfterVersion(4, 9); - -/** Type of `ts.factory.CreateParameterDeclaration` in TS 4.9+. */ -type Ts49CreateParameterDeclarationFn = ( - modifiers: readonly ts.ModifierLike[] | undefined, - dotDotDotToken: ts.DotDotDotToken | undefined, - name: string | ts.BindingName, - questionToken?: ts.QuestionToken | undefined, - type?: ts.TypeNode | undefined, - initializer?: ts.Expression, -) => ts.ParameterDeclaration; - -/** - * Creates a `ts.ParameterDeclaration` declaration. - * - * TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.9. - * We should remove it once we have dropped support for the older versions. - */ -export const createParameterDeclaration: Ts49CreateParameterDeclarationFn = - IS_AFTER_TS_49 - ? (ts.factory.createParameterDeclaration as any) - : (modifiers, dotDotDotToken, name, questionToken, type, initializer) => - (ts.factory.createParameterDeclaration as any)( - ...splitModifiers(modifiers), - dotDotDotToken, - name, - questionToken, - type, - initializer, - ); - -/** Type of `ts.factory.createImportDeclaration` in TS 4.9+. */ -type Ts49CreateImportDeclarationFn = ( - modifiers: readonly ts.Modifier[] | undefined, - importClause: ts.ImportClause | undefined, - moduleSpecifier: ts.Expression, - assertClause?: ts.AssertClause, -) => ts.ImportDeclaration; - -/** - * Creates a `ts.ImportDeclaration` declaration. - * - * TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.9. - * We should remove it once we have dropped support for the older versions. - */ -export const createImportDeclaration: Ts49CreateImportDeclarationFn = - IS_AFTER_TS_49 - ? (ts.factory.createImportDeclaration as any) - : (modifiers, importClause, moduleSpecifier, assertClause) => - (ts.factory.createImportDeclaration as any)( - undefined, - modifiers, - importClause, - moduleSpecifier, - assertClause, - ); - -/** Type of `ts.factory.createFunctionDeclaration` in TS 4.9+. */ -type Ts49CreateFunctionDeclarationFn = ( - modifiers: readonly ts.ModifierLike[] | undefined, - asteriskToken: ts.AsteriskToken | undefined, - name: string | ts.Identifier | undefined, - typeParameters: readonly ts.TypeParameterDeclaration[] | undefined, - parameters: readonly ts.ParameterDeclaration[], - type: ts.TypeNode | undefined, - body: ts.Block | undefined, -) => ts.FunctionDeclaration; - -/** - * Creates a `ts.FunctionDeclaration` declaration. - * - * TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.9. - * We should remove it once we have dropped support for the older versions. - */ -export const createFunctionDeclaration: Ts49CreateFunctionDeclarationFn = - IS_AFTER_TS_49 - ? (ts.factory.createFunctionDeclaration as any) - : ( - modifiers, - asteriskToken, - name, - typeParameters, - parameters, - type, - body, - ) => - (ts.factory.createFunctionDeclaration as any)( - ...splitModifiers(modifiers), - asteriskToken, - name, - typeParameters, - parameters, - type, - body, - ); - -/** Type of `ts.factory.createIndexSignature` in TS 4.9+. */ -type Ts49CreateIndexSignatureFn = ( - modifiers: readonly ts.Modifier[] | undefined, - parameters: readonly ts.ParameterDeclaration[], - type: ts.TypeNode, -) => ts.IndexSignatureDeclaration; - -/** - * Creates a `ts.IndexSignatureDeclaration` declaration. - * - * TODO(crisbeto): this is a backwards-compatibility layer for versions of TypeScript less than 4.9. - * We should remove it once we have dropped support for the older versions. - */ -export const createIndexSignature: Ts49CreateIndexSignatureFn = IS_AFTER_TS_49 - ? (ts.factory.createIndexSignature as any) - : (modifiers, parameters, type) => - (ts.factory.createIndexSignature as any)(modifiers, parameters, type); - -/** - * Splits a `ModifierLike` into two arrays: decorators and modifiers. Used for backwards - * compatibility with TS 4.7 and below where most factory functions require separate `decorators` - * and `modifiers` arrays. - */ -function splitModifiers( - allModifiers: readonly ts.ModifierLike[] | undefined, -): [ts.Decorator[] | undefined, ts.Modifier[] | undefined] { - if (!allModifiers) { - return [undefined, undefined]; - } - - const decorators: ts.Decorator[] = []; - const modifiers: ts.Modifier[] = []; - - for (const current of allModifiers) { - if (ts.isDecorator(current)) { - decorators.push(current); - } else { - modifiers.push(current); - } - } - - return [ - decorators.length ? decorators : undefined, - modifiers.length ? modifiers : undefined, - ]; -} - -/** Checks if the current version of TypeScript is after the specified major/minor versions. */ -function isAfterVersion(targetMajor: number, targetMinor: number): boolean { - const [major, minor] = ts.versionMajorMinor - .split('.') - .map((part) => parseInt(part)); - - if (major < targetMajor) { - return false; - } - - return major === targetMajor ? minor >= targetMinor : true; -} diff --git a/src/transform/compiler-cli/src/ngtsc/util/src/typescript.ts b/src/transform/compiler-cli/src/ngtsc/util/src/typescript.ts deleted file mode 100644 index 9e86bda..0000000 --- a/src/transform/compiler-cli/src/ngtsc/util/src/typescript.ts +++ /dev/null @@ -1,11 +0,0 @@ -import ts from 'typescript'; - -export function identifierOfNode( - decl: ts.Node & { name?: ts.Node }, -): ts.Identifier | null { - if (decl.name !== undefined && ts.isIdentifier(decl.name)) { - return decl.name; - } else { - return null; - } -} diff --git a/src/transform/compiler/compiler.ts b/src/transform/compiler/compiler.ts deleted file mode 100644 index 7ef6571..0000000 --- a/src/transform/compiler/compiler.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -// This file is not used to build this module. It is only used during editing -// by the TypeScript language service and during build for verification. `ngc` -// replaces this file with production index.ts when it rewrites private symbol -// names. - -export * from './public_api'; diff --git a/src/transform/compiler/index.ts b/src/transform/compiler/index.ts deleted file mode 100644 index e4acb3b..0000000 --- a/src/transform/compiler/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -// This file is not used to build this module. It is only used during editing -// by the TypeScript language service and during build for verification. `ngc` -// replaces this file with production index.ts when it rewrites private symbol -// names. - -export * from './compiler'; diff --git a/src/transform/compiler/public_api.ts b/src/transform/compiler/public_api.ts deleted file mode 100644 index d5d954a..0000000 --- a/src/transform/compiler/public_api.ts +++ /dev/null @@ -1,16 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -/** - * @module - * @description - * Entry point for all public APIs of this package. - */ -export * from './src/compiler'; - -// This file only reexports content of the `src` folder. Keep it that way. diff --git a/src/transform/compiler/src/compiler.ts b/src/transform/compiler/src/compiler.ts deleted file mode 100644 index 475d0b0..0000000 --- a/src/transform/compiler/src/compiler.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from './injectable_compiler_2'; -export * from './render3/r3_factory'; -export * from './output/output_ast'; -export * from './render3/util'; -export * from './parse_util'; diff --git a/src/transform/compiler/src/core.ts b/src/transform/compiler/src/core.ts deleted file mode 100644 index acbe945..0000000 --- a/src/transform/compiler/src/core.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -// Attention: -// This file duplicates types and values from @angular/core -// so that we are able to make @angular/compiler independent of @angular/core. -// This is important to prevent a build cycle, as @angular/core needs to -// be compiled with the compiler. - -/** Flags describing an input for a directive. */ -export enum InputFlags { - None = 0, - SignalBased = 1 << 0, - HasDecoratorInputTransform = 1 << 1, -} - -/** - * Injection flags for DI. - */ -export const enum InjectFlags { - Default = 0, - - /** Don't descend into ancestors of the node requesting injection. */ - Self = 1 << 1, - /** Skip the node that is requesting injection. */ - SkipSelf = 1 << 2, - /** Inject `defaultValue` instead if token not found. */ - Optional = 1 << 3, -} diff --git a/src/transform/compiler/src/injectable_compiler_2.ts b/src/transform/compiler/src/injectable_compiler_2.ts deleted file mode 100644 index 826abe7..0000000 --- a/src/transform/compiler/src/injectable_compiler_2.ts +++ /dev/null @@ -1,207 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import * as o from './output/output_ast'; -import { - compileFactoryFunction, - FactoryTarget, - R3DependencyMetadata, - R3FactoryDelegateType, - R3FactoryMetadata, -} from './render3/r3_factory'; -import { Identifiers } from './render3/r3_identifiers'; -import { - convertFromMaybeForwardRefExpression, - ForwardRefHandling, - generateForwardRef, - MaybeForwardRefExpression, - R3CompiledExpression, - R3Reference, - typeWithParameters, -} from './render3/util'; -import { DefinitionMap } from './render3/view/util'; - -export interface R3InjectableMetadata { - name: string; - type: R3Reference; - typeArgumentCount: number; - providedIn: MaybeForwardRefExpression; - useClass?: MaybeForwardRefExpression; - useFactory?: o.Expression; - useExisting?: MaybeForwardRefExpression; - useValue?: MaybeForwardRefExpression; - deps?: R3DependencyMetadata[]; -} - -export function compileInjectable( - meta: R3InjectableMetadata, - resolveForwardRefs: boolean, -): R3CompiledExpression { - let result: { expression: o.Expression; statements: o.Statement[] } | null = - null; - - const factoryMeta: R3FactoryMetadata = { - name: meta.name, - type: meta.type, - typeArgumentCount: meta.typeArgumentCount, - deps: [], - target: FactoryTarget.Injectable, - }; - - if (meta.useClass !== undefined) { - // meta.useClass has two modes of operation. Either deps are specified, in which case `new` is - // used to instantiate the class with dependencies injected, or deps are not specified and - // the factory of the class is used to instantiate it. - // - // A special case exists for useClass: Type where Type is the injectable type itself and no - // deps are specified, in which case 'useClass' is effectively ignored. - - const useClassOnSelf = meta.useClass.expression.isEquivalent( - meta.type.value, - ); - let deps: R3DependencyMetadata[] | undefined = undefined; - if (meta.deps !== undefined) { - deps = meta.deps; - } - - if (deps !== undefined) { - // factory: () => new meta.useClass(...deps) - result = compileFactoryFunction({ - ...factoryMeta, - delegate: meta.useClass.expression, - delegateDeps: deps, - delegateType: R3FactoryDelegateType.Class, - }); - } else if (useClassOnSelf) { - result = compileFactoryFunction(factoryMeta); - } else { - result = { - statements: [], - expression: delegateToFactory( - meta.type.value as o.WrappedNodeExpr, - meta.useClass.expression as o.WrappedNodeExpr, - resolveForwardRefs, - ), - }; - } - } else if (meta.useFactory !== undefined) { - if (meta.deps !== undefined) { - result = compileFactoryFunction({ - ...factoryMeta, - delegate: meta.useFactory, - delegateDeps: meta.deps || [], - delegateType: R3FactoryDelegateType.Function, - }); - } else { - result = { - statements: [], - expression: o.arrowFn([], meta.useFactory.callFn([])), - }; - } - } else if (meta.useValue !== undefined) { - // Note: it's safe to use `meta.useValue` instead of the `USE_VALUE in meta` check used for - // client code because meta.useValue is an Expression which will be defined even if the actual - // value is undefined. - result = compileFactoryFunction({ - ...factoryMeta, - expression: meta.useValue.expression, - }); - } else if (meta.useExisting !== undefined) { - // useExisting is an `inject` call on the existing token. - result = compileFactoryFunction({ - ...factoryMeta, - expression: o - .importExpr(Identifiers.inject) - .callFn([meta.useExisting.expression]), - }); - } else { - result = { - statements: [], - expression: delegateToFactory( - meta.type.value as o.WrappedNodeExpr, - meta.type.value as o.WrappedNodeExpr, - resolveForwardRefs, - ), - }; - } - - const token = meta.type.value; - - const injectableProps = new DefinitionMap<{ - token: o.Expression; - factory: o.Expression; - providedIn: o.Expression; - }>(); - injectableProps.set('token', token); - injectableProps.set('factory', result.expression); - - // Only generate providedIn property if it has a non-null value - if ((meta.providedIn.expression as o.LiteralExpr).value !== null) { - injectableProps.set( - 'providedIn', - convertFromMaybeForwardRefExpression(meta.providedIn), - ); - } - - const expression = o - .importExpr(Identifiers.ɵɵdefineInjectable) - .callFn([injectableProps.toLiteralMap()], undefined, true); - return { - expression, - type: createInjectableType(meta), - statements: result.statements, - }; -} - -export function createInjectableType(meta: R3InjectableMetadata) { - return new o.ExpressionType( - o.importExpr(Identifiers.InjectableDeclaration, [ - typeWithParameters(meta.type.type, meta.typeArgumentCount), - ]), - ); -} - -function delegateToFactory( - type: o.WrappedNodeExpr, - useType: o.WrappedNodeExpr, - unwrapForwardRefs: boolean, -): o.Expression { - if (type.node === useType.node) { - // The types are the same, so we can simply delegate directly to the type's factory. - // ``` - // factory: type.ɵfac - // ``` - return useType.prop('ɵfac'); - } - - if (!unwrapForwardRefs) { - // The type is not wrapped in a `forwardRef()`, so we create a simple factory function that - // accepts a sub-type as an argument. - // ``` - // factory: function(t) { return useType.ɵfac(t); } - // ``` - return createFactoryFunction(useType); - } - - // The useType is actually wrapped in a `forwardRef()` so we need to resolve that before - // calling its factory. - // ``` - // factory: function(t) { return core.resolveForwardRef(type).ɵfac(t); } - // ``` - const unwrappedType = o - .importExpr(Identifiers.resolveForwardRef) - .callFn([useType]); - return createFactoryFunction(unwrappedType); -} - -function createFactoryFunction(type: o.Expression): o.ArrowFunctionExpr { - return o.arrowFn( - [new o.FnParam('t', o.DYNAMIC_TYPE)], - type.prop('ɵfac').callFn([o.variable('t')]), - ); -} diff --git a/src/transform/compiler/src/output/output_ast.ts b/src/transform/compiler/src/output/output_ast.ts deleted file mode 100644 index dad85b6..0000000 --- a/src/transform/compiler/src/output/output_ast.ts +++ /dev/null @@ -1,1620 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { ParseSourceSpan } from '../parse_util'; - -//// Types -export enum TypeModifier { - None = 0, - Const = 1 << 0, -} - -export abstract class Type { - constructor(public modifiers: TypeModifier = TypeModifier.None) {} - abstract visitType(visitor: TypeVisitor, context: any): any; - - hasModifier(modifier: TypeModifier): boolean { - return (this.modifiers & modifier) !== 0; - } -} - -export enum BuiltinTypeName { - Dynamic, - Bool, - String, - Int, - Number, - Function, - Inferred, - None, -} - -export class BuiltinType extends Type { - constructor( - public name: BuiltinTypeName, - modifiers?: TypeModifier, - ) { - super(modifiers); - } - override visitType(visitor: TypeVisitor, context: any): any { - return visitor.visitBuiltinType(this, context); - } -} - -export class ExpressionType extends Type { - constructor( - public value: Expression, - modifiers?: TypeModifier, - public typeParams: Type[] | null = null, - ) { - super(modifiers); - } - override visitType(visitor: TypeVisitor, context: any): any { - return visitor.visitExpressionType(this, context); - } -} - -export class ArrayType extends Type { - constructor( - public of: Type, - modifiers?: TypeModifier, - ) { - super(modifiers); - } - override visitType(visitor: TypeVisitor, context: any): any { - return visitor.visitArrayType(this, context); - } -} - -export class MapType extends Type { - public valueType: Type | null; - constructor(valueType: Type | null | undefined, modifiers?: TypeModifier) { - super(modifiers); - this.valueType = valueType || null; - } - override visitType(visitor: TypeVisitor, context: any): any { - return visitor.visitMapType(this, context); - } -} - -export class TransplantedType extends Type { - constructor( - readonly type: T, - modifiers?: TypeModifier, - ) { - super(modifiers); - } - override visitType(visitor: TypeVisitor, context: any): any { - return visitor.visitTransplantedType(this, context); - } -} - -export const DYNAMIC_TYPE = new BuiltinType(BuiltinTypeName.Dynamic); -export const INFERRED_TYPE = new BuiltinType(BuiltinTypeName.Inferred); -export const BOOL_TYPE = new BuiltinType(BuiltinTypeName.Bool); -export const INT_TYPE = new BuiltinType(BuiltinTypeName.Int); -export const NUMBER_TYPE = new BuiltinType(BuiltinTypeName.Number); -export const STRING_TYPE = new BuiltinType(BuiltinTypeName.String); -export const FUNCTION_TYPE = new BuiltinType(BuiltinTypeName.Function); -export const NONE_TYPE = new BuiltinType(BuiltinTypeName.None); - -export interface TypeVisitor { - visitBuiltinType(type: BuiltinType, context: any): any; - visitExpressionType(type: ExpressionType, context: any): any; - visitArrayType(type: ArrayType, context: any): any; - visitMapType(type: MapType, context: any): any; - visitTransplantedType(type: TransplantedType, context: any): any; -} - -///// Expressions - -export enum UnaryOperator { - Minus, - Plus, -} - -export enum BinaryOperator { - Equals, - NotEquals, - Identical, - NotIdentical, - Minus, - Plus, - Divide, - Multiply, - Modulo, - And, - Or, - BitwiseOr, - BitwiseAnd, - Lower, - LowerEquals, - Bigger, - BiggerEquals, - NullishCoalesce, -} - -export function nullSafeIsEquivalent< - T extends { isEquivalent(other: T): boolean }, ->(base: T | null, other: T | null) { - if (base == null || other == null) { - return base == other; - } - return base.isEquivalent(other); -} - -function areAllEquivalentPredicate( - base: T[], - other: T[], - equivalentPredicate: (baseElement: T, otherElement: T) => boolean, -) { - const len = base.length; - if (len !== other.length) { - return false; - } - for (let i = 0; i < len; i++) { - if (!equivalentPredicate(base[i], other[i])) { - return false; - } - } - return true; -} - -export function areAllEquivalent( - base: T[], - other: T[], -) { - return areAllEquivalentPredicate( - base, - other, - (baseElement: T, otherElement: T) => baseElement.isEquivalent(otherElement), - ); -} - -export abstract class Expression { - public type: Type | null; - public sourceSpan: ParseSourceSpan | null; - - constructor( - type: Type | null | undefined, - sourceSpan?: ParseSourceSpan | null, - ) { - this.type = type || null; - this.sourceSpan = sourceSpan || null; - } - - abstract visitExpression(visitor: ExpressionVisitor, context: any): any; - - /** - * Calculates whether this expression produces the same value as the given expression. - * Note: We don't check Types nor ParseSourceSpans nor function arguments. - */ - abstract isEquivalent(e: Expression): boolean; - - /** - * Return true if the expression is constant. - */ - abstract isConstant(): boolean; - - abstract clone(): Expression; - - prop(name: string, sourceSpan?: ParseSourceSpan | null): ReadPropExpr { - return new ReadPropExpr(this, name, null, sourceSpan); - } - - key( - index: Expression, - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - ): ReadKeyExpr { - return new ReadKeyExpr(this, index, type, sourceSpan); - } - - callFn( - params: Expression[], - sourceSpan?: ParseSourceSpan | null, - pure?: boolean, - ): InvokeFunctionExpr { - return new InvokeFunctionExpr(this, params, null, sourceSpan, pure); - } - bitwiseOr( - rhs: Expression, - sourceSpan?: ParseSourceSpan | null, - parens: boolean = true, - ): BinaryOperatorExpr { - return new BinaryOperatorExpr( - BinaryOperator.BitwiseOr, - this, - rhs, - null, - sourceSpan, - parens, - ); - } - - toStmt(): Statement { - return new ExpressionStatement(this, null); - } -} - -export class ReadVarExpr extends Expression { - constructor( - public name: string, - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - ) { - super(type, sourceSpan); - } - - override isEquivalent(e: Expression): boolean { - return e instanceof ReadVarExpr && this.name === e.name; - } - - override isConstant() { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitReadVarExpr(this, context); - } - - override clone(): ReadVarExpr { - return new ReadVarExpr(this.name, this.type, this.sourceSpan); - } - - set(value: Expression): WriteVarExpr { - return new WriteVarExpr(this.name, value, null, this.sourceSpan); - } -} - -export class TypeofExpr extends Expression { - constructor( - public expr: Expression, - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - ) { - super(type, sourceSpan); - } - - override visitExpression(visitor: ExpressionVisitor, context: any) { - return visitor.visitTypeofExpr(this, context); - } - - override isEquivalent(e: Expression): boolean { - return e instanceof TypeofExpr && e.expr.isEquivalent(this.expr); - } - - override isConstant(): boolean { - return this.expr.isConstant(); - } - - override clone(): TypeofExpr { - return new TypeofExpr(this.expr.clone()); - } -} - -export class WrappedNodeExpr extends Expression { - constructor( - public node: T, - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - ) { - super(type, sourceSpan); - } - - override isEquivalent(e: Expression): boolean { - return e instanceof WrappedNodeExpr && this.node === e.node; - } - - override isConstant() { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitWrappedNodeExpr(this, context); - } - - override clone(): WrappedNodeExpr { - return new WrappedNodeExpr(this.node, this.type, this.sourceSpan); - } -} - -export class WriteVarExpr extends Expression { - public value: Expression; - constructor( - public name: string, - value: Expression, - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - ) { - super(type || value.type, sourceSpan); - this.value = value; - } - - override isEquivalent(e: Expression): boolean { - return ( - e instanceof WriteVarExpr && - this.name === e.name && - this.value.isEquivalent(e.value) - ); - } - - override isConstant() { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitWriteVarExpr(this, context); - } - - override clone(): WriteVarExpr { - return new WriteVarExpr( - this.name, - this.value.clone(), - this.type, - this.sourceSpan, - ); - } - - toDeclStmt(type?: Type | null, modifiers?: StmtModifier): DeclareVarStmt { - return new DeclareVarStmt( - this.name, - this.value, - type, - modifiers, - this.sourceSpan, - ); - } - - toConstDecl(): DeclareVarStmt { - return this.toDeclStmt(INFERRED_TYPE, StmtModifier.Final); - } -} - -export class WriteKeyExpr extends Expression { - public value: Expression; - constructor( - public receiver: Expression, - public index: Expression, - value: Expression, - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - ) { - super(type || value.type, sourceSpan); - this.value = value; - } - - override isEquivalent(e: Expression): boolean { - return ( - e instanceof WriteKeyExpr && - this.receiver.isEquivalent(e.receiver) && - this.index.isEquivalent(e.index) && - this.value.isEquivalent(e.value) - ); - } - - override isConstant() { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitWriteKeyExpr(this, context); - } - - override clone(): WriteKeyExpr { - return new WriteKeyExpr( - this.receiver.clone(), - this.index.clone(), - this.value.clone(), - this.type, - this.sourceSpan, - ); - } -} - -export class WritePropExpr extends Expression { - public value: Expression; - constructor( - public receiver: Expression, - public name: string, - value: Expression, - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - ) { - super(type || value.type, sourceSpan); - this.value = value; - } - - override isEquivalent(e: Expression): boolean { - return ( - e instanceof WritePropExpr && - this.receiver.isEquivalent(e.receiver) && - this.name === e.name && - this.value.isEquivalent(e.value) - ); - } - - override isConstant() { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitWritePropExpr(this, context); - } - - override clone(): WritePropExpr { - return new WritePropExpr( - this.receiver.clone(), - this.name, - this.value.clone(), - this.type, - this.sourceSpan, - ); - } -} - -export class InvokeFunctionExpr extends Expression { - constructor( - public fn: Expression, - public args: Expression[], - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - public pure = false, - ) { - super(type, sourceSpan); - } - - // An alias for fn, which allows other logic to handle calls and property reads together. - get receiver(): Expression { - return this.fn; - } - - override isEquivalent(e: Expression): boolean { - return ( - e instanceof InvokeFunctionExpr && - this.fn.isEquivalent(e.fn) && - areAllEquivalent(this.args, e.args) && - this.pure === e.pure - ); - } - - override isConstant() { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitInvokeFunctionExpr(this, context); - } - - override clone(): InvokeFunctionExpr { - return new InvokeFunctionExpr( - this.fn.clone(), - this.args.map((arg) => arg.clone()), - this.type, - this.sourceSpan, - this.pure, - ); - } -} - -export class InstantiateExpr extends Expression { - constructor( - public classExpr: Expression, - public args: Expression[], - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - ) { - super(type, sourceSpan); - } - - override isEquivalent(e: Expression): boolean { - return ( - e instanceof InstantiateExpr && - this.classExpr.isEquivalent(e.classExpr) && - areAllEquivalent(this.args, e.args) - ); - } - - override isConstant() { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitInstantiateExpr(this, context); - } - - override clone(): InstantiateExpr { - return new InstantiateExpr( - this.classExpr.clone(), - this.args.map((arg) => arg.clone()), - this.type, - this.sourceSpan, - ); - } -} - -export class LiteralExpr extends Expression { - constructor( - public value: number | string | boolean | null | undefined, - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - ) { - super(type, sourceSpan); - } - - override isEquivalent(e: Expression): boolean { - return e instanceof LiteralExpr && this.value === e.value; - } - - override isConstant() { - return true; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitLiteralExpr(this, context); - } - - override clone(): LiteralExpr { - return new LiteralExpr(this.value, this.type, this.sourceSpan); - } -} - -export class TemplateLiteral { - constructor( - public elements: TemplateLiteralElement[], - public expressions: Expression[], - ) {} - - clone(): TemplateLiteral { - return new TemplateLiteral( - this.elements.map((el) => el.clone()), - this.expressions.map((expr) => expr.clone()), - ); - } -} -export class TemplateLiteralElement { - rawText: string; - constructor( - public text: string, - public sourceSpan?: ParseSourceSpan, - rawText?: string, - ) { - // If `rawText` is not provided, try to extract the raw string from its - // associated `sourceSpan`. If that is also not available, "fake" the raw - // string instead by escaping the following control sequences: - // - "\" would otherwise indicate that the next character is a control character. - // - "`" and "${" are template string control sequences that would otherwise prematurely - // indicate the end of the template literal element. - this.rawText = - rawText ?? - sourceSpan?.toString() ?? - escapeForTemplateLiteral(escapeSlashes(text)); - } - - clone(): TemplateLiteralElement { - return new TemplateLiteralElement(this.text, this.sourceSpan, this.rawText); - } -} - -export class LiteralPiece { - constructor( - public text: string, - public sourceSpan: ParseSourceSpan, - ) {} -} - -/** - * A structure to hold the cooked and raw strings of a template literal element, along with its - * source-span range. - */ -export interface CookedRawString { - cooked: string; - raw: string; - range: ParseSourceSpan | null; -} - -const escapeSlashes = (str: string): string => str.replace(/\\/g, '\\\\'); -const escapeStartingColon = (str: string): string => str.replace(/^:/, '\\:'); -const escapeColons = (str: string): string => str.replace(/:/g, '\\:'); -const escapeForTemplateLiteral = (str: string): string => - str.replace(/`/g, '\\`').replace(/\${/g, '$\\{'); - -/** - * Creates a `{cooked, raw}` object from the `metaBlock` and `messagePart`. - * - * The `raw` text must have various character sequences escaped: - * * "\" would otherwise indicate that the next character is a control character. - * * "`" and "${" are template string control sequences that would otherwise prematurely indicate - * the end of a message part. - * * ":" inside a metablock would prematurely indicate the end of the metablock. - * * ":" at the start of a messagePart with no metablock would erroneously indicate the start of a - * metablock. - * - * @param metaBlock Any metadata that should be prepended to the string - * @param messagePart The message part of the string - */ -function createCookedRawString( - metaBlock: string, - messagePart: string, - range: ParseSourceSpan | null, -): CookedRawString { - if (metaBlock === '') { - return { - cooked: messagePart, - raw: escapeForTemplateLiteral( - escapeStartingColon(escapeSlashes(messagePart)), - ), - range, - }; - } else { - return { - cooked: `:${metaBlock}:${messagePart}`, - raw: escapeForTemplateLiteral( - `:${escapeColons(escapeSlashes(metaBlock))}:${escapeSlashes( - messagePart, - )}`, - ), - range, - }; - } -} - -export class ExternalExpr extends Expression { - constructor( - public value: ExternalReference, - type?: Type | null, - public typeParams: Type[] | null = null, - sourceSpan?: ParseSourceSpan | null, - ) { - super(type, sourceSpan); - } - - override isEquivalent(e: Expression): boolean { - return ( - e instanceof ExternalExpr && - this.value.name === e.value.name && - this.value.moduleName === e.value.moduleName && - this.value.runtime === e.value.runtime - ); - } - - override isConstant() { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitExternalExpr(this, context); - } - - override clone(): ExternalExpr { - return new ExternalExpr( - this.value, - this.type, - this.typeParams, - this.sourceSpan, - ); - } -} - -export class ExternalReference { - constructor( - public moduleName: string | null, - public name: string | null, - public runtime?: any | null, - ) {} - // Note: no isEquivalent method here as we use this as an interface too. -} - -export class ConditionalExpr extends Expression { - public trueCase: Expression; - - constructor( - public condition: Expression, - trueCase: Expression, - public falseCase: Expression | null = null, - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - ) { - super(type || trueCase.type, sourceSpan); - this.trueCase = trueCase; - } - - override isEquivalent(e: Expression): boolean { - return ( - e instanceof ConditionalExpr && - this.condition.isEquivalent(e.condition) && - this.trueCase.isEquivalent(e.trueCase) && - nullSafeIsEquivalent(this.falseCase, e.falseCase) - ); - } - - override isConstant() { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitConditionalExpr(this, context); - } - - override clone(): ConditionalExpr { - return new ConditionalExpr( - this.condition.clone(), - this.trueCase.clone(), - this.falseCase?.clone(), - this.type, - this.sourceSpan, - ); - } -} - -export class DynamicImportExpr extends Expression { - constructor( - public url: string, - sourceSpan?: ParseSourceSpan | null, - ) { - super(null, sourceSpan); - } - - override isEquivalent(e: Expression): boolean { - return e instanceof DynamicImportExpr && this.url === e.url; - } - - override isConstant() { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitDynamicImportExpr(this, context); - } - - override clone(): DynamicImportExpr { - return new DynamicImportExpr(this.url, this.sourceSpan); - } -} - -export class NotExpr extends Expression { - constructor( - public condition: Expression, - sourceSpan?: ParseSourceSpan | null, - ) { - super(BOOL_TYPE, sourceSpan); - } - - override isEquivalent(e: Expression): boolean { - return e instanceof NotExpr && this.condition.isEquivalent(e.condition); - } - - override isConstant() { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitNotExpr(this, context); - } - - override clone(): NotExpr { - return new NotExpr(this.condition.clone(), this.sourceSpan); - } -} - -export class FnParam { - constructor( - public name: string, - public type: Type | null = null, - ) {} - - isEquivalent(param: FnParam): boolean { - return this.name === param.name; - } - - clone(): FnParam { - return new FnParam(this.name, this.type); - } -} - -export class FunctionExpr extends Expression { - constructor( - public params: FnParam[], - public statements: Statement[], - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - public name?: string | null, - ) { - super(type, sourceSpan); - } - - override isEquivalent(e: Expression | Statement): boolean { - return ( - (e instanceof FunctionExpr || e instanceof DeclareFunctionStmt) && - areAllEquivalent(this.params, e.params) && - areAllEquivalent(this.statements, e.statements) - ); - } - - override isConstant() { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitFunctionExpr(this, context); - } - - toDeclStmt(name: string, modifiers?: StmtModifier): DeclareFunctionStmt { - return new DeclareFunctionStmt( - name, - this.params, - this.statements, - this.type, - modifiers, - this.sourceSpan, - ); - } - - override clone(): FunctionExpr { - // TODO: Should we deep clone statements? - return new FunctionExpr( - this.params.map((p) => p.clone()), - this.statements, - this.type, - this.sourceSpan, - this.name, - ); - } -} - -export class ArrowFunctionExpr extends Expression { - // Note that `body: Expression` represents `() => expr` whereas - // `body: Statement[]` represents `() => { expr }`. - - constructor( - public params: FnParam[], - public body: Expression | Statement[], - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - ) { - super(type, sourceSpan); - } - - override isEquivalent(e: Expression): boolean { - if ( - !(e instanceof ArrowFunctionExpr) || - !areAllEquivalent(this.params, e.params) - ) { - return false; - } - - if (this.body instanceof Expression && e.body instanceof Expression) { - return this.body.isEquivalent(e.body); - } - - if (Array.isArray(this.body) && Array.isArray(e.body)) { - return areAllEquivalent(this.body, e.body); - } - - return false; - } - - override isConstant(): boolean { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any) { - return visitor.visitArrowFunctionExpr(this, context); - } - - override clone(): Expression { - // TODO: Should we deep clone statements? - return new ArrowFunctionExpr( - this.params.map((p) => p.clone()), - Array.isArray(this.body) ? this.body : this.body.clone(), - this.type, - this.sourceSpan, - ); - } - - toDeclStmt(name: string, modifiers?: StmtModifier): DeclareVarStmt { - return new DeclareVarStmt( - name, - this, - INFERRED_TYPE, - modifiers, - this.sourceSpan, - ); - } -} - -export class UnaryOperatorExpr extends Expression { - constructor( - public operator: UnaryOperator, - public expr: Expression, - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - public parens: boolean = true, - ) { - super(type || NUMBER_TYPE, sourceSpan); - } - - override isEquivalent(e: Expression): boolean { - return ( - e instanceof UnaryOperatorExpr && - this.operator === e.operator && - this.expr.isEquivalent(e.expr) - ); - } - - override isConstant() { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitUnaryOperatorExpr(this, context); - } - - override clone(): UnaryOperatorExpr { - return new UnaryOperatorExpr( - this.operator, - this.expr.clone(), - this.type, - this.sourceSpan, - this.parens, - ); - } -} - -export class BinaryOperatorExpr extends Expression { - public lhs: Expression; - constructor( - public operator: BinaryOperator, - lhs: Expression, - public rhs: Expression, - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - public parens: boolean = true, - ) { - super(type || lhs.type, sourceSpan); - this.lhs = lhs; - } - - override isEquivalent(e: Expression): boolean { - return ( - e instanceof BinaryOperatorExpr && - this.operator === e.operator && - this.lhs.isEquivalent(e.lhs) && - this.rhs.isEquivalent(e.rhs) - ); - } - - override isConstant() { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitBinaryOperatorExpr(this, context); - } - - override clone(): BinaryOperatorExpr { - return new BinaryOperatorExpr( - this.operator, - this.lhs.clone(), - this.rhs.clone(), - this.type, - this.sourceSpan, - this.parens, - ); - } -} - -export class ReadPropExpr extends Expression { - constructor( - public receiver: Expression, - public name: string, - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - ) { - super(type, sourceSpan); - } - - // An alias for name, which allows other logic to handle property reads and keyed reads together. - get index() { - return this.name; - } - - override isEquivalent(e: Expression): boolean { - return ( - e instanceof ReadPropExpr && - this.receiver.isEquivalent(e.receiver) && - this.name === e.name - ); - } - - override isConstant() { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitReadPropExpr(this, context); - } - - set(value: Expression): WritePropExpr { - return new WritePropExpr( - this.receiver, - this.name, - value, - null, - this.sourceSpan, - ); - } - - override clone(): ReadPropExpr { - return new ReadPropExpr( - this.receiver.clone(), - this.name, - this.type, - this.sourceSpan, - ); - } -} - -export class ReadKeyExpr extends Expression { - constructor( - public receiver: Expression, - public index: Expression, - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - ) { - super(type, sourceSpan); - } - - override isEquivalent(e: Expression): boolean { - return ( - e instanceof ReadKeyExpr && - this.receiver.isEquivalent(e.receiver) && - this.index.isEquivalent(e.index) - ); - } - - override isConstant() { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitReadKeyExpr(this, context); - } - - set(value: Expression): WriteKeyExpr { - return new WriteKeyExpr( - this.receiver, - this.index, - value, - null, - this.sourceSpan, - ); - } - - override clone(): ReadKeyExpr { - return new ReadKeyExpr( - this.receiver.clone(), - this.index.clone(), - this.type, - this.sourceSpan, - ); - } -} - -export class LiteralArrayExpr extends Expression { - public entries: Expression[]; - constructor( - entries: Expression[], - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - ) { - super(type, sourceSpan); - this.entries = entries; - } - - override isConstant() { - return this.entries.every((e) => e.isConstant()); - } - - override isEquivalent(e: Expression): boolean { - return ( - e instanceof LiteralArrayExpr && areAllEquivalent(this.entries, e.entries) - ); - } - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitLiteralArrayExpr(this, context); - } - - override clone(): LiteralArrayExpr { - return new LiteralArrayExpr( - this.entries.map((e) => e.clone()), - this.type, - this.sourceSpan, - ); - } -} - -export class LiteralMapEntry { - constructor( - public key: string, - public value: Expression, - public quoted: boolean, - ) {} - isEquivalent(e: LiteralMapEntry): boolean { - return this.key === e.key && this.value.isEquivalent(e.value); - } - - clone(): LiteralMapEntry { - return new LiteralMapEntry(this.key, this.value.clone(), this.quoted); - } -} - -export class LiteralMapExpr extends Expression { - public valueType: Type | null = null; - constructor( - public entries: LiteralMapEntry[], - type?: MapType | null, - sourceSpan?: ParseSourceSpan | null, - ) { - super(type, sourceSpan); - if (type) { - this.valueType = type.valueType; - } - } - - override isEquivalent(e: Expression): boolean { - return ( - e instanceof LiteralMapExpr && areAllEquivalent(this.entries, e.entries) - ); - } - - override isConstant() { - return this.entries.every((e) => e.value.isConstant()); - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitLiteralMapExpr(this, context); - } - - override clone(): LiteralMapExpr { - const entriesClone = this.entries.map((entry) => entry.clone()); - return new LiteralMapExpr( - entriesClone, - this.type as MapType | null, - this.sourceSpan, - ); - } -} - -export class CommaExpr extends Expression { - constructor( - public parts: Expression[], - sourceSpan?: ParseSourceSpan | null, - ) { - super(parts[parts.length - 1].type, sourceSpan); - } - - override isEquivalent(e: Expression): boolean { - return e instanceof CommaExpr && areAllEquivalent(this.parts, e.parts); - } - - override isConstant() { - return false; - } - - override visitExpression(visitor: ExpressionVisitor, context: any): any { - return visitor.visitCommaExpr(this, context); - } - - override clone(): CommaExpr { - return new CommaExpr(this.parts.map((p) => p.clone())); - } -} - -export interface ExpressionVisitor { - visitReadVarExpr(ast: ReadVarExpr, context: any): any; - visitWriteVarExpr(expr: WriteVarExpr, context: any): any; - visitWriteKeyExpr(expr: WriteKeyExpr, context: any): any; - visitWritePropExpr(expr: WritePropExpr, context: any): any; - visitInvokeFunctionExpr(ast: InvokeFunctionExpr, context: any): any; - visitInstantiateExpr(ast: InstantiateExpr, context: any): any; - visitLiteralExpr(ast: LiteralExpr, context: any): any; - visitExternalExpr(ast: ExternalExpr, context: any): any; - visitConditionalExpr(ast: ConditionalExpr, context: any): any; - visitDynamicImportExpr(ast: DynamicImportExpr, context: any): any; - visitNotExpr(ast: NotExpr, context: any): any; - visitFunctionExpr(ast: FunctionExpr, context: any): any; - visitUnaryOperatorExpr(ast: UnaryOperatorExpr, context: any): any; - visitBinaryOperatorExpr(ast: BinaryOperatorExpr, context: any): any; - visitReadPropExpr(ast: ReadPropExpr, context: any): any; - visitReadKeyExpr(ast: ReadKeyExpr, context: any): any; - visitLiteralArrayExpr(ast: LiteralArrayExpr, context: any): any; - visitLiteralMapExpr(ast: LiteralMapExpr, context: any): any; - visitCommaExpr(ast: CommaExpr, context: any): any; - visitWrappedNodeExpr(ast: WrappedNodeExpr, context: any): any; - visitTypeofExpr(ast: TypeofExpr, context: any): any; - visitArrowFunctionExpr(ast: ArrowFunctionExpr, context: any): any; -} - -export const NULL_EXPR = new LiteralExpr(null, null, null); -export const TYPED_NULL_EXPR = new LiteralExpr(null, INFERRED_TYPE, null); - -//// Statements -export enum StmtModifier { - None = 0, - Final = 1 << 0, - Private = 1 << 1, - Exported = 1 << 2, - Static = 1 << 3, -} - -export class LeadingComment { - constructor( - public text: string, - public multiline: boolean, - public trailingNewline: boolean, - ) {} - toString() { - return this.multiline ? ` ${this.text} ` : this.text; - } -} -export class JSDocComment extends LeadingComment { - constructor(public tags: JSDocTag[]) { - super('', /* multiline */ true, /* trailingNewline */ true); - } - override toString(): string { - return serializeTags(this.tags); - } -} - -export abstract class Statement { - constructor( - public modifiers: StmtModifier = StmtModifier.None, - public sourceSpan: ParseSourceSpan | null = null, - public leadingComments?: LeadingComment[], - ) {} - /** - * Calculates whether this statement produces the same value as the given statement. - * Note: We don't check Types nor ParseSourceSpans nor function arguments. - */ - abstract isEquivalent(stmt: Statement): boolean; - - abstract visitStatement(visitor: StatementVisitor, context: any): any; - - hasModifier(modifier: StmtModifier): boolean { - return (this.modifiers & modifier) !== 0; - } - - addLeadingComment(leadingComment: LeadingComment): void { - this.leadingComments = this.leadingComments ?? []; - this.leadingComments.push(leadingComment); - } -} - -export class DeclareVarStmt extends Statement { - public type: Type | null; - constructor( - public name: string, - public value?: Expression, - type?: Type | null, - modifiers?: StmtModifier, - sourceSpan?: ParseSourceSpan | null, - leadingComments?: LeadingComment[], - ) { - super(modifiers, sourceSpan, leadingComments); - this.type = type || (value && value.type) || null; - } - override isEquivalent(stmt: Statement): boolean { - return ( - stmt instanceof DeclareVarStmt && - this.name === stmt.name && - (this.value - ? !!stmt.value && this.value.isEquivalent(stmt.value) - : !stmt.value) - ); - } - override visitStatement(visitor: StatementVisitor, context: any): any { - return visitor.visitDeclareVarStmt(this, context); - } -} - -export class DeclareFunctionStmt extends Statement { - public type: Type | null; - constructor( - public name: string, - public params: FnParam[], - public statements: Statement[], - type?: Type | null, - modifiers?: StmtModifier, - sourceSpan?: ParseSourceSpan | null, - leadingComments?: LeadingComment[], - ) { - super(modifiers, sourceSpan, leadingComments); - this.type = type || null; - } - override isEquivalent(stmt: Statement): boolean { - return ( - stmt instanceof DeclareFunctionStmt && - areAllEquivalent(this.params, stmt.params) && - areAllEquivalent(this.statements, stmt.statements) - ); - } - override visitStatement(visitor: StatementVisitor, context: any): any { - return visitor.visitDeclareFunctionStmt(this, context); - } -} - -export class ExpressionStatement extends Statement { - constructor( - public expr: Expression, - sourceSpan?: ParseSourceSpan | null, - leadingComments?: LeadingComment[], - ) { - super(StmtModifier.None, sourceSpan, leadingComments); - } - override isEquivalent(stmt: Statement): boolean { - return ( - stmt instanceof ExpressionStatement && this.expr.isEquivalent(stmt.expr) - ); - } - override visitStatement(visitor: StatementVisitor, context: any): any { - return visitor.visitExpressionStmt(this, context); - } -} - -export class ReturnStatement extends Statement { - constructor( - public value: Expression, - sourceSpan: ParseSourceSpan | null = null, - leadingComments?: LeadingComment[], - ) { - super(StmtModifier.None, sourceSpan, leadingComments); - } - override isEquivalent(stmt: Statement): boolean { - return ( - stmt instanceof ReturnStatement && this.value.isEquivalent(stmt.value) - ); - } - override visitStatement(visitor: StatementVisitor, context: any): any { - return visitor.visitReturnStmt(this, context); - } -} - -export class IfStmt extends Statement { - constructor( - public condition: Expression, - public trueCase: Statement[], - public falseCase: Statement[] = [], - sourceSpan?: ParseSourceSpan | null, - leadingComments?: LeadingComment[], - ) { - super(StmtModifier.None, sourceSpan, leadingComments); - } - override isEquivalent(stmt: Statement): boolean { - return ( - stmt instanceof IfStmt && - this.condition.isEquivalent(stmt.condition) && - areAllEquivalent(this.trueCase, stmt.trueCase) && - areAllEquivalent(this.falseCase, stmt.falseCase) - ); - } - override visitStatement(visitor: StatementVisitor, context: any): any { - return visitor.visitIfStmt(this, context); - } -} - -export interface StatementVisitor { - visitDeclareVarStmt(stmt: DeclareVarStmt, context: any): any; - visitDeclareFunctionStmt(stmt: DeclareFunctionStmt, context: any): any; - visitExpressionStmt(stmt: ExpressionStatement, context: any): any; - visitReturnStmt(stmt: ReturnStatement, context: any): any; - visitIfStmt(stmt: IfStmt, context: any): any; -} - -export function leadingComment( - text: string, - multiline: boolean = false, - trailingNewline: boolean = true, -): LeadingComment { - return new LeadingComment(text, multiline, trailingNewline); -} - -export function jsDocComment(tags: JSDocTag[] = []): JSDocComment { - return new JSDocComment(tags); -} - -export function variable( - name: string, - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, -): ReadVarExpr { - return new ReadVarExpr(name, type, sourceSpan); -} - -export function importExpr( - id: ExternalReference, - typeParams: Type[] | null = null, - sourceSpan?: ParseSourceSpan | null, -): ExternalExpr { - return new ExternalExpr(id, null, typeParams, sourceSpan); -} - -export function importType( - id: ExternalReference, - typeParams?: Type[] | null, - typeModifiers?: TypeModifier, -): ExpressionType | null { - return id != null - ? expressionType(importExpr(id, typeParams, null), typeModifiers) - : null; -} - -export function expressionType( - expr: Expression, - typeModifiers?: TypeModifier, - typeParams?: Type[] | null, -): ExpressionType { - return new ExpressionType(expr, typeModifiers, typeParams); -} - -export function transplantedType( - type: T, - typeModifiers?: TypeModifier, -): TransplantedType { - return new TransplantedType(type, typeModifiers); -} - -export function typeofExpr(expr: Expression) { - return new TypeofExpr(expr); -} - -export function literalArr( - values: Expression[], - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, -): LiteralArrayExpr { - return new LiteralArrayExpr(values, type, sourceSpan); -} - -export function literalMap( - values: { key: string; quoted: boolean; value: Expression }[], - type: MapType | null = null, -): LiteralMapExpr { - return new LiteralMapExpr( - values.map((e) => new LiteralMapEntry(e.key, e.value, e.quoted)), - type, - null, - ); -} - -export function unary( - operator: UnaryOperator, - expr: Expression, - type?: Type, - sourceSpan?: ParseSourceSpan | null, -): UnaryOperatorExpr { - return new UnaryOperatorExpr(operator, expr, type, sourceSpan); -} - -export function not( - expr: Expression, - sourceSpan?: ParseSourceSpan | null, -): NotExpr { - return new NotExpr(expr, sourceSpan); -} - -export function fn( - params: FnParam[], - body: Statement[], - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, - name?: string | null, -): FunctionExpr { - return new FunctionExpr(params, body, type, sourceSpan, name); -} - -export function arrowFn( - params: FnParam[], - body: Expression | Statement[], - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, -) { - return new ArrowFunctionExpr(params, body, type, sourceSpan); -} - -export function ifStmt( - condition: Expression, - thenClause: Statement[], - elseClause?: Statement[], - sourceSpan?: ParseSourceSpan, - leadingComments?: LeadingComment[], -) { - return new IfStmt( - condition, - thenClause, - elseClause, - sourceSpan, - leadingComments, - ); -} - -export function literal( - value: any, - type?: Type | null, - sourceSpan?: ParseSourceSpan | null, -): LiteralExpr { - return new LiteralExpr(value, type, sourceSpan); -} - -export function isNull(exp: Expression): boolean { - return exp instanceof LiteralExpr && exp.value === null; -} - -// The list of JSDoc tags that we currently support. Extend it if needed. -export const enum JSDocTagName { - Desc = 'desc', - Id = 'id', - Meaning = 'meaning', - Suppress = 'suppress', -} - -/* - * TypeScript has an API for JSDoc already, but it's not exposed. - * https://github.com/Microsoft/TypeScript/issues/7393 - * For now we create types that are similar to theirs so that migrating - * to their API will be easier. See e.g. `ts.JSDocTag` and `ts.JSDocComment`. - */ -export type JSDocTag = - | { - // `tagName` is e.g. "param" in an `@param` declaration - tagName: JSDocTagName | string; - // Any remaining text on the tag, e.g. the description - text?: string; - } - | { - // no `tagName` for plain text documentation that occurs before any `@param` lines - tagName?: undefined; - text: string; - }; - -/* - * Serializes a `Tag` into a string. - * Returns a string like " @foo {bar} baz" (note the leading whitespace before `@foo`). - */ -function tagToString(tag: JSDocTag): string { - let out = ''; - if (tag.tagName) { - out += ` @${tag.tagName}`; - } - if (tag.text) { - if (tag.text.match(/\/\*|\*\//)) { - throw new Error('JSDoc text cannot contain "/*" and "*/"'); - } - out += ' ' + tag.text.replace(/@/g, '\\@'); - } - return out; -} - -function serializeTags(tags: JSDocTag[]): string { - if (tags.length === 0) return ''; - - if (tags.length === 1 && tags[0].tagName && !tags[0].text) { - // The JSDOC comment is a single simple tag: e.g `/** @tagname */`. - return `*${tagToString(tags[0])} `; - } - - let out = '*\n'; - for (const tag of tags) { - out += ' *'; - // If the tagToString is multi-line, insert " * " prefixes on lines. - out += tagToString(tag).replace(/\n/g, '\n * '); - out += '\n'; - } - out += ' '; - return out; -} diff --git a/src/transform/compiler/src/parse_util.ts b/src/transform/compiler/src/parse_util.ts deleted file mode 100644 index 4137e61..0000000 --- a/src/transform/compiler/src/parse_util.ts +++ /dev/null @@ -1,65 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -export class ParseLocation { - constructor( - public file: ParseSourceFile, - public offset: number, - public line: number, - public col: number, - ) {} - - // Return the source around the location - // Up to `maxChars` or `maxLines` on each side of the location -} - -export class ParseSourceFile { - constructor( - public content: string, - public url: string, - ) {} -} - -export class ParseSourceSpan { - /** - * Create an object that holds information about spans of tokens/nodes captured during - * lexing/parsing of text. - * - * @param start - * The location of the start of the span (having skipped leading trivia). - * Skipping leading trivia makes source-spans more "user friendly", since things like HTML - * elements will appear to begin at the start of the opening tag, rather than at the start of any - * leading trivia, which could include newlines. - * - * @param end - * The location of the end of the span. - * - * @param fullStart - * The start of the token without skipping the leading trivia. - * This is used by tooling that splits tokens further, such as extracting Angular interpolations - * from text tokens. Such tooling creates new source-spans relative to the original token's - * source-span. If leading trivia characters have been skipped then the new source-spans may be - * incorrectly offset. - * - * @param details - * Additional information (such as identifier names) that should be associated with the span. - */ - constructor( - public start: ParseLocation, - public end: ParseLocation, - public fullStart: ParseLocation = start, - public details: string | null = null, - ) {} - - toString(): string { - return this.start.file.content.substring( - this.start.offset, - this.end.offset, - ); - } -} diff --git a/src/transform/compiler/src/render3/partial/api.ts b/src/transform/compiler/src/render3/partial/api.ts deleted file mode 100644 index 34ac37d..0000000 --- a/src/transform/compiler/src/render3/partial/api.ts +++ /dev/null @@ -1,199 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import * as o from '../../output/output_ast'; - -export interface R3PartialDeclaration { - /** - * The minimum version of the compiler that can process this partial declaration. - */ - minVersion: string; - - /** - * Version number of the Angular compiler that was used to compile this declaration. The linker - * will be able to detect which version a library is using and interpret its metadata accordingly. - */ - version: string; - - /** - * A reference to the `@angular/core` ES module, which allows access - * to all Angular exports, including Ivy instructions. - */ - ngImport: o.Expression; - - /** - * Reference to the decorated class, which is subject to this partial declaration. - */ - type: o.Expression; -} - -// TODO(legacy-partial-output-inputs): Remove in v18. -// https://github.com/angular/angular/blob/d4b423690210872b5c32a322a6090beda30b05a3/packages/core/src/compiler/compiler_facade_interface.ts#L197-L199 -export type LegacyInputPartialMapping = - | string - | [ - bindingPropertyName: string, - classPropertyName: string, - transformFunction?: o.Expression, - ]; - -/** - * Describes the shape of the objects that the `ɵɵngDeclareInjector()` accepts. - */ -export interface R3DeclareInjectorMetadata extends R3PartialDeclaration { - /** - * The list of providers provided by the injector. - */ - providers?: o.Expression; - /** - * The list of imports into the injector. - */ - imports?: o.Expression[]; -} - -/** - * Describes the shape of the object that the `ɵɵngDeclareFactory()` function accepts. - * - * This interface serves primarily as documentation, as conformance to this interface is not - * enforced during linking. - */ -export interface R3DeclareFactoryMetadata extends R3PartialDeclaration { - /** - * A collection of dependencies that this factory relies upon. - * - * If this is `null`, then the type's constructor is nonexistent and will be inherited from an - * ancestor of the type. - * - * If this is `'invalid'`, then one or more of the parameters wasn't resolvable and any attempt to - * use these deps will result in a runtime error. - */ - deps: R3DeclareDependencyMetadata[] | 'invalid' | null; - - /** - * Type of the target being created by the factory. - */ - target: FactoryTarget; -} - -export enum FactoryTarget { - Directive = 0, - Component = 1, - Injectable = 2, - Pipe = 3, - NgModule = 4, -} - -/** - * Describes the shape of the object that the `ɵɵngDeclareInjectable()` function accepts. - * - * This interface serves primarily as documentation, as conformance to this interface is not - * enforced during linking. - */ -export interface R3DeclareInjectableMetadata extends R3PartialDeclaration { - /** - * If provided, specifies that the declared injectable belongs to a particular injector: - * - `InjectorType` such as `NgModule`, - * - `'root'` the root injector - * - `'any'` all injectors. - * If not provided, then it does not belong to any injector. Must be explicitly listed in the - * providers of an injector. - */ - providedIn?: o.Expression; - - /** - * If provided, an expression that evaluates to a class to use when creating an instance of this - * injectable. - */ - useClass?: o.Expression; - - /** - * If provided, an expression that evaluates to a function to use when creating an instance of - * this injectable. - */ - useFactory?: o.Expression; - - /** - * If provided, an expression that evaluates to a token of another injectable that this injectable - * aliases. - */ - useExisting?: o.Expression; - - /** - * If provided, an expression that evaluates to the value of the instance of this injectable. - */ - useValue?: o.Expression; - - /** - * An array of dependencies to support instantiating this injectable via `useClass` or - * `useFactory`. - */ - deps?: R3DeclareDependencyMetadata[]; -} - -/** - * Metadata indicating how a dependency should be injected into a factory. - */ -export interface R3DeclareDependencyMetadata { - /** - * An expression representing the token or value to be injected, or `null` if the dependency is - * not valid. - * - * If this dependency is due to the `@Attribute()` decorator, then this is an expression - * evaluating to the name of the attribute. - */ - token: o.Expression | null; - - /** - * Whether the dependency is injecting an attribute value. - * Default: false. - */ - attribute?: boolean; - - /** - * Whether the dependency has an @Optional qualifier. - * Default: false, - */ - optional?: boolean; - - /** - * Whether the dependency has an @Self qualifier. - * Default: false, - */ - self?: boolean; - - /** - * Whether the dependency has an @SkipSelf qualifier. - * Default: false, - */ - skipSelf?: boolean; -} - -/** - * Describes the shape of the object that the `ɵɵngDeclareClassMetadata()` function accepts. - * - * This interface serves primarily as documentation, as conformance to this interface is not - * enforced during linking. - */ -export interface R3DeclareClassMetadata extends R3PartialDeclaration { - /** - * The Angular decorators of the class. - */ - decorators: o.Expression; - - /** - * Optionally specifies the constructor parameters, their types and the Angular decorators of each - * parameter. This property is omitted if the class does not have a constructor. - */ - ctorParameters?: o.Expression; - - /** - * Optionally specifies the Angular decorators applied to the class properties. This property is - * omitted if no properties have any decorators. - */ - propDecorators?: o.Expression; -} diff --git a/src/transform/compiler/src/render3/r3_factory.ts b/src/transform/compiler/src/render3/r3_factory.ts deleted file mode 100644 index 6173e0d..0000000 --- a/src/transform/compiler/src/render3/r3_factory.ts +++ /dev/null @@ -1,336 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ -import { InjectFlags } from '../core'; -import * as o from '../output/output_ast'; -import { Identifiers as R3 } from '../render3/r3_identifiers'; - -import { R3CompiledExpression, R3Reference, typeWithParameters } from './util'; - -/** - * Metadata required by the factory generator to generate a `factory` function for a type. - */ -export interface R3ConstructorFactoryMetadata { - /** - * String name of the type being generated (used to name the factory function). - */ - name: string; - - /** - * An expression representing the interface type being constructed. - */ - type: R3Reference; - - /** Number of arguments for the `type`. */ - typeArgumentCount: number; - - /** - * Regardless of whether `fnOrClass` is a constructor function or a user-defined factory, it - * may have 0 or more parameters, which will be injected according to the `R3DependencyMetadata` - * for those parameters. If this is `null`, then the type's constructor is nonexistent and will - * be inherited from `fnOrClass` which is interpreted as the current type. If this is `'invalid'`, - * then one or more of the parameters wasn't resolvable and any attempt to use these deps will - * result in a runtime error. - */ - deps: R3DependencyMetadata[] | 'invalid' | null; - - /** - * Type of the target being created by the factory. - */ - target: FactoryTarget; -} - -export enum R3FactoryDelegateType { - Class = 0, - Function = 1, -} - -export interface R3DelegatedFnOrClassMetadata - extends R3ConstructorFactoryMetadata { - delegate: o.Expression; - delegateType: R3FactoryDelegateType; - delegateDeps: R3DependencyMetadata[]; -} - -export interface R3ExpressionFactoryMetadata - extends R3ConstructorFactoryMetadata { - expression: o.Expression; -} - -export type R3FactoryMetadata = - | R3ConstructorFactoryMetadata - | R3DelegatedFnOrClassMetadata - | R3ExpressionFactoryMetadata; - -export enum FactoryTarget { - Directive = 0, - Component = 1, - Injectable = 2, - Pipe = 3, - NgModule = 4, -} - -export interface R3DependencyMetadata { - /** - * An expression representing the token or value to be injected. - * Or `null` if the dependency could not be resolved - making it invalid. - */ - token: o.Expression | null; - - /** - * If an @Attribute decorator is present, this is the literal type of the attribute name, or - * the unknown type if no literal type is available (e.g. the attribute name is an expression). - * Otherwise it is null; - */ - attributeNameType: o.Expression | null; - - /** - * Whether the dependency has an @Optional qualifier. - */ - optional: boolean; - - /** - * Whether the dependency has an @Self qualifier. - */ - self: boolean; - - /** - * Whether the dependency has an @SkipSelf qualifier. - */ - skipSelf: boolean; -} - -/** - * Construct a factory function expression for the given `R3FactoryMetadata`. - */ -export function compileFactoryFunction( - meta: R3FactoryMetadata, -): R3CompiledExpression { - const t = o.variable('t'); - let baseFactoryVar: o.ReadVarExpr | null = null; - - // The type to instantiate via constructor invocation. If there is no delegated factory, meaning - // this type is always created by constructor invocation, then this is the type-to-create - // parameter provided by the user (t) if specified, or the current type if not. If there is a - // delegated factory (which is used to create the current type) then this is only the type-to- - // create parameter (t). - const typeForCtor = !isDelegatedFactoryMetadata(meta) - ? new o.BinaryOperatorExpr(o.BinaryOperator.Or, t, meta.type.value) - : t; - - let ctorExpr: o.Expression | null = null; - if (meta.deps !== null) { - // There is a constructor (either explicitly or implicitly defined). - if (meta.deps !== 'invalid') { - ctorExpr = new o.InstantiateExpr( - typeForCtor, - injectDependencies(meta.deps, meta.target), - ); - } - } else { - // There is no constructor, use the base class' factory to construct typeForCtor. - baseFactoryVar = o.variable(`ɵ${meta.name}_BaseFactory`); - ctorExpr = baseFactoryVar.callFn([typeForCtor]); - } - - const body: o.Statement[] = []; - let retExpr: o.Expression | null = null; - - function makeConditionalFactory(nonCtorExpr: o.Expression): o.ReadVarExpr { - const r = o.variable('r'); - body.push(r.set(o.NULL_EXPR).toDeclStmt()); - const ctorStmt = - ctorExpr !== null - ? r.set(ctorExpr).toStmt() - : o.importExpr(R3.invalidFactory).callFn([]).toStmt(); - body.push(o.ifStmt(t, [ctorStmt], [r.set(nonCtorExpr).toStmt()])); - return r; - } - - if (isDelegatedFactoryMetadata(meta)) { - // This type is created with a delegated factory. If a type parameter is not specified, call - // the factory instead. - const delegateArgs = injectDependencies(meta.delegateDeps, meta.target); - // Either call `new delegate(...)` or `delegate(...)` depending on meta.delegateType. - const factoryExpr = new ( - meta.delegateType === R3FactoryDelegateType.Class - ? o.InstantiateExpr - : o.InvokeFunctionExpr - )(meta.delegate, delegateArgs); - retExpr = makeConditionalFactory(factoryExpr); - } else if (isExpressionFactoryMetadata(meta)) { - // TODO(alxhub): decide whether to lower the value here or in the caller - retExpr = makeConditionalFactory(meta.expression); - } else { - retExpr = ctorExpr; - } - - if (retExpr === null) { - // The expression cannot be formed so render an `ɵɵinvalidFactory()` call. - body.push(o.importExpr(R3.invalidFactory).callFn([]).toStmt()); - } else if (baseFactoryVar !== null) { - // This factory uses a base factory, so call `ɵɵgetInheritedFactory()` to compute it. - const getInheritedFactoryCall = o - .importExpr(R3.getInheritedFactory) - .callFn([meta.type.value]); - // Memoize the base factoryFn: `baseFactory || (baseFactory = ɵɵgetInheritedFactory(...))` - const baseFactory = new o.BinaryOperatorExpr( - o.BinaryOperator.Or, - baseFactoryVar, - baseFactoryVar.set(getInheritedFactoryCall), - ); - body.push(new o.ReturnStatement(baseFactory.callFn([typeForCtor]))); - } else { - // This is straightforward factory, just return it. - body.push(new o.ReturnStatement(retExpr)); - } - - let factoryFn: o.Expression = o.fn( - [new o.FnParam('t', o.DYNAMIC_TYPE)], - body, - o.INFERRED_TYPE, - undefined, - `${meta.name}_Factory`, - ); - - if (baseFactoryVar !== null) { - // There is a base factory variable so wrap its declaration along with the factory function into - // an IIFE. - factoryFn = o - .arrowFn( - [], - [ - new o.DeclareVarStmt(baseFactoryVar.name!), - new o.ReturnStatement(factoryFn), - ], - ) - .callFn([], /* sourceSpan */ undefined, /* pure */ true); - } - - return { - expression: factoryFn, - statements: [], - type: createFactoryType(meta), - }; -} - -export function createFactoryType(meta: R3FactoryMetadata) { - const ctorDepsType = - meta.deps !== null && meta.deps !== 'invalid' - ? createCtorDepsType(meta.deps) - : o.NONE_TYPE; - return o.expressionType( - o.importExpr(R3.FactoryDeclaration, [ - typeWithParameters(meta.type.type, meta.typeArgumentCount), - ctorDepsType, - ]), - ); -} - -function injectDependencies( - deps: R3DependencyMetadata[], - target: FactoryTarget, -): o.Expression[] { - return deps.map((dep, index) => compileInjectDependency(dep, target, index)); -} - -function compileInjectDependency( - dep: R3DependencyMetadata, - target: FactoryTarget, - index: number, -): o.Expression { - // Interpret the dependency according to its resolved type. - if (dep.token === null) { - return o.importExpr(R3.invalidFactoryDep).callFn([o.literal(index)]); - } else if (dep.attributeNameType === null) { - // Build up the injection flags according to the metadata. - const flags = - InjectFlags.Default | - (dep.self ? InjectFlags.Self : 0) | - (dep.skipSelf ? InjectFlags.SkipSelf : 0) | - 0 | - (dep.optional ? InjectFlags.Optional : 0) | - 0; - - // If this dependency is optional or otherwise has non-default flags, then additional - // parameters describing how to inject the dependency must be passed to the inject function - // that's being used. - let flagsParam: o.LiteralExpr | null = - flags !== InjectFlags.Default || dep.optional ? o.literal(flags) : null; - - // Build up the arguments to the injectFn call. - const injectArgs = [dep.token]; - if (flagsParam) { - injectArgs.push(flagsParam); - } - const injectFn = getInjectFn(target); - return o.importExpr(injectFn).callFn(injectArgs); - } else { - throw new Error('compileInjectDependency'); - } -} - -function createCtorDepsType(deps: R3DependencyMetadata[]): o.Type { - let hasTypes = false; - const attributeTypes = deps.map((dep) => { - const type = createCtorDepType(dep); - if (type !== null) { - hasTypes = true; - return type; - } else { - return o.literal(null); - } - }); - - if (hasTypes) { - return o.expressionType(o.literalArr(attributeTypes)); - } else { - return o.NONE_TYPE; - } -} - -function createCtorDepType(dep: R3DependencyMetadata): o.LiteralMapExpr | null { - const entries: { key: string; quoted: boolean; value: o.Expression }[] = []; - - if (dep.optional) { - entries.push({ key: 'optional', value: o.literal(true), quoted: false }); - } - - if (dep.self) { - entries.push({ key: 'self', value: o.literal(true), quoted: false }); - } - if (dep.skipSelf) { - entries.push({ key: 'skipSelf', value: o.literal(true), quoted: false }); - } - - return entries.length > 0 ? o.literalMap(entries) : null; -} - -export function isDelegatedFactoryMetadata( - meta: R3FactoryMetadata, -): meta is R3DelegatedFnOrClassMetadata { - return (meta as any).delegateType !== undefined; -} - -export function isExpressionFactoryMetadata( - meta: R3FactoryMetadata, -): meta is R3ExpressionFactoryMetadata { - return (meta as any).expression !== undefined; -} - -function getInjectFn(target: FactoryTarget): o.ExternalReference { - switch (target) { - case FactoryTarget.Component: - case FactoryTarget.Directive: - case FactoryTarget.Pipe: - return R3.directiveInject; - case FactoryTarget.NgModule: - case FactoryTarget.Injectable: - default: - return R3.inject; - } -} diff --git a/src/transform/compiler/src/render3/r3_identifiers.ts b/src/transform/compiler/src/render3/r3_identifiers.ts deleted file mode 100644 index 0ada594..0000000 --- a/src/transform/compiler/src/render3/r3_identifiers.ts +++ /dev/null @@ -1,69 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import * as o from '../output/output_ast'; - -const CORE = 'static-injector'; - -export class Identifiers { - /* Methods */ - - /* Instructions */ - - static inject: o.ExternalReference = { name: 'ɵɵinject', moduleName: CORE }; - - static directiveInject: o.ExternalReference = { - name: 'ɵɵdirectiveInject', - moduleName: CORE, - }; - static invalidFactory: o.ExternalReference = { - name: 'ɵɵinvalidFactory', - moduleName: CORE, - }; - static invalidFactoryDep: o.ExternalReference = { - name: 'ɵɵinvalidFactoryDep', - moduleName: CORE, - }; - - static forwardRef: o.ExternalReference = { - name: 'forwardRef', - moduleName: CORE, - }; - static resolveForwardRef: o.ExternalReference = { - name: 'resolveForwardRef', - moduleName: CORE, - }; - - static ɵɵdefineInjectable: o.ExternalReference = { - name: 'ɵɵdefineInjectable', - moduleName: CORE, - }; - - static InjectableDeclaration: o.ExternalReference = { - name: 'ɵɵInjectableDeclaration', - moduleName: CORE, - }; - - static FactoryDeclaration: o.ExternalReference = { - name: 'ɵɵFactoryDeclaration', - moduleName: CORE, - }; - - // Signal queries - - // Two-way bindings - - static getInheritedFactory: o.ExternalReference = { - name: 'ɵɵgetInheritedFactory', - moduleName: CORE, - }; - - // sanitization-related functions - - // type-checking -} diff --git a/src/transform/compiler/src/render3/util.ts b/src/transform/compiler/src/render3/util.ts deleted file mode 100644 index 6891bbd..0000000 --- a/src/transform/compiler/src/render3/util.ts +++ /dev/null @@ -1,128 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import * as o from '../output/output_ast'; - -import { Identifiers } from './r3_identifiers'; - -export function typeWithParameters( - type: o.Expression, - numParams: number, -): o.ExpressionType { - if (numParams === 0) { - return o.expressionType(type); - } - const params: o.Type[] = []; - for (let i = 0; i < numParams; i++) { - params.push(o.DYNAMIC_TYPE); - } - return o.expressionType(type, undefined, params); -} - -export interface R3Reference { - value: o.Expression; - type: o.Expression; -} - -/** - * Result of compilation of a render3 code unit, e.g. component, directive, pipe, etc. - */ -export interface R3CompiledExpression { - expression: o.Expression; - type: o.Type; - statements: o.Statement[]; -} - -/** - * Describes an expression that may have been wrapped in a `forwardRef()` guard. - * - * This is used when describing expressions that can refer to types that may eagerly reference types - * that have not yet been defined. - */ -export interface MaybeForwardRefExpression< - T extends o.Expression = o.Expression, -> { - /** - * The unwrapped expression. - */ - expression: T; - /** - * Specified whether the `expression` contains a reference to something that has not yet been - * defined, and whether the expression is still wrapped in a `forwardRef()` call. - * - * If this value is `ForwardRefHandling.None` then the `expression` is safe to use as-is. - * - * Otherwise the `expression` was wrapped in a call to `forwardRef()` and must not be eagerly - * evaluated. Instead it must be wrapped in a function closure that will be evaluated lazily to - * allow the definition of the expression to be evaluated first. - * - * In full AOT compilation it can be safe to unwrap the `forwardRef()` call up front if the - * expression will actually be evaluated lazily inside a function call after the value of - * `expression` has been defined. - * - * But in other cases, such as partial AOT compilation or JIT compilation the expression will be - * evaluated eagerly in top level code so will need to continue to be wrapped in a `forwardRef()` - * call. - * - */ - forwardRef: ForwardRefHandling; -} - -export function createMayBeForwardRefExpression( - expression: T, - forwardRef: ForwardRefHandling, -): MaybeForwardRefExpression { - return { expression, forwardRef }; -} - -/** - * Convert a `MaybeForwardRefExpression` to an `Expression`, possibly wrapping its expression in a - * `forwardRef()` call. - * - * If `MaybeForwardRefExpression.forwardRef` is `ForwardRefHandling.Unwrapped` then the expression - * was originally wrapped in a `forwardRef()` call to prevent the value from being eagerly evaluated - * in the code. - * - * See `packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts` and - * `packages/compiler/src/jit_compiler_facade.ts` for more information. - */ -export function convertFromMaybeForwardRefExpression({ - expression, - forwardRef, -}: MaybeForwardRefExpression): o.Expression { - switch (forwardRef) { - case ForwardRefHandling.None: - case ForwardRefHandling.Wrapped: - return expression; - case ForwardRefHandling.Unwrapped: - return generateForwardRef(expression); - } -} - -/** - * Generate an expression that has the given `expr` wrapped in the following form: - * - * ``` - * forwardRef(() => expr) - * ``` - */ -export function generateForwardRef(expr: o.Expression): o.Expression { - return o.importExpr(Identifiers.forwardRef).callFn([o.arrowFn([], expr)]); -} - -/** - * Specifies how a forward ref has been handled in a MaybeForwardRefExpression - */ -export const enum ForwardRefHandling { - /** The expression was not wrapped in a `forwardRef()` call in the first place. */ - None, - /** The expression is still wrapped in a `forwardRef()` call. */ - Wrapped, - /** The expression was wrapped in a `forwardRef()` call but has since been unwrapped. */ - Unwrapped, -} diff --git a/src/transform/compiler/src/render3/view/util.ts b/src/transform/compiler/src/render3/view/util.ts deleted file mode 100644 index 7e2a7e6..0000000 --- a/src/transform/compiler/src/render3/view/util.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * @license - * Copyright Google LLC All Rights Reserved. - * - * Use of this source code is governed by an MIT-style license that can be - * found in the LICENSE file at https://angular.io/license - */ - -import { InputFlags } from '../../core'; - -import * as o from '../../output/output_ast'; - -/** Special value representing a direct access to a template's context. */ -export const DIRECT_CONTEXT_REFERENCE = '#context'; - -/** - * A representation for an object literal used during codegen of definition objects. The generic - * type `T` allows to reference a documented type of the generated structure, such that the - * property names that are set can be resolved to their documented declaration. - */ -export class DefinitionMap { - values: { key: string; quoted: boolean; value: o.Expression }[] = []; - - set(key: keyof T, value: o.Expression | null): void { - if (value) { - const existing = this.values.find((value) => value.key === key); - - if (existing) { - existing.value = value; - } else { - this.values.push({ key: key as string, value, quoted: false }); - } - } - } - - toLiteralMap(): o.LiteralMapExpr { - return o.literalMap(this.values); - } -} diff --git a/src/transform/index.ts b/src/transform/index.ts deleted file mode 100644 index 6e4ddc9..0000000 --- a/src/transform/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './injectable-transform'; diff --git a/src/transform/injectable-transform.ts b/src/transform/injectable-transform.ts deleted file mode 100644 index de7fc06..0000000 --- a/src/transform/injectable-transform.ts +++ /dev/null @@ -1,379 +0,0 @@ -import ts, { ClassDeclaration, SourceFile } from 'typescript'; -import { InjectableDecoratorHandler } from './compiler-cli/src/ngtsc/annotations/src/injectable'; -import { NoopImportRewriter } from './compiler-cli/src/ngtsc/imports'; -import { - Decorator, - TypeScriptReflectionHost, -} from './compiler-cli/src/ngtsc/reflection'; -import { - addImports, - CompilationMode, - CompileResult, -} from './compiler-cli/src/ngtsc/transform'; -import { - ImportManager, - translateExpression, - translateStatement, -} from './compiler-cli/src/ngtsc/translator'; - -import { nodeIteration } from './node-Iteration'; -const NO_DECORATORS = new Set(); -interface ClassMetadata { - /** 要添加的静态方法 */ - members: ts.PropertyDeclaration[]; - /** 声明,未用到 */ - statements: any; - /** 要被移除的装饰器 */ - decorator: ts.Decorator; -} -export interface InjectableTransformerFactoryOptions { - strictCtorDeps?: boolean; -} -export function createTransformer( - program: ts.Program, - options?: InjectableTransformerFactoryOptions, -) { - let factory = new InjectableTransformerFactory(program, options); - return factory.getTransform(); -} -export class InjectableTransformerFactory { - typeChecker: ts.TypeChecker; - reflectionHost: TypeScriptReflectionHost; - handler: InjectableDecoratorHandler; - - constructor( - private program: ts.Program, - private options: InjectableTransformerFactoryOptions = {}, - ) { - this.typeChecker = this.program.getTypeChecker(); - this.reflectionHost = new TypeScriptReflectionHost(this.typeChecker); - this.handler = new InjectableDecoratorHandler( - this.reflectionHost, - false, - !!this.options.strictCtorDeps, - false, - CompilationMode.FULL, - ); - } - getTransform() { - return (context: ts.TransformationContext) => this.transform(context); - } - private visit( - node: T, - context: ts.TransformationContext, - map: Map, - ): T { - return ts.visitEachChild( - node, - (node) => { - let result = map.get(node as ClassDeclaration); - if (result) { - const filteredDecorators = - // Remove the decorator which triggered this compilation, leaving the others alone. - maybeFilterDecorator(ts.getDecorators(node as ClassDeclaration), [ - result.decorator, - ]); - const nodeModifiers = ts.getModifiers(node as ClassDeclaration); - - let updatedModifiers: ts.ModifierLike[] | undefined; - - if (filteredDecorators?.length || nodeModifiers?.length) { - updatedModifiers = [ - ...(filteredDecorators || []), - ...(nodeModifiers || []), - ]; - } - return ts.factory.updateClassDeclaration( - node as ClassDeclaration, - updatedModifiers, - (node as ClassDeclaration).name, - (node as ClassDeclaration).typeParameters, - (node as ClassDeclaration).heritageClauses || [], - [ - ...(node as ClassDeclaration).members.map((node) => - this._stripAngularDecorators(node), - ), - ...result.members, - ], - ); - } - return this.visit(node, context, map); - }, - context, - ); - } - - private transform(context: ts.TransformationContext) { - return (sf: SourceFile) => { - let map = this.preAnalysis(sf); - sf = this.updateStatements(sf, map.importManager); - return this.visit(sf, context, map.classMetadataMap); - }; - } - - private preAnalysis(sf: SourceFile) { - let classMetadataMap = new Map(); - let write = new NoopImportRewriter(); - let importManager = new ImportManager(write); - nodeIteration(sf, (node) => { - if ( - ts.isClassDeclaration(node) && - ts.getDecorators(node) && - this.reflectionHost.isClass(node) - ) { - const decorators = - this.reflectionHost.getDecoratorsOfDeclaration(node) || []; - - let result = this.handler.detect(node, decorators); - if (!result) { - return; - } - let analysisOutput = this.handler.analyze(node, result.metadata); - - let compileResult = this.handler.compileFull( - node, - analysisOutput.analysis!, - ); - let resultNode = this.translate(compileResult, importManager); - classMetadataMap.set(node, { - ...resultNode, - decorator: result.trigger as ts.Decorator, - }); - } - }); - - // this.sourceFileMetadataMap.set(sf, { - // classMetadataMap, - // importManager: importManager, - // }); - return { classMetadataMap, importManager }; - } - private translate( - compileResult: CompileResult[], - importManager: ImportManager, - ) { - // There is at least one field to add. - const statements: ts.Statement[] = []; - const members: ts.PropertyDeclaration[] = []; - - for (const field of compileResult) { - // Translate the initializer for the field into TS nodes. - const exprNode = translateExpression(field.initializer!, importManager); - - // Create a static property declaration for the new field. - const property = ts.factory.createPropertyDeclaration( - [ts.factory.createToken(ts.SyntaxKind.StaticKeyword)], - field.name, - undefined, - undefined, - exprNode, - ); - - if (false) { - // Closure compiler transforms the form `Service.ɵprov = X` into `Service$ɵprov = X`. To - // prevent this transformation, such assignments need to be annotated with @nocollapse. - // Note that tsickle is typically responsible for adding such annotations, however it - // doesn't yet handle synthetic fields added during other transformations. - ts.addSyntheticLeadingComment( - property, - ts.SyntaxKind.MultiLineCommentTrivia, - '* @nocollapse ', - /* hasTrailingNewLine */ false, - ); - } - - field.statements - .map((stmt) => translateStatement(stmt, importManager)) - .forEach((stmt) => statements.push(stmt)); - members.push(property); - } - return { statements, members }; - } - - /** - * Remove Angular decorators from a `ts.Node` in a shallow manner. - * - * This will remove decorators from class elements (getters, setters, properties, methods) as well - * as parameters of constructors. - */ - private _stripAngularDecorators(node: T): T { - const modifiers = ts.canHaveModifiers(node) - ? ts.getModifiers(node) - : undefined; - const nonCoreDecorators = ts.canHaveDecorators(node) - ? this._nonCoreDecoratorsOnly(node) - : undefined; - const combinedModifiers = [ - ...(nonCoreDecorators || []), - ...(modifiers || []), - ]; - - if (ts.isParameter(node)) { - // Strip decorators from parameters (probably of the constructor). - node = ts.factory.updateParameterDeclaration( - node, - combinedModifiers, - node.dotDotDotToken, - node.name, - node.questionToken, - node.type, - node.initializer, - ) as T & ts.ParameterDeclaration; - } else if (ts.isMethodDeclaration(node)) { - // Strip decorators of methods. - node = ts.factory.updateMethodDeclaration( - node, - combinedModifiers, - node.asteriskToken, - node.name, - node.questionToken, - node.typeParameters, - node.parameters, - node.type, - node.body, - ) as T & ts.MethodDeclaration; - } else if (ts.isPropertyDeclaration(node)) { - // Strip decorators of properties. - node = ts.factory.updatePropertyDeclaration( - node, - combinedModifiers, - node.name, - node.questionToken, - node.type, - node.initializer, - ) as T & ts.PropertyDeclaration; - } else if (ts.isGetAccessor(node)) { - // Strip decorators of getters. - node = ts.factory.updateGetAccessorDeclaration( - node, - combinedModifiers, - node.name, - node.parameters, - node.type, - node.body, - ) as T & ts.GetAccessorDeclaration; - } else if (ts.isSetAccessor(node)) { - // Strip decorators of setters. - node = ts.factory.updateSetAccessorDeclaration( - node, - combinedModifiers, - node.name, - node.parameters, - node.body, - ) as T & ts.SetAccessorDeclaration; - } else if (ts.isConstructorDeclaration(node)) { - // For constructors, strip decorators of the parameters. - const parameters = node.parameters.map((param) => - this._stripAngularDecorators(param), - ); - node = ts.factory.updateConstructorDeclaration( - node, - modifiers, - parameters, - node.body, - ) as T & ts.ConstructorDeclaration; - } - return node; - } - /** - * Return all decorators on a `Declaration` which are from static-injector, or an empty set if none - * are. - */ - private _angularCoreDecorators(decl: ts.Declaration): Set { - const decorators = this.reflectionHost.getDecoratorsOfDeclaration(decl); - if (decorators === null) { - return NO_DECORATORS; - } - const coreDecorators = decorators - .filter((dec) => isFromAngularCore(dec)) - .map((dec) => dec.node as ts.Decorator); - if (coreDecorators.length > 0) { - return new Set(coreDecorators); - } else { - return NO_DECORATORS; - } - } - - /** - * Given a `ts.Node`, filter the decorators array and return a version containing only non-Angular - * decorators. - * - * If all decorators are removed (or none existed in the first place), this method returns - * `undefined`. - */ - private _nonCoreDecoratorsOnly( - node: ts.HasDecorators, - ): ts.NodeArray | undefined { - const decorators = ts.getDecorators(node); - - // Shortcut if the node has no decorators. - if (decorators === undefined) { - return undefined; - } - // Build a Set of the decorators on this node from @angular/core. - const coreDecorators = this._angularCoreDecorators(node); - - if (coreDecorators.size === decorators.length) { - // If all decorators are to be removed, return `undefined`. - return undefined; - } else if (coreDecorators.size === 0) { - // If no decorators need to be removed, return the original decorators array. - return nodeArrayFromDecoratorsArray(decorators); - } - - // Filter out the core decorators. - const filtered = decorators.filter((dec) => !coreDecorators.has(dec)); - - // If no decorators survive, return `undefined`. This can only happen if a core decorator is - // repeated on the node. - if (filtered.length === 0) { - return undefined; - } - - // Create a new `NodeArray` with the filtered decorators that sourcemaps back to the original. - return nodeArrayFromDecoratorsArray(filtered); - } - private updateStatements(node: ts.SourceFile, importManager: ImportManager) { - return addImports(ts.factory, importManager, node); - } -} -/** - * todo 引入 - */ -function isFromAngularCore(decorator: Decorator): boolean { - return ( - decorator.import !== null && decorator.import.from === 'static-injector' - ); -} - -/** Creates a `NodeArray` with the correct offsets from an array of decorators. */ -function nodeArrayFromDecoratorsArray( - decorators: readonly ts.Decorator[], -): ts.NodeArray { - const array = ts.factory.createNodeArray(decorators); - - if (array.length > 0) { - (array.pos as number) = decorators[0].pos; - (array.end as number) = decorators[decorators.length - 1].end; - } - - return array; -} -function maybeFilterDecorator( - decorators: readonly ts.Decorator[] | undefined, - toRemove: ts.Decorator[], -): ts.NodeArray | undefined { - if (decorators === undefined) { - return undefined; - } - const filtered = decorators.filter( - (dec) => - toRemove.find( - (decToRemove) => ts.getOriginalNode(dec) === decToRemove, - ) === undefined, - ); - if (filtered.length === 0) { - return undefined; - } - return ts.factory.createNodeArray(filtered); -} diff --git a/src/transform/node-Iteration.ts b/src/transform/node-Iteration.ts deleted file mode 100644 index 3d9daf2..0000000 --- a/src/transform/node-Iteration.ts +++ /dev/null @@ -1,6 +0,0 @@ -import ts from 'typescript'; - -export function nodeIteration(node: ts.Node, fn: (node: ts.Node) => any): void { - fn(node); - ts.forEachChild(node, (node) => nodeIteration(node, fn)); -} diff --git a/test/fixture/destory.ts b/test/fixture/destory.ts index 92977e2..05649c3 100644 --- a/test/fixture/destory.ts +++ b/test/fixture/destory.ts @@ -1,6 +1,5 @@ import { Injectable, Injector, R3Injector } from 'static-injector'; let isDestroy = false; -@Injectable() export class MyClass { ngOnDestroy(): void { isDestroy = true; diff --git a/test/fixture/error/strict-constructor-deps.ts b/test/fixture/error/strict-constructor-deps.ts index 7850cad..ea70aa2 100644 --- a/test/fixture/error/strict-constructor-deps.ts +++ b/test/fixture/error/strict-constructor-deps.ts @@ -1,5 +1,5 @@ import { Injectable, Injector } from 'static-injector'; -@Injectable() + export class MyClass { constructor(a) {} } diff --git a/test/fixture/error/strict-constructor-interface-type-dep.ts b/test/fixture/error/strict-constructor-interface-type-dep.ts index 9ec5eae..ef07edd 100644 --- a/test/fixture/error/strict-constructor-interface-type-dep.ts +++ b/test/fixture/error/strict-constructor-interface-type-dep.ts @@ -1,6 +1,6 @@ import { Injectable, Injector } from 'static-injector'; interface A {} -@Injectable() + export class MyClass { constructor(a: A) {} } diff --git a/test/fixture/error/strict-constructor-union-type-dep.ts b/test/fixture/error/strict-constructor-union-type-dep.ts index 61106b1..b95561b 100644 --- a/test/fixture/error/strict-constructor-union-type-dep.ts +++ b/test/fixture/error/strict-constructor-union-type-dep.ts @@ -1,5 +1,5 @@ import { Injectable, Injector } from 'static-injector'; -@Injectable() + export class MyClass { constructor(a: number | string) {} } diff --git a/test/fixture/hello-without-provide-object.ts b/test/fixture/hello-without-provide-object.ts index 5ec94ab..ddbae46 100644 --- a/test/fixture/hello-without-provide-object.ts +++ b/test/fixture/hello-without-provide-object.ts @@ -1,5 +1,4 @@ import { Injectable, Injector } from 'static-injector'; -@Injectable() export class MyClass { hello() { return 'hello'; diff --git a/test/fixture/hello.ts b/test/fixture/hello.ts index 4660dd4..d09ca20 100644 --- a/test/fixture/hello.ts +++ b/test/fixture/hello.ts @@ -1,5 +1,4 @@ import { Injectable, Injector } from 'static-injector'; -@Injectable() export class MyClass { hello() { return 'hello'; diff --git a/test/fixture/inherit.ts b/test/fixture/inherit.ts index 96efa81..92c4ef0 100644 --- a/test/fixture/inherit.ts +++ b/test/fixture/inherit.ts @@ -1,12 +1,10 @@ import { Injectable, Injector } from 'static-injector'; -@Injectable() export class Parent { name = 'parent'; hello() { return ''; } } -@Injectable() export class MyClass extends Parent { hello() { return 'hello' + this.name; diff --git a/test/fixture/inject-class.ts b/test/fixture/inject-class.ts index e4d1dd4..c8e86f1 100644 --- a/test/fixture/inject-class.ts +++ b/test/fixture/inject-class.ts @@ -1,10 +1,8 @@ -import { Injectable, Injector, INJECTOR_SCOPE } from 'static-injector'; -@Injectable() +import { inject, Injectable, Injector, INJECTOR_SCOPE } from 'static-injector'; export class MyClass { - constructor( - private injectClass: InjectClass, - private rootInjectClass: RootInjectClass - ) {} + private injectClass = inject(InjectClass); + private rootInjectClass = inject(RootInjectClass); + constructor() {} out() { return { injectClass: this.injectClass, @@ -12,12 +10,11 @@ export class MyClass { }; } } -@Injectable() export class InjectClass { name = 'InjectClass'; } -@Injectable({ providedIn: 'root' }) export class RootInjectClass { + static injectOptions = { providedIn: 'root' }; name = 'RootInjectClass'; } diff --git a/test/fixture/inject-function.ts b/test/fixture/inject-function.ts index f5bd766..59b6783 100644 --- a/test/fixture/inject-function.ts +++ b/test/fixture/inject-function.ts @@ -1,5 +1,4 @@ import { inject, Injectable, Injector, INJECTOR_SCOPE } from 'static-injector'; -@Injectable() export class MyClass { private injectClass = inject(InjectClass); private rootInjectClass = inject(RootInjectClass); @@ -12,12 +11,12 @@ export class MyClass { }; } } -@Injectable() export class InjectClass { name = 'InjectClass'; } -@Injectable({ providedIn: 'root' }) + export class RootInjectClass { + static injectOptions = { providedIn: 'root' }; name = 'RootInjectClass'; } diff --git a/test/fixture/injectable.ts b/test/fixture/injectable.ts index 2925d1c..92e3cbb 100644 --- a/test/fixture/injectable.ts +++ b/test/fixture/injectable.ts @@ -1,22 +1,16 @@ import { + inject, Injectable, InjectionToken, Injector, - INJECTOR_SCOPE, - Optional, - SkipSelf, + INJECTOR_SCOPE } from 'static-injector'; -let token = new InjectionToken('token'); -@Injectable({ - providedIn: 'root', - useFactory: (token: string) => new MyClass(token), - deps: [ - [new Optional(), token], - [new Optional(), 'aaa'], - ], -}) +let token = new InjectionToken('token'); + export class MyClass { - constructor(private token: string) {} + static injectOptions = { providedIn: 'root' }; + private token = inject(token); + constructor() {} out() { return { token: this.token }; } diff --git a/test/fixture/main1.ts b/test/fixture/main1.ts index fcaba62..130f377 100644 --- a/test/fixture/main1.ts +++ b/test/fixture/main1.ts @@ -1,8 +1,9 @@ -import { Injectable, Injector } from 'static-injector'; +import { Injectable, Injector, inject } from 'static-injector'; import * as sub from './sub1'; -@Injectable() + export class Main1Class { - constructor(private sub: sub.Sub1Class) {} + private sub = inject(sub.Sub1Class); + constructor() {} hello() { return this.sub.hello(); } diff --git a/test/fixture/other-decorator.ts b/test/fixture/other-decorator.ts index 0fdd2bd..4044711 100644 --- a/test/fixture/other-decorator.ts +++ b/test/fixture/other-decorator.ts @@ -13,7 +13,7 @@ export class OnlyOtherClass { export const result = new OnlyOtherClass().hello(); @OtherDecorator() -@Injectable() + export class BothClass { hello() { return 'hello'; diff --git a/test/fixture/parameters-decorator.ts b/test/fixture/parameters-decorator.ts index 5aa3202..7402468 100644 --- a/test/fixture/parameters-decorator.ts +++ b/test/fixture/parameters-decorator.ts @@ -6,19 +6,17 @@ import { Optional, Self, SkipSelf, + inject, } from 'static-injector'; -@Injectable() + export class MyClass { - constructor( - @Inject(token1) private token1: number, - @Inject('noValue') @Optional() private noValue: unknown, - @Inject(token1) @SkipSelf() private token1WithInjectorL2: number, - @Inject(token1) @Self() private token1WithSelf: number - ) {} + private token1 = inject(token1); + private token1WithInjectorL2 = inject(token1, { skipSelf: true }); + private token1WithSelf = inject(token1, { self: true }); + constructor() {} out() { return { token1: this.token1, - noValue: this.noValue, token1WithInjectorL2: this.token1WithInjectorL2, token1WithSelf: this.token1WithSelf, }; diff --git a/test/fixture/provider.ts b/test/fixture/provider.ts index 9bacae9..148cf46 100644 --- a/test/fixture/provider.ts +++ b/test/fixture/provider.ts @@ -1,12 +1,11 @@ -import { Inject, Injectable, Injector, Optional } from 'static-injector'; -@Injectable() +import { Inject, Injector, Optional, inject } from 'static-injector'; + export class MyClass { - constructor( - private useClassClass: UseClassClass, - private useFactoryClass: UseFactoryClass, - private useExistingClass: UseExistingClass, - private classWithDeps: ClassWithDeps - ) {} + private useClassClass = inject(UseClassClass); + private useFactoryClass = inject(UseFactoryClass); + private useExistingClass = inject(UseExistingClass); + private classWithDeps = inject(ClassWithDeps); + constructor() {} out() { return { useClassClass: this.useClassClass, @@ -16,27 +15,27 @@ export class MyClass { }; } } -@Injectable() + export class UseClassClass { name = 'UseClassClass'; } -@Injectable() + export class UseFactoryClass { name = ''; constructor( private input: string, public noValue: string, - public injectValue: string + public injectValue: string, ) { this.name = input; } } -@Injectable() + export class UseExistingClass { name = 'noToBeUsed'; constructor(private input: string) {} } -@Injectable() + export class ClassWithDeps { constructor(public name: string) {} } diff --git a/test/fixture/sub-class.ts b/test/fixture/sub-class.ts index 5f2b58f..55e6bd8 100644 --- a/test/fixture/sub-class.ts +++ b/test/fixture/sub-class.ts @@ -2,7 +2,7 @@ import { Injectable, Injector } from 'static-injector'; export class FirstClass { init() { - @Injectable() + class SecondClass { name = 'second'; } diff --git a/test/fixture/sub1.ts b/test/fixture/sub1.ts index 100cebb..eb7c985 100644 --- a/test/fixture/sub1.ts +++ b/test/fixture/sub1.ts @@ -1,5 +1,5 @@ import { Injectable, Injector } from 'static-injector'; -@Injectable() + export class Sub1Class { hello() { return 'hello'; diff --git a/test/fixture/template-literal.ts b/test/fixture/template-literal.ts deleted file mode 100644 index 466d7bd..0000000 --- a/test/fixture/template-literal.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Inject, Injectable, Injector } from 'static-injector'; -@Injectable() -export class TemplateLiteralClass { - constructor(@Inject(`valu` + 'e') private noValue: boolean) {} - out() { - return { - noValue: this.noValue, - }; - } -} - -let inject = Injector.create({ - providers: [ - { provide: TemplateLiteralClass }, - { provide: `valu` + 'e', useValue: true }, - ], -}); -export const instance = inject.get(TemplateLiteralClass); diff --git a/test/import/parameters-decorator.spec.ts b/test/import/parameters-decorator.spec.ts index cac9802..b72375f 100644 --- a/test/import/parameters-decorator.spec.ts +++ b/test/import/parameters-decorator.spec.ts @@ -2,7 +2,6 @@ import { instance } from '../fixture/parameters-decorator'; describe('parameters-decorator', () => { it('parameters-decorator', () => { let out = instance.out(); - expect(out.noValue).toBe(null); expect(out.token1).toBe(3); expect(out.token1WithInjectorL2).toBe(2); expect(out.token1WithSelf).toBe(3); diff --git a/test/import/template-literal.spec.ts b/test/import/template-literal.spec.ts deleted file mode 100644 index 4cfe57b..0000000 --- a/test/import/template-literal.spec.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { instance } from '../fixture/template-literal'; -describe('hello', () => { - it('sub-class', () => { - expect(instance.out().noValue).toBe(true); - }); -}); diff --git a/test/transform/default.spec.ts b/test/transform/default.spec.ts deleted file mode 100644 index e4018e0..0000000 --- a/test/transform/default.spec.ts +++ /dev/null @@ -1,129 +0,0 @@ -import path from 'path'; -import { createTestTransformer } from '../util/create-test-transform'; -describe('default', () => { - it('hello-world', () => { - createTestTransformer( - [path.resolve(__dirname, '../fixture/hello.ts')], - undefined, - { - writeFile: (fileName, data) => { - expect(data).toContain(`MyClass.ɵfac`); - // expect(data).toContain(`MyClass.ɵprov`); - }, - } - ); - }); - - it('parameters-decorator', () => { - createTestTransformer( - [path.resolve(__dirname, '../fixture/parameters-decorator.ts')], - undefined, - { - writeFile: (fileName, data) => { - expect(data).toContain(`MyClass.ɵfac`); - // expect(data).toContain(`MyClass.ɵprov`); - }, - } - ); - }); - it('inject-class', () => { - createTestTransformer( - [path.resolve(__dirname, '../fixture/inject-class.ts')], - undefined, - { - writeFile: (fileName, data) => { - expect(data).toContain(`MyClass.ɵfac`); - // expect(data).toContain(`MyClass.ɵprov`); - }, - } - ); - }); - it('provider', () => { - createTestTransformer( - [path.resolve(__dirname, '../fixture/provider.ts')], - undefined, - { - writeFile: (fileName, data) => { - expect(data).toContain(`MyClass.ɵfac`); - // expect(data).toContain(`MyClass.ɵprov`); - }, - } - ); - }); - it('injectable', () => { - createTestTransformer( - [path.resolve(__dirname, '../fixture/injectable.ts')], - undefined, - { - writeFile: (fileName, data) => { - expect(data).toContain(`MyClass.ɵfac`); - // expect(data).toContain(`MyClass.ɵprov`); - }, - } - ); - }); - it('other-decorator', () => { - createTestTransformer( - [path.resolve(__dirname, '../fixture/other-decorator.ts')], - undefined, - { - writeFile: (fileName, data) => { - expect(data).not.toContain(`OnlyOtherClass.ɵfac`); - expect(data).not.toContain(`OnlyOtherClass.ɵprov`); - expect(data).toContain(`BothClass.ɵfac`); - // expect(data).toContain(`BothClass.ɵprov`); - }, - } - ); - }); - it('sub-class', () => { - createTestTransformer( - [path.resolve(__dirname, '../fixture/sub-class.ts')], - undefined, - { - writeFile: (fileName, data) => { - expect(data).not.toContain(`FirstClass.ɵfac`); - expect(data).not.toContain(`FirstClass.ɵprov`); - expect(data).toContain(`SecondClass.ɵfac`); - // expect(data).toContain(`SecondClass.ɵprov`); - }, - } - ); - }); - it('template-literal', () => { - createTestTransformer( - [path.resolve(__dirname, '../fixture/template-literal.ts')], - undefined, - { - writeFile: (fileName, data) => { - expect(data).toContain(`TemplateLiteralClass.ɵfac`); - // expect(data).toContain(`TemplateLiteralClass.ɵprov`); - }, - } - ); - }); - it('main1', () => { - createTestTransformer( - [path.resolve(__dirname, '../fixture/main1.ts')], - undefined, - { - writeFile: (fileName, data) => { - expect(data).toContain(`ɵfac`); - expect(data).toContain(`ɵprov`); - }, - } - ); - }); - it('inject(xxx)',() => { - createTestTransformer( - [path.resolve(__dirname, '../fixture/inject-function.ts')], - undefined, - { - writeFile: (fileName, data) => { - // expect(data).toContain(`ɵfac`); - // expect(data).toContain(`ɵprov`); - }, - } - ); - }) -}); diff --git a/test/transform/error.spec.ts b/test/transform/error.spec.ts deleted file mode 100644 index 4de649d..0000000 --- a/test/transform/error.spec.ts +++ /dev/null @@ -1,68 +0,0 @@ -import * as path from 'path'; -import { FatalDiagnosticError } from '../../src/transform/compiler-cli/src/ngtsc/diagnostics/error'; -import { createTestTransformer } from '../util/create-test-transform'; -describe('error', () => { - it('strict-constructor-deps', () => { - try { - createTestTransformer( - [ - path.resolve( - __dirname, - '../fixture/error/strict-constructor-deps.ts' - ), - ], - undefined, - { - writeFile: (fileName, data) => { - throw 'can not emit'; - }, - }, - { strictCtorDeps: true } - ); - } catch (error) { - expect(error instanceof FatalDiagnosticError).toBe(true); - } - }); - it('strict-constructor-union-type-dep', () => { - try { - createTestTransformer( - [ - path.resolve( - __dirname, - '../fixture/error/strict-constructor-union-type-dep.ts' - ), - ], - undefined, - { - writeFile: (fileName, data) => { - throw 'can not emit'; - }, - }, - { strictCtorDeps: true } - ); - } catch (error) { - expect(error instanceof FatalDiagnosticError).toBe(true); - } - }); - it('strict-constructor-interface-type-dep', () => { - try { - createTestTransformer( - [ - path.resolve( - __dirname, - '../fixture/error/strict-constructor-interface-type-dep.ts' - ), - ], - undefined, - { - writeFile: (fileName, data) => { - throw 'can not emit'; - }, - }, - { strictCtorDeps: true } - ); - } catch (error) { - expect(error instanceof FatalDiagnosticError).toBe(true); - } - }); -}); diff --git a/test/util/create-test-transform.ts b/test/util/create-test-transform.ts deleted file mode 100644 index 02713ea..0000000 --- a/test/util/create-test-transform.ts +++ /dev/null @@ -1,27 +0,0 @@ -import ts from 'typescript'; -import { - createTransformer, - InjectableTransformerFactoryOptions, -} from '../../src/transform'; - -export function createTestTransformer( - rootNames: string[], - options: ts.CompilerOptions = {}, - emitOptions: { - writeFile?: ts.WriteFileCallback; - emitOnlyDtsFiles?: boolean; - } = {}, - transformerOptions: InjectableTransformerFactoryOptions = {} -) { - let program = ts.createProgram({ rootNames: rootNames, options }); - let transformer = createTransformer(program, transformerOptions); - program.emit( - undefined, - emitOptions.writeFile, - undefined, - emitOptions.emitOnlyDtsFiles, - { - before: [transformer], - } - ); -} diff --git a/test/util/jest-test-transformer-loader.js b/test/util/jest-test-transformer-loader.js deleted file mode 100644 index 12e5c79..0000000 --- a/test/util/jest-test-transformer-loader.js +++ /dev/null @@ -1,5 +0,0 @@ -require('ts-node').register({ - require: ['tsconfig-paths/register'], - project: './tsconfig.transform.json', -}); -module.exports = require('./jest-test-transformer'); diff --git a/test/util/jest-test-transformer.ts b/test/util/jest-test-transformer.ts deleted file mode 100644 index 5f20e57..0000000 --- a/test/util/jest-test-transformer.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { - SourceFile, - TransformationContext, - TransformerFactory, -} from 'typescript'; -import { createTransformer } from '../../src/transform'; -import type { TsCompilerInstance } from 'ts-jest/dist/types'; -export const version = Math.random(); -export const name = 'import-transformer'; -export function factory( - compilerInstance: TsCompilerInstance -): TransformerFactory { - let transformer = createTransformer(compilerInstance.program!); - return (ctx: TransformationContext) => { - let fn = transformer(ctx); - return (sf: SourceFile) => { - return fn(sf); - }; - }; -} diff --git a/tsconfig.base.json b/tsconfig.base.json index 4dca110..e51d429 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -62,9 +62,6 @@ "skipLibCheck": true /* Skip type checking of declaration files. */, "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */, "paths": { - "static-injector/transform/compiler": [ - "./src/transform/compiler/index.ts" - ], "static-injector": ["./src/import"] } } diff --git a/tsconfig.import.json b/tsconfig.import.json index 3b01a49..8594b1c 100644 --- a/tsconfig.import.json +++ b/tsconfig.import.json @@ -1,12 +1,14 @@ { "extends": "./tsconfig.base.json", "compilerOptions": { - "outDir": "dist/import/es2022", - "declarationDir": "dist/import/typings", + "outDir": "dist/es2022", + "declarationDir": "dist/typings", "module": "ES2022", "target": "ES2022", "moduleResolution": "node", "strict": true }, - "include": ["./src/import"] -} + "include": [ + "./src/import" + ] +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index bbffd32..7087d8e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,9 +6,6 @@ { "path": "./tsconfig.import.json" }, - { - "path": "./tsconfig.transform.json" - }, { "path": "./tsconfig.import-test.json" }, diff --git a/tsconfig.transform.json b/tsconfig.transform.json deleted file mode 100644 index f7dfbb1..0000000 --- a/tsconfig.transform.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "extends": "./tsconfig.base.json", - "compilerOptions": { - "outDir": "dist/transform", - "strict": true - }, - "include": ["./src/transform"] -}