getsyntux 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 +21 -0
- package/README.md +142 -0
- package/dist/index.d.mts +62 -0
- package/dist/index.d.ts +62 -0
- package/dist/index.js +229 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +227 -0
- package/dist/index.mjs.map +1 -0
- package/dist/plugin.d.mts +2 -0
- package/dist/plugin.d.ts +2 -0
- package/dist/plugin.js +75 -0
- package/dist/plugin.js.map +1 -0
- package/dist/plugin.mjs +73 -0
- package/dist/plugin.mjs.map +1 -0
- package/package.json +38 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 ColonelParrot
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<i>syntux</i> lets you build <b>personalized</b> generative UIs that are <i>secure</i> and <i>deterministic</i>.
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
How it works:
|
|
9
|
+
|
|
10
|
+

|
|
11
|
+
<br/><br/>
|
|
12
|
+
`values` can be anything:
|
|
13
|
+
|
|
14
|
+

|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
<h3 align="center" margin="0"><a href="https://github.com/puffinsoft/syntux/wiki">➡️ view documentation</a></h3>
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
Features:
|
|
22
|
+
|
|
23
|
+
- 💾 **Cacheable** - generated interfaces <b>can be reused</b> (*) with different values.
|
|
24
|
+
- 🎨 **Consistency** - use and restrict custom components for reusability and consistent aesthetics.
|
|
25
|
+
- 🔒 **Secure by default** - uses built-in component mapping engine. No `dangerouslySetInnerHTML`.
|
|
26
|
+
- 🌐 **Server-sided** - for full SEO support and stronger first load performance.
|
|
27
|
+
|
|
28
|
+
<sup>* assuming same object structure (type). arrays are fully supported!</sup>
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
### Examples
|
|
33
|
+
|
|
34
|
+
Personalized analytics dashboard on Next.js:
|
|
35
|
+
|
|
36
|
+
```jsx
|
|
37
|
+
import { GeneratedPage, GeneratedContent } from 'getsyntux';
|
|
38
|
+
|
|
39
|
+
const interest = "marketing";
|
|
40
|
+
const statistics = [{ ... }, { ... }, { ... }];
|
|
41
|
+
|
|
42
|
+
<GeneratedPage context={`Analytics dashboard. User interest: ${interest}`} schema={
|
|
43
|
+
<div>
|
|
44
|
+
<Navbar />
|
|
45
|
+
<GeneratedContent
|
|
46
|
+
value={statistics}
|
|
47
|
+
allowedComponents={[ BarChart, LineChart, Histogram ]}
|
|
48
|
+
hint="show charts related to user interest first"
|
|
49
|
+
/>
|
|
50
|
+
<Footer />
|
|
51
|
+
</div>
|
|
52
|
+
} />
|
|
53
|
+
```
|
|
54
|
+
<sup><i>syntux</i> is tested for Next.js, but should support all React frameworks.</sup>
|
|
55
|
+
|
|
56
|
+
<h3 align="center" margin="0"><a href="https://github.com/puffinsoft/syntux/wiki">➡️ view documentation</a></h3>
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
### Installation
|
|
60
|
+
|
|
61
|
+
We use the [Vercel AI SDK](https://github.com/vercel/ai) to provide support for all LLM providers.
|
|
62
|
+
|
|
63
|
+
First, install via npm:
|
|
64
|
+
```
|
|
65
|
+
npm i ai
|
|
66
|
+
npm i getsyntux
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
That's not it though! See the [wiki](https://github.com/puffinsoft/syntux/wiki) on how to set it up. It takes less than 5 minutes.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
### FAQ
|
|
74
|
+
|
|
75
|
+
**How does generation work?**
|
|
76
|
+
|
|
77
|
+

|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
Generated designs are designed to be *reusable* and *cacheable*.
|
|
82
|
+
|
|
83
|
+
To do this, *syntux* generates a "React Interface Schema" (RIS). It's essentially an Abstract Syntax Tree tailored to the `value` that you pass in. This schema is then hydrated by *syntux* and rendered.
|
|
84
|
+
|
|
85
|
+
The RIS has built-in support for arrays, and thus can handle inputs of arbitrary lengths, making it cacheable. To get a better understanding, see the [LLM prompt itself](src/prompt.md).
|
|
86
|
+
|
|
87
|
+
\-
|
|
88
|
+
|
|
89
|
+
<details>
|
|
90
|
+
<summary>How does <i>syntux</i> understand how to use components?</summary>
|
|
91
|
+
|
|
92
|
+
👀 **tl:dr**: *syntux* is not designed to understand your codebase. It is only designed to know ***how to use*** your codebase.
|
|
93
|
+
|
|
94
|
+
**The LLM never sees your source code.** The result? Better privacy, lower LLM costs, faster generation time.
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
To do this, *syntux* automatically generates documentation (known as *llmContext*) for your components at compilation time.
|
|
99
|
+
|
|
100
|
+
We use Babel to scan your code and attach *llmContext* to components (automatically). Additionally, for best results, developers should provide *user context* to reinforce LLM understanding.
|
|
101
|
+
|
|
102
|
+
For instance:
|
|
103
|
+
|
|
104
|
+
```js
|
|
105
|
+
const Profile = ({ username, imageURL }: { username: string, imageURL: string }) => { /* ... */ }
|
|
106
|
+
console.log(Profile.llmContext) // "props: ({ username, imageURL }: { username: string, imageURL: string })"
|
|
107
|
+
console.log(Profile.llmName) // "Profile"
|
|
108
|
+
|
|
109
|
+
Profile.userContext = "Displays a small user profile"; // add further context
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
> **Note**: The name of your components and props matter!
|
|
113
|
+
>
|
|
114
|
+
> That information is directly sent to the LLM for context on how to incorporate it into the UI.
|
|
115
|
+
|
|
116
|
+
</details>
|
|
117
|
+
|
|
118
|
+
<details>
|
|
119
|
+
<summary>What about state? Can state be generated?</summary>
|
|
120
|
+
|
|
121
|
+
Non-stateful components should be wrapped in stateful components, then passed to *syntux* to generate.
|
|
122
|
+
|
|
123
|
+
Dynamic state generation violates the deterministic paradigm of <i>syntux</i>, and is thus not supported by design.
|
|
124
|
+
</details>
|
|
125
|
+
|
|
126
|
+
<details>
|
|
127
|
+
<summary>How do generated components share information?</summary>
|
|
128
|
+
|
|
129
|
+
Use contexts.
|
|
130
|
+
|
|
131
|
+
```jsx
|
|
132
|
+
<GeneratedPage schema={
|
|
133
|
+
<Context.Provider>
|
|
134
|
+
<GeneratedContent components={[ MyComponent ]} />
|
|
135
|
+
</Context.Provider>
|
|
136
|
+
} />
|
|
137
|
+
```
|
|
138
|
+
</details>
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
*syntux* is open source software, licensed under the [MIT](LICENSE) license.
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ComponentType } from 'react';
|
|
3
|
+
import { LanguageModel } from 'ai';
|
|
4
|
+
|
|
5
|
+
interface SchemaNode {
|
|
6
|
+
type?: string;
|
|
7
|
+
props?: Record<string, any>;
|
|
8
|
+
children?: (SchemaNode | string)[];
|
|
9
|
+
source?: string;
|
|
10
|
+
template?: SchemaNode;
|
|
11
|
+
$bind?: string;
|
|
12
|
+
}
|
|
13
|
+
interface RendererProps {
|
|
14
|
+
schema: SchemaNode | string;
|
|
15
|
+
global: any;
|
|
16
|
+
local?: any;
|
|
17
|
+
components: Record<string, ComponentType<any> | string>;
|
|
18
|
+
}
|
|
19
|
+
declare function Renderer({ schema, global, local, components }: RendererProps): react_jsx_runtime.JSX.Element;
|
|
20
|
+
|
|
21
|
+
type SyntuxComponent<P = any> = React.ComponentType<P> & {
|
|
22
|
+
userContext?: string;
|
|
23
|
+
llmContext?: string;
|
|
24
|
+
llmName?: string;
|
|
25
|
+
identifier?: Symbol;
|
|
26
|
+
};
|
|
27
|
+
type SyntuxElement<P = any> = React.ReactElement<P, SyntuxComponent<P>>;
|
|
28
|
+
|
|
29
|
+
interface GeneratedPageProps {
|
|
30
|
+
context?: string;
|
|
31
|
+
schema: SyntuxElement;
|
|
32
|
+
onGenerate?: (result: SchemaNode[]) => void;
|
|
33
|
+
cached?: (SchemaNode | string)[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface GeneratedContentProps {
|
|
37
|
+
values: any;
|
|
38
|
+
components?: (SyntuxComponent<any> | string)[];
|
|
39
|
+
hint?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Section of user interface for LLM to generate.
|
|
43
|
+
* @param values The values (object, primitive, or array) to be displayed.
|
|
44
|
+
* @param components List of allowed components that LLM can use.
|
|
45
|
+
* @param hint Additional custom instructions for the LLM.
|
|
46
|
+
*/
|
|
47
|
+
declare function GeneratedContent(props: GeneratedContentProps): react_jsx_runtime.JSX.Element;
|
|
48
|
+
declare namespace GeneratedContent {
|
|
49
|
+
var identifier: typeof SIGNATURE;
|
|
50
|
+
}
|
|
51
|
+
declare const SIGNATURE: unique symbol;
|
|
52
|
+
|
|
53
|
+
interface SyntuxFactoryConfig {
|
|
54
|
+
model: LanguageModel;
|
|
55
|
+
}
|
|
56
|
+
declare const createSyntuxFactory: (config: SyntuxFactoryConfig) => {
|
|
57
|
+
GeneratedPage: ({ context, schema, cached, onGenerate }: GeneratedPageProps) => Promise<react_jsx_runtime.JSX.Element>;
|
|
58
|
+
GeneratedContent: typeof GeneratedContent;
|
|
59
|
+
Renderer: typeof Renderer;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export { type GeneratedContentProps, type GeneratedPageProps, type SchemaNode, type SyntuxFactoryConfig, createSyntuxFactory };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import { ComponentType } from 'react';
|
|
3
|
+
import { LanguageModel } from 'ai';
|
|
4
|
+
|
|
5
|
+
interface SchemaNode {
|
|
6
|
+
type?: string;
|
|
7
|
+
props?: Record<string, any>;
|
|
8
|
+
children?: (SchemaNode | string)[];
|
|
9
|
+
source?: string;
|
|
10
|
+
template?: SchemaNode;
|
|
11
|
+
$bind?: string;
|
|
12
|
+
}
|
|
13
|
+
interface RendererProps {
|
|
14
|
+
schema: SchemaNode | string;
|
|
15
|
+
global: any;
|
|
16
|
+
local?: any;
|
|
17
|
+
components: Record<string, ComponentType<any> | string>;
|
|
18
|
+
}
|
|
19
|
+
declare function Renderer({ schema, global, local, components }: RendererProps): react_jsx_runtime.JSX.Element;
|
|
20
|
+
|
|
21
|
+
type SyntuxComponent<P = any> = React.ComponentType<P> & {
|
|
22
|
+
userContext?: string;
|
|
23
|
+
llmContext?: string;
|
|
24
|
+
llmName?: string;
|
|
25
|
+
identifier?: Symbol;
|
|
26
|
+
};
|
|
27
|
+
type SyntuxElement<P = any> = React.ReactElement<P, SyntuxComponent<P>>;
|
|
28
|
+
|
|
29
|
+
interface GeneratedPageProps {
|
|
30
|
+
context?: string;
|
|
31
|
+
schema: SyntuxElement;
|
|
32
|
+
onGenerate?: (result: SchemaNode[]) => void;
|
|
33
|
+
cached?: (SchemaNode | string)[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface GeneratedContentProps {
|
|
37
|
+
values: any;
|
|
38
|
+
components?: (SyntuxComponent<any> | string)[];
|
|
39
|
+
hint?: string;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Section of user interface for LLM to generate.
|
|
43
|
+
* @param values The values (object, primitive, or array) to be displayed.
|
|
44
|
+
* @param components List of allowed components that LLM can use.
|
|
45
|
+
* @param hint Additional custom instructions for the LLM.
|
|
46
|
+
*/
|
|
47
|
+
declare function GeneratedContent(props: GeneratedContentProps): react_jsx_runtime.JSX.Element;
|
|
48
|
+
declare namespace GeneratedContent {
|
|
49
|
+
var identifier: typeof SIGNATURE;
|
|
50
|
+
}
|
|
51
|
+
declare const SIGNATURE: unique symbol;
|
|
52
|
+
|
|
53
|
+
interface SyntuxFactoryConfig {
|
|
54
|
+
model: LanguageModel;
|
|
55
|
+
}
|
|
56
|
+
declare const createSyntuxFactory: (config: SyntuxFactoryConfig) => {
|
|
57
|
+
GeneratedPage: ({ context, schema, cached, onGenerate }: GeneratedPageProps) => Promise<react_jsx_runtime.JSX.Element>;
|
|
58
|
+
GeneratedContent: typeof GeneratedContent;
|
|
59
|
+
Renderer: typeof Renderer;
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export { type GeneratedContentProps, type GeneratedPageProps, type SchemaNode, type SyntuxFactoryConfig, createSyntuxFactory };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
5
|
+
var ai = require('ai');
|
|
6
|
+
|
|
7
|
+
// src/GeneratedPage.tsx
|
|
8
|
+
function GeneratedContent(props) {
|
|
9
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, {});
|
|
10
|
+
}
|
|
11
|
+
var SIGNATURE = /* @__PURE__ */ Symbol("GeneratedContent");
|
|
12
|
+
GeneratedContent.identifier = SIGNATURE;
|
|
13
|
+
var resolvePath = (obj, path) => {
|
|
14
|
+
if (path === "$") return obj;
|
|
15
|
+
return path.split(".").reduce((acc, curr) => acc == null ? void 0 : acc[curr], obj);
|
|
16
|
+
};
|
|
17
|
+
var get = (global, local, path) => {
|
|
18
|
+
if (path.startsWith("$item.")) {
|
|
19
|
+
path = path.slice(6);
|
|
20
|
+
return resolvePath(local, path);
|
|
21
|
+
} else {
|
|
22
|
+
if (path === "$item") return local;
|
|
23
|
+
return resolvePath(global, path);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
var resolveProps = (global, local, props) => {
|
|
27
|
+
if (!props) return;
|
|
28
|
+
if ("$bind" in props) return get(global, local, props.$bind);
|
|
29
|
+
Object.keys(props).forEach((key) => {
|
|
30
|
+
const val = props[key];
|
|
31
|
+
if (typeof val === "object") {
|
|
32
|
+
props[key] = resolveProps(global, local, val);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
return props;
|
|
36
|
+
};
|
|
37
|
+
function Renderer({
|
|
38
|
+
schema,
|
|
39
|
+
global,
|
|
40
|
+
local,
|
|
41
|
+
components
|
|
42
|
+
}) {
|
|
43
|
+
var _a;
|
|
44
|
+
if (typeof schema === "string") return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: schema });
|
|
45
|
+
if (schema.$bind) {
|
|
46
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: get(global, local, schema.$bind) });
|
|
47
|
+
}
|
|
48
|
+
if (schema.type === "__ForEach__" && schema.source && schema.template) {
|
|
49
|
+
const sourceArr = get(global, local, schema.source);
|
|
50
|
+
if (!Array.isArray(sourceArr)) return null;
|
|
51
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: sourceArr.map((item, index) => {
|
|
52
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
53
|
+
Renderer,
|
|
54
|
+
{
|
|
55
|
+
schema: schema.template,
|
|
56
|
+
global,
|
|
57
|
+
local: item,
|
|
58
|
+
components
|
|
59
|
+
},
|
|
60
|
+
index
|
|
61
|
+
);
|
|
62
|
+
}) });
|
|
63
|
+
}
|
|
64
|
+
if (!schema.type) return null;
|
|
65
|
+
const Component = components[schema.type] || schema.type;
|
|
66
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Component, { ...resolveProps(global, local, schema.props), children: (_a = schema.children) == null ? void 0 : _a.map((item, index) => {
|
|
67
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
68
|
+
Renderer,
|
|
69
|
+
{
|
|
70
|
+
schema: item,
|
|
71
|
+
global,
|
|
72
|
+
local,
|
|
73
|
+
components
|
|
74
|
+
},
|
|
75
|
+
index
|
|
76
|
+
);
|
|
77
|
+
}) });
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/util.ts
|
|
81
|
+
var endDelimiter = "</UISchema>";
|
|
82
|
+
function parseResponse(llmResponse) {
|
|
83
|
+
const split = llmResponse.split(/\<UISchema index="\d+">/m).slice(1).map((e) => e.trim());
|
|
84
|
+
const contents = split.map((e) => e.slice(0, -endDelimiter.length));
|
|
85
|
+
const parsed = contents.map((e) => JSON.parse(e));
|
|
86
|
+
return parsed;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// src/prompt.md
|
|
90
|
+
var prompt_default = '<system_persona>\r\nYou are the **UI Schema Generation Engine**, a specialized architect responsible for converting raw data structures into abstract, reusable React Interface Schemas (JSON-DSL).\r\n\r\nYour output is **NOT** code. Your output is a JSON-based Abstract Syntax Tree (AST) that describes the UI structure. The rendering engine will hydrate this schema with data later.\r\n</system_persona>\r\n\r\n<core_philosophy>\r\n1. **Separation of Concerns:** You define the *structure*. You do NOT hardcode *values*.\r\n2. **Strict Adherence:** You may ONLY use components explicitly listed in the `<AllowedComponents>` block of the input. If the block is missing or empty, revert to the <default_component_library>.\r\n3. **Semantic Structure:** Even though you are generating JSON, the resulting UI must be semantically correct (using proper hierarchy, semantic HTML tags, and logical grouping).\r\n4. **Reusability:** Your schema must be valid regardless of the specific values in the data. It must handle list lengths of 0 or 1000 gracefully using the Iterator Protocol.\r\n</core_philosophy>\r\n\r\n<dsl_syntax_rules>\r\nThe output must be a JSON object adhering to this strict recursive interface:\r\n\r\n### 1. The Standard Node\r\nUsed for HTML tags or Custom Components.\r\n```json\r\n{\r\n "type": "div" | "h1" | "MyCustomComponent",\r\n "props": { "className": "...", "customProp": "..." },\r\n "children": [] // Array of Nodes or Strings\r\n}\r\n```\r\n\r\n### 2. The Binding Protocol (`$bind`)\r\n\r\n**NEVER** output raw data values (e.g., "John", "john@email.com") in the schema.\r\nInstead, bind to a path.\r\n\r\n```json\r\n// BAD\r\n{ "type": "span", "children": ["John"] }\r\n\r\n// GOOD\r\n{ "type": "span", "children": [{ "$bind": "user.firstName" }] }\r\n```\r\n\r\nYou have access to exactly **two scopes** at any time:\r\n- **Global Scope (Root)**: Any path **WITHOUT** the `$item` prefix accesses the top-level global data object. This is available at any nesting depth.\r\n - *Example:* `"$bind": "pageTitle"` (Always looks at `data.pageTitle`)\r\n- **Local Scope (Current Item):** Any path **STARTING WITH** `$item` accesses the immediate object currently being iterated in a loop.\r\n - *Example:* `"$bind": "$item.name"` (Looks at `name` on the current loop item).\r\n - *Example:* `"$bind": "$item"` (Renders the current loop item, usually a string).\r\n\r\nIn special cases, you may need to reference a specific, fixed index in an array. To do that, use dot notation to access the index. For instance: `arr.1.property` accesses the `property` property of the 2nd item in `arr`. However, use this conservatively; prefer to use the Iterator Protocol unless it doesn\'t make sense (e.g., it\'s a static array).\r\n\r\n**CRITICAL:** Intermediate scopes are not accessible. Inside a nested loop, `$item` refers *only* to the innermost item.\r\n\r\n### 3. The Iterator Protocol (`__ForEach__`)\r\n\r\nIf the data value is an Array, you MUST use this node. Do not manually unroll lists.\r\n\r\n- **Root Arrays**: If the input value is the array itself, use "source": "$".\r\n- **Nested Arrays**: If the array is a property on the current item, use `"source": "$item.path.to.array"`.\r\n- **Global Arrays**: If the array is a property on the Global Root, use `"source": "path.to.array"`.\r\n\r\n```json\r\n{\r\n "type": "__ForEach__",\r\n "source": "$" | "$item.path.to.array" | "path.to.array",\r\n "template": {\r\n // This is the shape of a SINGLE item.\r\n // Inside here, use "$item" to refer to the current array element.\r\n "type": "li",\r\n "children": [{ "$bind": "$item.name" }]\r\n }\r\n}\r\n```\r\n\r\n</dsl_syntax_rules>\r\n\r\n<default_component_library>\r\nIf no specific allowed components are provided, you have access to this semantic HTML suite:\r\n\r\n * **Layout:** `div`, `section`, `article`, `main`, `aside`, `header`, `footer`\r\n * **Typography:** `h1`, `h2`, `h3`, `p`, `span`, `strong`, `em`, `blockquote`, `pre`, `code`\r\n * **Lists:** `ul`, `ol`, `li`\r\n * **Interaction:** `button`, `a` (use href prop), `details`, `summary`\r\n * **Form:** `input`, `label`, `textarea`, `select`, `option`\r\n * **Media:** `img`, `figure`, `figcaption`\r\n\r\n</default_component_library>\r\n\r\n<input_processing_rules>\r\nThe user will provide one or more `<GeneratedContent>` blocks.\r\n\r\n1. **Parse `AllowedComponents`:** A comma-separated list.\r\n * Lowercase = Native HTML tags.\r\n * Uppercase = Custom React Components.\r\n2. **Parse `ComponentContext`:** Defines the TypeScript interface for Custom Components.\r\n * *CRITICAL:* You must strictly adhere to the prop names and types defined here. Do not hallucinate props for custom components.\r\n * Components are separated by a comma, in the format `ComponentName [props: { ... }, details: "..."]`. The `props` indicate what `props` it must accept, in Typescript format. The `details` is an optional field, and describes what the component does. Use this information in whatever way to improve your generation output. If you encounter a complex type in `props`, look at the input values and make your best guess at what value is the best fit.\r\n3. **Parse `UserContext`:** This is anything the developer believes is relevant for your task. It could describe a specific UI style or the correct way to use a custom component.\r\n * *CRITICAL*: To the best of your ability, respect the developer\'s wishes. If no UserContext is provided, you should accomplish the task as you see fit, with no constraints.\r\n * *CRITICAL*: This is only relevant to the current <GeneratedContent> block!\r\n3. **Parse `Value`:** The JSON data structure you are building the UI for.\r\n\r\nAdditionally, the user may provide a <PageContext> before all <GeneratedContent> blocks. Think of this as a global UserContext. This is meant to provide additional context and guiding when designing the UI, which you should try to adhere to. If none is provided, accomplish the task as you see fit, with no constraints.\r\n\r\n</input_processing_rules>\r\n\r\n<output_formatting>\r\nFor every `<GeneratedContent>` input block, you must generate exactly one `<UISchema>` output block.\r\nThe order must be preserved.\r\n\r\nInput:\r\n<PageContext></PageContext>\r\n<GeneratedContent> ... </GeneratedContent> (Section 1)\r\n<GeneratedContent> ... </GeneratedContent> (Section 2)\r\n\r\nOutput:\r\n<UISchema index="0"> ...JSON... </UISchema>\r\n<UISchema index="1"> ...JSON... </UISchema>\r\n</output_formatting>\r\n\r\n<examples>\r\n**Input:**\r\n<GeneratedContent>\r\n<AllowedComponents>div,span,Avatar</AllowedComponents>\r\n<ComponentContext>Avatar [props: { url: string }]</ComponentContext>\r\n<UserContext>grouped under one div</UserContext>\r\n<Value>{ authors: [{ name: "J.K.", img: "..." }, { name: "Tolkien", img: "..." }] }</Value>\r\n</GeneratedContent>\r\n\r\n**Correct Output:**\r\n<UISchema index="0">\r\n{\r\n "type": "div",\r\n "props": {\r\n "className": "author-list"\r\n },\r\n "children": [\r\n {\r\n "type": "__ForEach__",\r\n "source": "authors",\r\n "template": {\r\n "type": "div",\r\n "props": {\r\n "className": "author-card"\r\n },\r\n "children": [\r\n {\r\n "type": "Avatar",\r\n "props": {\r\n "url": {\r\n "$bind": "$item.img"\r\n }\r\n }\r\n },\r\n {\r\n "type": "span",\r\n "children": [\r\n {\r\n "$bind": "$item.name"\r\n }\r\n ]\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n}\r\n</UISchema>\r\n</examples>\r\n\r\n<reasoning_requirements>\r\nBefore generating the JSON, briefly analyze the data structure to identify arrays (requiring `__ForEach__`) and custom component opportunities. Use the mental scratchpad if necessary, but keep the final output strictly within `<UISchema>` tags.\r\n</reasoning_requirements>\r\n\r\n<IMPORTANT>\r\nDo NOT output anything except the UISchema.\r\n</IMPORTANT>';
|
|
91
|
+
function extractChildren(element) {
|
|
92
|
+
var _a;
|
|
93
|
+
if ((_a = element == null ? void 0 : element.props) == null ? void 0 : _a.children) {
|
|
94
|
+
let children = element.props.children;
|
|
95
|
+
if (!Array.isArray(children)) children = [children];
|
|
96
|
+
return children;
|
|
97
|
+
}
|
|
98
|
+
return [];
|
|
99
|
+
}
|
|
100
|
+
function searchChildren(element, acc) {
|
|
101
|
+
const children = extractChildren(element);
|
|
102
|
+
children.forEach((element2, index) => {
|
|
103
|
+
if ((element2 == null ? void 0 : element2.type.identifier) === SIGNATURE) {
|
|
104
|
+
const { values, components, hint } = element2.props;
|
|
105
|
+
const realComponents = [];
|
|
106
|
+
if (components) {
|
|
107
|
+
components.forEach((comp) => {
|
|
108
|
+
if (typeof comp === "string") {
|
|
109
|
+
realComponents.push({
|
|
110
|
+
llmName: comp
|
|
111
|
+
});
|
|
112
|
+
} else {
|
|
113
|
+
realComponents.push({
|
|
114
|
+
llmName: comp.llmName,
|
|
115
|
+
llmContext: comp.llmContext,
|
|
116
|
+
userContext: comp.userContext
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
acc.push({
|
|
122
|
+
values,
|
|
123
|
+
components: realComponents,
|
|
124
|
+
hint: hint || ""
|
|
125
|
+
});
|
|
126
|
+
} else {
|
|
127
|
+
searchChildren(element2, acc);
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
function generateInput(content, context) {
|
|
132
|
+
let str = "";
|
|
133
|
+
if (context) {
|
|
134
|
+
str = `<PageContext>${context}</PageContext>
|
|
135
|
+
`;
|
|
136
|
+
}
|
|
137
|
+
content.forEach((schema) => {
|
|
138
|
+
const allowedComponents = schema.components.map((e) => e.llmName);
|
|
139
|
+
const componentContext = [];
|
|
140
|
+
schema.components.forEach((comp) => {
|
|
141
|
+
if (comp.llmContext) {
|
|
142
|
+
let contextStr;
|
|
143
|
+
if (comp.userContext) {
|
|
144
|
+
contextStr = `${comp.llmName} [${comp.llmContext}, details: ${comp.userContext}]`;
|
|
145
|
+
} else {
|
|
146
|
+
contextStr = `${comp.llmName} [${comp.llmContext}]`;
|
|
147
|
+
}
|
|
148
|
+
componentContext.push(contextStr);
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
const userContext = schema.hint;
|
|
152
|
+
const value = JSON.stringify(schema.values);
|
|
153
|
+
str += `<GeneratedContent>
|
|
154
|
+
<AllowedComponents>${allowedComponents.join(",")}</AllowedComponents>
|
|
155
|
+
<ComponentContext>${componentContext.join(",")}</ComponentContext>
|
|
156
|
+
<UserContext>${userContext}</UserContext>
|
|
157
|
+
<Value>${value}</Value>
|
|
158
|
+
</GeneratedContent>
|
|
159
|
+
`;
|
|
160
|
+
});
|
|
161
|
+
return str;
|
|
162
|
+
}
|
|
163
|
+
function createComponentRegistry(components) {
|
|
164
|
+
if (!components) return {};
|
|
165
|
+
return components.reduce((acc, curr) => {
|
|
166
|
+
if (typeof curr === "string") {
|
|
167
|
+
acc[curr] = curr;
|
|
168
|
+
} else {
|
|
169
|
+
if (curr.llmName) {
|
|
170
|
+
acc[curr.llmName] = curr;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return acc;
|
|
174
|
+
}, {});
|
|
175
|
+
}
|
|
176
|
+
function hydrate(schema, dsl) {
|
|
177
|
+
let componentIndex = 0;
|
|
178
|
+
function swapChildren(element) {
|
|
179
|
+
const children = extractChildren(element);
|
|
180
|
+
return children.map((child, ind) => {
|
|
181
|
+
if (!react.isValidElement(child)) return child;
|
|
182
|
+
if (child.type.identifier === SIGNATURE) {
|
|
183
|
+
const { values, components, hint } = child.props;
|
|
184
|
+
return /* @__PURE__ */ jsxRuntime.jsx(Renderer, { schema: dsl[componentIndex++], global: values, local: values, components: createComponentRegistry(components) }, ind);
|
|
185
|
+
}
|
|
186
|
+
return swapChildren(child);
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
return swapChildren(schema);
|
|
190
|
+
}
|
|
191
|
+
var createGeneratedPage = (model) => {
|
|
192
|
+
return async function GeneratedPage({
|
|
193
|
+
context,
|
|
194
|
+
schema,
|
|
195
|
+
cached,
|
|
196
|
+
onGenerate
|
|
197
|
+
}) {
|
|
198
|
+
if (cached) {
|
|
199
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: hydrate(schema, cached) });
|
|
200
|
+
}
|
|
201
|
+
const contents = [];
|
|
202
|
+
searchChildren(schema, contents);
|
|
203
|
+
if (contents.length == 0) return schema;
|
|
204
|
+
const llmInput = generateInput(contents, context);
|
|
205
|
+
const { text: llmResponse } = await ai.generateText({
|
|
206
|
+
model,
|
|
207
|
+
system: prompt_default,
|
|
208
|
+
prompt: llmInput
|
|
209
|
+
});
|
|
210
|
+
const parsedResponse = parseResponse(llmResponse);
|
|
211
|
+
if (onGenerate) {
|
|
212
|
+
onGenerate(parsedResponse);
|
|
213
|
+
}
|
|
214
|
+
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: hydrate(schema, parsedResponse) });
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
// src/index.ts
|
|
219
|
+
var createSyntuxFactory = (config) => {
|
|
220
|
+
return {
|
|
221
|
+
GeneratedPage: createGeneratedPage(config.model),
|
|
222
|
+
GeneratedContent,
|
|
223
|
+
Renderer
|
|
224
|
+
};
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
exports.createSyntuxFactory = createSyntuxFactory;
|
|
228
|
+
//# sourceMappingURL=index.js.map
|
|
229
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/GeneratedContent.tsx","../src/Renderer.tsx","../src/util.ts","../src/prompt.md","../src/GeneratedPage.tsx","../src/index.ts"],"names":["jsx","Fragment","element","isValidElement","generateText"],"mappings":"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","file":"index.js","sourcesContent":["import { ComponentType } from 'react'\r\nimport { SyntuxComponent } from './types';\r\n\r\nexport interface GeneratedContentProps {\r\n values: any;\r\n components?: (SyntuxComponent<any> | string)[];\r\n hint?: string;\r\n}\r\n\r\n/**\r\n * Section of user interface for LLM to generate.\r\n * @param values The values (object, primitive, or array) to be displayed.\r\n * @param components List of allowed components that LLM can use.\r\n * @param hint Additional custom instructions for the LLM.\r\n */\r\nexport function GeneratedContent(props: GeneratedContentProps) {\r\n /**\r\n * This is an empty component.\r\n * It acts as a declarative slot that <GeneratedPage> recognizes\r\n * and replaces with a Renderer during hydration.\r\n */\r\n return <></>;\r\n}\r\nexport const SIGNATURE = Symbol('GeneratedContent');\r\nGeneratedContent.identifier = SIGNATURE;","import { ComponentType } from 'react'\r\n\r\nconst resolvePath = (obj: any, path: string) => {\r\n if(path === '$') return obj;\r\n return path.split('.').reduce((acc, curr) => acc?.[curr], obj)\r\n}\r\n\r\nconst get = (global: any, local: any, path: string) => {\r\n if(path.startsWith(\"$item.\")){\r\n path = path.slice(6)\r\n return resolvePath(local, path);\r\n } else {\r\n if(path === \"$item\") return local;\r\n return resolvePath(global, path);\r\n }\r\n}\r\n\r\nconst resolveProps = (global: any, local: any, props: any) => {\r\n if(!props) return;\r\n if(\"$bind\" in props) return get(global, local, props.$bind); // $bind may be falsy value\r\n Object.keys(props).forEach((key) => {\r\n const val = props[key];\r\n if(typeof val === \"object\"){\r\n props[key] = resolveProps(global, local, val);\r\n }\r\n })\r\n return props;\r\n}\r\n\r\nexport interface SchemaNode {\r\n type?: string;\r\n props?: Record<string, any>;\r\n children?: (SchemaNode | string)[];\r\n source?: string;\r\n template?: SchemaNode;\r\n $bind?: string;\r\n}\r\n\r\nexport interface RendererProps {\r\n schema: SchemaNode | string; // string occurs recursively\r\n global: any;\r\n local?: any;\r\n components: Record<string, ComponentType<any> | string>;\r\n}\r\n\r\nexport function Renderer({\r\n schema, global, local, components\r\n}: RendererProps) {\r\n if(typeof schema === \"string\") return <>{schema}</>;\r\n if(schema.$bind) {\r\n return <>{get(global, local, schema.$bind)}</>\r\n }\r\n\r\n if(schema.type === '__ForEach__' && schema.source && schema.template){\r\n const sourceArr = get(global, local, schema.source);\r\n if(!Array.isArray(sourceArr)) return null;\r\n\r\n return <>\r\n {sourceArr.map((item, index) => {\r\n return <Renderer\r\n key={index}\r\n schema={schema.template!}\r\n global={global}\r\n local={item}\r\n components={components}\r\n />\r\n })}\r\n </>\r\n }\r\n\r\n if(!schema.type) return null;\r\n\r\n const Component = components[schema.type] || schema.type;\r\n return <Component {...resolveProps(global, local, schema.props)}>\r\n {schema.children?.map((item, index) => {\r\n return <Renderer\r\n key={index}\r\n schema={item}\r\n global={global}\r\n local={local}\r\n components={components}\r\n />\r\n })}\r\n </Component>\r\n}\r\n","import { SchemaNode } from \"./Renderer\"\r\n\r\nconst endDelimiter = \"</UISchema>\"\r\nexport function parseResponse(llmResponse: string): SchemaNode[] {\r\n const split = llmResponse.split(/\\<UISchema index=\"\\d+\">/m).slice(1).map(e => e.trim())\r\n const contents = split.map(e => e.slice(0, -endDelimiter.length));\r\n const parsed = contents.map(e => JSON.parse(e))\r\n return parsed\r\n}","<system_persona>\r\nYou are the **UI Schema Generation Engine**, a specialized architect responsible for converting raw data structures into abstract, reusable React Interface Schemas (JSON-DSL).\r\n\r\nYour output is **NOT** code. Your output is a JSON-based Abstract Syntax Tree (AST) that describes the UI structure. The rendering engine will hydrate this schema with data later.\r\n</system_persona>\r\n\r\n<core_philosophy>\r\n1. **Separation of Concerns:** You define the *structure*. You do NOT hardcode *values*.\r\n2. **Strict Adherence:** You may ONLY use components explicitly listed in the `<AllowedComponents>` block of the input. If the block is missing or empty, revert to the <default_component_library>.\r\n3. **Semantic Structure:** Even though you are generating JSON, the resulting UI must be semantically correct (using proper hierarchy, semantic HTML tags, and logical grouping).\r\n4. **Reusability:** Your schema must be valid regardless of the specific values in the data. It must handle list lengths of 0 or 1000 gracefully using the Iterator Protocol.\r\n</core_philosophy>\r\n\r\n<dsl_syntax_rules>\r\nThe output must be a JSON object adhering to this strict recursive interface:\r\n\r\n### 1. The Standard Node\r\nUsed for HTML tags or Custom Components.\r\n```json\r\n{\r\n \"type\": \"div\" | \"h1\" | \"MyCustomComponent\",\r\n \"props\": { \"className\": \"...\", \"customProp\": \"...\" },\r\n \"children\": [] // Array of Nodes or Strings\r\n}\r\n```\r\n\r\n### 2. The Binding Protocol (`$bind`)\r\n\r\n**NEVER** output raw data values (e.g., \"John\", \"john@email.com\") in the schema.\r\nInstead, bind to a path.\r\n\r\n```json\r\n// BAD\r\n{ \"type\": \"span\", \"children\": [\"John\"] }\r\n\r\n// GOOD\r\n{ \"type\": \"span\", \"children\": [{ \"$bind\": \"user.firstName\" }] }\r\n```\r\n\r\nYou have access to exactly **two scopes** at any time:\r\n- **Global Scope (Root)**: Any path **WITHOUT** the `$item` prefix accesses the top-level global data object. This is available at any nesting depth.\r\n - *Example:* `\"$bind\": \"pageTitle\"` (Always looks at `data.pageTitle`)\r\n- **Local Scope (Current Item):** Any path **STARTING WITH** `$item` accesses the immediate object currently being iterated in a loop.\r\n - *Example:* `\"$bind\": \"$item.name\"` (Looks at `name` on the current loop item).\r\n - *Example:* `\"$bind\": \"$item\"` (Renders the current loop item, usually a string).\r\n\r\nIn special cases, you may need to reference a specific, fixed index in an array. To do that, use dot notation to access the index. For instance: `arr.1.property` accesses the `property` property of the 2nd item in `arr`. However, use this conservatively; prefer to use the Iterator Protocol unless it doesn't make sense (e.g., it's a static array).\r\n\r\n**CRITICAL:** Intermediate scopes are not accessible. Inside a nested loop, `$item` refers *only* to the innermost item.\r\n\r\n### 3. The Iterator Protocol (`__ForEach__`)\r\n\r\nIf the data value is an Array, you MUST use this node. Do not manually unroll lists.\r\n\r\n- **Root Arrays**: If the input value is the array itself, use \"source\": \"$\".\r\n- **Nested Arrays**: If the array is a property on the current item, use `\"source\": \"$item.path.to.array\"`.\r\n- **Global Arrays**: If the array is a property on the Global Root, use `\"source\": \"path.to.array\"`.\r\n\r\n```json\r\n{\r\n \"type\": \"__ForEach__\",\r\n \"source\": \"$\" | \"$item.path.to.array\" | \"path.to.array\",\r\n \"template\": {\r\n // This is the shape of a SINGLE item.\r\n // Inside here, use \"$item\" to refer to the current array element.\r\n \"type\": \"li\",\r\n \"children\": [{ \"$bind\": \"$item.name\" }]\r\n }\r\n}\r\n```\r\n\r\n</dsl_syntax_rules>\r\n\r\n<default_component_library>\r\nIf no specific allowed components are provided, you have access to this semantic HTML suite:\r\n\r\n * **Layout:** `div`, `section`, `article`, `main`, `aside`, `header`, `footer`\r\n * **Typography:** `h1`, `h2`, `h3`, `p`, `span`, `strong`, `em`, `blockquote`, `pre`, `code`\r\n * **Lists:** `ul`, `ol`, `li`\r\n * **Interaction:** `button`, `a` (use href prop), `details`, `summary`\r\n * **Form:** `input`, `label`, `textarea`, `select`, `option`\r\n * **Media:** `img`, `figure`, `figcaption`\r\n\r\n</default_component_library>\r\n\r\n<input_processing_rules>\r\nThe user will provide one or more `<GeneratedContent>` blocks.\r\n\r\n1. **Parse `AllowedComponents`:** A comma-separated list.\r\n * Lowercase = Native HTML tags.\r\n * Uppercase = Custom React Components.\r\n2. **Parse `ComponentContext`:** Defines the TypeScript interface for Custom Components.\r\n * *CRITICAL:* You must strictly adhere to the prop names and types defined here. Do not hallucinate props for custom components.\r\n * Components are separated by a comma, in the format `ComponentName [props: { ... }, details: \"...\"]`. The `props` indicate what `props` it must accept, in Typescript format. The `details` is an optional field, and describes what the component does. Use this information in whatever way to improve your generation output. If you encounter a complex type in `props`, look at the input values and make your best guess at what value is the best fit.\r\n3. **Parse `UserContext`:** This is anything the developer believes is relevant for your task. It could describe a specific UI style or the correct way to use a custom component.\r\n * *CRITICAL*: To the best of your ability, respect the developer's wishes. If no UserContext is provided, you should accomplish the task as you see fit, with no constraints.\r\n * *CRITICAL*: This is only relevant to the current <GeneratedContent> block!\r\n3. **Parse `Value`:** The JSON data structure you are building the UI for.\r\n\r\nAdditionally, the user may provide a <PageContext> before all <GeneratedContent> blocks. Think of this as a global UserContext. This is meant to provide additional context and guiding when designing the UI, which you should try to adhere to. If none is provided, accomplish the task as you see fit, with no constraints.\r\n\r\n</input_processing_rules>\r\n\r\n<output_formatting>\r\nFor every `<GeneratedContent>` input block, you must generate exactly one `<UISchema>` output block.\r\nThe order must be preserved.\r\n\r\nInput:\r\n<PageContext></PageContext>\r\n<GeneratedContent> ... </GeneratedContent> (Section 1)\r\n<GeneratedContent> ... </GeneratedContent> (Section 2)\r\n\r\nOutput:\r\n<UISchema index=\"0\"> ...JSON... </UISchema>\r\n<UISchema index=\"1\"> ...JSON... </UISchema>\r\n</output_formatting>\r\n\r\n<examples>\r\n**Input:**\r\n<GeneratedContent>\r\n<AllowedComponents>div,span,Avatar</AllowedComponents>\r\n<ComponentContext>Avatar [props: { url: string }]</ComponentContext>\r\n<UserContext>grouped under one div</UserContext>\r\n<Value>{ authors: [{ name: \"J.K.\", img: \"...\" }, { name: \"Tolkien\", img: \"...\" }] }</Value>\r\n</GeneratedContent>\r\n\r\n**Correct Output:**\r\n<UISchema index=\"0\">\r\n{\r\n \"type\": \"div\",\r\n \"props\": {\r\n \"className\": \"author-list\"\r\n },\r\n \"children\": [\r\n {\r\n \"type\": \"__ForEach__\",\r\n \"source\": \"authors\",\r\n \"template\": {\r\n \"type\": \"div\",\r\n \"props\": {\r\n \"className\": \"author-card\"\r\n },\r\n \"children\": [\r\n {\r\n \"type\": \"Avatar\",\r\n \"props\": {\r\n \"url\": {\r\n \"$bind\": \"$item.img\"\r\n }\r\n }\r\n },\r\n {\r\n \"type\": \"span\",\r\n \"children\": [\r\n {\r\n \"$bind\": \"$item.name\"\r\n }\r\n ]\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n}\r\n</UISchema>\r\n</examples>\r\n\r\n<reasoning_requirements>\r\nBefore generating the JSON, briefly analyze the data structure to identify arrays (requiring `__ForEach__`) and custom component opportunities. Use the mental scratchpad if necessary, but keep the final output strictly within `<UISchema>` tags.\r\n</reasoning_requirements>\r\n\r\n<IMPORTANT>\r\nDo NOT output anything except the UISchema.\r\n</IMPORTANT>","import { isValidElement } from 'react';\r\nimport { GeneratedContentProps, SIGNATURE } from \"./GeneratedContent\";\r\nimport { Renderer, SchemaNode } from \"./Renderer\";\r\nimport { SyntuxComponent, SyntuxElement } from \"./types\";\r\nimport { parseResponse } from \"./util\";\r\nimport { generateText } from \"ai\";\r\nimport systemPrompt from './prompt.md';\r\n\r\nimport { type LanguageModel } from 'ai';\r\n\r\nexport interface GeneratedPageProps {\r\n context?: string;\r\n schema: SyntuxElement;\r\n onGenerate?: (result: SchemaNode[]) => void;\r\n cached?: (SchemaNode | string)[];\r\n}\r\n\r\nfunction extractChildren(element: any) {\r\n if (element?.props?.children) {\r\n let children = element.props.children;\r\n if (!Array.isArray(children)) children = [children];\r\n return children;\r\n }\r\n return [];\r\n}\r\n\r\nfunction searchChildren(element: any, acc: ContentSchema[]) {\r\n const children = extractChildren(element);\r\n\r\n children.forEach((element: SyntuxElement, index: number) => {\r\n if (element?.type.identifier === SIGNATURE) {\r\n const { values, components, hint } = element.props as GeneratedContentProps;\r\n const realComponents: any = []\r\n\r\n if (components) {\r\n components.forEach((comp: string | SyntuxComponent) => {\r\n if (typeof comp === \"string\") {\r\n realComponents.push({\r\n llmName: comp\r\n })\r\n } else {\r\n realComponents.push({\r\n llmName: comp.llmName,\r\n llmContext: comp.llmContext,\r\n userContext: comp.userContext\r\n })\r\n }\r\n })\r\n }\r\n acc.push({\r\n values, components: realComponents, hint: hint || \"\"\r\n })\r\n } else {\r\n searchChildren(element, acc)\r\n }\r\n })\r\n}\r\n\r\nfunction generateInput(content: ContentSchema[], context?: string) {\r\n let str = '';\r\n if (context) {\r\n str = `<PageContext>${context}</PageContext>\\n`;\r\n }\r\n\r\n content.forEach(schema => {\r\n const allowedComponents = schema.components.map(e => e.llmName);\r\n const componentContext: any = []\r\n schema.components.forEach(comp => {\r\n if (comp.llmContext) {\r\n let contextStr;\r\n if (comp.userContext) {\r\n contextStr = `${comp.llmName} [${comp.llmContext}, details: ${comp.userContext}]`\r\n } else {\r\n contextStr = `${comp.llmName} [${comp.llmContext}]`;\r\n }\r\n componentContext.push(contextStr)\r\n }\r\n })\r\n const userContext = schema.hint;\r\n const value = JSON.stringify(schema.values);\r\n\r\n str += `<GeneratedContent>\r\n <AllowedComponents>${allowedComponents.join(',')}</AllowedComponents>\r\n <ComponentContext>${componentContext.join(',')}</ComponentContext>\r\n <UserContext>${userContext}</UserContext>\r\n <Value>${value}</Value>\r\n</GeneratedContent>\\n`\r\n })\r\n\r\n return str;\r\n}\r\n\r\nfunction createComponentRegistry(components: (SyntuxComponent<any> | string)[] | undefined) {\r\n if (!components) return {};\r\n return components.reduce((acc: Record<string, SyntuxComponent<any> | string>, curr: SyntuxComponent<any> | string) => {\r\n if (typeof curr === \"string\") {\r\n acc[curr] = curr;\r\n } else {\r\n if (curr.llmName) {\r\n acc[curr.llmName] = curr;\r\n }\r\n }\r\n return acc;\r\n }, {})\r\n}\r\n\r\nfunction hydrate(schema: SyntuxElement, dsl: (SchemaNode | string)[]) {\r\n let componentIndex = 0;\r\n function swapChildren(element: SyntuxElement) {\r\n const children = extractChildren(element);\r\n\r\n return children.map((child: SyntuxElement, ind: number) => {\r\n if (!isValidElement(child)) return child;\r\n\r\n if (child.type.identifier === SIGNATURE) {\r\n const { values, components, hint } = child.props as GeneratedContentProps;\r\n return <Renderer key={ind} schema={dsl[componentIndex++]} global={values} local={values} components={createComponentRegistry(components)} />\r\n }\r\n\r\n return swapChildren(child);\r\n })\r\n }\r\n\r\n return swapChildren(schema);\r\n}\r\n\r\ninterface ContentSchema {\r\n values: any;\r\n components: { llmContext?: string, userContext?: string, llmName: string }[];\r\n hint: string;\r\n}\r\n\r\nexport const createGeneratedPage = (model: LanguageModel) => {\r\n /**\r\n * Container for content generation. Batches all <GeneratedContent> blocks into one LLM call.\r\n * \r\n * @param context Custom instructions for the LLM about the page, applicable to all components.\r\n * @param schema The structure of the page. Can be a mix of any type of component.\r\n * @param cached User provided React Interface Schema. Will skip schema generation if one is provided.\r\n * @param onGenerate Callback for receiving React Interface Schema after generation, to be used for caching. \r\n */\r\n return async function GeneratedPage({\r\n context, schema, cached, onGenerate\r\n }: GeneratedPageProps) {\r\n if(cached){\r\n return <>{hydrate(schema, cached)}</>\r\n }\r\n\r\n const contents: ContentSchema[] = [];\r\n searchChildren(schema, contents);\r\n\r\n if(contents.length == 0) return schema;\r\n\r\n const llmInput = generateInput(contents, context);\r\n\r\n const { text: llmResponse } = await generateText({\r\n model,\r\n system: systemPrompt,\r\n prompt: llmInput\r\n })\r\n const parsedResponse = parseResponse(llmResponse)\r\n\r\n if(onGenerate){\r\n onGenerate(parsedResponse)\r\n }\r\n \r\n return <>{hydrate(schema, parsedResponse)}</>\r\n }\r\n}","import { LanguageModel } from 'ai';\r\nimport { createGeneratedPage } from './GeneratedPage';\r\nimport { GeneratedContent } from './GeneratedContent';\r\nimport { Renderer } from './Renderer';\r\n\r\nexport { GeneratedContentProps } from './GeneratedContent';\r\nexport { GeneratedPageProps } from './GeneratedPage';\r\nexport {SchemaNode} from './Renderer';\r\n\r\nexport interface SyntuxFactoryConfig {\r\n model: LanguageModel;\r\n}\r\n\r\n\r\nexport const createSyntuxFactory = (config: SyntuxFactoryConfig) => {\r\n return {\r\n GeneratedPage: createGeneratedPage(config.model),\r\n GeneratedContent,\r\n Renderer\r\n }\r\n}"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { isValidElement } from 'react';
|
|
2
|
+
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
3
|
+
import { generateText } from 'ai';
|
|
4
|
+
|
|
5
|
+
// src/GeneratedPage.tsx
|
|
6
|
+
function GeneratedContent(props) {
|
|
7
|
+
return /* @__PURE__ */ jsx(Fragment, {});
|
|
8
|
+
}
|
|
9
|
+
var SIGNATURE = /* @__PURE__ */ Symbol("GeneratedContent");
|
|
10
|
+
GeneratedContent.identifier = SIGNATURE;
|
|
11
|
+
var resolvePath = (obj, path) => {
|
|
12
|
+
if (path === "$") return obj;
|
|
13
|
+
return path.split(".").reduce((acc, curr) => acc == null ? void 0 : acc[curr], obj);
|
|
14
|
+
};
|
|
15
|
+
var get = (global, local, path) => {
|
|
16
|
+
if (path.startsWith("$item.")) {
|
|
17
|
+
path = path.slice(6);
|
|
18
|
+
return resolvePath(local, path);
|
|
19
|
+
} else {
|
|
20
|
+
if (path === "$item") return local;
|
|
21
|
+
return resolvePath(global, path);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
var resolveProps = (global, local, props) => {
|
|
25
|
+
if (!props) return;
|
|
26
|
+
if ("$bind" in props) return get(global, local, props.$bind);
|
|
27
|
+
Object.keys(props).forEach((key) => {
|
|
28
|
+
const val = props[key];
|
|
29
|
+
if (typeof val === "object") {
|
|
30
|
+
props[key] = resolveProps(global, local, val);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return props;
|
|
34
|
+
};
|
|
35
|
+
function Renderer({
|
|
36
|
+
schema,
|
|
37
|
+
global,
|
|
38
|
+
local,
|
|
39
|
+
components
|
|
40
|
+
}) {
|
|
41
|
+
var _a;
|
|
42
|
+
if (typeof schema === "string") return /* @__PURE__ */ jsx(Fragment, { children: schema });
|
|
43
|
+
if (schema.$bind) {
|
|
44
|
+
return /* @__PURE__ */ jsx(Fragment, { children: get(global, local, schema.$bind) });
|
|
45
|
+
}
|
|
46
|
+
if (schema.type === "__ForEach__" && schema.source && schema.template) {
|
|
47
|
+
const sourceArr = get(global, local, schema.source);
|
|
48
|
+
if (!Array.isArray(sourceArr)) return null;
|
|
49
|
+
return /* @__PURE__ */ jsx(Fragment, { children: sourceArr.map((item, index) => {
|
|
50
|
+
return /* @__PURE__ */ jsx(
|
|
51
|
+
Renderer,
|
|
52
|
+
{
|
|
53
|
+
schema: schema.template,
|
|
54
|
+
global,
|
|
55
|
+
local: item,
|
|
56
|
+
components
|
|
57
|
+
},
|
|
58
|
+
index
|
|
59
|
+
);
|
|
60
|
+
}) });
|
|
61
|
+
}
|
|
62
|
+
if (!schema.type) return null;
|
|
63
|
+
const Component = components[schema.type] || schema.type;
|
|
64
|
+
return /* @__PURE__ */ jsx(Component, { ...resolveProps(global, local, schema.props), children: (_a = schema.children) == null ? void 0 : _a.map((item, index) => {
|
|
65
|
+
return /* @__PURE__ */ jsx(
|
|
66
|
+
Renderer,
|
|
67
|
+
{
|
|
68
|
+
schema: item,
|
|
69
|
+
global,
|
|
70
|
+
local,
|
|
71
|
+
components
|
|
72
|
+
},
|
|
73
|
+
index
|
|
74
|
+
);
|
|
75
|
+
}) });
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// src/util.ts
|
|
79
|
+
var endDelimiter = "</UISchema>";
|
|
80
|
+
function parseResponse(llmResponse) {
|
|
81
|
+
const split = llmResponse.split(/\<UISchema index="\d+">/m).slice(1).map((e) => e.trim());
|
|
82
|
+
const contents = split.map((e) => e.slice(0, -endDelimiter.length));
|
|
83
|
+
const parsed = contents.map((e) => JSON.parse(e));
|
|
84
|
+
return parsed;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// src/prompt.md
|
|
88
|
+
var prompt_default = '<system_persona>\r\nYou are the **UI Schema Generation Engine**, a specialized architect responsible for converting raw data structures into abstract, reusable React Interface Schemas (JSON-DSL).\r\n\r\nYour output is **NOT** code. Your output is a JSON-based Abstract Syntax Tree (AST) that describes the UI structure. The rendering engine will hydrate this schema with data later.\r\n</system_persona>\r\n\r\n<core_philosophy>\r\n1. **Separation of Concerns:** You define the *structure*. You do NOT hardcode *values*.\r\n2. **Strict Adherence:** You may ONLY use components explicitly listed in the `<AllowedComponents>` block of the input. If the block is missing or empty, revert to the <default_component_library>.\r\n3. **Semantic Structure:** Even though you are generating JSON, the resulting UI must be semantically correct (using proper hierarchy, semantic HTML tags, and logical grouping).\r\n4. **Reusability:** Your schema must be valid regardless of the specific values in the data. It must handle list lengths of 0 or 1000 gracefully using the Iterator Protocol.\r\n</core_philosophy>\r\n\r\n<dsl_syntax_rules>\r\nThe output must be a JSON object adhering to this strict recursive interface:\r\n\r\n### 1. The Standard Node\r\nUsed for HTML tags or Custom Components.\r\n```json\r\n{\r\n "type": "div" | "h1" | "MyCustomComponent",\r\n "props": { "className": "...", "customProp": "..." },\r\n "children": [] // Array of Nodes or Strings\r\n}\r\n```\r\n\r\n### 2. The Binding Protocol (`$bind`)\r\n\r\n**NEVER** output raw data values (e.g., "John", "john@email.com") in the schema.\r\nInstead, bind to a path.\r\n\r\n```json\r\n// BAD\r\n{ "type": "span", "children": ["John"] }\r\n\r\n// GOOD\r\n{ "type": "span", "children": [{ "$bind": "user.firstName" }] }\r\n```\r\n\r\nYou have access to exactly **two scopes** at any time:\r\n- **Global Scope (Root)**: Any path **WITHOUT** the `$item` prefix accesses the top-level global data object. This is available at any nesting depth.\r\n - *Example:* `"$bind": "pageTitle"` (Always looks at `data.pageTitle`)\r\n- **Local Scope (Current Item):** Any path **STARTING WITH** `$item` accesses the immediate object currently being iterated in a loop.\r\n - *Example:* `"$bind": "$item.name"` (Looks at `name` on the current loop item).\r\n - *Example:* `"$bind": "$item"` (Renders the current loop item, usually a string).\r\n\r\nIn special cases, you may need to reference a specific, fixed index in an array. To do that, use dot notation to access the index. For instance: `arr.1.property` accesses the `property` property of the 2nd item in `arr`. However, use this conservatively; prefer to use the Iterator Protocol unless it doesn\'t make sense (e.g., it\'s a static array).\r\n\r\n**CRITICAL:** Intermediate scopes are not accessible. Inside a nested loop, `$item` refers *only* to the innermost item.\r\n\r\n### 3. The Iterator Protocol (`__ForEach__`)\r\n\r\nIf the data value is an Array, you MUST use this node. Do not manually unroll lists.\r\n\r\n- **Root Arrays**: If the input value is the array itself, use "source": "$".\r\n- **Nested Arrays**: If the array is a property on the current item, use `"source": "$item.path.to.array"`.\r\n- **Global Arrays**: If the array is a property on the Global Root, use `"source": "path.to.array"`.\r\n\r\n```json\r\n{\r\n "type": "__ForEach__",\r\n "source": "$" | "$item.path.to.array" | "path.to.array",\r\n "template": {\r\n // This is the shape of a SINGLE item.\r\n // Inside here, use "$item" to refer to the current array element.\r\n "type": "li",\r\n "children": [{ "$bind": "$item.name" }]\r\n }\r\n}\r\n```\r\n\r\n</dsl_syntax_rules>\r\n\r\n<default_component_library>\r\nIf no specific allowed components are provided, you have access to this semantic HTML suite:\r\n\r\n * **Layout:** `div`, `section`, `article`, `main`, `aside`, `header`, `footer`\r\n * **Typography:** `h1`, `h2`, `h3`, `p`, `span`, `strong`, `em`, `blockquote`, `pre`, `code`\r\n * **Lists:** `ul`, `ol`, `li`\r\n * **Interaction:** `button`, `a` (use href prop), `details`, `summary`\r\n * **Form:** `input`, `label`, `textarea`, `select`, `option`\r\n * **Media:** `img`, `figure`, `figcaption`\r\n\r\n</default_component_library>\r\n\r\n<input_processing_rules>\r\nThe user will provide one or more `<GeneratedContent>` blocks.\r\n\r\n1. **Parse `AllowedComponents`:** A comma-separated list.\r\n * Lowercase = Native HTML tags.\r\n * Uppercase = Custom React Components.\r\n2. **Parse `ComponentContext`:** Defines the TypeScript interface for Custom Components.\r\n * *CRITICAL:* You must strictly adhere to the prop names and types defined here. Do not hallucinate props for custom components.\r\n * Components are separated by a comma, in the format `ComponentName [props: { ... }, details: "..."]`. The `props` indicate what `props` it must accept, in Typescript format. The `details` is an optional field, and describes what the component does. Use this information in whatever way to improve your generation output. If you encounter a complex type in `props`, look at the input values and make your best guess at what value is the best fit.\r\n3. **Parse `UserContext`:** This is anything the developer believes is relevant for your task. It could describe a specific UI style or the correct way to use a custom component.\r\n * *CRITICAL*: To the best of your ability, respect the developer\'s wishes. If no UserContext is provided, you should accomplish the task as you see fit, with no constraints.\r\n * *CRITICAL*: This is only relevant to the current <GeneratedContent> block!\r\n3. **Parse `Value`:** The JSON data structure you are building the UI for.\r\n\r\nAdditionally, the user may provide a <PageContext> before all <GeneratedContent> blocks. Think of this as a global UserContext. This is meant to provide additional context and guiding when designing the UI, which you should try to adhere to. If none is provided, accomplish the task as you see fit, with no constraints.\r\n\r\n</input_processing_rules>\r\n\r\n<output_formatting>\r\nFor every `<GeneratedContent>` input block, you must generate exactly one `<UISchema>` output block.\r\nThe order must be preserved.\r\n\r\nInput:\r\n<PageContext></PageContext>\r\n<GeneratedContent> ... </GeneratedContent> (Section 1)\r\n<GeneratedContent> ... </GeneratedContent> (Section 2)\r\n\r\nOutput:\r\n<UISchema index="0"> ...JSON... </UISchema>\r\n<UISchema index="1"> ...JSON... </UISchema>\r\n</output_formatting>\r\n\r\n<examples>\r\n**Input:**\r\n<GeneratedContent>\r\n<AllowedComponents>div,span,Avatar</AllowedComponents>\r\n<ComponentContext>Avatar [props: { url: string }]</ComponentContext>\r\n<UserContext>grouped under one div</UserContext>\r\n<Value>{ authors: [{ name: "J.K.", img: "..." }, { name: "Tolkien", img: "..." }] }</Value>\r\n</GeneratedContent>\r\n\r\n**Correct Output:**\r\n<UISchema index="0">\r\n{\r\n "type": "div",\r\n "props": {\r\n "className": "author-list"\r\n },\r\n "children": [\r\n {\r\n "type": "__ForEach__",\r\n "source": "authors",\r\n "template": {\r\n "type": "div",\r\n "props": {\r\n "className": "author-card"\r\n },\r\n "children": [\r\n {\r\n "type": "Avatar",\r\n "props": {\r\n "url": {\r\n "$bind": "$item.img"\r\n }\r\n }\r\n },\r\n {\r\n "type": "span",\r\n "children": [\r\n {\r\n "$bind": "$item.name"\r\n }\r\n ]\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n}\r\n</UISchema>\r\n</examples>\r\n\r\n<reasoning_requirements>\r\nBefore generating the JSON, briefly analyze the data structure to identify arrays (requiring `__ForEach__`) and custom component opportunities. Use the mental scratchpad if necessary, but keep the final output strictly within `<UISchema>` tags.\r\n</reasoning_requirements>\r\n\r\n<IMPORTANT>\r\nDo NOT output anything except the UISchema.\r\n</IMPORTANT>';
|
|
89
|
+
function extractChildren(element) {
|
|
90
|
+
var _a;
|
|
91
|
+
if ((_a = element == null ? void 0 : element.props) == null ? void 0 : _a.children) {
|
|
92
|
+
let children = element.props.children;
|
|
93
|
+
if (!Array.isArray(children)) children = [children];
|
|
94
|
+
return children;
|
|
95
|
+
}
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
function searchChildren(element, acc) {
|
|
99
|
+
const children = extractChildren(element);
|
|
100
|
+
children.forEach((element2, index) => {
|
|
101
|
+
if ((element2 == null ? void 0 : element2.type.identifier) === SIGNATURE) {
|
|
102
|
+
const { values, components, hint } = element2.props;
|
|
103
|
+
const realComponents = [];
|
|
104
|
+
if (components) {
|
|
105
|
+
components.forEach((comp) => {
|
|
106
|
+
if (typeof comp === "string") {
|
|
107
|
+
realComponents.push({
|
|
108
|
+
llmName: comp
|
|
109
|
+
});
|
|
110
|
+
} else {
|
|
111
|
+
realComponents.push({
|
|
112
|
+
llmName: comp.llmName,
|
|
113
|
+
llmContext: comp.llmContext,
|
|
114
|
+
userContext: comp.userContext
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
acc.push({
|
|
120
|
+
values,
|
|
121
|
+
components: realComponents,
|
|
122
|
+
hint: hint || ""
|
|
123
|
+
});
|
|
124
|
+
} else {
|
|
125
|
+
searchChildren(element2, acc);
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
function generateInput(content, context) {
|
|
130
|
+
let str = "";
|
|
131
|
+
if (context) {
|
|
132
|
+
str = `<PageContext>${context}</PageContext>
|
|
133
|
+
`;
|
|
134
|
+
}
|
|
135
|
+
content.forEach((schema) => {
|
|
136
|
+
const allowedComponents = schema.components.map((e) => e.llmName);
|
|
137
|
+
const componentContext = [];
|
|
138
|
+
schema.components.forEach((comp) => {
|
|
139
|
+
if (comp.llmContext) {
|
|
140
|
+
let contextStr;
|
|
141
|
+
if (comp.userContext) {
|
|
142
|
+
contextStr = `${comp.llmName} [${comp.llmContext}, details: ${comp.userContext}]`;
|
|
143
|
+
} else {
|
|
144
|
+
contextStr = `${comp.llmName} [${comp.llmContext}]`;
|
|
145
|
+
}
|
|
146
|
+
componentContext.push(contextStr);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
const userContext = schema.hint;
|
|
150
|
+
const value = JSON.stringify(schema.values);
|
|
151
|
+
str += `<GeneratedContent>
|
|
152
|
+
<AllowedComponents>${allowedComponents.join(",")}</AllowedComponents>
|
|
153
|
+
<ComponentContext>${componentContext.join(",")}</ComponentContext>
|
|
154
|
+
<UserContext>${userContext}</UserContext>
|
|
155
|
+
<Value>${value}</Value>
|
|
156
|
+
</GeneratedContent>
|
|
157
|
+
`;
|
|
158
|
+
});
|
|
159
|
+
return str;
|
|
160
|
+
}
|
|
161
|
+
function createComponentRegistry(components) {
|
|
162
|
+
if (!components) return {};
|
|
163
|
+
return components.reduce((acc, curr) => {
|
|
164
|
+
if (typeof curr === "string") {
|
|
165
|
+
acc[curr] = curr;
|
|
166
|
+
} else {
|
|
167
|
+
if (curr.llmName) {
|
|
168
|
+
acc[curr.llmName] = curr;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return acc;
|
|
172
|
+
}, {});
|
|
173
|
+
}
|
|
174
|
+
function hydrate(schema, dsl) {
|
|
175
|
+
let componentIndex = 0;
|
|
176
|
+
function swapChildren(element) {
|
|
177
|
+
const children = extractChildren(element);
|
|
178
|
+
return children.map((child, ind) => {
|
|
179
|
+
if (!isValidElement(child)) return child;
|
|
180
|
+
if (child.type.identifier === SIGNATURE) {
|
|
181
|
+
const { values, components, hint } = child.props;
|
|
182
|
+
return /* @__PURE__ */ jsx(Renderer, { schema: dsl[componentIndex++], global: values, local: values, components: createComponentRegistry(components) }, ind);
|
|
183
|
+
}
|
|
184
|
+
return swapChildren(child);
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
return swapChildren(schema);
|
|
188
|
+
}
|
|
189
|
+
var createGeneratedPage = (model) => {
|
|
190
|
+
return async function GeneratedPage({
|
|
191
|
+
context,
|
|
192
|
+
schema,
|
|
193
|
+
cached,
|
|
194
|
+
onGenerate
|
|
195
|
+
}) {
|
|
196
|
+
if (cached) {
|
|
197
|
+
return /* @__PURE__ */ jsx(Fragment, { children: hydrate(schema, cached) });
|
|
198
|
+
}
|
|
199
|
+
const contents = [];
|
|
200
|
+
searchChildren(schema, contents);
|
|
201
|
+
if (contents.length == 0) return schema;
|
|
202
|
+
const llmInput = generateInput(contents, context);
|
|
203
|
+
const { text: llmResponse } = await generateText({
|
|
204
|
+
model,
|
|
205
|
+
system: prompt_default,
|
|
206
|
+
prompt: llmInput
|
|
207
|
+
});
|
|
208
|
+
const parsedResponse = parseResponse(llmResponse);
|
|
209
|
+
if (onGenerate) {
|
|
210
|
+
onGenerate(parsedResponse);
|
|
211
|
+
}
|
|
212
|
+
return /* @__PURE__ */ jsx(Fragment, { children: hydrate(schema, parsedResponse) });
|
|
213
|
+
};
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
// src/index.ts
|
|
217
|
+
var createSyntuxFactory = (config) => {
|
|
218
|
+
return {
|
|
219
|
+
GeneratedPage: createGeneratedPage(config.model),
|
|
220
|
+
GeneratedContent,
|
|
221
|
+
Renderer
|
|
222
|
+
};
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
export { createSyntuxFactory };
|
|
226
|
+
//# sourceMappingURL=index.mjs.map
|
|
227
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/GeneratedContent.tsx","../src/Renderer.tsx","../src/util.ts","../src/prompt.md","../src/GeneratedPage.tsx","../src/index.ts"],"names":["jsx","Fragment","element"],"mappings":"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","file":"index.mjs","sourcesContent":["import { ComponentType } from 'react'\r\nimport { SyntuxComponent } from './types';\r\n\r\nexport interface GeneratedContentProps {\r\n values: any;\r\n components?: (SyntuxComponent<any> | string)[];\r\n hint?: string;\r\n}\r\n\r\n/**\r\n * Section of user interface for LLM to generate.\r\n * @param values The values (object, primitive, or array) to be displayed.\r\n * @param components List of allowed components that LLM can use.\r\n * @param hint Additional custom instructions for the LLM.\r\n */\r\nexport function GeneratedContent(props: GeneratedContentProps) {\r\n /**\r\n * This is an empty component.\r\n * It acts as a declarative slot that <GeneratedPage> recognizes\r\n * and replaces with a Renderer during hydration.\r\n */\r\n return <></>;\r\n}\r\nexport const SIGNATURE = Symbol('GeneratedContent');\r\nGeneratedContent.identifier = SIGNATURE;","import { ComponentType } from 'react'\r\n\r\nconst resolvePath = (obj: any, path: string) => {\r\n if(path === '$') return obj;\r\n return path.split('.').reduce((acc, curr) => acc?.[curr], obj)\r\n}\r\n\r\nconst get = (global: any, local: any, path: string) => {\r\n if(path.startsWith(\"$item.\")){\r\n path = path.slice(6)\r\n return resolvePath(local, path);\r\n } else {\r\n if(path === \"$item\") return local;\r\n return resolvePath(global, path);\r\n }\r\n}\r\n\r\nconst resolveProps = (global: any, local: any, props: any) => {\r\n if(!props) return;\r\n if(\"$bind\" in props) return get(global, local, props.$bind); // $bind may be falsy value\r\n Object.keys(props).forEach((key) => {\r\n const val = props[key];\r\n if(typeof val === \"object\"){\r\n props[key] = resolveProps(global, local, val);\r\n }\r\n })\r\n return props;\r\n}\r\n\r\nexport interface SchemaNode {\r\n type?: string;\r\n props?: Record<string, any>;\r\n children?: (SchemaNode | string)[];\r\n source?: string;\r\n template?: SchemaNode;\r\n $bind?: string;\r\n}\r\n\r\nexport interface RendererProps {\r\n schema: SchemaNode | string; // string occurs recursively\r\n global: any;\r\n local?: any;\r\n components: Record<string, ComponentType<any> | string>;\r\n}\r\n\r\nexport function Renderer({\r\n schema, global, local, components\r\n}: RendererProps) {\r\n if(typeof schema === \"string\") return <>{schema}</>;\r\n if(schema.$bind) {\r\n return <>{get(global, local, schema.$bind)}</>\r\n }\r\n\r\n if(schema.type === '__ForEach__' && schema.source && schema.template){\r\n const sourceArr = get(global, local, schema.source);\r\n if(!Array.isArray(sourceArr)) return null;\r\n\r\n return <>\r\n {sourceArr.map((item, index) => {\r\n return <Renderer\r\n key={index}\r\n schema={schema.template!}\r\n global={global}\r\n local={item}\r\n components={components}\r\n />\r\n })}\r\n </>\r\n }\r\n\r\n if(!schema.type) return null;\r\n\r\n const Component = components[schema.type] || schema.type;\r\n return <Component {...resolveProps(global, local, schema.props)}>\r\n {schema.children?.map((item, index) => {\r\n return <Renderer\r\n key={index}\r\n schema={item}\r\n global={global}\r\n local={local}\r\n components={components}\r\n />\r\n })}\r\n </Component>\r\n}\r\n","import { SchemaNode } from \"./Renderer\"\r\n\r\nconst endDelimiter = \"</UISchema>\"\r\nexport function parseResponse(llmResponse: string): SchemaNode[] {\r\n const split = llmResponse.split(/\\<UISchema index=\"\\d+\">/m).slice(1).map(e => e.trim())\r\n const contents = split.map(e => e.slice(0, -endDelimiter.length));\r\n const parsed = contents.map(e => JSON.parse(e))\r\n return parsed\r\n}","<system_persona>\r\nYou are the **UI Schema Generation Engine**, a specialized architect responsible for converting raw data structures into abstract, reusable React Interface Schemas (JSON-DSL).\r\n\r\nYour output is **NOT** code. Your output is a JSON-based Abstract Syntax Tree (AST) that describes the UI structure. The rendering engine will hydrate this schema with data later.\r\n</system_persona>\r\n\r\n<core_philosophy>\r\n1. **Separation of Concerns:** You define the *structure*. You do NOT hardcode *values*.\r\n2. **Strict Adherence:** You may ONLY use components explicitly listed in the `<AllowedComponents>` block of the input. If the block is missing or empty, revert to the <default_component_library>.\r\n3. **Semantic Structure:** Even though you are generating JSON, the resulting UI must be semantically correct (using proper hierarchy, semantic HTML tags, and logical grouping).\r\n4. **Reusability:** Your schema must be valid regardless of the specific values in the data. It must handle list lengths of 0 or 1000 gracefully using the Iterator Protocol.\r\n</core_philosophy>\r\n\r\n<dsl_syntax_rules>\r\nThe output must be a JSON object adhering to this strict recursive interface:\r\n\r\n### 1. The Standard Node\r\nUsed for HTML tags or Custom Components.\r\n```json\r\n{\r\n \"type\": \"div\" | \"h1\" | \"MyCustomComponent\",\r\n \"props\": { \"className\": \"...\", \"customProp\": \"...\" },\r\n \"children\": [] // Array of Nodes or Strings\r\n}\r\n```\r\n\r\n### 2. The Binding Protocol (`$bind`)\r\n\r\n**NEVER** output raw data values (e.g., \"John\", \"john@email.com\") in the schema.\r\nInstead, bind to a path.\r\n\r\n```json\r\n// BAD\r\n{ \"type\": \"span\", \"children\": [\"John\"] }\r\n\r\n// GOOD\r\n{ \"type\": \"span\", \"children\": [{ \"$bind\": \"user.firstName\" }] }\r\n```\r\n\r\nYou have access to exactly **two scopes** at any time:\r\n- **Global Scope (Root)**: Any path **WITHOUT** the `$item` prefix accesses the top-level global data object. This is available at any nesting depth.\r\n - *Example:* `\"$bind\": \"pageTitle\"` (Always looks at `data.pageTitle`)\r\n- **Local Scope (Current Item):** Any path **STARTING WITH** `$item` accesses the immediate object currently being iterated in a loop.\r\n - *Example:* `\"$bind\": \"$item.name\"` (Looks at `name` on the current loop item).\r\n - *Example:* `\"$bind\": \"$item\"` (Renders the current loop item, usually a string).\r\n\r\nIn special cases, you may need to reference a specific, fixed index in an array. To do that, use dot notation to access the index. For instance: `arr.1.property` accesses the `property` property of the 2nd item in `arr`. However, use this conservatively; prefer to use the Iterator Protocol unless it doesn't make sense (e.g., it's a static array).\r\n\r\n**CRITICAL:** Intermediate scopes are not accessible. Inside a nested loop, `$item` refers *only* to the innermost item.\r\n\r\n### 3. The Iterator Protocol (`__ForEach__`)\r\n\r\nIf the data value is an Array, you MUST use this node. Do not manually unroll lists.\r\n\r\n- **Root Arrays**: If the input value is the array itself, use \"source\": \"$\".\r\n- **Nested Arrays**: If the array is a property on the current item, use `\"source\": \"$item.path.to.array\"`.\r\n- **Global Arrays**: If the array is a property on the Global Root, use `\"source\": \"path.to.array\"`.\r\n\r\n```json\r\n{\r\n \"type\": \"__ForEach__\",\r\n \"source\": \"$\" | \"$item.path.to.array\" | \"path.to.array\",\r\n \"template\": {\r\n // This is the shape of a SINGLE item.\r\n // Inside here, use \"$item\" to refer to the current array element.\r\n \"type\": \"li\",\r\n \"children\": [{ \"$bind\": \"$item.name\" }]\r\n }\r\n}\r\n```\r\n\r\n</dsl_syntax_rules>\r\n\r\n<default_component_library>\r\nIf no specific allowed components are provided, you have access to this semantic HTML suite:\r\n\r\n * **Layout:** `div`, `section`, `article`, `main`, `aside`, `header`, `footer`\r\n * **Typography:** `h1`, `h2`, `h3`, `p`, `span`, `strong`, `em`, `blockquote`, `pre`, `code`\r\n * **Lists:** `ul`, `ol`, `li`\r\n * **Interaction:** `button`, `a` (use href prop), `details`, `summary`\r\n * **Form:** `input`, `label`, `textarea`, `select`, `option`\r\n * **Media:** `img`, `figure`, `figcaption`\r\n\r\n</default_component_library>\r\n\r\n<input_processing_rules>\r\nThe user will provide one or more `<GeneratedContent>` blocks.\r\n\r\n1. **Parse `AllowedComponents`:** A comma-separated list.\r\n * Lowercase = Native HTML tags.\r\n * Uppercase = Custom React Components.\r\n2. **Parse `ComponentContext`:** Defines the TypeScript interface for Custom Components.\r\n * *CRITICAL:* You must strictly adhere to the prop names and types defined here. Do not hallucinate props for custom components.\r\n * Components are separated by a comma, in the format `ComponentName [props: { ... }, details: \"...\"]`. The `props` indicate what `props` it must accept, in Typescript format. The `details` is an optional field, and describes what the component does. Use this information in whatever way to improve your generation output. If you encounter a complex type in `props`, look at the input values and make your best guess at what value is the best fit.\r\n3. **Parse `UserContext`:** This is anything the developer believes is relevant for your task. It could describe a specific UI style or the correct way to use a custom component.\r\n * *CRITICAL*: To the best of your ability, respect the developer's wishes. If no UserContext is provided, you should accomplish the task as you see fit, with no constraints.\r\n * *CRITICAL*: This is only relevant to the current <GeneratedContent> block!\r\n3. **Parse `Value`:** The JSON data structure you are building the UI for.\r\n\r\nAdditionally, the user may provide a <PageContext> before all <GeneratedContent> blocks. Think of this as a global UserContext. This is meant to provide additional context and guiding when designing the UI, which you should try to adhere to. If none is provided, accomplish the task as you see fit, with no constraints.\r\n\r\n</input_processing_rules>\r\n\r\n<output_formatting>\r\nFor every `<GeneratedContent>` input block, you must generate exactly one `<UISchema>` output block.\r\nThe order must be preserved.\r\n\r\nInput:\r\n<PageContext></PageContext>\r\n<GeneratedContent> ... </GeneratedContent> (Section 1)\r\n<GeneratedContent> ... </GeneratedContent> (Section 2)\r\n\r\nOutput:\r\n<UISchema index=\"0\"> ...JSON... </UISchema>\r\n<UISchema index=\"1\"> ...JSON... </UISchema>\r\n</output_formatting>\r\n\r\n<examples>\r\n**Input:**\r\n<GeneratedContent>\r\n<AllowedComponents>div,span,Avatar</AllowedComponents>\r\n<ComponentContext>Avatar [props: { url: string }]</ComponentContext>\r\n<UserContext>grouped under one div</UserContext>\r\n<Value>{ authors: [{ name: \"J.K.\", img: \"...\" }, { name: \"Tolkien\", img: \"...\" }] }</Value>\r\n</GeneratedContent>\r\n\r\n**Correct Output:**\r\n<UISchema index=\"0\">\r\n{\r\n \"type\": \"div\",\r\n \"props\": {\r\n \"className\": \"author-list\"\r\n },\r\n \"children\": [\r\n {\r\n \"type\": \"__ForEach__\",\r\n \"source\": \"authors\",\r\n \"template\": {\r\n \"type\": \"div\",\r\n \"props\": {\r\n \"className\": \"author-card\"\r\n },\r\n \"children\": [\r\n {\r\n \"type\": \"Avatar\",\r\n \"props\": {\r\n \"url\": {\r\n \"$bind\": \"$item.img\"\r\n }\r\n }\r\n },\r\n {\r\n \"type\": \"span\",\r\n \"children\": [\r\n {\r\n \"$bind\": \"$item.name\"\r\n }\r\n ]\r\n }\r\n ]\r\n }\r\n }\r\n ]\r\n}\r\n</UISchema>\r\n</examples>\r\n\r\n<reasoning_requirements>\r\nBefore generating the JSON, briefly analyze the data structure to identify arrays (requiring `__ForEach__`) and custom component opportunities. Use the mental scratchpad if necessary, but keep the final output strictly within `<UISchema>` tags.\r\n</reasoning_requirements>\r\n\r\n<IMPORTANT>\r\nDo NOT output anything except the UISchema.\r\n</IMPORTANT>","import { isValidElement } from 'react';\r\nimport { GeneratedContentProps, SIGNATURE } from \"./GeneratedContent\";\r\nimport { Renderer, SchemaNode } from \"./Renderer\";\r\nimport { SyntuxComponent, SyntuxElement } from \"./types\";\r\nimport { parseResponse } from \"./util\";\r\nimport { generateText } from \"ai\";\r\nimport systemPrompt from './prompt.md';\r\n\r\nimport { type LanguageModel } from 'ai';\r\n\r\nexport interface GeneratedPageProps {\r\n context?: string;\r\n schema: SyntuxElement;\r\n onGenerate?: (result: SchemaNode[]) => void;\r\n cached?: (SchemaNode | string)[];\r\n}\r\n\r\nfunction extractChildren(element: any) {\r\n if (element?.props?.children) {\r\n let children = element.props.children;\r\n if (!Array.isArray(children)) children = [children];\r\n return children;\r\n }\r\n return [];\r\n}\r\n\r\nfunction searchChildren(element: any, acc: ContentSchema[]) {\r\n const children = extractChildren(element);\r\n\r\n children.forEach((element: SyntuxElement, index: number) => {\r\n if (element?.type.identifier === SIGNATURE) {\r\n const { values, components, hint } = element.props as GeneratedContentProps;\r\n const realComponents: any = []\r\n\r\n if (components) {\r\n components.forEach((comp: string | SyntuxComponent) => {\r\n if (typeof comp === \"string\") {\r\n realComponents.push({\r\n llmName: comp\r\n })\r\n } else {\r\n realComponents.push({\r\n llmName: comp.llmName,\r\n llmContext: comp.llmContext,\r\n userContext: comp.userContext\r\n })\r\n }\r\n })\r\n }\r\n acc.push({\r\n values, components: realComponents, hint: hint || \"\"\r\n })\r\n } else {\r\n searchChildren(element, acc)\r\n }\r\n })\r\n}\r\n\r\nfunction generateInput(content: ContentSchema[], context?: string) {\r\n let str = '';\r\n if (context) {\r\n str = `<PageContext>${context}</PageContext>\\n`;\r\n }\r\n\r\n content.forEach(schema => {\r\n const allowedComponents = schema.components.map(e => e.llmName);\r\n const componentContext: any = []\r\n schema.components.forEach(comp => {\r\n if (comp.llmContext) {\r\n let contextStr;\r\n if (comp.userContext) {\r\n contextStr = `${comp.llmName} [${comp.llmContext}, details: ${comp.userContext}]`\r\n } else {\r\n contextStr = `${comp.llmName} [${comp.llmContext}]`;\r\n }\r\n componentContext.push(contextStr)\r\n }\r\n })\r\n const userContext = schema.hint;\r\n const value = JSON.stringify(schema.values);\r\n\r\n str += `<GeneratedContent>\r\n <AllowedComponents>${allowedComponents.join(',')}</AllowedComponents>\r\n <ComponentContext>${componentContext.join(',')}</ComponentContext>\r\n <UserContext>${userContext}</UserContext>\r\n <Value>${value}</Value>\r\n</GeneratedContent>\\n`\r\n })\r\n\r\n return str;\r\n}\r\n\r\nfunction createComponentRegistry(components: (SyntuxComponent<any> | string)[] | undefined) {\r\n if (!components) return {};\r\n return components.reduce((acc: Record<string, SyntuxComponent<any> | string>, curr: SyntuxComponent<any> | string) => {\r\n if (typeof curr === \"string\") {\r\n acc[curr] = curr;\r\n } else {\r\n if (curr.llmName) {\r\n acc[curr.llmName] = curr;\r\n }\r\n }\r\n return acc;\r\n }, {})\r\n}\r\n\r\nfunction hydrate(schema: SyntuxElement, dsl: (SchemaNode | string)[]) {\r\n let componentIndex = 0;\r\n function swapChildren(element: SyntuxElement) {\r\n const children = extractChildren(element);\r\n\r\n return children.map((child: SyntuxElement, ind: number) => {\r\n if (!isValidElement(child)) return child;\r\n\r\n if (child.type.identifier === SIGNATURE) {\r\n const { values, components, hint } = child.props as GeneratedContentProps;\r\n return <Renderer key={ind} schema={dsl[componentIndex++]} global={values} local={values} components={createComponentRegistry(components)} />\r\n }\r\n\r\n return swapChildren(child);\r\n })\r\n }\r\n\r\n return swapChildren(schema);\r\n}\r\n\r\ninterface ContentSchema {\r\n values: any;\r\n components: { llmContext?: string, userContext?: string, llmName: string }[];\r\n hint: string;\r\n}\r\n\r\nexport const createGeneratedPage = (model: LanguageModel) => {\r\n /**\r\n * Container for content generation. Batches all <GeneratedContent> blocks into one LLM call.\r\n * \r\n * @param context Custom instructions for the LLM about the page, applicable to all components.\r\n * @param schema The structure of the page. Can be a mix of any type of component.\r\n * @param cached User provided React Interface Schema. Will skip schema generation if one is provided.\r\n * @param onGenerate Callback for receiving React Interface Schema after generation, to be used for caching. \r\n */\r\n return async function GeneratedPage({\r\n context, schema, cached, onGenerate\r\n }: GeneratedPageProps) {\r\n if(cached){\r\n return <>{hydrate(schema, cached)}</>\r\n }\r\n\r\n const contents: ContentSchema[] = [];\r\n searchChildren(schema, contents);\r\n\r\n if(contents.length == 0) return schema;\r\n\r\n const llmInput = generateInput(contents, context);\r\n\r\n const { text: llmResponse } = await generateText({\r\n model,\r\n system: systemPrompt,\r\n prompt: llmInput\r\n })\r\n const parsedResponse = parseResponse(llmResponse)\r\n\r\n if(onGenerate){\r\n onGenerate(parsedResponse)\r\n }\r\n \r\n return <>{hydrate(schema, parsedResponse)}</>\r\n }\r\n}","import { LanguageModel } from 'ai';\r\nimport { createGeneratedPage } from './GeneratedPage';\r\nimport { GeneratedContent } from './GeneratedContent';\r\nimport { Renderer } from './Renderer';\r\n\r\nexport { GeneratedContentProps } from './GeneratedContent';\r\nexport { GeneratedPageProps } from './GeneratedPage';\r\nexport {SchemaNode} from './Renderer';\r\n\r\nexport interface SyntuxFactoryConfig {\r\n model: LanguageModel;\r\n}\r\n\r\n\r\nexport const createSyntuxFactory = (config: SyntuxFactoryConfig) => {\r\n return {\r\n GeneratedPage: createGeneratedPage(config.model),\r\n GeneratedContent,\r\n Renderer\r\n }\r\n}"]}
|
package/dist/plugin.d.ts
ADDED
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
5
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
// src/plugin.ts
|
|
9
|
+
var require_plugin = __commonJS({
|
|
10
|
+
"src/plugin.ts"(exports$1, module) {
|
|
11
|
+
module.exports = function({ types: t }) {
|
|
12
|
+
function extractProps(state, params) {
|
|
13
|
+
let signature = "props: ( empty )";
|
|
14
|
+
if (params.length > 0) {
|
|
15
|
+
const start = params[0].start;
|
|
16
|
+
const end = params[params.length - 1].end;
|
|
17
|
+
signature = `props: (${state.file.code.slice(start, end)})`;
|
|
18
|
+
}
|
|
19
|
+
return signature;
|
|
20
|
+
}
|
|
21
|
+
function contextAssignment(name, signature) {
|
|
22
|
+
return t.expressionStatement(
|
|
23
|
+
t.assignmentExpression(
|
|
24
|
+
"=",
|
|
25
|
+
t.memberExpression(t.identifier(name), t.identifier("llmContext")),
|
|
26
|
+
t.stringLiteral(signature)
|
|
27
|
+
)
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
function nameAssignment(name) {
|
|
31
|
+
return t.expressionStatement(
|
|
32
|
+
t.assignmentExpression(
|
|
33
|
+
"=",
|
|
34
|
+
t.memberExpression(t.identifier(name), t.identifier("llmName")),
|
|
35
|
+
t.stringLiteral(name)
|
|
36
|
+
)
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
visitor: {
|
|
41
|
+
/**
|
|
42
|
+
* functional components.
|
|
43
|
+
*/
|
|
44
|
+
FunctionDeclaration(path, state) {
|
|
45
|
+
const { node } = path;
|
|
46
|
+
if (!node.id) return;
|
|
47
|
+
const name = node.id.name;
|
|
48
|
+
if (!/^[A-Z]/.test(name)) return;
|
|
49
|
+
const params = node.params;
|
|
50
|
+
const props = extractProps(state, params);
|
|
51
|
+
path.insertAfter([contextAssignment(name, props), nameAssignment(name)]);
|
|
52
|
+
},
|
|
53
|
+
/**
|
|
54
|
+
* arrow function components.
|
|
55
|
+
*/
|
|
56
|
+
VariableDeclarator(path, state) {
|
|
57
|
+
const { node } = path;
|
|
58
|
+
if (!t.isIdentifier(node.id)) return;
|
|
59
|
+
const name = node.id.name;
|
|
60
|
+
if (!/^[A-Z]/.test(name)) return;
|
|
61
|
+
if (!t.isArrowFunctionExpression(node.init) && !t.isFunctionExpression(node.init)) return;
|
|
62
|
+
const params = node.init.params;
|
|
63
|
+
const props = extractProps(state, params);
|
|
64
|
+
path.parentPath.insertAfter([contextAssignment(name, props), nameAssignment(name)]);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
var plugin = require_plugin();
|
|
72
|
+
|
|
73
|
+
module.exports = plugin;
|
|
74
|
+
//# sourceMappingURL=plugin.js.map
|
|
75
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts"],"names":["exports"],"mappings":"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","file":"plugin.js","sourcesContent":["module.exports = function ({ types: t }) {\r\n // pulls props list verbatim from file for maximum context\r\n function extractProps(state, params) {\r\n let signature = \"props: ( empty )\";\r\n \r\n if (params.length > 0) {\r\n const start = params[0].start;\r\n const end = params[params.length - 1].end;\r\n signature = `props: (${state.file.code.slice(start, end)})`;\r\n }\r\n \r\n return signature;\r\n }\r\n \r\n // create expression name.llmContext = signature\r\n function contextAssignment(name, signature) {\r\n return t.expressionStatement(\r\n t.assignmentExpression(\r\n \"=\",\r\n t.memberExpression(t.identifier(name), t.identifier(\"llmContext\")),\r\n t.stringLiteral(signature)\r\n )\r\n );\r\n }\r\n\r\n // create expression name.llmName = name\r\n function nameAssignment(name){\r\n return t.expressionStatement(\r\n t.assignmentExpression(\r\n \"=\",\r\n t.memberExpression(t.identifier(name), t.identifier(\"llmName\")),\r\n t.stringLiteral(name)\r\n )\r\n ); \r\n }\r\n \r\n return {\r\n visitor: {\r\n /**\r\n * functional components.\r\n */\r\n FunctionDeclaration(path, state) {\r\n const { node } = path;\r\n if (!node.id) return;\r\n \r\n const name = node.id.name;\r\n if (!/^[A-Z]/.test(name)) return;\r\n \r\n const params = node.params;\r\n const props = extractProps(state, params);\r\n \r\n path.insertAfter([contextAssignment(name, props), nameAssignment(name)]);\r\n },\r\n \r\n /**\r\n * arrow function components.\r\n */\r\n VariableDeclarator(path, state) {\r\n const { node } = path;\r\n if (!t.isIdentifier(node.id)) return;\r\n \r\n const name = node.id.name;\r\n if (!/^[A-Z]/.test(name)) return;\r\n \r\n if (!t.isArrowFunctionExpression(node.init) &&\r\n !t.isFunctionExpression(node.init)) return;\r\n \r\n const params = node.init.params;\r\n const props = extractProps(state, params);\r\n \r\n path.parentPath.insertAfter([contextAssignment(name, props), nameAssignment(name)]);\r\n },\r\n },\r\n };\r\n };"]}
|
package/dist/plugin.mjs
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
2
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
3
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
// src/plugin.ts
|
|
7
|
+
var require_plugin = __commonJS({
|
|
8
|
+
"src/plugin.ts"(exports$1, module) {
|
|
9
|
+
module.exports = function({ types: t }) {
|
|
10
|
+
function extractProps(state, params) {
|
|
11
|
+
let signature = "props: ( empty )";
|
|
12
|
+
if (params.length > 0) {
|
|
13
|
+
const start = params[0].start;
|
|
14
|
+
const end = params[params.length - 1].end;
|
|
15
|
+
signature = `props: (${state.file.code.slice(start, end)})`;
|
|
16
|
+
}
|
|
17
|
+
return signature;
|
|
18
|
+
}
|
|
19
|
+
function contextAssignment(name, signature) {
|
|
20
|
+
return t.expressionStatement(
|
|
21
|
+
t.assignmentExpression(
|
|
22
|
+
"=",
|
|
23
|
+
t.memberExpression(t.identifier(name), t.identifier("llmContext")),
|
|
24
|
+
t.stringLiteral(signature)
|
|
25
|
+
)
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
function nameAssignment(name) {
|
|
29
|
+
return t.expressionStatement(
|
|
30
|
+
t.assignmentExpression(
|
|
31
|
+
"=",
|
|
32
|
+
t.memberExpression(t.identifier(name), t.identifier("llmName")),
|
|
33
|
+
t.stringLiteral(name)
|
|
34
|
+
)
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
return {
|
|
38
|
+
visitor: {
|
|
39
|
+
/**
|
|
40
|
+
* functional components.
|
|
41
|
+
*/
|
|
42
|
+
FunctionDeclaration(path, state) {
|
|
43
|
+
const { node } = path;
|
|
44
|
+
if (!node.id) return;
|
|
45
|
+
const name = node.id.name;
|
|
46
|
+
if (!/^[A-Z]/.test(name)) return;
|
|
47
|
+
const params = node.params;
|
|
48
|
+
const props = extractProps(state, params);
|
|
49
|
+
path.insertAfter([contextAssignment(name, props), nameAssignment(name)]);
|
|
50
|
+
},
|
|
51
|
+
/**
|
|
52
|
+
* arrow function components.
|
|
53
|
+
*/
|
|
54
|
+
VariableDeclarator(path, state) {
|
|
55
|
+
const { node } = path;
|
|
56
|
+
if (!t.isIdentifier(node.id)) return;
|
|
57
|
+
const name = node.id.name;
|
|
58
|
+
if (!/^[A-Z]/.test(name)) return;
|
|
59
|
+
if (!t.isArrowFunctionExpression(node.init) && !t.isFunctionExpression(node.init)) return;
|
|
60
|
+
const params = node.init.params;
|
|
61
|
+
const props = extractProps(state, params);
|
|
62
|
+
path.parentPath.insertAfter([contextAssignment(name, props), nameAssignment(name)]);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
});
|
|
69
|
+
var plugin = require_plugin();
|
|
70
|
+
|
|
71
|
+
export { plugin as default };
|
|
72
|
+
//# sourceMappingURL=plugin.mjs.map
|
|
73
|
+
//# sourceMappingURL=plugin.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin.ts"],"names":["exports"],"mappings":"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","file":"plugin.mjs","sourcesContent":["module.exports = function ({ types: t }) {\r\n // pulls props list verbatim from file for maximum context\r\n function extractProps(state, params) {\r\n let signature = \"props: ( empty )\";\r\n \r\n if (params.length > 0) {\r\n const start = params[0].start;\r\n const end = params[params.length - 1].end;\r\n signature = `props: (${state.file.code.slice(start, end)})`;\r\n }\r\n \r\n return signature;\r\n }\r\n \r\n // create expression name.llmContext = signature\r\n function contextAssignment(name, signature) {\r\n return t.expressionStatement(\r\n t.assignmentExpression(\r\n \"=\",\r\n t.memberExpression(t.identifier(name), t.identifier(\"llmContext\")),\r\n t.stringLiteral(signature)\r\n )\r\n );\r\n }\r\n\r\n // create expression name.llmName = name\r\n function nameAssignment(name){\r\n return t.expressionStatement(\r\n t.assignmentExpression(\r\n \"=\",\r\n t.memberExpression(t.identifier(name), t.identifier(\"llmName\")),\r\n t.stringLiteral(name)\r\n )\r\n ); \r\n }\r\n \r\n return {\r\n visitor: {\r\n /**\r\n * functional components.\r\n */\r\n FunctionDeclaration(path, state) {\r\n const { node } = path;\r\n if (!node.id) return;\r\n \r\n const name = node.id.name;\r\n if (!/^[A-Z]/.test(name)) return;\r\n \r\n const params = node.params;\r\n const props = extractProps(state, params);\r\n \r\n path.insertAfter([contextAssignment(name, props), nameAssignment(name)]);\r\n },\r\n \r\n /**\r\n * arrow function components.\r\n */\r\n VariableDeclarator(path, state) {\r\n const { node } = path;\r\n if (!t.isIdentifier(node.id)) return;\r\n \r\n const name = node.id.name;\r\n if (!/^[A-Z]/.test(name)) return;\r\n \r\n if (!t.isArrowFunctionExpression(node.init) &&\r\n !t.isFunctionExpression(node.init)) return;\r\n \r\n const params = node.init.params;\r\n const props = extractProps(state, params);\r\n \r\n path.parentPath.insertAfter([contextAssignment(name, props), nameAssignment(name)]);\r\n },\r\n },\r\n };\r\n };"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "getsyntux",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "The deterministic generative-UI library.",
|
|
5
|
+
"exports": {
|
|
6
|
+
".": {
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"import": "./dist/index.mjs",
|
|
9
|
+
"require": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"./plugin": "./dist/plugin.js"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/puffinsoft/syntux.git"
|
|
16
|
+
},
|
|
17
|
+
"author": "ColonelParrot",
|
|
18
|
+
"license": "MIT",
|
|
19
|
+
"bugs": {
|
|
20
|
+
"url": "https://github.com/puffinsoft/syntux/issues"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://github.com/puffinsoft/syntux#readme",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@types/node": "^25.0.2",
|
|
25
|
+
"@types/react": "^19.2.7",
|
|
26
|
+
"ai": "^5.0.115",
|
|
27
|
+
"tsup": "^8.5.1",
|
|
28
|
+
"typescript": "^5.9.3"
|
|
29
|
+
},
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "tsup",
|
|
32
|
+
"dev": "tsup --watch",
|
|
33
|
+
"prepublishOnly": "npm run build"
|
|
34
|
+
},
|
|
35
|
+
"files": [
|
|
36
|
+
"/dist/**/*"
|
|
37
|
+
]
|
|
38
|
+
}
|