@unoverse-platform/studio 0.1.93 → 0.1.95
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/package.json
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*
|
|
16
16
|
* FOUR TIERS (docs/architecture/DECLARATIVE_NODES.md §6). This is tiers 2 and 3.
|
|
17
17
|
* 1 editor $schema pointers + .vscode yaml.schemas, no tool
|
|
18
|
-
* 2 structural every part validated against nodes
|
|
18
|
+
* 2 structural every part validated against the node schemas (packages/docs/schemas/nodes)
|
|
19
19
|
* 3 semantic the cross-file rules a schema cannot express
|
|
20
20
|
* 4 dry run `unoverse node test`, executes against testData, not here
|
|
21
21
|
*/
|
|
@@ -36,16 +36,17 @@ import { lintPackage } from "./package.mjs";
|
|
|
36
36
|
/**
|
|
37
37
|
* Where the node schemas are, for this run.
|
|
38
38
|
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
* validating nothing while looking busy. So the schemas travel with the
|
|
43
|
-
* they sit beside this file (copy-lint.mjs puts them there, and the CLI
|
|
44
|
-
* folder); from source they are the
|
|
39
|
+
* Their home is packages/docs/schemas/nodes, which the docs site serves at the URL every
|
|
40
|
+
* node file's `$schema:` names (so any editor validates online). The linter runs offline
|
|
41
|
+
* and a developer's workspace holds no copy, and a linter that warned "no schema found" on
|
|
42
|
+
* every file was validating nothing while looking busy. So the schemas travel with the
|
|
43
|
+
* linter: in dist they sit beside this file (copy-lint.mjs puts them there, and the CLI
|
|
44
|
+
* vendors that folder); from source they are the docs tree's copy. A `_schema` folder in
|
|
45
|
+
* the workspace itself still wins, for anyone pinning a version.
|
|
45
46
|
*/
|
|
46
47
|
function schemaHome(home) {
|
|
47
48
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
48
|
-
for (const c of [join(home, "_schema"), join(here, "_schema"), resolve(here, "
|
|
49
|
+
for (const c of [join(home, "_schema"), join(here, "_schema"), resolve(here, "../../../../docs/schemas/nodes")])
|
|
49
50
|
if (existsSync(c)) return c;
|
|
50
51
|
return join(home, "_schema");
|
|
51
52
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Tier 2: structural validation against nodes
|
|
2
|
+
* Tier 2: structural validation against the node schemas (packages/docs/schemas/nodes).
|
|
3
3
|
*
|
|
4
4
|
* A JSON Schema catches shape. Everything a schema CANNOT express (cross-file agreement,
|
|
5
5
|
* ordering, reachability) is tier 3 and lives in the rule modules.
|
|
@@ -53,7 +53,7 @@ export function loadSchemas() {
|
|
|
53
53
|
export function validateAgainst(schemaId, doc, file, label) {
|
|
54
54
|
const schema = state.schemas[schemaId];
|
|
55
55
|
if (!schema) {
|
|
56
|
-
report("warn", file, `no schema found for ${label}.
|
|
56
|
+
report("warn", file, `no schema found for ${label}. The linter's bundled schemas are missing; rebuild base`);
|
|
57
57
|
return;
|
|
58
58
|
}
|
|
59
59
|
const v = new Validator(schema, "7", false);
|
|
@@ -47,7 +47,9 @@ export async function primeTemplating(): Promise<void> {}
|
|
|
47
47
|
* Deliberately only a dotted path: anything with a helper or a block is genuinely
|
|
48
48
|
* text assembly and belongs in Handlebars.
|
|
49
49
|
*/
|
|
50
|
-
|
|
50
|
+
// A segment may carry `-` or `/`: an org component's box is `<org>/<name>N`, and its
|
|
51
|
+
// paths are written as advertised (StringTemplateResolver, bracketSlashSegments).
|
|
52
|
+
const WHOLE_VALUE = /^\s*\{\{\s*([a-zA-Z_$][\w$/-]*(?:\.[\w$/-]+)*)\s*\}\}\s*$/;
|
|
51
53
|
|
|
52
54
|
function lookup(path: string, ctx: RunContext): unknown {
|
|
53
55
|
return path.split(".").reduce<any>((a, k) => (a == null ? a : a[k]), ctx as any);
|
|
@@ -48,10 +48,51 @@ Handlebars.registerHelper("contains", function (str, substring) {
|
|
|
48
48
|
return str.toLowerCase().includes(substring.toLowerCase());
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
+
/**
|
|
52
|
+
* A NODE ID MAY CARRY A SLASH, and Handlebars reads `/` as a path separator.
|
|
53
|
+
*
|
|
54
|
+
* An org component's box is minted as `<org>/<name>N` (componentRef), and every path
|
|
55
|
+
* the platform advertises for it is written the way an author would write it:
|
|
56
|
+
* `{{signal.some-org/card2.output.state}}`. Handlebars parses that as
|
|
57
|
+
* `signal.some-org.card2…`, finds nothing, and renders "" — no error, no log, an
|
|
58
|
+
* empty string where a page's state should be. Observed live 2026-09-05: a component
|
|
59
|
+
* capture parsed "" as JSON and the name on every extracted row was blank.
|
|
60
|
+
*
|
|
61
|
+
* Handlebars' own answer is the segment literal, `[some-org/card2]`, so every
|
|
62
|
+
* segment that carries a slash is bracketed before compile. Only bare path segments
|
|
63
|
+
* qualify (letters, digits, `_ $ -` and `/`): a quoted string, a URL with its colon, or
|
|
64
|
+
* a segment already bracketed is left exactly as written.
|
|
65
|
+
*/
|
|
66
|
+
const SLASH_SEGMENT = /(?<=^|[\s.(|=])([\w$-]+(?:\/[\w$-]+)+)(?=[.\s)}|]|$)/g;
|
|
67
|
+
export function bracketSlashSegments(template: string): string {
|
|
68
|
+
if (!template.includes("/")) return template;
|
|
69
|
+
return template.replace(/\{\{[^}]*\}\}/g, (mustache) => {
|
|
70
|
+
let out = "";
|
|
71
|
+
let quote: string | null = null;
|
|
72
|
+
let run = "";
|
|
73
|
+
const flush = () => {
|
|
74
|
+
out += run.replace(SLASH_SEGMENT, "[$1]");
|
|
75
|
+
run = "";
|
|
76
|
+
};
|
|
77
|
+
for (const ch of mustache) {
|
|
78
|
+
if (quote) {
|
|
79
|
+
out += ch;
|
|
80
|
+
if (ch === quote) quote = null;
|
|
81
|
+
} else if (ch === '"' || ch === "'") {
|
|
82
|
+
flush();
|
|
83
|
+
quote = ch;
|
|
84
|
+
out += ch;
|
|
85
|
+
} else run += ch;
|
|
86
|
+
}
|
|
87
|
+
flush();
|
|
88
|
+
return out;
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
|
|
51
92
|
// Create a memoized template compiler for performance
|
|
52
93
|
const compileTemplate = memoize((template: string) => {
|
|
53
94
|
// Disable HTML escaping to prevent issues like "I'll" becoming "I'll"
|
|
54
|
-
return Handlebars.compile(template, { noEscape: true });
|
|
95
|
+
return Handlebars.compile(bracketSlashSegments(template), { noEscape: true });
|
|
55
96
|
});
|
|
56
97
|
|
|
57
98
|
export function resolveStringTemplate(template: string, context: TemplateContext, logger: any): any {
|