@hozu/cli 0.1.0
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/bin/hozu.js +4 -0
- package/dist/commands/build.d.ts +4 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +81 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/explain.d.ts +5 -0
- package/dist/commands/explain.d.ts.map +1 -0
- package/dist/commands/explain.js +135 -0
- package/dist/commands/explain.js.map +1 -0
- package/dist/commands/graph.d.ts +7 -0
- package/dist/commands/graph.d.ts.map +1 -0
- package/dist/commands/graph.js +137 -0
- package/dist/commands/graph.js.map +1 -0
- package/dist/commands/impact.d.ts +5 -0
- package/dist/commands/impact.d.ts.map +1 -0
- package/dist/commands/impact.js +27 -0
- package/dist/commands/impact.js.map +1 -0
- package/dist/commands/inspect.d.ts +4 -0
- package/dist/commands/inspect.d.ts.map +1 -0
- package/dist/commands/inspect.js +31 -0
- package/dist/commands/inspect.js.map +1 -0
- package/dist/commands/plan.d.ts +5 -0
- package/dist/commands/plan.d.ts.map +1 -0
- package/dist/commands/plan.js +30 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/skill.d.ts +3 -0
- package/dist/commands/skill.d.ts.map +1 -0
- package/dist/commands/skill.js +27 -0
- package/dist/commands/skill.js.map +1 -0
- package/dist/commands/validate.d.ts +4 -0
- package/dist/commands/validate.d.ts.map +1 -0
- package/dist/commands/validate.js +96 -0
- package/dist/commands/validate.js.map +1 -0
- package/dist/contract.d.ts +107 -0
- package/dist/contract.d.ts.map +1 -0
- package/dist/contract.js +2 -0
- package/dist/contract.js.map +1 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +13 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/load.d.ts +9 -0
- package/dist/load.d.ts.map +1 -0
- package/dist/load.js +52 -0
- package/dist/load.js.map +1 -0
- package/dist/main.d.ts +2 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +120 -0
- package/dist/main.js.map +1 -0
- package/dist/output.d.ts +5 -0
- package/dist/output.d.ts.map +1 -0
- package/dist/output.js +28 -0
- package/dist/output.js.map +1 -0
- package/dist/render.d.ts +5 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +47 -0
- package/dist/render.js.map +1 -0
- package/dist/styles.d.ts +3 -0
- package/dist/styles.d.ts.map +1 -0
- package/dist/styles.js +41 -0
- package/dist/styles.js.map +1 -0
- package/package.json +54 -0
- package/schema/build.schema.json +29 -0
- package/schema/explain.schema.json +158 -0
- package/schema/graph.schema.json +109 -0
- package/schema/impact.schema.json +115 -0
- package/schema/inspect.schema.json +1658 -0
- package/schema/plan.schema.json +177 -0
- package/schema/skill.schema.json +21 -0
- package/schema/validate.schema.json +337 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { stat } from 'node:fs/promises';
|
|
2
|
+
import { basename, join } from 'node:path';
|
|
3
|
+
import { AGENTS, runnerOf, writeAgentFiles } from 'create-hozu';
|
|
4
|
+
import { HozuCliError } from '../errors.js';
|
|
5
|
+
const exists = (path) => stat(path).then(() => true, () => false);
|
|
6
|
+
export async function runSkill(cwd, requested) {
|
|
7
|
+
let agent = requested;
|
|
8
|
+
if (agent && !AGENTS.includes(agent))
|
|
9
|
+
throw new HozuCliError('usage', `--agent must be one of ${AGENTS.join(', ')}`, [...AGENTS]);
|
|
10
|
+
if (!agent) {
|
|
11
|
+
const claude = await exists(join(cwd, '.claude/skills/hozu'));
|
|
12
|
+
const agents = await exists(join(cwd, '.agents/skills/hozu'));
|
|
13
|
+
agent = claude && agents ? 'both' : claude ? 'claude' : agents ? 'agents' : undefined;
|
|
14
|
+
}
|
|
15
|
+
if (!agent)
|
|
16
|
+
throw new HozuCliError('usage', 'No Hozu skill in this directory yet; choose where to write it', [
|
|
17
|
+
'hozu skill --agent claude (CLAUDE.md + .claude/skills/hozu)',
|
|
18
|
+
'hozu skill --agent agents (AGENTS.md + .agents/skills/hozu)',
|
|
19
|
+
'hozu skill --agent both',
|
|
20
|
+
]);
|
|
21
|
+
const written = await writeAgentFiles(cwd, agent, {
|
|
22
|
+
name: basename(cwd),
|
|
23
|
+
runner: runnerOf(process.env.npm_config_user_agent),
|
|
24
|
+
});
|
|
25
|
+
return { written };
|
|
26
|
+
}
|
|
27
|
+
//# sourceMappingURL=skill.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill.js","sourceRoot":"","sources":["../../src/commands/skill.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAA;AACvC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAC1C,OAAO,EAAE,MAAM,EAAc,QAAQ,EAAE,eAAe,EAAE,MAAM,aAAa,CAAA;AAE3E,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAA;AAE3C,MAAM,MAAM,GAAG,CAAC,IAAY,EAAE,EAAE,CAC9B,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CACb,GAAG,EAAE,CAAC,IAAI,EACV,GAAG,EAAE,CAAC,KAAK,CACZ,CAAA;AAEH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAAC,GAAW,EAAE,SAA6B;IACvE,IAAI,KAAK,GAAG,SAA8B,CAAA;IAC1C,IAAI,KAAK,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;QAClC,MAAM,IAAI,YAAY,CAAC,OAAO,EAAE,0BAA0B,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,CAAA;IAC7F,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC,CAAA;QAC7D,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC,CAAA;QAC7D,KAAK,GAAG,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,SAAS,CAAA;IACvF,CAAC;IACD,IAAI,CAAC,KAAK;QACR,MAAM,IAAI,YAAY,CAAC,OAAO,EAAE,+DAA+D,EAAE;YAC/F,+DAA+D;YAC/D,+DAA+D;YAC/D,yBAAyB;SAC1B,CAAC,CAAA;IACJ,MAAM,OAAO,GAAG,MAAM,eAAe,CAAC,GAAG,EAAE,KAAK,EAAE;QAChD,IAAI,EAAE,QAAQ,CAAC,GAAG,CAAC;QACnB,MAAM,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;KACpD,CAAC,CAAA;IACF,OAAO,EAAE,OAAO,EAAE,CAAA;AACpB,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { ValidateOutput } from '../contract.ts';
|
|
2
|
+
import type { Loaded } from '../load.ts';
|
|
3
|
+
export declare function runValidate(loaded: Loaded, feature: string | undefined, cwd: string, updateLock?: boolean): Promise<ValidateOutput>;
|
|
4
|
+
//# sourceMappingURL=validate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.d.ts","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAY,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAE9D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAmCxC,wBAAsB,WAAW,CAC/B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,GAAG,SAAS,EAC3B,GAAG,EAAE,MAAM,EACX,UAAU,UAAQ,GACjB,OAAO,CAAC,cAAc,CAAC,CA2DzB"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join as joinPath } from 'node:path';
|
|
3
|
+
import { codes, hashJson, join, resolveSource } from '@hozu/core/ir';
|
|
4
|
+
import { verify } from '@hozu/validator';
|
|
5
|
+
import { HozuCliError } from '../errors.js';
|
|
6
|
+
import { json, relativize } from '../output.js';
|
|
7
|
+
import { unknownClasses } from '../styles.js';
|
|
8
|
+
function firstDifference(a, b, pointer = '') {
|
|
9
|
+
if (a === b)
|
|
10
|
+
return null;
|
|
11
|
+
if (typeof a !== 'object' ||
|
|
12
|
+
typeof b !== 'object' ||
|
|
13
|
+
a === null ||
|
|
14
|
+
b === null ||
|
|
15
|
+
Array.isArray(a) !== Array.isArray(b))
|
|
16
|
+
return pointer;
|
|
17
|
+
const keys = new Set([...Object.keys(a), ...Object.keys(b)]);
|
|
18
|
+
for (const key of [...keys].sort()) {
|
|
19
|
+
const diff = firstDifference(a[key] ?? null, b[key] ?? null, join(pointer, key));
|
|
20
|
+
if (diff !== null)
|
|
21
|
+
return diff;
|
|
22
|
+
}
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
function readLock(path) {
|
|
26
|
+
if (!existsSync(path))
|
|
27
|
+
return null;
|
|
28
|
+
try {
|
|
29
|
+
return JSON.parse(readFileSync(path, 'utf8'));
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
throw new HozuCliError('config', `Cannot read ${path}: ${error.message}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
export async function runValidate(loaded, feature, cwd, updateLock = false) {
|
|
36
|
+
const first = loaded.build(false);
|
|
37
|
+
const second = loaded.build(false);
|
|
38
|
+
const hash = hashJson(first.ir);
|
|
39
|
+
const lockPath = joinPath(dirname(loaded.path), 'hozu.lock.json');
|
|
40
|
+
const previous = readLock(lockPath);
|
|
41
|
+
const unknown = await unknownClasses(loaded.path, first);
|
|
42
|
+
const verified = verify(first.ir, { bindings: first.bindings, lock: previous, unknownClasses: unknown });
|
|
43
|
+
let diagnostics = [...first.diagnostics, ...verified.diagnostics];
|
|
44
|
+
if (hash !== hashJson(second.ir)) {
|
|
45
|
+
const pointer = firstDifference(first.ir, second.ir) ?? '';
|
|
46
|
+
const featureId = pointer.startsWith('/features/') ? (pointer.split('/')[2] ?? null) : null;
|
|
47
|
+
diagnostics.push({
|
|
48
|
+
code: 'HZ011',
|
|
49
|
+
severity: codes.HZ011.severity,
|
|
50
|
+
message: 'Building the project twice produced different IR',
|
|
51
|
+
location: { feature: featureId, pointer, source: null },
|
|
52
|
+
cause: 'A builder callback depends on something that changes between runs (time, randomness, mutable state).',
|
|
53
|
+
fix: {
|
|
54
|
+
summary: 'Make the callback a pure function of its reference arguments',
|
|
55
|
+
snippet: null,
|
|
56
|
+
patch: null,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
if (diagnostics.length) {
|
|
61
|
+
const traced = loaded.build(true);
|
|
62
|
+
diagnostics = diagnostics.map((d) => ({
|
|
63
|
+
...d,
|
|
64
|
+
location: { ...d.location, source: resolveSource(traced.sources, d.location.pointer) },
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
const clean = !diagnostics.some((d) => d.severity === 'error');
|
|
68
|
+
let lock = previous ? 'checked' : 'missing';
|
|
69
|
+
if (updateLock) {
|
|
70
|
+
lock = clean && verified.lock ? 'updated' : 'skipped';
|
|
71
|
+
if (lock === 'updated')
|
|
72
|
+
writeFileSync(lockPath, json(verified.lock));
|
|
73
|
+
}
|
|
74
|
+
const coverage = {};
|
|
75
|
+
for (const [fid, entries] of Object.entries(verified.lock?.features ?? {})) {
|
|
76
|
+
if (feature && fid !== feature)
|
|
77
|
+
continue;
|
|
78
|
+
const list = Object.values(entries);
|
|
79
|
+
coverage[fid] = {
|
|
80
|
+
covered: list.filter((e) => Object.keys(e.contracts).length > 0).length,
|
|
81
|
+
total: list.length,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
const selected = feature ? diagnostics.filter((d) => d.location.feature === feature) : diagnostics;
|
|
85
|
+
const errors = selected.filter((d) => d.severity === 'error').length;
|
|
86
|
+
return {
|
|
87
|
+
ok: errors === 0,
|
|
88
|
+
hash,
|
|
89
|
+
summary: { errors, warnings: selected.length - errors },
|
|
90
|
+
coverage,
|
|
91
|
+
lock,
|
|
92
|
+
styles: unknown ? 'checked' : 'unavailable',
|
|
93
|
+
diagnostics: relativize(selected, cwd),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=validate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate.js","sourceRoot":"","sources":["../../src/commands/validate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import type { RoutePlan } from '@hozu/compiler';
|
|
2
|
+
import type { Diagnostic, ExportsIR, FeatureIR } from '@hozu/core/ir';
|
|
3
|
+
import type { Impact } from '@hozu/validator';
|
|
4
|
+
export interface CliError {
|
|
5
|
+
error: {
|
|
6
|
+
code: 'usage' | 'config' | 'unknown-feature' | 'build';
|
|
7
|
+
message: string;
|
|
8
|
+
suggestions: string[];
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export interface Coverage {
|
|
12
|
+
covered: number;
|
|
13
|
+
total: number;
|
|
14
|
+
}
|
|
15
|
+
export interface ValidateOutput {
|
|
16
|
+
ok: boolean;
|
|
17
|
+
hash: string;
|
|
18
|
+
summary: {
|
|
19
|
+
errors: number;
|
|
20
|
+
warnings: number;
|
|
21
|
+
};
|
|
22
|
+
coverage: Record<string, Coverage>;
|
|
23
|
+
lock: 'missing' | 'checked' | 'updated' | 'skipped';
|
|
24
|
+
styles: 'checked' | 'unavailable';
|
|
25
|
+
diagnostics: Diagnostic[];
|
|
26
|
+
}
|
|
27
|
+
export interface InspectSummary {
|
|
28
|
+
states: number;
|
|
29
|
+
transitions: number;
|
|
30
|
+
events: number;
|
|
31
|
+
queries: number;
|
|
32
|
+
mutations: number;
|
|
33
|
+
views: number;
|
|
34
|
+
contracts: number;
|
|
35
|
+
hydrates: boolean;
|
|
36
|
+
imports: string[];
|
|
37
|
+
exports: ExportsIR;
|
|
38
|
+
}
|
|
39
|
+
export interface InspectOutput {
|
|
40
|
+
feature: string;
|
|
41
|
+
hash: string;
|
|
42
|
+
summary: InspectSummary;
|
|
43
|
+
ir: FeatureIR;
|
|
44
|
+
}
|
|
45
|
+
export type GraphNodeKind = 'state' | 'effect' | 'event' | 'feature' | 'view' | 'query';
|
|
46
|
+
export type GraphEdgeKind = 'on' | 'done' | 'failed' | 'after' | 'invoke' | 'import' | 'send' | 'reads' | 'embeds';
|
|
47
|
+
export interface GraphNode {
|
|
48
|
+
id: string;
|
|
49
|
+
kind: GraphNodeKind;
|
|
50
|
+
label: string;
|
|
51
|
+
initial: boolean;
|
|
52
|
+
final: boolean;
|
|
53
|
+
}
|
|
54
|
+
export interface GraphEdge {
|
|
55
|
+
from: string;
|
|
56
|
+
to: string;
|
|
57
|
+
kind: GraphEdgeKind;
|
|
58
|
+
label: string;
|
|
59
|
+
}
|
|
60
|
+
export interface GraphOutput {
|
|
61
|
+
feature: string;
|
|
62
|
+
nodes: GraphNode[];
|
|
63
|
+
edges: GraphEdge[];
|
|
64
|
+
}
|
|
65
|
+
export interface ExplainTransition {
|
|
66
|
+
id: string;
|
|
67
|
+
from: string;
|
|
68
|
+
to: string;
|
|
69
|
+
trigger: string;
|
|
70
|
+
guard: string | null;
|
|
71
|
+
assign: string[];
|
|
72
|
+
navigate: string | null;
|
|
73
|
+
coveredBy: string[];
|
|
74
|
+
}
|
|
75
|
+
export interface ExplainSend {
|
|
76
|
+
view: string;
|
|
77
|
+
node: string;
|
|
78
|
+
event: string;
|
|
79
|
+
handled: boolean;
|
|
80
|
+
}
|
|
81
|
+
export interface ExplainOutput {
|
|
82
|
+
feature: string;
|
|
83
|
+
state: string;
|
|
84
|
+
initial: boolean;
|
|
85
|
+
final: boolean;
|
|
86
|
+
invoke: {
|
|
87
|
+
effect: string;
|
|
88
|
+
input: string;
|
|
89
|
+
errors: string[];
|
|
90
|
+
} | null;
|
|
91
|
+
outgoing: ExplainTransition[];
|
|
92
|
+
incoming: ExplainTransition[];
|
|
93
|
+
sends: ExplainSend[];
|
|
94
|
+
}
|
|
95
|
+
export type ImpactOutput = Impact;
|
|
96
|
+
export interface PlanOutput extends RoutePlan {
|
|
97
|
+
soft: Record<string, string[]>;
|
|
98
|
+
}
|
|
99
|
+
export interface BuildOutput {
|
|
100
|
+
out: string;
|
|
101
|
+
manifest: string;
|
|
102
|
+
files: string[];
|
|
103
|
+
}
|
|
104
|
+
export interface SkillOutput {
|
|
105
|
+
written: string[];
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=contract.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
|
package/dist/contract.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":""}
|
package/dist/errors.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { CliError } from './contract.ts';
|
|
2
|
+
export declare class HozuCliError extends Error {
|
|
3
|
+
readonly code: CliError['error']['code'];
|
|
4
|
+
readonly suggestions: string[];
|
|
5
|
+
constructor(code: CliError['error']['code'], message: string, suggestions?: string[]);
|
|
6
|
+
toJSON(): CliError;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=errors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAE7C,qBAAa,YAAa,SAAQ,KAAK;IACrC,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAA;IACxC,QAAQ,CAAC,WAAW,EAAE,MAAM,EAAE,CAAA;IAE9B,YAAY,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,GAAE,MAAM,EAAO,EAIvF;IAED,MAAM,IAAI,QAAQ,CAEjB;CACF"}
|
package/dist/errors.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export class HozuCliError extends Error {
|
|
2
|
+
code;
|
|
3
|
+
suggestions;
|
|
4
|
+
constructor(code, message, suggestions = []) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.code = code;
|
|
7
|
+
this.suggestions = suggestions;
|
|
8
|
+
}
|
|
9
|
+
toJSON() {
|
|
10
|
+
return { error: { code: this.code, message: this.message, suggestions: this.suggestions } };
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=errors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,YAAa,SAAQ,KAAK;IAC5B,IAAI,CAA2B;IAC/B,WAAW,CAAU;IAE9B,YAAY,IAA+B,EAAE,OAAe,EAAE,WAAW,GAAa,EAAE;QACtF,KAAK,CAAC,OAAO,CAAC,CAAA;QACd,IAAI,CAAC,IAAI,GAAG,IAAI,CAAA;QAChB,IAAI,CAAC,WAAW,GAAG,WAAW,CAAA;IAChC,CAAC;IAED,MAAM;QACJ,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,EAAE,CAAA;IAC7F,CAAC;CACF"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AACtD,mBAAmB,eAAe,CAAA;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAEtD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA"}
|
package/dist/load.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type BuildResult, type ProjectIR } from '@hozu/core/ir';
|
|
2
|
+
export interface Loaded {
|
|
3
|
+
path: string;
|
|
4
|
+
project: unknown;
|
|
5
|
+
build: (sources?: boolean) => BuildResult;
|
|
6
|
+
}
|
|
7
|
+
export declare function load(config: string | undefined, cwd: string): Promise<Loaded>;
|
|
8
|
+
export declare function requireFeature(ir: ProjectIR, id: string | undefined): import("@hozu/core/ir").FeatureIR;
|
|
9
|
+
//# sourceMappingURL=load.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.d.ts","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,WAAW,EAAgB,KAAK,SAAS,EAAE,MAAM,eAAe,CAAA;AAI9E,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,CAAC,OAAO,CAAC,EAAE,OAAO,KAAK,WAAW,CAAA;CAC1C;AAED,wBAAsB,IAAI,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA2BnF;AAED,wBAAgB,cAAc,CAAC,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE,MAAM,GAAG,SAAS,qCAOnE"}
|
package/dist/load.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
+
});
|
|
6
|
+
}
|
|
7
|
+
return path;
|
|
8
|
+
};
|
|
9
|
+
import { existsSync } from 'node:fs';
|
|
10
|
+
import { resolve } from 'node:path';
|
|
11
|
+
import { pathToFileURL } from 'node:url';
|
|
12
|
+
import { buildProject } from '@hozu/core/ir';
|
|
13
|
+
import { closest } from '@hozu/validator';
|
|
14
|
+
import { HozuCliError } from './errors.js';
|
|
15
|
+
export async function load(config, cwd) {
|
|
16
|
+
const path = resolve(cwd, config ?? 'hozu.config.ts');
|
|
17
|
+
if (!existsSync(path))
|
|
18
|
+
throw new HozuCliError('config', `No config found at ${path}`, [
|
|
19
|
+
'Create hozu.config.ts exporting project({ ... }) as default, or pass --config <path>',
|
|
20
|
+
]);
|
|
21
|
+
let mod;
|
|
22
|
+
try {
|
|
23
|
+
mod = await import(__rewriteRelativeImportExtension(pathToFileURL(path).href));
|
|
24
|
+
}
|
|
25
|
+
catch (error) {
|
|
26
|
+
throw new HozuCliError('config', `Failed to load ${path}: ${error instanceof Error ? error.message : String(error)}`);
|
|
27
|
+
}
|
|
28
|
+
const project = mod.default;
|
|
29
|
+
return {
|
|
30
|
+
path,
|
|
31
|
+
project,
|
|
32
|
+
build: (sources = false) => {
|
|
33
|
+
try {
|
|
34
|
+
return buildProject(project, { sources });
|
|
35
|
+
}
|
|
36
|
+
catch (error) {
|
|
37
|
+
throw new HozuCliError('config', error instanceof Error ? error.message : String(error));
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
export function requireFeature(ir, id) {
|
|
43
|
+
const ids = Object.keys(ir.features);
|
|
44
|
+
if (!id)
|
|
45
|
+
throw new HozuCliError('usage', 'Missing <feature> argument', ids);
|
|
46
|
+
const feature = ir.features[id];
|
|
47
|
+
if (feature)
|
|
48
|
+
return feature;
|
|
49
|
+
const guess = closest(id, ids);
|
|
50
|
+
throw new HozuCliError('unknown-feature', `Unknown feature "${id}"`, guess ? [guess] : ids);
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=load.js.map
|
package/dist/load.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"load.js","sourceRoot":"","sources":["../src/load.ts"],"names":[],"mappings":";;;;;;;;AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAA;AACxC,OAAO,EAAoB,YAAY,EAAkB,MAAM,eAAe,CAAA;AAC9E,OAAO,EAAE,OAAO,EAAE,MAAM,iBAAiB,CAAA;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAQ1C,MAAM,CAAC,KAAK,UAAU,IAAI,CAAC,MAA0B,EAAE,GAAW;IAChE,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE,MAAM,IAAI,gBAAgB,CAAC,CAAA;IACrD,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QACnB,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,sBAAsB,IAAI,EAAE,EAAE;YAC7D,sFAAsF;SACvF,CAAC,CAAA;IACJ,IAAI,GAA0B,CAAA;IAC9B,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,MAAM,kCAAC,aAAa,CAAC,IAAI,CAAC,CAAC,IAAI,EAAC,CAAA;IAC9C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,YAAY,CACpB,QAAQ,EACR,kBAAkB,IAAI,KAAK,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CACpF,CAAA;IACH,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,CAAC,OAAO,CAAA;IAC3B,OAAO;QACL,IAAI;QACJ,OAAO;QACP,KAAK,EAAE,CAAC,OAAO,GAAG,KAAK,EAAE,EAAE;YACzB,IAAI,CAAC;gBACH,OAAO,YAAY,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,CAAA;YAC3C,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,IAAI,YAAY,CAAC,QAAQ,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAA;YAC1F,CAAC;QACH,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,EAAa,EAAE,EAAsB;IAClE,MAAM,GAAG,GAAG,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAA;IACpC,IAAI,CAAC,EAAE;QAAE,MAAM,IAAI,YAAY,CAAC,OAAO,EAAE,4BAA4B,EAAE,GAAG,CAAC,CAAA;IAC3E,MAAM,OAAO,GAAG,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAA;IAC/B,IAAI,OAAO;QAAE,OAAO,OAAO,CAAA;IAC3B,MAAM,KAAK,GAAG,OAAO,CAAC,EAAE,EAAE,GAAG,CAAC,CAAA;IAC9B,MAAM,IAAI,YAAY,CAAC,iBAAiB,EAAE,oBAAoB,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;AAC7F,CAAC"}
|
package/dist/main.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"AAkCA,wBAAsB,IAAI,CACxB,IAAI,EAAE,MAAM,EAAE,EACd,GAAG,SAAgB,EACnB,GAAG,GAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAqC,GACxD,OAAO,CAAC,MAAM,CAAC,CAwFjB"}
|
package/dist/main.js
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { parseArgs } from 'node:util';
|
|
2
|
+
import { runBuild } from './commands/build.js';
|
|
3
|
+
import { describeExplain, runExplain } from './commands/explain.js';
|
|
4
|
+
import { mermaid, runGraph } from './commands/graph.js';
|
|
5
|
+
import { describeImpact, runImpact } from './commands/impact.js';
|
|
6
|
+
import { runInspect } from './commands/inspect.js';
|
|
7
|
+
import { describePlan, runPlan } from './commands/plan.js';
|
|
8
|
+
import { runSkill } from './commands/skill.js';
|
|
9
|
+
import { runValidate } from './commands/validate.js';
|
|
10
|
+
import { HozuCliError } from './errors.js';
|
|
11
|
+
import { load } from './load.js';
|
|
12
|
+
import { human, json } from './output.js';
|
|
13
|
+
const usage = `Usage: hozu <command> [options]
|
|
14
|
+
|
|
15
|
+
Commands:
|
|
16
|
+
validate [feature] Build the IR, run contracts, report diagnostics (exit 1 on errors)
|
|
17
|
+
inspect <feature> Print a feature's canonical IR and summary
|
|
18
|
+
graph <feature> Print a feature's state/effect/view graph (Mermaid, or --json)
|
|
19
|
+
explain <feature>.<state> Explain a state: transitions, guards, effects, covering contracts
|
|
20
|
+
impact <feature>.<symbol> What a query, mutation, tag, event, fn or view affects
|
|
21
|
+
plan <route> Derived render plan: regions, cache modes, hydration islands
|
|
22
|
+
build Write dist/public, dist/server/render.js and dist/manifest.json for deployment
|
|
23
|
+
skill Rewrite the agent skill for this Hozu version (--agent claude|agents|both)
|
|
24
|
+
|
|
25
|
+
Options:
|
|
26
|
+
--json Machine-readable output (schemas in @hozu/cli/schema)
|
|
27
|
+
--config <path> Config file (default: hozu.config.ts)
|
|
28
|
+
--update-lock validate: rewrite hozu.lock.json when there are no errors
|
|
29
|
+
--out <dir> build: output directory (default: dist)
|
|
30
|
+
--agent <agent> skill: claude, agents or both (default: the folders that exist)
|
|
31
|
+
-h, --help Show this help
|
|
32
|
+
`;
|
|
33
|
+
export async function main(argv, cwd = process.cwd(), out = (s) => process.stdout.write(s)) {
|
|
34
|
+
let asJson = false;
|
|
35
|
+
try {
|
|
36
|
+
const { values, positionals } = parseArgs({
|
|
37
|
+
args: argv,
|
|
38
|
+
allowPositionals: true,
|
|
39
|
+
strict: true,
|
|
40
|
+
options: {
|
|
41
|
+
json: { type: 'boolean', default: false },
|
|
42
|
+
config: { type: 'string' },
|
|
43
|
+
'update-lock': { type: 'boolean', default: false },
|
|
44
|
+
out: { type: 'string' },
|
|
45
|
+
agent: { type: 'string' },
|
|
46
|
+
help: { type: 'boolean', short: 'h' },
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
asJson = values.json === true;
|
|
50
|
+
const [command, target] = positionals;
|
|
51
|
+
if (values.help || !command) {
|
|
52
|
+
out(usage);
|
|
53
|
+
return command || values.help ? 0 : 2;
|
|
54
|
+
}
|
|
55
|
+
const commands = ['validate', 'inspect', 'graph', 'explain', 'impact', 'plan', 'build', 'skill'];
|
|
56
|
+
if (!commands.includes(command))
|
|
57
|
+
throw new HozuCliError('usage', `Unknown command "${command}"`, commands);
|
|
58
|
+
if (command === 'skill') {
|
|
59
|
+
const result = await runSkill(cwd, values.agent);
|
|
60
|
+
out(asJson ? json(result) : `✔ wrote ${result.written.join(', ')}\n`);
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
const loaded = await load(values.config, cwd);
|
|
64
|
+
if (command === 'validate') {
|
|
65
|
+
const result = await runValidate(loaded, target, cwd, values['update-lock'] === true);
|
|
66
|
+
if (asJson)
|
|
67
|
+
out(json(result));
|
|
68
|
+
else {
|
|
69
|
+
for (const d of result.diagnostics)
|
|
70
|
+
out(`${human(d)}\n\n`);
|
|
71
|
+
const coverage = Object.entries(result.coverage)
|
|
72
|
+
.map(([f, c]) => `${f} ${c.covered}/${c.total}`)
|
|
73
|
+
.join(', ');
|
|
74
|
+
out(`${result.ok ? '✔' : '✖'} ${result.summary.errors} errors, ${result.summary.warnings} warnings · contracts cover ${coverage || 'n/a'} · styles ${result.styles} · lock ${result.lock} (ir ${result.hash.slice(0, 12)})\n`);
|
|
75
|
+
}
|
|
76
|
+
return result.ok ? 0 : 1;
|
|
77
|
+
}
|
|
78
|
+
if (command === 'inspect') {
|
|
79
|
+
const result = runInspect(loaded, target);
|
|
80
|
+
out(asJson
|
|
81
|
+
? json(result)
|
|
82
|
+
: `${json({ feature: result.feature, hash: result.hash, summary: result.summary })}`);
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
if (command === 'build') {
|
|
86
|
+
const result = await runBuild(loaded, values.out, cwd);
|
|
87
|
+
out(asJson ? json(result) : `✔ wrote ${result.files.length} static files and ${result.manifest}\n`);
|
|
88
|
+
return 0;
|
|
89
|
+
}
|
|
90
|
+
if (command === 'plan') {
|
|
91
|
+
const result = runPlan(loaded, target);
|
|
92
|
+
out(asJson ? json(result) : describePlan(result));
|
|
93
|
+
return 0;
|
|
94
|
+
}
|
|
95
|
+
if (command === 'impact') {
|
|
96
|
+
const result = runImpact(loaded, target);
|
|
97
|
+
out(asJson ? json(result) : describeImpact(result));
|
|
98
|
+
return 0;
|
|
99
|
+
}
|
|
100
|
+
if (command === 'explain') {
|
|
101
|
+
const result = runExplain(loaded, target);
|
|
102
|
+
out(asJson ? json(result) : describeExplain(result));
|
|
103
|
+
return 0;
|
|
104
|
+
}
|
|
105
|
+
const graph = runGraph(loaded, target);
|
|
106
|
+
out(asJson ? json(graph) : mermaid(graph));
|
|
107
|
+
return 0;
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
const e = error instanceof HozuCliError
|
|
111
|
+
? error
|
|
112
|
+
: new HozuCliError('usage', error instanceof Error ? error.message : String(error));
|
|
113
|
+
if (asJson)
|
|
114
|
+
out(json(e.toJSON()));
|
|
115
|
+
else
|
|
116
|
+
process.stderr.write(`hozu: ${e.message}${e.suggestions.length ? `\n ${e.suggestions.join('\n ')}` : ''}\n`);
|
|
117
|
+
return 2;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
//# sourceMappingURL=main.js.map
|
package/dist/main.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":"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"}
|
package/dist/output.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type Diagnostic } from '@hozu/core/ir';
|
|
2
|
+
export declare const json: (value: unknown) => string;
|
|
3
|
+
export declare const relativize: (diagnostics: Diagnostic[], cwd: string) => Diagnostic[];
|
|
4
|
+
export declare function human(d: Diagnostic): string;
|
|
5
|
+
//# sourceMappingURL=output.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AACA,OAAO,EAAsB,KAAK,UAAU,EAAE,MAAM,eAAe,CAAA;AAEnE,eAAO,MAAM,IAAI,UAAW,OAAO,KAAG,MACiC,CAAA;AAEvE,eAAO,MAAM,UAAU,gBAAiB,UAAU,EAAE,OAAO,MAAM,KAAG,UAAU,EAW3E,CAAA;AAEH,wBAAgB,KAAK,CAAC,CAAC,EAAE,UAAU,GAAG,MAAM,CAY3C"}
|
package/dist/output.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { relative } from 'node:path';
|
|
2
|
+
import { canonicalStringify } from '@hozu/core/ir';
|
|
3
|
+
export const json = (value) => `${JSON.stringify(JSON.parse(canonicalStringify(value)), null, 2)}\n`;
|
|
4
|
+
export const relativize = (diagnostics, cwd) => diagnostics.map((d) => d.location.source
|
|
5
|
+
? {
|
|
6
|
+
...d,
|
|
7
|
+
location: {
|
|
8
|
+
...d.location,
|
|
9
|
+
source: { ...d.location.source, file: relative(cwd, d.location.source.file) },
|
|
10
|
+
},
|
|
11
|
+
}
|
|
12
|
+
: d);
|
|
13
|
+
export function human(d) {
|
|
14
|
+
const where = d.location.source
|
|
15
|
+
? `${d.location.source.file}:${d.location.source.line}:${d.location.source.column}`
|
|
16
|
+
: `${d.location.pointer}`;
|
|
17
|
+
const lines = [
|
|
18
|
+
`${where} ${d.severity} ${d.code} ${d.message}`,
|
|
19
|
+
` at ${d.location.pointer}`,
|
|
20
|
+
` cause: ${d.cause}`,
|
|
21
|
+
];
|
|
22
|
+
if (d.fix)
|
|
23
|
+
lines.push(` fix: ${d.fix.summary}${d.fix.patch ? ' (patch available with --json)' : ''}`);
|
|
24
|
+
if (d.fix?.snippet)
|
|
25
|
+
lines.push(d.fix.snippet.replace(/^/gm, ' '));
|
|
26
|
+
return lines.join('\n');
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAA;AACpC,OAAO,EAAE,kBAAkB,EAAmB,MAAM,eAAe,CAAA;AAEnE,MAAM,CAAC,MAAM,IAAI,GAAG,CAAC,KAAc,EAAU,EAAE,CAC7C,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAA;AAEvE,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,WAAyB,EAAE,GAAW,EAAgB,EAAE,CACjF,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CACpB,CAAC,CAAC,QAAQ,CAAC,MAAM;IACf,CAAC,CAAC;QACE,GAAG,CAAC;QACJ,QAAQ,EAAE;YACR,GAAG,CAAC,CAAC,QAAQ;YACb,MAAM,EAAE,EAAE,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,QAAQ,CAAC,GAAG,EAAE,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE;SAC9E;KACF;IACH,CAAC,CAAC,CAAC,CACN,CAAA;AAEH,MAAM,UAAU,KAAK,CAAC,CAAa;IACjC,MAAM,KAAK,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM;QAC7B,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,IAAI,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE;QACnF,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAA;IAC3B,MAAM,KAAK,GAAG;QACZ,GAAG,KAAK,KAAK,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE;QAClD,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,EAAE;QAC5B,YAAY,CAAC,CAAC,KAAK,EAAE;KACtB,CAAA;IACD,IAAI,CAAC,CAAC,GAAG;QAAE,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,gCAAgC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACtG,IAAI,CAAC,CAAC,GAAG,EAAE,OAAO;QAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAA;IACpE,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AACzB,CAAC"}
|
package/dist/render.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { AssignOp, GuardExpr, ValueExpr } from '@hozu/core/ir';
|
|
2
|
+
export declare function renderValue(v: ValueExpr): string;
|
|
3
|
+
export declare function renderGuard(g: GuardExpr): string;
|
|
4
|
+
export declare function renderAssign(a: AssignOp): string;
|
|
5
|
+
//# sourceMappingURL=render.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../src/render.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAKnE,wBAAgB,WAAW,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAWhD;AAID,wBAAgB,WAAW,CAAC,CAAC,EAAE,SAAS,GAAG,MAAM,CAYhD;AAED,wBAAgB,YAAY,CAAC,CAAC,EAAE,QAAQ,GAAG,MAAM,CAYhD"}
|
package/dist/render.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const local = (ref) => ref.slice(ref.indexOf('.') + 1);
|
|
2
|
+
const suffix = (path) => path.map((p) => `.${p}`).join('');
|
|
3
|
+
export function renderValue(v) {
|
|
4
|
+
if ('literal' in v)
|
|
5
|
+
return JSON.stringify(v.literal);
|
|
6
|
+
if ('object' in v)
|
|
7
|
+
return `{ ${Object.entries(v.object)
|
|
8
|
+
.map(([k, x]) => `${k}: ${renderValue(x)}`)
|
|
9
|
+
.join(', ')} }`;
|
|
10
|
+
if ('fn' in v)
|
|
11
|
+
return `${local(v.fn)}(${renderValue(v.arg)})`;
|
|
12
|
+
if ('test' in v)
|
|
13
|
+
return `(${renderGuard(v.test)})`;
|
|
14
|
+
if ('link' in v)
|
|
15
|
+
return `link(${local(v.link)}, ${renderValue(v.params)}, ${renderValue(v.search)})`;
|
|
16
|
+
if (v.ref === 'binding')
|
|
17
|
+
return `item${v.depth}${suffix(v.path)}`;
|
|
18
|
+
return `${v.ref}${suffix(v.path)}`;
|
|
19
|
+
}
|
|
20
|
+
const symbols = { eq: '==', neq: '!=', lt: '<', lte: '<=', gt: '>', gte: '>=' };
|
|
21
|
+
export function renderGuard(g) {
|
|
22
|
+
switch (g.op) {
|
|
23
|
+
case 'and':
|
|
24
|
+
case 'or':
|
|
25
|
+
return g.args.map((a) => `(${renderGuard(a)})`).join(g.op === 'and' ? ' && ' : ' || ');
|
|
26
|
+
case 'not':
|
|
27
|
+
return `!(${renderGuard(g.arg)})`;
|
|
28
|
+
case 'fn':
|
|
29
|
+
return `${local(g.fn)}(${renderValue(g.arg)})`;
|
|
30
|
+
default:
|
|
31
|
+
return `${renderValue(g.left)} ${symbols[g.op]} ${renderValue(g.right)}`;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export function renderAssign(a) {
|
|
35
|
+
const target = `context${suffix(a.path)}`;
|
|
36
|
+
switch (a.op) {
|
|
37
|
+
case 'set':
|
|
38
|
+
return `${target} = ${renderValue(a.value)}`;
|
|
39
|
+
case 'append':
|
|
40
|
+
return `${target}.push(${renderValue(a.value)})`;
|
|
41
|
+
case 'inc':
|
|
42
|
+
return `${target} += ${renderValue(a.value)}`;
|
|
43
|
+
case 'removeWhere':
|
|
44
|
+
return `${target} = ${target}.filter(x => x.${a.key} != ${renderValue(a.value)})`;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=render.js.map
|