@elench/testkit 0.1.65 → 0.1.67
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -62
- package/lib/app/browser-bridge.mjs +66 -0
- package/lib/app/configs.mjs +81 -0
- package/lib/app/configs.test.mjs +34 -0
- package/lib/app/doctor.mjs +139 -0
- package/lib/app/typecheck.mjs +203 -0
- package/lib/cli/command-helpers.mjs +2 -10
- package/lib/cli/commands/browser/serve.mjs +3 -62
- package/lib/cli/commands/doctor.mjs +39 -0
- package/lib/cli/commands/typecheck.mjs +28 -0
- package/lib/cli/db.mjs +3 -68
- package/lib/cli/entrypoint.mjs +2 -0
- package/lib/config/binaries.mjs +34 -0
- package/lib/config/database.mjs +9 -6
- package/lib/config/index.mjs +13 -31
- package/lib/config/runtime.mjs +35 -96
- package/lib/config/runtime.test.mjs +26 -0
- package/lib/config/validation.mjs +18 -62
- package/lib/coverage/backend-discovery.mjs +68 -85
- package/lib/coverage/backend-discovery.test.mjs +55 -46
- package/lib/coverage/graph-builder.mjs +5 -5
- package/lib/coverage/index.test.mjs +4 -2
- package/lib/coverage/next-ir-to-graph.mjs +0 -1
- package/lib/coverage/routing.mjs +2 -29
- package/lib/coverage/routing.test.mjs +0 -16
- package/lib/coverage/shared.mjs +22 -82
- package/lib/database/fingerprint.mjs +1 -1
- package/lib/discovery/file-metadata.mjs +122 -0
- package/lib/discovery/file-metadata.test.mjs +51 -0
- package/lib/discovery/index.mjs +10 -2
- package/lib/discovery/index.test.mjs +19 -19
- package/lib/known-failures/github-cache.mjs +159 -0
- package/lib/known-failures/github-transport.mjs +174 -0
- package/lib/known-failures/github.mjs +17 -325
- package/lib/runner/default-runtime-runner.mjs +4 -10
- package/lib/runner/execution-config.mjs +12 -83
- package/lib/runner/live-run.mjs +45 -0
- package/lib/runner/managed-processes.mjs +29 -0
- package/lib/runner/orchestrator.mjs +57 -188
- package/lib/runner/planning.mjs +10 -3
- package/lib/runner/planning.test.mjs +26 -0
- package/lib/runner/playwright-runner.mjs +4 -11
- package/lib/runner/run-finalization.mjs +132 -0
- package/lib/runner/run-guards.mjs +45 -0
- package/lib/runner/runtime-preparation.mjs +1 -1
- package/lib/runner/services.mjs +3 -4
- package/lib/runner/template-steps.mjs +8 -45
- package/lib/runner/template.mjs +7 -28
- package/lib/setup/index.d.ts +88 -21
- package/lib/setup/index.mjs +177 -50
- package/lib/setup/index.test.mjs +194 -64
- package/lib/shared/build-config.mjs +144 -0
- package/lib/shared/build-config.test.mjs +81 -0
- package/lib/shared/configured-steps.mjs +178 -0
- package/lib/shared/configured-steps.test.mjs +73 -0
- package/lib/shared/execution-schema.mjs +74 -0
- package/lib/shared/execution-schema.test.mjs +26 -0
- package/node_modules/@elench/next-analysis/dist/api-routes.d.ts +7 -0
- package/node_modules/@elench/next-analysis/dist/api-routes.d.ts.map +1 -0
- package/node_modules/@elench/next-analysis/dist/api-routes.js +66 -0
- package/node_modules/@elench/next-analysis/dist/api-routes.js.map +1 -0
- package/node_modules/@elench/next-analysis/dist/app-root.d.ts +2 -0
- package/node_modules/@elench/next-analysis/dist/app-root.d.ts.map +1 -0
- package/node_modules/@elench/next-analysis/dist/app-root.js +7 -0
- package/node_modules/@elench/next-analysis/dist/app-root.js.map +1 -0
- package/node_modules/@elench/next-analysis/dist/backend-links.d.ts +8 -0
- package/node_modules/@elench/next-analysis/dist/backend-links.d.ts.map +1 -0
- package/node_modules/@elench/next-analysis/dist/backend-links.js +30 -0
- package/node_modules/@elench/next-analysis/dist/backend-links.js.map +1 -0
- package/node_modules/@elench/next-analysis/dist/index.d.ts +11 -0
- package/node_modules/@elench/next-analysis/dist/index.d.ts.map +1 -0
- package/node_modules/@elench/next-analysis/dist/index.js +10 -0
- package/node_modules/@elench/next-analysis/dist/index.js.map +1 -0
- package/node_modules/@elench/next-analysis/dist/pages.d.ts +7 -0
- package/node_modules/@elench/next-analysis/dist/pages.d.ts.map +1 -0
- package/node_modules/@elench/next-analysis/dist/pages.js +47 -0
- package/node_modules/@elench/next-analysis/dist/pages.js.map +1 -0
- package/node_modules/@elench/next-analysis/dist/project.d.ts +3 -0
- package/node_modules/@elench/next-analysis/dist/project.d.ts.map +1 -0
- package/node_modules/@elench/next-analysis/dist/project.js +102 -0
- package/node_modules/@elench/next-analysis/dist/project.js.map +1 -0
- package/node_modules/@elench/next-analysis/dist/route-tree.d.ts +7 -0
- package/node_modules/@elench/next-analysis/dist/route-tree.d.ts.map +1 -0
- package/node_modules/@elench/next-analysis/dist/route-tree.js +575 -0
- package/node_modules/@elench/next-analysis/dist/route-tree.js.map +1 -0
- package/node_modules/@elench/next-analysis/dist/routes.d.ts +6 -0
- package/node_modules/@elench/next-analysis/dist/routes.d.ts.map +1 -0
- package/node_modules/@elench/next-analysis/dist/routes.js +41 -0
- package/node_modules/@elench/next-analysis/dist/routes.js.map +1 -0
- package/node_modules/@elench/next-analysis/dist/server-actions.d.ts +7 -0
- package/node_modules/@elench/next-analysis/dist/server-actions.d.ts.map +1 -0
- package/node_modules/@elench/next-analysis/dist/server-actions.js +37 -0
- package/node_modules/@elench/next-analysis/dist/server-actions.js.map +1 -0
- package/node_modules/@elench/next-analysis/dist/shared.d.ts +57 -0
- package/node_modules/@elench/next-analysis/dist/shared.d.ts.map +1 -0
- package/node_modules/@elench/next-analysis/dist/shared.js +229 -0
- package/node_modules/@elench/next-analysis/dist/shared.js.map +1 -0
- package/node_modules/@elench/next-analysis/dist/swc.d.ts +53 -0
- package/node_modules/@elench/next-analysis/dist/swc.d.ts.map +1 -0
- package/node_modules/@elench/next-analysis/dist/swc.js +387 -0
- package/node_modules/@elench/next-analysis/dist/swc.js.map +1 -0
- package/node_modules/@elench/next-analysis/dist/types.d.ts +125 -0
- package/node_modules/@elench/next-analysis/dist/types.d.ts.map +1 -0
- package/node_modules/@elench/next-analysis/dist/types.js +2 -0
- package/node_modules/@elench/next-analysis/dist/types.js.map +1 -0
- package/node_modules/@elench/next-analysis/package.json +15 -2
- package/node_modules/@elench/testkit-bridge/dist/index.d.ts +36 -0
- package/node_modules/@elench/testkit-bridge/dist/index.d.ts.map +1 -0
- package/node_modules/@elench/testkit-bridge/dist/index.js +538 -0
- package/node_modules/@elench/testkit-bridge/dist/index.js.map +1 -0
- package/node_modules/@elench/testkit-bridge/package.json +16 -5
- package/node_modules/@elench/testkit-protocol/dist/index.d.ts +190 -0
- package/node_modules/@elench/testkit-protocol/dist/index.d.ts.map +1 -0
- package/node_modules/@elench/testkit-protocol/dist/index.js +296 -0
- package/node_modules/@elench/testkit-protocol/dist/index.js.map +1 -0
- package/node_modules/@elench/testkit-protocol/package.json +14 -7
- package/node_modules/@elench/ts-analysis/dist/callables.d.ts +8 -0
- package/node_modules/@elench/ts-analysis/dist/callables.d.ts.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/callables.js +126 -0
- package/node_modules/@elench/ts-analysis/dist/callables.js.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/exports.d.ts +6 -0
- package/node_modules/@elench/ts-analysis/dist/exports.d.ts.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/exports.js +70 -0
- package/node_modules/@elench/ts-analysis/dist/exports.js.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/index.d.ts +10 -0
- package/node_modules/@elench/ts-analysis/dist/index.d.ts.map +1 -0
- package/node_modules/@elench/ts-analysis/{src/index.mjs → dist/index.js} +9 -14
- package/node_modules/@elench/ts-analysis/dist/index.js.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/jsx.d.ts +9 -0
- package/node_modules/@elench/ts-analysis/dist/jsx.d.ts.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/jsx.js +68 -0
- package/node_modules/@elench/ts-analysis/dist/jsx.js.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/project.d.ts +5 -0
- package/node_modules/@elench/ts-analysis/dist/project.d.ts.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/project.js +90 -0
- package/node_modules/@elench/ts-analysis/dist/project.js.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/requests.d.ts +6 -0
- package/node_modules/@elench/ts-analysis/dist/requests.d.ts.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/requests.js +140 -0
- package/node_modules/@elench/ts-analysis/dist/requests.js.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/resolution.d.ts +4 -0
- package/node_modules/@elench/ts-analysis/dist/resolution.d.ts.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/resolution.js +53 -0
- package/node_modules/@elench/ts-analysis/dist/resolution.js.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/shared.d.ts +6 -0
- package/node_modules/@elench/ts-analysis/dist/shared.d.ts.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/shared.js +31 -0
- package/node_modules/@elench/ts-analysis/dist/shared.js.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/syntax.d.ts +7 -0
- package/node_modules/@elench/ts-analysis/dist/syntax.d.ts.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/syntax.js +27 -0
- package/node_modules/@elench/ts-analysis/dist/syntax.js.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/types.d.ts +58 -0
- package/node_modules/@elench/ts-analysis/dist/types.d.ts.map +1 -0
- package/node_modules/@elench/ts-analysis/dist/types.js +2 -0
- package/node_modules/@elench/ts-analysis/dist/types.js.map +1 -0
- package/node_modules/@elench/ts-analysis/package.json +18 -2
- package/node_modules/typescript/LICENSE.txt +55 -0
- package/node_modules/typescript/README.md +50 -0
- package/node_modules/typescript/SECURITY.md +41 -0
- package/node_modules/typescript/ThirdPartyNoticeText.txt +193 -0
- package/node_modules/typescript/bin/tsc +2 -0
- package/node_modules/typescript/bin/tsserver +2 -0
- package/node_modules/typescript/lib/_tsc.js +133818 -0
- package/node_modules/typescript/lib/_tsserver.js +659 -0
- package/node_modules/typescript/lib/_typingsInstaller.js +222 -0
- package/node_modules/typescript/lib/cs/diagnosticMessages.generated.json +2122 -0
- package/node_modules/typescript/lib/de/diagnosticMessages.generated.json +2122 -0
- package/node_modules/typescript/lib/es/diagnosticMessages.generated.json +2122 -0
- package/node_modules/typescript/lib/fr/diagnosticMessages.generated.json +2122 -0
- package/node_modules/typescript/lib/it/diagnosticMessages.generated.json +2122 -0
- package/node_modules/typescript/lib/ja/diagnosticMessages.generated.json +2122 -0
- package/node_modules/typescript/lib/ko/diagnosticMessages.generated.json +2122 -0
- package/node_modules/typescript/lib/lib.d.ts +22 -0
- package/node_modules/typescript/lib/lib.decorators.d.ts +384 -0
- package/node_modules/typescript/lib/lib.decorators.legacy.d.ts +22 -0
- package/node_modules/typescript/lib/lib.dom.asynciterable.d.ts +41 -0
- package/node_modules/typescript/lib/lib.dom.d.ts +39429 -0
- package/node_modules/typescript/lib/lib.dom.iterable.d.ts +571 -0
- package/node_modules/typescript/lib/lib.es2015.collection.d.ts +147 -0
- package/node_modules/typescript/lib/lib.es2015.core.d.ts +597 -0
- package/node_modules/typescript/lib/lib.es2015.d.ts +28 -0
- package/node_modules/typescript/lib/lib.es2015.generator.d.ts +77 -0
- package/node_modules/typescript/lib/lib.es2015.iterable.d.ts +605 -0
- package/node_modules/typescript/lib/lib.es2015.promise.d.ts +81 -0
- package/node_modules/typescript/lib/lib.es2015.proxy.d.ts +128 -0
- package/node_modules/typescript/lib/lib.es2015.reflect.d.ts +144 -0
- package/node_modules/typescript/lib/lib.es2015.symbol.d.ts +46 -0
- package/node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts +326 -0
- package/node_modules/typescript/lib/lib.es2016.array.include.d.ts +116 -0
- package/node_modules/typescript/lib/lib.es2016.d.ts +21 -0
- package/node_modules/typescript/lib/lib.es2016.full.d.ts +23 -0
- package/node_modules/typescript/lib/lib.es2016.intl.d.ts +31 -0
- package/node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts +21 -0
- package/node_modules/typescript/lib/lib.es2017.d.ts +26 -0
- package/node_modules/typescript/lib/lib.es2017.date.d.ts +31 -0
- package/node_modules/typescript/lib/lib.es2017.full.d.ts +23 -0
- package/node_modules/typescript/lib/lib.es2017.intl.d.ts +44 -0
- package/node_modules/typescript/lib/lib.es2017.object.d.ts +49 -0
- package/node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts +135 -0
- package/node_modules/typescript/lib/lib.es2017.string.d.ts +45 -0
- package/node_modules/typescript/lib/lib.es2017.typedarrays.d.ts +53 -0
- package/node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts +77 -0
- package/node_modules/typescript/lib/lib.es2018.asynciterable.d.ts +53 -0
- package/node_modules/typescript/lib/lib.es2018.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2018.full.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2018.intl.d.ts +83 -0
- package/node_modules/typescript/lib/lib.es2018.promise.d.ts +30 -0
- package/node_modules/typescript/lib/lib.es2018.regexp.d.ts +37 -0
- package/node_modules/typescript/lib/lib.es2019.array.d.ts +79 -0
- package/node_modules/typescript/lib/lib.es2019.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2019.full.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2019.intl.d.ts +23 -0
- package/node_modules/typescript/lib/lib.es2019.object.d.ts +33 -0
- package/node_modules/typescript/lib/lib.es2019.string.d.ts +37 -0
- package/node_modules/typescript/lib/lib.es2019.symbol.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2020.bigint.d.ts +765 -0
- package/node_modules/typescript/lib/lib.es2020.d.ts +27 -0
- package/node_modules/typescript/lib/lib.es2020.date.d.ts +42 -0
- package/node_modules/typescript/lib/lib.es2020.full.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2020.intl.d.ts +474 -0
- package/node_modules/typescript/lib/lib.es2020.number.d.ts +28 -0
- package/node_modules/typescript/lib/lib.es2020.promise.d.ts +47 -0
- package/node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts +99 -0
- package/node_modules/typescript/lib/lib.es2020.string.d.ts +44 -0
- package/node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts +41 -0
- package/node_modules/typescript/lib/lib.es2021.d.ts +23 -0
- package/node_modules/typescript/lib/lib.es2021.full.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2021.intl.d.ts +166 -0
- package/node_modules/typescript/lib/lib.es2021.promise.d.ts +48 -0
- package/node_modules/typescript/lib/lib.es2021.string.d.ts +33 -0
- package/node_modules/typescript/lib/lib.es2021.weakref.d.ts +78 -0
- package/node_modules/typescript/lib/lib.es2022.array.d.ts +121 -0
- package/node_modules/typescript/lib/lib.es2022.d.ts +25 -0
- package/node_modules/typescript/lib/lib.es2022.error.d.ts +75 -0
- package/node_modules/typescript/lib/lib.es2022.full.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2022.intl.d.ts +145 -0
- package/node_modules/typescript/lib/lib.es2022.object.d.ts +26 -0
- package/node_modules/typescript/lib/lib.es2022.regexp.d.ts +39 -0
- package/node_modules/typescript/lib/lib.es2022.string.d.ts +25 -0
- package/node_modules/typescript/lib/lib.es2023.array.d.ts +924 -0
- package/node_modules/typescript/lib/lib.es2023.collection.d.ts +21 -0
- package/node_modules/typescript/lib/lib.es2023.d.ts +22 -0
- package/node_modules/typescript/lib/lib.es2023.full.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2023.intl.d.ts +56 -0
- package/node_modules/typescript/lib/lib.es2024.arraybuffer.d.ts +65 -0
- package/node_modules/typescript/lib/lib.es2024.collection.d.ts +29 -0
- package/node_modules/typescript/lib/lib.es2024.d.ts +26 -0
- package/node_modules/typescript/lib/lib.es2024.full.d.ts +24 -0
- package/node_modules/typescript/lib/lib.es2024.object.d.ts +29 -0
- package/node_modules/typescript/lib/lib.es2024.promise.d.ts +35 -0
- package/node_modules/typescript/lib/lib.es2024.regexp.d.ts +25 -0
- package/node_modules/typescript/lib/lib.es2024.sharedmemory.d.ts +68 -0
- package/node_modules/typescript/lib/lib.es2024.string.d.ts +29 -0
- package/node_modules/typescript/lib/lib.es5.d.ts +4601 -0
- package/node_modules/typescript/lib/lib.es6.d.ts +23 -0
- package/node_modules/typescript/lib/lib.esnext.array.d.ts +35 -0
- package/node_modules/typescript/lib/lib.esnext.collection.d.ts +96 -0
- package/node_modules/typescript/lib/lib.esnext.d.ts +29 -0
- package/node_modules/typescript/lib/lib.esnext.decorators.d.ts +28 -0
- package/node_modules/typescript/lib/lib.esnext.disposable.d.ts +193 -0
- package/node_modules/typescript/lib/lib.esnext.error.d.ts +24 -0
- package/node_modules/typescript/lib/lib.esnext.float16.d.ts +445 -0
- package/node_modules/typescript/lib/lib.esnext.full.d.ts +24 -0
- package/node_modules/typescript/lib/lib.esnext.intl.d.ts +21 -0
- package/node_modules/typescript/lib/lib.esnext.iterator.d.ts +148 -0
- package/node_modules/typescript/lib/lib.esnext.promise.d.ts +34 -0
- package/node_modules/typescript/lib/lib.esnext.sharedmemory.d.ts +25 -0
- package/node_modules/typescript/lib/lib.scripthost.d.ts +322 -0
- package/node_modules/typescript/lib/lib.webworker.asynciterable.d.ts +41 -0
- package/node_modules/typescript/lib/lib.webworker.d.ts +13150 -0
- package/node_modules/typescript/lib/lib.webworker.importscripts.d.ts +23 -0
- package/node_modules/typescript/lib/lib.webworker.iterable.d.ts +340 -0
- package/node_modules/typescript/lib/pl/diagnosticMessages.generated.json +2122 -0
- package/node_modules/typescript/lib/pt-br/diagnosticMessages.generated.json +2122 -0
- package/node_modules/typescript/lib/ru/diagnosticMessages.generated.json +2122 -0
- package/node_modules/typescript/lib/tr/diagnosticMessages.generated.json +2122 -0
- package/node_modules/typescript/lib/tsc.js +8 -0
- package/node_modules/typescript/lib/tsserver.js +8 -0
- package/node_modules/typescript/lib/tsserverlibrary.d.ts +17 -0
- package/node_modules/typescript/lib/tsserverlibrary.js +21 -0
- package/node_modules/typescript/lib/typesMap.json +497 -0
- package/node_modules/typescript/lib/typescript.d.ts +11437 -0
- package/node_modules/typescript/lib/typescript.js +200276 -0
- package/node_modules/typescript/lib/typingsInstaller.js +8 -0
- package/node_modules/typescript/lib/watchGuard.js +53 -0
- package/node_modules/typescript/lib/zh-cn/diagnosticMessages.generated.json +2122 -0
- package/node_modules/typescript/lib/zh-tw/diagnosticMessages.generated.json +2122 -0
- package/node_modules/typescript/package.json +120 -0
- package/package.json +12 -9
- package/lib/coverage/fs-walk.mjs +0 -64
- package/node_modules/@elench/next-analysis/src/api-routes.mjs +0 -81
- package/node_modules/@elench/next-analysis/src/api-routes.test.mjs +0 -22
- package/node_modules/@elench/next-analysis/src/app-root.mjs +0 -7
- package/node_modules/@elench/next-analysis/src/backend-links.mjs +0 -31
- package/node_modules/@elench/next-analysis/src/index.mjs +0 -21
- package/node_modules/@elench/next-analysis/src/pages.mjs +0 -68
- package/node_modules/@elench/next-analysis/src/project.mjs +0 -94
- package/node_modules/@elench/next-analysis/src/project.test.mjs +0 -35
- package/node_modules/@elench/next-analysis/src/route-tree.mjs +0 -621
- package/node_modules/@elench/next-analysis/src/routes.mjs +0 -41
- package/node_modules/@elench/next-analysis/src/routes.test.mjs +0 -25
- package/node_modules/@elench/next-analysis/src/server-actions.mjs +0 -53
- package/node_modules/@elench/next-analysis/src/server-actions.test.mjs +0 -37
- package/node_modules/@elench/next-analysis/src/shared.mjs +0 -209
- package/node_modules/@elench/next-analysis/src/swc.mjs +0 -388
- package/node_modules/@elench/testkit-bridge/src/index.mjs +0 -583
- package/node_modules/@elench/testkit-bridge/src/index.test.mjs +0 -409
- package/node_modules/@elench/testkit-protocol/src/index.d.ts +0 -231
- package/node_modules/@elench/testkit-protocol/src/index.mjs +0 -265
- package/node_modules/@elench/testkit-protocol/src/index.test.mjs +0 -242
- package/node_modules/@elench/ts-analysis/src/callables.mjs +0 -135
- package/node_modules/@elench/ts-analysis/src/callables.test.mjs +0 -55
- package/node_modules/@elench/ts-analysis/src/exports.mjs +0 -69
- package/node_modules/@elench/ts-analysis/src/exports.test.mjs +0 -50
- package/node_modules/@elench/ts-analysis/src/jsx.mjs +0 -69
- package/node_modules/@elench/ts-analysis/src/jsx.test.mjs +0 -43
- package/node_modules/@elench/ts-analysis/src/project.mjs +0 -100
- package/node_modules/@elench/ts-analysis/src/project.test.mjs +0 -54
- package/node_modules/@elench/ts-analysis/src/requests.mjs +0 -141
- package/node_modules/@elench/ts-analysis/src/requests.test.mjs +0 -35
- package/node_modules/@elench/ts-analysis/src/resolution.mjs +0 -53
- package/node_modules/@elench/ts-analysis/src/shared.mjs +0 -32
- package/node_modules/@elench/ts-analysis/src/syntax.mjs +0 -27
package/README.md
CHANGED
|
@@ -87,16 +87,13 @@ Create `testkit.setup.ts` at repo root:
|
|
|
87
87
|
|
|
88
88
|
```ts
|
|
89
89
|
import {
|
|
90
|
-
commandStep,
|
|
91
90
|
defineTestkitSetup,
|
|
92
|
-
|
|
93
|
-
|
|
91
|
+
defineTestkitFile,
|
|
92
|
+
nextApp,
|
|
94
93
|
nodeToolchain,
|
|
95
|
-
|
|
94
|
+
nodeApp,
|
|
96
95
|
seedCommand,
|
|
97
|
-
|
|
98
|
-
service,
|
|
99
|
-
tsxService,
|
|
96
|
+
templateDatabase,
|
|
100
97
|
verifyModule,
|
|
101
98
|
} from "@elench/testkit/setup";
|
|
102
99
|
|
|
@@ -121,77 +118,53 @@ export default defineTestkitSetup({
|
|
|
121
118
|
}),
|
|
122
119
|
},
|
|
123
120
|
services: {
|
|
124
|
-
api:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
port: 3004,
|
|
129
|
-
readyPath: "/health",
|
|
130
|
-
}),
|
|
121
|
+
api: nodeApp({
|
|
122
|
+
cwd: ".",
|
|
123
|
+
entry: "src/index.ts",
|
|
124
|
+
port: 3004,
|
|
131
125
|
envFiles: [".env.testkit"],
|
|
132
|
-
database:
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
verify: verifyModule("src/testkit/verify-seed.ts#verifySeed"),
|
|
138
|
-
}),
|
|
126
|
+
database: templateDatabase({
|
|
127
|
+
inputs: ["db/schema.sql", "scripts/seed.ts"],
|
|
128
|
+
schema: "db/schema.sql",
|
|
129
|
+
seed: seedCommand("npm run db:seed"),
|
|
130
|
+
verify: verifyModule("src/testkit/verify-seed.ts#verifySeed"),
|
|
139
131
|
}),
|
|
140
132
|
runtime: {
|
|
141
133
|
instances: 1,
|
|
142
134
|
maxConcurrentTasks: 4,
|
|
143
135
|
},
|
|
144
|
-
requirements: {
|
|
145
|
-
files: [
|
|
146
|
-
{
|
|
147
|
-
path: "src/api/routes/__testkit__/crawls-worker-concurrency.int.testkit.ts",
|
|
148
|
-
locks: ["global-worker-loop"],
|
|
149
|
-
},
|
|
150
|
-
],
|
|
151
|
-
},
|
|
152
136
|
}),
|
|
153
|
-
frontend:
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
start: "./node_modules/.bin/next start --port {port}",
|
|
158
|
-
env: {
|
|
159
|
-
NEXT_DIST_DIR: "{prepareDir}/dist",
|
|
160
|
-
NEXT_PUBLIC_API_URL: "{baseUrl:api}",
|
|
161
|
-
},
|
|
162
|
-
}),
|
|
137
|
+
frontend: nextApp({
|
|
138
|
+
cwd: "frontend",
|
|
139
|
+
mode: "start",
|
|
140
|
+
port: 3000,
|
|
163
141
|
dependsOn: ["api"],
|
|
164
142
|
envFiles: ["frontend/.env.testkit"],
|
|
143
|
+
env: {
|
|
144
|
+
NEXT_DIST_DIR: "{prepareDir}/dist",
|
|
145
|
+
NEXT_PUBLIC_API_URL: "{baseUrl:api}",
|
|
146
|
+
},
|
|
165
147
|
runtime: {
|
|
166
148
|
instances: 1,
|
|
167
149
|
maxConcurrentTasks: 2,
|
|
168
150
|
toolchain: "frontendNode",
|
|
169
|
-
prepare: {
|
|
170
|
-
inputs: ["frontend/src", "frontend/public", "frontend/package.json"],
|
|
171
|
-
steps: [commandStep("npm run build", { cwd: "frontend" })],
|
|
172
|
-
},
|
|
173
|
-
},
|
|
174
|
-
}),
|
|
175
|
-
billing: service({
|
|
176
|
-
skip: {
|
|
177
|
-
files: [
|
|
178
|
-
{
|
|
179
|
-
path: "__testkit__/invoices/invoices.int.testkit.ts",
|
|
180
|
-
reason: "Billing is still stubbed locally",
|
|
181
|
-
},
|
|
182
|
-
],
|
|
183
|
-
suites: [
|
|
184
|
-
{
|
|
185
|
-
selector: "pw:lifecycle",
|
|
186
|
-
reason: "End-to-end billing lifecycle is not implemented yet",
|
|
187
|
-
},
|
|
188
|
-
],
|
|
189
151
|
},
|
|
190
152
|
}),
|
|
191
153
|
},
|
|
192
154
|
});
|
|
193
155
|
```
|
|
194
156
|
|
|
157
|
+
File-local execution metadata now lives next to the test when possible:
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { defineTestkitFile } from "@elench/testkit/setup";
|
|
161
|
+
|
|
162
|
+
export const testkit = defineTestkitFile({
|
|
163
|
+
skip: "Billing is still stubbed locally",
|
|
164
|
+
locks: ["global-worker-loop"],
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
195
168
|
`testkit.setup.ts` is optional for simple repos, but it is the primary escape hatch
|
|
196
169
|
for:
|
|
197
170
|
|
|
@@ -232,7 +205,7 @@ For most repos, prefer the intent-focused helpers:
|
|
|
232
205
|
- `seedModule(...)`
|
|
233
206
|
- `verifyCommand(...)`
|
|
234
207
|
- `verifyModule(...)`
|
|
235
|
-
- `
|
|
208
|
+
- `templateDatabase(...)`
|
|
236
209
|
|
|
237
210
|
Use raw `commandStep(...)`, `sqlFileStep(...)`, and `moduleStep(...)` arrays when
|
|
238
211
|
you need lower-level control over the exact stage layout.
|
|
@@ -264,7 +237,9 @@ toolchains: {
|
|
|
264
237
|
}),
|
|
265
238
|
},
|
|
266
239
|
services: {
|
|
267
|
-
frontend:
|
|
240
|
+
frontend: nextApp({
|
|
241
|
+
cwd: "frontend",
|
|
242
|
+
port: 3000,
|
|
268
243
|
runtime: {
|
|
269
244
|
toolchain: "frontendNode",
|
|
270
245
|
},
|
|
@@ -473,7 +448,7 @@ Git metadata.
|
|
|
473
448
|
## Local Databases
|
|
474
449
|
|
|
475
450
|
`@elench/testkit` provisions Docker-managed local Postgres automatically for
|
|
476
|
-
services that define `database:
|
|
451
|
+
services that define `database: postgresDatabase(...)` or `database: templateDatabase(...)`.
|
|
477
452
|
|
|
478
453
|
- template databases are cached
|
|
479
454
|
- runtime databases are cloned from templates when binding is `per-runtime`
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { loadConfigContext, resolveProductDir } from "../config/index.mjs";
|
|
2
|
+
import { discoverTests } from "../discovery/index.mjs";
|
|
3
|
+
import { loadCurrentRunArtifact } from "../cli/viewer.mjs";
|
|
4
|
+
|
|
5
|
+
export async function loadBrowserBridgeContext(options = {}) {
|
|
6
|
+
const productDir = resolveProductDir(process.cwd(), options.dir);
|
|
7
|
+
const [configContext, discovery] = await Promise.all([
|
|
8
|
+
loadConfigContext({
|
|
9
|
+
dir: productDir,
|
|
10
|
+
discoveryOptions: { strict: false },
|
|
11
|
+
}),
|
|
12
|
+
discoverTests({
|
|
13
|
+
dir: productDir,
|
|
14
|
+
diagnostics: "report",
|
|
15
|
+
}),
|
|
16
|
+
]);
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
productDir,
|
|
20
|
+
context: {
|
|
21
|
+
product: {
|
|
22
|
+
name: discovery.product.name,
|
|
23
|
+
directory: discovery.product.directory,
|
|
24
|
+
},
|
|
25
|
+
services: configContext.configs
|
|
26
|
+
.map((config) => {
|
|
27
|
+
const baseUrl = config.testkit.local?.baseUrl || null;
|
|
28
|
+
const browserOrigins = config.testkit.browser?.origins || [];
|
|
29
|
+
if (!baseUrl && browserOrigins.length === 0) return null;
|
|
30
|
+
const serviceEntries = [];
|
|
31
|
+
if (baseUrl && !baseUrl.includes("{port}")) {
|
|
32
|
+
try {
|
|
33
|
+
const parsed = new URL(baseUrl);
|
|
34
|
+
serviceEntries.push({
|
|
35
|
+
name: config.name,
|
|
36
|
+
baseUrl,
|
|
37
|
+
origin: parsed.origin,
|
|
38
|
+
});
|
|
39
|
+
} catch {
|
|
40
|
+
// Ignore invalid local.baseUrl templates here; explicit browser origins still work.
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
for (const origin of browserOrigins) {
|
|
44
|
+
serviceEntries.push({
|
|
45
|
+
name: config.name,
|
|
46
|
+
baseUrl: origin,
|
|
47
|
+
origin,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return serviceEntries;
|
|
51
|
+
})
|
|
52
|
+
.flat()
|
|
53
|
+
.filter(Boolean),
|
|
54
|
+
discovery,
|
|
55
|
+
runArtifact: loadRunArtifactIfPresent(productDir),
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function loadRunArtifactIfPresent(productDir) {
|
|
61
|
+
try {
|
|
62
|
+
return loadCurrentRunArtifact(productDir);
|
|
63
|
+
} catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { loadConfigs } from "../config/index.mjs";
|
|
2
|
+
|
|
3
|
+
export async function loadManagedConfigs(options = {}) {
|
|
4
|
+
const allConfigs = await loadConfigs({ dir: options.dir });
|
|
5
|
+
const configs = filterConfigsByService(allConfigs, options.service || null);
|
|
6
|
+
return { allConfigs, configs };
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function filterConfigsByService(allConfigs, serviceName) {
|
|
10
|
+
if (!serviceName) return allConfigs;
|
|
11
|
+
const configs = allConfigs.filter((config) => config.name === serviceName);
|
|
12
|
+
if (configs.length > 0) return configs;
|
|
13
|
+
const available = allConfigs.map((config) => config.name).join(", ");
|
|
14
|
+
throw new Error(`Service "${serviceName}" not found. Available: ${available}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function resolveTargetConfig(configs, serviceName = null) {
|
|
18
|
+
if (serviceName) {
|
|
19
|
+
const match = configs.find((config) => config.name === serviceName);
|
|
20
|
+
if (!match) {
|
|
21
|
+
const available = configs.map((config) => config.name).join(", ");
|
|
22
|
+
throw new Error(`Service "${serviceName}" not found. Available: ${available}`);
|
|
23
|
+
}
|
|
24
|
+
return match;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
if (configs.length === 1) return configs[0];
|
|
28
|
+
const withLocalDb = configs.filter((config) => config.testkit.database?.provider === "local");
|
|
29
|
+
if (withLocalDb.length === 1) return withLocalDb[0];
|
|
30
|
+
|
|
31
|
+
const available = configs.map((config) => config.name).join(", ");
|
|
32
|
+
throw new Error(`Multiple services available. Pass --service. Available: ${available}`);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function collectRequiredConfigs(configs, targetName) {
|
|
36
|
+
const byName = new Map(configs.map((config) => [config.name, config]));
|
|
37
|
+
const required = new Set();
|
|
38
|
+
|
|
39
|
+
const visit = (name) => {
|
|
40
|
+
if (required.has(name)) return;
|
|
41
|
+
const config = byName.get(name);
|
|
42
|
+
if (!config) {
|
|
43
|
+
throw new Error(`Missing config for dependency "${name}"`);
|
|
44
|
+
}
|
|
45
|
+
required.add(name);
|
|
46
|
+
for (const depName of config.testkit.dependsOn || []) {
|
|
47
|
+
visit(depName);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
visit(targetName);
|
|
52
|
+
return configs.filter((config) => required.has(config.name));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function topologicallySortConfigs(configs) {
|
|
56
|
+
const byName = new Map(configs.map((config) => [config.name, config]));
|
|
57
|
+
const visited = new Set();
|
|
58
|
+
const visiting = new Set();
|
|
59
|
+
const ordered = [];
|
|
60
|
+
|
|
61
|
+
const visit = (config) => {
|
|
62
|
+
if (visited.has(config.name)) return;
|
|
63
|
+
if (visiting.has(config.name)) {
|
|
64
|
+
throw new Error(`Dependency cycle while resolving configs for "${config.name}"`);
|
|
65
|
+
}
|
|
66
|
+
visiting.add(config.name);
|
|
67
|
+
for (const depName of config.testkit.dependsOn || []) {
|
|
68
|
+
const dependency = byName.get(depName);
|
|
69
|
+
if (dependency) visit(dependency);
|
|
70
|
+
}
|
|
71
|
+
visiting.delete(config.name);
|
|
72
|
+
visited.add(config.name);
|
|
73
|
+
ordered.push(config);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
for (const config of configs) {
|
|
77
|
+
visit(config);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return ordered;
|
|
81
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
collectRequiredConfigs,
|
|
4
|
+
filterConfigsByService,
|
|
5
|
+
resolveTargetConfig,
|
|
6
|
+
topologicallySortConfigs,
|
|
7
|
+
} from "./configs.mjs";
|
|
8
|
+
|
|
9
|
+
function makeConfig(name, dependsOn = [], provider = null) {
|
|
10
|
+
return {
|
|
11
|
+
name,
|
|
12
|
+
testkit: {
|
|
13
|
+
dependsOn,
|
|
14
|
+
database: provider ? { provider } : undefined,
|
|
15
|
+
},
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
describe("app config helpers", () => {
|
|
20
|
+
it("filters and resolves target configs", () => {
|
|
21
|
+
const configs = [makeConfig("api"), makeConfig("frontend", ["api"], "local")];
|
|
22
|
+
|
|
23
|
+
expect(filterConfigsByService(configs, "api")).toEqual([configs[0]]);
|
|
24
|
+
expect(resolveTargetConfig(configs)).toBe(configs[1]);
|
|
25
|
+
expect(() => filterConfigsByService(configs, "missing")).toThrow('Service "missing" not found');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it("collects dependencies and sorts them topologically", () => {
|
|
29
|
+
const configs = [makeConfig("frontend", ["api"]), makeConfig("api"), makeConfig("worker", ["api"])];
|
|
30
|
+
|
|
31
|
+
expect(collectRequiredConfigs(configs, "frontend").map((config) => config.name).sort()).toEqual(["api", "frontend"]);
|
|
32
|
+
expect(topologicallySortConfigs(configs).map((config) => config.name)).toEqual(["api", "frontend", "worker"]);
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import ts from "typescript";
|
|
4
|
+
import { discoverTests } from "../discovery/index.mjs";
|
|
5
|
+
import { loadConfigContext } from "../config/index.mjs";
|
|
6
|
+
import { runTestkitTypecheck } from "./typecheck.mjs";
|
|
7
|
+
|
|
8
|
+
export async function runDoctor(options = {}) {
|
|
9
|
+
const checks = [];
|
|
10
|
+
const productDir = options.dir ? path.resolve(process.cwd(), options.dir) : process.cwd();
|
|
11
|
+
|
|
12
|
+
await loadConfigContext({ dir: productDir });
|
|
13
|
+
checks.push({
|
|
14
|
+
code: "config-load",
|
|
15
|
+
level: "pass",
|
|
16
|
+
message: "Loaded testkit setup and service config",
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
const discovery = await discoverTests({ dir: productDir, diagnostics: "report" });
|
|
20
|
+
const discoveryErrors = discovery.diagnostics.filter((entry) => entry.severity === "error");
|
|
21
|
+
checks.push({
|
|
22
|
+
code: "discovery",
|
|
23
|
+
level: discoveryErrors.length === 0 ? "pass" : "fail",
|
|
24
|
+
message:
|
|
25
|
+
discoveryErrors.length === 0
|
|
26
|
+
? `Discovered ${discovery.files.length} testkit files without diagnostics`
|
|
27
|
+
: `Discovery reported ${discoveryErrors.length} error diagnostics`,
|
|
28
|
+
details: discoveryErrors,
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const playwrightViolations = findPlaywrightRuntimeImportViolations(productDir);
|
|
32
|
+
checks.push({
|
|
33
|
+
code: "playwright-runtime-imports",
|
|
34
|
+
level: playwrightViolations.length === 0 ? "pass" : "fail",
|
|
35
|
+
message:
|
|
36
|
+
playwrightViolations.length === 0
|
|
37
|
+
? "No runtime @playwright/test imports found in testkit Playwright suites"
|
|
38
|
+
: `Found ${playwrightViolations.length} Playwright runtime import violation(s)`,
|
|
39
|
+
details: playwrightViolations,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const hasBrowserOrNextWork = discovery.files.some((entry) => entry.selectionType === "pw");
|
|
43
|
+
if (hasBrowserOrNextWork) {
|
|
44
|
+
const nodeCount = discovery.coverageGraph?.nodes?.length || 0;
|
|
45
|
+
checks.push({
|
|
46
|
+
code: "coverage-graph",
|
|
47
|
+
level: nodeCount > 0 ? "pass" : "warning",
|
|
48
|
+
message:
|
|
49
|
+
nodeCount > 0
|
|
50
|
+
? `Coverage graph contains ${nodeCount} node(s)`
|
|
51
|
+
: "Coverage graph is empty even though browser-facing suites were discovered",
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (options.typecheck !== false) {
|
|
56
|
+
try {
|
|
57
|
+
const typecheck = await runTestkitTypecheck({ dir: productDir });
|
|
58
|
+
checks.push({
|
|
59
|
+
code: "typecheck",
|
|
60
|
+
level: "pass",
|
|
61
|
+
message: `Typechecked ${typecheck.results.length} generated program(s)`,
|
|
62
|
+
});
|
|
63
|
+
} catch (error) {
|
|
64
|
+
checks.push({
|
|
65
|
+
code: "typecheck",
|
|
66
|
+
level: "fail",
|
|
67
|
+
message: error?.result?.stderr || error?.result?.stdout || error.message,
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
const failed = checks.some((check) => check.level === "fail");
|
|
73
|
+
return {
|
|
74
|
+
ok: !failed,
|
|
75
|
+
productDir,
|
|
76
|
+
checks,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function findPlaywrightRuntimeImportViolations(productDir) {
|
|
81
|
+
const violations = [];
|
|
82
|
+
for (const absolutePath of collectFiles(productDir)) {
|
|
83
|
+
const sourceText = fs.readFileSync(absolutePath, "utf8");
|
|
84
|
+
const sourceFile = ts.createSourceFile(absolutePath, sourceText, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
85
|
+
|
|
86
|
+
for (const statement of sourceFile.statements) {
|
|
87
|
+
if (!ts.isImportDeclaration(statement)) continue;
|
|
88
|
+
if (!ts.isStringLiteral(statement.moduleSpecifier)) continue;
|
|
89
|
+
if (statement.moduleSpecifier.text !== "@playwright/test") continue;
|
|
90
|
+
const clause = statement.importClause;
|
|
91
|
+
if (clause?.isTypeOnly) continue;
|
|
92
|
+
if (!clause) {
|
|
93
|
+
violations.push(relativeViolation(productDir, absolutePath, sourceFile, statement));
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (clause.name) {
|
|
97
|
+
violations.push(relativeViolation(productDir, absolutePath, sourceFile, statement));
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (!clause.namedBindings) {
|
|
101
|
+
violations.push(relativeViolation(productDir, absolutePath, sourceFile, statement));
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
if (ts.isNamespaceImport(clause.namedBindings)) {
|
|
105
|
+
violations.push(relativeViolation(productDir, absolutePath, sourceFile, statement));
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (clause.namedBindings.elements.some((entry) => !entry.isTypeOnly)) {
|
|
109
|
+
violations.push(relativeViolation(productDir, absolutePath, sourceFile, statement));
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return violations;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function collectFiles(rootDir, out = []) {
|
|
117
|
+
if (!fs.existsSync(rootDir)) return out;
|
|
118
|
+
for (const entry of fs.readdirSync(rootDir, { withFileTypes: true })) {
|
|
119
|
+
const absolutePath = path.join(rootDir, entry.name);
|
|
120
|
+
if (entry.isDirectory()) {
|
|
121
|
+
if (entry.name === "node_modules" || entry.name === ".git" || entry.name === ".testkit") continue;
|
|
122
|
+
collectFiles(absolutePath, out);
|
|
123
|
+
continue;
|
|
124
|
+
}
|
|
125
|
+
if (entry.isFile() && entry.name.endsWith(".pw.testkit.ts")) {
|
|
126
|
+
out.push(absolutePath);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return out.sort((left, right) => left.localeCompare(right));
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function relativeViolation(productDir, absolutePath, sourceFile, statement) {
|
|
133
|
+
const position = sourceFile.getLineAndCharacterOfPosition(statement.getStart(sourceFile));
|
|
134
|
+
return {
|
|
135
|
+
file: path.relative(productDir, absolutePath).split(path.sep).join("/"),
|
|
136
|
+
line: position.line + 1,
|
|
137
|
+
snippet: statement.getText(sourceFile),
|
|
138
|
+
};
|
|
139
|
+
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { spawn } from "child_process";
|
|
4
|
+
import { fileURLToPath } from "url";
|
|
5
|
+
import { loadConfigContext } from "../config/index.mjs";
|
|
6
|
+
import { detectNextApp } from "../config/runtime.mjs";
|
|
7
|
+
|
|
8
|
+
const PACKAGE_ROOT = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..", "..");
|
|
9
|
+
|
|
10
|
+
export async function runTestkitTypecheck(options = {}) {
|
|
11
|
+
const context = await loadConfigContext({ dir: options.dir });
|
|
12
|
+
const productDir = context.productDir;
|
|
13
|
+
const tempDir = path.join(productDir, ".testkit", "_typecheck");
|
|
14
|
+
fs.mkdirSync(tempDir, { recursive: true });
|
|
15
|
+
|
|
16
|
+
const checks = [];
|
|
17
|
+
const rootTsconfig = writeRootTypecheckConfig({
|
|
18
|
+
productDir,
|
|
19
|
+
setupFile: context.setupFile,
|
|
20
|
+
outputDir: tempDir,
|
|
21
|
+
});
|
|
22
|
+
checks.push({
|
|
23
|
+
label: "repo",
|
|
24
|
+
cwd: productDir,
|
|
25
|
+
tsconfigPath: rootTsconfig,
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
for (const config of context.configs) {
|
|
29
|
+
const cwd = config.testkit.local?.cwd;
|
|
30
|
+
if (!cwd) continue;
|
|
31
|
+
const absoluteCwd = path.resolve(productDir, cwd);
|
|
32
|
+
if (!detectNextApp(absoluteCwd)) continue;
|
|
33
|
+
|
|
34
|
+
const serviceTsconfig = writeNextServiceTypecheckConfig({
|
|
35
|
+
productDir,
|
|
36
|
+
cwd,
|
|
37
|
+
outputDir: tempDir,
|
|
38
|
+
serviceName: config.name,
|
|
39
|
+
});
|
|
40
|
+
checks.push({
|
|
41
|
+
label: config.name,
|
|
42
|
+
cwd: productDir,
|
|
43
|
+
tsconfigPath: serviceTsconfig,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const results = [];
|
|
48
|
+
for (const check of checks) {
|
|
49
|
+
const result = await runTscCheck(check);
|
|
50
|
+
results.push(result);
|
|
51
|
+
if (!result.ok) {
|
|
52
|
+
const error = new Error(`testkit typecheck failed for ${check.label}`);
|
|
53
|
+
error.result = result;
|
|
54
|
+
error.results = results;
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return {
|
|
60
|
+
ok: true,
|
|
61
|
+
productDir,
|
|
62
|
+
results,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function writeRootTypecheckConfig({ productDir, setupFile, outputDir }) {
|
|
67
|
+
const tsconfigPath = path.join(outputDir, "repo.tsconfig.json");
|
|
68
|
+
const extendsPath = findExistingTsconfig(productDir) || null;
|
|
69
|
+
const config = {
|
|
70
|
+
...(extendsPath ? { extends: relativeJsonPath(tsconfigPath, extendsPath) } : {}),
|
|
71
|
+
compilerOptions: {
|
|
72
|
+
baseUrl: ".",
|
|
73
|
+
module: "ESNext",
|
|
74
|
+
moduleResolution: "Bundler",
|
|
75
|
+
noEmit: true,
|
|
76
|
+
paths: packageTypePaths(tsconfigPath),
|
|
77
|
+
rootDir: relativeJsonPath(tsconfigPath, productDir),
|
|
78
|
+
target: "ES2022",
|
|
79
|
+
},
|
|
80
|
+
include: [
|
|
81
|
+
setupFile ? relativeJsonPath(tsconfigPath, setupFile) : "testkit.setup.ts",
|
|
82
|
+
"**/*.int.testkit.ts",
|
|
83
|
+
"**/*.e2e.testkit.ts",
|
|
84
|
+
"**/*.scenario.testkit.ts",
|
|
85
|
+
"**/*.dal.testkit.ts",
|
|
86
|
+
"**/*.load.testkit.ts",
|
|
87
|
+
"**/__testkit__/helpers/**/*.ts",
|
|
88
|
+
],
|
|
89
|
+
exclude: ["node_modules", "dist", ".testkit", "**/*.pw.testkit.ts"],
|
|
90
|
+
};
|
|
91
|
+
fs.writeFileSync(tsconfigPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
92
|
+
return tsconfigPath;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function writeNextServiceTypecheckConfig({ productDir, cwd, outputDir, serviceName }) {
|
|
96
|
+
const serviceDir = path.resolve(productDir, cwd);
|
|
97
|
+
const tsconfigPath = path.join(outputDir, `${serviceName}.tsconfig.json`);
|
|
98
|
+
const extendsPath =
|
|
99
|
+
findExistingTsconfig(serviceDir) ||
|
|
100
|
+
findExistingTsconfig(productDir) ||
|
|
101
|
+
null;
|
|
102
|
+
const config = {
|
|
103
|
+
...(extendsPath ? { extends: relativeJsonPath(tsconfigPath, extendsPath) } : {}),
|
|
104
|
+
compilerOptions: {
|
|
105
|
+
baseUrl: ".",
|
|
106
|
+
module: "ESNext",
|
|
107
|
+
moduleResolution: "Bundler",
|
|
108
|
+
noEmit: true,
|
|
109
|
+
paths: packageTypePaths(tsconfigPath),
|
|
110
|
+
target: "ES2022",
|
|
111
|
+
},
|
|
112
|
+
include: [
|
|
113
|
+
serviceExists(serviceDir, "next-env.d.ts") ? relativeJsonPath(tsconfigPath, path.join(serviceDir, "next-env.d.ts")) : undefined,
|
|
114
|
+
relativeGlob(tsconfigPath, serviceDir, "src/**/*.pw.testkit.ts"),
|
|
115
|
+
relativeGlob(tsconfigPath, serviceDir, "tests/**/*.ts"),
|
|
116
|
+
relativeGlob(tsconfigPath, serviceDir, ".next/types/**/*.ts"),
|
|
117
|
+
relativeGlob(tsconfigPath, serviceDir, ".next/dev/types/**/*.ts"),
|
|
118
|
+
relativeGlob(tsconfigPath, serviceDir, ".next-testkit/**/dist/types/**/*.ts"),
|
|
119
|
+
relativeGlob(tsconfigPath, serviceDir, ".next-testkit/**/dist/dev/types/**/*.ts"),
|
|
120
|
+
].filter(Boolean),
|
|
121
|
+
exclude: ["node_modules", ".next/cache", ".next/dev"],
|
|
122
|
+
};
|
|
123
|
+
fs.writeFileSync(tsconfigPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
124
|
+
return tsconfigPath;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function runTscCheck({ label, cwd, tsconfigPath }) {
|
|
128
|
+
const binary = resolveTscBinary(cwd);
|
|
129
|
+
return new Promise((resolve, reject) => {
|
|
130
|
+
const child = spawn(binary, ["--noEmit", "-p", tsconfigPath], {
|
|
131
|
+
cwd,
|
|
132
|
+
env: process.env,
|
|
133
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
134
|
+
});
|
|
135
|
+
let stdout = "";
|
|
136
|
+
let stderr = "";
|
|
137
|
+
child.stdout.on("data", (chunk) => {
|
|
138
|
+
stdout += String(chunk);
|
|
139
|
+
});
|
|
140
|
+
child.stderr.on("data", (chunk) => {
|
|
141
|
+
stderr += String(chunk);
|
|
142
|
+
});
|
|
143
|
+
child.on("error", reject);
|
|
144
|
+
child.on("close", (code) => {
|
|
145
|
+
resolve({
|
|
146
|
+
label,
|
|
147
|
+
tsconfigPath,
|
|
148
|
+
ok: code === 0,
|
|
149
|
+
exitCode: code,
|
|
150
|
+
stdout,
|
|
151
|
+
stderr,
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function resolveTscBinary(productDir) {
|
|
158
|
+
let current = productDir;
|
|
159
|
+
const binaryName = process.platform === "win32" ? "tsc.cmd" : "tsc";
|
|
160
|
+
|
|
161
|
+
while (true) {
|
|
162
|
+
const candidate = path.join(current, "node_modules", ".bin", binaryName);
|
|
163
|
+
if (fs.existsSync(candidate)) {
|
|
164
|
+
return candidate;
|
|
165
|
+
}
|
|
166
|
+
const parent = path.dirname(current);
|
|
167
|
+
if (parent === current) break;
|
|
168
|
+
current = parent;
|
|
169
|
+
}
|
|
170
|
+
const packageCandidate = path.join(PACKAGE_ROOT, "node_modules", ".bin", binaryName);
|
|
171
|
+
if (fs.existsSync(packageCandidate)) {
|
|
172
|
+
return packageCandidate;
|
|
173
|
+
}
|
|
174
|
+
throw new Error(`TypeScript compiler not found from ${productDir} upward`);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function findExistingTsconfig(rootDir) {
|
|
178
|
+
for (const candidate of ["tsconfig.json", "tsconfig.build.json"]) {
|
|
179
|
+
const absolute = path.join(rootDir, candidate);
|
|
180
|
+
if (fs.existsSync(absolute)) return absolute;
|
|
181
|
+
}
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
function relativeJsonPath(fromFile, targetPath) {
|
|
186
|
+
return path.relative(path.dirname(fromFile), targetPath).split(path.sep).join("/");
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
function relativeGlob(fromFile, rootDir, pattern) {
|
|
190
|
+
return path.join(relativeJsonPath(fromFile, rootDir), pattern).split(path.sep).join("/");
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function serviceExists(rootDir, relativePath) {
|
|
194
|
+
return fs.existsSync(path.join(rootDir, relativePath));
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function packageTypePaths(tsconfigPath) {
|
|
198
|
+
return {
|
|
199
|
+
"@elench/testkit": [relativeJsonPath(tsconfigPath, path.join(PACKAGE_ROOT, "lib", "index.d.ts"))],
|
|
200
|
+
"@elench/testkit/setup": [relativeJsonPath(tsconfigPath, path.join(PACKAGE_ROOT, "lib", "setup", "index.d.ts"))],
|
|
201
|
+
"@elench/testkit/runtime": [relativeJsonPath(tsconfigPath, path.join(PACKAGE_ROOT, "lib", "runtime", "index.d.ts"))],
|
|
202
|
+
};
|
|
203
|
+
}
|