@open-mercato/cli 0.4.9-develop-94fb251ed3 → 0.4.9-develop-8d8db18714
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/dist/agentic/shared/AGENTS.md.template +2 -0
- package/dist/agentic/shared/ai/skills/eject-and-customize/SKILL.md +3 -1
- package/dist/bin.js +1 -0
- package/dist/bin.js.map +2 -2
- package/dist/lib/__fixtures__/official-module-package/src/index.js +1 -0
- package/dist/lib/__fixtures__/official-module-package/src/index.js.map +7 -0
- package/dist/lib/__fixtures__/official-module-package/src/modules/test_package/index.js +10 -0
- package/dist/lib/__fixtures__/official-module-package/src/modules/test_package/index.js.map +7 -0
- package/dist/lib/eject.js +30 -38
- package/dist/lib/eject.js.map +2 -2
- package/dist/lib/generators/index.js +2 -0
- package/dist/lib/generators/index.js.map +2 -2
- package/dist/lib/generators/module-package-sources.js +45 -0
- package/dist/lib/generators/module-package-sources.js.map +7 -0
- package/dist/lib/module-install-args.js +40 -0
- package/dist/lib/module-install-args.js.map +7 -0
- package/dist/lib/module-install.js +157 -0
- package/dist/lib/module-install.js.map +7 -0
- package/dist/lib/module-package.js +245 -0
- package/dist/lib/module-package.js.map +7 -0
- package/dist/lib/modules-config.js +255 -0
- package/dist/lib/modules-config.js.map +7 -0
- package/dist/lib/resolver.js +19 -5
- package/dist/lib/resolver.js.map +2 -2
- package/dist/lib/testing/integration-discovery.js +20 -9
- package/dist/lib/testing/integration-discovery.js.map +2 -2
- package/dist/lib/testing/integration.js +86 -47
- package/dist/lib/testing/integration.js.map +2 -2
- package/dist/mercato.js +120 -43
- package/dist/mercato.js.map +3 -3
- package/package.json +5 -4
- package/src/__tests__/mercato.test.ts +6 -1
- package/src/bin.ts +1 -0
- package/src/lib/__fixtures__/official-module-package/dist/modules/test_package/index.js +2 -0
- package/src/lib/__fixtures__/official-module-package/package.json +33 -0
- package/src/lib/__fixtures__/official-module-package/src/index.ts +1 -0
- package/src/lib/__fixtures__/official-module-package/src/modules/test_package/index.ts +6 -0
- package/src/lib/__fixtures__/official-module-package/src/modules/test_package/widgets/injection/test/widget.tsx +3 -0
- package/src/lib/__tests__/eject.test.ts +107 -1
- package/src/lib/__tests__/module-install-args.test.ts +35 -0
- package/src/lib/__tests__/module-install.test.ts +217 -0
- package/src/lib/__tests__/module-package.test.ts +215 -0
- package/src/lib/__tests__/modules-config.test.ts +104 -0
- package/src/lib/__tests__/resolve-environment.test.ts +141 -0
- package/src/lib/eject.ts +45 -55
- package/src/lib/generators/__tests__/generators.test.ts +11 -0
- package/src/lib/generators/__tests__/module-package-sources.test.ts +121 -0
- package/src/lib/generators/index.ts +1 -0
- package/src/lib/generators/module-package-sources.ts +59 -0
- package/src/lib/module-install-args.ts +50 -0
- package/src/lib/module-install.ts +234 -0
- package/src/lib/module-package.ts +355 -0
- package/src/lib/modules-config.ts +393 -0
- package/src/lib/resolver.ts +46 -4
- package/src/lib/testing/__tests__/integration-discovery.test.ts +30 -0
- package/src/lib/testing/integration-discovery.ts +23 -8
- package/src/lib/testing/integration.ts +97 -57
- package/src/mercato.ts +128 -49
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/module-install.ts"],
|
|
4
|
+
"sourcesContent": ["import fs from 'node:fs'\nimport path from 'node:path'\nimport { spawn } from 'node:child_process'\nimport { copyDirRecursive, rewriteCrossModuleImports } from './eject'\nimport {\n parsePackageNameFromSpec,\n resolveInstalledOfficialModulePackage,\n validateEjectBoundaries,\n type ValidatedOfficialModulePackage,\n} from './module-package'\nimport { ensureModuleRegistration } from './modules-config'\nimport type { PackageResolver } from './resolver'\n\ntype ModuleCommandResult = {\n moduleId: string\n packageName: string\n from: string\n registrationChanged: boolean\n}\n\ntype InstallTarget = {\n cwd: string\n args: string[]\n}\n\nfunction resolveYarnBinary(): string {\n return process.platform === 'win32' ? 'yarn.cmd' : 'yarn'\n}\n\nfunction readAppPackageName(appDir: string): string {\n const packageJsonPath = path.join(appDir, 'package.json')\n if (!fs.existsSync(packageJsonPath)) {\n throw new Error(`App package.json not found at ${packageJsonPath}.`)\n }\n\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')) as { name?: string }\n if (!packageJson.name) {\n throw new Error(`App package.json at ${packageJsonPath} is missing the \"name\" field.`)\n }\n\n return packageJson.name\n}\n\nfunction resolveInstallTarget(resolver: PackageResolver): InstallTarget {\n if (!resolver.isMonorepo()) {\n return {\n cwd: resolver.getAppDir(),\n args: ['add'],\n }\n }\n\n return {\n cwd: resolver.getRootDir(),\n args: ['workspace', readAppPackageName(resolver.getAppDir()), 'add'],\n }\n}\n\nfunction runCommand(\n command: string,\n args: string[],\n cwd: string,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, {\n cwd,\n env: process.env,\n stdio: 'inherit',\n })\n\n child.on('error', reject)\n child.on('exit', (code) => {\n if (code === 0) {\n resolve()\n return\n }\n\n reject(new Error(`Command failed: ${command} ${args.join(' ')} (exit ${code ?? 'unknown'}).`))\n })\n })\n}\n\nasync function installPackageSpec(\n resolver: PackageResolver,\n packageSpec: string,\n): Promise<void> {\n const target = resolveInstallTarget(resolver)\n await runCommand(resolveYarnBinary(), [...target.args, packageSpec], target.cwd)\n}\n\nexport async function runModuleGenerators(\n resolver: PackageResolver,\n quiet = true,\n): Promise<void> {\n const {\n generateEntityIds,\n generateModuleDi,\n generateModuleEntities,\n generateModulePackageSources,\n generateModuleRegistry,\n generateModuleRegistryCli,\n generateOpenApi,\n } = await import('./generators')\n\n await generateEntityIds({ resolver, quiet })\n await generateModuleRegistry({ resolver, quiet })\n await generateModuleRegistryCli({ resolver, quiet })\n await generateModuleEntities({ resolver, quiet })\n await generateModuleDi({ resolver, quiet })\n await generateModulePackageSources({ resolver, quiet })\n await generateOpenApi({ resolver, quiet })\n}\n\nasync function runGeneratorsWithRegistrationNotice(\n resolver: PackageResolver,\n moduleId: string,\n): Promise<void> {\n try {\n await runModuleGenerators(resolver)\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n throw new Error(\n `Module \"${moduleId}\" is enabled, but generated artifacts are stale because generation failed. Rerun \"yarn mercato generate\" after fixing the underlying error. ${message}`,\n )\n }\n}\n\nfunction assertPackageName(packageName: string | null): asserts packageName is string {\n if (!packageName || !packageName.startsWith('@open-mercato/')) {\n throw new Error('Only @open-mercato/* package specs are supported by \"mercato module add\".')\n }\n}\n\nfunction validateBeforeRegistration(\n modulePackage: ValidatedOfficialModulePackage,\n resolver: PackageResolver,\n eject: boolean,\n): string {\n const appModuleDir = path.join(resolver.getAppDir(), 'src', 'modules', modulePackage.metadata.moduleId)\n\n if (eject && fs.existsSync(appModuleDir)) {\n throw new Error(`Destination directory already exists: ${appModuleDir}. Remove it first or rerun without --eject.`)\n }\n\n return appModuleDir\n}\n\nfunction prepareRegistrationSource(\n modulePackage: ValidatedOfficialModulePackage,\n resolver: PackageResolver,\n packageName: string,\n eject: boolean,\n): string {\n const appModuleDir = validateBeforeRegistration(modulePackage, resolver, eject)\n\n if (!eject) {\n return packageName\n }\n\n if (!modulePackage.metadata.ejectable) {\n throw new Error(`Package \"${packageName}\" is not ejectable. --eject requires open-mercato.ejectable === true.`)\n }\n\n validateEjectBoundaries(modulePackage)\n copyDirRecursive(modulePackage.sourceModuleDir, appModuleDir)\n rewriteCrossModuleImports(\n modulePackage.sourceModuleDir,\n appModuleDir,\n modulePackage.metadata.moduleId,\n packageName,\n )\n\n return '@app'\n}\n\nasync function registerResolvedOfficialModule(\n resolver: PackageResolver,\n modulePackage: ValidatedOfficialModulePackage,\n packageName: string,\n eject: boolean,\n): Promise<ModuleCommandResult> {\n const from = prepareRegistrationSource(modulePackage, resolver, packageName, eject)\n\n const registration = ensureModuleRegistration(\n resolver.getModulesConfigPath(),\n {\n id: modulePackage.metadata.moduleId,\n from,\n },\n )\n\n if (!registration.changed) {\n throw new Error(\n `Module \"${modulePackage.metadata.moduleId}\" from \"${from}\" is already enabled in modules.ts.`,\n )\n }\n\n await runGeneratorsWithRegistrationNotice(resolver, modulePackage.metadata.moduleId)\n\n return {\n moduleId: modulePackage.metadata.moduleId,\n packageName,\n from,\n registrationChanged: registration.changed,\n }\n}\n\nexport async function addOfficialModule(\n resolver: PackageResolver,\n packageSpec: string,\n eject: boolean,\n moduleId?: string,\n): Promise<ModuleCommandResult> {\n const packageName = parsePackageNameFromSpec(packageSpec)\n assertPackageName(packageName)\n\n await installPackageSpec(resolver, packageSpec)\n\n const modulePackage = resolveInstalledOfficialModulePackage(resolver, packageName, moduleId)\n return registerResolvedOfficialModule(resolver, modulePackage, packageName, eject)\n}\n\nexport async function enableOfficialModule(\n resolver: PackageResolver,\n packageName: string,\n moduleId?: string,\n eject = false,\n): Promise<ModuleCommandResult> {\n if (!packageName.startsWith('@open-mercato/')) {\n throw new Error('Only @open-mercato/* packages can be enabled with \"mercato module enable\".')\n }\n\n const modulePackage = resolveInstalledOfficialModulePackage(resolver, packageName, moduleId)\n return registerResolvedOfficialModule(resolver, modulePackage, packageName, eject)\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
const SOURCE_FILE_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
5
|
+
const SKIP_DIRS = /* @__PURE__ */ new Set(["__tests__", "__mocks__", "node_modules"]);
|
|
6
|
+
const MODULE_ID_PATTERN = /^[a-z0-9]+(?:_[a-z0-9]+)*$/;
|
|
7
|
+
const requireFromCli = createRequire(path.join(process.cwd(), "package.json"));
|
|
8
|
+
function shouldSkipEntryName(name) {
|
|
9
|
+
return SKIP_DIRS.has(name) || name === ".DS_Store" || name.startsWith("._");
|
|
10
|
+
}
|
|
11
|
+
function readPackageJson(packageJsonPath) {
|
|
12
|
+
try {
|
|
13
|
+
const raw = fs.readFileSync(packageJsonPath, "utf8");
|
|
14
|
+
return JSON.parse(raw);
|
|
15
|
+
} catch (error) {
|
|
16
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17
|
+
throw new Error(`Failed to read package manifest at ${packageJsonPath}: ${message}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function parseModuleInfo(indexPath) {
|
|
21
|
+
if (!fs.existsSync(indexPath)) return {};
|
|
22
|
+
const source = fs.readFileSync(indexPath, "utf8");
|
|
23
|
+
const result = {};
|
|
24
|
+
const titleMatch = source.match(/\btitle\s*:\s*['"]([^'"]+)['"]/);
|
|
25
|
+
if (titleMatch) result.title = titleMatch[1];
|
|
26
|
+
const descriptionMatch = source.match(/\bdescription\s*:\s*['"]([^'"]+)['"]/);
|
|
27
|
+
if (descriptionMatch) result.description = descriptionMatch[1];
|
|
28
|
+
const ejectableMatch = source.match(/\bejectable\s*:\s*(true|false)/);
|
|
29
|
+
if (ejectableMatch) result.ejectable = ejectableMatch[1] === "true";
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
function discoverModulesInPackage(packageRoot) {
|
|
33
|
+
const srcModulesDir = path.join(packageRoot, "src", "modules");
|
|
34
|
+
const distModulesDir = path.join(packageRoot, "dist", "modules");
|
|
35
|
+
const enumerationDir = fs.existsSync(srcModulesDir) ? srcModulesDir : fs.existsSync(distModulesDir) ? distModulesDir : null;
|
|
36
|
+
if (!enumerationDir) return [];
|
|
37
|
+
const modules = [];
|
|
38
|
+
for (const entry of fs.readdirSync(enumerationDir, { withFileTypes: true })) {
|
|
39
|
+
if (!entry.isDirectory() || shouldSkipEntryName(entry.name) || !MODULE_ID_PATTERN.test(entry.name)) continue;
|
|
40
|
+
const moduleId = entry.name;
|
|
41
|
+
const srcIndexPath = path.join(packageRoot, "src", "modules", moduleId, "index.ts");
|
|
42
|
+
const distIndexPath = path.join(packageRoot, "dist", "modules", moduleId, "index.js");
|
|
43
|
+
const indexPath = fs.existsSync(srcIndexPath) ? srcIndexPath : distIndexPath;
|
|
44
|
+
const info = parseModuleInfo(indexPath);
|
|
45
|
+
modules.push({ moduleId, ejectable: info.ejectable ?? false });
|
|
46
|
+
}
|
|
47
|
+
return modules;
|
|
48
|
+
}
|
|
49
|
+
function resolveRelativeImportTarget(sourceFile, importPath) {
|
|
50
|
+
if (!importPath.startsWith(".")) return null;
|
|
51
|
+
const basePath = path.resolve(path.dirname(sourceFile), importPath);
|
|
52
|
+
const candidates = [basePath];
|
|
53
|
+
for (const ext of SOURCE_FILE_EXTENSIONS) {
|
|
54
|
+
candidates.push(`${basePath}${ext}`);
|
|
55
|
+
candidates.push(path.join(basePath, `index${ext}`));
|
|
56
|
+
}
|
|
57
|
+
for (const candidate of candidates) {
|
|
58
|
+
if (fs.existsSync(candidate)) {
|
|
59
|
+
return candidate;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
function collectSourceFiles(dir) {
|
|
65
|
+
const files = [];
|
|
66
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
67
|
+
for (const entry of entries) {
|
|
68
|
+
if (shouldSkipEntryName(entry.name)) continue;
|
|
69
|
+
const fullPath = path.join(dir, entry.name);
|
|
70
|
+
if (entry.isDirectory()) {
|
|
71
|
+
files.push(...collectSourceFiles(fullPath));
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
const ext = path.extname(entry.name);
|
|
75
|
+
if (!SOURCE_FILE_EXTENSIONS.includes(ext)) continue;
|
|
76
|
+
files.push(fullPath);
|
|
77
|
+
}
|
|
78
|
+
return files;
|
|
79
|
+
}
|
|
80
|
+
function collectBoundaryViolations(moduleDir) {
|
|
81
|
+
const modulesRoot = path.resolve(moduleDir, "..");
|
|
82
|
+
const modulePrefix = `${moduleDir}${path.sep}`;
|
|
83
|
+
const modulesPrefix = `${modulesRoot}${path.sep}`;
|
|
84
|
+
const files = collectSourceFiles(moduleDir);
|
|
85
|
+
const violations = /* @__PURE__ */ new Set();
|
|
86
|
+
for (const filePath of files) {
|
|
87
|
+
const content = fs.readFileSync(filePath, "utf8");
|
|
88
|
+
const matches = [
|
|
89
|
+
...content.matchAll(/\bfrom\s*['"]([^'"]+)['"]/g),
|
|
90
|
+
...content.matchAll(/\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/g)
|
|
91
|
+
];
|
|
92
|
+
for (const match of matches) {
|
|
93
|
+
const specifier = match[1];
|
|
94
|
+
if (!specifier) continue;
|
|
95
|
+
const resolvedTarget = resolveRelativeImportTarget(filePath, specifier);
|
|
96
|
+
if (!resolvedTarget) continue;
|
|
97
|
+
if (resolvedTarget.startsWith(modulePrefix)) continue;
|
|
98
|
+
if (resolvedTarget.startsWith(modulesPrefix)) continue;
|
|
99
|
+
const relativeSource = path.relative(moduleDir, filePath).split(path.sep).join("/");
|
|
100
|
+
const relativeTarget = path.relative(path.dirname(filePath), resolvedTarget).split(path.sep).join("/");
|
|
101
|
+
violations.add(`${relativeSource} -> ${relativeTarget}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return Array.from(violations).sort((left, right) => left.localeCompare(right));
|
|
105
|
+
}
|
|
106
|
+
function findResolvedPackageRoot(resolvedPath, packageName) {
|
|
107
|
+
let currentPath = fs.statSync(resolvedPath).isDirectory() ? resolvedPath : path.dirname(resolvedPath);
|
|
108
|
+
while (currentPath !== path.dirname(currentPath)) {
|
|
109
|
+
const packageJsonPath = path.join(currentPath, "package.json");
|
|
110
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
111
|
+
const packageJson = readPackageJson(packageJsonPath);
|
|
112
|
+
if (packageJson.name === packageName) {
|
|
113
|
+
return currentPath;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
currentPath = path.dirname(currentPath);
|
|
117
|
+
}
|
|
118
|
+
return null;
|
|
119
|
+
}
|
|
120
|
+
function resolveInstalledPackageRootWithRequire(packageName, appDir) {
|
|
121
|
+
const specifiers = [`${packageName}/package.json`, packageName];
|
|
122
|
+
for (const specifier of specifiers) {
|
|
123
|
+
try {
|
|
124
|
+
const resolvedPath = requireFromCli.resolve(specifier, {
|
|
125
|
+
paths: [appDir]
|
|
126
|
+
});
|
|
127
|
+
const packageRoot = specifier === packageName ? findResolvedPackageRoot(resolvedPath, packageName) : path.dirname(resolvedPath);
|
|
128
|
+
if (packageRoot) {
|
|
129
|
+
return packageRoot;
|
|
130
|
+
}
|
|
131
|
+
} catch {
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
function parsePackageNameFromSpec(packageSpec) {
|
|
138
|
+
const trimmed = packageSpec.trim();
|
|
139
|
+
if (!trimmed) return null;
|
|
140
|
+
if (trimmed.startsWith("@")) {
|
|
141
|
+
const slashIndex = trimmed.indexOf("/");
|
|
142
|
+
if (slashIndex < 0) return null;
|
|
143
|
+
const versionSeparator2 = trimmed.indexOf("@", slashIndex + 1);
|
|
144
|
+
return versionSeparator2 < 0 ? trimmed : trimmed.slice(0, versionSeparator2);
|
|
145
|
+
}
|
|
146
|
+
const versionSeparator = trimmed.indexOf("@");
|
|
147
|
+
return versionSeparator < 0 ? trimmed : trimmed.slice(0, versionSeparator);
|
|
148
|
+
}
|
|
149
|
+
function resolveInstalledPackageRoot(resolver, packageName) {
|
|
150
|
+
const resolvedWithRequire = resolveInstalledPackageRootWithRequire(packageName, resolver.getAppDir());
|
|
151
|
+
if (resolvedWithRequire) {
|
|
152
|
+
return resolvedWithRequire;
|
|
153
|
+
}
|
|
154
|
+
const fallback = resolver.getPackageRoot(packageName);
|
|
155
|
+
if (fs.existsSync(path.join(fallback, "package.json"))) {
|
|
156
|
+
return fallback;
|
|
157
|
+
}
|
|
158
|
+
const nodeModulesFallback = path.join(resolver.getRootDir(), "node_modules", packageName);
|
|
159
|
+
if (fs.existsSync(path.join(nodeModulesFallback, "package.json"))) {
|
|
160
|
+
return nodeModulesFallback;
|
|
161
|
+
}
|
|
162
|
+
throw new Error(`Package "${packageName}" is not installed in ${resolver.getAppDir()}.`);
|
|
163
|
+
}
|
|
164
|
+
function readOfficialModulePackageFromRoot(packageRoot, expectedPackageName, targetModuleId) {
|
|
165
|
+
const packageJsonPath = path.join(packageRoot, "package.json");
|
|
166
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
167
|
+
throw new Error(`Package manifest not found at ${packageJsonPath}.`);
|
|
168
|
+
}
|
|
169
|
+
const packageJson = readPackageJson(packageJsonPath);
|
|
170
|
+
const packageName = packageJson.name;
|
|
171
|
+
if (!packageName || !packageName.startsWith("@open-mercato/")) {
|
|
172
|
+
throw new Error(`Package at ${packageRoot} is not under the @open-mercato scope.`);
|
|
173
|
+
}
|
|
174
|
+
if (expectedPackageName && packageName !== expectedPackageName) {
|
|
175
|
+
throw new Error(`Resolved package "${packageName}" does not match requested package "${expectedPackageName}".`);
|
|
176
|
+
}
|
|
177
|
+
const discoveredModules = discoverModulesInPackage(packageRoot);
|
|
178
|
+
if (discoveredModules.length === 0) {
|
|
179
|
+
throw new Error(`Package "${packageName}" has no modules in src/modules/ or dist/modules/.`);
|
|
180
|
+
}
|
|
181
|
+
let selected;
|
|
182
|
+
if (targetModuleId) {
|
|
183
|
+
const found = discoveredModules.find((m) => m.moduleId === targetModuleId);
|
|
184
|
+
if (!found) {
|
|
185
|
+
const available = discoveredModules.map((m) => m.moduleId).join(", ");
|
|
186
|
+
throw new Error(
|
|
187
|
+
`Package "${packageName}" does not contain module "${targetModuleId}". Available: ${available}`
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
selected = found;
|
|
191
|
+
} else {
|
|
192
|
+
if (discoveredModules.length > 1) {
|
|
193
|
+
const available = discoveredModules.map((m) => m.moduleId).join(", ");
|
|
194
|
+
throw new Error(
|
|
195
|
+
`Package "${packageName}" contains multiple modules (${available}). Specify one with --module <moduleId>.`
|
|
196
|
+
);
|
|
197
|
+
}
|
|
198
|
+
selected = discoveredModules[0];
|
|
199
|
+
}
|
|
200
|
+
const { moduleId } = selected;
|
|
201
|
+
const sourceModuleDir = path.join(packageRoot, "src", "modules", moduleId);
|
|
202
|
+
const distModuleDir = path.join(packageRoot, "dist", "modules", moduleId);
|
|
203
|
+
if (!fs.existsSync(sourceModuleDir)) {
|
|
204
|
+
throw new Error(`Package "${packageName}" is missing src/modules/${moduleId}.`);
|
|
205
|
+
}
|
|
206
|
+
if (!fs.existsSync(distModuleDir)) {
|
|
207
|
+
throw new Error(`Package "${packageName}" is missing dist/modules/${moduleId}.`);
|
|
208
|
+
}
|
|
209
|
+
const info = parseModuleInfo(path.join(sourceModuleDir, "index.ts"));
|
|
210
|
+
return {
|
|
211
|
+
packageName,
|
|
212
|
+
packageRoot,
|
|
213
|
+
packageJson,
|
|
214
|
+
metadata: { moduleId, ejectable: selected.ejectable },
|
|
215
|
+
moduleInfo: { title: info.title, description: info.description },
|
|
216
|
+
sourceModuleDir,
|
|
217
|
+
distModuleDir
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
function resolveInstalledOfficialModulePackage(resolver, packageName, moduleId) {
|
|
221
|
+
const packageRoot = resolveInstalledPackageRoot(resolver, packageName);
|
|
222
|
+
return readOfficialModulePackageFromRoot(packageRoot, packageName, moduleId);
|
|
223
|
+
}
|
|
224
|
+
function validateEjectBoundaries(modulePackage) {
|
|
225
|
+
const violations = collectBoundaryViolations(modulePackage.sourceModuleDir);
|
|
226
|
+
if (violations.length === 0) {
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
throw new Error(
|
|
230
|
+
[
|
|
231
|
+
`Package "${modulePackage.packageName}" cannot be added with --eject because it imports files outside src/modules/${modulePackage.metadata.moduleId}.`,
|
|
232
|
+
"Invalid imports:",
|
|
233
|
+
...violations.map((violation) => `- ${violation}`)
|
|
234
|
+
].join("\n")
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
export {
|
|
238
|
+
discoverModulesInPackage,
|
|
239
|
+
parsePackageNameFromSpec,
|
|
240
|
+
readOfficialModulePackageFromRoot,
|
|
241
|
+
resolveInstalledOfficialModulePackage,
|
|
242
|
+
resolveInstalledPackageRoot,
|
|
243
|
+
validateEjectBoundaries
|
|
244
|
+
};
|
|
245
|
+
//# sourceMappingURL=module-package.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/module-package.ts"],
|
|
4
|
+
"sourcesContent": ["import fs from 'node:fs'\nimport path from 'node:path'\nimport { createRequire } from 'node:module'\nimport type { PackageResolver } from './resolver'\n\ntype PackageJsonRecord = {\n name?: string\n version?: string\n dependencies?: Record<string, string>\n peerDependencies?: Record<string, string>\n}\n\nexport type ModulePackageMetadata = {\n moduleId: string\n ejectable: boolean\n}\n\nexport type ModuleInfoSnapshot = {\n title?: string\n description?: string\n}\n\nexport type ValidatedOfficialModulePackage = {\n packageName: string\n packageRoot: string\n packageJson: PackageJsonRecord\n metadata: ModulePackageMetadata\n moduleInfo: ModuleInfoSnapshot\n sourceModuleDir: string\n distModuleDir: string\n}\n\ntype DiscoveredModule = {\n moduleId: string\n ejectable: boolean\n}\n\nconst SOURCE_FILE_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs']\nconst SKIP_DIRS = new Set(['__tests__', '__mocks__', 'node_modules'])\nconst MODULE_ID_PATTERN = /^[a-z0-9]+(?:_[a-z0-9]+)*$/\nconst requireFromCli = createRequire(path.join(process.cwd(), 'package.json'))\n\nfunction shouldSkipEntryName(name: string): boolean {\n return SKIP_DIRS.has(name) || name === '.DS_Store' || name.startsWith('._')\n}\n\nfunction readPackageJson(packageJsonPath: string): PackageJsonRecord {\n try {\n const raw = fs.readFileSync(packageJsonPath, 'utf8')\n return JSON.parse(raw) as PackageJsonRecord\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n throw new Error(`Failed to read package manifest at ${packageJsonPath}: ${message}`)\n }\n}\n\nfunction parseModuleInfo(indexPath: string): { title?: string; description?: string; ejectable?: boolean } {\n if (!fs.existsSync(indexPath)) return {}\n\n const source = fs.readFileSync(indexPath, 'utf8')\n const result: { title?: string; description?: string; ejectable?: boolean } = {}\n\n const titleMatch = source.match(/\\btitle\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (titleMatch) result.title = titleMatch[1]\n\n const descriptionMatch = source.match(/\\bdescription\\s*:\\s*['\"]([^'\"]+)['\"]/)\n if (descriptionMatch) result.description = descriptionMatch[1]\n\n const ejectableMatch = source.match(/\\bejectable\\s*:\\s*(true|false)/)\n if (ejectableMatch) result.ejectable = ejectableMatch[1] === 'true'\n\n return result\n}\n\nexport function discoverModulesInPackage(packageRoot: string): DiscoveredModule[] {\n const srcModulesDir = path.join(packageRoot, 'src', 'modules')\n const distModulesDir = path.join(packageRoot, 'dist', 'modules')\n\n const enumerationDir = fs.existsSync(srcModulesDir)\n ? srcModulesDir\n : fs.existsSync(distModulesDir)\n ? distModulesDir\n : null\n\n if (!enumerationDir) return []\n\n const modules: DiscoveredModule[] = []\n\n for (const entry of fs.readdirSync(enumerationDir, { withFileTypes: true })) {\n if (!entry.isDirectory() || shouldSkipEntryName(entry.name) || !MODULE_ID_PATTERN.test(entry.name)) continue\n\n const moduleId = entry.name\n const srcIndexPath = path.join(packageRoot, 'src', 'modules', moduleId, 'index.ts')\n const distIndexPath = path.join(packageRoot, 'dist', 'modules', moduleId, 'index.js')\n const indexPath = fs.existsSync(srcIndexPath) ? srcIndexPath : distIndexPath\n\n const info = parseModuleInfo(indexPath)\n modules.push({ moduleId, ejectable: info.ejectable ?? false })\n }\n\n return modules\n}\n\nfunction resolveRelativeImportTarget(sourceFile: string, importPath: string): string | null {\n if (!importPath.startsWith('.')) return null\n\n const basePath = path.resolve(path.dirname(sourceFile), importPath)\n const candidates = [basePath]\n\n for (const ext of SOURCE_FILE_EXTENSIONS) {\n candidates.push(`${basePath}${ext}`)\n candidates.push(path.join(basePath, `index${ext}`))\n }\n\n for (const candidate of candidates) {\n if (fs.existsSync(candidate)) {\n return candidate\n }\n }\n\n return null\n}\n\nfunction collectSourceFiles(dir: string): string[] {\n const files: string[] = []\n const entries = fs.readdirSync(dir, { withFileTypes: true })\n\n for (const entry of entries) {\n if (shouldSkipEntryName(entry.name)) continue\n\n const fullPath = path.join(dir, entry.name)\n if (entry.isDirectory()) {\n files.push(...collectSourceFiles(fullPath))\n continue\n }\n\n const ext = path.extname(entry.name)\n if (!SOURCE_FILE_EXTENSIONS.includes(ext)) continue\n files.push(fullPath)\n }\n\n return files\n}\n\nfunction collectBoundaryViolations(moduleDir: string): string[] {\n const modulesRoot = path.resolve(moduleDir, '..')\n const modulePrefix = `${moduleDir}${path.sep}`\n const modulesPrefix = `${modulesRoot}${path.sep}`\n const files = collectSourceFiles(moduleDir)\n const violations = new Set<string>()\n\n for (const filePath of files) {\n const content = fs.readFileSync(filePath, 'utf8')\n const matches = [\n ...content.matchAll(/\\bfrom\\s*['\"]([^'\"]+)['\"]/g),\n ...content.matchAll(/\\bimport\\s*\\(\\s*['\"]([^'\"]+)['\"]\\s*\\)/g),\n ]\n\n for (const match of matches) {\n const specifier = match[1]\n if (!specifier) continue\n const resolvedTarget = resolveRelativeImportTarget(filePath, specifier)\n if (!resolvedTarget) continue\n if (resolvedTarget.startsWith(modulePrefix)) continue\n if (resolvedTarget.startsWith(modulesPrefix)) continue\n\n const relativeSource = path.relative(moduleDir, filePath).split(path.sep).join('/')\n const relativeTarget = path.relative(path.dirname(filePath), resolvedTarget).split(path.sep).join('/')\n violations.add(`${relativeSource} -> ${relativeTarget}`)\n }\n }\n\n return Array.from(violations).sort((left, right) => left.localeCompare(right))\n}\n\nfunction findResolvedPackageRoot(\n resolvedPath: string,\n packageName: string,\n): string | null {\n let currentPath = fs.statSync(resolvedPath).isDirectory()\n ? resolvedPath\n : path.dirname(resolvedPath)\n\n while (currentPath !== path.dirname(currentPath)) {\n const packageJsonPath = path.join(currentPath, 'package.json')\n if (fs.existsSync(packageJsonPath)) {\n const packageJson = readPackageJson(packageJsonPath)\n if (packageJson.name === packageName) {\n return currentPath\n }\n }\n currentPath = path.dirname(currentPath)\n }\n\n return null\n}\n\nfunction resolveInstalledPackageRootWithRequire(packageName: string, appDir: string): string | null {\n const specifiers = [`${packageName}/package.json`, packageName]\n\n for (const specifier of specifiers) {\n try {\n const resolvedPath = requireFromCli.resolve(specifier, {\n paths: [appDir],\n })\n const packageRoot =\n specifier === packageName\n ? findResolvedPackageRoot(resolvedPath, packageName)\n : path.dirname(resolvedPath)\n\n if (packageRoot) {\n return packageRoot\n }\n } catch {\n continue\n }\n }\n\n return null\n}\n\nexport function parsePackageNameFromSpec(packageSpec: string): string | null {\n const trimmed = packageSpec.trim()\n if (!trimmed) return null\n\n if (trimmed.startsWith('@')) {\n const slashIndex = trimmed.indexOf('/')\n if (slashIndex < 0) return null\n const versionSeparator = trimmed.indexOf('@', slashIndex + 1)\n return versionSeparator < 0 ? trimmed : trimmed.slice(0, versionSeparator)\n }\n\n const versionSeparator = trimmed.indexOf('@')\n return versionSeparator < 0 ? trimmed : trimmed.slice(0, versionSeparator)\n}\n\nexport function resolveInstalledPackageRoot(\n resolver: PackageResolver,\n packageName: string,\n): string {\n const resolvedWithRequire = resolveInstalledPackageRootWithRequire(packageName, resolver.getAppDir())\n if (resolvedWithRequire) {\n return resolvedWithRequire\n }\n\n const fallback = resolver.getPackageRoot(packageName)\n if (fs.existsSync(path.join(fallback, 'package.json'))) {\n return fallback\n }\n\n // In monorepo mode, getPackageRoot resolves to packages/<name> (workspace convention),\n // but externally installed packages land in root node_modules \u2014 check there too.\n const nodeModulesFallback = path.join(resolver.getRootDir(), 'node_modules', packageName)\n if (fs.existsSync(path.join(nodeModulesFallback, 'package.json'))) {\n return nodeModulesFallback\n }\n\n throw new Error(`Package \"${packageName}\" is not installed in ${resolver.getAppDir()}.`)\n}\n\nexport function readOfficialModulePackageFromRoot(\n packageRoot: string,\n expectedPackageName?: string,\n targetModuleId?: string,\n): ValidatedOfficialModulePackage {\n const packageJsonPath = path.join(packageRoot, 'package.json')\n if (!fs.existsSync(packageJsonPath)) {\n throw new Error(`Package manifest not found at ${packageJsonPath}.`)\n }\n\n const packageJson = readPackageJson(packageJsonPath)\n const packageName = packageJson.name\n if (!packageName || !packageName.startsWith('@open-mercato/')) {\n throw new Error(`Package at ${packageRoot} is not under the @open-mercato scope.`)\n }\n\n if (expectedPackageName && packageName !== expectedPackageName) {\n throw new Error(`Resolved package \"${packageName}\" does not match requested package \"${expectedPackageName}\".`)\n }\n\n const discoveredModules = discoverModulesInPackage(packageRoot)\n\n if (discoveredModules.length === 0) {\n throw new Error(`Package \"${packageName}\" has no modules in src/modules/ or dist/modules/.`)\n }\n\n let selected: DiscoveredModule\n\n if (targetModuleId) {\n const found = discoveredModules.find((m) => m.moduleId === targetModuleId)\n if (!found) {\n const available = discoveredModules.map((m) => m.moduleId).join(', ')\n throw new Error(\n `Package \"${packageName}\" does not contain module \"${targetModuleId}\". Available: ${available}`,\n )\n }\n selected = found\n } else {\n if (discoveredModules.length > 1) {\n const available = discoveredModules.map((m) => m.moduleId).join(', ')\n throw new Error(\n `Package \"${packageName}\" contains multiple modules (${available}). Specify one with --module <moduleId>.`,\n )\n }\n selected = discoveredModules[0]\n }\n\n const { moduleId } = selected\n const sourceModuleDir = path.join(packageRoot, 'src', 'modules', moduleId)\n const distModuleDir = path.join(packageRoot, 'dist', 'modules', moduleId)\n\n if (!fs.existsSync(sourceModuleDir)) {\n throw new Error(`Package \"${packageName}\" is missing src/modules/${moduleId}.`)\n }\n\n if (!fs.existsSync(distModuleDir)) {\n throw new Error(`Package \"${packageName}\" is missing dist/modules/${moduleId}.`)\n }\n\n const info = parseModuleInfo(path.join(sourceModuleDir, 'index.ts'))\n\n return {\n packageName,\n packageRoot,\n packageJson,\n metadata: { moduleId, ejectable: selected.ejectable },\n moduleInfo: { title: info.title, description: info.description },\n sourceModuleDir,\n distModuleDir,\n }\n}\n\nexport function resolveInstalledOfficialModulePackage(\n resolver: PackageResolver,\n packageName: string,\n moduleId?: string,\n): ValidatedOfficialModulePackage {\n const packageRoot = resolveInstalledPackageRoot(resolver, packageName)\n return readOfficialModulePackageFromRoot(packageRoot, packageName, moduleId)\n}\n\nexport function validateEjectBoundaries(modulePackage: ValidatedOfficialModulePackage): void {\n const violations = collectBoundaryViolations(modulePackage.sourceModuleDir)\n if (violations.length === 0) {\n return\n }\n\n throw new Error(\n [\n `Package \"${modulePackage.packageName}\" cannot be added with --eject because it imports files outside src/modules/${modulePackage.metadata.moduleId}.`,\n 'Invalid imports:',\n ...violations.map((violation) => `- ${violation}`),\n ].join('\\n'),\n )\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["versionSeparator"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import ts from "typescript";
|
|
3
|
+
import { parseBooleanWithDefault } from "@open-mercato/shared/lib/boolean";
|
|
4
|
+
function parseModuleEntryFromObjectLiteral(node) {
|
|
5
|
+
let id = null;
|
|
6
|
+
let from = null;
|
|
7
|
+
for (const property of node.properties) {
|
|
8
|
+
if (!ts.isPropertyAssignment(property) || !ts.isIdentifier(property.name)) continue;
|
|
9
|
+
if (property.name.text === "id" && ts.isStringLiteralLike(property.initializer)) {
|
|
10
|
+
id = property.initializer.text;
|
|
11
|
+
}
|
|
12
|
+
if (property.name.text === "from" && ts.isStringLiteralLike(property.initializer)) {
|
|
13
|
+
from = property.initializer.text;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (!id) return null;
|
|
17
|
+
return {
|
|
18
|
+
id,
|
|
19
|
+
from: from ?? "@open-mercato/core"
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function parseProcessEnvAccess(node, env) {
|
|
23
|
+
if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name)) {
|
|
24
|
+
const target = node.expression;
|
|
25
|
+
if (ts.isPropertyAccessExpression(target) && ts.isIdentifier(target.expression) && target.expression.text === "process" && target.name.text === "env") {
|
|
26
|
+
return { matched: true, value: env[node.name.text] };
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
if (ts.isElementAccessExpression(node) && ts.isPropertyAccessExpression(node.expression) && ts.isIdentifier(node.expression.expression) && node.expression.expression.text === "process" && node.expression.name.text === "env" && ts.isStringLiteralLike(node.argumentExpression)) {
|
|
30
|
+
return { matched: true, value: env[node.argumentExpression.text] };
|
|
31
|
+
}
|
|
32
|
+
return { matched: false, value: void 0 };
|
|
33
|
+
}
|
|
34
|
+
function evaluateStaticExpressionWithScope(node, env, scope) {
|
|
35
|
+
if (ts.isParenthesizedExpression(node)) {
|
|
36
|
+
return evaluateStaticExpressionWithScope(node.expression, env, scope);
|
|
37
|
+
}
|
|
38
|
+
if (ts.isIdentifier(node)) {
|
|
39
|
+
return scope.get(node.text);
|
|
40
|
+
}
|
|
41
|
+
if (ts.isStringLiteralLike(node) || ts.isNoSubstitutionTemplateLiteral(node)) {
|
|
42
|
+
return node.text;
|
|
43
|
+
}
|
|
44
|
+
if (ts.isNumericLiteral(node)) {
|
|
45
|
+
return Number(node.text);
|
|
46
|
+
}
|
|
47
|
+
if (node.kind === ts.SyntaxKind.TrueKeyword) return true;
|
|
48
|
+
if (node.kind === ts.SyntaxKind.FalseKeyword) return false;
|
|
49
|
+
if (node.kind === ts.SyntaxKind.NullKeyword) return null;
|
|
50
|
+
const envAccess = parseProcessEnvAccess(node, env);
|
|
51
|
+
if (envAccess.matched) {
|
|
52
|
+
return envAccess.value;
|
|
53
|
+
}
|
|
54
|
+
if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.ExclamationToken) {
|
|
55
|
+
return !Boolean(evaluateStaticExpressionWithScope(node.operand, env, scope));
|
|
56
|
+
}
|
|
57
|
+
if (ts.isBinaryExpression(node)) {
|
|
58
|
+
if (node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) {
|
|
59
|
+
return Boolean(evaluateStaticExpressionWithScope(node.left, env, scope)) && Boolean(evaluateStaticExpressionWithScope(node.right, env, scope));
|
|
60
|
+
}
|
|
61
|
+
if (node.operatorToken.kind === ts.SyntaxKind.BarBarToken) {
|
|
62
|
+
return Boolean(evaluateStaticExpressionWithScope(node.left, env, scope)) || Boolean(evaluateStaticExpressionWithScope(node.right, env, scope));
|
|
63
|
+
}
|
|
64
|
+
if (node.operatorToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken) {
|
|
65
|
+
return evaluateStaticExpressionWithScope(node.left, env, scope) === evaluateStaticExpressionWithScope(node.right, env, scope);
|
|
66
|
+
}
|
|
67
|
+
if (node.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken) {
|
|
68
|
+
return evaluateStaticExpressionWithScope(node.left, env, scope) !== evaluateStaticExpressionWithScope(node.right, env, scope);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
if (ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === "parseBooleanWithDefault") {
|
|
72
|
+
const rawValueNode = node.arguments[0];
|
|
73
|
+
const fallbackNode = node.arguments[1];
|
|
74
|
+
const rawValue = rawValueNode ? evaluateStaticExpressionWithScope(rawValueNode, env, scope) : void 0;
|
|
75
|
+
const fallbackValue = fallbackNode ? evaluateStaticExpressionWithScope(fallbackNode, env, scope) : false;
|
|
76
|
+
return parseBooleanWithDefault(
|
|
77
|
+
typeof rawValue === "string" ? rawValue : void 0,
|
|
78
|
+
Boolean(fallbackValue)
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
return void 0;
|
|
82
|
+
}
|
|
83
|
+
function evaluateStaticCondition(node, env, scope) {
|
|
84
|
+
return Boolean(evaluateStaticExpressionWithScope(node, env, scope));
|
|
85
|
+
}
|
|
86
|
+
function collectPushEntriesFromStatement(statement, env, targetVariableName, scope) {
|
|
87
|
+
if (ts.isBlock(statement)) {
|
|
88
|
+
return statement.statements.flatMap(
|
|
89
|
+
(child) => collectPushEntriesFromStatement(child, env, targetVariableName, scope)
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
if (ts.isIfStatement(statement)) {
|
|
93
|
+
if (evaluateStaticCondition(statement.expression, env, scope)) {
|
|
94
|
+
return collectPushEntriesFromStatement(statement.thenStatement, env, targetVariableName, scope);
|
|
95
|
+
}
|
|
96
|
+
if (statement.elseStatement) {
|
|
97
|
+
return collectPushEntriesFromStatement(statement.elseStatement, env, targetVariableName, scope);
|
|
98
|
+
}
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
if (!ts.isExpressionStatement(statement)) return [];
|
|
102
|
+
const expression = statement.expression;
|
|
103
|
+
if (!ts.isCallExpression(expression) || !ts.isPropertyAccessExpression(expression.expression)) {
|
|
104
|
+
return [];
|
|
105
|
+
}
|
|
106
|
+
const pushTarget = expression.expression.expression;
|
|
107
|
+
const pushMethod = expression.expression.name;
|
|
108
|
+
if (!ts.isIdentifier(pushTarget) || pushTarget.text !== targetVariableName || pushMethod.text !== "push") {
|
|
109
|
+
return [];
|
|
110
|
+
}
|
|
111
|
+
return expression.arguments.flatMap((argument) => {
|
|
112
|
+
if (!ts.isObjectLiteralExpression(argument)) return [];
|
|
113
|
+
const entry = parseModuleEntryFromObjectLiteral(argument);
|
|
114
|
+
return entry ? [{ entry, node: argument }] : [];
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
function parseModuleConfigShape(source, env = process.env) {
|
|
118
|
+
const sourceFile = ts.createSourceFile("modules.ts", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
119
|
+
const variableName = "enabledModules";
|
|
120
|
+
const occurrences = [];
|
|
121
|
+
const scope = /* @__PURE__ */ new Map();
|
|
122
|
+
let arrayNode = null;
|
|
123
|
+
let foundDeclaration = false;
|
|
124
|
+
for (const statement of sourceFile.statements) {
|
|
125
|
+
if (ts.isVariableStatement(statement)) {
|
|
126
|
+
for (const declaration of statement.declarationList.declarations) {
|
|
127
|
+
if (!ts.isIdentifier(declaration.name)) continue;
|
|
128
|
+
if (declaration.name.text === variableName) {
|
|
129
|
+
if (!declaration.initializer || !ts.isArrayLiteralExpression(declaration.initializer)) continue;
|
|
130
|
+
arrayNode = declaration.initializer;
|
|
131
|
+
occurrences.push(...declaration.initializer.elements.flatMap((element) => {
|
|
132
|
+
if (!ts.isObjectLiteralExpression(element)) return [];
|
|
133
|
+
const entry = parseModuleEntryFromObjectLiteral(element);
|
|
134
|
+
return entry ? [{ entry, node: element }] : [];
|
|
135
|
+
}));
|
|
136
|
+
foundDeclaration = true;
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
if (!declaration.initializer) continue;
|
|
140
|
+
scope.set(
|
|
141
|
+
declaration.name.text,
|
|
142
|
+
evaluateStaticExpressionWithScope(declaration.initializer, env, scope)
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
if (!foundDeclaration) continue;
|
|
148
|
+
occurrences.push(...collectPushEntriesFromStatement(statement, env, variableName, scope));
|
|
149
|
+
}
|
|
150
|
+
if (!arrayNode) {
|
|
151
|
+
throw new Error("Could not find enabledModules array declaration in src/modules.ts");
|
|
152
|
+
}
|
|
153
|
+
return { arrayNode, occurrences };
|
|
154
|
+
}
|
|
155
|
+
function normalizeModuleEntry(entry) {
|
|
156
|
+
return {
|
|
157
|
+
id: entry.id,
|
|
158
|
+
from: entry.from ?? "@open-mercato/core"
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
function escapeSingleQuotedString(value) {
|
|
162
|
+
return value.replace(/\\/g, "\\\\").replace(/'/g, "\\'");
|
|
163
|
+
}
|
|
164
|
+
function buildModuleEntryLiteral(entry) {
|
|
165
|
+
const normalized = normalizeModuleEntry(entry);
|
|
166
|
+
return `{ id: '${escapeSingleQuotedString(normalized.id)}', from: '${escapeSingleQuotedString(normalized.from ?? "@open-mercato/core")}' }`;
|
|
167
|
+
}
|
|
168
|
+
function lineIndentAt(source, position) {
|
|
169
|
+
const lineStart = source.lastIndexOf("\n", Math.max(0, position - 1)) + 1;
|
|
170
|
+
const lineToPosition = source.slice(lineStart, position);
|
|
171
|
+
const match = lineToPosition.match(/^\s*/);
|
|
172
|
+
return match?.[0] ?? "";
|
|
173
|
+
}
|
|
174
|
+
function replaceArrayLiteral(source, arrayNode, entry, sourceFile) {
|
|
175
|
+
const existingElements = arrayNode.elements.map(
|
|
176
|
+
(element) => source.slice(element.getStart(sourceFile), element.end).trim()
|
|
177
|
+
);
|
|
178
|
+
const closingIndent = lineIndentAt(source, arrayNode.end - 1);
|
|
179
|
+
const elementIndent = arrayNode.elements.length > 0 ? lineIndentAt(source, arrayNode.elements[0].getStart(sourceFile)) : `${closingIndent} `;
|
|
180
|
+
const updatedArray = [
|
|
181
|
+
"[",
|
|
182
|
+
...[...existingElements, buildModuleEntryLiteral(entry)].map((value) => `${elementIndent}${value},`),
|
|
183
|
+
`${closingIndent}]`
|
|
184
|
+
].join("\n");
|
|
185
|
+
return source.slice(0, arrayNode.getStart(sourceFile)) + updatedArray + source.slice(arrayNode.end);
|
|
186
|
+
}
|
|
187
|
+
function upsertModuleSource(objectLiteral, from) {
|
|
188
|
+
if (/from\s*:\s*'[^']*'/.test(objectLiteral)) {
|
|
189
|
+
return objectLiteral.replace(/from\s*:\s*'[^']*'/, `from: '${escapeSingleQuotedString(from)}'`);
|
|
190
|
+
}
|
|
191
|
+
if (/from\s*:\s*"[^"]*"/.test(objectLiteral)) {
|
|
192
|
+
return objectLiteral.replace(/from\s*:\s*"[^"]*"/, `from: "${from.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`);
|
|
193
|
+
}
|
|
194
|
+
return objectLiteral.replace(/\}\s*$/, `, from: '${escapeSingleQuotedString(from)}' }`);
|
|
195
|
+
}
|
|
196
|
+
function ensureModuleRegistration(modulesPath, entry) {
|
|
197
|
+
if (!fs.existsSync(modulesPath)) {
|
|
198
|
+
throw new Error(`modules.ts not found at ${modulesPath}`);
|
|
199
|
+
}
|
|
200
|
+
const source = fs.readFileSync(modulesPath, "utf8");
|
|
201
|
+
const sourceFile = ts.createSourceFile("modules.ts", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
202
|
+
const config = parseModuleConfigShape(source);
|
|
203
|
+
const normalized = normalizeModuleEntry(entry);
|
|
204
|
+
const matches = config.occurrences.filter((occurrence) => occurrence.entry.id === normalized.id);
|
|
205
|
+
if (matches.length > 1) {
|
|
206
|
+
throw new Error(
|
|
207
|
+
`Module "${normalized.id}" is registered multiple times in ${modulesPath}. Resolve duplicates manually before running this command.`
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
if (matches.length === 1) {
|
|
211
|
+
const existing = normalizeModuleEntry(matches[0].entry);
|
|
212
|
+
if (existing.from === normalized.from) {
|
|
213
|
+
return { changed: false, registeredAs: normalized.from ?? "@open-mercato/core" };
|
|
214
|
+
}
|
|
215
|
+
throw new Error(
|
|
216
|
+
`Module "${normalized.id}" is already registered from "${existing.from}". Remove or eject the existing registration first.`
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
const updated = replaceArrayLiteral(source, config.arrayNode, normalized, sourceFile);
|
|
220
|
+
fs.writeFileSync(modulesPath, updated);
|
|
221
|
+
return { changed: true, registeredAs: normalized.from ?? "@open-mercato/core" };
|
|
222
|
+
}
|
|
223
|
+
function setModuleRegistrationSource(modulesPath, moduleId, from) {
|
|
224
|
+
if (!fs.existsSync(modulesPath)) {
|
|
225
|
+
throw new Error(`modules.ts not found at ${modulesPath}`);
|
|
226
|
+
}
|
|
227
|
+
const source = fs.readFileSync(modulesPath, "utf8");
|
|
228
|
+
const config = parseModuleConfigShape(source);
|
|
229
|
+
const matches = config.occurrences.filter((occurrence) => occurrence.entry.id === moduleId);
|
|
230
|
+
if (matches.length === 0) {
|
|
231
|
+
throw new Error(
|
|
232
|
+
`Could not find module entry for "${moduleId}" in ${modulesPath}. Expected a pattern like: { id: '${moduleId}', from: '...' } or { id: '${moduleId}' }`
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
if (matches.length > 1) {
|
|
236
|
+
throw new Error(
|
|
237
|
+
`Module "${moduleId}" is registered multiple times in ${modulesPath}. Resolve duplicates manually before running this command.`
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
const match = matches[0];
|
|
241
|
+
const current = normalizeModuleEntry(match.entry);
|
|
242
|
+
if (current.from === from) {
|
|
243
|
+
return { changed: false };
|
|
244
|
+
}
|
|
245
|
+
const objectLiteral = source.slice(match.node.getStart(), match.node.end);
|
|
246
|
+
const updatedObjectLiteral = upsertModuleSource(objectLiteral, from);
|
|
247
|
+
const updated = source.slice(0, match.node.getStart()) + updatedObjectLiteral + source.slice(match.node.end);
|
|
248
|
+
fs.writeFileSync(modulesPath, updated);
|
|
249
|
+
return { changed: true };
|
|
250
|
+
}
|
|
251
|
+
export {
|
|
252
|
+
ensureModuleRegistration,
|
|
253
|
+
setModuleRegistrationSource
|
|
254
|
+
};
|
|
255
|
+
//# sourceMappingURL=modules-config.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/modules-config.ts"],
|
|
4
|
+
"sourcesContent": ["import fs from 'node:fs'\nimport ts from 'typescript'\nimport { parseBooleanWithDefault } from '@open-mercato/shared/lib/boolean'\n\nexport type ModuleEntry = {\n id: string\n from?: '@open-mercato/core' | '@app' | string\n}\n\ntype ModuleOccurrence = {\n entry: ModuleEntry\n node: ts.ObjectLiteralExpression\n}\n\ntype ModuleConfigShape = {\n arrayNode: ts.ArrayLiteralExpression\n occurrences: ModuleOccurrence[]\n}\n\nfunction parseModuleEntryFromObjectLiteral(node: ts.ObjectLiteralExpression): ModuleEntry | null {\n let id: string | null = null\n let from: string | null = null\n\n for (const property of node.properties) {\n if (!ts.isPropertyAssignment(property) || !ts.isIdentifier(property.name)) continue\n\n if (property.name.text === 'id' && ts.isStringLiteralLike(property.initializer)) {\n id = property.initializer.text\n }\n\n if (property.name.text === 'from' && ts.isStringLiteralLike(property.initializer)) {\n from = property.initializer.text\n }\n }\n\n if (!id) return null\n\n return {\n id,\n from: from ?? '@open-mercato/core',\n }\n}\n\nfunction parseProcessEnvAccess(\n node: ts.Expression,\n env: NodeJS.ProcessEnv,\n): { matched: boolean; value: string | undefined } {\n if (ts.isPropertyAccessExpression(node) && ts.isIdentifier(node.name)) {\n const target = node.expression\n if (\n ts.isPropertyAccessExpression(target)\n && ts.isIdentifier(target.expression)\n && target.expression.text === 'process'\n && target.name.text === 'env'\n ) {\n return { matched: true, value: env[node.name.text] }\n }\n }\n\n if (\n ts.isElementAccessExpression(node)\n && ts.isPropertyAccessExpression(node.expression)\n && ts.isIdentifier(node.expression.expression)\n && node.expression.expression.text === 'process'\n && node.expression.name.text === 'env'\n && ts.isStringLiteralLike(node.argumentExpression)\n ) {\n return { matched: true, value: env[node.argumentExpression.text] }\n }\n\n return { matched: false, value: undefined }\n}\n\nfunction evaluateStaticExpressionWithScope(\n node: ts.Expression,\n env: NodeJS.ProcessEnv,\n scope: Map<string, unknown>,\n): unknown {\n if (ts.isParenthesizedExpression(node)) {\n return evaluateStaticExpressionWithScope(node.expression, env, scope)\n }\n\n if (ts.isIdentifier(node)) {\n return scope.get(node.text)\n }\n\n if (ts.isStringLiteralLike(node) || ts.isNoSubstitutionTemplateLiteral(node)) {\n return node.text\n }\n\n if (ts.isNumericLiteral(node)) {\n return Number(node.text)\n }\n\n if (node.kind === ts.SyntaxKind.TrueKeyword) return true\n if (node.kind === ts.SyntaxKind.FalseKeyword) return false\n if (node.kind === ts.SyntaxKind.NullKeyword) return null\n\n const envAccess = parseProcessEnvAccess(node, env)\n if (envAccess.matched) {\n return envAccess.value\n }\n\n if (ts.isPrefixUnaryExpression(node) && node.operator === ts.SyntaxKind.ExclamationToken) {\n return !Boolean(evaluateStaticExpressionWithScope(node.operand, env, scope))\n }\n\n if (ts.isBinaryExpression(node)) {\n if (node.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) {\n return Boolean(evaluateStaticExpressionWithScope(node.left, env, scope))\n && Boolean(evaluateStaticExpressionWithScope(node.right, env, scope))\n }\n\n if (node.operatorToken.kind === ts.SyntaxKind.BarBarToken) {\n return Boolean(evaluateStaticExpressionWithScope(node.left, env, scope))\n || Boolean(evaluateStaticExpressionWithScope(node.right, env, scope))\n }\n\n if (node.operatorToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken) {\n return evaluateStaticExpressionWithScope(node.left, env, scope)\n === evaluateStaticExpressionWithScope(node.right, env, scope)\n }\n\n if (node.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken) {\n return evaluateStaticExpressionWithScope(node.left, env, scope)\n !== evaluateStaticExpressionWithScope(node.right, env, scope)\n }\n }\n\n if (\n ts.isCallExpression(node)\n && ts.isIdentifier(node.expression)\n && node.expression.text === 'parseBooleanWithDefault'\n ) {\n const rawValueNode = node.arguments[0]\n const fallbackNode = node.arguments[1]\n const rawValue = rawValueNode\n ? evaluateStaticExpressionWithScope(rawValueNode, env, scope)\n : undefined\n const fallbackValue = fallbackNode\n ? evaluateStaticExpressionWithScope(fallbackNode, env, scope)\n : false\n\n return parseBooleanWithDefault(\n typeof rawValue === 'string' ? rawValue : undefined,\n Boolean(fallbackValue),\n )\n }\n\n return undefined\n}\n\nfunction evaluateStaticCondition(\n node: ts.Expression,\n env: NodeJS.ProcessEnv,\n scope: Map<string, unknown>,\n): boolean {\n return Boolean(evaluateStaticExpressionWithScope(node, env, scope))\n}\n\nfunction collectPushEntriesFromStatement(\n statement: ts.Statement,\n env: NodeJS.ProcessEnv,\n targetVariableName: string,\n scope: Map<string, unknown>,\n): ModuleOccurrence[] {\n if (ts.isBlock(statement)) {\n return statement.statements.flatMap((child) =>\n collectPushEntriesFromStatement(child, env, targetVariableName, scope),\n )\n }\n\n if (ts.isIfStatement(statement)) {\n if (evaluateStaticCondition(statement.expression, env, scope)) {\n return collectPushEntriesFromStatement(statement.thenStatement, env, targetVariableName, scope)\n }\n\n if (statement.elseStatement) {\n return collectPushEntriesFromStatement(statement.elseStatement, env, targetVariableName, scope)\n }\n\n return []\n }\n\n if (!ts.isExpressionStatement(statement)) return []\n\n const expression = statement.expression\n if (!ts.isCallExpression(expression) || !ts.isPropertyAccessExpression(expression.expression)) {\n return []\n }\n\n const pushTarget = expression.expression.expression\n const pushMethod = expression.expression.name\n\n if (!ts.isIdentifier(pushTarget) || pushTarget.text !== targetVariableName || pushMethod.text !== 'push') {\n return []\n }\n\n return expression.arguments.flatMap((argument) => {\n if (!ts.isObjectLiteralExpression(argument)) return []\n const entry = parseModuleEntryFromObjectLiteral(argument)\n return entry ? [{ entry, node: argument }] : []\n })\n}\n\nfunction parseModuleConfigShape(\n source: string,\n env: NodeJS.ProcessEnv = process.env,\n): ModuleConfigShape {\n const sourceFile = ts.createSourceFile('modules.ts', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS)\n const variableName = 'enabledModules'\n const occurrences: ModuleOccurrence[] = []\n const scope = new Map<string, unknown>()\n let arrayNode: ts.ArrayLiteralExpression | null = null\n let foundDeclaration = false\n\n for (const statement of sourceFile.statements) {\n if (ts.isVariableStatement(statement)) {\n for (const declaration of statement.declarationList.declarations) {\n if (!ts.isIdentifier(declaration.name)) continue\n\n if (declaration.name.text === variableName) {\n if (!declaration.initializer || !ts.isArrayLiteralExpression(declaration.initializer)) continue\n\n arrayNode = declaration.initializer\n occurrences.push(...declaration.initializer.elements.flatMap((element) => {\n if (!ts.isObjectLiteralExpression(element)) return []\n const entry = parseModuleEntryFromObjectLiteral(element)\n return entry ? [{ entry, node: element }] : []\n }))\n foundDeclaration = true\n continue\n }\n\n if (!declaration.initializer) continue\n\n scope.set(\n declaration.name.text,\n evaluateStaticExpressionWithScope(declaration.initializer, env, scope),\n )\n }\n continue\n }\n\n if (!foundDeclaration) continue\n\n occurrences.push(...collectPushEntriesFromStatement(statement, env, variableName, scope))\n }\n\n if (!arrayNode) {\n throw new Error('Could not find enabledModules array declaration in src/modules.ts')\n }\n\n return { arrayNode, occurrences }\n}\n\nfunction normalizeModuleEntry(entry: ModuleEntry): ModuleEntry {\n return {\n id: entry.id,\n from: entry.from ?? '@open-mercato/core',\n }\n}\n\nfunction escapeSingleQuotedString(value: string): string {\n return value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\")\n}\n\nfunction buildModuleEntryLiteral(entry: ModuleEntry): string {\n const normalized = normalizeModuleEntry(entry)\n return `{ id: '${escapeSingleQuotedString(normalized.id)}', from: '${escapeSingleQuotedString(normalized.from ?? '@open-mercato/core')}' }`\n}\n\nfunction lineIndentAt(source: string, position: number): string {\n const lineStart = source.lastIndexOf('\\n', Math.max(0, position - 1)) + 1\n const lineToPosition = source.slice(lineStart, position)\n const match = lineToPosition.match(/^\\s*/)\n return match?.[0] ?? ''\n}\n\nfunction replaceArrayLiteral(\n source: string,\n arrayNode: ts.ArrayLiteralExpression,\n entry: ModuleEntry,\n sourceFile: ts.SourceFile,\n): string {\n const existingElements = arrayNode.elements.map((element) =>\n source.slice(element.getStart(sourceFile), element.end).trim(),\n )\n const closingIndent = lineIndentAt(source, arrayNode.end - 1)\n const elementIndent =\n arrayNode.elements.length > 0\n ? lineIndentAt(source, arrayNode.elements[0].getStart(sourceFile))\n : `${closingIndent} `\n const updatedArray = [\n '[',\n ...[...existingElements, buildModuleEntryLiteral(entry)].map((value) => `${elementIndent}${value},`),\n `${closingIndent}]`,\n ].join('\\n')\n\n return source.slice(0, arrayNode.getStart(sourceFile)) + updatedArray + source.slice(arrayNode.end)\n}\n\nfunction upsertModuleSource(objectLiteral: string, from: string): string {\n if (/from\\s*:\\s*'[^']*'/.test(objectLiteral)) {\n return objectLiteral.replace(/from\\s*:\\s*'[^']*'/, `from: '${escapeSingleQuotedString(from)}'`)\n }\n\n if (/from\\s*:\\s*\"[^\"]*\"/.test(objectLiteral)) {\n return objectLiteral.replace(/from\\s*:\\s*\"[^\"]*\"/, `from: \"${from.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`)\n }\n\n return objectLiteral.replace(/\\}\\s*$/, `, from: '${escapeSingleQuotedString(from)}' }`)\n}\n\nexport function ensureModuleRegistration(\n modulesPath: string,\n entry: ModuleEntry,\n): { changed: boolean; registeredAs: string } {\n if (!fs.existsSync(modulesPath)) {\n throw new Error(`modules.ts not found at ${modulesPath}`)\n }\n\n const source = fs.readFileSync(modulesPath, 'utf8')\n const sourceFile = ts.createSourceFile('modules.ts', source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS)\n const config = parseModuleConfigShape(source)\n const normalized = normalizeModuleEntry(entry)\n const matches = config.occurrences.filter((occurrence) => occurrence.entry.id === normalized.id)\n\n if (matches.length > 1) {\n throw new Error(\n `Module \"${normalized.id}\" is registered multiple times in ${modulesPath}. Resolve duplicates manually before running this command.`,\n )\n }\n\n if (matches.length === 1) {\n const existing = normalizeModuleEntry(matches[0].entry)\n if (existing.from === normalized.from) {\n return { changed: false, registeredAs: normalized.from ?? '@open-mercato/core' }\n }\n\n throw new Error(\n `Module \"${normalized.id}\" is already registered from \"${existing.from}\". Remove or eject the existing registration first.`,\n )\n }\n\n const updated = replaceArrayLiteral(source, config.arrayNode, normalized, sourceFile)\n fs.writeFileSync(modulesPath, updated)\n\n return { changed: true, registeredAs: normalized.from ?? '@open-mercato/core' }\n}\n\nexport function setModuleRegistrationSource(\n modulesPath: string,\n moduleId: string,\n from: string,\n): { changed: boolean } {\n if (!fs.existsSync(modulesPath)) {\n throw new Error(`modules.ts not found at ${modulesPath}`)\n }\n\n const source = fs.readFileSync(modulesPath, 'utf8')\n const config = parseModuleConfigShape(source)\n const matches = config.occurrences.filter((occurrence) => occurrence.entry.id === moduleId)\n\n if (matches.length === 0) {\n throw new Error(\n `Could not find module entry for \"${moduleId}\" in ${modulesPath}. Expected a pattern like: { id: '${moduleId}', from: '...' } or { id: '${moduleId}' }`,\n )\n }\n\n if (matches.length > 1) {\n throw new Error(\n `Module \"${moduleId}\" is registered multiple times in ${modulesPath}. Resolve duplicates manually before running this command.`,\n )\n }\n\n const match = matches[0]\n const current = normalizeModuleEntry(match.entry)\n if (current.from === from) {\n return { changed: false }\n }\n\n const objectLiteral = source.slice(match.node.getStart(), match.node.end)\n const updatedObjectLiteral = upsertModuleSource(objectLiteral, from)\n const updated =\n source.slice(0, match.node.getStart()) +\n updatedObjectLiteral +\n source.slice(match.node.end)\n\n fs.writeFileSync(modulesPath, updated)\n\n return { changed: true }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|