@open-mercato/cli 0.4.2-canary-c02407ff85
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/bin/mercato +21 -0
- package/build.mjs +78 -0
- package/dist/bin.js +51 -0
- package/dist/bin.js.map +7 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +7 -0
- package/dist/lib/db/commands.js +350 -0
- package/dist/lib/db/commands.js.map +7 -0
- package/dist/lib/db/index.js +7 -0
- package/dist/lib/db/index.js.map +7 -0
- package/dist/lib/generators/entity-ids.js +257 -0
- package/dist/lib/generators/entity-ids.js.map +7 -0
- package/dist/lib/generators/index.js +12 -0
- package/dist/lib/generators/index.js.map +7 -0
- package/dist/lib/generators/module-di.js +73 -0
- package/dist/lib/generators/module-di.js.map +7 -0
- package/dist/lib/generators/module-entities.js +104 -0
- package/dist/lib/generators/module-entities.js.map +7 -0
- package/dist/lib/generators/module-registry.js +1081 -0
- package/dist/lib/generators/module-registry.js.map +7 -0
- package/dist/lib/resolver.js +205 -0
- package/dist/lib/resolver.js.map +7 -0
- package/dist/lib/utils.js +161 -0
- package/dist/lib/utils.js.map +7 -0
- package/dist/mercato.js +1045 -0
- package/dist/mercato.js.map +7 -0
- package/dist/registry.js +7 -0
- package/dist/registry.js.map +7 -0
- package/jest.config.cjs +19 -0
- package/package.json +71 -0
- package/src/__tests__/mercato.test.ts +90 -0
- package/src/bin.ts +74 -0
- package/src/index.ts +2 -0
- package/src/lib/__tests__/resolver.test.ts +101 -0
- package/src/lib/__tests__/utils.test.ts +270 -0
- package/src/lib/db/__tests__/commands.test.ts +131 -0
- package/src/lib/db/commands.ts +431 -0
- package/src/lib/db/index.ts +1 -0
- package/src/lib/generators/__tests__/generators.test.ts +197 -0
- package/src/lib/generators/entity-ids.ts +336 -0
- package/src/lib/generators/index.ts +4 -0
- package/src/lib/generators/module-di.ts +89 -0
- package/src/lib/generators/module-entities.ts +124 -0
- package/src/lib/generators/module-registry.ts +1222 -0
- package/src/lib/resolver.ts +308 -0
- package/src/lib/utils.ts +200 -0
- package/src/mercato.ts +1106 -0
- package/src/registry.ts +2 -0
- package/tsconfig.build.json +4 -0
- package/tsconfig.json +12 -0
- package/watch.mjs +6 -0
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
function calculateChecksum(content) {
|
|
5
|
+
return crypto.createHash("md5").update(content).digest("hex");
|
|
6
|
+
}
|
|
7
|
+
function readChecksumRecord(filePath) {
|
|
8
|
+
if (!fs.existsSync(filePath)) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
const parsed = JSON.parse(fs.readFileSync(filePath, "utf8"));
|
|
13
|
+
if (parsed && typeof parsed.content === "string" && typeof parsed.structure === "string") {
|
|
14
|
+
return { content: parsed.content, structure: parsed.structure };
|
|
15
|
+
}
|
|
16
|
+
} catch {
|
|
17
|
+
}
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
function writeChecksumRecord(filePath, record) {
|
|
21
|
+
fs.writeFileSync(filePath, JSON.stringify(record) + "\n");
|
|
22
|
+
}
|
|
23
|
+
function collectStructureEntries(target, base, acc) {
|
|
24
|
+
let entries;
|
|
25
|
+
try {
|
|
26
|
+
entries = fs.readdirSync(target, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
27
|
+
} catch (err) {
|
|
28
|
+
acc.push(`error:${path.relative(base, target)}:${err.message}`);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
for (const entry of entries) {
|
|
32
|
+
const fullPath = path.join(target, entry.name);
|
|
33
|
+
const rel = path.relative(base, fullPath);
|
|
34
|
+
try {
|
|
35
|
+
const stat = fs.statSync(fullPath);
|
|
36
|
+
if (entry.isDirectory()) {
|
|
37
|
+
acc.push(`dir:${rel}:${stat.mtimeMs}`);
|
|
38
|
+
collectStructureEntries(fullPath, base, acc);
|
|
39
|
+
} else if (entry.isFile()) {
|
|
40
|
+
acc.push(`file:${rel}:${stat.size}:${stat.mtimeMs}`);
|
|
41
|
+
} else {
|
|
42
|
+
acc.push(`other:${rel}:${stat.mtimeMs}`);
|
|
43
|
+
}
|
|
44
|
+
} catch {
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
function calculateStructureChecksum(paths) {
|
|
50
|
+
const normalized = Array.from(new Set(paths.map((p) => path.resolve(p)))).sort();
|
|
51
|
+
const entries = [];
|
|
52
|
+
for (const target of normalized) {
|
|
53
|
+
if (!fs.existsSync(target)) {
|
|
54
|
+
entries.push(`missing:${target}`);
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const stat = fs.statSync(target);
|
|
58
|
+
entries.push(`${stat.isDirectory() ? "dir" : "file"}:${target}:${stat.mtimeMs}`);
|
|
59
|
+
if (stat.isDirectory()) collectStructureEntries(target, target, entries);
|
|
60
|
+
}
|
|
61
|
+
return calculateChecksum(entries.join("\n"));
|
|
62
|
+
}
|
|
63
|
+
function writeIfChanged(filePath, content, checksumPath, structureChecksum) {
|
|
64
|
+
const newChecksum = calculateChecksum(content);
|
|
65
|
+
if (checksumPath) {
|
|
66
|
+
const existingRecord = readChecksumRecord(checksumPath);
|
|
67
|
+
const newRecord = {
|
|
68
|
+
content: newChecksum,
|
|
69
|
+
structure: structureChecksum || ""
|
|
70
|
+
};
|
|
71
|
+
const shouldWrite = !existingRecord || existingRecord.content !== newRecord.content || structureChecksum && existingRecord.structure !== newRecord.structure;
|
|
72
|
+
if (shouldWrite) {
|
|
73
|
+
ensureDir(filePath);
|
|
74
|
+
fs.writeFileSync(filePath, content);
|
|
75
|
+
writeChecksumRecord(checksumPath, newRecord);
|
|
76
|
+
return true;
|
|
77
|
+
}
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
if (fs.existsSync(filePath)) {
|
|
81
|
+
const existing = fs.readFileSync(filePath, "utf8");
|
|
82
|
+
if (existing === content) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
ensureDir(filePath);
|
|
87
|
+
fs.writeFileSync(filePath, content);
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
function ensureDir(filePath) {
|
|
91
|
+
fs.mkdirSync(path.dirname(filePath), { recursive: true });
|
|
92
|
+
}
|
|
93
|
+
const ALLOWED_RIMRAF_PATTERNS = [
|
|
94
|
+
"/generated/",
|
|
95
|
+
"/dist/",
|
|
96
|
+
"/.mercato/",
|
|
97
|
+
"/entities/",
|
|
98
|
+
"\\generated\\",
|
|
99
|
+
"\\dist\\",
|
|
100
|
+
"\\.mercato\\",
|
|
101
|
+
"\\entities\\"
|
|
102
|
+
];
|
|
103
|
+
function rimrafDir(dir, opts) {
|
|
104
|
+
if (!fs.existsSync(dir)) return;
|
|
105
|
+
const resolved = path.resolve(dir);
|
|
106
|
+
const allowed = opts?.allowedPatterns ?? ALLOWED_RIMRAF_PATTERNS;
|
|
107
|
+
const normalized = {
|
|
108
|
+
posix: resolved.replace(/\\/g, "/"),
|
|
109
|
+
win: resolved.replace(/\//g, "\\")
|
|
110
|
+
};
|
|
111
|
+
if (!allowed.some((pattern) => normalized.posix.includes(pattern) || normalized.win.includes(pattern))) {
|
|
112
|
+
throw new Error(`Refusing to delete directory outside allowed paths: ${resolved}. Allowed patterns: ${allowed.join(", ")}`);
|
|
113
|
+
}
|
|
114
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
115
|
+
const p = path.join(dir, entry.name);
|
|
116
|
+
if (entry.isDirectory()) rimrafDir(p, opts);
|
|
117
|
+
else fs.unlinkSync(p);
|
|
118
|
+
}
|
|
119
|
+
fs.rmdirSync(dir);
|
|
120
|
+
}
|
|
121
|
+
function toVar(s) {
|
|
122
|
+
return s.replace(/[^a-zA-Z0-9_]/g, "_");
|
|
123
|
+
}
|
|
124
|
+
function toSnake(s) {
|
|
125
|
+
return s.replace(/([a-z0-9])([A-Z])/g, "$1_$2").replace(/\W+/g, "_").replace(/_{2,}/g, "_").replace(/^_+|_+$/g, "").toLowerCase();
|
|
126
|
+
}
|
|
127
|
+
async function moduleHasExport(filePath, exportName) {
|
|
128
|
+
try {
|
|
129
|
+
const mod = await import(filePath);
|
|
130
|
+
return mod != null && Object.prototype.hasOwnProperty.call(mod, exportName);
|
|
131
|
+
} catch {
|
|
132
|
+
return false;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function logGenerationResult(label, changed) {
|
|
136
|
+
if (changed) {
|
|
137
|
+
console.log(`Generated ${label}`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function createGeneratorResult() {
|
|
141
|
+
return {
|
|
142
|
+
filesWritten: [],
|
|
143
|
+
filesUnchanged: [],
|
|
144
|
+
errors: []
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
export {
|
|
148
|
+
calculateChecksum,
|
|
149
|
+
calculateStructureChecksum,
|
|
150
|
+
createGeneratorResult,
|
|
151
|
+
ensureDir,
|
|
152
|
+
logGenerationResult,
|
|
153
|
+
moduleHasExport,
|
|
154
|
+
readChecksumRecord,
|
|
155
|
+
rimrafDir,
|
|
156
|
+
toSnake,
|
|
157
|
+
toVar,
|
|
158
|
+
writeChecksumRecord,
|
|
159
|
+
writeIfChanged
|
|
160
|
+
};
|
|
161
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/lib/utils.ts"],
|
|
4
|
+
"sourcesContent": ["import fs from 'node:fs'\nimport path from 'node:path'\nimport crypto from 'node:crypto'\n\nexport type ChecksumRecord = {\n content: string\n structure: string\n}\n\nexport interface GeneratorResult {\n filesWritten: string[]\n filesUnchanged: string[]\n errors: string[]\n}\n\nexport function calculateChecksum(content: string): string {\n return crypto.createHash('md5').update(content).digest('hex')\n}\n\nexport function readChecksumRecord(filePath: string): ChecksumRecord | null {\n if (!fs.existsSync(filePath)) {\n return null\n }\n try {\n const parsed = JSON.parse(fs.readFileSync(filePath, 'utf8')) as Partial<ChecksumRecord>\n if (parsed && typeof parsed.content === 'string' && typeof parsed.structure === 'string') {\n return { content: parsed.content, structure: parsed.structure }\n }\n } catch {\n // Invalid checksum file\n }\n return null\n}\n\nexport function writeChecksumRecord(filePath: string, record: ChecksumRecord): void {\n fs.writeFileSync(filePath, JSON.stringify(record) + '\\n')\n}\n\nfunction collectStructureEntries(target: string, base: string, acc: string[]): void {\n let entries: fs.Dirent[]\n try {\n entries = fs.readdirSync(target, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))\n } catch (err) {\n acc.push(`error:${path.relative(base, target)}:${(err as Error).message}`)\n return\n }\n\n for (const entry of entries) {\n const fullPath = path.join(target, entry.name)\n const rel = path.relative(base, fullPath)\n try {\n const stat = fs.statSync(fullPath)\n if (entry.isDirectory()) {\n acc.push(`dir:${rel}:${stat.mtimeMs}`)\n collectStructureEntries(fullPath, base, acc)\n } else if (entry.isFile()) {\n acc.push(`file:${rel}:${stat.size}:${stat.mtimeMs}`)\n } else {\n acc.push(`other:${rel}:${stat.mtimeMs}`)\n }\n } catch {\n // File was deleted between readdir and stat - skip it\n continue\n }\n }\n}\n\nexport function calculateStructureChecksum(paths: string[]): string {\n const normalized = Array.from(new Set(paths.map((p) => path.resolve(p)))).sort()\n const entries: string[] = []\n for (const target of normalized) {\n if (!fs.existsSync(target)) {\n entries.push(`missing:${target}`)\n continue\n }\n const stat = fs.statSync(target)\n entries.push(`${stat.isDirectory() ? 'dir' : 'file'}:${target}:${stat.mtimeMs}`)\n if (stat.isDirectory()) collectStructureEntries(target, target, entries)\n }\n return calculateChecksum(entries.join('\\n'))\n}\n\nexport function writeIfChanged(\n filePath: string,\n content: string,\n checksumPath?: string,\n structureChecksum?: string\n): boolean {\n const newChecksum = calculateChecksum(content)\n\n if (checksumPath) {\n const existingRecord = readChecksumRecord(checksumPath)\n const newRecord: ChecksumRecord = {\n content: newChecksum,\n structure: structureChecksum || '',\n }\n\n const shouldWrite =\n !existingRecord ||\n existingRecord.content !== newRecord.content ||\n (structureChecksum && existingRecord.structure !== newRecord.structure)\n\n if (shouldWrite) {\n ensureDir(filePath)\n fs.writeFileSync(filePath, content)\n writeChecksumRecord(checksumPath, newRecord)\n return true\n }\n return false\n }\n\n // Simple comparison without checksum file\n if (fs.existsSync(filePath)) {\n const existing = fs.readFileSync(filePath, 'utf8')\n if (existing === content) {\n return false\n }\n }\n\n ensureDir(filePath)\n fs.writeFileSync(filePath, content)\n return true\n}\n\nexport function ensureDir(filePath: string): void {\n fs.mkdirSync(path.dirname(filePath), { recursive: true })\n}\n\n// Allowed path substrings for safe deletion. Include both POSIX and Windows separators.\nconst ALLOWED_RIMRAF_PATTERNS = [\n '/generated/',\n '/dist/',\n '/.mercato/',\n '/entities/',\n '\\\\generated\\\\',\n '\\\\dist\\\\',\n '\\\\.mercato\\\\',\n '\\\\entities\\\\',\n]\n\nexport function rimrafDir(dir: string, opts?: { allowedPatterns?: string[] }): void {\n if (!fs.existsSync(dir)) return\n\n // Safety check: only allow deletion within known safe directories\n const resolved = path.resolve(dir)\n const allowed = opts?.allowedPatterns ?? ALLOWED_RIMRAF_PATTERNS\n\n // Normalize resolved path to support matching against both POSIX and Windows patterns\n const normalized = {\n posix: resolved.replace(/\\\\/g, '/'),\n win: resolved.replace(/\\//g, '\\\\'),\n }\n\n if (!allowed.some((pattern) => normalized.posix.includes(pattern) || normalized.win.includes(pattern))) {\n throw new Error(`Refusing to delete directory outside allowed paths: ${resolved}. Allowed patterns: ${allowed.join(', ')}`)\n }\n\n for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {\n const p = path.join(dir, entry.name)\n if (entry.isDirectory()) rimrafDir(p, opts)\n else fs.unlinkSync(p)\n }\n fs.rmdirSync(dir)\n}\n\nexport function toVar(s: string): string {\n return s.replace(/[^a-zA-Z0-9_]/g, '_')\n}\n\nexport function toSnake(s: string): string {\n return s\n .replace(/([a-z0-9])([A-Z])/g, '$1_$2')\n .replace(/\\W+/g, '_')\n .replace(/_{2,}/g, '_')\n .replace(/^_+|_+$/g, '')\n .toLowerCase()\n}\n\nexport async function moduleHasExport(filePath: string, exportName: string): Promise<boolean> {\n try {\n const mod = await import(filePath)\n return mod != null && Object.prototype.hasOwnProperty.call(mod, exportName)\n } catch {\n return false\n }\n}\n\nexport function logGenerationResult(label: string, changed: boolean): void {\n if (changed) {\n console.log(`Generated ${label}`)\n }\n}\n\nexport function createGeneratorResult(): GeneratorResult {\n return {\n filesWritten: [],\n filesUnchanged: [],\n errors: [],\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|