@milehimikey/em 1.1.0 → 1.1.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/.claude/skills/event-modeling/SKILL.md +23 -70
- package/.claude/skills/event-modeling/reference/em-dsl.md +0 -15
- package/.claude/skills/event-modeling/templates/model-readme.md +4 -4
- package/.claude/skills/event-modeling/templates/slice.md +2 -4
- package/.claude/skills/event-modeling/templates/state.md +3 -9
- package/README.md +4 -31
- package/dist/cli.js +4 -227
- package/dist/cli.js.map +1 -1
- package/dist/model/validate.d.ts +0 -2
- package/dist/model/validate.js +1 -1
- package/dist/model/validate.js.map +1 -1
- package/package.json +2 -3
- package/.claude/skills/event-modeling/reference/frontmatter.md +0 -129
- package/dist/config.d.ts +0 -15
- package/dist/config.js +0 -60
- package/dist/config.js.map +0 -1
- package/dist/migrate/migrate.d.ts +0 -26
- package/dist/migrate/migrate.js +0 -276
- package/dist/migrate/migrate.js.map +0 -1
- package/dist/model/deriveSliceFields.d.ts +0 -21
- package/dist/model/deriveSliceFields.js +0 -60
- package/dist/model/deriveSliceFields.js.map +0 -1
- package/dist/model/frontmatter.d.ts +0 -21
- package/dist/model/frontmatter.js +0 -38
- package/dist/model/frontmatter.js.map +0 -1
- package/dist/model/sliceDoc.d.ts +0 -56
- package/dist/model/sliceDoc.js +0 -28
- package/dist/model/sliceDoc.js.map +0 -1
- package/dist/model/validateSliceDocs.d.ts +0 -7
- package/dist/model/validateSliceDocs.js +0 -195
- package/dist/model/validateSliceDocs.js.map +0 -1
- package/dist/slice/generate.d.ts +0 -17
- package/dist/slice/generate.js +0 -61
- package/dist/slice/generate.js.map +0 -1
- package/dist/slice/query.d.ts +0 -42
- package/dist/slice/query.js +0 -96
- package/dist/slice/query.js.map +0 -1
- package/dist/slice/sync.d.ts +0 -18
- package/dist/slice/sync.js +0 -104
- package/dist/slice/sync.js.map +0 -1
- package/dist/util/findModel.d.ts +0 -1
- package/dist/util/findModel.js +0 -27
- package/dist/util/findModel.js.map +0 -1
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
// Computes the "generated" slice-doc frontmatter fields (docs/1.0.0-spec.md §2.2)
|
|
3
|
-
// from the .em model. Shared by validateSliceDocs.ts (drift detection) and the
|
|
4
|
-
// future `em slice sync` (Phase C) so there's exactly one definition of
|
|
5
|
-
// "what these fields should be" — never duplicated between check and write.
|
|
6
|
-
import { AUTOMATION_KINDS } from "../parser/ast.js";
|
|
7
|
-
/**
|
|
8
|
-
* Derive the generated fields for the slice that `sliceElementId` belongs to.
|
|
9
|
-
* `docIdByElementId` maps every *other* slice doc's linked element id to that
|
|
10
|
-
* doc's frontmatter `id`, so `triggers`/`triggeredBy` (the automation/translation
|
|
11
|
-
* two-slice split) can be resolved without a second .em pass per doc. Returns
|
|
12
|
-
* null if `sliceElementId` doesn't resolve to a real element.
|
|
13
|
-
*/
|
|
14
|
-
export function deriveGeneratedFields(model, sliceElementId, docIdByElementId) {
|
|
15
|
-
const element = model.byId.get(sliceElementId);
|
|
16
|
-
if (!element)
|
|
17
|
-
return null;
|
|
18
|
-
const slice = model.slices[element.sliceIndex];
|
|
19
|
-
const commands = slice.elements.filter((e) => e.kind === "command").map((e) => e.name);
|
|
20
|
-
const events = slice.elements.filter((e) => e.kind === "event").map((e) => e.name);
|
|
21
|
-
const readModels = slice.elements.filter((e) => e.kind === "view").map((e) => e.name);
|
|
22
|
-
const contexts = dedupe(slice.elements.filter((e) => e.kind === "event" && e.context).map((e) => e.context));
|
|
23
|
-
const personas = dedupe(slice.elements.filter((e) => e.kind === "ui" && e.persona).map((e) => e.persona));
|
|
24
|
-
const fields = { commands, events, readModels, contexts, personas };
|
|
25
|
-
const isReaction = slice.elements.some((e) => AUTOMATION_KINDS.has(e.kind));
|
|
26
|
-
if (isReaction) {
|
|
27
|
-
const nextSlice = model.slices[slice.index + 1];
|
|
28
|
-
const triggeredCommand = nextSlice?.elements.find((e) => e.kind === "command");
|
|
29
|
-
const triggeredDocId = triggeredCommand && docIdByElementId.get(triggeredCommand.id);
|
|
30
|
-
if (triggeredDocId)
|
|
31
|
-
fields.triggers = triggeredDocId;
|
|
32
|
-
}
|
|
33
|
-
else if (commands.length > 0) {
|
|
34
|
-
const prevSlice = model.slices[slice.index - 1];
|
|
35
|
-
const reaction = prevSlice?.elements.find((e) => AUTOMATION_KINDS.has(e.kind));
|
|
36
|
-
const triggeringDocId = reaction && docIdByElementId.get(reaction.id);
|
|
37
|
-
if (triggeringDocId)
|
|
38
|
-
fields.triggeredBy = triggeringDocId;
|
|
39
|
-
}
|
|
40
|
-
return fields;
|
|
41
|
-
}
|
|
42
|
-
function dedupe(values) {
|
|
43
|
-
return Array.from(new Set(values));
|
|
44
|
-
}
|
|
45
|
-
/** Map every doc's linked .em element id -> that doc's frontmatter `id`, skipping unusable docs. */
|
|
46
|
-
export function buildDocIdByElementId(model, docs) {
|
|
47
|
-
const index = new Map();
|
|
48
|
-
for (const doc of docs) {
|
|
49
|
-
const data = doc.frontmatter;
|
|
50
|
-
if (!data)
|
|
51
|
-
continue;
|
|
52
|
-
const id = data.id;
|
|
53
|
-
const sliceElement = data.sliceElement;
|
|
54
|
-
if (typeof id === "string" && typeof sliceElement === "string" && model.byId.has(sliceElement)) {
|
|
55
|
-
index.set(sliceElement, id);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
return index;
|
|
59
|
-
}
|
|
60
|
-
//# sourceMappingURL=deriveSliceFields.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"deriveSliceFields.js","sourceRoot":"","sources":["../../src/model/deriveSliceFields.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { Document } from "yaml";
|
|
2
|
-
export interface ParsedFrontmatter {
|
|
3
|
-
/** Parsed YAML data, or null if the file has no frontmatter block. */
|
|
4
|
-
data: Record<string, unknown> | null;
|
|
5
|
-
/** The YAML Document, kept around so writes can preserve comments/formatting. Null if no block. */
|
|
6
|
-
document: Document | null;
|
|
7
|
-
/** Everything after the closing `---`. Equal to the whole input when there's no frontmatter block. */
|
|
8
|
-
body: string;
|
|
9
|
-
}
|
|
10
|
-
/** Parse a slice doc's leading frontmatter block, if it has one. */
|
|
11
|
-
export declare function parseFrontmatter(raw: string): ParsedFrontmatter;
|
|
12
|
-
/** Reassemble a `---\n...\n---\n<body>` string from a Document and body text. */
|
|
13
|
-
export declare function stringifyFrontmatter(document: Document, body: string): string;
|
|
14
|
-
/** Build a fresh Document from a plain object (used when creating a new slice doc). */
|
|
15
|
-
export declare function frontmatterFromData(data: Record<string, unknown>): Document;
|
|
16
|
-
/**
|
|
17
|
-
* Shallow-merge `patch` into `document` in place, preserving every other key
|
|
18
|
-
* (including ones `em` doesn't know about) and existing comments. Returns the
|
|
19
|
-
* same Document instance for convenience.
|
|
20
|
-
*/
|
|
21
|
-
export declare function mergeFrontmatter(document: Document, patch: Record<string, unknown>): Document;
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
// Split/parse/stringify a `---\n...\n---\n` YAML frontmatter block. Backed by
|
|
3
|
-
// the `yaml` package's Document API so incremental writes (slice sync/update,
|
|
4
|
-
// migrate) preserve comments and fields the CLI doesn't know about — external
|
|
5
|
-
// tools may own fields in this same block (see docs/1.0.0-spec.md §8).
|
|
6
|
-
import { Document, parseDocument } from "yaml";
|
|
7
|
-
const DELIMITER = /^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/;
|
|
8
|
-
/** Parse a slice doc's leading frontmatter block, if it has one. */
|
|
9
|
-
export function parseFrontmatter(raw) {
|
|
10
|
-
const match = raw.match(DELIMITER);
|
|
11
|
-
if (!match)
|
|
12
|
-
return { data: null, document: null, body: raw };
|
|
13
|
-
const [, yamlText, body] = match;
|
|
14
|
-
const document = parseDocument(yamlText);
|
|
15
|
-
const data = (document.toJS() ?? {});
|
|
16
|
-
return { data, document, body };
|
|
17
|
-
}
|
|
18
|
-
/** Reassemble a `---\n...\n---\n<body>` string from a Document and body text. */
|
|
19
|
-
export function stringifyFrontmatter(document, body) {
|
|
20
|
-
const yamlText = document.toString().replace(/\n+$/, "");
|
|
21
|
-
return `---\n${yamlText}\n---\n${body}`;
|
|
22
|
-
}
|
|
23
|
-
/** Build a fresh Document from a plain object (used when creating a new slice doc). */
|
|
24
|
-
export function frontmatterFromData(data) {
|
|
25
|
-
return new Document(data);
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Shallow-merge `patch` into `document` in place, preserving every other key
|
|
29
|
-
* (including ones `em` doesn't know about) and existing comments. Returns the
|
|
30
|
-
* same Document instance for convenience.
|
|
31
|
-
*/
|
|
32
|
-
export function mergeFrontmatter(document, patch) {
|
|
33
|
-
for (const [key, value] of Object.entries(patch)) {
|
|
34
|
-
document.set(key, value);
|
|
35
|
-
}
|
|
36
|
-
return document;
|
|
37
|
-
}
|
|
38
|
-
//# sourceMappingURL=frontmatter.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"frontmatter.js","sourceRoot":"","sources":["../../src/model/frontmatter.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,8EAA8E;AAC9E,8EAA8E;AAC9E,8EAA8E;AAC9E,uEAAuE;AAEvE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,MAAM,CAAC;AAE/C,MAAM,SAAS,GAAG,6CAA6C,CAAC;AAWhE,oEAAoE;AACpE,MAAM,UAAU,gBAAgB,CAAC,GAAW;IAC1C,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACnC,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IAE7D,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,CAAC,GAAG,KAAK,CAAC;IACjC,MAAM,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,CAAC,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,CAA4B,CAAC;IAChE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC;AAClC,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,oBAAoB,CAAC,QAAkB,EAAE,IAAY;IACnE,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACzD,OAAO,QAAQ,QAAQ,UAAU,IAAI,EAAE,CAAC;AAC1C,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,mBAAmB,CAAC,IAA6B;IAC/D,OAAO,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC5B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAC,QAAkB,EAAE,KAA8B;IACjF,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACjD,QAAQ,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC3B,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
package/dist/model/sliceDoc.d.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { Document } from "yaml";
|
|
2
|
-
export type SlicePattern = "state-change" | "state-view" | "automation" | "translation";
|
|
3
|
-
export type SliceStatus = "draft" | "reviewed" | "ready-to-implement" | "in-progress" | "implemented" | "deprecated" | "superseded";
|
|
4
|
-
/**
|
|
5
|
-
* The frontmatter schema from docs/1.0.0-spec.md §2. This is the *expected*
|
|
6
|
-
* shape for a valid doc — loadSliceDocs() does not enforce it (a doc on disk
|
|
7
|
-
* may be missing fields, mistyped, or have no frontmatter at all; that's what
|
|
8
|
-
* validateSliceDocs() reports). Unknown/external fields always round-trip
|
|
9
|
-
* through SliceDoc.document even though they aren't listed here.
|
|
10
|
-
*/
|
|
11
|
-
export interface SliceFrontmatter {
|
|
12
|
-
schemaVersion: number;
|
|
13
|
-
id: string;
|
|
14
|
-
title: string;
|
|
15
|
-
pattern: SlicePattern;
|
|
16
|
-
status: SliceStatus;
|
|
17
|
-
version: number;
|
|
18
|
-
model: string;
|
|
19
|
-
sliceElement: string;
|
|
20
|
-
commands?: string[];
|
|
21
|
-
events?: string[];
|
|
22
|
-
readModels?: string[];
|
|
23
|
-
contexts?: string[];
|
|
24
|
-
personas?: string[];
|
|
25
|
-
triggers?: string;
|
|
26
|
-
triggeredBy?: string;
|
|
27
|
-
swimlane?: {
|
|
28
|
-
persona?: string;
|
|
29
|
-
context?: string;
|
|
30
|
-
};
|
|
31
|
-
upstreamEvents?: string[];
|
|
32
|
-
relatedSlices?: string[];
|
|
33
|
-
tags?: string[];
|
|
34
|
-
owner?: string;
|
|
35
|
-
created?: string;
|
|
36
|
-
updated?: string;
|
|
37
|
-
contentHash?: string;
|
|
38
|
-
supersededBy?: string;
|
|
39
|
-
implementedRef?: string;
|
|
40
|
-
}
|
|
41
|
-
export interface SliceDoc {
|
|
42
|
-
/** Absolute path to the doc. */
|
|
43
|
-
path: string;
|
|
44
|
-
/** Filename without directory, e.g. "place-order.md". */
|
|
45
|
-
file: string;
|
|
46
|
-
/** Parsed frontmatter, or null if the doc has no `---` block at all. Not validated. */
|
|
47
|
-
frontmatter: Record<string, unknown> | null;
|
|
48
|
-
/** The YAML Document backing `frontmatter`, for round-trip-safe writes. Null alongside frontmatter. */
|
|
49
|
-
document: Document | null;
|
|
50
|
-
/** Everything after the closing `---` (or the whole file, if there's no frontmatter block). */
|
|
51
|
-
body: string;
|
|
52
|
-
/** Full file contents, as read from disk. */
|
|
53
|
-
raw: string;
|
|
54
|
-
}
|
|
55
|
-
/** Load every `slices/*.md` doc in a model directory. Returns [] if `slices/` doesn't exist. */
|
|
56
|
-
export declare function loadSliceDocs(modelDir: string): SliceDoc[];
|
package/dist/model/sliceDoc.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
// Loads slice design docs (slices/*.md) and their frontmatter. Parsing only —
|
|
3
|
-
// no validation here (see validateSliceDocs.ts) and no writing (see
|
|
4
|
-
// src/slice/*.ts). Kept separate so "what's on disk" stays cheap and pure.
|
|
5
|
-
import { readdirSync, readFileSync } from "node:fs";
|
|
6
|
-
import { join } from "node:path";
|
|
7
|
-
import { parseFrontmatter } from "./frontmatter.js";
|
|
8
|
-
/** Load every `slices/*.md` doc in a model directory. Returns [] if `slices/` doesn't exist. */
|
|
9
|
-
export function loadSliceDocs(modelDir) {
|
|
10
|
-
const slicesDir = join(modelDir, "slices");
|
|
11
|
-
let entries;
|
|
12
|
-
try {
|
|
13
|
-
entries = readdirSync(slicesDir);
|
|
14
|
-
}
|
|
15
|
-
catch {
|
|
16
|
-
return [];
|
|
17
|
-
}
|
|
18
|
-
return entries
|
|
19
|
-
.filter((f) => f.endsWith(".md"))
|
|
20
|
-
.sort()
|
|
21
|
-
.map((file) => {
|
|
22
|
-
const path = join(slicesDir, file);
|
|
23
|
-
const raw = readFileSync(path, "utf8");
|
|
24
|
-
const { data, document, body } = parseFrontmatter(raw);
|
|
25
|
-
return { path, file, frontmatter: data, document, body, raw };
|
|
26
|
-
});
|
|
27
|
-
}
|
|
28
|
-
//# sourceMappingURL=sliceDoc.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sliceDoc.js","sourceRoot":"","sources":["../../src/model/sliceDoc.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAC/B,8EAA8E;AAC9E,oEAAoE;AACpE,2EAA2E;AAE3E,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAmEpD,gGAAgG;AAChG,MAAM,UAAU,aAAa,CAAC,QAAgB;IAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAC3C,IAAI,OAAiB,CAAC;IACtB,IAAI,CAAC;QACH,OAAO,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,OAAO,OAAO;SACX,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;SAChC,IAAI,EAAE;SACN,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACvC,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;QACvD,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,GAAG,EAAE,CAAC;IAChE,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import { Diagnostic } from "./validate.js";
|
|
2
|
-
import { NormalizedModel } from "./model.js";
|
|
3
|
-
import { SliceDoc, SlicePattern, SliceStatus } from "./sliceDoc.js";
|
|
4
|
-
export declare const CURRENT_SCHEMA_VERSION = 1;
|
|
5
|
-
export declare const VALID_PATTERNS: SlicePattern[];
|
|
6
|
-
export declare const VALID_STATUSES: SliceStatus[];
|
|
7
|
-
export declare function validateSliceDocs(model: NormalizedModel, modelPath: string, docs: SliceDoc[]): Diagnostic[];
|
|
@@ -1,195 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
// Diagnostics for slice docs (slices/*.md), per docs/1.0.0-spec.md §5. Mirrors
|
|
3
|
-
// the Diagnostic { severity, message, line? } shape from validate.ts, using
|
|
4
|
-
// `file` instead of `line` since these point at a Markdown doc, not the .em.
|
|
5
|
-
import { existsSync } from "node:fs";
|
|
6
|
-
import { dirname, resolve } from "node:path";
|
|
7
|
-
import { buildDocIdByElementId, deriveGeneratedFields } from "./deriveSliceFields.js";
|
|
8
|
-
export const CURRENT_SCHEMA_VERSION = 1;
|
|
9
|
-
export const VALID_PATTERNS = [
|
|
10
|
-
"state-change",
|
|
11
|
-
"state-view",
|
|
12
|
-
"automation",
|
|
13
|
-
"translation",
|
|
14
|
-
];
|
|
15
|
-
export const VALID_STATUSES = [
|
|
16
|
-
"draft",
|
|
17
|
-
"reviewed",
|
|
18
|
-
"ready-to-implement",
|
|
19
|
-
"in-progress",
|
|
20
|
-
"implemented",
|
|
21
|
-
"deprecated",
|
|
22
|
-
"superseded",
|
|
23
|
-
];
|
|
24
|
-
const KEBAB_RE = /^[a-z0-9]+(-[a-z0-9]+)*$/;
|
|
25
|
-
function sameStringArray(a, b) {
|
|
26
|
-
if (!Array.isArray(a))
|
|
27
|
-
return b.length === 0;
|
|
28
|
-
if (a.length !== b.length)
|
|
29
|
-
return false;
|
|
30
|
-
return a.every((v, i) => v === b[i]);
|
|
31
|
-
}
|
|
32
|
-
export function validateSliceDocs(model, modelPath, docs) {
|
|
33
|
-
const diags = [];
|
|
34
|
-
// Which .em elements already have a doc linking back to them (note "slices/<file>.md").
|
|
35
|
-
const notedPaths = new Set();
|
|
36
|
-
for (const el of model.elements) {
|
|
37
|
-
if (el.note)
|
|
38
|
-
notedPaths.add(resolve(dirname(modelPath), el.note));
|
|
39
|
-
}
|
|
40
|
-
// Every doc whose id + sliceElement look usable, so triggers/triggeredBy and
|
|
41
|
-
// drift-checks can resolve cross-doc even when other fields on a doc are invalid.
|
|
42
|
-
const docIdByElementId = buildDocIdByElementId(model, docs);
|
|
43
|
-
const seenIds = new Map(); // id -> first doc path that used it
|
|
44
|
-
const knownIds = new Set(docs.map((d) => d.frontmatter?.id).filter(Boolean));
|
|
45
|
-
for (const doc of docs) {
|
|
46
|
-
const data = doc.frontmatter;
|
|
47
|
-
if (!data) {
|
|
48
|
-
diags.push({
|
|
49
|
-
severity: "error",
|
|
50
|
-
file: doc.path,
|
|
51
|
-
message: "no frontmatter block found; run `em migrate` to upgrade this model directory",
|
|
52
|
-
});
|
|
53
|
-
continue;
|
|
54
|
-
}
|
|
55
|
-
if (typeof data.schemaVersion !== "number" || !Number.isInteger(data.schemaVersion)) {
|
|
56
|
-
diags.push({ severity: "error", file: doc.path, message: "missing or invalid `schemaVersion`" });
|
|
57
|
-
}
|
|
58
|
-
else if (data.schemaVersion > CURRENT_SCHEMA_VERSION) {
|
|
59
|
-
diags.push({
|
|
60
|
-
severity: "error",
|
|
61
|
-
file: doc.path,
|
|
62
|
-
message: `schemaVersion ${data.schemaVersion} is newer than this em build understands (${CURRENT_SCHEMA_VERSION}); upgrade @milehimikey/em`,
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
if (typeof data.id !== "string" || data.id.length === 0) {
|
|
66
|
-
diags.push({ severity: "error", file: doc.path, message: "missing or invalid `id`" });
|
|
67
|
-
}
|
|
68
|
-
else {
|
|
69
|
-
if (!KEBAB_RE.test(data.id)) {
|
|
70
|
-
diags.push({
|
|
71
|
-
severity: "error",
|
|
72
|
-
file: doc.path,
|
|
73
|
-
message: `id "${data.id}" is not kebab-case (expected e.g. "place-order")`,
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
|
-
const firstPath = seenIds.get(data.id);
|
|
77
|
-
if (firstPath && firstPath !== doc.path) {
|
|
78
|
-
diags.push({
|
|
79
|
-
severity: "error",
|
|
80
|
-
file: doc.path,
|
|
81
|
-
message: `id "${data.id}" is also used by ${firstPath}; slice ids must be unique within a model directory`,
|
|
82
|
-
});
|
|
83
|
-
}
|
|
84
|
-
else if (!firstPath) {
|
|
85
|
-
seenIds.set(data.id, doc.path);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
if (typeof data.title !== "string" || data.title.length === 0) {
|
|
89
|
-
diags.push({ severity: "error", file: doc.path, message: "missing or invalid `title`" });
|
|
90
|
-
}
|
|
91
|
-
if (typeof data.pattern !== "string" || !VALID_PATTERNS.includes(data.pattern)) {
|
|
92
|
-
diags.push({
|
|
93
|
-
severity: "error",
|
|
94
|
-
file: doc.path,
|
|
95
|
-
message: `\`pattern\` must be one of ${VALID_PATTERNS.join(", ")}`,
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
if (typeof data.status !== "string" || !VALID_STATUSES.includes(data.status)) {
|
|
99
|
-
diags.push({
|
|
100
|
-
severity: "error",
|
|
101
|
-
file: doc.path,
|
|
102
|
-
message: `\`status\` must be one of ${VALID_STATUSES.join(", ")}`,
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
if (typeof data.version !== "number" || !Number.isInteger(data.version) || data.version < 1) {
|
|
106
|
-
diags.push({ severity: "error", file: doc.path, message: "`version` must be a positive integer" });
|
|
107
|
-
}
|
|
108
|
-
if (typeof data.model !== "string" || data.model.length === 0) {
|
|
109
|
-
diags.push({ severity: "error", file: doc.path, message: "missing or invalid `model`" });
|
|
110
|
-
}
|
|
111
|
-
else if (!existsSync(resolve(dirname(doc.path), data.model))) {
|
|
112
|
-
diags.push({
|
|
113
|
-
severity: "error",
|
|
114
|
-
file: doc.path,
|
|
115
|
-
message: `\`model\` "${data.model}" does not resolve to an existing file`,
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
let sliceElementId;
|
|
119
|
-
if (typeof data.sliceElement !== "string" || data.sliceElement.length === 0) {
|
|
120
|
-
diags.push({ severity: "error", file: doc.path, message: "missing or invalid `sliceElement`" });
|
|
121
|
-
}
|
|
122
|
-
else if (!model.byId.has(data.sliceElement)) {
|
|
123
|
-
diags.push({
|
|
124
|
-
severity: "error",
|
|
125
|
-
file: doc.path,
|
|
126
|
-
message: `sliceElement "${data.sliceElement}" does not match any element in ${modelPath}`,
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
else {
|
|
130
|
-
sliceElementId = data.sliceElement;
|
|
131
|
-
}
|
|
132
|
-
if (Array.isArray(data.upstreamEvents)) {
|
|
133
|
-
for (const name of data.upstreamEvents) {
|
|
134
|
-
const found = model.elements.some((e) => e.kind === "event" && e.name === name);
|
|
135
|
-
if (!found) {
|
|
136
|
-
diags.push({
|
|
137
|
-
severity: "warning",
|
|
138
|
-
file: doc.path,
|
|
139
|
-
message: `upstreamEvents references unknown event "${name}"`,
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
if (Array.isArray(data.relatedSlices)) {
|
|
145
|
-
for (const id of data.relatedSlices) {
|
|
146
|
-
if (!knownIds.has(id)) {
|
|
147
|
-
diags.push({
|
|
148
|
-
severity: "warning",
|
|
149
|
-
file: doc.path,
|
|
150
|
-
message: `relatedSlices references unknown slice id "${id}"`,
|
|
151
|
-
});
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
if (!notedPaths.has(resolve(doc.path))) {
|
|
156
|
-
diags.push({
|
|
157
|
-
severity: "warning",
|
|
158
|
-
file: doc.path,
|
|
159
|
-
message: 'no element in the .em model has `note "..."` pointing at this doc (orphan doc)',
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
else if (sliceElementId) {
|
|
163
|
-
const el = model.byId.get(sliceElementId);
|
|
164
|
-
const notePath = el.note && resolve(dirname(modelPath), el.note);
|
|
165
|
-
if (notePath !== resolve(doc.path)) {
|
|
166
|
-
diags.push({
|
|
167
|
-
severity: "warning",
|
|
168
|
-
file: doc.path,
|
|
169
|
-
message: `sliceElement "${sliceElementId}"'s note does not point back at this doc`,
|
|
170
|
-
});
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
if (sliceElementId) {
|
|
174
|
-
const derived = deriveGeneratedFields(model, sliceElementId, docIdByElementId);
|
|
175
|
-
if (derived) {
|
|
176
|
-
const drifted = !sameStringArray(data.commands, derived.commands) ||
|
|
177
|
-
!sameStringArray(data.events, derived.events) ||
|
|
178
|
-
!sameStringArray(data.readModels, derived.readModels) ||
|
|
179
|
-
!sameStringArray(data.contexts, derived.contexts) ||
|
|
180
|
-
!sameStringArray(data.personas, derived.personas) ||
|
|
181
|
-
(data.triggers ?? undefined) !== derived.triggers ||
|
|
182
|
-
(data.triggeredBy ?? undefined) !== derived.triggeredBy;
|
|
183
|
-
if (drifted) {
|
|
184
|
-
diags.push({
|
|
185
|
-
severity: "warning",
|
|
186
|
-
file: doc.path,
|
|
187
|
-
message: "frontmatter out of sync with .em; run `em slice sync`",
|
|
188
|
-
});
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
return diags;
|
|
194
|
-
}
|
|
195
|
-
//# sourceMappingURL=validateSliceDocs.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"validateSliceDocs.js","sourceRoot":"","sources":["../../src/model/validateSliceDocs.ts"],"names":[],"mappings":"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"}
|
package/dist/slice/generate.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
import { SlicePattern } from "../model/sliceDoc.js";
|
|
2
|
-
export interface NewSliceOptions {
|
|
3
|
-
dir?: string;
|
|
4
|
-
modelPath?: string;
|
|
5
|
-
configPath?: string;
|
|
6
|
-
pattern?: SlicePattern;
|
|
7
|
-
id?: string;
|
|
8
|
-
/** The .em Element.id this doc documents, if already known (skips straight to a synced doc). */
|
|
9
|
-
sliceElement?: string;
|
|
10
|
-
force?: boolean;
|
|
11
|
-
}
|
|
12
|
-
export interface NewSliceResult {
|
|
13
|
-
path: string;
|
|
14
|
-
id: string;
|
|
15
|
-
modelPath: string;
|
|
16
|
-
}
|
|
17
|
-
export declare function newSlice(name: string, opts?: NewSliceOptions): NewSliceResult;
|
package/dist/slice/generate.js
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
1
|
-
// SPDX-License-Identifier: MIT
|
|
2
|
-
// `em slice new` — scaffolds slices/<id>.md: resolves the configured (or
|
|
3
|
-
// default) body template, injects the required frontmatter block, and never
|
|
4
|
-
// touches the .em (wiring `note "slices/<id>.md"` onto an element stays the
|
|
5
|
-
// agent's job — see docs/1.0.0-spec.md §6).
|
|
6
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
7
|
-
import { join, relative } from "node:path";
|
|
8
|
-
import { resolveConfig, resolveSliceTemplatePath } from "../config.js";
|
|
9
|
-
import { frontmatterFromData, stringifyFrontmatter } from "../model/frontmatter.js";
|
|
10
|
-
import { loadSliceDocs } from "../model/sliceDoc.js";
|
|
11
|
-
import { CURRENT_SCHEMA_VERSION } from "../model/validateSliceDocs.js";
|
|
12
|
-
import { findModelFile } from "../util/findModel.js";
|
|
13
|
-
import { dedupe, kebabSlug } from "../util/slug.js";
|
|
14
|
-
import { syncSlice } from "./sync.js";
|
|
15
|
-
export function newSlice(name, opts = {}) {
|
|
16
|
-
const dir = opts.dir ?? process.cwd();
|
|
17
|
-
const modelPath = findModelFile(dir, opts.modelPath);
|
|
18
|
-
const slicesDir = join(dir, "slices");
|
|
19
|
-
mkdirSync(slicesDir, { recursive: true });
|
|
20
|
-
const existingIds = new Set(loadSliceDocs(dir)
|
|
21
|
-
.map((d) => d.frontmatter?.id)
|
|
22
|
-
.filter((id) => typeof id === "string"));
|
|
23
|
-
let id;
|
|
24
|
-
if (opts.id) {
|
|
25
|
-
if (existingIds.has(opts.id)) {
|
|
26
|
-
throw new Error(`id "${opts.id}" is already used by another slice doc in ${slicesDir}`);
|
|
27
|
-
}
|
|
28
|
-
id = opts.id;
|
|
29
|
-
}
|
|
30
|
-
else {
|
|
31
|
-
id = dedupe(kebabSlug(name), existingIds, "-");
|
|
32
|
-
}
|
|
33
|
-
const path = join(slicesDir, `${id}.md`);
|
|
34
|
-
if (existsSync(path) && !opts.force) {
|
|
35
|
-
throw new Error(`refusing to overwrite ${path} (use --force)`);
|
|
36
|
-
}
|
|
37
|
-
const resolvedConfig = resolveConfig(dir, opts.configPath);
|
|
38
|
-
const templatePath = resolveSliceTemplatePath(resolvedConfig);
|
|
39
|
-
const bodyTemplate = readFileSync(templatePath, "utf8");
|
|
40
|
-
const body = bodyTemplate.replaceAll("{{Slice Name}}", name);
|
|
41
|
-
const today = new Date().toISOString().slice(0, 10);
|
|
42
|
-
const data = {
|
|
43
|
-
schemaVersion: CURRENT_SCHEMA_VERSION,
|
|
44
|
-
id,
|
|
45
|
-
title: name,
|
|
46
|
-
pattern: opts.pattern ?? "state-change",
|
|
47
|
-
status: "draft",
|
|
48
|
-
version: 1,
|
|
49
|
-
model: relative(slicesDir, modelPath),
|
|
50
|
-
created: today,
|
|
51
|
-
updated: today,
|
|
52
|
-
};
|
|
53
|
-
if (opts.sliceElement)
|
|
54
|
-
data.sliceElement = opts.sliceElement;
|
|
55
|
-
writeFileSync(path, stringifyFrontmatter(frontmatterFromData(data), body));
|
|
56
|
-
if (opts.sliceElement) {
|
|
57
|
-
syncSlice(id, { dir, modelPath });
|
|
58
|
-
}
|
|
59
|
-
return { path, id, modelPath };
|
|
60
|
-
}
|
|
61
|
-
//# sourceMappingURL=generate.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"generate.js","sourceRoot":"","sources":["../../src/slice/generate.ts"],"names":[],"mappings":"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"}
|
package/dist/slice/query.d.ts
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import { SliceDoc, SlicePattern, SliceStatus } from "../model/sliceDoc.js";
|
|
2
|
-
export interface SliceSummary {
|
|
3
|
-
id: string;
|
|
4
|
-
title: string;
|
|
5
|
-
pattern: SlicePattern | undefined;
|
|
6
|
-
status: SliceStatus | undefined;
|
|
7
|
-
version: number | undefined;
|
|
8
|
-
file: string;
|
|
9
|
-
}
|
|
10
|
-
/**
|
|
11
|
-
* A doc's complete frontmatter, plus the `file` it came from so a caller can
|
|
12
|
-
* open it without a second lookup. `file` is set after the spread, so it wins
|
|
13
|
-
* over a frontmatter key of the same name — treat `file` as reserved.
|
|
14
|
-
*/
|
|
15
|
-
export type SliceRecord = Record<string, unknown> & {
|
|
16
|
-
file: string;
|
|
17
|
-
};
|
|
18
|
-
export interface ListOptions {
|
|
19
|
-
dir?: string;
|
|
20
|
-
status?: SliceStatus;
|
|
21
|
-
pattern?: SlicePattern;
|
|
22
|
-
context?: string;
|
|
23
|
-
tag?: string;
|
|
24
|
-
}
|
|
25
|
-
export declare function listSlices(opts?: ListOptions): SliceSummary[];
|
|
26
|
-
/** Same selection as listSlices, but every frontmatter field rather than the summary. */
|
|
27
|
-
export declare function listSliceRecords(opts?: ListOptions): SliceRecord[];
|
|
28
|
-
export declare function showSlice(id: string, opts?: {
|
|
29
|
-
dir?: string;
|
|
30
|
-
}): SliceDoc | undefined;
|
|
31
|
-
export type SearchOptions = ListOptions;
|
|
32
|
-
export declare function searchSlices(query: string, opts?: SearchOptions): SliceSummary[];
|
|
33
|
-
/** Same selection as searchSlices, but every frontmatter field rather than the summary. */
|
|
34
|
-
export declare function searchSliceRecords(query: string, opts?: SearchOptions): SliceRecord[];
|
|
35
|
-
export interface UpdateOptions {
|
|
36
|
-
dir?: string;
|
|
37
|
-
status?: SliceStatus;
|
|
38
|
-
bumpVersion?: boolean;
|
|
39
|
-
}
|
|
40
|
-
export declare function updateSlice(id: string, opts?: UpdateOptions): {
|
|
41
|
-
path: string;
|
|
42
|
-
};
|