@shrkcrft/generator 0.1.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +15 -0
- package/dist/conflict-handler.d.ts +12 -0
- package/dist/conflict-handler.d.ts.map +1 -0
- package/dist/conflict-handler.js +25 -0
- package/dist/dry-run.d.ts +10 -0
- package/dist/dry-run.d.ts.map +1 -0
- package/dist/dry-run.js +178 -0
- package/dist/file-change.d.ts +46 -0
- package/dist/file-change.d.ts.map +1 -0
- package/dist/file-change.js +22 -0
- package/dist/folder-apply.d.ts +29 -0
- package/dist/folder-apply.d.ts.map +1 -0
- package/dist/folder-apply.js +117 -0
- package/dist/folder-safety.d.ts +12 -0
- package/dist/folder-safety.d.ts.map +1 -0
- package/dist/folder-safety.js +75 -0
- package/dist/generation-plan.d.ts +24 -0
- package/dist/generation-plan.d.ts.map +1 -0
- package/dist/generation-plan.js +1 -0
- package/dist/generation-request.d.ts +14 -0
- package/dist/generation-request.d.ts.map +1 -0
- package/dist/generation-request.js +1 -0
- package/dist/generator-engine.d.ts +12 -0
- package/dist/generator-engine.d.ts.map +1 -0
- package/dist/generator-engine.js +74 -0
- package/dist/grounding/extracted-plan.d.ts +42 -0
- package/dist/grounding/extracted-plan.d.ts.map +1 -0
- package/dist/grounding/extracted-plan.js +12 -0
- package/dist/grounding/extractor-registry.d.ts +21 -0
- package/dist/grounding/extractor-registry.d.ts.map +1 -0
- package/dist/grounding/extractor-registry.js +30 -0
- package/dist/grounding/extractor.d.ts +24 -0
- package/dist/grounding/extractor.d.ts.map +1 -0
- package/dist/grounding/extractor.js +8 -0
- package/dist/grounding/extractors/markdown-frontmatter-loose.d.ts +17 -0
- package/dist/grounding/extractors/markdown-frontmatter-loose.d.ts.map +1 -0
- package/dist/grounding/extractors/markdown-frontmatter-loose.js +160 -0
- package/dist/grounding/extractors/sharkcraft-spec-v1.d.ts +12 -0
- package/dist/grounding/extractors/sharkcraft-spec-v1.d.ts.map +1 -0
- package/dist/grounding/extractors/sharkcraft-spec-v1.js +56 -0
- package/dist/grounding/index.d.ts +6 -0
- package/dist/grounding/index.d.ts.map +1 -0
- package/dist/grounding/index.js +5 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +16 -0
- package/dist/naming-strategy.d.ts +5 -0
- package/dist/naming-strategy.d.ts.map +1 -0
- package/dist/naming-strategy.js +28 -0
- package/dist/overwrite-strategy.d.ts +14 -0
- package/dist/overwrite-strategy.d.ts.map +1 -0
- package/dist/overwrite-strategy.js +15 -0
- package/dist/plan-signing.d.ts +37 -0
- package/dist/plan-signing.d.ts.map +1 -0
- package/dist/plan-signing.js +82 -0
- package/dist/planned-change.d.ts +167 -0
- package/dist/planned-change.d.ts.map +1 -0
- package/dist/planned-change.js +507 -0
- package/dist/saved-plan.d.ts +110 -0
- package/dist/saved-plan.d.ts.map +1 -0
- package/dist/saved-plan.js +281 -0
- package/dist/spec/index.d.ts +7 -0
- package/dist/spec/index.d.ts.map +1 -0
- package/dist/spec/index.js +6 -0
- package/dist/spec/spec-derive.d.ts +15 -0
- package/dist/spec/spec-derive.d.ts.map +1 -0
- package/dist/spec/spec-derive.js +294 -0
- package/dist/spec/spec-frontmatter.d.ts +37 -0
- package/dist/spec/spec-frontmatter.d.ts.map +1 -0
- package/dist/spec/spec-frontmatter.js +497 -0
- package/dist/spec/spec-id.d.ts +30 -0
- package/dist/spec/spec-id.d.ts.map +1 -0
- package/dist/spec/spec-id.js +38 -0
- package/dist/spec/spec-io.d.ts +56 -0
- package/dist/spec/spec-io.d.ts.map +1 -0
- package/dist/spec/spec-io.js +176 -0
- package/dist/spec/spec-model.d.ts +117 -0
- package/dist/spec/spec-model.d.ts.map +1 -0
- package/dist/spec/spec-model.js +225 -0
- package/dist/spec/spec-scaffold.d.ts +32 -0
- package/dist/spec/spec-scaffold.d.ts.map +1 -0
- package/dist/spec/spec-scaffold.js +106 -0
- package/dist/synthetic-plan.d.ts +14 -0
- package/dist/synthetic-plan.d.ts.map +1 -0
- package/dist/synthetic-plan.js +123 -0
- package/package.json +53 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Synthetic plan evaluation.
|
|
3
|
+
*
|
|
4
|
+
* Some plans (e.g. plugin-lifecycle rename/remove) are produced by code that
|
|
5
|
+
* is not a template — there is nothing to "regenerate" against. They carry
|
|
6
|
+
* their structural intent in `ISavedPlan.expectedChanges[].operation` plus
|
|
7
|
+
* `ISavedPlan.folderOps[]`.
|
|
8
|
+
*
|
|
9
|
+
* `evaluateSavedPlanInPlace` evaluates every operation against the live file
|
|
10
|
+
* system and builds an `IGenerationPlan` shaped like a normal one so the
|
|
11
|
+
* apply pipeline can write the resulting changes through the same path.
|
|
12
|
+
*
|
|
13
|
+
* Synthetic plans are identified by a `__`-prefixed templateId so existing
|
|
14
|
+
* template-driven plans are unaffected.
|
|
15
|
+
*/
|
|
16
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
17
|
+
import * as nodePath from 'node:path';
|
|
18
|
+
import { evaluatePlannedChange } from "./planned-change.js";
|
|
19
|
+
import { FileChangeType } from "./file-change.js";
|
|
20
|
+
export const SYNTHETIC_TEMPLATE_PREFIX = '__';
|
|
21
|
+
export function isSyntheticTemplateId(templateId) {
|
|
22
|
+
return templateId.startsWith(SYNTHETIC_TEMPLATE_PREFIX);
|
|
23
|
+
}
|
|
24
|
+
export function evaluateSavedPlanInPlace(plan, projectRoot) {
|
|
25
|
+
const changes = [];
|
|
26
|
+
const warnings = [];
|
|
27
|
+
let hasConflicts = false;
|
|
28
|
+
const expected = plan.expectedChanges ?? [];
|
|
29
|
+
for (const e of expected) {
|
|
30
|
+
if (!e.operation) {
|
|
31
|
+
// Without an operation we cannot reconstruct contents — surface as
|
|
32
|
+
// conflict so apply refuses the write. This is the safe default for
|
|
33
|
+
// synthetic plans missing intent.
|
|
34
|
+
changes.push({
|
|
35
|
+
type: FileChangeType.Conflict,
|
|
36
|
+
absolutePath: nodePath.resolve(projectRoot, e.relativePath),
|
|
37
|
+
relativePath: e.relativePath,
|
|
38
|
+
contents: '',
|
|
39
|
+
reason: 'synthetic-plan: expected change has no operation intent',
|
|
40
|
+
sizeBytes: 0,
|
|
41
|
+
});
|
|
42
|
+
hasConflicts = true;
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const change = applyOperation(projectRoot, e.relativePath, e.operation);
|
|
46
|
+
if (change.type === FileChangeType.Conflict)
|
|
47
|
+
hasConflicts = true;
|
|
48
|
+
changes.push(change);
|
|
49
|
+
}
|
|
50
|
+
const out = {
|
|
51
|
+
templateId: plan.templateId,
|
|
52
|
+
templateName: plan.templateId,
|
|
53
|
+
changes,
|
|
54
|
+
totalFiles: changes.length,
|
|
55
|
+
hasConflicts,
|
|
56
|
+
warnings,
|
|
57
|
+
postGenerationNotes: [],
|
|
58
|
+
};
|
|
59
|
+
if (plan.folderOps && plan.folderOps.length > 0) {
|
|
60
|
+
out.folderOps = plan.folderOps;
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
function applyOperation(projectRoot, relativePath, operation) {
|
|
65
|
+
const absolutePath = nodePath.resolve(projectRoot, relativePath);
|
|
66
|
+
const existing = existsSync(absolutePath) ? readFileSync(absolutePath, 'utf8') : null;
|
|
67
|
+
return evaluatePlannedChange({
|
|
68
|
+
change: { targetPath: relativePath, operation },
|
|
69
|
+
absolutePath,
|
|
70
|
+
relativePath,
|
|
71
|
+
existing,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Write evaluated changes from a synthetic plan directly. The caller
|
|
76
|
+
* is responsible for verifying signature / divergence / folder-op safety
|
|
77
|
+
* before invoking this.
|
|
78
|
+
*/
|
|
79
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
80
|
+
import { AppErrorImpl, ERROR_CODES, err, ok } from '@shrkcrft/core';
|
|
81
|
+
export function writeSyntheticPlan(plan) {
|
|
82
|
+
if (plan.hasConflicts) {
|
|
83
|
+
return err(new AppErrorImpl(ERROR_CODES.TARGET_FILE_EXISTS, 'Synthetic plan refused: conflicts present', { details: { conflicts: plan.changes.filter((c) => c.type === FileChangeType.Conflict) } }));
|
|
84
|
+
}
|
|
85
|
+
const written = [];
|
|
86
|
+
let totalBytes = 0;
|
|
87
|
+
let skipped = 0;
|
|
88
|
+
for (const change of plan.changes) {
|
|
89
|
+
if (change.type === FileChangeType.Skip) {
|
|
90
|
+
skipped += 1;
|
|
91
|
+
continue;
|
|
92
|
+
}
|
|
93
|
+
if (!isWriteableSyntheticChange(change.type))
|
|
94
|
+
continue;
|
|
95
|
+
try {
|
|
96
|
+
mkdirSync(nodePath.dirname(change.absolutePath), { recursive: true });
|
|
97
|
+
writeFileSync(change.absolutePath, change.contents, 'utf8');
|
|
98
|
+
written.push(change);
|
|
99
|
+
totalBytes += change.sizeBytes;
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
return err(new AppErrorImpl(ERROR_CODES.FILE_WRITE_ERROR, `Failed to write ${change.absolutePath}`, { details: { path: change.absolutePath }, cause: e }));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return ok({
|
|
106
|
+
summary: { written: written.length, skipped, conflicts: 0, totalBytes },
|
|
107
|
+
written,
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function isWriteableSyntheticChange(type) {
|
|
111
|
+
switch (type) {
|
|
112
|
+
case FileChangeType.Create:
|
|
113
|
+
case FileChangeType.Update:
|
|
114
|
+
case FileChangeType.Append:
|
|
115
|
+
case FileChangeType.InsertAfter:
|
|
116
|
+
case FileChangeType.InsertBefore:
|
|
117
|
+
case FileChangeType.Replace:
|
|
118
|
+
case FileChangeType.Export:
|
|
119
|
+
return true;
|
|
120
|
+
default:
|
|
121
|
+
return false;
|
|
122
|
+
}
|
|
123
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@shrkcrft/generator",
|
|
3
|
+
"version": "0.1.0-alpha.1",
|
|
4
|
+
"description": "SharkCraft plan-first generator: GenerationPlan, FileChange, dry-run, safe writes.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "SharkCraft contributors",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/sharkcraft/sharkcraft.git",
|
|
25
|
+
"directory": "packages/generator"
|
|
26
|
+
},
|
|
27
|
+
"homepage": "https://github.com/sharkcraft/sharkcraft",
|
|
28
|
+
"bugs": {
|
|
29
|
+
"url": "https://github.com/sharkcraft/sharkcraft/issues"
|
|
30
|
+
},
|
|
31
|
+
"keywords": [
|
|
32
|
+
"sharkcraft",
|
|
33
|
+
"generator",
|
|
34
|
+
"codegen",
|
|
35
|
+
"dry-run"
|
|
36
|
+
],
|
|
37
|
+
"engines": {
|
|
38
|
+
"bun": ">=1.1.0",
|
|
39
|
+
"node": ">=18"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
43
|
+
},
|
|
44
|
+
"dependencies": {
|
|
45
|
+
"@shrkcrft/core": "^0.1.0-alpha.1",
|
|
46
|
+
"@shrkcrft/templates": "^0.1.0-alpha.1",
|
|
47
|
+
"@shrkcrft/rules": "^0.1.0-alpha.1",
|
|
48
|
+
"@shrkcrft/paths": "^0.1.0-alpha.1"
|
|
49
|
+
},
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public"
|
|
52
|
+
}
|
|
53
|
+
}
|