@mdocui/core 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +299 -0
- package/dist/index.cjs +614 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +140 -0
- package/dist/index.d.ts +140 -0
- package/dist/index.js +580 -0
- package/dist/index.js.map +1 -0
- package/package.json +40 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
// src/tokenizer.ts
|
|
2
|
+
var TokenizerState = /* @__PURE__ */ ((TokenizerState2) => {
|
|
3
|
+
TokenizerState2["IN_PROSE"] = "IN_PROSE";
|
|
4
|
+
TokenizerState2["IN_TAG"] = "IN_TAG";
|
|
5
|
+
TokenizerState2["IN_STRING"] = "IN_STRING";
|
|
6
|
+
return TokenizerState2;
|
|
7
|
+
})(TokenizerState || {});
|
|
8
|
+
var TokenType = /* @__PURE__ */ ((TokenType2) => {
|
|
9
|
+
TokenType2["PROSE"] = "PROSE";
|
|
10
|
+
TokenType2["TAG_OPEN"] = "TAG_OPEN";
|
|
11
|
+
TokenType2["TAG_SELF_CLOSE"] = "TAG_SELF_CLOSE";
|
|
12
|
+
TokenType2["TAG_CLOSE"] = "TAG_CLOSE";
|
|
13
|
+
return TokenType2;
|
|
14
|
+
})(TokenType || {});
|
|
15
|
+
var Tokenizer = class {
|
|
16
|
+
state = "IN_PROSE" /* IN_PROSE */;
|
|
17
|
+
buffer = "";
|
|
18
|
+
proseBuffer = "";
|
|
19
|
+
stringChar = null;
|
|
20
|
+
escaped = false;
|
|
21
|
+
tokens = [];
|
|
22
|
+
getState() {
|
|
23
|
+
return this.state;
|
|
24
|
+
}
|
|
25
|
+
getBuffer() {
|
|
26
|
+
return this.buffer;
|
|
27
|
+
}
|
|
28
|
+
write(chunk) {
|
|
29
|
+
this.tokens = [];
|
|
30
|
+
for (let i = 0; i < chunk.length; i++) {
|
|
31
|
+
const char = chunk[i];
|
|
32
|
+
const next = chunk[i + 1];
|
|
33
|
+
switch (this.state) {
|
|
34
|
+
case "IN_PROSE" /* IN_PROSE */:
|
|
35
|
+
if (char === "{" && next === "%") {
|
|
36
|
+
this.flushProse();
|
|
37
|
+
this.buffer = "{%";
|
|
38
|
+
this.state = "IN_TAG" /* IN_TAG */;
|
|
39
|
+
i++;
|
|
40
|
+
} else {
|
|
41
|
+
this.proseBuffer += char;
|
|
42
|
+
}
|
|
43
|
+
break;
|
|
44
|
+
case "IN_TAG" /* IN_TAG */:
|
|
45
|
+
this.buffer += char;
|
|
46
|
+
if (char === '"' || char === "'") {
|
|
47
|
+
this.stringChar = char;
|
|
48
|
+
this.escaped = false;
|
|
49
|
+
this.state = "IN_STRING" /* IN_STRING */;
|
|
50
|
+
} else if (char === "%" && next === "}") {
|
|
51
|
+
this.buffer += "}";
|
|
52
|
+
i++;
|
|
53
|
+
this.emitTag();
|
|
54
|
+
this.state = "IN_PROSE" /* IN_PROSE */;
|
|
55
|
+
}
|
|
56
|
+
break;
|
|
57
|
+
case "IN_STRING" /* IN_STRING */:
|
|
58
|
+
this.buffer += char;
|
|
59
|
+
if (this.escaped) {
|
|
60
|
+
this.escaped = false;
|
|
61
|
+
} else if (char === "\\") {
|
|
62
|
+
this.escaped = true;
|
|
63
|
+
} else if (char === this.stringChar) {
|
|
64
|
+
this.stringChar = null;
|
|
65
|
+
this.state = "IN_TAG" /* IN_TAG */;
|
|
66
|
+
}
|
|
67
|
+
break;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (this.state === "IN_PROSE" /* IN_PROSE */) {
|
|
71
|
+
this.flushProse();
|
|
72
|
+
}
|
|
73
|
+
return this.tokens;
|
|
74
|
+
}
|
|
75
|
+
flush() {
|
|
76
|
+
this.tokens = [];
|
|
77
|
+
if (this.state === "IN_TAG" /* IN_TAG */ || this.state === "IN_STRING" /* IN_STRING */) {
|
|
78
|
+
this.proseBuffer += this.buffer;
|
|
79
|
+
this.buffer = "";
|
|
80
|
+
this.state = "IN_PROSE" /* IN_PROSE */;
|
|
81
|
+
}
|
|
82
|
+
this.flushProse();
|
|
83
|
+
return this.tokens;
|
|
84
|
+
}
|
|
85
|
+
reset() {
|
|
86
|
+
this.state = "IN_PROSE" /* IN_PROSE */;
|
|
87
|
+
this.buffer = "";
|
|
88
|
+
this.proseBuffer = "";
|
|
89
|
+
this.stringChar = null;
|
|
90
|
+
this.escaped = false;
|
|
91
|
+
this.tokens = [];
|
|
92
|
+
}
|
|
93
|
+
flushProse() {
|
|
94
|
+
if (this.proseBuffer.length > 0) {
|
|
95
|
+
this.tokens.push({ type: "PROSE" /* PROSE */, raw: this.proseBuffer });
|
|
96
|
+
this.proseBuffer = "";
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
emitTag() {
|
|
100
|
+
const raw = this.buffer;
|
|
101
|
+
this.buffer = "";
|
|
102
|
+
const inner = raw.slice(2, -2).trim();
|
|
103
|
+
if (inner.length === 0) return;
|
|
104
|
+
if (inner.startsWith("/")) {
|
|
105
|
+
this.tokens.push({ type: "TAG_CLOSE" /* TAG_CLOSE */, raw, name: inner.slice(1).trim() });
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const selfClosing = inner.endsWith("/");
|
|
109
|
+
const content = selfClosing ? inner.slice(0, -1).trim() : inner;
|
|
110
|
+
const spaceIdx = content.indexOf(" ");
|
|
111
|
+
this.tokens.push({
|
|
112
|
+
type: selfClosing ? "TAG_SELF_CLOSE" /* TAG_SELF_CLOSE */ : "TAG_OPEN" /* TAG_OPEN */,
|
|
113
|
+
raw,
|
|
114
|
+
name: spaceIdx === -1 ? content : content.slice(0, spaceIdx),
|
|
115
|
+
attrs: spaceIdx === -1 ? "" : content.slice(spaceIdx + 1).trim(),
|
|
116
|
+
selfClosing
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// src/attributes.ts
|
|
122
|
+
var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
|
|
123
|
+
function parseAttributes(input) {
|
|
124
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
125
|
+
let i = 0;
|
|
126
|
+
while (i < input.length) {
|
|
127
|
+
while (i < input.length && isWhitespace(input[i])) i++;
|
|
128
|
+
if (i >= input.length) break;
|
|
129
|
+
const keyStart = i;
|
|
130
|
+
while (i < input.length && input[i] !== "=" && !isWhitespace(input[i])) i++;
|
|
131
|
+
const key = input.slice(keyStart, i);
|
|
132
|
+
if (key.length === 0) break;
|
|
133
|
+
if (UNSAFE_KEYS.has(key)) {
|
|
134
|
+
while (i < input.length && isWhitespace(input[i])) i++;
|
|
135
|
+
if (i < input.length && input[i] === "=") {
|
|
136
|
+
i++;
|
|
137
|
+
i = skipValue(input, i);
|
|
138
|
+
}
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
while (i < input.length && isWhitespace(input[i])) i++;
|
|
142
|
+
if (i >= input.length || input[i] !== "=") {
|
|
143
|
+
result[key] = true;
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
i++;
|
|
147
|
+
while (i < input.length && isWhitespace(input[i])) i++;
|
|
148
|
+
if (i >= input.length) {
|
|
149
|
+
result[key] = true;
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
const char = input[i];
|
|
153
|
+
if (char === '"' || char === "'") {
|
|
154
|
+
const quote = char;
|
|
155
|
+
i++;
|
|
156
|
+
let value = "";
|
|
157
|
+
while (i < input.length && input[i] !== quote) {
|
|
158
|
+
if (input[i] === "\\" && i + 1 < input.length) {
|
|
159
|
+
value += input[i + 1];
|
|
160
|
+
i += 2;
|
|
161
|
+
} else {
|
|
162
|
+
value += input[i];
|
|
163
|
+
i++;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (i < input.length) i++;
|
|
167
|
+
result[key] = value;
|
|
168
|
+
} else if (char === "[") {
|
|
169
|
+
const start = i;
|
|
170
|
+
let depth = 1;
|
|
171
|
+
i++;
|
|
172
|
+
let inStr = false;
|
|
173
|
+
let strChar = "";
|
|
174
|
+
let escaped = false;
|
|
175
|
+
while (i < input.length && depth > 0) {
|
|
176
|
+
if (inStr) {
|
|
177
|
+
if (escaped) {
|
|
178
|
+
escaped = false;
|
|
179
|
+
} else if (input[i] === "\\") {
|
|
180
|
+
escaped = true;
|
|
181
|
+
} else if (input[i] === strChar) {
|
|
182
|
+
inStr = false;
|
|
183
|
+
}
|
|
184
|
+
} else {
|
|
185
|
+
if (input[i] === '"' || input[i] === "'") {
|
|
186
|
+
inStr = true;
|
|
187
|
+
strChar = input[i];
|
|
188
|
+
} else if (input[i] === "[") {
|
|
189
|
+
depth++;
|
|
190
|
+
} else if (input[i] === "]") {
|
|
191
|
+
depth--;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
i++;
|
|
195
|
+
}
|
|
196
|
+
const raw = input.slice(start, i);
|
|
197
|
+
try {
|
|
198
|
+
result[key] = JSON.parse(raw);
|
|
199
|
+
} catch {
|
|
200
|
+
result[key] = raw;
|
|
201
|
+
}
|
|
202
|
+
} else {
|
|
203
|
+
const valStart = i;
|
|
204
|
+
while (i < input.length && !isWhitespace(input[i])) i++;
|
|
205
|
+
const raw = input.slice(valStart, i);
|
|
206
|
+
result[key] = coerce(raw);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
function skipValue(input, start) {
|
|
212
|
+
let pos = start;
|
|
213
|
+
while (pos < input.length && isWhitespace(input[pos])) pos++;
|
|
214
|
+
if (pos >= input.length) return pos;
|
|
215
|
+
const ch = input[pos];
|
|
216
|
+
if (ch === '"' || ch === "'") {
|
|
217
|
+
pos++;
|
|
218
|
+
while (pos < input.length && input[pos] !== ch) {
|
|
219
|
+
if (input[pos] === "\\") pos++;
|
|
220
|
+
pos++;
|
|
221
|
+
}
|
|
222
|
+
if (pos < input.length) pos++;
|
|
223
|
+
} else if (ch === "[") {
|
|
224
|
+
let depth = 1;
|
|
225
|
+
pos++;
|
|
226
|
+
while (pos < input.length && depth > 0) {
|
|
227
|
+
if (input[pos] === "[") depth++;
|
|
228
|
+
else if (input[pos] === "]") depth--;
|
|
229
|
+
pos++;
|
|
230
|
+
}
|
|
231
|
+
} else {
|
|
232
|
+
while (pos < input.length && !isWhitespace(input[pos])) pos++;
|
|
233
|
+
}
|
|
234
|
+
return pos;
|
|
235
|
+
}
|
|
236
|
+
function isWhitespace(ch) {
|
|
237
|
+
return ch === " " || ch === " " || ch === "\n" || ch === "\r";
|
|
238
|
+
}
|
|
239
|
+
function coerce(raw) {
|
|
240
|
+
if (raw === "true") return true;
|
|
241
|
+
if (raw === "false") return false;
|
|
242
|
+
if (raw === "null") return null;
|
|
243
|
+
const num = Number(raw);
|
|
244
|
+
if (!Number.isNaN(num) && raw.length > 0) return num;
|
|
245
|
+
return raw;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
// src/parser.ts
|
|
249
|
+
var StreamingParser = class {
|
|
250
|
+
tokenizer = new Tokenizer();
|
|
251
|
+
completedNodes = [];
|
|
252
|
+
bodyStack = [];
|
|
253
|
+
errors = [];
|
|
254
|
+
options;
|
|
255
|
+
constructor(options) {
|
|
256
|
+
this.options = {
|
|
257
|
+
dropUnknown: options?.dropUnknown ?? true,
|
|
258
|
+
knownTags: options?.knownTags ?? /* @__PURE__ */ new Set()
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
write(chunk) {
|
|
262
|
+
const tokens = this.tokenizer.write(chunk);
|
|
263
|
+
const newNodes = [];
|
|
264
|
+
for (const token of tokens) {
|
|
265
|
+
newNodes.push(...this.processToken(token));
|
|
266
|
+
}
|
|
267
|
+
this.completedNodes.push(...newNodes);
|
|
268
|
+
return newNodes;
|
|
269
|
+
}
|
|
270
|
+
/** Flush remaining buffers. Open body tags are force-closed. */
|
|
271
|
+
flush() {
|
|
272
|
+
const remaining = this.tokenizer.flush();
|
|
273
|
+
const newNodes = [];
|
|
274
|
+
for (const token of remaining) {
|
|
275
|
+
newNodes.push(...this.processToken(token));
|
|
276
|
+
}
|
|
277
|
+
while (this.bodyStack.length > 0) {
|
|
278
|
+
const frame = this.popFrame();
|
|
279
|
+
this.errors.push({
|
|
280
|
+
code: "unclosed",
|
|
281
|
+
tagName: frame.name,
|
|
282
|
+
message: `Tag "{% ${frame.name} %}" was never closed`
|
|
283
|
+
});
|
|
284
|
+
const node = this.buildComponentNode(frame);
|
|
285
|
+
if (this.isInBody()) {
|
|
286
|
+
this.currentFrame().children.push(node);
|
|
287
|
+
} else {
|
|
288
|
+
newNodes.push(node);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
this.completedNodes.push(...newNodes);
|
|
292
|
+
return newNodes;
|
|
293
|
+
}
|
|
294
|
+
getNodes() {
|
|
295
|
+
return this.completedNodes;
|
|
296
|
+
}
|
|
297
|
+
getMeta() {
|
|
298
|
+
return {
|
|
299
|
+
errors: [...this.errors],
|
|
300
|
+
nodeCount: this.completedNodes.length,
|
|
301
|
+
isComplete: this.bodyStack.length === 0
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
reset() {
|
|
305
|
+
this.tokenizer.reset();
|
|
306
|
+
this.completedNodes = [];
|
|
307
|
+
this.bodyStack = [];
|
|
308
|
+
this.errors = [];
|
|
309
|
+
}
|
|
310
|
+
processToken(token) {
|
|
311
|
+
const nodes = [];
|
|
312
|
+
switch (token.type) {
|
|
313
|
+
case "PROSE" /* PROSE */:
|
|
314
|
+
this.handleProse(token.raw, nodes);
|
|
315
|
+
break;
|
|
316
|
+
case "TAG_SELF_CLOSE" /* TAG_SELF_CLOSE */:
|
|
317
|
+
this.handleSelfClose(token, nodes);
|
|
318
|
+
break;
|
|
319
|
+
case "TAG_OPEN" /* TAG_OPEN */:
|
|
320
|
+
this.handleOpen(token);
|
|
321
|
+
break;
|
|
322
|
+
case "TAG_CLOSE" /* TAG_CLOSE */:
|
|
323
|
+
this.handleClose(token, nodes);
|
|
324
|
+
break;
|
|
325
|
+
}
|
|
326
|
+
return nodes;
|
|
327
|
+
}
|
|
328
|
+
handleProse(content, out) {
|
|
329
|
+
if (content.length === 0) return;
|
|
330
|
+
const node = { type: "prose", content };
|
|
331
|
+
if (this.isInBody()) {
|
|
332
|
+
this.currentFrame().children.push(node);
|
|
333
|
+
} else {
|
|
334
|
+
out.push(node);
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
handleSelfClose(token, out) {
|
|
338
|
+
const name = token.name ?? "";
|
|
339
|
+
if (!this.isKnown(name)) {
|
|
340
|
+
this.errors.push({
|
|
341
|
+
code: "unknown_tag",
|
|
342
|
+
tagName: name,
|
|
343
|
+
message: `Unknown component: ${name}`,
|
|
344
|
+
raw: token.raw
|
|
345
|
+
});
|
|
346
|
+
if (!this.options.dropUnknown) {
|
|
347
|
+
this.handleProse(token.raw, out);
|
|
348
|
+
}
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
const props = parseAttributes(token.attrs ?? "");
|
|
352
|
+
const node = {
|
|
353
|
+
type: "component",
|
|
354
|
+
name,
|
|
355
|
+
props,
|
|
356
|
+
children: [],
|
|
357
|
+
selfClosing: true
|
|
358
|
+
};
|
|
359
|
+
if (this.isInBody()) {
|
|
360
|
+
this.currentFrame().children.push(node);
|
|
361
|
+
} else {
|
|
362
|
+
out.push(node);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
handleOpen(token) {
|
|
366
|
+
const name = token.name ?? "";
|
|
367
|
+
if (!this.isKnown(name)) {
|
|
368
|
+
this.errors.push({
|
|
369
|
+
code: "unknown_tag",
|
|
370
|
+
tagName: name,
|
|
371
|
+
message: `Unknown component: ${name}`,
|
|
372
|
+
raw: token.raw
|
|
373
|
+
});
|
|
374
|
+
return;
|
|
375
|
+
}
|
|
376
|
+
this.bodyStack.push({
|
|
377
|
+
name,
|
|
378
|
+
props: parseAttributes(token.attrs ?? ""),
|
|
379
|
+
children: []
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
handleClose(token, out) {
|
|
383
|
+
const name = token.name ?? "";
|
|
384
|
+
let frameIdx = -1;
|
|
385
|
+
for (let i = this.bodyStack.length - 1; i >= 0; i--) {
|
|
386
|
+
if (this.bodyStack[i].name === name) {
|
|
387
|
+
frameIdx = i;
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
if (frameIdx === -1) {
|
|
392
|
+
this.errors.push({
|
|
393
|
+
code: "malformed",
|
|
394
|
+
tagName: name,
|
|
395
|
+
message: `Closing tag "{% /${name} %}" has no matching opening tag`,
|
|
396
|
+
raw: token.raw
|
|
397
|
+
});
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
while (this.bodyStack.length > frameIdx + 1) {
|
|
401
|
+
const orphan = this.popFrame();
|
|
402
|
+
this.errors.push({
|
|
403
|
+
code: "unclosed",
|
|
404
|
+
tagName: orphan.name,
|
|
405
|
+
message: `Tag "{% ${orphan.name} %}" was force-closed by "{% /${name} %}"`
|
|
406
|
+
});
|
|
407
|
+
const orphanNode = this.buildComponentNode(orphan);
|
|
408
|
+
this.bodyStack[this.bodyStack.length - 1].children.push(orphanNode);
|
|
409
|
+
}
|
|
410
|
+
const frame = this.popFrame();
|
|
411
|
+
const node = this.buildComponentNode(frame);
|
|
412
|
+
if (this.isInBody()) {
|
|
413
|
+
this.currentFrame().children.push(node);
|
|
414
|
+
} else {
|
|
415
|
+
out.push(node);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
buildComponentNode(frame) {
|
|
419
|
+
return {
|
|
420
|
+
type: "component",
|
|
421
|
+
name: frame.name,
|
|
422
|
+
props: frame.props,
|
|
423
|
+
children: frame.children,
|
|
424
|
+
selfClosing: false
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
popFrame() {
|
|
428
|
+
return this.bodyStack.pop();
|
|
429
|
+
}
|
|
430
|
+
isInBody() {
|
|
431
|
+
return this.bodyStack.length > 0;
|
|
432
|
+
}
|
|
433
|
+
currentFrame() {
|
|
434
|
+
return this.bodyStack[this.bodyStack.length - 1];
|
|
435
|
+
}
|
|
436
|
+
isKnown(name) {
|
|
437
|
+
if (this.options.knownTags.size === 0) return true;
|
|
438
|
+
return this.options.knownTags.has(name);
|
|
439
|
+
}
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
// src/registry.ts
|
|
443
|
+
function defineComponent(definition) {
|
|
444
|
+
return definition;
|
|
445
|
+
}
|
|
446
|
+
var ComponentRegistry = class {
|
|
447
|
+
components = /* @__PURE__ */ new Map();
|
|
448
|
+
register(definition) {
|
|
449
|
+
this.components.set(definition.name, definition);
|
|
450
|
+
return this;
|
|
451
|
+
}
|
|
452
|
+
registerAll(definitions) {
|
|
453
|
+
for (const def of definitions) this.register(def);
|
|
454
|
+
return this;
|
|
455
|
+
}
|
|
456
|
+
get(name) {
|
|
457
|
+
return this.components.get(name);
|
|
458
|
+
}
|
|
459
|
+
has(name) {
|
|
460
|
+
return this.components.has(name);
|
|
461
|
+
}
|
|
462
|
+
names() {
|
|
463
|
+
return [...this.components.keys()];
|
|
464
|
+
}
|
|
465
|
+
all() {
|
|
466
|
+
return [...this.components.values()];
|
|
467
|
+
}
|
|
468
|
+
knownTags() {
|
|
469
|
+
return new Set(this.components.keys());
|
|
470
|
+
}
|
|
471
|
+
validate(tagName, props) {
|
|
472
|
+
const def = this.components.get(tagName);
|
|
473
|
+
if (!def) {
|
|
474
|
+
return { valid: false, errors: [`Unknown component: ${tagName}`] };
|
|
475
|
+
}
|
|
476
|
+
const result = def.props.safeParse(props);
|
|
477
|
+
if (result.success) {
|
|
478
|
+
return { valid: true, errors: [], props: result.data };
|
|
479
|
+
}
|
|
480
|
+
return {
|
|
481
|
+
valid: false,
|
|
482
|
+
errors: result.error.issues.map(
|
|
483
|
+
(issue) => `${issue.path.join(".")}: ${issue.message}`
|
|
484
|
+
)
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
// src/prompt.ts
|
|
490
|
+
function generatePrompt(registry, options) {
|
|
491
|
+
const sections = [];
|
|
492
|
+
if (options?.preamble) {
|
|
493
|
+
sections.push(options.preamble, "");
|
|
494
|
+
}
|
|
495
|
+
sections.push(
|
|
496
|
+
"You respond in mdocUI format.",
|
|
497
|
+
"",
|
|
498
|
+
"Write natural markdown prose. Embed UI components using Markdoc tag syntax.",
|
|
499
|
+
"",
|
|
500
|
+
"## TAG SYNTAX",
|
|
501
|
+
'Self-closing: {% tagname attr="value" attr2=123 /%}',
|
|
502
|
+
'With body: {% tagname attr="value" %}',
|
|
503
|
+
" content here",
|
|
504
|
+
" {% /tagname %}",
|
|
505
|
+
"",
|
|
506
|
+
"Never wrap tags in code fences.",
|
|
507
|
+
"Never invent component names not listed below.",
|
|
508
|
+
"Unknown tags will be silently dropped.",
|
|
509
|
+
""
|
|
510
|
+
);
|
|
511
|
+
const defs = registry.all();
|
|
512
|
+
if (defs.length > 0) {
|
|
513
|
+
sections.push("## COMPONENTS", "");
|
|
514
|
+
if (options?.groups && options.groups.length > 0) {
|
|
515
|
+
const grouped = /* @__PURE__ */ new Set();
|
|
516
|
+
for (const group of options.groups) {
|
|
517
|
+
sections.push(`### ${group.name}`);
|
|
518
|
+
if (group.notes) {
|
|
519
|
+
for (const note of group.notes) sections.push(`> ${note}`);
|
|
520
|
+
}
|
|
521
|
+
sections.push("");
|
|
522
|
+
for (const name of group.components) {
|
|
523
|
+
const def = registry.get(name);
|
|
524
|
+
if (def) {
|
|
525
|
+
sections.push(formatComponent(def), "");
|
|
526
|
+
grouped.add(name);
|
|
527
|
+
}
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
for (const def of defs) {
|
|
531
|
+
if (!grouped.has(def.name)) sections.push(formatComponent(def), "");
|
|
532
|
+
}
|
|
533
|
+
} else {
|
|
534
|
+
for (const def of defs) sections.push(formatComponent(def), "");
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
sections.push(
|
|
538
|
+
"## STREAMING GUIDELINE",
|
|
539
|
+
"Write prose content before components.",
|
|
540
|
+
"Users see text immediately while components load.",
|
|
541
|
+
""
|
|
542
|
+
);
|
|
543
|
+
if (options?.additionalRules && options.additionalRules.length > 0) {
|
|
544
|
+
sections.push("## RULES");
|
|
545
|
+
for (const rule of options.additionalRules) sections.push(`- ${rule}`);
|
|
546
|
+
sections.push("");
|
|
547
|
+
}
|
|
548
|
+
if (options?.examples && options.examples.length > 0) {
|
|
549
|
+
sections.push("## EXAMPLE", "");
|
|
550
|
+
for (const example of options.examples) sections.push(example, "");
|
|
551
|
+
}
|
|
552
|
+
return sections.join("\n").trim();
|
|
553
|
+
}
|
|
554
|
+
function formatComponent(def) {
|
|
555
|
+
const closing = def.children === "none" ? " /%}" : " %}";
|
|
556
|
+
const shape = def.props.shape;
|
|
557
|
+
const propNames = Object.keys(shape);
|
|
558
|
+
const sig = propNames.map((name) => shape[name].isOptional() ? `${name}?` : name).join(" ");
|
|
559
|
+
const lines = [`{% ${def.name} ${sig}${closing}`, ` ${def.description}`];
|
|
560
|
+
for (const [name, field] of Object.entries(shape)) {
|
|
561
|
+
const desc = field._def.description ?? "";
|
|
562
|
+
const opt = field.isOptional() ? " (optional)" : "";
|
|
563
|
+
lines.push(` ${name}: ${desc}${opt}`);
|
|
564
|
+
}
|
|
565
|
+
if (def.children && def.children !== "none") {
|
|
566
|
+
lines.push(" (accepts body content)");
|
|
567
|
+
}
|
|
568
|
+
return lines.join("\n");
|
|
569
|
+
}
|
|
570
|
+
export {
|
|
571
|
+
ComponentRegistry,
|
|
572
|
+
StreamingParser,
|
|
573
|
+
TokenType,
|
|
574
|
+
Tokenizer,
|
|
575
|
+
TokenizerState,
|
|
576
|
+
defineComponent,
|
|
577
|
+
generatePrompt,
|
|
578
|
+
parseAttributes
|
|
579
|
+
};
|
|
580
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/tokenizer.ts","../src/attributes.ts","../src/parser.ts","../src/registry.ts","../src/prompt.ts"],"sourcesContent":["export enum TokenizerState {\n\tIN_PROSE = 'IN_PROSE',\n\tIN_TAG = 'IN_TAG',\n\tIN_STRING = 'IN_STRING',\n}\n\nexport enum TokenType {\n\tPROSE = 'PROSE',\n\tTAG_OPEN = 'TAG_OPEN',\n\tTAG_SELF_CLOSE = 'TAG_SELF_CLOSE',\n\tTAG_CLOSE = 'TAG_CLOSE',\n}\n\nexport interface Token {\n\ttype: TokenType\n\traw: string\n\tname?: string\n\tattrs?: string\n\tselfClosing?: boolean\n}\n\nexport class Tokenizer {\n\tprivate state: TokenizerState = TokenizerState.IN_PROSE\n\tprivate buffer = ''\n\tprivate proseBuffer = ''\n\tprivate stringChar: string | null = null\n\tprivate escaped = false\n\tprivate tokens: Token[] = []\n\n\tgetState(): TokenizerState {\n\t\treturn this.state\n\t}\n\n\tgetBuffer(): string {\n\t\treturn this.buffer\n\t}\n\n\twrite(chunk: string): Token[] {\n\t\tthis.tokens = []\n\n\t\tfor (let i = 0; i < chunk.length; i++) {\n\t\t\tconst char = chunk[i]\n\t\t\tconst next = chunk[i + 1]\n\n\t\t\tswitch (this.state) {\n\t\t\t\tcase TokenizerState.IN_PROSE:\n\t\t\t\t\tif (char === '{' && next === '%') {\n\t\t\t\t\t\tthis.flushProse()\n\t\t\t\t\t\tthis.buffer = '{%'\n\t\t\t\t\t\tthis.state = TokenizerState.IN_TAG\n\t\t\t\t\t\ti++\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.proseBuffer += char\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\n\t\t\t\tcase TokenizerState.IN_TAG:\n\t\t\t\t\tthis.buffer += char\n\t\t\t\t\tif (char === '\"' || char === \"'\") {\n\t\t\t\t\t\tthis.stringChar = char\n\t\t\t\t\t\tthis.escaped = false\n\t\t\t\t\t\tthis.state = TokenizerState.IN_STRING\n\t\t\t\t\t} else if (char === '%' && next === '}') {\n\t\t\t\t\t\tthis.buffer += '}'\n\t\t\t\t\t\ti++\n\t\t\t\t\t\tthis.emitTag()\n\t\t\t\t\t\tthis.state = TokenizerState.IN_PROSE\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\n\t\t\t\tcase TokenizerState.IN_STRING:\n\t\t\t\t\tthis.buffer += char\n\t\t\t\t\tif (this.escaped) {\n\t\t\t\t\t\tthis.escaped = false\n\t\t\t\t\t} else if (char === '\\\\') {\n\t\t\t\t\t\tthis.escaped = true\n\t\t\t\t\t} else if (char === this.stringChar) {\n\t\t\t\t\t\tthis.stringChar = null\n\t\t\t\t\t\tthis.state = TokenizerState.IN_TAG\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif (this.state === TokenizerState.IN_PROSE) {\n\t\t\tthis.flushProse()\n\t\t}\n\n\t\treturn this.tokens\n\t}\n\n\tflush(): Token[] {\n\t\tthis.tokens = []\n\n\t\tif (this.state === TokenizerState.IN_TAG || this.state === TokenizerState.IN_STRING) {\n\t\t\tthis.proseBuffer += this.buffer\n\t\t\tthis.buffer = ''\n\t\t\tthis.state = TokenizerState.IN_PROSE\n\t\t}\n\n\t\tthis.flushProse()\n\t\treturn this.tokens\n\t}\n\n\treset(): void {\n\t\tthis.state = TokenizerState.IN_PROSE\n\t\tthis.buffer = ''\n\t\tthis.proseBuffer = ''\n\t\tthis.stringChar = null\n\t\tthis.escaped = false\n\t\tthis.tokens = []\n\t}\n\n\tprivate flushProse(): void {\n\t\tif (this.proseBuffer.length > 0) {\n\t\t\tthis.tokens.push({ type: TokenType.PROSE, raw: this.proseBuffer })\n\t\t\tthis.proseBuffer = ''\n\t\t}\n\t}\n\n\tprivate emitTag(): void {\n\t\tconst raw = this.buffer\n\t\tthis.buffer = ''\n\n\t\tconst inner = raw.slice(2, -2).trim()\n\t\tif (inner.length === 0) return\n\n\t\tif (inner.startsWith('/')) {\n\t\t\tthis.tokens.push({ type: TokenType.TAG_CLOSE, raw, name: inner.slice(1).trim() })\n\t\t\treturn\n\t\t}\n\n\t\tconst selfClosing = inner.endsWith('/')\n\t\tconst content = selfClosing ? inner.slice(0, -1).trim() : inner\n\t\tconst spaceIdx = content.indexOf(' ')\n\n\t\tthis.tokens.push({\n\t\t\ttype: selfClosing ? TokenType.TAG_SELF_CLOSE : TokenType.TAG_OPEN,\n\t\t\traw,\n\t\t\tname: spaceIdx === -1 ? content : content.slice(0, spaceIdx),\n\t\t\tattrs: spaceIdx === -1 ? '' : content.slice(spaceIdx + 1).trim(),\n\t\t\tselfClosing,\n\t\t})\n\t}\n}\n","const UNSAFE_KEYS = new Set(['__proto__', 'constructor', 'prototype'])\n\nexport function parseAttributes(input: string): Record<string, unknown> {\n\tconst result = Object.create(null) as Record<string, unknown>\n\tlet i = 0\n\n\twhile (i < input.length) {\n\t\twhile (i < input.length && isWhitespace(input[i])) i++\n\t\tif (i >= input.length) break\n\n\t\tconst keyStart = i\n\t\twhile (i < input.length && input[i] !== '=' && !isWhitespace(input[i])) i++\n\t\tconst key = input.slice(keyStart, i)\n\t\tif (key.length === 0) break\n\n\t\tif (UNSAFE_KEYS.has(key)) {\n\t\t\t// skip past the value if there is one\n\t\t\twhile (i < input.length && isWhitespace(input[i])) i++\n\t\t\tif (i < input.length && input[i] === '=') {\n\t\t\t\ti++\n\t\t\t\ti = skipValue(input, i)\n\t\t\t}\n\t\t\tcontinue\n\t\t}\n\n\t\twhile (i < input.length && isWhitespace(input[i])) i++\n\n\t\tif (i >= input.length || input[i] !== '=') {\n\t\t\tresult[key] = true\n\t\t\tcontinue\n\t\t}\n\t\ti++ // skip =\n\t\twhile (i < input.length && isWhitespace(input[i])) i++\n\n\t\tif (i >= input.length) {\n\t\t\tresult[key] = true\n\t\t\tbreak\n\t\t}\n\n\t\tconst char = input[i]\n\n\t\tif (char === '\"' || char === \"'\") {\n\t\t\tconst quote = char\n\t\t\ti++\n\t\t\tlet value = ''\n\t\t\twhile (i < input.length && input[i] !== quote) {\n\t\t\t\tif (input[i] === '\\\\' && i + 1 < input.length) {\n\t\t\t\t\tvalue += input[i + 1]\n\t\t\t\t\ti += 2\n\t\t\t\t} else {\n\t\t\t\t\tvalue += input[i]\n\t\t\t\t\ti++\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (i < input.length) i++ // skip closing quote\n\t\t\tresult[key] = value\n\t\t} else if (char === '[') {\n\t\t\tconst start = i\n\t\t\tlet depth = 1\n\t\t\ti++\n\t\t\tlet inStr = false\n\t\t\tlet strChar = ''\n\t\t\tlet escaped = false\n\t\t\twhile (i < input.length && depth > 0) {\n\t\t\t\tif (inStr) {\n\t\t\t\t\tif (escaped) {\n\t\t\t\t\t\tescaped = false\n\t\t\t\t\t} else if (input[i] === '\\\\') {\n\t\t\t\t\t\tescaped = true\n\t\t\t\t\t} else if (input[i] === strChar) {\n\t\t\t\t\t\tinStr = false\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tif (input[i] === '\"' || input[i] === \"'\") {\n\t\t\t\t\t\tinStr = true\n\t\t\t\t\t\tstrChar = input[i]\n\t\t\t\t\t} else if (input[i] === '[') {\n\t\t\t\t\t\tdepth++\n\t\t\t\t\t} else if (input[i] === ']') {\n\t\t\t\t\t\tdepth--\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\ti++\n\t\t\t}\n\t\t\tconst raw = input.slice(start, i)\n\t\t\ttry {\n\t\t\t\tresult[key] = JSON.parse(raw)\n\t\t\t} catch {\n\t\t\t\tresult[key] = raw\n\t\t\t}\n\t\t} else {\n\t\t\tconst valStart = i\n\t\t\twhile (i < input.length && !isWhitespace(input[i])) i++\n\t\t\tconst raw = input.slice(valStart, i)\n\t\t\tresult[key] = coerce(raw)\n\t\t}\n\t}\n\n\treturn result\n}\n\nfunction skipValue(input: string, start: number): number {\n\tlet pos = start\n\twhile (pos < input.length && isWhitespace(input[pos])) pos++\n\tif (pos >= input.length) return pos\n\n\tconst ch = input[pos]\n\tif (ch === '\"' || ch === \"'\") {\n\t\tpos++\n\t\twhile (pos < input.length && input[pos] !== ch) {\n\t\t\tif (input[pos] === '\\\\') pos++\n\t\t\tpos++\n\t\t}\n\t\tif (pos < input.length) pos++\n\t} else if (ch === '[') {\n\t\tlet depth = 1\n\t\tpos++\n\t\twhile (pos < input.length && depth > 0) {\n\t\t\tif (input[pos] === '[') depth++\n\t\t\telse if (input[pos] === ']') depth--\n\t\t\tpos++\n\t\t}\n\t} else {\n\t\twhile (pos < input.length && !isWhitespace(input[pos])) pos++\n\t}\n\treturn pos\n}\n\nfunction isWhitespace(ch: string): boolean {\n\treturn ch === ' ' || ch === '\\t' || ch === '\\n' || ch === '\\r'\n}\n\nfunction coerce(raw: string): unknown {\n\tif (raw === 'true') return true\n\tif (raw === 'false') return false\n\tif (raw === 'null') return null\n\tconst num = Number(raw)\n\tif (!Number.isNaN(num) && raw.length > 0) return num\n\treturn raw\n}\n","import { parseAttributes } from './attributes'\nimport { TokenType, Tokenizer } from './tokenizer'\nimport type { Token } from './tokenizer'\nimport type { ASTNode, ComponentNode, ParseError, ParseMeta, ProseNode } from './types'\n\nexport interface ParserOptions {\n\tdropUnknown?: boolean\n\tknownTags?: Set<string>\n}\n\nexport class StreamingParser {\n\tprivate tokenizer = new Tokenizer()\n\tprivate completedNodes: ASTNode[] = []\n\tprivate bodyStack: BodyFrame[] = []\n\tprivate errors: ParseError[] = []\n\tprivate options: Required<ParserOptions>\n\n\tconstructor(options?: ParserOptions) {\n\t\tthis.options = {\n\t\t\tdropUnknown: options?.dropUnknown ?? true,\n\t\t\tknownTags: options?.knownTags ?? new Set(),\n\t\t}\n\t}\n\n\twrite(chunk: string): ASTNode[] {\n\t\tconst tokens = this.tokenizer.write(chunk)\n\t\tconst newNodes: ASTNode[] = []\n\n\t\tfor (const token of tokens) {\n\t\t\tnewNodes.push(...this.processToken(token))\n\t\t}\n\n\t\tthis.completedNodes.push(...newNodes)\n\t\treturn newNodes\n\t}\n\n\t/** Flush remaining buffers. Open body tags are force-closed. */\n\tflush(): ASTNode[] {\n\t\tconst remaining = this.tokenizer.flush()\n\t\tconst newNodes: ASTNode[] = []\n\n\t\tfor (const token of remaining) {\n\t\t\tnewNodes.push(...this.processToken(token))\n\t\t}\n\n\t\twhile (this.bodyStack.length > 0) {\n\t\t\tconst frame = this.popFrame()\n\t\t\tthis.errors.push({\n\t\t\t\tcode: 'unclosed',\n\t\t\t\ttagName: frame.name,\n\t\t\t\tmessage: `Tag \"{% ${frame.name} %}\" was never closed`,\n\t\t\t})\n\t\t\tconst node = this.buildComponentNode(frame)\n\t\t\tif (this.isInBody()) {\n\t\t\t\tthis.currentFrame().children.push(node)\n\t\t\t} else {\n\t\t\t\tnewNodes.push(node)\n\t\t\t}\n\t\t}\n\n\t\tthis.completedNodes.push(...newNodes)\n\t\treturn newNodes\n\t}\n\n\tgetNodes(): ASTNode[] {\n\t\treturn this.completedNodes\n\t}\n\n\tgetMeta(): ParseMeta {\n\t\treturn {\n\t\t\terrors: [...this.errors],\n\t\t\tnodeCount: this.completedNodes.length,\n\t\t\tisComplete: this.bodyStack.length === 0,\n\t\t}\n\t}\n\n\treset(): void {\n\t\tthis.tokenizer.reset()\n\t\tthis.completedNodes = []\n\t\tthis.bodyStack = []\n\t\tthis.errors = []\n\t}\n\n\tprivate processToken(token: Token): ASTNode[] {\n\t\tconst nodes: ASTNode[] = []\n\n\t\tswitch (token.type) {\n\t\t\tcase TokenType.PROSE:\n\t\t\t\tthis.handleProse(token.raw, nodes)\n\t\t\t\tbreak\n\t\t\tcase TokenType.TAG_SELF_CLOSE:\n\t\t\t\tthis.handleSelfClose(token, nodes)\n\t\t\t\tbreak\n\t\t\tcase TokenType.TAG_OPEN:\n\t\t\t\tthis.handleOpen(token)\n\t\t\t\tbreak\n\t\t\tcase TokenType.TAG_CLOSE:\n\t\t\t\tthis.handleClose(token, nodes)\n\t\t\t\tbreak\n\t\t}\n\n\t\treturn nodes\n\t}\n\n\tprivate handleProse(content: string, out: ASTNode[]): void {\n\t\tif (content.length === 0) return\n\n\t\tconst node: ProseNode = { type: 'prose', content }\n\t\tif (this.isInBody()) {\n\t\t\tthis.currentFrame().children.push(node)\n\t\t} else {\n\t\t\tout.push(node)\n\t\t}\n\t}\n\n\tprivate handleSelfClose(token: Token, out: ASTNode[]): void {\n\t\tconst name = token.name ?? ''\n\t\tif (!this.isKnown(name)) {\n\t\t\tthis.errors.push({\n\t\t\t\tcode: 'unknown_tag',\n\t\t\t\ttagName: name,\n\t\t\t\tmessage: `Unknown component: ${name}`,\n\t\t\t\traw: token.raw,\n\t\t\t})\n\t\t\tif (!this.options.dropUnknown) {\n\t\t\t\tthis.handleProse(token.raw, out)\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tconst props = parseAttributes(token.attrs ?? '')\n\t\tconst node: ComponentNode = {\n\t\t\ttype: 'component',\n\t\t\tname,\n\t\t\tprops,\n\t\t\tchildren: [],\n\t\t\tselfClosing: true,\n\t\t}\n\n\t\tif (this.isInBody()) {\n\t\t\tthis.currentFrame().children.push(node)\n\t\t} else {\n\t\t\tout.push(node)\n\t\t}\n\t}\n\n\tprivate handleOpen(token: Token): void {\n\t\tconst name = token.name ?? ''\n\t\tif (!this.isKnown(name)) {\n\t\t\tthis.errors.push({\n\t\t\t\tcode: 'unknown_tag',\n\t\t\t\ttagName: name,\n\t\t\t\tmessage: `Unknown component: ${name}`,\n\t\t\t\traw: token.raw,\n\t\t\t})\n\t\t\treturn\n\t\t}\n\n\t\tthis.bodyStack.push({\n\t\t\tname,\n\t\t\tprops: parseAttributes(token.attrs ?? ''),\n\t\t\tchildren: [],\n\t\t})\n\t}\n\n\tprivate handleClose(token: Token, out: ASTNode[]): void {\n\t\tconst name = token.name ?? ''\n\n\t\tlet frameIdx = -1\n\t\tfor (let i = this.bodyStack.length - 1; i >= 0; i--) {\n\t\t\tif (this.bodyStack[i].name === name) {\n\t\t\t\tframeIdx = i\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif (frameIdx === -1) {\n\t\t\tthis.errors.push({\n\t\t\t\tcode: 'malformed',\n\t\t\t\ttagName: name,\n\t\t\t\tmessage: `Closing tag \"{% /${name} %}\" has no matching opening tag`,\n\t\t\t\traw: token.raw,\n\t\t\t})\n\t\t\treturn\n\t\t}\n\n\t\t// force-close anything nested above the matching opener\n\t\twhile (this.bodyStack.length > frameIdx + 1) {\n\t\t\tconst orphan = this.popFrame()\n\t\t\tthis.errors.push({\n\t\t\t\tcode: 'unclosed',\n\t\t\t\ttagName: orphan.name,\n\t\t\t\tmessage: `Tag \"{% ${orphan.name} %}\" was force-closed by \"{% /${name} %}\"`,\n\t\t\t})\n\t\t\tconst orphanNode = this.buildComponentNode(orphan)\n\t\t\tthis.bodyStack[this.bodyStack.length - 1].children.push(orphanNode)\n\t\t}\n\n\t\tconst frame = this.popFrame()\n\t\tconst node = this.buildComponentNode(frame)\n\n\t\tif (this.isInBody()) {\n\t\t\tthis.currentFrame().children.push(node)\n\t\t} else {\n\t\t\tout.push(node)\n\t\t}\n\t}\n\n\tprivate buildComponentNode(frame: BodyFrame): ComponentNode {\n\t\treturn {\n\t\t\ttype: 'component',\n\t\t\tname: frame.name,\n\t\t\tprops: frame.props,\n\t\t\tchildren: frame.children,\n\t\t\tselfClosing: false,\n\t\t}\n\t}\n\n\tprivate popFrame(): BodyFrame {\n\t\treturn this.bodyStack.pop() as BodyFrame\n\t}\n\n\tprivate isInBody(): boolean {\n\t\treturn this.bodyStack.length > 0\n\t}\n\n\tprivate currentFrame(): BodyFrame {\n\t\treturn this.bodyStack[this.bodyStack.length - 1]\n\t}\n\n\tprivate isKnown(name: string): boolean {\n\t\tif (this.options.knownTags.size === 0) return true\n\t\treturn this.options.knownTags.has(name)\n\t}\n}\n\ninterface BodyFrame {\n\tname: string\n\tprops: Record<string, unknown>\n\tchildren: ASTNode[]\n}\n","import type { z } from 'zod'\nimport type { ComponentDefinition, ValidationResult } from './types'\n\n/** Type helper — returns the definition unchanged. */\nexport function defineComponent(definition: ComponentDefinition): ComponentDefinition {\n\treturn definition\n}\n\nexport class ComponentRegistry {\n\tprivate components = new Map<string, ComponentDefinition>()\n\n\tregister(definition: ComponentDefinition): this {\n\t\tthis.components.set(definition.name, definition)\n\t\treturn this\n\t}\n\n\tregisterAll(definitions: ComponentDefinition[]): this {\n\t\tfor (const def of definitions) this.register(def)\n\t\treturn this\n\t}\n\n\tget(name: string): ComponentDefinition | undefined {\n\t\treturn this.components.get(name)\n\t}\n\n\thas(name: string): boolean {\n\t\treturn this.components.has(name)\n\t}\n\n\tnames(): string[] {\n\t\treturn [...this.components.keys()]\n\t}\n\n\tall(): ComponentDefinition[] {\n\t\treturn [...this.components.values()]\n\t}\n\n\tknownTags(): Set<string> {\n\t\treturn new Set(this.components.keys())\n\t}\n\n\tvalidate(tagName: string, props: Record<string, unknown>): ValidationResult {\n\t\tconst def = this.components.get(tagName)\n\t\tif (!def) {\n\t\t\treturn { valid: false, errors: [`Unknown component: ${tagName}`] }\n\t\t}\n\n\t\tconst result = def.props.safeParse(props)\n\t\tif (result.success) {\n\t\t\treturn { valid: true, errors: [], props: result.data as Record<string, unknown> }\n\t\t}\n\n\t\treturn {\n\t\t\tvalid: false,\n\t\t\terrors: result.error.issues.map(\n\t\t\t\t(issue: z.ZodIssue) => `${issue.path.join('.')}: ${issue.message}`,\n\t\t\t),\n\t\t}\n\t}\n}\n","import type { ComponentRegistry } from './registry'\nimport type { ComponentDefinition, PromptOptions } from './types'\n\nexport function generatePrompt(registry: ComponentRegistry, options?: PromptOptions): string {\n\tconst sections: string[] = []\n\n\tif (options?.preamble) {\n\t\tsections.push(options.preamble, '')\n\t}\n\n\tsections.push(\n\t\t'You respond in mdocUI format.',\n\t\t'',\n\t\t'Write natural markdown prose. Embed UI components using Markdoc tag syntax.',\n\t\t'',\n\t\t'## TAG SYNTAX',\n\t\t'Self-closing: {% tagname attr=\"value\" attr2=123 /%}',\n\t\t'With body: {% tagname attr=\"value\" %}',\n\t\t' content here',\n\t\t' {% /tagname %}',\n\t\t'',\n\t\t'Never wrap tags in code fences.',\n\t\t'Never invent component names not listed below.',\n\t\t'Unknown tags will be silently dropped.',\n\t\t'',\n\t)\n\n\tconst defs = registry.all()\n\tif (defs.length > 0) {\n\t\tsections.push('## COMPONENTS', '')\n\n\t\tif (options?.groups && options.groups.length > 0) {\n\t\t\tconst grouped = new Set<string>()\n\n\t\t\tfor (const group of options.groups) {\n\t\t\t\tsections.push(`### ${group.name}`)\n\t\t\t\tif (group.notes) {\n\t\t\t\t\tfor (const note of group.notes) sections.push(`> ${note}`)\n\t\t\t\t}\n\t\t\t\tsections.push('')\n\t\t\t\tfor (const name of group.components) {\n\t\t\t\t\tconst def = registry.get(name)\n\t\t\t\t\tif (def) {\n\t\t\t\t\t\tsections.push(formatComponent(def), '')\n\t\t\t\t\t\tgrouped.add(name)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor (const def of defs) {\n\t\t\t\tif (!grouped.has(def.name)) sections.push(formatComponent(def), '')\n\t\t\t}\n\t\t} else {\n\t\t\tfor (const def of defs) sections.push(formatComponent(def), '')\n\t\t}\n\t}\n\n\tsections.push(\n\t\t'## STREAMING GUIDELINE',\n\t\t'Write prose content before components.',\n\t\t'Users see text immediately while components load.',\n\t\t'',\n\t)\n\n\tif (options?.additionalRules && options.additionalRules.length > 0) {\n\t\tsections.push('## RULES')\n\t\tfor (const rule of options.additionalRules) sections.push(`- ${rule}`)\n\t\tsections.push('')\n\t}\n\n\tif (options?.examples && options.examples.length > 0) {\n\t\tsections.push('## EXAMPLE', '')\n\t\tfor (const example of options.examples) sections.push(example, '')\n\t}\n\n\treturn sections.join('\\n').trim()\n}\n\ninterface ZodField {\n\tisOptional: () => boolean\n\t_def: { description?: string }\n}\n\nfunction formatComponent(def: ComponentDefinition): string {\n\tconst closing = def.children === 'none' ? ' /%}' : ' %}'\n\tconst shape = def.props.shape as Record<string, ZodField>\n\tconst propNames = Object.keys(shape)\n\n\tconst sig = propNames.map((name) => (shape[name].isOptional() ? `${name}?` : name)).join(' ')\n\n\tconst lines = [`{% ${def.name} ${sig}${closing}`, ` ${def.description}`]\n\n\tfor (const [name, field] of Object.entries(shape)) {\n\t\tconst desc = field._def.description ?? ''\n\t\tconst opt = field.isOptional() ? ' (optional)' : ''\n\t\tlines.push(` ${name}: ${desc}${opt}`)\n\t}\n\n\tif (def.children && def.children !== 'none') {\n\t\tlines.push(' (accepts body content)')\n\t}\n\n\treturn lines.join('\\n')\n}\n"],"mappings":"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","names":["TokenizerState","TokenType"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mdocui/core",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Streaming Markdoc parser, component registry, and system prompt generator for LLM generative UI",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": ["dist"],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsup",
|
|
19
|
+
"test": "vitest run",
|
|
20
|
+
"test:watch": "vitest",
|
|
21
|
+
"clean": "rm -rf dist"
|
|
22
|
+
},
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"zod": "catalog:"
|
|
25
|
+
},
|
|
26
|
+
"devDependencies": {
|
|
27
|
+
"tsup": "^8.5.0",
|
|
28
|
+
"vitest": "^3.2.0"
|
|
29
|
+
},
|
|
30
|
+
"license": "MIT",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/mdocui/mdocui",
|
|
34
|
+
"directory": "packages/core"
|
|
35
|
+
},
|
|
36
|
+
"keywords": ["markdoc", "llm", "generative-ui", "streaming", "parser"],
|
|
37
|
+
"publishConfig": {
|
|
38
|
+
"access": "public"
|
|
39
|
+
}
|
|
40
|
+
}
|