@streetui/compiler 1.0.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 StreetUI contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,26 @@
1
+ # @streetui/compiler
2
+
3
+ StreetUI compiler — DSL → validation → Semantic Application Graph
4
+
5
+ Part of [StreetUI](https://github.com/streetui/streetui) — a semantic,
6
+ signal-based UI framework with its own reactivity and keyed DOM reconciler
7
+ (no virtual DOM).
8
+
9
+ ## Install
10
+
11
+ ```sh
12
+ npm install @streetui/compiler
13
+ ```
14
+
15
+ ## Usage
16
+
17
+ ```ts
18
+ import * as pkg from '@streetui/compiler';
19
+ ```
20
+
21
+ Both ESM (`import`) and CommonJS (`require`) entry points are shipped, with
22
+ matching TypeScript declarations.
23
+
24
+ ## License
25
+
26
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,178 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ compile: () => compile,
24
+ compileGraph: () => compileGraph,
25
+ transformGraph: () => transformGraph,
26
+ validateGraph: () => validateGraph
27
+ });
28
+ module.exports = __toCommonJS(index_exports);
29
+
30
+ // src/compile.ts
31
+ var import_core2 = require("@streetui/core");
32
+
33
+ // src/validation/validator.ts
34
+ var import_core = require("@streetui/core");
35
+ function validateGraph(graph) {
36
+ const dc = new import_core.DiagnosticCollector();
37
+ dc.merge(graph.validate());
38
+ const pages = graph.findByType("page");
39
+ if (pages.length === 0) {
40
+ dc.warn(
41
+ "COMPILER_NO_PAGES",
42
+ "Application has no pages defined. At least one page is recommended."
43
+ );
44
+ }
45
+ graph.walk((node) => {
46
+ validateNode(node, dc);
47
+ });
48
+ return dc;
49
+ }
50
+ function validateNode(node, dc) {
51
+ switch (node.type) {
52
+ case "heading": {
53
+ const text = node.getProp("text");
54
+ if (text === void 0 || text === "") {
55
+ dc.warn("COMPILER_EMPTY_HEADING", `Heading node "${node.id}" has no text content`, {
56
+ nodeId: node.id
57
+ });
58
+ }
59
+ break;
60
+ }
61
+ case "image": {
62
+ const src = node.getProp("src");
63
+ const alt = node.getProp("alt");
64
+ if (!src) {
65
+ dc.error("COMPILER_IMAGE_NO_SRC", `Image node "${node.id}" is missing src`, {
66
+ nodeId: node.id
67
+ });
68
+ }
69
+ if (!alt) {
70
+ dc.warn("COMPILER_IMAGE_NO_ALT", `Image node "${node.id}" is missing alt text`, {
71
+ nodeId: node.id
72
+ });
73
+ }
74
+ break;
75
+ }
76
+ case "link": {
77
+ const href = node.getProp("href");
78
+ if (!href) {
79
+ dc.error("COMPILER_LINK_NO_HREF", `Link node "${node.id}" is missing href`, {
80
+ nodeId: node.id
81
+ });
82
+ }
83
+ break;
84
+ }
85
+ default:
86
+ break;
87
+ }
88
+ }
89
+
90
+ // src/transform/transform.ts
91
+ function transformGraph(graph) {
92
+ graph.walk((node, depth) => {
93
+ applyDefaults(node);
94
+ ensureRenderKey(node, depth);
95
+ });
96
+ }
97
+ function applyDefaults(node) {
98
+ switch (node.type) {
99
+ case "heading": {
100
+ if (node.getProp("level") === void 0) {
101
+ node.setProp("level", 1);
102
+ }
103
+ break;
104
+ }
105
+ case "input": {
106
+ if (node.getProp("inputType") === void 0) {
107
+ node.setProp("inputType", "text");
108
+ }
109
+ break;
110
+ }
111
+ case "link": {
112
+ if (node.getProp("external") === void 0) {
113
+ node.setProp("external", false);
114
+ }
115
+ break;
116
+ }
117
+ default:
118
+ break;
119
+ }
120
+ }
121
+ function ensureRenderKey(node, depth) {
122
+ if (node.getProp("_renderKey") === void 0) {
123
+ const key = node.key ?? `${node.type}:${node.id}:${depth}`;
124
+ node.setProp("_renderKey", key);
125
+ }
126
+ }
127
+
128
+ // src/compile.ts
129
+ function compile(app, options = {}) {
130
+ const strict = options.strict ?? true;
131
+ const strictWarnings = options.strictWarnings ?? false;
132
+ const dc = new import_core2.DiagnosticCollector();
133
+ const graph = app.graph;
134
+ const validationDc = validateGraph(graph);
135
+ dc.merge(validationDc);
136
+ if (strict && dc.hasErrors) {
137
+ dc.throwIfErrors();
138
+ }
139
+ if (strictWarnings && dc.hasWarnings) {
140
+ throw new Error(
141
+ `[StreetUI Compiler] Compilation failed: warnings treated as errors.
142
+ ` + dc.diagnostics.filter((d) => d.severity === "warning").map((d) => ` [${d.code}] ${d.message}`).join("\n")
143
+ );
144
+ }
145
+ transformGraph(graph);
146
+ return {
147
+ graph,
148
+ diagnostics: dc,
149
+ name: graph.name,
150
+ version: graph.version,
151
+ compiledAt: Date.now()
152
+ };
153
+ }
154
+ function compileGraph(graph, options = {}) {
155
+ const strict = options.strict ?? true;
156
+ const dc = new import_core2.DiagnosticCollector();
157
+ const validationDc = validateGraph(graph);
158
+ dc.merge(validationDc);
159
+ if (strict && dc.hasErrors) {
160
+ dc.throwIfErrors();
161
+ }
162
+ transformGraph(graph);
163
+ return {
164
+ graph,
165
+ diagnostics: dc,
166
+ name: graph.name,
167
+ version: graph.version,
168
+ compiledAt: Date.now()
169
+ };
170
+ }
171
+ // Annotate the CommonJS export names for ESM import in node:
172
+ 0 && (module.exports = {
173
+ compile,
174
+ compileGraph,
175
+ transformGraph,
176
+ validateGraph
177
+ });
178
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/compile.ts","../src/validation/validator.ts","../src/transform/transform.ts"],"sourcesContent":["export * from './compile.js';\nexport * from './validation/validator.js';\nexport * from './transform/transform.js';\n","/**\n * StreetUI compiler entry point.\n *\n * Pipeline:\n * StreetApp (DSL)\n * → ApplicationGraph (build)\n * → validate\n * → transform\n * → CompiledApplication\n */\n\nimport { DiagnosticCollector } from '@streetui/core';\nimport { type ApplicationGraph } from '@streetui/graph';\nimport { type StreetApp } from '@streetui/dsl';\nimport { validateGraph } from './validation/validator.js';\nimport { transformGraph } from './transform/transform.js';\n\nexport interface CompiledApplication {\n /** The fully built, validated, and transformed graph. */\n readonly graph: ApplicationGraph;\n /** Diagnostics accumulated during compilation. */\n readonly diagnostics: DiagnosticCollector;\n /** Metadata */\n readonly name: string;\n readonly version: string;\n readonly compiledAt: number;\n}\n\nexport interface CompileOptions {\n /** If true, compilation throws on errors. Defaults to true. */\n readonly strict?: boolean;\n /** If true, also throw on warnings. Defaults to false. */\n readonly strictWarnings?: boolean;\n}\n\n/**\n * Compile a StreetApp DSL definition into a CompiledApplication\n * ready for the runtime to execute.\n */\nexport function compile(\n app: StreetApp,\n options: CompileOptions = {},\n): CompiledApplication {\n const strict = options.strict ?? true;\n const strictWarnings = options.strictWarnings ?? false;\n const dc = new DiagnosticCollector();\n\n // 1. Build the graph from the DSL\n const graph = app.graph;\n\n // 2. Validate\n const validationDc = validateGraph(graph);\n dc.merge(validationDc);\n\n if (strict && dc.hasErrors) {\n dc.throwIfErrors();\n }\n if (strictWarnings && dc.hasWarnings) {\n throw new Error(\n `[StreetUI Compiler] Compilation failed: warnings treated as errors.\\n` +\n dc.diagnostics\n .filter(d => d.severity === 'warning')\n .map(d => ` [${d.code}] ${d.message}`)\n .join('\\n'),\n );\n }\n\n // 3. Transform\n transformGraph(graph);\n\n return {\n graph,\n diagnostics: dc,\n name: graph.name,\n version: graph.version,\n compiledAt: Date.now(),\n };\n}\n\n/**\n * Compile from a pre-built ApplicationGraph (used when the graph\n * was constructed programmatically rather than through the DSL).\n */\nexport function compileGraph(\n graph: ApplicationGraph,\n options: CompileOptions = {},\n): CompiledApplication {\n const strict = options.strict ?? true;\n const dc = new DiagnosticCollector();\n\n const validationDc = validateGraph(graph);\n dc.merge(validationDc);\n\n if (strict && dc.hasErrors) {\n dc.throwIfErrors();\n }\n\n transformGraph(graph);\n\n return {\n graph,\n diagnostics: dc,\n name: graph.name,\n version: graph.version,\n compiledAt: Date.now(),\n };\n}\n","/**\n * Compiler-phase validation of the ApplicationGraph.\n *\n * This runs after the DSL has built the graph but before the runtime\n * receives a CompiledApplication. More checks live here than in the\n * graph's own validate() because the compiler has broader context.\n */\n\nimport { DiagnosticCollector } from '@streetui/core';\nimport { ApplicationGraph, GraphNode } from '@streetui/graph';\n\nexport function validateGraph(graph: ApplicationGraph): DiagnosticCollector {\n const dc = new DiagnosticCollector();\n\n // Merge built-in graph validations\n dc.merge(graph.validate());\n\n // Must have at least one page\n const pages = graph.findByType('page');\n if (pages.length === 0) {\n dc.warn(\n 'COMPILER_NO_PAGES',\n 'Application has no pages defined. At least one page is recommended.',\n );\n }\n\n // Walk and validate individual nodes\n graph.walk((node) => {\n validateNode(node, dc);\n });\n\n return dc;\n}\n\nfunction validateNode(node: GraphNode, dc: DiagnosticCollector): void {\n switch (node.type) {\n case 'heading': {\n const text = node.getProp('text');\n if (text === undefined || text === '') {\n dc.warn('COMPILER_EMPTY_HEADING', `Heading node \"${node.id}\" has no text content`, {\n nodeId: node.id,\n });\n }\n break;\n }\n case 'image': {\n const src = node.getProp('src');\n const alt = node.getProp('alt');\n if (!src) {\n dc.error('COMPILER_IMAGE_NO_SRC', `Image node \"${node.id}\" is missing src`, {\n nodeId: node.id,\n });\n }\n if (!alt) {\n dc.warn('COMPILER_IMAGE_NO_ALT', `Image node \"${node.id}\" is missing alt text`, {\n nodeId: node.id,\n });\n }\n break;\n }\n case 'link': {\n const href = node.getProp('href');\n if (!href) {\n dc.error('COMPILER_LINK_NO_HREF', `Link node \"${node.id}\" is missing href`, {\n nodeId: node.id,\n });\n }\n break;\n }\n default:\n break;\n }\n}\n","/**\n * Graph transformation pass.\n *\n * After validation, the transformer prepares the graph for the runtime by:\n * - Resolving implicit defaults (e.g. heading level defaults to 1)\n * - Normalizing prop names\n * - Assigning deterministic render keys where missing\n * - Flattening / hoisting where beneficial\n */\n\nimport { ApplicationGraph, GraphNode } from '@streetui/graph';\n\nexport function transformGraph(graph: ApplicationGraph): void {\n graph.walk((node, depth) => {\n applyDefaults(node);\n ensureRenderKey(node, depth);\n });\n}\n\nfunction applyDefaults(node: GraphNode): void {\n switch (node.type) {\n case 'heading': {\n if (node.getProp('level') === undefined) {\n node.setProp('level', 1);\n }\n break;\n }\n case 'input': {\n if (node.getProp('inputType') === undefined) {\n node.setProp('inputType', 'text');\n }\n break;\n }\n case 'link': {\n if (node.getProp('external') === undefined) {\n node.setProp('external', false);\n }\n break;\n }\n default:\n break;\n }\n}\n\nfunction ensureRenderKey(node: GraphNode, depth: number): void {\n if (node.getProp('_renderKey') === undefined) {\n const key = node.key ?? `${node.type}:${node.id}:${depth}`;\n node.setProp('_renderKey', key);\n }\n}\n"],"mappings":"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","names":["import_core"]}
@@ -0,0 +1,65 @@
1
+ import { DiagnosticCollector } from '@streetui/core';
2
+ import { ApplicationGraph } from '@streetui/graph';
3
+ import { StreetApp } from '@streetui/dsl';
4
+
5
+ /**
6
+ * StreetUI compiler entry point.
7
+ *
8
+ * Pipeline:
9
+ * StreetApp (DSL)
10
+ * → ApplicationGraph (build)
11
+ * → validate
12
+ * → transform
13
+ * → CompiledApplication
14
+ */
15
+
16
+ interface CompiledApplication {
17
+ /** The fully built, validated, and transformed graph. */
18
+ readonly graph: ApplicationGraph;
19
+ /** Diagnostics accumulated during compilation. */
20
+ readonly diagnostics: DiagnosticCollector;
21
+ /** Metadata */
22
+ readonly name: string;
23
+ readonly version: string;
24
+ readonly compiledAt: number;
25
+ }
26
+ interface CompileOptions {
27
+ /** If true, compilation throws on errors. Defaults to true. */
28
+ readonly strict?: boolean;
29
+ /** If true, also throw on warnings. Defaults to false. */
30
+ readonly strictWarnings?: boolean;
31
+ }
32
+ /**
33
+ * Compile a StreetApp DSL definition into a CompiledApplication
34
+ * ready for the runtime to execute.
35
+ */
36
+ declare function compile(app: StreetApp, options?: CompileOptions): CompiledApplication;
37
+ /**
38
+ * Compile from a pre-built ApplicationGraph (used when the graph
39
+ * was constructed programmatically rather than through the DSL).
40
+ */
41
+ declare function compileGraph(graph: ApplicationGraph, options?: CompileOptions): CompiledApplication;
42
+
43
+ /**
44
+ * Compiler-phase validation of the ApplicationGraph.
45
+ *
46
+ * This runs after the DSL has built the graph but before the runtime
47
+ * receives a CompiledApplication. More checks live here than in the
48
+ * graph's own validate() because the compiler has broader context.
49
+ */
50
+
51
+ declare function validateGraph(graph: ApplicationGraph): DiagnosticCollector;
52
+
53
+ /**
54
+ * Graph transformation pass.
55
+ *
56
+ * After validation, the transformer prepares the graph for the runtime by:
57
+ * - Resolving implicit defaults (e.g. heading level defaults to 1)
58
+ * - Normalizing prop names
59
+ * - Assigning deterministic render keys where missing
60
+ * - Flattening / hoisting where beneficial
61
+ */
62
+
63
+ declare function transformGraph(graph: ApplicationGraph): void;
64
+
65
+ export { type CompileOptions, type CompiledApplication, compile, compileGraph, transformGraph, validateGraph };
@@ -0,0 +1,65 @@
1
+ import { DiagnosticCollector } from '@streetui/core';
2
+ import { ApplicationGraph } from '@streetui/graph';
3
+ import { StreetApp } from '@streetui/dsl';
4
+
5
+ /**
6
+ * StreetUI compiler entry point.
7
+ *
8
+ * Pipeline:
9
+ * StreetApp (DSL)
10
+ * → ApplicationGraph (build)
11
+ * → validate
12
+ * → transform
13
+ * → CompiledApplication
14
+ */
15
+
16
+ interface CompiledApplication {
17
+ /** The fully built, validated, and transformed graph. */
18
+ readonly graph: ApplicationGraph;
19
+ /** Diagnostics accumulated during compilation. */
20
+ readonly diagnostics: DiagnosticCollector;
21
+ /** Metadata */
22
+ readonly name: string;
23
+ readonly version: string;
24
+ readonly compiledAt: number;
25
+ }
26
+ interface CompileOptions {
27
+ /** If true, compilation throws on errors. Defaults to true. */
28
+ readonly strict?: boolean;
29
+ /** If true, also throw on warnings. Defaults to false. */
30
+ readonly strictWarnings?: boolean;
31
+ }
32
+ /**
33
+ * Compile a StreetApp DSL definition into a CompiledApplication
34
+ * ready for the runtime to execute.
35
+ */
36
+ declare function compile(app: StreetApp, options?: CompileOptions): CompiledApplication;
37
+ /**
38
+ * Compile from a pre-built ApplicationGraph (used when the graph
39
+ * was constructed programmatically rather than through the DSL).
40
+ */
41
+ declare function compileGraph(graph: ApplicationGraph, options?: CompileOptions): CompiledApplication;
42
+
43
+ /**
44
+ * Compiler-phase validation of the ApplicationGraph.
45
+ *
46
+ * This runs after the DSL has built the graph but before the runtime
47
+ * receives a CompiledApplication. More checks live here than in the
48
+ * graph's own validate() because the compiler has broader context.
49
+ */
50
+
51
+ declare function validateGraph(graph: ApplicationGraph): DiagnosticCollector;
52
+
53
+ /**
54
+ * Graph transformation pass.
55
+ *
56
+ * After validation, the transformer prepares the graph for the runtime by:
57
+ * - Resolving implicit defaults (e.g. heading level defaults to 1)
58
+ * - Normalizing prop names
59
+ * - Assigning deterministic render keys where missing
60
+ * - Flattening / hoisting where beneficial
61
+ */
62
+
63
+ declare function transformGraph(graph: ApplicationGraph): void;
64
+
65
+ export { type CompileOptions, type CompiledApplication, compile, compileGraph, transformGraph, validateGraph };
package/dist/index.js ADDED
@@ -0,0 +1,148 @@
1
+ // src/compile.ts
2
+ import { DiagnosticCollector as DiagnosticCollector2 } from "@streetui/core";
3
+
4
+ // src/validation/validator.ts
5
+ import { DiagnosticCollector } from "@streetui/core";
6
+ function validateGraph(graph) {
7
+ const dc = new DiagnosticCollector();
8
+ dc.merge(graph.validate());
9
+ const pages = graph.findByType("page");
10
+ if (pages.length === 0) {
11
+ dc.warn(
12
+ "COMPILER_NO_PAGES",
13
+ "Application has no pages defined. At least one page is recommended."
14
+ );
15
+ }
16
+ graph.walk((node) => {
17
+ validateNode(node, dc);
18
+ });
19
+ return dc;
20
+ }
21
+ function validateNode(node, dc) {
22
+ switch (node.type) {
23
+ case "heading": {
24
+ const text = node.getProp("text");
25
+ if (text === void 0 || text === "") {
26
+ dc.warn("COMPILER_EMPTY_HEADING", `Heading node "${node.id}" has no text content`, {
27
+ nodeId: node.id
28
+ });
29
+ }
30
+ break;
31
+ }
32
+ case "image": {
33
+ const src = node.getProp("src");
34
+ const alt = node.getProp("alt");
35
+ if (!src) {
36
+ dc.error("COMPILER_IMAGE_NO_SRC", `Image node "${node.id}" is missing src`, {
37
+ nodeId: node.id
38
+ });
39
+ }
40
+ if (!alt) {
41
+ dc.warn("COMPILER_IMAGE_NO_ALT", `Image node "${node.id}" is missing alt text`, {
42
+ nodeId: node.id
43
+ });
44
+ }
45
+ break;
46
+ }
47
+ case "link": {
48
+ const href = node.getProp("href");
49
+ if (!href) {
50
+ dc.error("COMPILER_LINK_NO_HREF", `Link node "${node.id}" is missing href`, {
51
+ nodeId: node.id
52
+ });
53
+ }
54
+ break;
55
+ }
56
+ default:
57
+ break;
58
+ }
59
+ }
60
+
61
+ // src/transform/transform.ts
62
+ function transformGraph(graph) {
63
+ graph.walk((node, depth) => {
64
+ applyDefaults(node);
65
+ ensureRenderKey(node, depth);
66
+ });
67
+ }
68
+ function applyDefaults(node) {
69
+ switch (node.type) {
70
+ case "heading": {
71
+ if (node.getProp("level") === void 0) {
72
+ node.setProp("level", 1);
73
+ }
74
+ break;
75
+ }
76
+ case "input": {
77
+ if (node.getProp("inputType") === void 0) {
78
+ node.setProp("inputType", "text");
79
+ }
80
+ break;
81
+ }
82
+ case "link": {
83
+ if (node.getProp("external") === void 0) {
84
+ node.setProp("external", false);
85
+ }
86
+ break;
87
+ }
88
+ default:
89
+ break;
90
+ }
91
+ }
92
+ function ensureRenderKey(node, depth) {
93
+ if (node.getProp("_renderKey") === void 0) {
94
+ const key = node.key ?? `${node.type}:${node.id}:${depth}`;
95
+ node.setProp("_renderKey", key);
96
+ }
97
+ }
98
+
99
+ // src/compile.ts
100
+ function compile(app, options = {}) {
101
+ const strict = options.strict ?? true;
102
+ const strictWarnings = options.strictWarnings ?? false;
103
+ const dc = new DiagnosticCollector2();
104
+ const graph = app.graph;
105
+ const validationDc = validateGraph(graph);
106
+ dc.merge(validationDc);
107
+ if (strict && dc.hasErrors) {
108
+ dc.throwIfErrors();
109
+ }
110
+ if (strictWarnings && dc.hasWarnings) {
111
+ throw new Error(
112
+ `[StreetUI Compiler] Compilation failed: warnings treated as errors.
113
+ ` + dc.diagnostics.filter((d) => d.severity === "warning").map((d) => ` [${d.code}] ${d.message}`).join("\n")
114
+ );
115
+ }
116
+ transformGraph(graph);
117
+ return {
118
+ graph,
119
+ diagnostics: dc,
120
+ name: graph.name,
121
+ version: graph.version,
122
+ compiledAt: Date.now()
123
+ };
124
+ }
125
+ function compileGraph(graph, options = {}) {
126
+ const strict = options.strict ?? true;
127
+ const dc = new DiagnosticCollector2();
128
+ const validationDc = validateGraph(graph);
129
+ dc.merge(validationDc);
130
+ if (strict && dc.hasErrors) {
131
+ dc.throwIfErrors();
132
+ }
133
+ transformGraph(graph);
134
+ return {
135
+ graph,
136
+ diagnostics: dc,
137
+ name: graph.name,
138
+ version: graph.version,
139
+ compiledAt: Date.now()
140
+ };
141
+ }
142
+ export {
143
+ compile,
144
+ compileGraph,
145
+ transformGraph,
146
+ validateGraph
147
+ };
148
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/compile.ts","../src/validation/validator.ts","../src/transform/transform.ts"],"sourcesContent":["/**\n * StreetUI compiler entry point.\n *\n * Pipeline:\n * StreetApp (DSL)\n * → ApplicationGraph (build)\n * → validate\n * → transform\n * → CompiledApplication\n */\n\nimport { DiagnosticCollector } from '@streetui/core';\nimport { type ApplicationGraph } from '@streetui/graph';\nimport { type StreetApp } from '@streetui/dsl';\nimport { validateGraph } from './validation/validator.js';\nimport { transformGraph } from './transform/transform.js';\n\nexport interface CompiledApplication {\n /** The fully built, validated, and transformed graph. */\n readonly graph: ApplicationGraph;\n /** Diagnostics accumulated during compilation. */\n readonly diagnostics: DiagnosticCollector;\n /** Metadata */\n readonly name: string;\n readonly version: string;\n readonly compiledAt: number;\n}\n\nexport interface CompileOptions {\n /** If true, compilation throws on errors. Defaults to true. */\n readonly strict?: boolean;\n /** If true, also throw on warnings. Defaults to false. */\n readonly strictWarnings?: boolean;\n}\n\n/**\n * Compile a StreetApp DSL definition into a CompiledApplication\n * ready for the runtime to execute.\n */\nexport function compile(\n app: StreetApp,\n options: CompileOptions = {},\n): CompiledApplication {\n const strict = options.strict ?? true;\n const strictWarnings = options.strictWarnings ?? false;\n const dc = new DiagnosticCollector();\n\n // 1. Build the graph from the DSL\n const graph = app.graph;\n\n // 2. Validate\n const validationDc = validateGraph(graph);\n dc.merge(validationDc);\n\n if (strict && dc.hasErrors) {\n dc.throwIfErrors();\n }\n if (strictWarnings && dc.hasWarnings) {\n throw new Error(\n `[StreetUI Compiler] Compilation failed: warnings treated as errors.\\n` +\n dc.diagnostics\n .filter(d => d.severity === 'warning')\n .map(d => ` [${d.code}] ${d.message}`)\n .join('\\n'),\n );\n }\n\n // 3. Transform\n transformGraph(graph);\n\n return {\n graph,\n diagnostics: dc,\n name: graph.name,\n version: graph.version,\n compiledAt: Date.now(),\n };\n}\n\n/**\n * Compile from a pre-built ApplicationGraph (used when the graph\n * was constructed programmatically rather than through the DSL).\n */\nexport function compileGraph(\n graph: ApplicationGraph,\n options: CompileOptions = {},\n): CompiledApplication {\n const strict = options.strict ?? true;\n const dc = new DiagnosticCollector();\n\n const validationDc = validateGraph(graph);\n dc.merge(validationDc);\n\n if (strict && dc.hasErrors) {\n dc.throwIfErrors();\n }\n\n transformGraph(graph);\n\n return {\n graph,\n diagnostics: dc,\n name: graph.name,\n version: graph.version,\n compiledAt: Date.now(),\n };\n}\n","/**\n * Compiler-phase validation of the ApplicationGraph.\n *\n * This runs after the DSL has built the graph but before the runtime\n * receives a CompiledApplication. More checks live here than in the\n * graph's own validate() because the compiler has broader context.\n */\n\nimport { DiagnosticCollector } from '@streetui/core';\nimport { ApplicationGraph, GraphNode } from '@streetui/graph';\n\nexport function validateGraph(graph: ApplicationGraph): DiagnosticCollector {\n const dc = new DiagnosticCollector();\n\n // Merge built-in graph validations\n dc.merge(graph.validate());\n\n // Must have at least one page\n const pages = graph.findByType('page');\n if (pages.length === 0) {\n dc.warn(\n 'COMPILER_NO_PAGES',\n 'Application has no pages defined. At least one page is recommended.',\n );\n }\n\n // Walk and validate individual nodes\n graph.walk((node) => {\n validateNode(node, dc);\n });\n\n return dc;\n}\n\nfunction validateNode(node: GraphNode, dc: DiagnosticCollector): void {\n switch (node.type) {\n case 'heading': {\n const text = node.getProp('text');\n if (text === undefined || text === '') {\n dc.warn('COMPILER_EMPTY_HEADING', `Heading node \"${node.id}\" has no text content`, {\n nodeId: node.id,\n });\n }\n break;\n }\n case 'image': {\n const src = node.getProp('src');\n const alt = node.getProp('alt');\n if (!src) {\n dc.error('COMPILER_IMAGE_NO_SRC', `Image node \"${node.id}\" is missing src`, {\n nodeId: node.id,\n });\n }\n if (!alt) {\n dc.warn('COMPILER_IMAGE_NO_ALT', `Image node \"${node.id}\" is missing alt text`, {\n nodeId: node.id,\n });\n }\n break;\n }\n case 'link': {\n const href = node.getProp('href');\n if (!href) {\n dc.error('COMPILER_LINK_NO_HREF', `Link node \"${node.id}\" is missing href`, {\n nodeId: node.id,\n });\n }\n break;\n }\n default:\n break;\n }\n}\n","/**\n * Graph transformation pass.\n *\n * After validation, the transformer prepares the graph for the runtime by:\n * - Resolving implicit defaults (e.g. heading level defaults to 1)\n * - Normalizing prop names\n * - Assigning deterministic render keys where missing\n * - Flattening / hoisting where beneficial\n */\n\nimport { ApplicationGraph, GraphNode } from '@streetui/graph';\n\nexport function transformGraph(graph: ApplicationGraph): void {\n graph.walk((node, depth) => {\n applyDefaults(node);\n ensureRenderKey(node, depth);\n });\n}\n\nfunction applyDefaults(node: GraphNode): void {\n switch (node.type) {\n case 'heading': {\n if (node.getProp('level') === undefined) {\n node.setProp('level', 1);\n }\n break;\n }\n case 'input': {\n if (node.getProp('inputType') === undefined) {\n node.setProp('inputType', 'text');\n }\n break;\n }\n case 'link': {\n if (node.getProp('external') === undefined) {\n node.setProp('external', false);\n }\n break;\n }\n default:\n break;\n }\n}\n\nfunction ensureRenderKey(node: GraphNode, depth: number): void {\n if (node.getProp('_renderKey') === undefined) {\n const key = node.key ?? `${node.type}:${node.id}:${depth}`;\n node.setProp('_renderKey', key);\n }\n}\n"],"mappings":"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","names":["DiagnosticCollector","DiagnosticCollector"]}
package/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@streetui/compiler",
3
+ "version": "1.0.0",
4
+ "description": "StreetUI compiler — DSL → validation → Semantic Application Graph",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": {
12
+ "types": "./dist/index.d.ts",
13
+ "default": "./dist/index.js"
14
+ },
15
+ "require": {
16
+ "types": "./dist/index.d.cts",
17
+ "default": "./dist/index.cjs"
18
+ }
19
+ }
20
+ },
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "typecheck": "tsc --noEmit",
24
+ "test": "vitest run",
25
+ "clean": "rm -rf dist"
26
+ },
27
+ "dependencies": {
28
+ "@streetui/core": "1.0.0",
29
+ "@streetui/graph": "1.0.0",
30
+ "@streetui/dsl": "1.0.0",
31
+ "@streetui/state": "1.0.0"
32
+ },
33
+ "devDependencies": {
34
+ "typescript": "*",
35
+ "tsup": "*",
36
+ "vitest": "*"
37
+ },
38
+ "license": "MIT",
39
+ "sideEffects": false,
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "files": [
44
+ "dist",
45
+ "README.md",
46
+ "LICENSE"
47
+ ]
48
+ }