create-m5kdev 0.30.0 → 0.31.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.
Files changed (60) hide show
  1. package/dist/src/catalog.cjs +140 -0
  2. package/dist/src/catalog.cjs.map +1 -0
  3. package/dist/src/catalog.d.cts +31 -0
  4. package/dist/src/changes.cjs +70 -0
  5. package/dist/src/changes.cjs.map +1 -0
  6. package/dist/src/changes.d.cts +26 -0
  7. package/dist/src/create.cjs +37 -23
  8. package/dist/src/create.cjs.map +1 -1
  9. package/dist/src/diagnostics.cjs +33 -0
  10. package/dist/src/diagnostics.cjs.map +1 -0
  11. package/dist/src/diagnostics.d.cts +20 -0
  12. package/dist/src/doctor.cjs +246 -0
  13. package/dist/src/doctor.cjs.map +1 -0
  14. package/dist/src/doctor.d.cts +13 -0
  15. package/dist/src/fs.cjs +56 -26
  16. package/dist/src/fs.cjs.map +1 -1
  17. package/dist/src/fs.d.cts +11 -4
  18. package/dist/src/init.cjs +110 -0
  19. package/dist/src/init.cjs.map +1 -0
  20. package/dist/src/init.d.cts +36 -0
  21. package/dist/src/migrations/ast.cjs +49 -0
  22. package/dist/src/migrations/ast.cjs.map +1 -0
  23. package/dist/src/migrations/ast.d.cts +10 -0
  24. package/dist/src/migrations/registry.cjs +41 -0
  25. package/dist/src/migrations/registry.cjs.map +1 -0
  26. package/dist/src/migrations/registry.d.cts +12 -0
  27. package/dist/src/migrations/types.cjs +0 -0
  28. package/dist/src/migrations/types.d.cts +22 -0
  29. package/dist/src/prompts.cjs +1 -1
  30. package/dist/src/prompts.cjs.map +1 -1
  31. package/dist/src/reconcile.cjs +361 -0
  32. package/dist/src/reconcile.cjs.map +1 -0
  33. package/dist/src/reconcile.d.cts +26 -0
  34. package/dist/src/runCli.cjs +155 -27
  35. package/dist/src/runCli.cjs.map +1 -1
  36. package/dist/src/state.cjs +107 -0
  37. package/dist/src/state.cjs.map +1 -0
  38. package/dist/src/state.d.cts +50 -0
  39. package/dist/src/template.cjs +45 -0
  40. package/dist/src/template.cjs.map +1 -0
  41. package/dist/src/template.d.cts +10 -0
  42. package/dist/src/types.d.cts +20 -1
  43. package/dist/src/update.cjs +91 -0
  44. package/dist/src/update.cjs.map +1 -0
  45. package/dist/src/update.d.cts +33 -0
  46. package/package.json +12 -4
  47. package/templates/minimal-app/README.md.tpl +18 -3
  48. package/templates/minimal-app/apps/email/src/emails/accountDeletionEmail.tsx.tpl +36 -35
  49. package/templates/minimal-app/apps/email/src/emails/organizationInviteEmail.tsx.tpl +35 -34
  50. package/templates/minimal-app/apps/email/src/emails/passwordResetEmail.tsx.tpl +36 -35
  51. package/templates/minimal-app/apps/email/src/emails/verificationEmail.tsx.tpl +38 -37
  52. package/templates/minimal-app/apps/email/src/emails/waitlistEmails.tsx.tpl +88 -87
  53. package/templates/minimal-app/apps/email/src/index.ts.tpl +74 -72
  54. package/templates/minimal-app/apps/email/tsconfig.json.tpl +11 -16
  55. package/templates/minimal-app/apps/server/tsconfig.json.tpl +13 -20
  56. package/templates/minimal-app/apps/shared/tsconfig.json.tpl +12 -16
  57. package/templates/minimal-app/apps/webapp/src/modules/posts/hooks/usePostsList.ts.tpl +98 -98
  58. package/templates/minimal-app/biome.json.tpl +9 -2
  59. package/templates/minimal-app/pnpm-workspace.yaml.tpl +61 -63
  60. package/templates/minimal-app/template.manifest.json +30 -0
@@ -0,0 +1,140 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
3
+ let node_fs = require("node:fs");
4
+ node_fs = require_runtime.__toESM(node_fs);
5
+ let node_path = require("node:path");
6
+ node_path = require_runtime.__toESM(node_path);
7
+ let yaml = require("yaml");
8
+ //#region src/catalog.ts
9
+ const DEPENDENCY_FIELDS = [
10
+ "dependencies",
11
+ "devDependencies",
12
+ "peerDependencies",
13
+ "optionalDependencies"
14
+ ];
15
+ function walkPackageJsonFiles(directory, out = []) {
16
+ for (const entry of node_fs.default.readdirSync(directory, { withFileTypes: true })) {
17
+ if (entry.name === "node_modules" || entry.name === ".git") continue;
18
+ const entryPath = node_path.default.join(directory, entry.name);
19
+ if (entry.isDirectory()) walkPackageJsonFiles(entryPath, out);
20
+ else if (entry.isFile() && entry.name === "package.json") out.push(entryPath);
21
+ }
22
+ return out;
23
+ }
24
+ function readJson(filePath) {
25
+ return JSON.parse(node_fs.default.readFileSync(filePath, "utf8"));
26
+ }
27
+ function collectConsumerDependencyNamesFromManifests(manifests) {
28
+ const names = /* @__PURE__ */ new Set();
29
+ for (const manifest of manifests) for (const field of DEPENDENCY_FIELDS) {
30
+ const dependencies = manifest[field];
31
+ for (const [name, specifier] of Object.entries(dependencies ?? {})) if (specifier.startsWith("catalog:") || name.startsWith("@m5kdev/") && specifier.startsWith("workspace:")) names.add(name);
32
+ }
33
+ return [...names].sort((left, right) => left.localeCompare(right));
34
+ }
35
+ function collectConsumerDependencyNames(packageFiles) {
36
+ return collectConsumerDependencyNamesFromManifests(packageFiles.map(readJson));
37
+ }
38
+ function buildConsumerCatalog(options) {
39
+ const workspacePath = node_path.default.join(options.repoRoot, "pnpm-workspace.yaml");
40
+ const sourceCatalog = (0, yaml.parse)(node_fs.default.readFileSync(workspacePath, "utf8")).catalog ?? {};
41
+ const names = collectConsumerDependencyNames([...walkPackageJsonFiles(options.starterDirectory), node_path.default.join(options.rootTemplatesDirectory, "package.json.tpl")]);
42
+ const catalog = {};
43
+ const missing = [];
44
+ for (const name of names) {
45
+ if (name.startsWith("@m5kdev/")) {
46
+ const packageName = name.slice(8);
47
+ const packagePath = node_path.default.join(options.repoRoot, "packages", packageName, "package.json");
48
+ if (!node_fs.default.existsSync(packagePath)) {
49
+ missing.push(name);
50
+ continue;
51
+ }
52
+ const packageManifest = readJson(packagePath);
53
+ if (typeof packageManifest.version !== "string") {
54
+ missing.push(name);
55
+ continue;
56
+ }
57
+ catalog[name] = packageManifest.version;
58
+ continue;
59
+ }
60
+ const version = sourceCatalog[name];
61
+ if (version === void 0) {
62
+ missing.push(name);
63
+ continue;
64
+ }
65
+ catalog[name] = String(version);
66
+ }
67
+ if (missing.length > 0) throw new Error(`Missing consumer catalog versions for: ${missing.join(", ")}`);
68
+ return catalog;
69
+ }
70
+ function renderConsumerWorkspace(source, catalog) {
71
+ const workspace = (0, yaml.parse)(source);
72
+ workspace.catalog = Object.fromEntries(Object.entries(catalog).sort(([left], [right]) => left.localeCompare(right)));
73
+ return (0, yaml.stringify)(workspace, { lineWidth: 0 });
74
+ }
75
+ function readCatalog(source) {
76
+ const workspace = (0, yaml.parse)(source);
77
+ return Object.fromEntries(Object.entries(workspace.catalog ?? {}).map(([name, version]) => [name, String(version)]));
78
+ }
79
+ function assertCatalogKeys(catalog, expectedNames, label = "consumer catalog") {
80
+ const expected = new Set(expectedNames);
81
+ const missing = expectedNames.filter((name) => !(name in catalog));
82
+ const obsolete = Object.keys(catalog).filter((name) => !expected.has(name));
83
+ if (missing.length > 0 || obsolete.length > 0) {
84
+ const details = [missing.length > 0 ? `missing: ${missing.join(", ")}` : void 0, obsolete.length > 0 ? `obsolete: ${obsolete.join(", ")}` : void 0].filter(Boolean);
85
+ throw new Error(`Invalid ${label} (${details.join("; ")})`);
86
+ }
87
+ }
88
+ function mergeManagedCatalog(options) {
89
+ const document = (0, yaml.parseDocument)(options.source);
90
+ const local = readCatalog(options.source);
91
+ const conflicts = [];
92
+ const names = new Set([...Object.keys(options.base), ...Object.keys(options.target)]);
93
+ for (const name of [...names].sort((left, right) => left.localeCompare(right))) {
94
+ const base = options.base[name];
95
+ const current = local[name];
96
+ const target = options.target[name];
97
+ if (base === void 0) {
98
+ if (current === void 0) document.setIn(["catalog", name], target);
99
+ else if (current !== target) conflicts.push({
100
+ name,
101
+ local: current,
102
+ target
103
+ });
104
+ continue;
105
+ }
106
+ if (target === void 0) {
107
+ if (current === base) document.deleteIn(["catalog", name]);
108
+ else if (current !== void 0) conflicts.push({
109
+ name,
110
+ base,
111
+ local: current
112
+ });
113
+ continue;
114
+ }
115
+ if (current === base) document.setIn(["catalog", name], target);
116
+ else if (current !== target && target !== base) conflicts.push({
117
+ name,
118
+ base,
119
+ local: current,
120
+ target
121
+ });
122
+ }
123
+ const merged = document.toString({ lineWidth: 0 });
124
+ return {
125
+ source: merged,
126
+ changed: merged !== options.source,
127
+ conflicts
128
+ };
129
+ }
130
+ //#endregion
131
+ exports.assertCatalogKeys = assertCatalogKeys;
132
+ exports.buildConsumerCatalog = buildConsumerCatalog;
133
+ exports.collectConsumerDependencyNames = collectConsumerDependencyNames;
134
+ exports.collectConsumerDependencyNamesFromManifests = collectConsumerDependencyNamesFromManifests;
135
+ exports.mergeManagedCatalog = mergeManagedCatalog;
136
+ exports.readCatalog = readCatalog;
137
+ exports.renderConsumerWorkspace = renderConsumerWorkspace;
138
+ exports.walkPackageJsonFiles = walkPackageJsonFiles;
139
+
140
+ //# sourceMappingURL=catalog.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"catalog.cjs","names":["fs","path"],"sources":["../../src/catalog.ts"],"sourcesContent":["import fs from \"node:fs\";\r\nimport path from \"node:path\";\r\nimport { parse, parseDocument, stringify } from \"yaml\";\r\n\r\nconst DEPENDENCY_FIELDS = [\r\n \"dependencies\",\r\n \"devDependencies\",\r\n \"peerDependencies\",\r\n \"optionalDependencies\",\r\n] as const;\r\n\r\nexport type ConsumerCatalog = Record<string, string>;\r\n\r\nexport function walkPackageJsonFiles(directory: string, out: string[] = []): string[] {\r\n for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {\r\n if (entry.name === \"node_modules\" || entry.name === \".git\") continue;\r\n const entryPath = path.join(directory, entry.name);\r\n if (entry.isDirectory()) {\r\n walkPackageJsonFiles(entryPath, out);\r\n } else if (entry.isFile() && entry.name === \"package.json\") {\r\n out.push(entryPath);\r\n }\r\n }\r\n return out;\r\n}\r\n\r\nfunction readJson(filePath: string): Record<string, unknown> {\r\n return JSON.parse(fs.readFileSync(filePath, \"utf8\")) as Record<string, unknown>;\r\n}\r\n\r\nexport function collectConsumerDependencyNamesFromManifests(\r\n manifests: readonly Record<string, unknown>[]\r\n): string[] {\r\n const names = new Set<string>();\r\n\r\n for (const manifest of manifests) {\r\n for (const field of DEPENDENCY_FIELDS) {\r\n const dependencies = manifest[field] as Record<string, string> | undefined;\r\n for (const [name, specifier] of Object.entries(dependencies ?? {})) {\r\n if (\r\n specifier.startsWith(\"catalog:\") ||\r\n (name.startsWith(\"@m5kdev/\") && specifier.startsWith(\"workspace:\"))\r\n ) {\r\n names.add(name);\r\n }\r\n }\r\n }\r\n }\r\n\r\n return [...names].sort((left, right) => left.localeCompare(right));\r\n}\r\n\r\nexport function collectConsumerDependencyNames(packageFiles: readonly string[]): string[] {\r\n return collectConsumerDependencyNamesFromManifests(packageFiles.map(readJson));\r\n}\r\n\r\nexport function buildConsumerCatalog(options: {\r\n repoRoot: string;\r\n starterDirectory: string;\r\n rootTemplatesDirectory: string;\r\n}): ConsumerCatalog {\r\n const workspacePath = path.join(options.repoRoot, \"pnpm-workspace.yaml\");\r\n const workspace = parse(fs.readFileSync(workspacePath, \"utf8\")) as {\r\n catalog?: Record<string, string | number>;\r\n };\r\n const sourceCatalog = workspace.catalog ?? {};\r\n const packageFiles = [\r\n ...walkPackageJsonFiles(options.starterDirectory),\r\n path.join(options.rootTemplatesDirectory, \"package.json.tpl\"),\r\n ];\r\n const names = collectConsumerDependencyNames(packageFiles);\r\n const catalog: ConsumerCatalog = {};\r\n const missing: string[] = [];\r\n\r\n for (const name of names) {\r\n if (name.startsWith(\"@m5kdev/\")) {\r\n const packageName = name.slice(\"@m5kdev/\".length);\r\n const packagePath = path.join(options.repoRoot, \"packages\", packageName, \"package.json\");\r\n if (!fs.existsSync(packagePath)) {\r\n missing.push(name);\r\n continue;\r\n }\r\n const packageManifest = readJson(packagePath);\r\n if (typeof packageManifest.version !== \"string\") {\r\n missing.push(name);\r\n continue;\r\n }\r\n catalog[name] = packageManifest.version;\r\n continue;\r\n }\r\n\r\n const version = sourceCatalog[name];\r\n if (version === undefined) {\r\n missing.push(name);\r\n continue;\r\n }\r\n catalog[name] = String(version);\r\n }\r\n\r\n if (missing.length > 0) {\r\n throw new Error(`Missing consumer catalog versions for: ${missing.join(\", \")}`);\r\n }\r\n\r\n return catalog;\r\n}\r\n\r\nexport function renderConsumerWorkspace(source: string, catalog: ConsumerCatalog): string {\r\n const workspace = parse(source) as Record<string, unknown>;\r\n workspace.catalog = Object.fromEntries(\r\n Object.entries(catalog).sort(([left], [right]) => left.localeCompare(right))\r\n );\r\n return stringify(workspace, { lineWidth: 0 });\r\n}\r\n\r\nexport function readCatalog(source: string): ConsumerCatalog {\r\n const workspace = parse(source) as { catalog?: Record<string, string | number> };\r\n return Object.fromEntries(\r\n Object.entries(workspace.catalog ?? {}).map(([name, version]) => [name, String(version)])\r\n );\r\n}\r\n\r\nexport function assertCatalogKeys(\r\n catalog: ConsumerCatalog,\r\n expectedNames: readonly string[],\r\n label = \"consumer catalog\"\r\n): void {\r\n const expected = new Set(expectedNames);\r\n const missing = expectedNames.filter((name) => !(name in catalog));\r\n const obsolete = Object.keys(catalog).filter((name) => !expected.has(name));\r\n if (missing.length > 0 || obsolete.length > 0) {\r\n const details = [\r\n missing.length > 0 ? `missing: ${missing.join(\", \")}` : undefined,\r\n obsolete.length > 0 ? `obsolete: ${obsolete.join(\", \")}` : undefined,\r\n ].filter(Boolean);\r\n throw new Error(`Invalid ${label} (${details.join(\"; \")})`);\r\n }\r\n}\r\n\r\nexport interface CatalogMergeConflict {\r\n name: string;\r\n base?: string;\r\n local?: string;\r\n target?: string;\r\n}\r\n\r\nexport function mergeManagedCatalog(options: {\r\n source: string;\r\n base: ConsumerCatalog;\r\n target: ConsumerCatalog;\r\n}): { source: string; changed: boolean; conflicts: CatalogMergeConflict[] } {\r\n const document = parseDocument(options.source);\r\n const local = readCatalog(options.source);\r\n const conflicts: CatalogMergeConflict[] = [];\r\n const names = new Set([...Object.keys(options.base), ...Object.keys(options.target)]);\r\n\r\n for (const name of [...names].sort((left, right) => left.localeCompare(right))) {\r\n const base = options.base[name];\r\n const current = local[name];\r\n const target = options.target[name];\r\n\r\n if (base === undefined) {\r\n if (current === undefined) document.setIn([\"catalog\", name], target);\r\n else if (current !== target) conflicts.push({ name, local: current, target });\r\n continue;\r\n }\r\n if (target === undefined) {\r\n if (current === base) document.deleteIn([\"catalog\", name]);\r\n else if (current !== undefined) conflicts.push({ name, base, local: current });\r\n continue;\r\n }\r\n if (current === base) document.setIn([\"catalog\", name], target);\r\n else if (current !== target && target !== base) {\r\n conflicts.push({ name, base, local: current, target });\r\n }\r\n }\r\n\r\n const merged = document.toString({ lineWidth: 0 });\r\n return { source: merged, changed: merged !== options.source, conflicts };\r\n}\r\n"],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ //#region src/catalog.d.ts
2
+ type ConsumerCatalog = Record<string, string>;
3
+ declare function walkPackageJsonFiles(directory: string, out?: string[]): string[];
4
+ declare function collectConsumerDependencyNamesFromManifests(manifests: readonly Record<string, unknown>[]): string[];
5
+ declare function collectConsumerDependencyNames(packageFiles: readonly string[]): string[];
6
+ declare function buildConsumerCatalog(options: {
7
+ repoRoot: string;
8
+ starterDirectory: string;
9
+ rootTemplatesDirectory: string;
10
+ }): ConsumerCatalog;
11
+ declare function renderConsumerWorkspace(source: string, catalog: ConsumerCatalog): string;
12
+ declare function readCatalog(source: string): ConsumerCatalog;
13
+ declare function assertCatalogKeys(catalog: ConsumerCatalog, expectedNames: readonly string[], label?: string): void;
14
+ interface CatalogMergeConflict {
15
+ name: string;
16
+ base?: string;
17
+ local?: string;
18
+ target?: string;
19
+ }
20
+ declare function mergeManagedCatalog(options: {
21
+ source: string;
22
+ base: ConsumerCatalog;
23
+ target: ConsumerCatalog;
24
+ }): {
25
+ source: string;
26
+ changed: boolean;
27
+ conflicts: CatalogMergeConflict[];
28
+ };
29
+ //#endregion
30
+ export { CatalogMergeConflict, ConsumerCatalog, assertCatalogKeys, buildConsumerCatalog, collectConsumerDependencyNames, collectConsumerDependencyNamesFromManifests, mergeManagedCatalog, readCatalog, renderConsumerWorkspace, walkPackageJsonFiles };
31
+ //# sourceMappingURL=catalog.d.cts.map
@@ -0,0 +1,70 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_runtime = require("../_virtual/_rolldown/runtime.cjs");
3
+ let node_path = require("node:path");
4
+ node_path = require_runtime.__toESM(node_path);
5
+ let node_fs_promises = require("node:fs/promises");
6
+ node_fs_promises = require_runtime.__toESM(node_fs_promises);
7
+ //#region src/changes.ts
8
+ function safePath(repoRoot, relativePath) {
9
+ if (node_path.default.isAbsolute(relativePath)) throw new Error(`Absolute change path is not allowed: ${relativePath}`);
10
+ const normalized = node_path.default.posix.normalize(relativePath.split("\\").join("/"));
11
+ if (normalized === ".." || normalized.startsWith("../")) throw new Error(`Change path escapes the repository: ${relativePath}`);
12
+ const resolved = node_path.default.resolve(repoRoot, normalized);
13
+ if (resolved !== repoRoot && !resolved.startsWith(`${repoRoot}${node_path.default.sep}`)) throw new Error(`Change path escapes the repository: ${relativePath}`);
14
+ return resolved;
15
+ }
16
+ async function findRepositorySymlink(repoRoot, relativePath) {
17
+ safePath(repoRoot, relativePath);
18
+ const normalized = node_path.default.posix.normalize(relativePath.split("\\").join("/"));
19
+ let current = node_path.default.resolve(repoRoot);
20
+ let currentRelative = "";
21
+ for (const segment of normalized.split("/")) {
22
+ current = node_path.default.join(current, segment);
23
+ currentRelative = currentRelative ? `${currentRelative}/${segment}` : segment;
24
+ const stat = await node_fs_promises.default.lstat(current).catch(() => null);
25
+ if (!stat) return void 0;
26
+ if (stat.isSymbolicLink()) return currentRelative;
27
+ }
28
+ }
29
+ var ChangeSet = class {
30
+ constructor(repoRoot) {
31
+ this.repoRoot = repoRoot;
32
+ this.changes = /* @__PURE__ */ new Map();
33
+ this.conflicts = [];
34
+ }
35
+ addChange(change) {
36
+ safePath(this.repoRoot, change.path);
37
+ this.changes.set(change.path, change);
38
+ }
39
+ addConflict(conflict) {
40
+ safePath(this.repoRoot, conflict.path);
41
+ this.conflicts.push(conflict);
42
+ }
43
+ async read(pathName) {
44
+ const planned = this.changes.get(pathName);
45
+ if (planned) return planned.kind === "delete" ? void 0 : planned.content;
46
+ const symlink = await findRepositorySymlink(this.repoRoot, pathName);
47
+ if (symlink) throw new Error(`Refusing to read through symlink: ${symlink}`);
48
+ return node_fs_promises.default.readFile(safePath(this.repoRoot, pathName)).catch(() => void 0);
49
+ }
50
+ async apply() {
51
+ if (this.conflicts.length > 0) throw new Error("Cannot apply a change set with conflicts.");
52
+ const changes = [...this.changes.values()].sort((left, right) => left.path.localeCompare(right.path));
53
+ for (const change of changes) {
54
+ const target = safePath(this.repoRoot, change.path);
55
+ const symlink = await findRepositorySymlink(this.repoRoot, change.path);
56
+ if (symlink) throw new Error(`Refusing to write through symlink: ${symlink}`);
57
+ if (change.kind === "delete") {
58
+ await node_fs_promises.default.rm(target, { force: true });
59
+ continue;
60
+ }
61
+ await node_fs_promises.default.mkdir(node_path.default.dirname(target), { recursive: true });
62
+ await node_fs_promises.default.writeFile(target, change.content ?? Buffer.alloc(0));
63
+ }
64
+ }
65
+ };
66
+ //#endregion
67
+ exports.ChangeSet = ChangeSet;
68
+ exports.findRepositorySymlink = findRepositorySymlink;
69
+
70
+ //# sourceMappingURL=changes.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"changes.cjs","names":["path","fs"],"sources":["../../src/changes.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\r\nimport path from \"node:path\";\r\n\r\nexport type PlannedChangeKind = \"add\" | \"modify\" | \"delete\";\r\n\r\nexport interface PlannedChange {\r\n kind: PlannedChangeKind;\r\n path: string;\r\n content?: Buffer;\r\n reason: string;\r\n}\r\n\r\nexport interface PlannedConflict {\r\n path: string;\r\n reason: string;\r\n}\r\n\r\nfunction safePath(repoRoot: string, relativePath: string): string {\r\n if (path.isAbsolute(relativePath))\r\n throw new Error(`Absolute change path is not allowed: ${relativePath}`);\r\n const normalized = path.posix.normalize(relativePath.split(\"\\\\\").join(\"/\"));\r\n if (normalized === \"..\" || normalized.startsWith(\"../\")) {\r\n throw new Error(`Change path escapes the repository: ${relativePath}`);\r\n }\r\n const resolved = path.resolve(repoRoot, normalized);\r\n if (resolved !== repoRoot && !resolved.startsWith(`${repoRoot}${path.sep}`)) {\r\n throw new Error(`Change path escapes the repository: ${relativePath}`);\r\n }\r\n return resolved;\r\n}\r\n\r\nexport async function findRepositorySymlink(\r\n repoRoot: string,\r\n relativePath: string\r\n): Promise<string | undefined> {\r\n safePath(repoRoot, relativePath);\r\n const normalized = path.posix.normalize(relativePath.split(\"\\\\\").join(\"/\"));\r\n let current = path.resolve(repoRoot);\r\n let currentRelative = \"\";\r\n for (const segment of normalized.split(\"/\")) {\r\n current = path.join(current, segment);\r\n currentRelative = currentRelative ? `${currentRelative}/${segment}` : segment;\r\n const stat = await fs.lstat(current).catch(() => null);\r\n if (!stat) return undefined;\r\n if (stat.isSymbolicLink()) return currentRelative;\r\n }\r\n return undefined;\r\n}\r\n\r\nexport class ChangeSet {\r\n readonly changes = new Map<string, PlannedChange>();\r\n readonly conflicts: PlannedConflict[] = [];\r\n\r\n constructor(readonly repoRoot: string) {}\r\n\r\n addChange(change: PlannedChange): void {\r\n safePath(this.repoRoot, change.path);\r\n this.changes.set(change.path, change);\r\n }\r\n\r\n addConflict(conflict: PlannedConflict): void {\r\n safePath(this.repoRoot, conflict.path);\r\n this.conflicts.push(conflict);\r\n }\r\n\r\n async read(pathName: string): Promise<Buffer | undefined> {\r\n const planned = this.changes.get(pathName);\r\n if (planned) return planned.kind === \"delete\" ? undefined : planned.content;\r\n const symlink = await findRepositorySymlink(this.repoRoot, pathName);\r\n if (symlink) throw new Error(`Refusing to read through symlink: ${symlink}`);\r\n return fs.readFile(safePath(this.repoRoot, pathName)).catch(() => undefined);\r\n }\r\n\r\n async apply(): Promise<void> {\r\n if (this.conflicts.length > 0) throw new Error(\"Cannot apply a change set with conflicts.\");\r\n const changes = [...this.changes.values()].sort((left, right) =>\r\n left.path.localeCompare(right.path)\r\n );\r\n for (const change of changes) {\r\n const target = safePath(this.repoRoot, change.path);\r\n const symlink = await findRepositorySymlink(this.repoRoot, change.path);\r\n if (symlink) throw new Error(`Refusing to write through symlink: ${symlink}`);\r\n if (change.kind === \"delete\") {\r\n await fs.rm(target, { force: true });\r\n continue;\r\n }\r\n await fs.mkdir(path.dirname(target), { recursive: true });\r\n await fs.writeFile(target, change.content ?? Buffer.alloc(0));\r\n }\r\n }\r\n}\r\n"],"mappings":";;;;;;;AAiBA,SAAS,SAAS,UAAkB,cAA8B;AAChE,KAAIA,UAAAA,QAAK,WAAW,aAAa,CAC/B,OAAM,IAAI,MAAM,wCAAwC,eAAe;CACzE,MAAM,aAAaA,UAAAA,QAAK,MAAM,UAAU,aAAa,MAAM,KAAK,CAAC,KAAK,IAAI,CAAC;AAC3E,KAAI,eAAe,QAAQ,WAAW,WAAW,MAAM,CACrD,OAAM,IAAI,MAAM,uCAAuC,eAAe;CAExE,MAAM,WAAWA,UAAAA,QAAK,QAAQ,UAAU,WAAW;AACnD,KAAI,aAAa,YAAY,CAAC,SAAS,WAAW,GAAG,WAAWA,UAAAA,QAAK,MAAM,CACzE,OAAM,IAAI,MAAM,uCAAuC,eAAe;AAExE,QAAO;;AAGT,eAAsB,sBACpB,UACA,cAC6B;AAC7B,UAAS,UAAU,aAAa;CAChC,MAAM,aAAaA,UAAAA,QAAK,MAAM,UAAU,aAAa,MAAM,KAAK,CAAC,KAAK,IAAI,CAAC;CAC3E,IAAI,UAAUA,UAAAA,QAAK,QAAQ,SAAS;CACpC,IAAI,kBAAkB;AACtB,MAAK,MAAM,WAAW,WAAW,MAAM,IAAI,EAAE;AAC3C,YAAUA,UAAAA,QAAK,KAAK,SAAS,QAAQ;AACrC,oBAAkB,kBAAkB,GAAG,gBAAgB,GAAG,YAAY;EACtE,MAAM,OAAO,MAAMC,iBAAAA,QAAG,MAAM,QAAQ,CAAC,YAAY,KAAK;AACtD,MAAI,CAAC,KAAM,QAAO,KAAA;AAClB,MAAI,KAAK,gBAAgB,CAAE,QAAO;;;AAKtC,IAAa,YAAb,MAAuB;CAIrB,YAAY,UAA2B;AAAlB,OAAA,WAAA;iCAHF,IAAI,KAA4B;mBACX,EAAE;;CAI1C,UAAU,QAA6B;AACrC,WAAS,KAAK,UAAU,OAAO,KAAK;AACpC,OAAK,QAAQ,IAAI,OAAO,MAAM,OAAO;;CAGvC,YAAY,UAAiC;AAC3C,WAAS,KAAK,UAAU,SAAS,KAAK;AACtC,OAAK,UAAU,KAAK,SAAS;;CAG/B,MAAM,KAAK,UAA+C;EACxD,MAAM,UAAU,KAAK,QAAQ,IAAI,SAAS;AAC1C,MAAI,QAAS,QAAO,QAAQ,SAAS,WAAW,KAAA,IAAY,QAAQ;EACpE,MAAM,UAAU,MAAM,sBAAsB,KAAK,UAAU,SAAS;AACpE,MAAI,QAAS,OAAM,IAAI,MAAM,qCAAqC,UAAU;AAC5E,SAAOA,iBAAAA,QAAG,SAAS,SAAS,KAAK,UAAU,SAAS,CAAC,CAAC,YAAY,KAAA,EAAU;;CAG9E,MAAM,QAAuB;AAC3B,MAAI,KAAK,UAAU,SAAS,EAAG,OAAM,IAAI,MAAM,4CAA4C;EAC3F,MAAM,UAAU,CAAC,GAAG,KAAK,QAAQ,QAAQ,CAAC,CAAC,MAAM,MAAM,UACrD,KAAK,KAAK,cAAc,MAAM,KAAK,CACpC;AACD,OAAK,MAAM,UAAU,SAAS;GAC5B,MAAM,SAAS,SAAS,KAAK,UAAU,OAAO,KAAK;GACnD,MAAM,UAAU,MAAM,sBAAsB,KAAK,UAAU,OAAO,KAAK;AACvE,OAAI,QAAS,OAAM,IAAI,MAAM,sCAAsC,UAAU;AAC7E,OAAI,OAAO,SAAS,UAAU;AAC5B,UAAMA,iBAAAA,QAAG,GAAG,QAAQ,EAAE,OAAO,MAAM,CAAC;AACpC;;AAEF,SAAMA,iBAAAA,QAAG,MAAMD,UAAAA,QAAK,QAAQ,OAAO,EAAE,EAAE,WAAW,MAAM,CAAC;AACzD,SAAMC,iBAAAA,QAAG,UAAU,QAAQ,OAAO,WAAW,OAAO,MAAM,EAAE,CAAC"}
@@ -0,0 +1,26 @@
1
+ //#region src/changes.d.ts
2
+ type PlannedChangeKind = "add" | "modify" | "delete";
3
+ interface PlannedChange {
4
+ kind: PlannedChangeKind;
5
+ path: string;
6
+ content?: Buffer;
7
+ reason: string;
8
+ }
9
+ interface PlannedConflict {
10
+ path: string;
11
+ reason: string;
12
+ }
13
+ declare function findRepositorySymlink(repoRoot: string, relativePath: string): Promise<string | undefined>;
14
+ declare class ChangeSet {
15
+ readonly repoRoot: string;
16
+ readonly changes: Map<string, PlannedChange>;
17
+ readonly conflicts: PlannedConflict[];
18
+ constructor(repoRoot: string);
19
+ addChange(change: PlannedChange): void;
20
+ addConflict(conflict: PlannedConflict): void;
21
+ read(pathName: string): Promise<Buffer | undefined>;
22
+ apply(): Promise<void>;
23
+ }
24
+ //#endregion
25
+ export { ChangeSet, PlannedChange, PlannedChangeKind, PlannedConflict, findRepositorySymlink };
26
+ //# sourceMappingURL=changes.d.cts.map
@@ -5,40 +5,54 @@ const require_src_strings = require("./strings.cjs");
5
5
  const require_src_fs = require("./fs.cjs");
6
6
  const require_src_paths = require("./paths.cjs");
7
7
  const require_src_prompts = require("./prompts.cjs");
8
- let node_fs = require("node:fs");
9
- node_fs = require_runtime.__toESM(node_fs);
8
+ const require_src_template = require("./template.cjs");
9
+ const require_src_state = require("./state.cjs");
10
10
  let node_path = require("node:path");
11
11
  node_path = require_runtime.__toESM(node_path);
12
+ let node_fs_promises = require("node:fs/promises");
13
+ node_fs_promises = require_runtime.__toESM(node_fs_promises);
12
14
  //#region src/create.ts
13
- function loadFeatureManifest(templateDirectory) {
14
- const manifestPath = node_path.default.join(templateDirectory, "template.manifest.json");
15
- if (!node_fs.default.existsSync(manifestPath)) return { features: {} };
16
- return JSON.parse(node_fs.default.readFileSync(manifestPath, "utf8"));
17
- }
18
15
  async function scaffoldProject(initialOptions) {
19
16
  const options = await require_src_prompts.resolveCreateCommandOptions(initialOptions);
20
- const appSlug = require_src_strings.slugifyAppName(options.appName);
21
- const targetDirectory = node_path.default.resolve(process.cwd(), options.targetDirectory);
17
+ const { appName, appDescription, targetDirectory: targetDirectoryOption } = options;
18
+ if (!appName || !appDescription || !targetDirectoryOption) throw new Error("Unable to resolve the required create options.");
19
+ const appSlug = require_src_strings.slugifyAppName(appName);
20
+ const targetDirectory = node_path.default.resolve(process.cwd(), targetDirectoryOption);
22
21
  const templateDirectory = require_src_paths.getTemplateRoot();
23
22
  const context = {
24
- appName: options.appName,
25
- appDescription: options.appDescription,
23
+ appName,
24
+ appDescription,
26
25
  appSlug,
27
26
  packageScope: require_src_strings.derivePackageScope(appSlug),
28
27
  betterAuthSecret: require_src_strings.createBetterAuthSecret()
29
28
  };
30
- const platform = options.platform ?? "web";
31
- const enabledFeatures = /* @__PURE__ */ new Set();
32
- if (platform !== "expo") enabledFeatures.add("webapp");
33
- if (platform !== "web") enabledFeatures.add("expo");
34
- if (options.testHarness) enabledFeatures.add("test-harness");
35
- const manifest = loadFeatureManifest(templateDirectory);
36
- const excludePrefixes = Object.entries(manifest.features).filter(([feature]) => !enabledFeatures.has(feature)).flatMap(([, config]) => config.paths);
37
- await require_src_fs.ensureDirectoryState(targetDirectory, options.force);
38
- await require_src_fs.copyTemplateDirectory(templateDirectory, targetDirectory, context, {
39
- excludePrefixes,
40
- enabledFeatures
41
- });
29
+ const enabledFeatures = require_src_template.getEnabledFeatures(options.platform ?? "web", Boolean(options.testHarness));
30
+ const manifest = require_src_template.loadTemplateManifest(templateDirectory);
31
+ const excludePrefixes = require_src_template.getExcludedFeaturePaths(manifest, enabledFeatures);
32
+ const createdTargetDirectory = await require_src_fs.ensureDirectoryState(targetDirectory, options.force);
33
+ try {
34
+ await require_src_fs.copyTemplateDirectory(templateDirectory, targetDirectory, context, {
35
+ excludePrefixes,
36
+ enabledFeatures
37
+ });
38
+ const renderedFiles = await require_src_fs.collectTemplateFiles(templateDirectory, context, {
39
+ excludePrefixes,
40
+ enabledFeatures
41
+ });
42
+ await require_src_state.writeManagedState(targetDirectory, require_src_state.createManagedState({
43
+ templateVersion: require_src_state.getCliVersion(),
44
+ enabledFeatures,
45
+ context,
46
+ renderedFiles,
47
+ manifest
48
+ }));
49
+ } catch (error) {
50
+ if (createdTargetDirectory) await node_fs_promises.default.rm(targetDirectory, {
51
+ recursive: true,
52
+ force: true
53
+ });
54
+ throw error;
55
+ }
42
56
  if (!options.skipGit) await require_src_fs.runGitInit(targetDirectory);
43
57
  if (!options.skipInstall) await require_src_fs.runInstall(targetDirectory);
44
58
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"create.cjs","names":["path","fs","resolveCreateCommandOptions","slugifyAppName","getTemplateRoot","derivePackageScope","createBetterAuthSecret","ensureDirectoryState","copyTemplateDirectory","runGitInit","runInstall","TEMPLATE_NAME"],"sources":["../../src/create.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { TEMPLATE_NAME } from \"./constants\";\nimport { copyTemplateDirectory, ensureDirectoryState, runGitInit, runInstall } from \"./fs\";\nimport { getTemplateRoot } from \"./paths\";\nimport { resolveCreateCommandOptions } from \"./prompts\";\nimport { createBetterAuthSecret, derivePackageScope, slugifyAppName } from \"./strings\";\nimport type {\n CreateCommandOptions,\n TemplateContext,\n TemplateFeatureManifest,\n} from \"./types\";\n\nexport interface ScaffoldResult {\n context: TemplateContext;\n targetDirectory: string;\n templateName: string;\n}\n\nfunction loadFeatureManifest(templateDirectory: string): TemplateFeatureManifest {\n const manifestPath = path.join(templateDirectory, \"template.manifest.json\");\n if (!fs.existsSync(manifestPath)) {\n return { features: {} };\n }\n return JSON.parse(fs.readFileSync(manifestPath, \"utf8\")) as TemplateFeatureManifest;\n}\n\nexport async function scaffoldProject(initialOptions: CreateCommandOptions): Promise<ScaffoldResult> {\n const options = await resolveCreateCommandOptions(initialOptions);\n const appSlug = slugifyAppName(options.appName!);\n const targetDirectory = path.resolve(process.cwd(), options.targetDirectory!);\n const templateDirectory = getTemplateRoot();\n\n const context: TemplateContext = {\n appName: options.appName!,\n appDescription: options.appDescription!,\n appSlug,\n packageScope: derivePackageScope(appSlug),\n betterAuthSecret: createBetterAuthSecret(),\n };\n\n const platform = options.platform ?? \"web\";\n const enabledFeatures = new Set<string>();\n if (platform !== \"expo\") enabledFeatures.add(\"webapp\");\n if (platform !== \"web\") enabledFeatures.add(\"expo\");\n if (options.testHarness) enabledFeatures.add(\"test-harness\");\n\n const manifest = loadFeatureManifest(templateDirectory);\n const excludePrefixes = Object.entries(manifest.features)\n .filter(([feature]) => !enabledFeatures.has(feature))\n .flatMap(([, config]) => config.paths);\n\n await ensureDirectoryState(targetDirectory, options.force);\n await copyTemplateDirectory(templateDirectory, targetDirectory, context, {\n excludePrefixes,\n enabledFeatures,\n });\n\n if (!options.skipGit) {\n await runGitInit(targetDirectory);\n }\n\n if (!options.skipInstall) {\n await runInstall(targetDirectory);\n }\n\n return {\n context,\n targetDirectory,\n templateName: TEMPLATE_NAME,\n };\n}\n"],"mappings":";;;;;;;;;;;;AAmBA,SAAS,oBAAoB,mBAAoD;CAC/E,MAAM,eAAeA,UAAAA,QAAK,KAAK,mBAAmB,yBAAyB;AAC3E,KAAI,CAACC,QAAAA,QAAG,WAAW,aAAa,CAC9B,QAAO,EAAE,UAAU,EAAE,EAAE;AAEzB,QAAO,KAAK,MAAMA,QAAAA,QAAG,aAAa,cAAc,OAAO,CAAC;;AAG1D,eAAsB,gBAAgB,gBAA+D;CACnG,MAAM,UAAU,MAAMC,oBAAAA,4BAA4B,eAAe;CACjE,MAAM,UAAUC,oBAAAA,eAAe,QAAQ,QAAS;CAChD,MAAM,kBAAkBH,UAAAA,QAAK,QAAQ,QAAQ,KAAK,EAAE,QAAQ,gBAAiB;CAC7E,MAAM,oBAAoBI,kBAAAA,iBAAiB;CAE3C,MAAM,UAA2B;EAC/B,SAAS,QAAQ;EACjB,gBAAgB,QAAQ;EACxB;EACA,cAAcC,oBAAAA,mBAAmB,QAAQ;EACzC,kBAAkBC,oBAAAA,wBAAwB;EAC3C;CAED,MAAM,WAAW,QAAQ,YAAY;CACrC,MAAM,kCAAkB,IAAI,KAAa;AACzC,KAAI,aAAa,OAAQ,iBAAgB,IAAI,SAAS;AACtD,KAAI,aAAa,MAAO,iBAAgB,IAAI,OAAO;AACnD,KAAI,QAAQ,YAAa,iBAAgB,IAAI,eAAe;CAE5D,MAAM,WAAW,oBAAoB,kBAAkB;CACvD,MAAM,kBAAkB,OAAO,QAAQ,SAAS,SAAS,CACtD,QAAQ,CAAC,aAAa,CAAC,gBAAgB,IAAI,QAAQ,CAAC,CACpD,SAAS,GAAG,YAAY,OAAO,MAAM;AAExC,OAAMC,eAAAA,qBAAqB,iBAAiB,QAAQ,MAAM;AAC1D,OAAMC,eAAAA,sBAAsB,mBAAmB,iBAAiB,SAAS;EACvE;EACA;EACD,CAAC;AAEF,KAAI,CAAC,QAAQ,QACX,OAAMC,eAAAA,WAAW,gBAAgB;AAGnC,KAAI,CAAC,QAAQ,YACX,OAAMC,eAAAA,WAAW,gBAAgB;AAGnC,QAAO;EACL;EACA;EACA,cAAcC,sBAAAA;EACf"}
1
+ {"version":3,"file":"create.cjs","names":["resolveCreateCommandOptions","slugifyAppName","path","getTemplateRoot","derivePackageScope","createBetterAuthSecret","getEnabledFeatures","loadTemplateManifest","getExcludedFeaturePaths","ensureDirectoryState","copyTemplateDirectory","collectTemplateFiles","writeManagedState","createManagedState","getCliVersion","fs","runGitInit","runInstall","TEMPLATE_NAME"],"sources":["../../src/create.ts"],"sourcesContent":["import fs from \"node:fs/promises\";\r\nimport path from \"node:path\";\r\nimport { TEMPLATE_NAME } from \"./constants\";\r\nimport {\r\n collectTemplateFiles,\r\n copyTemplateDirectory,\r\n ensureDirectoryState,\r\n runGitInit,\r\n runInstall,\r\n} from \"./fs\";\r\nimport { getTemplateRoot } from \"./paths\";\r\nimport { resolveCreateCommandOptions } from \"./prompts\";\r\nimport { createManagedState, getCliVersion, writeManagedState } from \"./state\";\r\nimport { createBetterAuthSecret, derivePackageScope, slugifyAppName } from \"./strings\";\r\nimport { getEnabledFeatures, getExcludedFeaturePaths, loadTemplateManifest } from \"./template\";\r\nimport type { CreateCommandOptions, TemplateContext } from \"./types\";\r\n\r\nexport interface ScaffoldResult {\r\n context: TemplateContext;\r\n targetDirectory: string;\r\n templateName: string;\r\n}\r\n\r\nexport async function scaffoldProject(\r\n initialOptions: CreateCommandOptions\r\n): Promise<ScaffoldResult> {\r\n const options = await resolveCreateCommandOptions(initialOptions);\r\n const { appName, appDescription, targetDirectory: targetDirectoryOption } = options;\r\n if (!appName || !appDescription || !targetDirectoryOption) {\r\n throw new Error(\"Unable to resolve the required create options.\");\r\n }\r\n const appSlug = slugifyAppName(appName);\r\n const targetDirectory = path.resolve(process.cwd(), targetDirectoryOption);\r\n const templateDirectory = getTemplateRoot();\r\n\r\n const context: TemplateContext = {\r\n appName,\r\n appDescription,\r\n appSlug,\r\n packageScope: derivePackageScope(appSlug),\r\n betterAuthSecret: createBetterAuthSecret(),\r\n };\r\n\r\n const enabledFeatures = getEnabledFeatures(\r\n options.platform ?? \"web\",\r\n Boolean(options.testHarness)\r\n );\r\n const manifest = loadTemplateManifest(templateDirectory);\r\n const excludePrefixes = getExcludedFeaturePaths(manifest, enabledFeatures);\r\n\r\n const createdTargetDirectory = await ensureDirectoryState(targetDirectory, options.force);\r\n try {\r\n await copyTemplateDirectory(templateDirectory, targetDirectory, context, {\r\n excludePrefixes,\r\n enabledFeatures,\r\n });\r\n const renderedFiles = await collectTemplateFiles(templateDirectory, context, {\r\n excludePrefixes,\r\n enabledFeatures,\r\n });\r\n await writeManagedState(\r\n targetDirectory,\r\n createManagedState({\r\n templateVersion: getCliVersion(),\r\n enabledFeatures,\r\n context,\r\n renderedFiles,\r\n manifest,\r\n })\r\n );\r\n } catch (error) {\r\n if (createdTargetDirectory) {\r\n await fs.rm(targetDirectory, { recursive: true, force: true });\r\n }\r\n throw error;\r\n }\r\n\r\n if (!options.skipGit) {\r\n await runGitInit(targetDirectory);\r\n }\r\n\r\n if (!options.skipInstall) {\r\n await runInstall(targetDirectory);\r\n }\r\n\r\n return {\r\n context,\r\n targetDirectory,\r\n templateName: TEMPLATE_NAME,\r\n };\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;AAuBA,eAAsB,gBACpB,gBACyB;CACzB,MAAM,UAAU,MAAMA,oBAAAA,4BAA4B,eAAe;CACjE,MAAM,EAAE,SAAS,gBAAgB,iBAAiB,0BAA0B;AAC5E,KAAI,CAAC,WAAW,CAAC,kBAAkB,CAAC,sBAClC,OAAM,IAAI,MAAM,iDAAiD;CAEnE,MAAM,UAAUC,oBAAAA,eAAe,QAAQ;CACvC,MAAM,kBAAkBC,UAAAA,QAAK,QAAQ,QAAQ,KAAK,EAAE,sBAAsB;CAC1E,MAAM,oBAAoBC,kBAAAA,iBAAiB;CAE3C,MAAM,UAA2B;EAC/B;EACA;EACA;EACA,cAAcC,oBAAAA,mBAAmB,QAAQ;EACzC,kBAAkBC,oBAAAA,wBAAwB;EAC3C;CAED,MAAM,kBAAkBC,qBAAAA,mBACtB,QAAQ,YAAY,OACpB,QAAQ,QAAQ,YAAY,CAC7B;CACD,MAAM,WAAWC,qBAAAA,qBAAqB,kBAAkB;CACxD,MAAM,kBAAkBC,qBAAAA,wBAAwB,UAAU,gBAAgB;CAE1E,MAAM,yBAAyB,MAAMC,eAAAA,qBAAqB,iBAAiB,QAAQ,MAAM;AACzF,KAAI;AACF,QAAMC,eAAAA,sBAAsB,mBAAmB,iBAAiB,SAAS;GACvE;GACA;GACD,CAAC;EACF,MAAM,gBAAgB,MAAMC,eAAAA,qBAAqB,mBAAmB,SAAS;GAC3E;GACA;GACD,CAAC;AACF,QAAMC,kBAAAA,kBACJ,iBACAC,kBAAAA,mBAAmB;GACjB,iBAAiBC,kBAAAA,eAAe;GAChC;GACA;GACA;GACA;GACD,CAAC,CACH;UACM,OAAO;AACd,MAAI,uBACF,OAAMC,iBAAAA,QAAG,GAAG,iBAAiB;GAAE,WAAW;GAAM,OAAO;GAAM,CAAC;AAEhE,QAAM;;AAGR,KAAI,CAAC,QAAQ,QACX,OAAMC,eAAAA,WAAW,gBAAgB;AAGnC,KAAI,CAAC,QAAQ,YACX,OAAMC,eAAAA,WAAW,gBAAgB;AAGnC,QAAO;EACL;EACA;EACA,cAAcC,sBAAAA;EACf"}
@@ -0,0 +1,33 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/diagnostics.ts
3
+ function createDiagnosticReport(diagnostics) {
4
+ return {
5
+ ok: !diagnostics.some((diagnostic) => diagnostic.severity === "error"),
6
+ diagnostics
7
+ };
8
+ }
9
+ function printDiagnosticReport(report) {
10
+ for (const [severity, title] of [
11
+ ["error", "Errors"],
12
+ ["warning", "Warnings"],
13
+ ["info", "Information"]
14
+ ]) {
15
+ const entries = report.diagnostics.filter((diagnostic) => diagnostic.severity === severity);
16
+ if (entries.length === 0) continue;
17
+ console.log(`${title}:`);
18
+ for (const diagnostic of entries) {
19
+ const location = diagnostic.path ? ` (${diagnostic.path})` : "";
20
+ console.log(` [${diagnostic.code}] ${diagnostic.message}${location}`);
21
+ if (diagnostic.migrationId) console.log(` migration: ${diagnostic.migrationId}`);
22
+ if (diagnostic.guide) console.log(` guide: ${diagnostic.guide}`);
23
+ if (diagnostic.suggestion) console.log(` ${diagnostic.suggestion}`);
24
+ }
25
+ console.log("");
26
+ }
27
+ if (report.diagnostics.length === 0) console.log("No issues found.");
28
+ }
29
+ //#endregion
30
+ exports.createDiagnosticReport = createDiagnosticReport;
31
+ exports.printDiagnosticReport = printDiagnosticReport;
32
+
33
+ //# sourceMappingURL=diagnostics.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnostics.cjs","names":[],"sources":["../../src/diagnostics.ts"],"sourcesContent":["export type DiagnosticSeverity = \"error\" | \"warning\" | \"info\";\r\n\r\nexport interface Diagnostic {\r\n code: string;\r\n severity: DiagnosticSeverity;\r\n message: string;\r\n path?: string;\r\n suggestion?: string;\r\n migrationId?: string;\r\n guide?: string;\r\n}\r\n\r\nexport interface DiagnosticReport {\r\n ok: boolean;\r\n diagnostics: Diagnostic[];\r\n}\r\n\r\nexport function createDiagnosticReport(diagnostics: Diagnostic[]): DiagnosticReport {\r\n return {\r\n ok: !diagnostics.some((diagnostic) => diagnostic.severity === \"error\"),\r\n diagnostics,\r\n };\r\n}\r\n\r\nexport function printDiagnosticReport(report: DiagnosticReport): void {\r\n const groups: Array<[DiagnosticSeverity, string]> = [\r\n [\"error\", \"Errors\"],\r\n [\"warning\", \"Warnings\"],\r\n [\"info\", \"Information\"],\r\n ];\r\n\r\n for (const [severity, title] of groups) {\r\n const entries = report.diagnostics.filter((diagnostic) => diagnostic.severity === severity);\r\n if (entries.length === 0) continue;\r\n console.log(`${title}:`);\r\n for (const diagnostic of entries) {\r\n const location = diagnostic.path ? ` (${diagnostic.path})` : \"\";\r\n console.log(` [${diagnostic.code}] ${diagnostic.message}${location}`);\r\n if (diagnostic.migrationId) console.log(` migration: ${diagnostic.migrationId}`);\r\n if (diagnostic.guide) console.log(` guide: ${diagnostic.guide}`);\r\n if (diagnostic.suggestion) console.log(` ${diagnostic.suggestion}`);\r\n }\r\n console.log(\"\");\r\n }\r\n\r\n if (report.diagnostics.length === 0) console.log(\"No issues found.\");\r\n}\r\n"],"mappings":";;AAiBA,SAAgB,uBAAuB,aAA6C;AAClF,QAAO;EACL,IAAI,CAAC,YAAY,MAAM,eAAe,WAAW,aAAa,QAAQ;EACtE;EACD;;AAGH,SAAgB,sBAAsB,QAAgC;AAOpE,MAAK,MAAM,CAAC,UAAU,UAN8B;EAClD,CAAC,SAAS,SAAS;EACnB,CAAC,WAAW,WAAW;EACvB,CAAC,QAAQ,cAAc;EACxB,EAEuC;EACtC,MAAM,UAAU,OAAO,YAAY,QAAQ,eAAe,WAAW,aAAa,SAAS;AAC3F,MAAI,QAAQ,WAAW,EAAG;AAC1B,UAAQ,IAAI,GAAG,MAAM,GAAG;AACxB,OAAK,MAAM,cAAc,SAAS;GAChC,MAAM,WAAW,WAAW,OAAO,KAAK,WAAW,KAAK,KAAK;AAC7D,WAAQ,IAAI,MAAM,WAAW,KAAK,IAAI,WAAW,UAAU,WAAW;AACtE,OAAI,WAAW,YAAa,SAAQ,IAAI,kBAAkB,WAAW,cAAc;AACnF,OAAI,WAAW,MAAO,SAAQ,IAAI,cAAc,WAAW,QAAQ;AACnE,OAAI,WAAW,WAAY,SAAQ,IAAI,OAAO,WAAW,aAAa;;AAExE,UAAQ,IAAI,GAAG;;AAGjB,KAAI,OAAO,YAAY,WAAW,EAAG,SAAQ,IAAI,mBAAmB"}
@@ -0,0 +1,20 @@
1
+ //#region src/diagnostics.d.ts
2
+ type DiagnosticSeverity = "error" | "warning" | "info";
3
+ interface Diagnostic {
4
+ code: string;
5
+ severity: DiagnosticSeverity;
6
+ message: string;
7
+ path?: string;
8
+ suggestion?: string;
9
+ migrationId?: string;
10
+ guide?: string;
11
+ }
12
+ interface DiagnosticReport {
13
+ ok: boolean;
14
+ diagnostics: Diagnostic[];
15
+ }
16
+ declare function createDiagnosticReport(diagnostics: Diagnostic[]): DiagnosticReport;
17
+ declare function printDiagnosticReport(report: DiagnosticReport): void;
18
+ //#endregion
19
+ export { Diagnostic, DiagnosticReport, DiagnosticSeverity, createDiagnosticReport, printDiagnosticReport };
20
+ //# sourceMappingURL=diagnostics.d.cts.map