@runcontext/site 0.1.0 → 0.2.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/dist/index.cjs CHANGED
@@ -1,549 +1,663 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } }// src/generator.ts
2
- var _promises = require('fs/promises');
3
- var _path = require('path');
4
- var _url = require('url');
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { newObj[key] = obj[key]; } } } newObj.default = obj; return newObj; } } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/generator.ts
5
2
  var _ejs = require('ejs'); var _ejs2 = _interopRequireDefault(_ejs);
3
+ var _fs = require('fs'); var fs = _interopRequireWildcard(_fs);
4
+ var _path = require('path'); var path = _interopRequireWildcard(_path);
6
5
 
7
6
  // src/templates.ts
8
- var layoutTemplate = `<!DOCTYPE html>
7
+ var HEAD = `<!DOCTYPE html>
9
8
  <html lang="en">
10
9
  <head>
11
10
  <meta charset="UTF-8">
12
11
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
13
- <title><%= pageTitle %> - <%= project.displayName %></title>
12
+ <title><%= pageTitle %> \u2014 <%= siteTitle %></title>
14
13
  <script src="https://cdn.tailwindcss.com"></script>
15
- <link rel="stylesheet" href="<%= basePath %>/style.css">
16
- </head>
17
- <body class="bg-gray-50 text-gray-900 min-h-screen flex flex-col">
18
- <nav class="bg-white border-b border-gray-200 px-6 py-3">
19
- <div class="max-w-6xl mx-auto flex items-center gap-6">
20
- <a href="<%= basePath %>/" class="font-bold text-lg text-blue-600"><%= project.displayName %></a>
21
- <div class="flex gap-4 text-sm">
22
- <a href="<%= basePath %>/" class="hover:text-blue-600">Home</a>
23
- <a href="<%= basePath %>/glossary.html" class="hover:text-blue-600">Glossary</a>
24
- <a href="<%= basePath %>/search.html" class="hover:text-blue-600">Search</a>
14
+ </head>`;
15
+ var NAV = `<nav class="bg-gray-900 text-white px-6 py-3 flex items-center gap-6">
16
+ <a href="<%= basePath %>/" class="font-bold text-lg"><%- siteTitle %></a>
17
+ <a href="<%= basePath %>/" class="hover:underline">Models</a>
18
+ <a href="<%= basePath %>/glossary.html" class="hover:underline">Glossary</a>
19
+ <a href="<%= basePath %>/search.html" class="hover:underline">Search</a>
20
+ </nav>`;
21
+ var FOOTER = `<footer class="mt-12 border-t py-4 px-6 text-gray-500 text-sm">
22
+ Generated by <a href="https://github.com/erickittelson/ContextKit" class="underline">ContextKit</a>
23
+ </footer>`;
24
+ var TIER_BADGE = `<% function tierBadge(tier) {
25
+ var colors = { none: 'bg-gray-200 text-gray-700', bronze: 'bg-amber-700 text-white', silver: 'bg-gray-400 text-white', gold: 'bg-yellow-400 text-black' };
26
+ var cls = colors[tier] || colors.none;
27
+ return '<span class="px-2 py-0.5 rounded text-xs font-semibold uppercase ' + cls + '">' + tier + '</span>';
28
+ } %>`;
29
+ var indexTemplate = `${HEAD}
30
+ <body class="bg-white text-gray-900 min-h-screen">
31
+ ${NAV}
32
+ ${TIER_BADGE}
33
+ <main class="max-w-5xl mx-auto p-6">
34
+ <h1 class="text-3xl font-bold mb-6"><%- siteTitle %></h1>
35
+
36
+ <section>
37
+ <h2 class="text-xl font-semibold mb-4">Models</h2>
38
+ <% if (Object.keys(models).length === 0) { %>
39
+ <p class="text-gray-500">No models found.</p>
40
+ <% } else { %>
41
+ <div class="grid gap-4">
42
+ <% for (var name of Object.keys(models)) { %>
43
+ <div class="border rounded-lg p-4 hover:shadow transition">
44
+ <div class="flex items-center gap-3">
45
+ <a href="<%= basePath %>/models/<%= name %>.html" class="text-lg font-medium text-blue-600 hover:underline"><%= name %></a>
46
+ <% if (tiers[name]) { %><%- tierBadge(tiers[name].tier) %><% } %>
47
+ </div>
48
+ <% if (models[name].description) { %>
49
+ <p class="text-gray-600 mt-1"><%= models[name].description %></p>
50
+ <% } %>
51
+ <% if (governance[name]) { %>
52
+ <div class="flex gap-2 mt-2 text-xs text-gray-500">
53
+ <% if (governance[name].owner) { %>
54
+ <span>Owner: <a href="<%= basePath %>/owners/<%= governance[name].owner %>.html" class="underline"><%= governance[name].owner %></a></span>
55
+ <% } %>
56
+ <% if (governance[name].trust) { %>
57
+ <span>Trust: <%= governance[name].trust %></span>
58
+ <% } %>
59
+ </div>
60
+ <% } %>
61
+ </div>
62
+ <% } %>
25
63
  </div>
26
- </div>
27
- </nav>
28
- <main class="flex-1 max-w-6xl mx-auto w-full px-6 py-8">
29
- <%- content %>
30
- </main>
31
- <footer class="bg-white border-t border-gray-200 px-6 py-4 text-center text-sm text-gray-500">
32
- Built with <a href="https://github.com/contextkit" class="text-blue-600 hover:underline">ContextKit</a> &middot; <%= build.timestamp %>
33
- </footer>
64
+ <% } %>
65
+ </section>
66
+
67
+ <% if (Object.keys(owners).length > 0) { %>
68
+ <section class="mt-8">
69
+ <h2 class="text-xl font-semibold mb-4">Owners</h2>
70
+ <ul class="space-y-1">
71
+ <% for (var oid of Object.keys(owners)) { %>
72
+ <li><a href="<%= basePath %>/owners/<%= oid %>.html" class="text-blue-600 hover:underline"><%= owners[oid].display_name %></a></li>
73
+ <% } %>
74
+ </ul>
75
+ </section>
76
+ <% } %>
77
+ </main>
78
+ ${FOOTER}
34
79
  </body>
35
80
  </html>`;
36
- var indexTemplate = `<h1 class="text-3xl font-bold mb-2"><%= project.displayName %></h1>
37
- <p class="text-gray-600 mb-6">Version <%= project.version %></p>
38
-
39
- <div class="grid grid-cols-2 md:grid-cols-3 gap-4 mb-8">
40
- <div class="bg-white rounded-lg shadow p-4 text-center">
41
- <div class="text-2xl font-bold text-blue-600"><%= concepts.length %></div>
42
- <div class="text-sm text-gray-500">Concepts</div>
43
- </div>
44
- <div class="bg-white rounded-lg shadow p-4 text-center">
45
- <div class="text-2xl font-bold text-green-600"><%= products.length %></div>
46
- <div class="text-sm text-gray-500">Products</div>
81
+ var modelTemplate = `${HEAD}
82
+ <body class="bg-white text-gray-900 min-h-screen">
83
+ ${NAV}
84
+ ${TIER_BADGE}
85
+ <main class="max-w-5xl mx-auto p-6">
86
+ <div class="flex items-center gap-3 mb-2">
87
+ <h1 class="text-3xl font-bold"><%= model.name %></h1>
88
+ <% if (tier) { %><%- tierBadge(tier.tier) %><% } %>
47
89
  </div>
48
- <div class="bg-white rounded-lg shadow p-4 text-center">
49
- <div class="text-2xl font-bold text-purple-600"><%= policies.length %></div>
50
- <div class="text-sm text-gray-500">Policies</div>
51
- </div>
52
- <div class="bg-white rounded-lg shadow p-4 text-center">
53
- <div class="text-2xl font-bold text-orange-600"><%= entities.length %></div>
54
- <div class="text-sm text-gray-500">Entities</div>
55
- </div>
56
- <div class="bg-white rounded-lg shadow p-4 text-center">
57
- <div class="text-2xl font-bold text-teal-600"><%= terms.length %></div>
58
- <div class="text-sm text-gray-500">Terms</div>
90
+ <% if (model.description) { %>
91
+ <p class="text-gray-600 mb-4"><%= model.description %></p>
92
+ <% } %>
93
+
94
+ <div class="flex gap-3 mb-6 text-sm">
95
+ <a href="<%= basePath %>/models/<%= model.name %>/schema.html" class="text-blue-600 hover:underline">Schema Browser</a>
96
+ <a href="<%= basePath %>/models/<%= model.name %>/rules.html" class="text-blue-600 hover:underline">Rules &amp; Queries</a>
59
97
  </div>
60
- <div class="bg-white rounded-lg shadow p-4 text-center">
61
- <div class="text-2xl font-bold text-red-600"><%= owners.length %></div>
62
- <div class="text-sm text-gray-500">Owners</div>
98
+
99
+ <% if (gov) { %>
100
+ <section class="mb-6">
101
+ <h2 class="text-xl font-semibold mb-2">Governance</h2>
102
+ <table class="table-auto border-collapse text-sm">
103
+ <tbody>
104
+ <tr><td class="pr-4 font-medium">Owner</td><td><a href="<%= basePath %>/owners/<%= gov.owner %>.html" class="text-blue-600 underline"><%= gov.owner %></a></td></tr>
105
+ <% if (gov.trust) { %><tr><td class="pr-4 font-medium">Trust</td><td><%= gov.trust %></td></tr><% } %>
106
+ <% if (gov.security) { %><tr><td class="pr-4 font-medium">Security</td><td><%= gov.security %></td></tr><% } %>
107
+ <% if (gov.tags && gov.tags.length > 0) { %><tr><td class="pr-4 font-medium">Tags</td><td><%= gov.tags.join(', ') %></td></tr><% } %>
108
+ </tbody>
109
+ </table>
110
+ </section>
111
+ <% } %>
112
+
113
+ <% if (model.datasets && model.datasets.length > 0) { %>
114
+ <section class="mb-6">
115
+ <h2 class="text-xl font-semibold mb-2">Datasets</h2>
116
+ <div class="space-y-3">
117
+ <% for (var ds of model.datasets) { %>
118
+ <div class="border rounded p-3">
119
+ <div class="font-medium"><%= ds.name %></div>
120
+ <div class="text-xs text-gray-500">Source: <%= ds.source %></div>
121
+ <% if (ds.description) { %><p class="text-sm text-gray-600 mt-1"><%= ds.description %></p><% } %>
122
+ <% if (ds.fields && ds.fields.length > 0) { %>
123
+ <div class="text-xs text-gray-500 mt-1"><%= ds.fields.length %> field(s)</div>
124
+ <% } %>
125
+ </div>
126
+ <% } %>
127
+ </div>
128
+ </section>
129
+ <% } %>
130
+
131
+ <% if (model.relationships && model.relationships.length > 0) { %>
132
+ <section class="mb-6">
133
+ <h2 class="text-xl font-semibold mb-2">Relationships</h2>
134
+ <table class="table-auto w-full text-sm border-collapse">
135
+ <thead>
136
+ <tr class="border-b"><th class="text-left py-1 pr-3">Name</th><th class="text-left py-1 pr-3">From</th><th class="text-left py-1">To</th></tr>
137
+ </thead>
138
+ <tbody>
139
+ <% for (var rel of model.relationships) { %>
140
+ <tr class="border-b"><td class="py-1 pr-3"><%= rel.name %></td><td class="py-1 pr-3"><%= rel.from %></td><td class="py-1"><%= rel.to %></td></tr>
141
+ <% } %>
142
+ </tbody>
143
+ </table>
144
+ </section>
145
+ <% } %>
146
+
147
+ <% if (model.metrics && model.metrics.length > 0) { %>
148
+ <section class="mb-6">
149
+ <h2 class="text-xl font-semibold mb-2">Metrics</h2>
150
+ <div class="space-y-2">
151
+ <% for (var metric of model.metrics) { %>
152
+ <div class="border rounded p-3">
153
+ <div class="font-medium"><%= metric.name %></div>
154
+ <% if (metric.description) { %><p class="text-sm text-gray-600"><%= metric.description %></p><% } %>
155
+ </div>
156
+ <% } %>
157
+ </div>
158
+ </section>
159
+ <% } %>
160
+
161
+ <% if (tier) { %>
162
+ <section class="mb-6">
163
+ <h2 class="text-xl font-semibold mb-2">Tier Details</h2>
164
+ <% var tierLevels = ['bronze', 'silver', 'gold']; %>
165
+ <% for (var lvl of tierLevels) { %>
166
+ <div class="mb-3">
167
+ <h3 class="font-medium capitalize flex items-center gap-2">
168
+ <%= lvl %>
169
+ <% if (tier[lvl].passed) { %>
170
+ <span class="text-green-600 text-xs">Passed</span>
171
+ <% } else { %>
172
+ <span class="text-red-500 text-xs">Not passed</span>
173
+ <% } %>
174
+ </h3>
175
+ <% if (tier[lvl].checks && tier[lvl].checks.length > 0) { %>
176
+ <ul class="text-sm ml-4 list-disc">
177
+ <% for (var chk of tier[lvl].checks) { %>
178
+ <li class="<%= chk.passed ? 'text-green-700' : 'text-red-600' %>"><%= chk.label %><% if (chk.detail) { %> \u2014 <%= chk.detail %><% } %></li>
179
+ <% } %>
180
+ </ul>
181
+ <% } %>
182
+ </div>
183
+ <% } %>
184
+ </section>
185
+ <% } %>
186
+ </main>
187
+ ${FOOTER}
188
+ </body>
189
+ </html>`;
190
+ var schemaTemplate = `${HEAD}
191
+ <body class="bg-white text-gray-900 min-h-screen">
192
+ ${NAV}
193
+ ${TIER_BADGE}
194
+ <main class="max-w-5xl mx-auto p-6">
195
+ <div class="flex items-center gap-3 mb-2">
196
+ <h1 class="text-3xl font-bold"><%= model.name %> \u2014 Schema Browser</h1>
197
+ <% if (tier) { %><%- tierBadge(tier.tier) %><% } %>
63
198
  </div>
64
- </div>
65
-
66
- <% if (concepts.length > 0) { %>
67
- <h2 class="text-xl font-semibold mb-3">Concepts</h2>
68
- <ul class="mb-6 space-y-1">
69
- <% concepts.forEach(function(c) { %>
70
- <li><a href="<%= basePath %>/concepts/<%= c.id %>.html" class="text-blue-600 hover:underline"><%= c.id %></a>
71
- <% if (c.certified) { %><span class="ml-1 text-xs bg-green-100 text-green-800 px-1.5 py-0.5 rounded">certified</span><% } %>
72
- </li>
73
- <% }); %>
74
- </ul>
75
- <% } %>
76
-
77
- <% if (products.length > 0) { %>
78
- <h2 class="text-xl font-semibold mb-3">Products</h2>
79
- <ul class="mb-6 space-y-1">
80
- <% products.forEach(function(p) { %>
81
- <li><a href="<%= basePath %>/products/<%= p.id %>.html" class="text-blue-600 hover:underline"><%= p.id %></a></li>
82
- <% }); %>
83
- </ul>
84
- <% } %>
85
-
86
- <% if (policies.length > 0) { %>
87
- <h2 class="text-xl font-semibold mb-3">Policies</h2>
88
- <ul class="mb-6 space-y-1">
89
- <% policies.forEach(function(p) { %>
90
- <li><a href="<%= basePath %>/policies/<%= p.id %>.html" class="text-blue-600 hover:underline"><%= p.id %></a></li>
91
- <% }); %>
92
- </ul>
93
- <% } %>
94
-
95
- <% if (owners.length > 0) { %>
96
- <h2 class="text-xl font-semibold mb-3">Owners</h2>
97
- <ul class="mb-6 space-y-1">
98
- <% owners.forEach(function(o) { %>
99
- <li><a href="<%= basePath %>/owners/<%= o.id %>.html" class="text-blue-600 hover:underline"><%= o.displayName %></a></li>
100
- <% }); %>
101
- </ul>
102
- <% } %>`;
103
- var conceptTemplate = `<nav class="text-sm text-gray-500 mb-4">
104
- <a href="<%= basePath %>/" class="hover:text-blue-600">Home</a> &rsaquo; Concepts &rsaquo; <%= concept.id %>
105
- </nav>
106
-
107
- <h1 class="text-3xl font-bold mb-2"><%= concept.id %>
108
- <% if (concept.certified) { %><span class="ml-2 text-sm bg-green-100 text-green-800 px-2 py-0.5 rounded">certified</span><% } %>
109
- </h1>
110
-
111
- <p class="text-lg text-gray-700 mb-6"><%= concept.definition %></p>
112
-
113
- <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
114
- <% if (concept.owner) { %>
115
- <div class="bg-white rounded-lg shadow p-4">
116
- <div class="text-sm text-gray-500">Owner</div>
117
- <a href="<%= basePath %>/owners/<%= concept.owner %>.html" class="text-blue-600 hover:underline"><%= concept.owner %></a>
199
+ <div class="mb-4 text-sm">
200
+ <a href="<%= basePath %>/models/<%= model.name %>.html" class="text-blue-600 hover:underline">&larr; Back to model</a>
118
201
  </div>
202
+
203
+ <% if (model.datasets && model.datasets.length > 0) { %>
204
+ <% for (var ds of model.datasets) { %>
205
+ <section class="mb-8 border rounded-lg p-4">
206
+ <h2 class="text-xl font-semibold mb-1"><%= ds.name %></h2>
207
+ <div class="text-xs text-gray-500 mb-2">Source: <%= ds.source %></div>
208
+ <% if (ds.description) { %><p class="text-sm text-gray-600 mb-3"><%= ds.description %></p><% } %>
209
+
210
+ <% var dsGov = gov && gov.datasets && gov.datasets[ds.name]; %>
211
+ <% if (dsGov) { %>
212
+ <div class="text-xs text-gray-500 mb-3 flex gap-4">
213
+ <% if (dsGov.grain) { %><span>Grain: <strong><%= dsGov.grain %></strong></span><% } %>
214
+ <% if (dsGov.table_type) { %><span>Type: <strong><%= dsGov.table_type %></strong></span><% } %>
215
+ <% if (dsGov.refresh) { %><span>Refresh: <strong><%= dsGov.refresh %></strong></span><% } %>
216
+ <% if (dsGov.security) { %><span>Security: <strong><%= dsGov.security %></strong></span><% } %>
217
+ </div>
218
+ <% } %>
219
+
220
+ <% if (ds.fields && ds.fields.length > 0) { %>
221
+ <table class="table-auto w-full text-sm border-collapse">
222
+ <thead>
223
+ <tr class="border-b bg-gray-50">
224
+ <th class="text-left py-2 px-2">Field</th>
225
+ <th class="text-left py-2 px-2">Description</th>
226
+ <th class="text-left py-2 px-2">Semantic Role</th>
227
+ <th class="text-left py-2 px-2">Aggregation</th>
228
+ </tr>
229
+ </thead>
230
+ <tbody>
231
+ <% for (var field of ds.fields) { %>
232
+ <% var fieldKey = ds.name + '.' + field.name; %>
233
+ <% var fGov = gov && gov.fields && gov.fields[fieldKey]; %>
234
+ <tr class="border-b">
235
+ <td class="py-1 px-2 font-mono text-xs"><%= field.name %></td>
236
+ <td class="py-1 px-2"><%= field.description || '' %></td>
237
+ <td class="py-1 px-2"><%= fGov && fGov.semantic_role ? fGov.semantic_role : '' %></td>
238
+ <td class="py-1 px-2"><%= fGov && fGov.default_aggregation ? fGov.default_aggregation : '' %></td>
239
+ </tr>
240
+ <% } %>
241
+ </tbody>
242
+ </table>
243
+ <% } else { %>
244
+ <p class="text-gray-400 text-sm">No fields defined.</p>
245
+ <% } %>
246
+ </section>
247
+ <% } %>
248
+ <% } else { %>
249
+ <p class="text-gray-500">No datasets found.</p>
119
250
  <% } %>
120
- <% if (concept.productId) { %>
121
- <div class="bg-white rounded-lg shadow p-4">
122
- <div class="text-sm text-gray-500">Product</div>
123
- <a href="<%= basePath %>/products/<%= concept.productId %>.html" class="text-blue-600 hover:underline"><%= concept.productId %></a>
251
+ </main>
252
+ ${FOOTER}
253
+ </body>
254
+ </html>`;
255
+ var rulesTemplate = `${HEAD}
256
+ <body class="bg-white text-gray-900 min-h-screen">
257
+ ${NAV}
258
+ <main class="max-w-5xl mx-auto p-6">
259
+ <h1 class="text-3xl font-bold mb-2"><%= modelName %> \u2014 Rules &amp; Queries</h1>
260
+ <div class="mb-4 text-sm">
261
+ <a href="<%= basePath %>/models/<%= modelName %>.html" class="text-blue-600 hover:underline">&larr; Back to model</a>
124
262
  </div>
263
+
264
+ <% if (rules && rules.golden_queries && rules.golden_queries.length > 0) { %>
265
+ <section class="mb-8">
266
+ <h2 class="text-xl font-semibold mb-3">Golden Queries</h2>
267
+ <div class="space-y-4">
268
+ <% for (var gq of rules.golden_queries) { %>
269
+ <div class="border rounded-lg p-4">
270
+ <div class="font-medium mb-2"><%= gq.question %></div>
271
+ <pre class="bg-gray-100 rounded p-3 text-sm overflow-x-auto"><code><%= gq.sql %></code></pre>
272
+ <% if (gq.dialect) { %><div class="text-xs text-gray-500 mt-1">Dialect: <%= gq.dialect %></div><% } %>
273
+ <% if (gq.tags && gq.tags.length > 0) { %><div class="text-xs text-gray-500 mt-1">Tags: <%= gq.tags.join(', ') %></div><% } %>
274
+ </div>
275
+ <% } %>
276
+ </div>
277
+ </section>
125
278
  <% } %>
126
- </div>
127
-
128
- <% if (concept.tags && concept.tags.length > 0) { %>
129
- <div class="mb-4">
130
- <span class="text-sm text-gray-500 mr-2">Tags:</span>
131
- <% concept.tags.forEach(function(tag) { %>
132
- <span class="inline-block bg-gray-100 text-gray-700 text-xs px-2 py-0.5 rounded mr-1"><%= tag %></span>
133
- <% }); %>
134
- </div>
135
- <% } %>
136
-
137
- <% if (concept.dependsOn && concept.dependsOn.length > 0) { %>
138
- <h2 class="text-xl font-semibold mb-3">Dependencies</h2>
139
- <ul class="mb-6 space-y-1">
140
- <% concept.dependsOn.forEach(function(dep) { %>
141
- <li><a href="<%= basePath %>/concepts/<%= dep %>.html" class="text-blue-600 hover:underline"><%= dep %></a></li>
142
- <% }); %>
143
- </ul>
144
- <% } %>`;
145
- var productTemplate = `<nav class="text-sm text-gray-500 mb-4">
146
- <a href="<%= basePath %>/" class="hover:text-blue-600">Home</a> &rsaquo; Products &rsaquo; <%= product.id %>
147
- </nav>
148
-
149
- <h1 class="text-3xl font-bold mb-2"><%= product.id %></h1>
150
- <p class="text-lg text-gray-700 mb-6"><%= product.description %></p>
151
-
152
- <% if (product.owner) { %>
153
- <div class="mb-4">
154
- <span class="text-sm text-gray-500 mr-2">Owner:</span>
155
- <a href="<%= basePath %>/owners/<%= product.owner %>.html" class="text-blue-600 hover:underline"><%= product.owner %></a>
156
- </div>
157
- <% } %>
158
-
159
- <% if (product.tags && product.tags.length > 0) { %>
160
- <div class="mb-4">
161
- <span class="text-sm text-gray-500 mr-2">Tags:</span>
162
- <% product.tags.forEach(function(tag) { %>
163
- <span class="inline-block bg-gray-100 text-gray-700 text-xs px-2 py-0.5 rounded mr-1"><%= tag %></span>
164
- <% }); %>
165
- </div>
166
- <% } %>
167
-
168
- <% if (relatedConcepts.length > 0) { %>
169
- <h2 class="text-xl font-semibold mb-3">Concepts</h2>
170
- <ul class="mb-6 space-y-1">
171
- <% relatedConcepts.forEach(function(c) { %>
172
- <li><a href="<%= basePath %>/concepts/<%= c.id %>.html" class="text-blue-600 hover:underline"><%= c.id %></a> &mdash; <%= c.definition %></li>
173
- <% }); %>
174
- </ul>
175
- <% } %>`;
176
- var policyTemplate = `<nav class="text-sm text-gray-500 mb-4">
177
- <a href="<%= basePath %>/" class="hover:text-blue-600">Home</a> &rsaquo; Policies &rsaquo; <%= policy.id %>
178
- </nav>
179
-
180
- <h1 class="text-3xl font-bold mb-2"><%= policy.id %></h1>
181
- <p class="text-lg text-gray-700 mb-6"><%= policy.description %></p>
182
-
183
- <% if (policy.owner) { %>
184
- <div class="mb-4">
185
- <span class="text-sm text-gray-500 mr-2">Owner:</span>
186
- <a href="<%= basePath %>/owners/<%= policy.owner %>.html" class="text-blue-600 hover:underline"><%= policy.owner %></a>
187
- </div>
188
- <% } %>
189
-
190
- <% if (policy.tags && policy.tags.length > 0) { %>
191
- <div class="mb-4">
192
- <span class="text-sm text-gray-500 mr-2">Tags:</span>
193
- <% policy.tags.forEach(function(tag) { %>
194
- <span class="inline-block bg-gray-100 text-gray-700 text-xs px-2 py-0.5 rounded mr-1"><%= tag %></span>
195
- <% }); %>
196
- </div>
197
- <% } %>
198
-
199
- <% if (policy.rules && policy.rules.length > 0) { %>
200
- <h2 class="text-xl font-semibold mb-3">Rules</h2>
201
- <div class="overflow-x-auto">
202
- <table class="min-w-full bg-white rounded-lg shadow text-sm">
203
- <thead>
204
- <tr class="bg-gray-50 text-left">
205
- <th class="px-4 py-2">Priority</th>
206
- <th class="px-4 py-2">When</th>
207
- <th class="px-4 py-2">Then</th>
208
- </tr>
209
- </thead>
210
- <tbody>
211
- <% policy.rules.forEach(function(rule) { %>
212
- <tr class="border-t">
213
- <td class="px-4 py-2"><%= rule.priority %></td>
214
- <td class="px-4 py-2">
215
- <% if (rule.when.tagsAny) { %>tags: <%= rule.when.tagsAny.join(', ') %><% } %>
216
- <% if (rule.when.conceptIds) { %>concepts: <%= rule.when.conceptIds.join(', ') %><% } %>
217
- <% if (rule.when.status) { %>status: <%= rule.when.status %><% } %>
218
- </td>
219
- <td class="px-4 py-2">
220
- <% if (rule.then.requireRole) { %>require role: <%= rule.then.requireRole %><% } %>
221
- <% if (rule.then.deny) { %>deny<% } %>
222
- <% if (rule.then.warn) { %>warn: <%= rule.then.warn %><% } %>
223
- </td>
224
- </tr>
225
- <% }); %>
226
- </tbody>
227
- </table>
228
- </div>
229
- <% } %>`;
230
- var ownerTemplate = `<nav class="text-sm text-gray-500 mb-4">
231
- <a href="<%= basePath %>/" class="hover:text-blue-600">Home</a> &rsaquo; Owners &rsaquo; <%= owner.id %>
232
- </nav>
233
-
234
- <h1 class="text-3xl font-bold mb-2"><%= owner.displayName %></h1>
235
-
236
- <div class="grid grid-cols-1 md:grid-cols-3 gap-4 mb-6">
237
- <div class="bg-white rounded-lg shadow p-4">
238
- <div class="text-sm text-gray-500">ID</div>
239
- <div><%= owner.id %></div>
240
- </div>
241
- <% if (owner.email) { %>
242
- <div class="bg-white rounded-lg shadow p-4">
243
- <div class="text-sm text-gray-500">Email</div>
244
- <div><a href="mailto:<%= owner.email %>" class="text-blue-600 hover:underline"><%= owner.email %></a></div>
245
- </div>
279
+
280
+ <% if (rules && rules.business_rules && rules.business_rules.length > 0) { %>
281
+ <section class="mb-8">
282
+ <h2 class="text-xl font-semibold mb-3">Business Rules</h2>
283
+ <div class="space-y-3">
284
+ <% for (var br of rules.business_rules) { %>
285
+ <div class="border rounded p-4">
286
+ <div class="font-medium"><%= br.name %></div>
287
+ <p class="text-sm text-gray-600 mt-1"><%= br.definition %></p>
288
+ <% if (br.enforcement && br.enforcement.length > 0) { %>
289
+ <div class="text-xs text-gray-500 mt-1">Enforcement: <%= br.enforcement.join(', ') %></div>
290
+ <% } %>
291
+ <% if (br.avoid && br.avoid.length > 0) { %>
292
+ <div class="text-xs text-red-500 mt-1">Avoid: <%= br.avoid.join(', ') %></div>
293
+ <% } %>
294
+ </div>
295
+ <% } %>
296
+ </div>
297
+ </section>
298
+ <% } %>
299
+
300
+ <% if (rules && rules.guardrail_filters && rules.guardrail_filters.length > 0) { %>
301
+ <section class="mb-8">
302
+ <h2 class="text-xl font-semibold mb-3">Guardrail Filters</h2>
303
+ <div class="space-y-3">
304
+ <% for (var gf of rules.guardrail_filters) { %>
305
+ <div class="border rounded p-4">
306
+ <div class="font-medium"><%= gf.name %></div>
307
+ <pre class="bg-gray-100 rounded p-2 text-sm mt-1"><code><%= gf.filter %></code></pre>
308
+ <p class="text-sm text-gray-600 mt-1"><%= gf.reason %></p>
309
+ </div>
310
+ <% } %>
311
+ </div>
312
+ </section>
313
+ <% } %>
314
+
315
+ <% if (rules && rules.hierarchies && rules.hierarchies.length > 0) { %>
316
+ <section class="mb-8">
317
+ <h2 class="text-xl font-semibold mb-3">Hierarchies</h2>
318
+ <div class="space-y-3">
319
+ <% for (var h of rules.hierarchies) { %>
320
+ <div class="border rounded p-4">
321
+ <div class="font-medium"><%= h.name %></div>
322
+ <div class="text-sm text-gray-600 mt-1">Dataset: <%= h.dataset %></div>
323
+ <div class="text-sm text-gray-600">Levels: <%= h.levels.join(' &rarr; ') %></div>
324
+ </div>
325
+ <% } %>
326
+ </div>
327
+ </section>
246
328
  <% } %>
247
- <% if (owner.team) { %>
248
- <div class="bg-white rounded-lg shadow p-4">
249
- <div class="text-sm text-gray-500">Team</div>
250
- <div><%= owner.team %></div>
329
+
330
+ <% if (!rules || ((!rules.golden_queries || rules.golden_queries.length === 0) && (!rules.business_rules || rules.business_rules.length === 0) && (!rules.guardrail_filters || rules.guardrail_filters.length === 0) && (!rules.hierarchies || rules.hierarchies.length === 0))) { %>
331
+ <p class="text-gray-500">No rules or queries defined for this model.</p>
332
+ <% } %>
333
+ </main>
334
+ ${FOOTER}
335
+ </body>
336
+ </html>`;
337
+ var glossaryTemplate = `${HEAD}
338
+ <body class="bg-white text-gray-900 min-h-screen">
339
+ ${NAV}
340
+ <main class="max-w-5xl mx-auto p-6">
341
+ <h1 class="text-3xl font-bold mb-6">Glossary</h1>
342
+
343
+ <% var termIds = Object.keys(terms).sort(); %>
344
+ <% if (termIds.length === 0) { %>
345
+ <p class="text-gray-500">No terms defined.</p>
346
+ <% } else { %>
347
+ <div class="space-y-4">
348
+ <% for (var tid of termIds) { %>
349
+ <% var term = terms[tid]; %>
350
+ <div class="border rounded-lg p-4" id="term-<%= tid %>">
351
+ <h2 class="text-lg font-semibold"><%= tid %></h2>
352
+ <p class="text-gray-700 mt-1"><%= term.definition %></p>
353
+ <% if (term.synonyms && term.synonyms.length > 0) { %>
354
+ <div class="text-sm text-gray-500 mt-1">Synonyms: <%= term.synonyms.join(', ') %></div>
355
+ <% } %>
356
+ <% if (term.maps_to && term.maps_to.length > 0) { %>
357
+ <div class="text-sm text-gray-500 mt-1">Maps to: <%= term.maps_to.join(', ') %></div>
358
+ <% } %>
359
+ <% if (term.owner) { %>
360
+ <div class="text-sm text-gray-500 mt-1">Owner: <a href="<%= basePath %>/owners/<%= term.owner %>.html" class="text-blue-600 underline"><%= term.owner %></a></div>
361
+ <% } %>
362
+ </div>
363
+ <% } %>
364
+ </div>
365
+ <% } %>
366
+ </main>
367
+ ${FOOTER}
368
+ </body>
369
+ </html>`;
370
+ var ownerTemplate = `${HEAD}
371
+ <body class="bg-white text-gray-900 min-h-screen">
372
+ ${NAV}
373
+ ${TIER_BADGE}
374
+ <main class="max-w-5xl mx-auto p-6">
375
+ <h1 class="text-3xl font-bold mb-2"><%= owner.display_name %></h1>
376
+ <div class="text-sm text-gray-500 mb-4">
377
+ <% if (owner.email) { %><span>Email: <%= owner.email %></span><% } %>
378
+ <% if (owner.team) { %><span class="ml-4">Team: <%= owner.team %></span><% } %>
251
379
  </div>
380
+ <% if (owner.description) { %>
381
+ <p class="text-gray-600 mb-4"><%= owner.description %></p>
252
382
  <% } %>
253
- </div>
254
-
255
- <% if (ownedNodes.length > 0) { %>
256
- <h2 class="text-xl font-semibold mb-3">Owned Nodes</h2>
257
- <ul class="space-y-1">
258
- <% ownedNodes.forEach(function(node) { %>
259
- <li>
260
- <span class="inline-block bg-gray-100 text-xs px-1.5 py-0.5 rounded mr-1"><%= node.kind %></span>
261
- <a href="<%= node.href %>" class="text-blue-600 hover:underline"><%= node.id %></a>
262
- </li>
263
- <% }); %>
264
- </ul>
265
- <% } %>`;
266
- var glossaryTemplate = `<nav class="text-sm text-gray-500 mb-4">
267
- <a href="<%= basePath %>/" class="hover:text-blue-600">Home</a> &rsaquo; Glossary
268
- </nav>
269
-
270
- <h1 class="text-3xl font-bold mb-6">Glossary</h1>
271
-
272
- <% if (terms.length === 0) { %>
273
- <p class="text-gray-500">No terms defined.</p>
274
- <% } else { %>
275
- <div class="overflow-x-auto">
276
- <table class="min-w-full bg-white rounded-lg shadow text-sm">
277
- <thead>
278
- <tr class="bg-gray-50 text-left">
279
- <th class="px-4 py-2">Term</th>
280
- <th class="px-4 py-2">Definition</th>
281
- <th class="px-4 py-2">Synonyms</th>
282
- <th class="px-4 py-2">Maps To</th>
283
- </tr>
284
- </thead>
285
- <tbody>
286
- <% terms.forEach(function(term) { %>
287
- <tr class="border-t">
288
- <td class="px-4 py-2 font-medium"><%= term.id %></td>
289
- <td class="px-4 py-2"><%= term.definition %></td>
290
- <td class="px-4 py-2"><%= (term.synonyms || []).join(', ') %></td>
291
- <td class="px-4 py-2">
292
- <% (term.mapsTo || []).forEach(function(target) { %>
293
- <a href="<%= basePath %>/concepts/<%= target %>.html" class="text-blue-600 hover:underline"><%= target %></a><%= ' ' %>
294
- <% }); %>
295
- </td>
296
- </tr>
297
- <% }); %>
298
- </tbody>
299
- </table>
300
- </div>
301
- <% } %>`;
302
- var searchTemplate = `<nav class="text-sm text-gray-500 mb-4">
303
- <a href="<%= basePath %>/" class="hover:text-blue-600">Home</a> &rsaquo; Search
304
- </nav>
305
-
306
- <h1 class="text-3xl font-bold mb-6">Search</h1>
307
-
308
- <input
309
- id="search-input"
310
- type="text"
311
- placeholder="Search concepts, products, policies, terms..."
312
- class="w-full border border-gray-300 rounded-lg px-4 py-2 mb-6 focus:outline-none focus:ring-2 focus:ring-blue-500"
313
- >
314
-
315
- <div id="search-results" class="space-y-3"></div>
316
-
317
- <script>window.__CONTEXTKIT_BASE_PATH__ = '<%= basePath %>';</script>
318
- <script src="<%= basePath %>/search.js"></script>`;
319
383
 
320
- // src/search/build-index.ts
321
- var _minisearch = require('minisearch'); var _minisearch2 = _interopRequireDefault(_minisearch);
322
- function buildSearchIndex(manifest) {
323
- const miniSearch = new (0, _minisearch2.default)({
324
- fields: ["id", "text", "tags"],
325
- storeFields: ["id", "kind", "text"],
326
- searchOptions: {
327
- boost: { id: 2 },
328
- fuzzy: 0.2,
329
- prefix: true
384
+ <% if (governedModels.length > 0) { %>
385
+ <section>
386
+ <h2 class="text-xl font-semibold mb-3">Governed Models</h2>
387
+ <div class="space-y-2">
388
+ <% for (var gm of governedModels) { %>
389
+ <div class="flex items-center gap-3">
390
+ <a href="<%= basePath %>/models/<%= gm.name %>.html" class="text-blue-600 hover:underline"><%= gm.name %></a>
391
+ <% if (gm.tier) { %><%- tierBadge(gm.tier) %><% } %>
392
+ </div>
393
+ <% } %>
394
+ </div>
395
+ </section>
396
+ <% } else { %>
397
+ <p class="text-gray-500">No models governed by this owner.</p>
398
+ <% } %>
399
+ </main>
400
+ ${FOOTER}
401
+ </body>
402
+ </html>`;
403
+ var searchTemplate = `${HEAD}
404
+ <body class="bg-white text-gray-900 min-h-screen">
405
+ ${NAV}
406
+ <main class="max-w-5xl mx-auto p-6">
407
+ <h1 class="text-3xl font-bold mb-6">Search</h1>
408
+
409
+ <input type="text" id="search-input"
410
+ placeholder="Search models, datasets, terms..."
411
+ class="w-full border rounded-lg px-4 py-2 mb-4 focus:outline-none focus:ring-2 focus:ring-blue-500" />
412
+
413
+ <div id="search-results" class="space-y-2"></div>
414
+ </main>
415
+ ${FOOTER}
416
+
417
+ <script src="https://cdn.jsdelivr.net/npm/minisearch@7.1.0/dist/umd/index.min.js"></script>
418
+ <script>
419
+ (function() {
420
+ var indexData = <%- searchIndexJson %>;
421
+ var miniSearch = MiniSearch.loadJSON(JSON.stringify(indexData.index), indexData.options);
422
+
423
+ var input = document.getElementById('search-input');
424
+ var resultsContainer = document.getElementById('search-results');
425
+ var docs = indexData.documents;
426
+
427
+ function clearResults() {
428
+ while (resultsContainer.firstChild) {
429
+ resultsContainer.removeChild(resultsContainer.firstChild);
330
430
  }
331
- });
332
- const documents = [];
333
- for (const concept of manifest.concepts) {
334
- documents.push({
335
- id: concept.id,
336
- kind: "concept",
337
- text: concept.definition,
338
- tags: (_nullishCoalesce(concept.tags, () => ( []))).join(" ")
339
- });
340
431
  }
341
- for (const product of manifest.products) {
342
- documents.push({
343
- id: product.id,
344
- kind: "product",
345
- text: product.description,
346
- tags: (_nullishCoalesce(product.tags, () => ( []))).join(" ")
347
- });
432
+
433
+ function createResultElement(doc) {
434
+ var wrapper = document.createElement('div');
435
+ wrapper.className = 'border rounded p-3';
436
+
437
+ var link = document.createElement('a');
438
+ link.href = doc.url;
439
+ link.className = 'text-blue-600 font-medium hover:underline';
440
+ link.textContent = doc.title;
441
+ wrapper.appendChild(link);
442
+
443
+ var badge = document.createElement('span');
444
+ badge.className = 'ml-2 text-xs text-gray-400 uppercase';
445
+ badge.textContent = doc.type;
446
+ wrapper.appendChild(badge);
447
+
448
+ if (doc.description) {
449
+ var desc = document.createElement('p');
450
+ desc.className = 'text-sm text-gray-600 mt-1';
451
+ desc.textContent = doc.description;
452
+ wrapper.appendChild(desc);
453
+ }
454
+
455
+ return wrapper;
348
456
  }
349
- for (const policy of manifest.policies) {
350
- documents.push({
351
- id: policy.id,
352
- kind: "policy",
353
- text: policy.description,
354
- tags: (_nullishCoalesce(policy.tags, () => ( []))).join(" ")
457
+
458
+ input.addEventListener('input', function() {
459
+ var query = input.value.trim();
460
+ clearResults();
461
+ if (!query) return;
462
+ var hits = miniSearch.search(query, { prefix: true, fuzzy: 0.2 });
463
+ if (hits.length === 0) {
464
+ var noResults = document.createElement('p');
465
+ noResults.className = 'text-gray-500';
466
+ noResults.textContent = 'No results found.';
467
+ resultsContainer.appendChild(noResults);
468
+ return;
469
+ }
470
+ hits.slice(0, 20).forEach(function(hit) {
471
+ var doc = docs[hit.id];
472
+ if (doc) {
473
+ resultsContainer.appendChild(createResultElement(doc));
474
+ }
475
+ });
476
+ });
477
+ })();
478
+ </script>
479
+ </body>
480
+ </html>`;
481
+
482
+ // src/search/build-index.ts
483
+ var _minisearch = require('minisearch'); var _minisearch2 = _interopRequireDefault(_minisearch);
484
+ var MINISEARCH_OPTIONS = {
485
+ fields: ["title", "description", "type"],
486
+ storeFields: ["title", "description", "type", "url"],
487
+ idField: "id"
488
+ };
489
+ function buildSearchIndex(manifest, basePath) {
490
+ const docs = [];
491
+ let idCounter = 0;
492
+ for (const [name, model] of Object.entries(manifest.models)) {
493
+ docs.push({
494
+ id: String(idCounter++),
495
+ type: "model",
496
+ title: name,
497
+ description: _nullishCoalesce(model.description, () => ( "")),
498
+ url: `${basePath}/models/${name}.html`
355
499
  });
500
+ if (model.datasets) {
501
+ for (const ds of model.datasets) {
502
+ docs.push({
503
+ id: String(idCounter++),
504
+ type: "dataset",
505
+ title: `${name} / ${ds.name}`,
506
+ description: _nullishCoalesce(ds.description, () => ( "")),
507
+ url: `${basePath}/models/${name}/schema.html`
508
+ });
509
+ }
510
+ }
356
511
  }
357
- for (const entity of manifest.entities) {
358
- documents.push({
359
- id: entity.id,
360
- kind: "entity",
361
- text: _nullishCoalesce(entity.definition, () => ( "")),
362
- tags: (_nullishCoalesce(entity.tags, () => ( []))).join(" ")
512
+ for (const [termId, term] of Object.entries(manifest.terms)) {
513
+ docs.push({
514
+ id: String(idCounter++),
515
+ type: "term",
516
+ title: termId,
517
+ description: term.definition,
518
+ url: `${basePath}/glossary.html#term-${termId}`
363
519
  });
364
520
  }
365
- for (const term of manifest.terms) {
366
- documents.push({
367
- id: term.id,
368
- kind: "term",
369
- text: term.definition,
370
- tags: (_nullishCoalesce(term.tags, () => ( []))).join(" ")
521
+ for (const [oid, owner] of Object.entries(manifest.owners)) {
522
+ docs.push({
523
+ id: String(idCounter++),
524
+ type: "owner",
525
+ title: owner.display_name,
526
+ description: _nullishCoalesce(owner.description, () => ( "")),
527
+ url: `${basePath}/owners/${oid}.html`
371
528
  });
372
529
  }
373
- miniSearch.addAll(documents);
374
- return JSON.stringify(miniSearch);
530
+ const miniSearch = new (0, _minisearch2.default)(MINISEARCH_OPTIONS);
531
+ miniSearch.addAll(docs);
532
+ const documentsMap = {};
533
+ for (const doc of docs) {
534
+ documentsMap[doc.id] = doc;
535
+ }
536
+ return {
537
+ index: JSON.parse(JSON.stringify(miniSearch)),
538
+ options: MINISEARCH_OPTIONS,
539
+ documents: documentsMap
540
+ };
375
541
  }
376
542
 
377
543
  // src/generator.ts
378
- function renderPage(contentTemplate, data, pageTitle, manifest, basePath) {
379
- const content = _ejs2.default.render(contentTemplate, { ...data, basePath });
380
- return _ejs2.default.render(layoutTemplate, {
381
- content,
382
- pageTitle,
383
- project: manifest.project,
384
- build: manifest.build,
544
+ function generateSite(manifest, config) {
545
+ const files = /* @__PURE__ */ new Map();
546
+ const siteTitle = _nullishCoalesce(_optionalChain([config, 'optionalAccess', _ => _.title]), () => ( "ContextKit"));
547
+ const basePath = (_nullishCoalesce(_optionalChain([config, 'optionalAccess', _2 => _2.base_path]), () => ( ""))).replace(/\/+$/, "");
548
+ const commonData = {
549
+ siteTitle,
385
550
  basePath
386
- });
387
- }
388
- async function writeOutputFile(filePath, content) {
389
- await _promises.mkdir.call(void 0, _path.dirname.call(void 0, filePath), { recursive: true });
390
- await _promises.writeFile.call(void 0, filePath, content, "utf-8");
391
- }
392
- function resolveAssetPath(filename) {
393
- const currentDir = _path.dirname.call(void 0, _url.fileURLToPath.call(void 0, import.meta.url));
394
- return _path.join.call(void 0, currentDir, "assets", filename);
395
- }
396
- async function generateSite(options) {
397
- const { manifest, outputDir, title, basePath = "" } = options;
398
- const projectData = {
399
- ...manifest.project,
400
- displayName: _nullishCoalesce(title, () => ( manifest.project.displayName))
401
551
  };
402
- const manifestWithTitle = { ...manifest, project: projectData };
403
- await _promises.mkdir.call(void 0, _path.join.call(void 0, outputDir, "concepts"), { recursive: true });
404
- await _promises.mkdir.call(void 0, _path.join.call(void 0, outputDir, "products"), { recursive: true });
405
- await _promises.mkdir.call(void 0, _path.join.call(void 0, outputDir, "policies"), { recursive: true });
406
- await _promises.mkdir.call(void 0, _path.join.call(void 0, outputDir, "owners"), { recursive: true });
407
- const indexHtml = renderPage(
408
- indexTemplate,
409
- {
410
- project: manifestWithTitle.project,
411
- concepts: manifest.concepts,
412
- products: manifest.products,
413
- policies: manifest.policies,
414
- entities: manifest.entities,
415
- terms: manifest.terms,
552
+ files.set(
553
+ "index.html",
554
+ _ejs2.default.render(indexTemplate, {
555
+ ...commonData,
556
+ pageTitle: "Home",
557
+ models: manifest.models,
558
+ governance: manifest.governance,
559
+ tiers: manifest.tiers,
416
560
  owners: manifest.owners
417
- },
418
- "Home",
419
- manifestWithTitle,
420
- basePath
561
+ })
421
562
  );
422
- await writeOutputFile(_path.join.call(void 0, outputDir, "index.html"), indexHtml);
423
- for (const concept of manifest.concepts) {
424
- const html = renderPage(
425
- conceptTemplate,
426
- { concept },
427
- concept.id,
428
- manifestWithTitle,
429
- basePath
563
+ for (const [name, model] of Object.entries(manifest.models)) {
564
+ const gov = _nullishCoalesce(manifest.governance[name], () => ( null));
565
+ const tier = _nullishCoalesce(manifest.tiers[name], () => ( null));
566
+ const rules = _nullishCoalesce(manifest.rules[name], () => ( null));
567
+ files.set(
568
+ `models/${name}.html`,
569
+ _ejs2.default.render(modelTemplate, {
570
+ ...commonData,
571
+ pageTitle: name,
572
+ model,
573
+ gov,
574
+ tier,
575
+ rules
576
+ })
430
577
  );
431
- await writeOutputFile(_path.join.call(void 0, outputDir, "concepts", `${concept.id}.html`), html);
432
- }
433
- for (const product of manifest.products) {
434
- const relatedConcepts = manifest.concepts.filter(
435
- (c) => c.productId === product.id
436
- );
437
- const html = renderPage(
438
- productTemplate,
439
- { product, relatedConcepts },
440
- product.id,
441
- manifestWithTitle,
442
- basePath
578
+ files.set(
579
+ `models/${name}/schema.html`,
580
+ _ejs2.default.render(schemaTemplate, {
581
+ ...commonData,
582
+ pageTitle: `${name} \u2014 Schema`,
583
+ model,
584
+ gov,
585
+ tier
586
+ })
443
587
  );
444
- await writeOutputFile(_path.join.call(void 0, outputDir, "products", `${product.id}.html`), html);
445
- }
446
- for (const policy of manifest.policies) {
447
- const html = renderPage(
448
- policyTemplate,
449
- { policy },
450
- policy.id,
451
- manifestWithTitle,
452
- basePath
588
+ files.set(
589
+ `models/${name}/rules.html`,
590
+ _ejs2.default.render(rulesTemplate, {
591
+ ...commonData,
592
+ pageTitle: `${name} \u2014 Rules`,
593
+ modelName: name,
594
+ rules
595
+ })
453
596
  );
454
- await writeOutputFile(_path.join.call(void 0, outputDir, "policies", `${policy.id}.html`), html);
455
597
  }
456
- for (const owner of manifest.owners) {
457
- const ownedNodes = [];
458
- for (const concept of manifest.concepts) {
459
- if (concept.owner === owner.id) {
460
- ownedNodes.push({
461
- id: concept.id,
462
- kind: "concept",
463
- href: `${basePath}/concepts/${concept.id}.html`
464
- });
465
- }
466
- }
467
- for (const product of manifest.products) {
468
- if (product.owner === owner.id) {
469
- ownedNodes.push({
470
- id: product.id,
471
- kind: "product",
472
- href: `${basePath}/products/${product.id}.html`
473
- });
474
- }
475
- }
476
- for (const policy of manifest.policies) {
477
- if (policy.owner === owner.id) {
478
- ownedNodes.push({
479
- id: policy.id,
480
- kind: "policy",
481
- href: `${basePath}/policies/${policy.id}.html`
482
- });
483
- }
484
- }
485
- for (const entity of manifest.entities) {
486
- if (entity.owner === owner.id) {
487
- ownedNodes.push({
488
- id: entity.id,
489
- kind: "entity",
490
- href: `${basePath}/`
491
- });
492
- }
493
- }
494
- for (const term of manifest.terms) {
495
- if (term.owner === owner.id) {
496
- ownedNodes.push({
497
- id: term.id,
498
- kind: "term",
499
- href: `${basePath}/glossary.html`
598
+ files.set(
599
+ "glossary.html",
600
+ _ejs2.default.render(glossaryTemplate, {
601
+ ...commonData,
602
+ pageTitle: "Glossary",
603
+ terms: manifest.terms
604
+ })
605
+ );
606
+ for (const [oid, owner] of Object.entries(manifest.owners)) {
607
+ const governedModels = [];
608
+ for (const [modelName, gov] of Object.entries(manifest.governance)) {
609
+ if (gov.owner === oid) {
610
+ const tierScore = manifest.tiers[modelName];
611
+ governedModels.push({
612
+ name: modelName,
613
+ tier: _nullishCoalesce(_optionalChain([tierScore, 'optionalAccess', _3 => _3.tier]), () => ( null))
500
614
  });
501
615
  }
502
616
  }
503
- const html = renderPage(
504
- ownerTemplate,
505
- { owner, ownedNodes },
506
- owner.displayName,
507
- manifestWithTitle,
508
- basePath
617
+ files.set(
618
+ `owners/${oid}.html`,
619
+ _ejs2.default.render(ownerTemplate, {
620
+ ...commonData,
621
+ pageTitle: owner.display_name,
622
+ owner,
623
+ governedModels
624
+ })
509
625
  );
510
- await writeOutputFile(_path.join.call(void 0, outputDir, "owners", `${owner.id}.html`), html);
511
626
  }
512
- const glossaryHtml = renderPage(
513
- glossaryTemplate,
514
- { terms: manifest.terms },
515
- "Glossary",
516
- manifestWithTitle,
517
- basePath
627
+ const searchIndex = buildSearchIndex(manifest, basePath);
628
+ files.set(
629
+ "search.html",
630
+ _ejs2.default.render(searchTemplate, {
631
+ ...commonData,
632
+ pageTitle: "Search",
633
+ searchIndexJson: JSON.stringify(searchIndex)
634
+ })
518
635
  );
519
- await writeOutputFile(_path.join.call(void 0, outputDir, "glossary.html"), glossaryHtml);
520
- const searchHtml = renderPage(
521
- searchTemplate,
522
- {},
523
- "Search",
524
- manifestWithTitle,
525
- basePath
526
- );
527
- await writeOutputFile(_path.join.call(void 0, outputDir, "search.html"), searchHtml);
528
- const searchIndexJson = buildSearchIndex(manifest);
529
- await writeOutputFile(_path.join.call(void 0, outputDir, "search-index.json"), searchIndexJson);
530
- let searchJs;
531
- try {
532
- searchJs = await _promises.readFile.call(void 0, resolveAssetPath("search.js"), "utf-8");
533
- } catch (e) {
534
- searchJs = "// Search functionality - load search-index.json\n";
535
- }
536
- await writeOutputFile(_path.join.call(void 0, outputDir, "search.js"), searchJs);
537
- let styleCss;
538
- try {
539
- styleCss = await _promises.readFile.call(void 0, resolveAssetPath("style.css"), "utf-8");
540
- } catch (e2) {
541
- styleCss = "/* ContextKit Site Styles */\n";
636
+ files.set("search-index.json", JSON.stringify(searchIndex, null, 2));
637
+ return files;
638
+ }
639
+ async function buildSite(manifest, config, outputDir) {
640
+ const siteConfig = config.site;
641
+ const files = generateSite(manifest, siteConfig);
642
+ for (const [filePath, content] of files) {
643
+ const fullPath = path.join(outputDir, filePath);
644
+ const dir = path.dirname(fullPath);
645
+ if (!fs.existsSync(dir)) {
646
+ fs.mkdirSync(dir, { recursive: true });
647
+ }
648
+ fs.writeFileSync(fullPath, content, "utf-8");
542
649
  }
543
- await writeOutputFile(_path.join.call(void 0, outputDir, "style.css"), styleCss);
544
650
  }
545
651
 
546
652
 
547
653
 
548
- exports.buildSearchIndex = buildSearchIndex; exports.generateSite = generateSite;
654
+
655
+
656
+
657
+
658
+
659
+
660
+
661
+
662
+ exports.buildSearchIndex = buildSearchIndex; exports.buildSite = buildSite; exports.generateSite = generateSite; exports.glossaryTemplate = glossaryTemplate; exports.indexTemplate = indexTemplate; exports.modelTemplate = modelTemplate; exports.ownerTemplate = ownerTemplate; exports.rulesTemplate = rulesTemplate; exports.schemaTemplate = schemaTemplate; exports.searchTemplate = searchTemplate;
549
663
  //# sourceMappingURL=index.cjs.map