@refrakt-md/cli 0.34.0 → 0.36.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.
Files changed (38) hide show
  1. package/dist/bin.js +144 -23
  2. package/dist/bin.js.map +1 -1
  3. package/dist/commands/config.d.ts +3 -2
  4. package/dist/commands/config.d.ts.map +1 -1
  5. package/dist/commands/config.js +110 -2
  6. package/dist/commands/config.js.map +1 -1
  7. package/dist/commands/contracts.d.ts +10 -0
  8. package/dist/commands/contracts.d.ts.map +1 -1
  9. package/dist/commands/contracts.js +13 -1
  10. package/dist/commands/contracts.js.map +1 -1
  11. package/dist/commands/inspect.d.ts.map +1 -1
  12. package/dist/commands/inspect.js +55 -0
  13. package/dist/commands/inspect.js.map +1 -1
  14. package/dist/commands/theme-validate.d.ts +23 -0
  15. package/dist/commands/theme-validate.d.ts.map +1 -0
  16. package/dist/commands/theme-validate.js +73 -0
  17. package/dist/commands/theme-validate.js.map +1 -0
  18. package/dist/commands/validate-config.d.ts +35 -0
  19. package/dist/commands/validate-config.d.ts.map +1 -0
  20. package/dist/commands/validate-config.js +123 -0
  21. package/dist/commands/validate-config.js.map +1 -0
  22. package/dist/commands/validate-core.d.ts +51 -0
  23. package/dist/commands/validate-core.d.ts.map +1 -0
  24. package/dist/commands/validate-core.js +113 -0
  25. package/dist/commands/validate-core.js.map +1 -0
  26. package/dist/commands/validate.d.ts +12 -2
  27. package/dist/commands/validate.d.ts.map +1 -1
  28. package/dist/commands/validate.js +62 -60
  29. package/dist/commands/validate.js.map +1 -1
  30. package/dist/lib/format.d.ts +2 -0
  31. package/dist/lib/format.d.ts.map +1 -1
  32. package/dist/lib/format.js +4 -0
  33. package/dist/lib/format.js.map +1 -1
  34. package/dist/lib/schema-row.d.ts +28 -0
  35. package/dist/lib/schema-row.d.ts.map +1 -0
  36. package/dist/lib/schema-row.js +149 -0
  37. package/dist/lib/schema-row.js.map +1 -0
  38. package/package.json +10 -6
@@ -0,0 +1,149 @@
1
+ import { findByName } from '@refrakt-md/runes';
2
+ /**
3
+ * Find sources the rune's rendered output does not provide.
4
+ *
5
+ * Mechanically checkable, unlike a wrong schema.org type — which is exactly why
6
+ * it is worth a tool. A table naming a `data-name` the rune never emits is the
7
+ * failure mode WORK-561 exists to prevent and that every later migration can
8
+ * reintroduce, and it fails *silently*: the property is simply absent from the
9
+ * published graph.
10
+ *
11
+ * A source resolves if a node carries the name, or if the field bag has it —
12
+ * the same two routes the applier has, checked the same way.
13
+ */
14
+ export function auditSchemaSources(row, tree, declaredAttributes = []) {
15
+ const bag = collectBags(tree);
16
+ // A source is resolvable if the rune *can* emit it, not merely if this one
17
+ // fixture did. An optional attribute the fixture leaves unset — `rating` on
18
+ // `testimonial` — produces no node and no bag entry, and flagging that would
19
+ // report the table as broken when it is correct and the input is simply
20
+ // minimal. Matching the rune's declared attributes is what separates "this
21
+ // input did not exercise it" from the failure mode actually worth catching:
22
+ // a source name that is a typo or a rename, which resolves to nothing ever.
23
+ const declared = new Set();
24
+ for (const name of declaredAttributes) {
25
+ declared.add(name);
26
+ declared.add(kebab(name));
27
+ }
28
+ // The child keys this row retypes. A parent source must not be judged
29
+ // resolved by a stamp that a *child* row produced: `playlist` maps `headline`
30
+ // and its items map `track-name`, both to `name`, and looking at the whole
31
+ // tree would let either cover for the other's typo.
32
+ const childNames = new Set(row.children.map((c) => c.rune));
33
+ const unresolved = [];
34
+ for (const entry of row.properties) {
35
+ // A generated value has no source to resolve — that is what makes it
36
+ // generated.
37
+ if (entry.kind === 'generated')
38
+ continue;
39
+ // A `children:` mapping names sources on nodes *another rune* emitted, with
40
+ // their own attributes and their own bag. Auditing those against this
41
+ // rune's tree and this rune's declared attributes reports every one of them
42
+ // as broken — which is how a check stops being read. Resolve them against
43
+ // the children themselves, and say nothing when the input contains none:
44
+ // that is "this fixture did not exercise it", not "this row is wrong".
45
+ if (entry.scope === 'child' && entry.entity) {
46
+ const children = findChildren(tree, entry.entity);
47
+ if (children.length === 0)
48
+ continue;
49
+ // The most direct evidence there is: the property this row maps to is
50
+ // stamped on the child, so the source resolved to *something*. The
51
+ // applier clears a retyped child's stamps before re-applying, so
52
+ // anything present came from this row.
53
+ if (children.some((c) => hasProperty(c, entry.property, childNames)))
54
+ continue;
55
+ if (children.some((c) => findByName(c, entry.source)))
56
+ continue;
57
+ if (children.some((c) => Object.hasOwn(collectBags(c), entry.source)))
58
+ continue;
59
+ unresolved.push({ source: entry.source, property: entry.property, entity: entry.entity });
60
+ continue;
61
+ }
62
+ // The same evidence for the rune's own sources, and for a rebuilt one it is
63
+ // the only evidence left: the identity transform consumes
64
+ // `data-rune-fields`, and this audit reads the rendered tree, so a source
65
+ // the applier recovered from the bag leaves no trace of the bag behind —
66
+ // only the carrier it built. Children are excluded, per `childNames`.
67
+ if (hasProperty(tree, entry.property, childNames))
68
+ continue;
69
+ if (findByName(tree, entry.source))
70
+ continue;
71
+ if (Object.hasOwn(bag, entry.source))
72
+ continue;
73
+ if (declared.has(entry.source) || declared.has(kebab(entry.source)))
74
+ continue;
75
+ unresolved.push({ source: entry.source, property: entry.property, entity: entry.entity });
76
+ }
77
+ return unresolved;
78
+ }
79
+ /**
80
+ * Does any node in this subtree carry `property="<name>"`?
81
+ *
82
+ * `skip` names child keys whose subtrees are somebody else's row to answer for;
83
+ * a node matching one is not descended into, and is itself skipped unless it is
84
+ * the subtree being asked about.
85
+ */
86
+ function hasProperty(node, property, skip = new Set(), top = true) {
87
+ if (Array.isArray(node))
88
+ return node.some((c) => hasProperty(c, property, skip, top));
89
+ if (!node || typeof node !== 'object')
90
+ return false;
91
+ const attrs = node.attributes ?? {};
92
+ if (!top && skip.size > 0 && isChildOf(attrs, skip))
93
+ return false;
94
+ if (attrs.property === property)
95
+ return true;
96
+ return (node.children ?? []).some((c) => hasProperty(c, property, skip, false));
97
+ }
98
+ const isChildOf = (attrs, names) => names.has(attrs['data-rune']) ||
99
+ names.has(attrs['data-name']) ||
100
+ names.has(attrs['data-field']);
101
+ /**
102
+ * The nodes a `children:` row applies to — the same match the applier makes.
103
+ *
104
+ * Kept in step with `findChildren` in the applier deliberately: an audit that
105
+ * looked in different nodes than the mechanism does would report on a population
106
+ * nobody maps.
107
+ */
108
+ function findChildren(node, name, out = []) {
109
+ if (Array.isArray(node)) {
110
+ for (const c of node)
111
+ findChildren(c, name, out);
112
+ return out;
113
+ }
114
+ if (!node || typeof node !== 'object')
115
+ return out;
116
+ const attrs = node.attributes ?? {};
117
+ if (attrs['data-rune'] === name || attrs['data-name'] === name || attrs['data-field'] === name) {
118
+ out.push(node);
119
+ }
120
+ for (const c of node.children ?? [])
121
+ findChildren(c, name, out);
122
+ return out;
123
+ }
124
+ const kebab = (s) => s.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase();
125
+ /** Every `data-rune-fields` bag in the tree, merged. */
126
+ function collectBags(node, into = {}) {
127
+ if (Array.isArray(node)) {
128
+ for (const child of node)
129
+ collectBags(child, into);
130
+ return into;
131
+ }
132
+ if (!node || typeof node !== 'object')
133
+ return into;
134
+ const attrs = node.attributes;
135
+ const raw = attrs?.['data-rune-fields'];
136
+ if (typeof raw === 'string') {
137
+ try {
138
+ Object.assign(into, JSON.parse(raw));
139
+ }
140
+ catch {
141
+ // A malformed bag is a defect elsewhere; the audit reports the sources
142
+ // it could not resolve either way.
143
+ }
144
+ }
145
+ for (const child of node.children ?? [])
146
+ collectBags(child, into);
147
+ return into;
148
+ }
149
+ //# sourceMappingURL=schema-row.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-row.js","sourceRoot":"","sources":["../../src/lib/schema-row.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@refrakt-md/cli",
3
3
  "description": "CLI tools for refrakt.md",
4
- "version": "0.34.0",
4
+ "version": "0.36.0",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
7
  "repository": {
@@ -26,6 +26,10 @@
26
26
  "./lib/levenshtein.js": {
27
27
  "types": "./dist/lib/levenshtein.d.ts",
28
28
  "default": "./dist/lib/levenshtein.js"
29
+ },
30
+ "./validate.js": {
31
+ "types": "./dist/commands/validate-core.d.ts",
32
+ "default": "./dist/commands/validate-core.js"
29
33
  }
30
34
  },
31
35
  "files": [
@@ -36,11 +40,11 @@
36
40
  },
37
41
  "dependencies": {
38
42
  "@markdoc/markdoc": "0.4.0",
39
- "@refrakt-md/ai": "0.34.0",
40
- "@refrakt-md/editor": "0.34.0",
41
- "@refrakt-md/html": "0.34.0",
42
- "@refrakt-md/runes": "0.34.0",
43
- "@refrakt-md/transform": "0.34.0",
43
+ "@refrakt-md/ai": "0.36.0",
44
+ "@refrakt-md/editor": "0.36.0",
45
+ "@refrakt-md/html": "0.36.0",
46
+ "@refrakt-md/runes": "0.36.0",
47
+ "@refrakt-md/transform": "0.36.0",
44
48
  "esbuild": "^0.27.5",
45
49
  "postcss": "^8.4.0"
46
50
  }