@codemoreira/esad 1.4.6 → 2.0.0-rc.1
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/package.json +1 -1
- package/src/cli/commands/build.js +18 -16
- package/src/cli/commands/createModule.js +5 -2
- package/src/cli/commands/deploy.js +35 -67
- package/src/cli/commands/dev.js +30 -49
- package/src/cli/commands/init.js +33 -14
- package/src/cli/utils/config.js +33 -4
- package/src/cli/utils/transformer.js +44 -0
package/package.json
CHANGED
|
@@ -3,40 +3,41 @@ const path = require('path');
|
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
4
|
const chalk = require('chalk');
|
|
5
5
|
const { getWorkspaceConfig } = require('../utils/config');
|
|
6
|
-
const { resolveProjectDir
|
|
6
|
+
const { resolveProjectDir } = require('../utils/resolution');
|
|
7
|
+
const { clearAllDevMode } = require('../utils/transformer');
|
|
7
8
|
|
|
8
9
|
module.exports = async (options) => {
|
|
9
|
-
let cwd = process.cwd();
|
|
10
|
-
|
|
11
|
-
// Enforce Workspace Root
|
|
12
10
|
const configObj = getWorkspaceConfig();
|
|
13
11
|
if (!configObj) {
|
|
14
|
-
console.error(chalk.red(`❌ Error:
|
|
12
|
+
console.error(chalk.red(`❌ Error: esad.config.js not found.`));
|
|
15
13
|
process.exit(1);
|
|
16
14
|
}
|
|
17
15
|
|
|
18
|
-
const
|
|
16
|
+
const config = await configObj.load();
|
|
17
|
+
const workspaceRoot = configObj.root;
|
|
18
|
+
const projectName = config.default?.projectName || config.projectName;
|
|
19
|
+
|
|
20
|
+
let cwd = process.cwd();
|
|
19
21
|
|
|
20
22
|
if (options.id) {
|
|
21
23
|
const targetDir = resolveProjectDir(options.id, configObj);
|
|
22
24
|
if (!targetDir) {
|
|
23
|
-
console.error(chalk.red(
|
|
24
|
-
listAvailableModules(configObj);
|
|
25
|
+
console.error(chalk.red(`❌ Error: Module not found: ${options.id}`));
|
|
25
26
|
process.exit(1);
|
|
26
27
|
}
|
|
27
28
|
cwd = targetDir;
|
|
28
|
-
} else {
|
|
29
|
-
// Build host by default if in root
|
|
30
|
-
const hostDir = path.join(path.dirname(configObj.path), `${projectName}-host`);
|
|
31
|
-
if (fs.existsSync(hostDir)) cwd = hostDir;
|
|
32
29
|
}
|
|
33
30
|
|
|
34
31
|
const platform = options.platform || 'android';
|
|
35
32
|
|
|
36
|
-
console.log(`\n🏗️ Building production bundle for ${path.basename(cwd)} (${platform})...\n`);
|
|
33
|
+
console.log(`\n🏗️ Building production bundle for ${chalk.cyan(path.basename(cwd))} (${platform})...\n`);
|
|
37
34
|
|
|
35
|
+
// 1. CLEANUP CONFIG (Avoid shipping local dev URLs)
|
|
36
|
+
console.log(chalk.gray(`🧹 Cleaning up devMode mappings in esad.config.js...`));
|
|
37
|
+
clearAllDevMode(configObj.path);
|
|
38
|
+
|
|
38
39
|
try {
|
|
39
|
-
const bundleOutput = path.join(cwd, 'build',
|
|
40
|
+
const bundleOutput = path.join(cwd, 'build', 'index.bundle'); // Simplified path as per V2
|
|
40
41
|
fs.ensureDirSync(path.dirname(bundleOutput));
|
|
41
42
|
|
|
42
43
|
// Run Re.Pack production build
|
|
@@ -47,12 +48,13 @@ module.exports = async (options) => {
|
|
|
47
48
|
'--dev', 'false',
|
|
48
49
|
'--bundle-output', bundleOutput,
|
|
49
50
|
'--assets-dest', path.dirname(bundleOutput)
|
|
50
|
-
], cwd);
|
|
51
|
+
], { cwd });
|
|
51
52
|
|
|
52
53
|
console.log(chalk.green(`\n✅ Build complete! Assets generated in build/ directory.`));
|
|
53
|
-
console.log(`👉
|
|
54
|
+
console.log(`👉 Next step: 'esad deploy ${options.id || ''}'\n`);
|
|
54
55
|
} catch (err) {
|
|
55
56
|
console.error(chalk.red(`\n❌ Build failed: ${err.message}`));
|
|
56
57
|
process.exit(1);
|
|
57
58
|
}
|
|
58
59
|
};
|
|
60
|
+
|
|
@@ -8,12 +8,15 @@ const templatesConfig = require('../templates/templates.json');
|
|
|
8
8
|
module.exports = async (moduleName) => {
|
|
9
9
|
const configObj = getWorkspaceConfig();
|
|
10
10
|
if (!configObj) {
|
|
11
|
-
console.error(`❌ Error: Call this command from inside an ESAD workspace (esad.config.
|
|
11
|
+
console.error(`❌ Error: Call this command from inside an ESAD workspace (esad.config.js not found).`);
|
|
12
12
|
return;
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
const
|
|
15
|
+
const config = await configObj.load();
|
|
16
|
+
const projectName = config.default?.projectName || config.projectName;
|
|
17
|
+
|
|
16
18
|
const isPrefixed = moduleName.startsWith(`${projectName}-`);
|
|
19
|
+
|
|
17
20
|
const finalModuleName = isPrefixed ? moduleName : `${projectName}-${moduleName}`;
|
|
18
21
|
|
|
19
22
|
const workspaceDir = path.dirname(configObj.path);
|
|
@@ -3,110 +3,78 @@ const path = require('path');
|
|
|
3
3
|
const AdmZip = require('adm-zip');
|
|
4
4
|
const chalk = require('chalk');
|
|
5
5
|
const { getWorkspaceConfig } = require('../utils/config');
|
|
6
|
-
const { resolveModuleMetadata
|
|
6
|
+
const { resolveModuleMetadata } = require('../utils/resolution');
|
|
7
7
|
|
|
8
8
|
module.exports = async (options) => {
|
|
9
|
-
let cwd = process.cwd();
|
|
10
|
-
let pkgPath = path.join(cwd, 'package.json');
|
|
11
|
-
|
|
12
|
-
// Enforce Workspace Root
|
|
13
9
|
const configObj = getWorkspaceConfig();
|
|
14
10
|
if (!configObj) {
|
|
15
|
-
console.error(chalk.red(`❌ Error:
|
|
11
|
+
console.error(chalk.red(`❌ Error: esad.config.js not found in this or parent directories.`));
|
|
16
12
|
process.exit(1);
|
|
17
13
|
}
|
|
18
14
|
|
|
19
|
-
const
|
|
20
|
-
const
|
|
15
|
+
const config = await configObj.load();
|
|
16
|
+
const workspaceRoot = configObj.root;
|
|
17
|
+
const projectName = config.default?.projectName || config.projectName;
|
|
21
18
|
|
|
22
19
|
let moduleId = options.id;
|
|
23
|
-
|
|
20
|
+
let cwd = process.cwd();
|
|
21
|
+
|
|
22
|
+
// Resolve Context
|
|
24
23
|
if (moduleId) {
|
|
25
24
|
const meta = resolveModuleMetadata(moduleId, configObj);
|
|
26
25
|
if (!meta) {
|
|
27
|
-
console.error(chalk.red(
|
|
28
|
-
listAvailableModules(configObj);
|
|
26
|
+
console.error(chalk.red(`❌ Error: Module not found: ${moduleId}`));
|
|
29
27
|
process.exit(1);
|
|
30
28
|
}
|
|
31
29
|
cwd = meta.path;
|
|
32
|
-
moduleId = meta.id; // Correct fully qualified ID
|
|
33
|
-
pkgPath = path.join(cwd, 'package.json');
|
|
34
|
-
console.log(`📂 Module detected for Deploy: ${path.basename(cwd)}`);
|
|
35
|
-
} else {
|
|
36
|
-
// Target host by default if in root
|
|
37
|
-
const hostDir = path.join(workspaceRoot, `${projectName}-host`);
|
|
38
|
-
if (fs.existsSync(hostDir)) {
|
|
39
|
-
cwd = hostDir;
|
|
40
|
-
pkgPath = path.join(cwd, 'package.json');
|
|
41
|
-
console.log(chalk.green(`📂 Host detected for Deploy: ${path.basename(cwd)}`));
|
|
42
|
-
}
|
|
43
30
|
}
|
|
44
31
|
|
|
32
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
45
33
|
if (!fs.existsSync(pkgPath)) {
|
|
46
34
|
console.error(chalk.red(`❌ Error: package.json not found in ${cwd}.`));
|
|
47
35
|
process.exit(1);
|
|
48
36
|
}
|
|
49
37
|
|
|
50
38
|
const pkg = fs.readJsonSync(pkgPath);
|
|
51
|
-
|
|
39
|
+
const resolvedModuleId = moduleId || pkg.name;
|
|
52
40
|
const version = options.version || pkg.version;
|
|
53
|
-
const entry = options.entry || 'index.bundle';
|
|
54
41
|
|
|
55
|
-
console.log(`\n
|
|
56
|
-
|
|
57
|
-
const config = configObj ? configObj.data : null;
|
|
58
|
-
if (!config?.deployEndpoint) {
|
|
59
|
-
console.error(`❌ Error: 'deployEndpoint' not configured in esad.config.json.`);
|
|
60
|
-
process.exit(1);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const deployUrl = config.deployEndpoint.replace('{{moduleId}}', moduleId);
|
|
64
|
-
console.log(`📡 Deployment Endpoint Resolved: ${deployUrl}`);
|
|
65
|
-
|
|
42
|
+
console.log(`\n🚀 Starting ESAD Deploy for ${chalk.cyan(resolvedModuleId)} (v${version})\n`);
|
|
43
|
+
|
|
66
44
|
const distPath = path.join(cwd, 'build');
|
|
67
45
|
if (!fs.existsSync(distPath)) {
|
|
68
|
-
console.error(`❌ Error: build/ directory not found
|
|
46
|
+
console.error(chalk.red(`❌ Error: build/ directory not found. Please run 'esad build' first.`));
|
|
69
47
|
process.exit(1);
|
|
70
48
|
}
|
|
71
49
|
|
|
50
|
+
// ZIP BUNDLE
|
|
72
51
|
const zip = new AdmZip();
|
|
73
52
|
zip.addLocalFolder(distPath);
|
|
53
|
+
const buffer = zip.toBuffer();
|
|
74
54
|
|
|
75
|
-
|
|
76
|
-
zip.writeZip(zipPath);
|
|
77
|
-
console.log(`🗜️ Zipped output to ${zipPath}`);
|
|
55
|
+
console.log(`🗜️ Generated bundle zip (${(buffer.length / 1024).toFixed(2)} KB)`);
|
|
78
56
|
|
|
79
|
-
|
|
57
|
+
// RUN DEPLOY HOOK
|
|
58
|
+
const deployHook = config.default?.deploy || config.deploy;
|
|
80
59
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
form.append('bundle', fs.createReadStream(zipPath));
|
|
86
|
-
|
|
87
|
-
const fetch = (...args) => import('node-fetch').then(({default: fetch}) => fetch(...args));
|
|
88
|
-
|
|
89
|
-
// Simple CDN expects POST /api/admin/assets/:id/versions
|
|
90
|
-
const uploadUrl = deployUrl.includes('/versions') ? deployUrl : `${deployUrl}/versions`;
|
|
60
|
+
if (typeof deployHook !== 'function') {
|
|
61
|
+
console.error(chalk.red(`❌ Error: 'deploy' function not found in esad.config.js.`));
|
|
62
|
+
process.exit(1);
|
|
63
|
+
}
|
|
91
64
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
65
|
+
try {
|
|
66
|
+
console.log(`📡 Invoking custom 'deploy' hook...`);
|
|
67
|
+
const result = await deployHook(buffer, {
|
|
68
|
+
version,
|
|
69
|
+
moduleId: resolvedModuleId,
|
|
70
|
+
options
|
|
96
71
|
});
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
console.log(chalk.green(`✅ Successfully uploaded ${moduleId} v${version} to CDN!`));
|
|
101
|
-
console.log(`📄 Active Version is now: ${result.active_version}`);
|
|
102
|
-
} else {
|
|
103
|
-
const errorText = await response.text();
|
|
104
|
-
console.error(chalk.red(`❌ Failed to upload: ${response.status} ${response.statusText}`));
|
|
105
|
-
console.error(errorText);
|
|
106
|
-
}
|
|
72
|
+
|
|
73
|
+
console.log(chalk.green(`\n✅ Deployment successful!`));
|
|
74
|
+
if (result) console.log(JSON.stringify(result, null, 2));
|
|
107
75
|
} catch (err) {
|
|
108
|
-
console.error(chalk.red(
|
|
109
|
-
|
|
110
|
-
fs.unlinkSync(zipPath);
|
|
76
|
+
console.error(chalk.red(`\n❌ Deployment failed: ${err.message}`));
|
|
77
|
+
process.exit(1);
|
|
111
78
|
}
|
|
112
79
|
};
|
|
80
|
+
|
package/src/cli/commands/dev.js
CHANGED
|
@@ -1,89 +1,70 @@
|
|
|
1
|
-
const {
|
|
1
|
+
const { runProcess } = require('../utils/process');
|
|
2
2
|
const { getWorkspaceConfig } = require('../utils/config');
|
|
3
3
|
const fs = require('fs-extra');
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const chalk = require('chalk');
|
|
6
6
|
const { prepareNative } = require('../utils/scaffold');
|
|
7
|
-
const { resolveProjectDir
|
|
7
|
+
const { resolveProjectDir } = require('../utils/resolution');
|
|
8
8
|
|
|
9
9
|
module.exports = async (options) => {
|
|
10
|
-
let cwd = process.cwd();
|
|
11
|
-
let pkgPath = path.join(cwd, 'package.json');
|
|
12
|
-
|
|
13
|
-
// Enforce Workspace Root
|
|
14
10
|
const configObj = getWorkspaceConfig();
|
|
15
11
|
if (!configObj) {
|
|
16
|
-
console.error(chalk.red(`❌ Error:
|
|
12
|
+
console.error(chalk.red(`❌ Error: esad.config.js not found. Run this from your project root.`));
|
|
17
13
|
process.exit(1);
|
|
18
14
|
}
|
|
19
15
|
|
|
20
|
-
const
|
|
21
|
-
const
|
|
16
|
+
const config = await configObj.load();
|
|
17
|
+
const workspaceRoot = configObj.root;
|
|
18
|
+
const projectName = config.default?.projectName || config.projectName;
|
|
22
19
|
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
let cwd = process.cwd();
|
|
21
|
+
let selectedModuleId = options.id;
|
|
22
|
+
|
|
23
|
+
if (selectedModuleId) {
|
|
24
|
+
const targetDir = resolveProjectDir(selectedModuleId, configObj);
|
|
25
25
|
if (!targetDir) {
|
|
26
|
-
console.error(chalk.red(
|
|
27
|
-
listAvailableModules(configObj);
|
|
26
|
+
console.error(chalk.red(`❌ Error: Module not found: ${selectedModuleId}`));
|
|
28
27
|
process.exit(1);
|
|
29
28
|
}
|
|
30
29
|
cwd = targetDir;
|
|
31
|
-
pkgPath = path.join(cwd, 'package.json');
|
|
32
|
-
console.log(chalk.green(`📂 Module detected: ${path.relative(workspaceRoot, cwd)}`));
|
|
33
|
-
} else {
|
|
34
|
-
// Target host by default if in root
|
|
35
|
-
const hostDir = path.join(workspaceRoot, `${projectName}-host`);
|
|
36
|
-
if (fs.existsSync(hostDir)) {
|
|
37
|
-
cwd = hostDir;
|
|
38
|
-
pkgPath = path.join(cwd, 'package.json');
|
|
39
|
-
console.log(chalk.green(`📂 Host detected: ${path.relative(workspaceRoot, cwd)}`));
|
|
40
|
-
}
|
|
41
30
|
}
|
|
42
31
|
|
|
32
|
+
const pkgPath = path.join(cwd, 'package.json');
|
|
43
33
|
const pkg = fs.readJsonSync(pkgPath);
|
|
44
|
-
const moduleId =
|
|
34
|
+
const moduleId = selectedModuleId || pkg.name;
|
|
45
35
|
const port = options.port || '8081';
|
|
46
36
|
|
|
47
37
|
// Determine if it's a Host or Module
|
|
48
38
|
const isHost = pkg.name.endsWith('-host') || pkg.dependencies?.['@callstack/repack'];
|
|
49
39
|
|
|
50
|
-
// 1. Initial Checks & Automated Native Preparation
|
|
51
40
|
await prepareNative(cwd, 'all');
|
|
52
41
|
|
|
53
|
-
if (isHost && !
|
|
54
|
-
console.log(`\n🚀 Starting Host App Dev Server (Re.Pack/Rspack)...\n`);
|
|
55
|
-
await
|
|
42
|
+
if (isHost && !selectedModuleId) {
|
|
43
|
+
console.log(`\n🚀 Starting ${chalk.green('Host App')} Dev Server (Re.Pack/Rspack)...\n`);
|
|
44
|
+
await runProcess('npx', ['react-native', 'webpack-start'], { cwd });
|
|
56
45
|
return;
|
|
57
46
|
}
|
|
58
47
|
|
|
59
|
-
|
|
48
|
+
const { updateDevMode, removeDevMode } = require('../utils/transformer');
|
|
60
49
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
const body = {
|
|
68
|
-
is_dev_mode: isActive,
|
|
69
|
-
...(isActive && { dev_url: `http://localhost:${port}/index.bundle` })
|
|
70
|
-
};
|
|
71
|
-
const res = await fetch(devApiUrl, { method: 'PUT', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) });
|
|
72
|
-
if (res.ok) console.log(`📡 Registry Sync: Dev Override is ${isActive ? 'ON' : 'OFF'} for module ${moduleId}`);
|
|
73
|
-
} catch(e) { /* ignore */ }
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
await setDevMode(true);
|
|
50
|
+
console.log(`\n⚡ Starting ESAD Dev Server for ${chalk.cyan(moduleId)} on port ${port}...\n`);
|
|
51
|
+
|
|
52
|
+
// Automate devMode update in esad.config.js
|
|
53
|
+
const localBundleUrl = `http://localhost:${port}/index.bundle`;
|
|
54
|
+
updateDevMode(configObj.path, moduleId, localBundleUrl);
|
|
55
|
+
console.log(chalk.gray(`📡 Mode: Module Dev. Host configured to load ${moduleId} from ${localBundleUrl}`));
|
|
77
56
|
|
|
78
|
-
const proc =
|
|
57
|
+
const proc = runProcess('npx', ['react-native', 'webpack-start', '--port', port], { cwd });
|
|
79
58
|
|
|
80
59
|
const shutdown = async () => {
|
|
81
|
-
console.log(`\n🛑 Stopping ESAD Dev Server and reverting
|
|
82
|
-
|
|
83
|
-
proc.kill();
|
|
60
|
+
console.log(`\n🛑 Stopping ESAD Dev Server and reverting config...`);
|
|
61
|
+
removeDevMode(configObj.path, moduleId);
|
|
62
|
+
if (proc.kill) proc.kill();
|
|
84
63
|
process.exit(0);
|
|
85
64
|
};
|
|
86
65
|
|
|
66
|
+
|
|
87
67
|
process.on('SIGINT', shutdown);
|
|
88
68
|
process.on('SIGTERM', shutdown);
|
|
89
69
|
};
|
|
70
|
+
|
package/src/cli/commands/init.js
CHANGED
|
@@ -10,34 +10,53 @@ module.exports = async (projectName) => {
|
|
|
10
10
|
|
|
11
11
|
fs.ensureDirSync(workspaceDir);
|
|
12
12
|
|
|
13
|
-
const configPath = path.join(workspaceDir, 'esad.config.
|
|
13
|
+
const configPath = path.join(workspaceDir, 'esad.config.js');
|
|
14
14
|
if (!fs.existsSync(configPath)) {
|
|
15
|
-
const configTemplate =
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
15
|
+
const configTemplate = `/**
|
|
16
|
+
* ESAD: Super App Configuration
|
|
17
|
+
*/
|
|
18
|
+
export default {
|
|
19
|
+
projectName: '${projectName}',
|
|
20
|
+
|
|
21
|
+
// 1. Development Overrides
|
|
22
|
+
// Managed automatically by 'esad dev'
|
|
23
|
+
devMode: {},
|
|
24
|
+
|
|
25
|
+
// 2. Programmable Deployment
|
|
26
|
+
// Receives the compiled bundle.
|
|
27
|
+
async deploy(bundle, { version, moduleId, options }) {
|
|
28
|
+
console.log('🚀 Starting custom upload for ' + moduleId + '...');
|
|
29
|
+
|
|
30
|
+
// Example: Simple CDN V2 upload
|
|
31
|
+
// const response = await fetch('http://localhost:3000/api/admin/modules/' + moduleId + '/versions', {
|
|
32
|
+
// method: 'POST',
|
|
33
|
+
// body: bundle,
|
|
34
|
+
// headers: { 'Authorization': 'Bearer YOUR_TOKEN' }
|
|
35
|
+
// });
|
|
36
|
+
// return await response.json();
|
|
37
|
+
|
|
38
|
+
return { status: 'mock_success', moduleId, version };
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
`;
|
|
42
|
+
fs.writeFileSync(configPath, configTemplate);
|
|
43
|
+
console.log(`✅ Generated programmable configuration: esad.config.js`);
|
|
23
44
|
}
|
|
24
45
|
|
|
25
46
|
const gitignorePath = path.join(workspaceDir, '.gitignore');
|
|
26
47
|
if (!fs.existsSync(gitignorePath)) {
|
|
27
48
|
const hostName = `${projectName}-host`;
|
|
28
49
|
const gitignoreContent = `# ESAD Workspace Git Configuration\n` +
|
|
29
|
-
`# Ignore everything by default\n` +
|
|
30
50
|
`/*\n\n` +
|
|
31
|
-
`# Exceptions: Track only the Host and Configs\n` +
|
|
32
51
|
`!/${hostName}/\n` +
|
|
33
|
-
`!/esad.config.
|
|
52
|
+
`!/esad.config.js\n` +
|
|
34
53
|
`!/.gitignore\n` +
|
|
35
|
-
`\n
|
|
36
|
-
`node_modules/\n`;
|
|
54
|
+
`\nnode_modules/\n`;
|
|
37
55
|
fs.writeFileSync(gitignorePath, gitignoreContent);
|
|
38
56
|
console.log(`✅ Generated .gitignore`);
|
|
39
57
|
}
|
|
40
58
|
|
|
59
|
+
|
|
41
60
|
const hostName = `${projectName}-host`;
|
|
42
61
|
const hostDir = path.join(workspaceDir, hostName);
|
|
43
62
|
|
package/src/cli/utils/config.js
CHANGED
|
@@ -1,11 +1,40 @@
|
|
|
1
1
|
const fs = require('fs-extra');
|
|
2
2
|
const path = require('path');
|
|
3
|
+
const { createJiti } = require('jiti');
|
|
3
4
|
|
|
4
5
|
const getWorkspaceConfig = () => {
|
|
5
|
-
let
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
let current = process.cwd();
|
|
7
|
+
let configPath = null;
|
|
8
|
+
|
|
9
|
+
// Search upwards for esad.config.js
|
|
10
|
+
while (current !== path.parse(current).root) {
|
|
11
|
+
const check = path.join(current, 'esad.config.js');
|
|
12
|
+
if (fs.existsSync(check)) {
|
|
13
|
+
configPath = check;
|
|
14
|
+
break;
|
|
15
|
+
}
|
|
16
|
+
current = path.dirname(current);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
if (!configPath) return null;
|
|
20
|
+
|
|
21
|
+
try {
|
|
22
|
+
const jiti = createJiti(__filename);
|
|
23
|
+
const configModule = jiti.import(configPath);
|
|
24
|
+
// jiti.import returns a promise for async imports if needed, but for esad.config.js
|
|
25
|
+
// we expect a sync structure or we resolve it.
|
|
26
|
+
// However, jiti v2 import is async.
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
path: configPath,
|
|
30
|
+
root: path.dirname(configPath),
|
|
31
|
+
load: () => configModule
|
|
32
|
+
};
|
|
33
|
+
} catch (err) {
|
|
34
|
+
console.error(`❌ Failed to load esad.config.js: ${err.message}`);
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
9
37
|
};
|
|
10
38
|
|
|
11
39
|
module.exports = { getWorkspaceConfig };
|
|
40
|
+
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const fs = require('fs-extra');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Safely updates the devMode object in esad.config.js
|
|
6
|
+
* This uses a simple yet robust regex approach to preserve comments/formatting.
|
|
7
|
+
*/
|
|
8
|
+
const updateDevMode = (configPath, moduleId, url) => {
|
|
9
|
+
let content = fs.readFileSync(configPath, 'utf8');
|
|
10
|
+
|
|
11
|
+
// 1. Ensure devMode object exists
|
|
12
|
+
if (!content.includes('devMode:')) {
|
|
13
|
+
// Inject devMode before the last closing brace (naive but effective for clean configs)
|
|
14
|
+
content = content.replace(/}([^}]*)$/, ` devMode: {},\n}$1`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// 2. Add or update the module entry
|
|
18
|
+
const entryRegex = new RegExp(`(['"]${moduleId}['"]|${moduleId}):\\s*['"]([^'"]*)['"]`, 'g');
|
|
19
|
+
|
|
20
|
+
if (entryRegex.test(content)) {
|
|
21
|
+
// Update existing
|
|
22
|
+
content = content.replace(entryRegex, `$1: '${url}'`);
|
|
23
|
+
} else {
|
|
24
|
+
// Insert new entry into devMode object
|
|
25
|
+
const devModeRegex = /(devMode:\s*{)/;
|
|
26
|
+
content = content.replace(devModeRegex, `$1\n '${moduleId}': '${url}',`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
fs.writeFileSync(configPath, content);
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const clearAllDevMode = (configPath) => {
|
|
33
|
+
if (!fs.existsSync(configPath)) return;
|
|
34
|
+
let content = fs.readFileSync(configPath, 'utf8');
|
|
35
|
+
|
|
36
|
+
// Remove the entire devMode block
|
|
37
|
+
const devModeBlockRegex = /\s*devMode:\s*{[\s\S]*?},?/g;
|
|
38
|
+
content = content.replace(devModeBlockRegex, '');
|
|
39
|
+
|
|
40
|
+
fs.writeFileSync(configPath, content);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
module.exports = { updateDevMode, removeDevMode, clearAllDevMode };
|
|
44
|
+
|