codeceptjs 4.0.0-beta.2 → 4.0.0-beta.20
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 +133 -120
- package/bin/codecept.js +107 -96
- package/bin/test-server.js +64 -0
- package/docs/webapi/clearCookie.mustache +1 -1
- package/docs/webapi/click.mustache +5 -1
- package/lib/actor.js +71 -103
- package/lib/ai.js +159 -188
- package/lib/assert/empty.js +22 -24
- package/lib/assert/equal.js +30 -37
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +43 -48
- package/lib/assert/throws.js +11 -11
- package/lib/assert/truth.js +22 -22
- package/lib/assert.js +20 -18
- package/lib/codecept.js +262 -162
- package/lib/colorUtils.js +50 -52
- package/lib/command/check.js +206 -0
- package/lib/command/configMigrate.js +56 -51
- package/lib/command/definitions.js +96 -109
- package/lib/command/dryRun.js +77 -79
- package/lib/command/generate.js +234 -194
- package/lib/command/gherkin/init.js +42 -33
- package/lib/command/gherkin/snippets.js +76 -74
- package/lib/command/gherkin/steps.js +20 -17
- package/lib/command/info.js +74 -38
- package/lib/command/init.js +301 -290
- package/lib/command/interactive.js +41 -32
- package/lib/command/list.js +28 -27
- package/lib/command/run-multiple/chunk.js +51 -48
- package/lib/command/run-multiple/collection.js +5 -5
- package/lib/command/run-multiple/run.js +5 -1
- package/lib/command/run-multiple.js +97 -97
- package/lib/command/run-rerun.js +19 -25
- package/lib/command/run-workers.js +68 -92
- package/lib/command/run.js +39 -27
- package/lib/command/utils.js +80 -64
- package/lib/command/workers/runTests.js +388 -226
- package/lib/config.js +109 -50
- package/lib/container.js +641 -261
- package/lib/data/context.js +60 -61
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +32 -32
- package/lib/data/table.js +22 -22
- package/lib/effects.js +307 -0
- package/lib/element/WebElement.js +327 -0
- package/lib/els.js +160 -0
- package/lib/event.js +173 -163
- package/lib/globals.js +141 -0
- package/lib/heal.js +89 -85
- package/lib/helper/AI.js +131 -41
- package/lib/helper/ApiDataFactory.js +107 -75
- package/lib/helper/Appium.js +542 -404
- package/lib/helper/FileSystem.js +100 -79
- package/lib/helper/GraphQL.js +44 -43
- package/lib/helper/GraphQLDataFactory.js +52 -52
- package/lib/helper/JSONResponse.js +126 -88
- package/lib/helper/Mochawesome.js +54 -29
- package/lib/helper/Playwright.js +2547 -1316
- package/lib/helper/Puppeteer.js +1578 -1181
- package/lib/helper/REST.js +209 -68
- package/lib/helper/WebDriver.js +1482 -1342
- package/lib/helper/errors/ConnectionRefused.js +6 -6
- package/lib/helper/errors/ElementAssertion.js +11 -16
- package/lib/helper/errors/ElementNotFound.js +5 -9
- package/lib/helper/errors/RemoteBrowserConnectionRefused.js +5 -5
- package/lib/helper/extras/Console.js +11 -11
- package/lib/helper/extras/PlaywrightLocator.js +110 -0
- package/lib/helper/extras/PlaywrightPropEngine.js +18 -18
- package/lib/helper/extras/PlaywrightReactVueLocator.js +17 -8
- package/lib/helper/extras/PlaywrightRestartOpts.js +25 -11
- package/lib/helper/extras/Popup.js +22 -22
- package/lib/helper/extras/React.js +27 -28
- package/lib/helper/network/actions.js +36 -42
- package/lib/helper/network/utils.js +78 -84
- package/lib/helper/scripts/blurElement.js +5 -5
- package/lib/helper/scripts/focusElement.js +5 -5
- package/lib/helper/scripts/highlightElement.js +8 -8
- package/lib/helper/scripts/isElementClickable.js +34 -34
- package/lib/helper.js +2 -3
- package/lib/history.js +23 -19
- package/lib/hooks.js +8 -8
- package/lib/html.js +94 -104
- package/lib/index.js +38 -27
- package/lib/listener/config.js +30 -23
- package/lib/listener/emptyRun.js +54 -0
- package/lib/listener/enhancedGlobalRetry.js +110 -0
- package/lib/listener/exit.js +16 -18
- package/lib/listener/globalRetry.js +70 -0
- package/lib/listener/globalTimeout.js +181 -0
- package/lib/listener/helpers.js +76 -51
- package/lib/listener/mocha.js +10 -11
- package/lib/listener/result.js +11 -0
- package/lib/listener/retryEnhancer.js +85 -0
- package/lib/listener/steps.js +71 -59
- package/lib/listener/store.js +20 -0
- package/lib/locator.js +214 -197
- package/lib/mocha/asyncWrapper.js +274 -0
- package/lib/mocha/bdd.js +167 -0
- package/lib/mocha/cli.js +341 -0
- package/lib/mocha/factory.js +163 -0
- package/lib/mocha/featureConfig.js +89 -0
- package/lib/mocha/gherkin.js +231 -0
- package/lib/mocha/hooks.js +121 -0
- package/lib/mocha/index.js +21 -0
- package/lib/mocha/inject.js +46 -0
- package/lib/{interfaces → mocha}/scenarioConfig.js +58 -34
- package/lib/mocha/suite.js +89 -0
- package/lib/mocha/test.js +184 -0
- package/lib/mocha/types.d.ts +42 -0
- package/lib/mocha/ui.js +242 -0
- package/lib/output.js +141 -71
- package/lib/parser.js +47 -44
- package/lib/pause.js +173 -145
- package/lib/plugin/analyze.js +403 -0
- package/lib/plugin/{autoLogin.js → auth.js} +178 -79
- package/lib/plugin/autoDelay.js +36 -40
- package/lib/plugin/coverage.js +131 -78
- package/lib/plugin/customLocator.js +22 -21
- package/lib/plugin/customReporter.js +53 -0
- package/lib/plugin/enhancedRetryFailedStep.js +99 -0
- package/lib/plugin/heal.js +101 -110
- package/lib/plugin/htmlReporter.js +3648 -0
- package/lib/plugin/pageInfo.js +140 -0
- package/lib/plugin/pauseOnFail.js +12 -11
- package/lib/plugin/retryFailedStep.js +82 -47
- package/lib/plugin/screenshotOnFail.js +111 -92
- package/lib/plugin/stepByStepReport.js +159 -101
- package/lib/plugin/stepTimeout.js +20 -25
- package/lib/plugin/subtitles.js +38 -38
- package/lib/recorder.js +193 -130
- package/lib/rerun.js +94 -49
- package/lib/result.js +238 -0
- package/lib/retryCoordinator.js +207 -0
- package/lib/secret.js +20 -18
- package/lib/session.js +95 -89
- package/lib/step/base.js +239 -0
- package/lib/step/comment.js +10 -0
- package/lib/step/config.js +50 -0
- package/lib/step/func.js +46 -0
- package/lib/step/helper.js +50 -0
- package/lib/step/meta.js +99 -0
- package/lib/step/record.js +74 -0
- package/lib/step/retry.js +11 -0
- package/lib/step/section.js +55 -0
- package/lib/step.js +18 -329
- package/lib/steps.js +54 -0
- package/lib/store.js +38 -7
- package/lib/template/heal.js +3 -12
- package/lib/template/prompts/generatePageObject.js +31 -0
- package/lib/template/prompts/healStep.js +13 -0
- package/lib/template/prompts/writeStep.js +9 -0
- package/lib/test-server.js +334 -0
- package/lib/timeout.js +60 -0
- package/lib/transform.js +8 -8
- package/lib/translation.js +34 -21
- package/lib/utils/loaderCheck.js +124 -0
- package/lib/utils/mask_data.js +47 -0
- package/lib/utils/typescript.js +237 -0
- package/lib/utils.js +411 -228
- package/lib/workerStorage.js +37 -34
- package/lib/workers.js +532 -296
- package/package.json +124 -95
- package/translations/de-DE.js +5 -3
- package/translations/fr-FR.js +5 -4
- package/translations/index.js +22 -12
- package/translations/it-IT.js +4 -3
- package/translations/ja-JP.js +4 -3
- package/translations/nl-NL.js +76 -0
- package/translations/pl-PL.js +4 -3
- package/translations/pt-BR.js +4 -3
- package/translations/ru-RU.js +4 -3
- package/translations/utils.js +10 -0
- package/translations/zh-CN.js +4 -3
- package/translations/zh-TW.js +4 -3
- package/typings/index.d.ts +546 -185
- package/typings/promiseBasedTypes.d.ts +150 -875
- package/typings/types.d.ts +547 -992
- package/lib/cli.js +0 -249
- package/lib/dirname.js +0 -5
- package/lib/helper/Expect.js +0 -425
- package/lib/helper/ExpectHelper.js +0 -399
- package/lib/helper/MockServer.js +0 -223
- package/lib/helper/Nightmare.js +0 -1411
- package/lib/helper/Protractor.js +0 -1835
- package/lib/helper/SoftExpectHelper.js +0 -381
- package/lib/helper/TestCafe.js +0 -1410
- package/lib/helper/clientscripts/nightmare.js +0 -213
- package/lib/helper/testcafe/testControllerHolder.js +0 -42
- package/lib/helper/testcafe/testcafe-utils.js +0 -63
- package/lib/interfaces/bdd.js +0 -98
- package/lib/interfaces/featureConfig.js +0 -69
- package/lib/interfaces/gherkin.js +0 -195
- package/lib/listener/artifacts.js +0 -19
- package/lib/listener/retry.js +0 -68
- package/lib/listener/timeout.js +0 -109
- package/lib/mochaFactory.js +0 -110
- package/lib/plugin/allure.js +0 -15
- package/lib/plugin/commentStep.js +0 -136
- package/lib/plugin/debugErrors.js +0 -67
- package/lib/plugin/eachElement.js +0 -127
- package/lib/plugin/fakerTransform.js +0 -49
- package/lib/plugin/retryTo.js +0 -121
- package/lib/plugin/selenoid.js +0 -371
- package/lib/plugin/standardActingHelpers.js +0 -9
- package/lib/plugin/tryTo.js +0 -105
- package/lib/plugin/wdio.js +0 -246
- package/lib/scenario.js +0 -222
- package/lib/ui.js +0 -238
- package/lib/within.js +0 -70
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Utilities for checking TypeScript loader availability
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Check if a TypeScript loader is available for test files
|
|
7
|
+
* Note: This checks if loaders are in the require array, not if packages are installed
|
|
8
|
+
* Package installation is checked when actually requiring modules
|
|
9
|
+
* @param {string[]} requiredModules - Array of required modules from config
|
|
10
|
+
* @returns {boolean}
|
|
11
|
+
*/
|
|
12
|
+
export function checkTypeScriptLoader(requiredModules = []) {
|
|
13
|
+
// Check if a loader is configured in the require array
|
|
14
|
+
return (
|
|
15
|
+
requiredModules.includes('tsx/esm') ||
|
|
16
|
+
requiredModules.includes('tsx/cjs') ||
|
|
17
|
+
requiredModules.includes('tsx') ||
|
|
18
|
+
requiredModules.includes('ts-node/esm') ||
|
|
19
|
+
requiredModules.includes('ts-node/register') ||
|
|
20
|
+
requiredModules.includes('ts-node')
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Generate helpful error message if .ts tests found but no loader configured
|
|
26
|
+
* @param {string[]} testFiles - Array of test file paths
|
|
27
|
+
* @returns {string|null} Error message or null if no TypeScript files
|
|
28
|
+
*/
|
|
29
|
+
export function getTypeScriptLoaderError(testFiles) {
|
|
30
|
+
const tsFiles = testFiles.filter(f => f.endsWith('.ts'))
|
|
31
|
+
|
|
32
|
+
if (tsFiles.length === 0) return null
|
|
33
|
+
|
|
34
|
+
return `
|
|
35
|
+
╔═════════════════════════════════════════════════════════════════════════════╗
|
|
36
|
+
║ ║
|
|
37
|
+
║ ⚠️ TypeScript Test Files Detected but No Loader Configured ║
|
|
38
|
+
║ ║
|
|
39
|
+
╚═════════════════════════════════════════════════════════════════════════════╝
|
|
40
|
+
|
|
41
|
+
Found ${tsFiles.length} TypeScript test file(s) but no TypeScript loader is configured.
|
|
42
|
+
|
|
43
|
+
CodeceptJS 4.x uses ES Modules (ESM) and requires a loader to run TypeScript tests.
|
|
44
|
+
|
|
45
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
46
|
+
│ Option 1: tsx (Recommended - Fast, Zero Config) │
|
|
47
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
48
|
+
|
|
49
|
+
Installation:
|
|
50
|
+
npm install --save-dev tsx
|
|
51
|
+
|
|
52
|
+
Configuration:
|
|
53
|
+
Add to your codecept.conf.ts or codecept.conf.js:
|
|
54
|
+
|
|
55
|
+
export const config = {
|
|
56
|
+
tests: './**/*_test.ts',
|
|
57
|
+
require: ['tsx/cjs'], // ← Add this line
|
|
58
|
+
helpers: { /* ... */ }
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
Why tsx?
|
|
62
|
+
⚡ Fast: Built on esbuild
|
|
63
|
+
🎯 Zero config: No tsconfig.json required
|
|
64
|
+
✅ Works with Mocha: Uses CommonJS hooks
|
|
65
|
+
✅ Complete: Handles all TypeScript features
|
|
66
|
+
|
|
67
|
+
┌─────────────────────────────────────────────────────────────────────────────┐
|
|
68
|
+
│ Option 2: ts-node/esm (Alternative - Established, Requires Config) │
|
|
69
|
+
└─────────────────────────────────────────────────────────────────────────────┘
|
|
70
|
+
|
|
71
|
+
Installation:
|
|
72
|
+
npm install --save-dev ts-node
|
|
73
|
+
|
|
74
|
+
Configuration:
|
|
75
|
+
1. Add to your codecept.conf.ts:
|
|
76
|
+
require: ['ts-node/esm']
|
|
77
|
+
|
|
78
|
+
2. Create tsconfig.json:
|
|
79
|
+
{
|
|
80
|
+
"compilerOptions": {
|
|
81
|
+
"module": "ESNext",
|
|
82
|
+
"target": "ES2022",
|
|
83
|
+
"moduleResolution": "node",
|
|
84
|
+
"esModuleInterop": true
|
|
85
|
+
},
|
|
86
|
+
"ts-node": {
|
|
87
|
+
"esm": true,
|
|
88
|
+
"experimentalSpecifierResolution": "node"
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
📚 Documentation: https://codecept.io/typescript
|
|
93
|
+
|
|
94
|
+
Note: TypeScript config files (codecept.conf.ts) and helpers are automatically
|
|
95
|
+
transpiled. Only test files require a loader to be configured.
|
|
96
|
+
`
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Check if user is trying to run TypeScript tests without proper loader
|
|
101
|
+
* @param {string[]} testFiles - Array of test file paths
|
|
102
|
+
* @param {string[]} requiredModules - Array of required modules from config
|
|
103
|
+
* @returns {{hasError: boolean, message: string|null}}
|
|
104
|
+
*/
|
|
105
|
+
export function validateTypeScriptSetup(testFiles, requiredModules = []) {
|
|
106
|
+
const tsFiles = testFiles.filter(f => f.endsWith('.ts'))
|
|
107
|
+
|
|
108
|
+
if (tsFiles.length === 0) {
|
|
109
|
+
// No TypeScript test files, all good
|
|
110
|
+
return { hasError: false, message: null }
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Check if a loader is configured in the require array
|
|
114
|
+
const hasLoader = checkTypeScriptLoader(requiredModules)
|
|
115
|
+
|
|
116
|
+
if (hasLoader) {
|
|
117
|
+
// Loader configured, all good (package will be checked when requireModules runs)
|
|
118
|
+
return { hasError: false, message: null }
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// No loader configured and TypeScript tests exist
|
|
122
|
+
const message = getTypeScriptLoaderError(testFiles)
|
|
123
|
+
return { hasError: true, message }
|
|
124
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { maskSensitiveData } from 'invisi-data'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Mask sensitive data utility for CodeceptJS
|
|
5
|
+
* Supports both boolean and object configuration formats
|
|
6
|
+
*
|
|
7
|
+
* @param {string} input - The string to mask
|
|
8
|
+
* @param {boolean|object} config - Masking configuration
|
|
9
|
+
* @returns {string} - Masked string
|
|
10
|
+
*/
|
|
11
|
+
export function maskData(input, config) {
|
|
12
|
+
if (!config) {
|
|
13
|
+
return input
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// Handle boolean config (backward compatibility)
|
|
17
|
+
if (typeof config === 'boolean' && config === true) {
|
|
18
|
+
return maskSensitiveData(input)
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
// Handle object config with custom patterns
|
|
22
|
+
if (typeof config === 'object' && config.enabled === true) {
|
|
23
|
+
const customPatterns = config.patterns || []
|
|
24
|
+
return maskSensitiveData(input, customPatterns)
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return input
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Check if masking is enabled based on global configuration
|
|
32
|
+
*
|
|
33
|
+
* @returns {boolean|object} - Current masking configuration
|
|
34
|
+
*/
|
|
35
|
+
export function getMaskConfig() {
|
|
36
|
+
return global.maskSensitiveData || false
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Check if data should be masked
|
|
41
|
+
*
|
|
42
|
+
* @returns {boolean} - True if masking is enabled
|
|
43
|
+
*/
|
|
44
|
+
export function shouldMaskData() {
|
|
45
|
+
const config = getMaskConfig()
|
|
46
|
+
return config === true || (typeof config === 'object' && config.enabled === true)
|
|
47
|
+
}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import path from 'path'
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Transpile TypeScript files to ES modules with CommonJS shim support
|
|
6
|
+
* Handles recursive transpilation of imported TypeScript files
|
|
7
|
+
*
|
|
8
|
+
* @param {string} mainFilePath - Path to the main TypeScript file to transpile
|
|
9
|
+
* @param {object} typescript - TypeScript compiler instance
|
|
10
|
+
* @returns {Promise<{tempFile: string, allTempFiles: string[]}>} - Main temp file and all temp files created
|
|
11
|
+
*/
|
|
12
|
+
export async function transpileTypeScript(mainFilePath, typescript) {
|
|
13
|
+
const { transpile } = typescript
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Transpile a single TypeScript file to JavaScript
|
|
17
|
+
* Injects CommonJS shims (require, module, exports, __dirname, __filename) as needed
|
|
18
|
+
*/
|
|
19
|
+
const transpileTS = (filePath) => {
|
|
20
|
+
const tsContent = fs.readFileSync(filePath, 'utf8')
|
|
21
|
+
|
|
22
|
+
// Transpile TypeScript to JavaScript with ES module output
|
|
23
|
+
let jsContent = transpile(tsContent, {
|
|
24
|
+
module: 99, // ModuleKind.ESNext
|
|
25
|
+
target: 99, // ScriptTarget.ESNext
|
|
26
|
+
esModuleInterop: true,
|
|
27
|
+
allowSyntheticDefaultImports: true,
|
|
28
|
+
lib: ['lib.esnext.d.ts'], // Enable latest features including top-level await
|
|
29
|
+
suppressOutputPathCheck: true,
|
|
30
|
+
skipLibCheck: true,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
// Check if the code uses CommonJS globals
|
|
34
|
+
const usesCommonJSGlobals = /__dirname|__filename/.test(jsContent)
|
|
35
|
+
const usesRequire = /\brequire\s*\(/.test(jsContent)
|
|
36
|
+
const usesModuleExports = /\b(module\.exports|exports\.)/.test(jsContent)
|
|
37
|
+
|
|
38
|
+
if (usesCommonJSGlobals || usesRequire || usesModuleExports) {
|
|
39
|
+
// Inject ESM equivalents at the top of the file
|
|
40
|
+
let esmGlobals = ''
|
|
41
|
+
|
|
42
|
+
if (usesRequire || usesModuleExports) {
|
|
43
|
+
// IMPORTANT: Use the original .ts file path as the base for require()
|
|
44
|
+
// This ensures dynamic require() calls work with relative paths from the original file location
|
|
45
|
+
const originalFileUrl = `file://${filePath.replace(/\\/g, '/')}`
|
|
46
|
+
esmGlobals += `import { createRequire } from 'module';
|
|
47
|
+
import { extname as __extname } from 'path';
|
|
48
|
+
const __baseRequire = createRequire('${originalFileUrl}');
|
|
49
|
+
|
|
50
|
+
// Wrap require to auto-resolve extensions (mimics CommonJS behavior)
|
|
51
|
+
const require = (id) => {
|
|
52
|
+
try {
|
|
53
|
+
return __baseRequire(id);
|
|
54
|
+
} catch (err) {
|
|
55
|
+
// If module not found and it's a relative/absolute path without extension, try common extensions
|
|
56
|
+
if (err.code === 'MODULE_NOT_FOUND' && (id.startsWith('./') || id.startsWith('../') || id.startsWith('/'))) {
|
|
57
|
+
const ext = __extname(id);
|
|
58
|
+
// Only treat known file extensions as real extensions (so names like .TEST don't block probing)
|
|
59
|
+
const __knownExts = ['.js', '.cjs', '.mjs', '.json', '.node'];
|
|
60
|
+
const hasKnownExt = ext && __knownExts.includes(ext.toLowerCase());
|
|
61
|
+
if (!hasKnownExt) {
|
|
62
|
+
// Try common extensions in order: .js, .cjs, .json, .node
|
|
63
|
+
// Note: .ts files cannot be required - they need transpilation first
|
|
64
|
+
const extensions = ['.js', '.cjs', '.json', '.node'];
|
|
65
|
+
for (const testExt of extensions) {
|
|
66
|
+
try {
|
|
67
|
+
return __baseRequire(id + testExt);
|
|
68
|
+
} catch (e) {
|
|
69
|
+
// Continue to next extension
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Re-throw original error if all attempts failed
|
|
75
|
+
throw err;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const module = { exports: {} };
|
|
80
|
+
const exports = module.exports;
|
|
81
|
+
|
|
82
|
+
`
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (usesCommonJSGlobals) {
|
|
86
|
+
// For __dirname and __filename, also use the original file path
|
|
87
|
+
const originalFileUrl = `file://${filePath.replace(/\\/g, '/')}`
|
|
88
|
+
esmGlobals += `import { fileURLToPath as __fileURLToPath } from 'url';
|
|
89
|
+
import { dirname as __dirname_fn } from 'path';
|
|
90
|
+
const __filename = '${filePath.replace(/\\/g, '/')}';
|
|
91
|
+
const __dirname = __dirname_fn(__filename);
|
|
92
|
+
|
|
93
|
+
`
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
jsContent = esmGlobals + jsContent
|
|
97
|
+
|
|
98
|
+
// If module.exports is used, we need to export it as default
|
|
99
|
+
if (usesModuleExports) {
|
|
100
|
+
jsContent += `\nexport default module.exports;\n`
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return jsContent
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Create a map to track transpiled files
|
|
108
|
+
const transpiledFiles = new Map()
|
|
109
|
+
const baseDir = path.dirname(mainFilePath)
|
|
110
|
+
|
|
111
|
+
// Recursive function to transpile a file and all its TypeScript dependencies
|
|
112
|
+
const transpileFileAndDeps = (filePath) => {
|
|
113
|
+
// Already transpiled, skip
|
|
114
|
+
if (transpiledFiles.has(filePath)) {
|
|
115
|
+
return
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Transpile this file
|
|
119
|
+
let jsContent = transpileTS(filePath)
|
|
120
|
+
|
|
121
|
+
// Find all relative TypeScript imports in this file
|
|
122
|
+
const importRegex = /from\s+['"](\..+?)(?:\.ts)?['"]/g
|
|
123
|
+
let match
|
|
124
|
+
const imports = []
|
|
125
|
+
|
|
126
|
+
while ((match = importRegex.exec(jsContent)) !== null) {
|
|
127
|
+
imports.push(match[1])
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Get the base directory for this file
|
|
131
|
+
const fileBaseDir = path.dirname(filePath)
|
|
132
|
+
|
|
133
|
+
// Recursively transpile each imported TypeScript file
|
|
134
|
+
for (const relativeImport of imports) {
|
|
135
|
+
let importedPath = path.resolve(fileBaseDir, relativeImport)
|
|
136
|
+
|
|
137
|
+
// Handle .js extensions that might actually be .ts files
|
|
138
|
+
if (importedPath.endsWith('.js')) {
|
|
139
|
+
const tsVersion = importedPath.replace(/\.js$/, '.ts')
|
|
140
|
+
if (fs.existsSync(tsVersion)) {
|
|
141
|
+
importedPath = tsVersion
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Try adding .ts extension if file doesn't exist and no extension provided
|
|
146
|
+
if (!path.extname(importedPath)) {
|
|
147
|
+
const tsPath = importedPath + '.ts'
|
|
148
|
+
if (fs.existsSync(tsPath)) {
|
|
149
|
+
importedPath = tsPath
|
|
150
|
+
} else {
|
|
151
|
+
// Try .js extension as well
|
|
152
|
+
const jsPath = importedPath + '.js'
|
|
153
|
+
if (fs.existsSync(jsPath)) {
|
|
154
|
+
// Skip .js files, they don't need transpilation
|
|
155
|
+
continue
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// If it's a TypeScript file, recursively transpile it and its dependencies
|
|
161
|
+
if (importedPath.endsWith('.ts') && fs.existsSync(importedPath)) {
|
|
162
|
+
transpileFileAndDeps(importedPath)
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// After all dependencies are transpiled, rewrite imports in this file
|
|
167
|
+
jsContent = jsContent.replace(
|
|
168
|
+
/from\s+['"](\..+?)(?:\.ts)?['"]/g,
|
|
169
|
+
(match, importPath) => {
|
|
170
|
+
let resolvedPath = path.resolve(fileBaseDir, importPath)
|
|
171
|
+
|
|
172
|
+
// Handle .js extension that might be .ts
|
|
173
|
+
if (resolvedPath.endsWith('.js')) {
|
|
174
|
+
const tsVersion = resolvedPath.replace(/\.js$/, '.ts')
|
|
175
|
+
if (transpiledFiles.has(tsVersion)) {
|
|
176
|
+
const tempFile = transpiledFiles.get(tsVersion)
|
|
177
|
+
const relPath = path.relative(fileBaseDir, tempFile).replace(/\\/g, '/')
|
|
178
|
+
// Ensure the path starts with ./
|
|
179
|
+
if (!relPath.startsWith('.')) {
|
|
180
|
+
return `from './${relPath}'`
|
|
181
|
+
}
|
|
182
|
+
return `from '${relPath}'`
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Try with .ts extension
|
|
187
|
+
const tsPath = resolvedPath.endsWith('.ts') ? resolvedPath : resolvedPath + '.ts'
|
|
188
|
+
|
|
189
|
+
// If we transpiled this file, use the temp file
|
|
190
|
+
if (transpiledFiles.has(tsPath)) {
|
|
191
|
+
const tempFile = transpiledFiles.get(tsPath)
|
|
192
|
+
const relPath = path.relative(fileBaseDir, tempFile).replace(/\\/g, '/')
|
|
193
|
+
// Ensure the path starts with ./
|
|
194
|
+
if (!relPath.startsWith('.')) {
|
|
195
|
+
return `from './${relPath}'`
|
|
196
|
+
}
|
|
197
|
+
return `from '${relPath}'`
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Otherwise, keep the import as-is
|
|
201
|
+
return match
|
|
202
|
+
}
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
// Write the transpiled file with updated imports
|
|
206
|
+
const tempFile = filePath.replace(/\.ts$/, '.temp.mjs')
|
|
207
|
+
fs.writeFileSync(tempFile, jsContent)
|
|
208
|
+
transpiledFiles.set(filePath, tempFile)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// Start recursive transpilation from the main file
|
|
212
|
+
transpileFileAndDeps(mainFilePath)
|
|
213
|
+
|
|
214
|
+
// Get the main transpiled file
|
|
215
|
+
const tempJsFile = transpiledFiles.get(mainFilePath)
|
|
216
|
+
|
|
217
|
+
// Store all temp files for cleanup
|
|
218
|
+
const allTempFiles = Array.from(transpiledFiles.values())
|
|
219
|
+
|
|
220
|
+
return { tempFile: tempJsFile, allTempFiles }
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Clean up temporary transpiled files
|
|
225
|
+
* @param {string[]} tempFiles - Array of temp file paths to delete
|
|
226
|
+
*/
|
|
227
|
+
export function cleanupTempFiles(tempFiles) {
|
|
228
|
+
for (const file of tempFiles) {
|
|
229
|
+
if (fs.existsSync(file)) {
|
|
230
|
+
try {
|
|
231
|
+
fs.unlinkSync(file)
|
|
232
|
+
} catch (err) {
|
|
233
|
+
// Ignore cleanup errors
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|