@superbuilders/prompt 0.1.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 +12 -0
- package/README.md +28 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +87 -0
- package/dist/index.js.map +1 -0
- package/dist/jsx-dev-runtime.d.ts +3 -0
- package/dist/jsx-dev-runtime.d.ts.map +1 -0
- package/dist/jsx-dev-runtime.js +2 -0
- package/dist/jsx-dev-runtime.js.map +1 -0
- package/dist/jsx-runtime.d.ts +28 -0
- package/dist/jsx-runtime.d.ts.map +1 -0
- package/dist/jsx-runtime.js +71 -0
- package/dist/jsx-runtime.js.map +1 -0
- package/package.json +58 -0
- package/src/index.ts +109 -0
- package/src/jsx-dev-runtime.ts +2 -0
- package/src/jsx-runtime.ts +100 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
Copyright © 2025 Bjorn Pagen <11238136+bjornpagen@users.noreply.github.com>
|
|
2
|
+
|
|
3
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
4
|
+
purpose with or without fee is hereby granted.
|
|
5
|
+
|
|
6
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
|
|
7
|
+
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
|
8
|
+
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
|
|
9
|
+
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
|
10
|
+
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
|
|
11
|
+
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
|
12
|
+
PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# @superbuilders/prompt
|
|
2
|
+
|
|
3
|
+
JSX runtime for authoring structured LLM prompts as components. Declare a per-file pragma and write prompts as composable JSX:
|
|
4
|
+
|
|
5
|
+
```tsx
|
|
6
|
+
/** @jsxImportSource @superbuilders/prompt */
|
|
7
|
+
|
|
8
|
+
export function SystemPrompt(props: { role: string }) {
|
|
9
|
+
return (
|
|
10
|
+
<system>
|
|
11
|
+
You are {props.role}.
|
|
12
|
+
</system>
|
|
13
|
+
)
|
|
14
|
+
}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Built for bare-Node type stripping: internal imports are `#` subpath imports resolved through the package's conditional map (`types` → `src`, `default` → `dist`), emitted per-file by tsgo with declarations and source maps.
|
|
18
|
+
|
|
19
|
+
## Scripts
|
|
20
|
+
|
|
21
|
+
- `pnpm build` — `tsgo -p tsconfig.build.json` into `dist/`
|
|
22
|
+
- `pnpm typecheck` — `tsgo --noEmit`
|
|
23
|
+
- `pnpm lint` — `biome check .`
|
|
24
|
+
|
|
25
|
+
## Exports
|
|
26
|
+
|
|
27
|
+
- `@superbuilders/prompt` — the component/runtime API
|
|
28
|
+
- `@superbuilders/prompt/jsx-runtime`, `@superbuilders/prompt/jsx-dev-runtime` — automatic-runtime entry points consumed via the `@jsxImportSource` pragma
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
type PromptPrimitive = string | number | boolean;
|
|
2
|
+
type PromptAttrValue = PromptPrimitive | null | undefined | false;
|
|
3
|
+
type PromptNode = PromptElement | PromptPrimitive | null | undefined | false | readonly PromptNode[];
|
|
4
|
+
type PromptElement = {
|
|
5
|
+
tag: string;
|
|
6
|
+
attrs: Record<string, PromptAttrValue>;
|
|
7
|
+
children: readonly PromptNode[];
|
|
8
|
+
};
|
|
9
|
+
type PromptComponentProps = Record<string, unknown> & {
|
|
10
|
+
children?: PromptNode;
|
|
11
|
+
};
|
|
12
|
+
type PromptComponent = (props: PromptComponentProps) => PromptNode;
|
|
13
|
+
declare function render(node: PromptNode): string;
|
|
14
|
+
export type { PromptAttrValue, PromptComponent, PromptComponentProps, PromptElement, PromptNode };
|
|
15
|
+
export { render };
|
|
16
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,KAAK,eAAe,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAA;AAChD,KAAK,eAAe,GAAG,eAAe,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,CAAA;AACjE,KAAK,UAAU,GAAG,aAAa,GAAG,eAAe,GAAG,IAAI,GAAG,SAAS,GAAG,KAAK,GAAG,SAAS,UAAU,EAAE,CAAA;AAEpG,KAAK,aAAa,GAAG;IACpB,GAAG,EAAE,MAAM,CAAA;IACX,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,CAAA;IACtC,QAAQ,EAAE,SAAS,UAAU,EAAE,CAAA;CAC/B,CAAA;AAED,KAAK,oBAAoB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,QAAQ,CAAC,EAAE,UAAU,CAAA;CAAE,CAAA;AAC/E,KAAK,eAAe,GAAG,CAAC,KAAK,EAAE,oBAAoB,KAAK,UAAU,CAAA;AAsFlE,iBAAS,MAAM,CAAC,IAAI,EAAE,UAAU,GAAG,MAAM,CAQxC;AAED,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,oBAAoB,EAAE,aAAa,EAAE,UAAU,EAAE,CAAA;AACjG,OAAO,EAAE,MAAM,EAAE,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
function isPromptElement(value) {
|
|
2
|
+
return typeof value === "object" && value !== null && "tag" in value && "attrs" in value && "children" in value;
|
|
3
|
+
}
|
|
4
|
+
function escapeText(value) {
|
|
5
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
6
|
+
}
|
|
7
|
+
function escapeAttr(value) {
|
|
8
|
+
return escapeText(value).replace(/"/g, """).replace(/'/g, "'");
|
|
9
|
+
}
|
|
10
|
+
function renderAttrs(attrs) {
|
|
11
|
+
const parts = [];
|
|
12
|
+
for (const key in attrs) {
|
|
13
|
+
const value = attrs[key];
|
|
14
|
+
if (value === undefined || value === null || value === false) {
|
|
15
|
+
continue;
|
|
16
|
+
}
|
|
17
|
+
parts.push(` ${key}="${escapeAttr(String(value))}"`);
|
|
18
|
+
}
|
|
19
|
+
return parts.join("");
|
|
20
|
+
}
|
|
21
|
+
function childIsInline(node) {
|
|
22
|
+
if (node === undefined || node === null || node === false) {
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
if (Array.isArray(node)) {
|
|
26
|
+
return node.every(childIsInline);
|
|
27
|
+
}
|
|
28
|
+
return !isPromptElement(node);
|
|
29
|
+
}
|
|
30
|
+
function renderInline(node) {
|
|
31
|
+
if (node === undefined || node === null || node === false) {
|
|
32
|
+
return "";
|
|
33
|
+
}
|
|
34
|
+
if (Array.isArray(node)) {
|
|
35
|
+
return node.map(renderInline).join("");
|
|
36
|
+
}
|
|
37
|
+
if (isPromptElement(node)) {
|
|
38
|
+
return renderElement(node, 0);
|
|
39
|
+
}
|
|
40
|
+
return escapeText(String(node));
|
|
41
|
+
}
|
|
42
|
+
function renderChild(node, level) {
|
|
43
|
+
if (node === undefined || node === null || node === false) {
|
|
44
|
+
return "";
|
|
45
|
+
}
|
|
46
|
+
if (Array.isArray(node)) {
|
|
47
|
+
return node
|
|
48
|
+
.map(function renderArrayChild(child) {
|
|
49
|
+
return renderChild(child, level);
|
|
50
|
+
})
|
|
51
|
+
.join("");
|
|
52
|
+
}
|
|
53
|
+
if (isPromptElement(node)) {
|
|
54
|
+
return `${" ".repeat(level)}${renderElement(node, level)}\n`;
|
|
55
|
+
}
|
|
56
|
+
const text = escapeText(String(node));
|
|
57
|
+
if (text.includes("\n")) {
|
|
58
|
+
return `${text}\n`;
|
|
59
|
+
}
|
|
60
|
+
return `${" ".repeat(level)}${text}\n`;
|
|
61
|
+
}
|
|
62
|
+
function renderElement(element, level) {
|
|
63
|
+
const attrs = renderAttrs(element.attrs);
|
|
64
|
+
if (element.children.length === 0) {
|
|
65
|
+
return `<${element.tag}${attrs}></${element.tag}>`;
|
|
66
|
+
}
|
|
67
|
+
if (element.children.every(childIsInline)) {
|
|
68
|
+
return `<${element.tag}${attrs}>${element.children.map(renderInline).join("")}</${element.tag}>`;
|
|
69
|
+
}
|
|
70
|
+
const children = element.children
|
|
71
|
+
.map(function renderNestedChild(child) {
|
|
72
|
+
return renderChild(child, level + 1);
|
|
73
|
+
})
|
|
74
|
+
.join("");
|
|
75
|
+
return `<${element.tag}${attrs}>\n${children}${" ".repeat(level)}</${element.tag}>`;
|
|
76
|
+
}
|
|
77
|
+
function render(node) {
|
|
78
|
+
if (Array.isArray(node)) {
|
|
79
|
+
return node.map(render).join("\n\n");
|
|
80
|
+
}
|
|
81
|
+
if (isPromptElement(node)) {
|
|
82
|
+
return renderElement(node, 0);
|
|
83
|
+
}
|
|
84
|
+
return renderInline(node);
|
|
85
|
+
}
|
|
86
|
+
export { render };
|
|
87
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsx-dev-runtime.d.ts","sourceRoot":"","sources":["../src/jsx-dev-runtime.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAA;AAC1C,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI,MAAM,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsx-dev-runtime.js","sourceRoot":"","sources":["../src/jsx-dev-runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,GAAG,IAAI,MAAM,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { PromptComponentProps, PromptNode } from "#index.ts";
|
|
2
|
+
type JsxComponent<P extends PromptComponentProps = PromptComponentProps> = (props: P) => PromptNode;
|
|
3
|
+
declare function jsx<P extends PromptComponentProps>(tag: JsxComponent<P>, props: P): PromptNode;
|
|
4
|
+
declare function jsx(tag: string, props?: PromptComponentProps): PromptNode;
|
|
5
|
+
declare function jsxs<P extends PromptComponentProps>(tag: JsxComponent<P>, props: P): PromptNode;
|
|
6
|
+
declare function jsxs(tag: string, props?: PromptComponentProps): PromptNode;
|
|
7
|
+
declare function Fragment(props: {
|
|
8
|
+
children?: PromptNode;
|
|
9
|
+
}): PromptNode;
|
|
10
|
+
export declare namespace JSX {
|
|
11
|
+
type Element = PromptNode;
|
|
12
|
+
type ElementType = string | ((props: never) => PromptNode);
|
|
13
|
+
type ElementChildrenAttribute = {
|
|
14
|
+
children: unknown;
|
|
15
|
+
};
|
|
16
|
+
type IntrinsicAttributes = {
|
|
17
|
+
key?: string | number;
|
|
18
|
+
};
|
|
19
|
+
type IntrinsicElements = {
|
|
20
|
+
[tag: string]: {
|
|
21
|
+
children?: PromptNode;
|
|
22
|
+
key?: string | number;
|
|
23
|
+
[attr: string]: PromptNode | string | number | boolean | null | undefined;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export { Fragment, jsx, jsxs };
|
|
28
|
+
//# sourceMappingURL=jsx-runtime.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsx-runtime.d.ts","sourceRoot":"","sources":["../src/jsx-runtime.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAmB,oBAAoB,EAAiB,UAAU,EAAE,MAAM,WAAW,CAAA;AAEjG,KAAK,YAAY,CAAC,CAAC,SAAS,oBAAoB,GAAG,oBAAoB,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,UAAU,CAAA;AA0CnG,iBAAS,GAAG,CAAC,CAAC,SAAS,oBAAoB,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,UAAU,CAAA;AACxF,iBAAS,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,oBAAoB,GAAG,UAAU,CAAA;AAiBnE,iBAAS,IAAI,CAAC,CAAC,SAAS,oBAAoB,EAAE,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,UAAU,CAAA;AACzF,iBAAS,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,oBAAoB,GAAG,UAAU,CAAA;AAiBpE,iBAAS,QAAQ,CAAC,KAAK,EAAE;IAAE,QAAQ,CAAC,EAAE,UAAU,CAAA;CAAE,GAAG,UAAU,CAE9D;AAED,yBAAiB,GAAG,CAAC;IACpB,KAAY,OAAO,GAAG,UAAU,CAAA;IAChC,KAAY,WAAW,GAAG,MAAM,GAAG,CAAC,CAAC,KAAK,EAAE,KAAK,KAAK,UAAU,CAAC,CAAA;IACjE,KAAY,wBAAwB,GAAG;QAAE,QAAQ,EAAE,OAAO,CAAA;KAAE,CAAA;IAC5D,KAAY,mBAAmB,GAAG;QAAE,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAA;IAC3D,KAAY,iBAAiB,GAAG;QAC/B,CAAC,GAAG,EAAE,MAAM,GAAG;YACd,QAAQ,CAAC,EAAE,UAAU,CAAA;YACrB,GAAG,CAAC,EAAE,MAAM,GAAG,MAAM,CAAA;YACrB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,CAAA;SACzE,CAAA;KACD,CAAA;CACD;AAED,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,CAAA"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import * as errors from "@superbuilders/errors";
|
|
2
|
+
/**
|
|
3
|
+
* Attributes must be primitives (string/number/boolean/null/undefined). A
|
|
4
|
+
* non-primitive attr (object, array, function) is a caller bug and THROWS —
|
|
5
|
+
* for a library whose whole job is "the same bytes render every run", a
|
|
6
|
+
* silently dropped attr would be an invisible prompt mutation.
|
|
7
|
+
*/
|
|
8
|
+
function attrsFromProps(props) {
|
|
9
|
+
const attrs = {};
|
|
10
|
+
for (const key in props) {
|
|
11
|
+
if (key === "children" || key === "key") {
|
|
12
|
+
continue;
|
|
13
|
+
}
|
|
14
|
+
const value = props[key];
|
|
15
|
+
if (typeof value === "string" ||
|
|
16
|
+
typeof value === "number" ||
|
|
17
|
+
typeof value === "boolean" ||
|
|
18
|
+
value === null ||
|
|
19
|
+
value === undefined) {
|
|
20
|
+
attrs[key] = value;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
throw errors.new(`prompt attr '${key}' must be a primitive, got ${typeof value}`);
|
|
24
|
+
}
|
|
25
|
+
return attrs;
|
|
26
|
+
}
|
|
27
|
+
function childrenFromProps(props) {
|
|
28
|
+
const children = props.children;
|
|
29
|
+
if (children === undefined) {
|
|
30
|
+
return [];
|
|
31
|
+
}
|
|
32
|
+
if (Array.isArray(children)) {
|
|
33
|
+
return children;
|
|
34
|
+
}
|
|
35
|
+
return [children];
|
|
36
|
+
}
|
|
37
|
+
function jsx(tag, props) {
|
|
38
|
+
let safeProps = {};
|
|
39
|
+
if (props !== undefined) {
|
|
40
|
+
safeProps = props;
|
|
41
|
+
}
|
|
42
|
+
if (typeof tag === "function") {
|
|
43
|
+
return tag(safeProps);
|
|
44
|
+
}
|
|
45
|
+
const element = {
|
|
46
|
+
tag,
|
|
47
|
+
attrs: attrsFromProps(safeProps),
|
|
48
|
+
children: childrenFromProps(safeProps)
|
|
49
|
+
};
|
|
50
|
+
return element;
|
|
51
|
+
}
|
|
52
|
+
function jsxs(tag, props) {
|
|
53
|
+
let safeProps = {};
|
|
54
|
+
if (props !== undefined) {
|
|
55
|
+
safeProps = props;
|
|
56
|
+
}
|
|
57
|
+
if (typeof tag === "function") {
|
|
58
|
+
return tag(safeProps);
|
|
59
|
+
}
|
|
60
|
+
const element = {
|
|
61
|
+
tag,
|
|
62
|
+
attrs: attrsFromProps(safeProps),
|
|
63
|
+
children: childrenFromProps(safeProps)
|
|
64
|
+
};
|
|
65
|
+
return element;
|
|
66
|
+
}
|
|
67
|
+
function Fragment(props) {
|
|
68
|
+
return props.children;
|
|
69
|
+
}
|
|
70
|
+
export { Fragment, jsx, jsxs };
|
|
71
|
+
//# sourceMappingURL=jsx-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"jsx-runtime.js","sourceRoot":"","sources":["../src/jsx-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,uBAAuB,CAAA;AAM/C;;;;;GAKG;AACH,SAAS,cAAc,CAAC,KAA2B;IAClD,MAAM,KAAK,GAAoC,EAAE,CAAA;IACjD,KAAK,MAAM,GAAG,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,GAAG,KAAK,UAAU,IAAI,GAAG,KAAK,KAAK,EAAE,CAAC;YACzC,SAAQ;QACT,CAAC;QACD,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,CAAA;QACxB,IACC,OAAO,KAAK,KAAK,QAAQ;YACzB,OAAO,KAAK,KAAK,QAAQ;YACzB,OAAO,KAAK,KAAK,SAAS;YAC1B,KAAK,KAAK,IAAI;YACd,KAAK,KAAK,SAAS,EAClB,CAAC;YACF,KAAK,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;YAClB,SAAQ;QACT,CAAC;QACD,MAAM,MAAM,CAAC,GAAG,CAAC,gBAAgB,GAAG,8BAA8B,OAAO,KAAK,EAAE,CAAC,CAAA;IAClF,CAAC;IACD,OAAO,KAAK,CAAA;AACb,CAAC;AAED,SAAS,iBAAiB,CAAC,KAA2B;IACrD,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,CAAA;IAC/B,IAAI,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC5B,OAAO,EAAE,CAAA;IACV,CAAC;IACD,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,QAAQ,CAAA;IAChB,CAAC;IACD,OAAO,CAAC,QAAQ,CAAC,CAAA;AAClB,CAAC;AAID,SAAS,GAAG,CAAC,GAAW,EAAE,KAA4B;IACrD,IAAI,SAAS,GAAyB,EAAE,CAAA;IACxC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACzB,SAAS,GAAG,KAAK,CAAA;IAClB,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,UAAU,EAAE,CAAC;QAC/B,OAAO,GAAG,CAAC,SAAS,CAAC,CAAA;IACtB,CAAC;IACD,MAAM,OAAO,GAAkB;QAC9B,GAAG;QACH,KAAK,EAAE,cAAc,CAAC,SAAS,CAAC;QAChC,QAAQ,EAAE,iBAAiB,CAAC,SAAS,CAAC;KACtC,CAAA;IACD,OAAO,OAAO,CAAA;AACf,CAAC;AAID,SAAS,IAAI,CAAC,GAAW,EAAE,KAA4B;IACtD,IAAI,SAAS,GAAyB,EAAE,CAAA;IACxC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACzB,SAAS,GAAG,KAAK,CAAA;IAClB,CAAC;IACD,IAAI,OAAO,GAAG,KAAK,UAAU,EAAE,CAAC;QAC/B,OAAO,GAAG,CAAC,SAAS,CAAC,CAAA;IACtB,CAAC;IACD,MAAM,OAAO,GAAkB;QAC9B,GAAG;QACH,KAAK,EAAE,cAAc,CAAC,SAAS,CAAC;QAChC,QAAQ,EAAE,iBAAiB,CAAC,SAAS,CAAC;KACtC,CAAA;IACD,OAAO,OAAO,CAAA;AACf,CAAC;AAED,SAAS,QAAQ,CAAC,KAAgC;IACjD,OAAO,KAAK,CAAC,QAAQ,CAAA;AACtB,CAAC;AAgBD,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@superbuilders/prompt",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Tiny JSX prompt rendering primitives for Superbuilders applications",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"imports": {
|
|
7
|
+
"#*.ts": {
|
|
8
|
+
"types": "./src/*.ts",
|
|
9
|
+
"default": "./dist/*.js"
|
|
10
|
+
},
|
|
11
|
+
"#*.tsx": {
|
|
12
|
+
"types": "./src/*.tsx",
|
|
13
|
+
"default": "./dist/*.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"exports": {
|
|
17
|
+
".": {
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"import": "./dist/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./jsx-runtime": {
|
|
22
|
+
"types": "./dist/jsx-runtime.d.ts",
|
|
23
|
+
"import": "./dist/jsx-runtime.js"
|
|
24
|
+
},
|
|
25
|
+
"./jsx-dev-runtime": {
|
|
26
|
+
"types": "./dist/jsx-dev-runtime.d.ts",
|
|
27
|
+
"import": "./dist/jsx-dev-runtime.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"dist",
|
|
32
|
+
"src"
|
|
33
|
+
],
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@superbuilders/errors": "^3.0.2"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@biomejs/biome": "^2.5.2",
|
|
39
|
+
"@types/node": "^26.1.0",
|
|
40
|
+
"@typescript/native-preview": "7.0.0-dev.20260702.3",
|
|
41
|
+
"typescript": "^6.0.3"
|
|
42
|
+
},
|
|
43
|
+
"keywords": [
|
|
44
|
+
"jsx",
|
|
45
|
+
"prompt",
|
|
46
|
+
"xml",
|
|
47
|
+
"superbuilders"
|
|
48
|
+
],
|
|
49
|
+
"license": "0BSD",
|
|
50
|
+
"publishConfig": {
|
|
51
|
+
"access": "public"
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"build": "rm -rf dist && tsgo -p tsconfig.build.json",
|
|
55
|
+
"typecheck": "tsgo --noEmit",
|
|
56
|
+
"lint": "biome check ."
|
|
57
|
+
}
|
|
58
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
type PromptPrimitive = string | number | boolean
|
|
2
|
+
type PromptAttrValue = PromptPrimitive | null | undefined | false
|
|
3
|
+
type PromptNode = PromptElement | PromptPrimitive | null | undefined | false | readonly PromptNode[]
|
|
4
|
+
|
|
5
|
+
type PromptElement = {
|
|
6
|
+
tag: string
|
|
7
|
+
attrs: Record<string, PromptAttrValue>
|
|
8
|
+
children: readonly PromptNode[]
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type PromptComponentProps = Record<string, unknown> & { children?: PromptNode }
|
|
12
|
+
type PromptComponent = (props: PromptComponentProps) => PromptNode
|
|
13
|
+
|
|
14
|
+
function isPromptElement(value: unknown): value is PromptElement {
|
|
15
|
+
return typeof value === "object" && value !== null && "tag" in value && "attrs" in value && "children" in value
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function escapeText(value: string): string {
|
|
19
|
+
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">")
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function escapeAttr(value: string): string {
|
|
23
|
+
return escapeText(value).replace(/"/g, """).replace(/'/g, "'")
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function renderAttrs(attrs: Record<string, PromptAttrValue>): string {
|
|
27
|
+
const parts: string[] = []
|
|
28
|
+
for (const key in attrs) {
|
|
29
|
+
const value = attrs[key]
|
|
30
|
+
if (value === undefined || value === null || value === false) {
|
|
31
|
+
continue
|
|
32
|
+
}
|
|
33
|
+
parts.push(` ${key}="${escapeAttr(String(value))}"`)
|
|
34
|
+
}
|
|
35
|
+
return parts.join("")
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function childIsInline(node: PromptNode): boolean {
|
|
39
|
+
if (node === undefined || node === null || node === false) {
|
|
40
|
+
return true
|
|
41
|
+
}
|
|
42
|
+
if (Array.isArray(node)) {
|
|
43
|
+
return node.every(childIsInline)
|
|
44
|
+
}
|
|
45
|
+
return !isPromptElement(node)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function renderInline(node: PromptNode): string {
|
|
49
|
+
if (node === undefined || node === null || node === false) {
|
|
50
|
+
return ""
|
|
51
|
+
}
|
|
52
|
+
if (Array.isArray(node)) {
|
|
53
|
+
return node.map(renderInline).join("")
|
|
54
|
+
}
|
|
55
|
+
if (isPromptElement(node)) {
|
|
56
|
+
return renderElement(node, 0)
|
|
57
|
+
}
|
|
58
|
+
return escapeText(String(node))
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function renderChild(node: PromptNode, level: number): string {
|
|
62
|
+
if (node === undefined || node === null || node === false) {
|
|
63
|
+
return ""
|
|
64
|
+
}
|
|
65
|
+
if (Array.isArray(node)) {
|
|
66
|
+
return node
|
|
67
|
+
.map(function renderArrayChild(child) {
|
|
68
|
+
return renderChild(child, level)
|
|
69
|
+
})
|
|
70
|
+
.join("")
|
|
71
|
+
}
|
|
72
|
+
if (isPromptElement(node)) {
|
|
73
|
+
return `${" ".repeat(level)}${renderElement(node, level)}\n`
|
|
74
|
+
}
|
|
75
|
+
const text = escapeText(String(node))
|
|
76
|
+
if (text.includes("\n")) {
|
|
77
|
+
return `${text}\n`
|
|
78
|
+
}
|
|
79
|
+
return `${" ".repeat(level)}${text}\n`
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function renderElement(element: PromptElement, level: number): string {
|
|
83
|
+
const attrs = renderAttrs(element.attrs)
|
|
84
|
+
if (element.children.length === 0) {
|
|
85
|
+
return `<${element.tag}${attrs}></${element.tag}>`
|
|
86
|
+
}
|
|
87
|
+
if (element.children.every(childIsInline)) {
|
|
88
|
+
return `<${element.tag}${attrs}>${element.children.map(renderInline).join("")}</${element.tag}>`
|
|
89
|
+
}
|
|
90
|
+
const children = element.children
|
|
91
|
+
.map(function renderNestedChild(child) {
|
|
92
|
+
return renderChild(child, level + 1)
|
|
93
|
+
})
|
|
94
|
+
.join("")
|
|
95
|
+
return `<${element.tag}${attrs}>\n${children}${" ".repeat(level)}</${element.tag}>`
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function render(node: PromptNode): string {
|
|
99
|
+
if (Array.isArray(node)) {
|
|
100
|
+
return node.map(render).join("\n\n")
|
|
101
|
+
}
|
|
102
|
+
if (isPromptElement(node)) {
|
|
103
|
+
return renderElement(node, 0)
|
|
104
|
+
}
|
|
105
|
+
return renderInline(node)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export type { PromptAttrValue, PromptComponent, PromptComponentProps, PromptElement, PromptNode }
|
|
109
|
+
export { render }
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import * as errors from "@superbuilders/errors"
|
|
2
|
+
import type { PromptAttrValue, PromptComponentProps, PromptElement, PromptNode } from "#index.ts"
|
|
3
|
+
|
|
4
|
+
type JsxComponent<P extends PromptComponentProps = PromptComponentProps> = (props: P) => PromptNode
|
|
5
|
+
type JsxTag<P extends PromptComponentProps = PromptComponentProps> = string | JsxComponent<P>
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Attributes must be primitives (string/number/boolean/null/undefined). A
|
|
9
|
+
* non-primitive attr (object, array, function) is a caller bug and THROWS —
|
|
10
|
+
* for a library whose whole job is "the same bytes render every run", a
|
|
11
|
+
* silently dropped attr would be an invisible prompt mutation.
|
|
12
|
+
*/
|
|
13
|
+
function attrsFromProps(props: PromptComponentProps): Record<string, PromptAttrValue> {
|
|
14
|
+
const attrs: Record<string, PromptAttrValue> = {}
|
|
15
|
+
for (const key in props) {
|
|
16
|
+
if (key === "children" || key === "key") {
|
|
17
|
+
continue
|
|
18
|
+
}
|
|
19
|
+
const value = props[key]
|
|
20
|
+
if (
|
|
21
|
+
typeof value === "string" ||
|
|
22
|
+
typeof value === "number" ||
|
|
23
|
+
typeof value === "boolean" ||
|
|
24
|
+
value === null ||
|
|
25
|
+
value === undefined
|
|
26
|
+
) {
|
|
27
|
+
attrs[key] = value
|
|
28
|
+
continue
|
|
29
|
+
}
|
|
30
|
+
throw errors.new(`prompt attr '${key}' must be a primitive, got ${typeof value}`)
|
|
31
|
+
}
|
|
32
|
+
return attrs
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function childrenFromProps(props: PromptComponentProps): readonly PromptNode[] {
|
|
36
|
+
const children = props.children
|
|
37
|
+
if (children === undefined) {
|
|
38
|
+
return []
|
|
39
|
+
}
|
|
40
|
+
if (Array.isArray(children)) {
|
|
41
|
+
return children
|
|
42
|
+
}
|
|
43
|
+
return [children]
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function jsx<P extends PromptComponentProps>(tag: JsxComponent<P>, props: P): PromptNode
|
|
47
|
+
function jsx(tag: string, props?: PromptComponentProps): PromptNode
|
|
48
|
+
function jsx(tag: JsxTag, props?: PromptComponentProps): PromptNode {
|
|
49
|
+
let safeProps: PromptComponentProps = {}
|
|
50
|
+
if (props !== undefined) {
|
|
51
|
+
safeProps = props
|
|
52
|
+
}
|
|
53
|
+
if (typeof tag === "function") {
|
|
54
|
+
return tag(safeProps)
|
|
55
|
+
}
|
|
56
|
+
const element: PromptElement = {
|
|
57
|
+
tag,
|
|
58
|
+
attrs: attrsFromProps(safeProps),
|
|
59
|
+
children: childrenFromProps(safeProps)
|
|
60
|
+
}
|
|
61
|
+
return element
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function jsxs<P extends PromptComponentProps>(tag: JsxComponent<P>, props: P): PromptNode
|
|
65
|
+
function jsxs(tag: string, props?: PromptComponentProps): PromptNode
|
|
66
|
+
function jsxs(tag: JsxTag, props?: PromptComponentProps): PromptNode {
|
|
67
|
+
let safeProps: PromptComponentProps = {}
|
|
68
|
+
if (props !== undefined) {
|
|
69
|
+
safeProps = props
|
|
70
|
+
}
|
|
71
|
+
if (typeof tag === "function") {
|
|
72
|
+
return tag(safeProps)
|
|
73
|
+
}
|
|
74
|
+
const element: PromptElement = {
|
|
75
|
+
tag,
|
|
76
|
+
attrs: attrsFromProps(safeProps),
|
|
77
|
+
children: childrenFromProps(safeProps)
|
|
78
|
+
}
|
|
79
|
+
return element
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function Fragment(props: { children?: PromptNode }): PromptNode {
|
|
83
|
+
return props.children
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export namespace JSX {
|
|
87
|
+
export type Element = PromptNode
|
|
88
|
+
export type ElementType = string | ((props: never) => PromptNode)
|
|
89
|
+
export type ElementChildrenAttribute = { children: unknown }
|
|
90
|
+
export type IntrinsicAttributes = { key?: string | number }
|
|
91
|
+
export type IntrinsicElements = {
|
|
92
|
+
[tag: string]: {
|
|
93
|
+
children?: PromptNode
|
|
94
|
+
key?: string | number
|
|
95
|
+
[attr: string]: PromptNode | string | number | boolean | null | undefined
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export { Fragment, jsx, jsxs }
|