getsyntux 0.2.0 → 0.3.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/README.md +87 -33
- package/dist/bin/cli.d.mts +180 -74
- package/dist/bin/cli.mjs +1 -1
- package/dist/bin/cli.mjs.map +1 -1
- package/dist/client.d.mts +9 -2
- package/dist/client.mjs +2 -2
- package/dist/client.mjs.map +1 -1
- package/dist/index.d.mts +16 -0
- package/dist/index.mjs.map +1 -1
- package/dist/metafile-esm.json +1 -1
- package/dist/templates/GeneratedUI.tsx +2 -2
- package/dist/templates/spec.md +2 -2
- package/dist/templates/spec.ts +8 -2
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
9
|
-
https://github.com/user-attachments/assets/
|
|
9
|
+
https://github.com/user-attachments/assets/a930d35d-92ab-45f4-9f71-f7bc0380c4f1
|
|
10
10
|
|
|
11
11
|
- ⚡ **Streamable** - display UI as you generate.
|
|
12
12
|
- 🎨 **Custom Components** - maintain aesthetics and reusability.
|
|
@@ -18,6 +18,47 @@ https://github.com/user-attachments/assets/f968d2c3-3b1e-4fc8-8e72-628f4361359b
|
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
+
### API
|
|
22
|
+
|
|
23
|
+
<i>syntux</i> is built for React and Next.js.
|
|
24
|
+
|
|
25
|
+
One component is all you need:
|
|
26
|
+
|
|
27
|
+
```jsx
|
|
28
|
+
const valueToDisplay = {
|
|
29
|
+
"username": "John",
|
|
30
|
+
"email": "john@gmail.com",
|
|
31
|
+
"age": 22
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
<GeneratedUI
|
|
35
|
+
model={anthropic('claude-sonnet-4-5')}
|
|
36
|
+
value={valueToDisplay}
|
|
37
|
+
hint="UI should look like..."
|
|
38
|
+
/>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
*syntux* takes the `value` into consideration and designs a UI to best display it. `value` can be anything; an object, array or primitive.
|
|
42
|
+
|
|
43
|
+
### Installation
|
|
44
|
+
|
|
45
|
+
In the root of your project:
|
|
46
|
+
|
|
47
|
+
```
|
|
48
|
+
$ npx getsyntux@latest
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
This will automatically install the required components in the `lib/getsyntux` folder.
|
|
52
|
+
|
|
53
|
+
We use the [Vercel AI SDK](https://github.com/vercel/ai) to provide support for all LLM providers. To install the model providers:
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
$ npm i ai
|
|
57
|
+
$ npm i @ai-sdk/anthropic (if you're using Claude)
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
---
|
|
61
|
+
|
|
21
62
|
### Examples
|
|
22
63
|
|
|
23
64
|
Generate a UI based on `valueToDisplay` (can be anything, including arrays):
|
|
@@ -48,64 +89,77 @@ export default function Home(){
|
|
|
48
89
|
}
|
|
49
90
|
```
|
|
50
91
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
---
|
|
92
|
+
Use custom React components:
|
|
54
93
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
94
|
+
```jsx
|
|
95
|
+
import { CustomOne, CustomTwo } from '@/my_components'
|
|
96
|
+
export default function Home(){
|
|
97
|
+
const valueToDisplay = { ... };
|
|
58
98
|
|
|
59
|
-
|
|
60
|
-
|
|
99
|
+
<GeneratedUI components={[
|
|
100
|
+
{ name: 'Button', props: "{ color: string, text: string }", component: CustomOne },
|
|
101
|
+
{ name: 'Input', props: "{ initial: string, disabled: boolean }", component: CustomTwo, context: "Creates an input field with an (initial) value. Can be disabled." }
|
|
102
|
+
]} />
|
|
103
|
+
}
|
|
61
104
|
```
|
|
62
105
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
We use the [Vercel AI SDK](https://github.com/vercel/ai) to provide support for all LLM providers. To install the model providers:
|
|
66
|
-
|
|
67
|
-
```
|
|
68
|
-
$ npm i ai
|
|
69
|
-
$ npm i @ai-sdk/anthropic (if you're using Claude)
|
|
70
|
-
```
|
|
106
|
+
See the [documentation](https://github.com/puffinsoft/syntux/wiki) for an in-depth explanation.
|
|
71
107
|
|
|
72
108
|
---
|
|
73
109
|
|
|
74
110
|
### FAQ
|
|
75
111
|
|
|
76
|
-
|
|
112
|
+
<details>
|
|
113
|
+
<summary>How does generation work? (Does it generate source code?)</summary>
|
|
114
|
+
|
|
115
|
+
Generated UIs must be *secure*, *reusable* and *cacheable*.
|
|
116
|
+
|
|
117
|
+
As such, *syntux* does not generate source code. It generates a schema for the UI, known as a "React Interface Schema" (RIS). See the question below to get a better understanding.
|
|
118
|
+
|
|
119
|
+
This schema is tailored to the `value` that you provide. It is then hydrated by *syntux* and rendered.
|
|
77
120
|
|
|
78
121
|

|
|
122
|
+
</details>
|
|
79
123
|
|
|
124
|
+
<details>
|
|
125
|
+
<summary>How does caching work?</summary>
|
|
80
126
|
|
|
81
|
-
|
|
127
|
+
The generated UI is determined by the React Interface Schema (see the above question).
|
|
82
128
|
|
|
83
|
-
|
|
129
|
+
Thus, if the same schema is provided, the same UI will be generated.
|
|
84
130
|
|
|
85
|
-
|
|
131
|
+
For simplicity, the schema is simply a string. It is up to you how you wish to store it; in memory, in a file, in a database etc,.
|
|
86
132
|
|
|
87
|
-
|
|
133
|
+
Use the `onGenerate` and `cached` properties to retrieve/provide a cached schema respectively.
|
|
134
|
+
</details>
|
|
88
135
|
|
|
89
136
|
<details>
|
|
90
137
|
<summary>What about state? Can state be generated?</summary>
|
|
91
138
|
|
|
92
|
-
|
|
139
|
+
Generating state is an anti-pattern and leads to poorly performing, insecure applications.
|
|
93
140
|
|
|
94
|
-
|
|
141
|
+
If you need to handle state, wrap non-stateful components in stateful ones, then pass those as custom components to *syntux*.
|
|
95
142
|
</details>
|
|
96
143
|
|
|
97
144
|
<details>
|
|
98
|
-
<summary>
|
|
145
|
+
<summary>What does the React Interface Schema look like?</summary>
|
|
146
|
+
|
|
147
|
+
It's a list of JSON objects, each delimited by a newline. Each object contains information about the element/component, props, and an `id` and `parentId`.
|
|
99
148
|
|
|
100
|
-
|
|
149
|
+
The RIS **does not hardcode values**. It **binds** to properties of the `value` and has **built-in iterators** (with the `type` field), making it reusable and token-efficient (for arrays).
|
|
101
150
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
```
|
|
151
|
+
Originally (pre-v0.2.x), the schema was a deep JSON tree. However, post-v0.2.x it was switched to a flat JSON list, as this allows for the UI to be built progressively (streamed).
|
|
152
|
+
|
|
153
|
+
As such, the `id` and `parentId` fields are used to construct the tree as-you-go.
|
|
154
|
+
|
|
155
|
+
Below is an example:
|
|
156
|
+
|
|
157
|
+
```json
|
|
158
|
+
{"id":"loop_1", "parentId":"root", "type":"__ForEach__", "props":{"source":"authors"}}
|
|
159
|
+
{"id":"card_1", "parentId":"loop_1", "type":"div", "props":{"className":"card"}, "content": {"$bind": "$item.name"}}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
To get a better understanding, or to implement your own parser, see the [spec](https://raw.githubusercontent.com/puffinsoft/syntux/refs/heads/master/src/templates/spec.md).
|
|
109
163
|
</details>
|
|
110
164
|
|
|
111
165
|
---
|
package/dist/bin/cli.d.mts
CHANGED
|
@@ -1,99 +1,205 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { Command } from 'commander';
|
|
2
3
|
import fs from 'fs-extra';
|
|
3
4
|
import path, { dirname } from 'path';
|
|
4
5
|
import { execSync } from 'child_process';
|
|
5
6
|
import prompts from 'prompts';
|
|
6
7
|
import chalk from 'chalk';
|
|
7
8
|
import { fileURLToPath } from 'url';
|
|
9
|
+
import { withCustomConfig } from 'react-docgen-typescript';
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return "npm install getsyntux";
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const userRoot = process.cwd();
|
|
25
|
-
const packageJsonPath = path.join(userRoot, 'package.json');
|
|
26
|
-
|
|
27
|
-
if (!fs.existsSync(packageJsonPath)) {
|
|
28
|
-
console.log(chalk.magenta('getsyntux') + ': ' + chalk.red('Failed to find package.json. Run this command from your project root.'));
|
|
29
|
-
process.exit(1);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
33
|
-
const allDeps = {
|
|
34
|
-
...packageJson.dependencies,
|
|
35
|
-
...packageJson.devDependencies
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
if (allDeps['getsyntux']) {
|
|
39
|
-
console.log(chalk.magenta('getsyntux') + `: library has already been installed. Continuing...`);
|
|
40
|
-
} else {
|
|
41
|
-
console.log(chalk.magenta('getsyntux') + `: library not detected in package.json. Please install to continue...`);
|
|
42
|
-
const packageManager = getPackageManager(userRoot);
|
|
43
|
-
const command = getInstallCommand(packageManager);
|
|
44
|
-
const response = await prompts({
|
|
45
|
-
type: 'select',
|
|
46
|
-
name: 'install',
|
|
47
|
-
message: `Run ${command}?`,
|
|
48
|
-
choices: [{ title: 'Yes' }, { title: 'No' }],
|
|
49
|
-
});
|
|
11
|
+
function log(msg){
|
|
12
|
+
console.log(chalk.magenta('getsyntux') + ': '+ msg);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* initialization command
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
const initCommand = new Command("init").description("Initialize the project").action(async () => {
|
|
21
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
22
|
+
const __dirname = dirname(__filename);
|
|
50
23
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
24
|
+
function getPackageManager(root) {
|
|
25
|
+
if (fs.existsSync(path.join(root, 'yarn.lock'))) return 'yarn';
|
|
26
|
+
if (fs.existsSync(path.join(root, 'pnpm-lock.yaml'))) return 'pnpm';
|
|
27
|
+
return 'npm';
|
|
54
28
|
}
|
|
55
29
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
console.log(chalk.magenta('getsyntux') + ': installation ' + chalk.red('failed') + ' from ' + packageManager + '.');
|
|
61
|
-
process.exit(1);
|
|
30
|
+
function getInstallCommand(manager) {
|
|
31
|
+
if (manager === "yarn") return "yarn add getsyntux";
|
|
32
|
+
if (manager === "pnpm") return "pnpm add getsyntux";
|
|
33
|
+
return "npm install getsyntux";
|
|
62
34
|
}
|
|
63
|
-
}
|
|
64
35
|
|
|
65
|
-
|
|
66
|
-
|
|
36
|
+
/**
|
|
37
|
+
* verifying
|
|
38
|
+
*/
|
|
67
39
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
process.exit(1);
|
|
71
|
-
}
|
|
40
|
+
const userRoot = process.cwd();
|
|
41
|
+
const packageJsonPath = path.join(userRoot, 'package.json');
|
|
72
42
|
|
|
73
|
-
|
|
43
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
44
|
+
log(chalk.red('Failed to find package.json. Run this command from your project root.'));
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
74
47
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
48
|
+
/**
|
|
49
|
+
* installing
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
53
|
+
const allDeps = {
|
|
54
|
+
...packageJson.dependencies,
|
|
55
|
+
...packageJson.devDependencies
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
if (allDeps['getsyntux']) {
|
|
59
|
+
log('library has already been installed. Continuing...');
|
|
60
|
+
} else {
|
|
61
|
+
log('library not detected in package.json. Please install to continue...');
|
|
62
|
+
const packageManager = getPackageManager(userRoot);
|
|
63
|
+
const command = getInstallCommand(packageManager);
|
|
79
64
|
const response = await prompts({
|
|
80
65
|
type: 'select',
|
|
81
|
-
name: '
|
|
82
|
-
message: `
|
|
66
|
+
name: 'install',
|
|
67
|
+
message: `Run ${command}?`,
|
|
83
68
|
choices: [{ title: 'Yes' }, { title: 'No' }],
|
|
84
69
|
});
|
|
85
|
-
|
|
86
|
-
if (response.
|
|
87
|
-
|
|
70
|
+
|
|
71
|
+
if (response.install !== 0) {
|
|
72
|
+
log('installation cancelled.');
|
|
88
73
|
process.exit(0);
|
|
89
74
|
}
|
|
90
75
|
|
|
91
|
-
|
|
76
|
+
try {
|
|
77
|
+
execSync(command, { stdio: 'inherit' });
|
|
78
|
+
log('installed from ' + chalk.green(packageManager) + ' successfully.');
|
|
79
|
+
} catch (error) {
|
|
80
|
+
log('installation ' + chalk.red('failed') + ' from ' + packageManager + '.');
|
|
81
|
+
process.exit(1);
|
|
82
|
+
}
|
|
92
83
|
}
|
|
93
|
-
}
|
|
94
84
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
85
|
+
/**
|
|
86
|
+
* copying
|
|
87
|
+
*/
|
|
88
|
+
|
|
89
|
+
const templateDir = path.resolve(__dirname, '../templates');
|
|
90
|
+
const targetDir = path.resolve(process.cwd(), 'lib/getsyntux');
|
|
91
|
+
|
|
92
|
+
if (!fs.existsSync(templateDir)) {
|
|
93
|
+
log(chalk.red("failed to find template directory. This is not your fault."));
|
|
94
|
+
process.exit(1);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
log('generating files...');
|
|
98
|
+
|
|
99
|
+
if (fs.existsSync(targetDir)) {
|
|
100
|
+
const files = fs.readdirSync(targetDir);
|
|
101
|
+
if (files.length > 0) {
|
|
102
|
+
log('target directory lib/getsyntux already contains files.');
|
|
103
|
+
const response = await prompts({
|
|
104
|
+
type: 'select',
|
|
105
|
+
name: 'copy',
|
|
106
|
+
message: `Empty directory?`,
|
|
107
|
+
choices: [{ title: 'Yes' }, { title: 'No' }],
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
if (response.copy !== 0) {
|
|
111
|
+
log('installation cancelled.');
|
|
112
|
+
process.exit(0);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
fs.emptyDirSync(targetDir);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
fs.copySync(templateDir, targetDir, {
|
|
120
|
+
overwrite: true,
|
|
121
|
+
errorOnExist: false
|
|
122
|
+
});
|
|
123
|
+
log(chalk.green('installation complete.'));
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* schema generation command
|
|
128
|
+
*/
|
|
129
|
+
|
|
130
|
+
const generateDefsCommand = new Command("generate-defs").description("Generate a definition for a component")
|
|
131
|
+
.argument('<path>', 'path to component file')
|
|
132
|
+
.action(async (rawPath) => {
|
|
133
|
+
const userRoot = process.cwd();
|
|
134
|
+
const tsConfigPath = path.join(userRoot, "tsconfig.json");
|
|
135
|
+
|
|
136
|
+
const parser = withCustomConfig(tsConfigPath, {
|
|
137
|
+
shouldExtractLiteralValuesFromEnum: true,
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
const filePath = path.resolve(rawPath);
|
|
141
|
+
|
|
142
|
+
if (!fs.existsSync(filePath)) {
|
|
143
|
+
log('file [' + filePath + '] ' + chalk.red('not found.'));
|
|
144
|
+
process.exit(1);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
log('parsing file...');
|
|
148
|
+
const docs = parser.parse(filePath);
|
|
149
|
+
|
|
150
|
+
if (docs.length == 0) {
|
|
151
|
+
log('there are no components with props in that file. Stopping now.');
|
|
152
|
+
process.exit(0);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
log(`found ${docs.length} component(s) with prop definitions [${docs.map(e => e.displayName).join(', ')}]`);
|
|
156
|
+
|
|
157
|
+
function generatePropSignature(props) {
|
|
158
|
+
const signature = Object.entries(props).map(([key, value]) => {
|
|
159
|
+
return `${key}${value.required ? '' : '?'}: ${value.type.name}`
|
|
160
|
+
}).join(', ');
|
|
161
|
+
|
|
162
|
+
if (!signature) return '{}' // usually for class components
|
|
163
|
+
return '{ ' + signature + ' }';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
const userContexts = [];
|
|
167
|
+
|
|
168
|
+
let index = 0;
|
|
169
|
+
for (const component of docs) {
|
|
170
|
+
log(chalk.bold(`component #${index + 1}`) + ": " + component.displayName);
|
|
171
|
+
const response = await prompts({
|
|
172
|
+
type: 'text',
|
|
173
|
+
name: 'userContext',
|
|
174
|
+
message: 'What does this component do? (optional)'
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
userContexts.push(response.userContext.replaceAll('"', '\\"'));
|
|
178
|
+
index++;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
function generateSignature(component, props, userContext) {
|
|
182
|
+
if (!userContext) {
|
|
183
|
+
return `{ name: "${component.displayName}", props: "${props}", component: ${component.displayName} }`;
|
|
184
|
+
} else {
|
|
185
|
+
return `{ name: "${component.displayName}", props: "${props}", component: ${component.displayName}, context: "${userContext}" }`;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
console.log();
|
|
190
|
+
log('generated definitions (safe to copy & paste directly):');
|
|
191
|
+
docs.forEach((component, index) => {
|
|
192
|
+
const props = generatePropSignature(component.props);
|
|
193
|
+
console.log(generateSignature(component, props, userContexts[index]) + ", ");
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
const program = new Command();
|
|
198
|
+
program.name("getsyntux").description("The declarative generative-UI library.");
|
|
199
|
+
program.addCommand(initCommand);
|
|
200
|
+
program.addCommand(generateDefsCommand);
|
|
201
|
+
|
|
202
|
+
const args = process.argv.slice(2);
|
|
203
|
+
if(args.length === 0) process.argv.splice(2, 0, "init");
|
|
204
|
+
|
|
205
|
+
program.parse(process.argv);
|
package/dist/bin/cli.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import
|
|
2
|
+
import{Command as J}from"commander";import{Command as v}from"commander";import o from"fs-extra";import l,{dirname as b}from"path";import{execSync as N}from"child_process";import C from"prompts";import m from"chalk";import k from"chalk";function t(c){console.log(k.magenta("getsyntux")+": "+c)}import{fileURLToPath as D}from"url";var P=new v("init").description("Initialize the project").action(async()=>{let c=D(import.meta.url),g=b(c);function u(e){return o.existsSync(l.join(e,"yarn.lock"))?"yarn":o.existsSync(l.join(e,"pnpm-lock.yaml"))?"pnpm":"npm"}function y(e){return e==="yarn"?"yarn add getsyntux":e==="pnpm"?"pnpm add getsyntux":"npm install getsyntux"}let i=process.cwd(),r=l.join(i,"package.json");o.existsSync(r)||(t(m.red("Failed to find package.json. Run this command from your project root.")),process.exit(1));let f=JSON.parse(o.readFileSync(r,"utf8"));if({...f.dependencies,...f.devDependencies}.getsyntux)t("library has already been installed. Continuing...");else{t("library not detected in package.json. Please install to continue...");let e=u(i),n=y(e);(await C({type:"select",name:"install",message:`Run ${n}?`,choices:[{title:"Yes"},{title:"No"}]})).install!==0&&(t("installation cancelled."),process.exit(0));try{N(n,{stdio:"inherit"}),t("installed from "+m.green(e)+" successfully.")}catch{t("installation "+m.red("failed")+" from "+e+"."),process.exit(1)}}let p=l.resolve(g,"../templates"),a=l.resolve(process.cwd(),"lib/getsyntux");o.existsSync(p)||(t(m.red("failed to find template directory. This is not your fault.")),process.exit(1)),t("generating files..."),o.existsSync(a)&&o.readdirSync(a).length>0&&(t("target directory lib/getsyntux already contains files."),(await C({type:"select",name:"copy",message:"Empty directory?",choices:[{title:"Yes"},{title:"No"}]})).copy!==0&&(t("installation cancelled."),process.exit(0)),o.emptyDirSync(a)),o.copySync(p,a,{overwrite:!0,errorOnExist:!1}),t(m.green("installation complete."))}),S=P;import{Command as E}from"commander";import w from"path";import{withCustomConfig as R}from"react-docgen-typescript";import _ from"prompts";import $ from"chalk";import F from"fs-extra";var I=new E("generate-defs").description("Generate a definition for a component").argument("<path>","path to component file").action(async c=>{let g=process.cwd(),u=w.join(g,"tsconfig.json"),y=R(u,{shouldExtractLiteralValuesFromEnum:!0}),i=w.resolve(c);F.existsSync(i)||(t("file ["+i+"] "+$.red("not found.")),process.exit(1)),t("parsing file...");let r=y.parse(i);r.length==0&&(t("there are no components with props in that file. Stopping now."),process.exit(0)),t(`found ${r.length} component(s) with prop definitions [${r.map(e=>e.displayName).join(", ")}]`);function f(e){let n=Object.entries(e).map(([s,x])=>`${s}${x.required?"":"?"}: ${x.type.name}`).join(", ");return n?"{ "+n+" }":"{}"}let h=[],p=0;for(let e of r){t($.bold(`component #${p+1}`)+": "+e.displayName);let n=await _({type:"text",name:"userContext",message:"What does this component do? (optional)"});h.push(n.userContext.replaceAll('"','\\"')),p++}function a(e,n,s){return s?`{ name: "${e.displayName}", props: "${n}", component: ${e.displayName}, context: "${s}" }`:`{ name: "${e.displayName}", props: "${n}", component: ${e.displayName} }`}console.log(),t("generated definitions (safe to copy & paste directly):"),r.forEach((e,n)=>{let s=f(e.props);console.log(a(e,s,h[n])+", ")})}),j=I;var d=new J;d.name("getsyntux").description("The declarative generative-UI library.");d.addCommand(S);d.addCommand(j);var O=process.argv.slice(2);O.length===0&&process.argv.splice(2,0,"init");d.parse(process.argv);
|
|
3
3
|
//# sourceMappingURL=cli.mjs.map
|
package/dist/bin/cli.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/bin/cli.mjs"],"sourcesContent":["#!/usr/bin/env node\r\n\r\nimport fs from 'fs-extra';\r\nimport path, { dirname } from 'path';\r\nimport { execSync } from 'child_process';\r\nimport prompts from 'prompts';\r\nimport chalk from 'chalk';\r\n\r\nimport { fileURLToPath } from 'url';\r\n\r\nconst __filename = fileURLToPath(import.meta.url);\r\nconst __dirname = dirname(__filename);\r\n\r\nfunction getPackageManager(root) {\r\n if (fs.existsSync(path.join(root, 'yarn.lock'))) return 'yarn';\r\n if (fs.existsSync(path.join(root, 'pnpm-lock.yaml'))) return 'pnpm';\r\n return 'npm';\r\n}\r\n\r\nfunction getInstallCommand(manager) {\r\n if (manager === \"yarn\") return \"yarn add getsyntux\";\r\n if (manager === \"pnpm\") return \"pnpm add getsyntux\";\r\n return \"npm install getsyntux\";\r\n}\r\n\r\nconst userRoot = process.cwd();\r\nconst packageJsonPath = path.join(userRoot, 'package.json');\r\n\r\nif (!fs.existsSync(packageJsonPath)) {\r\n console.log(chalk.magenta('getsyntux') + ': ' + chalk.red('Failed to find package.json. Run this command from your project root.'));\r\n process.exit(1);\r\n}\r\n\r\nconst packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));\r\nconst allDeps = {\r\n ...packageJson.dependencies,\r\n ...packageJson.devDependencies\r\n};\r\n\r\nif (allDeps['getsyntux']) {\r\n console.log(chalk.magenta('getsyntux') + `: library has already been installed. Continuing...`);\r\n} else {\r\n console.log(chalk.magenta('getsyntux') + `: library not detected in package.json. Please install to continue...`);\r\n const packageManager = getPackageManager(userRoot);\r\n const command = getInstallCommand(packageManager);\r\n const response = await prompts({\r\n type: 'select',\r\n name: 'install',\r\n message: `Run ${command}?`,\r\n choices: [{ title: 'Yes' }, { title: 'No' }],\r\n })\r\n\r\n if (response.install !== 0) {\r\n console.log(chalk.magenta('getsyntux') + ': installation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n try {\r\n execSync(command, { stdio: 'inherit' });\r\n console.log(chalk.magenta('getsyntux') + ': installed from ' + chalk.green(packageManager) + ' successfully.');\r\n } catch (error) {\r\n console.log(chalk.magenta('getsyntux') + ': installation ' + chalk.red('failed') + ' from ' + packageManager + '.');\r\n process.exit(1);\r\n }\r\n}\r\n\r\nconst templateDir = path.resolve(__dirname, '../templates')\r\nconst targetDir = path.resolve(process.cwd(), 'lib/getsyntux');\r\n\r\nif (!fs.existsSync(templateDir)) {\r\n console.log(chalk.magenta('getsyntux') + ': ' + chalk.red(\"failed to find template directory. This is not your fault.\"));\r\n process.exit(1);\r\n}\r\n\r\nconsole.log(chalk.magenta('getsyntux') + ': generating files...');\r\n\r\nif(fs.existsSync(targetDir)){\r\n const files = fs.readdirSync(targetDir);\r\n if(files.length > 0){\r\n console.log(chalk.magenta('getsyntux') + `: target directory lib/getsyntux already contains files.`);\r\n const response = await prompts({\r\n type: 'select',\r\n name: 'copy',\r\n message: `Empty directory?`,\r\n choices: [{ title: 'Yes' }, { title: 'No' }],\r\n })\r\n \r\n if (response.copy !== 0) {\r\n console.log(chalk.magenta('getsyntux') + ': installation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n fs.emptyDirSync(targetDir);\r\n }\r\n}\r\n\r\nfs.copySync(templateDir, targetDir, {\r\n overwrite: true,\r\n errorOnExist: false\r\n})\r\nconsole.log(chalk.magenta('getsyntux') + ': ' + chalk.green('installation complete.'));"],"mappings":";AAEA,OAAOA,MAAQ,WACf,OAAOC,GAAQ,WAAAC,MAAe,OAC9B,OAAS,YAAAC,MAAgB,gBACzB,OAAOC,MAAa,UACpB,OAAOC,MAAW,QAElB,OAAS,iBAAAC,MAAqB,MAE9B,IAAMC,EAAaD,EAAc,YAAY,GAAG,EAC1CE,EAAYN,EAAQK,CAAU,EAEpC,SAASE,EAAkBC,EAAM,CAC7B,OAAIV,EAAG,WAAWC,EAAK,KAAKS,EAAM,WAAW,CAAC,EAAU,OACpDV,EAAG,WAAWC,EAAK,KAAKS,EAAM,gBAAgB,CAAC,EAAU,OACtD,KACX,CAEA,SAASC,EAAkBC,EAAS,CAChC,OAAIA,IAAY,OAAe,qBAC3BA,IAAY,OAAe,qBACxB,uBACX,CAEA,IAAMC,EAAW,QAAQ,IAAI,EACvBC,EAAkBb,EAAK,KAAKY,EAAU,cAAc,EAErDb,EAAG,WAAWc,CAAe,IAC9B,QAAQ,IAAIT,EAAM,QAAQ,WAAW,EAAI,KAAOA,EAAM,IAAI,uEAAuE,CAAC,EAClI,QAAQ,KAAK,CAAC,GAGlB,IAAMU,EAAc,KAAK,MAAMf,EAAG,aAAac,EAAiB,MAAM,CAAC,EACjEE,EAAU,CACZ,GAAGD,EAAY,aACf,GAAGA,EAAY,eACnB,EAEA,GAAIC,EAAQ,UACR,QAAQ,IAAIX,EAAM,QAAQ,WAAW,EAAI,qDAAqD,MAC3F,CACH,QAAQ,IAAIA,EAAM,QAAQ,WAAW,EAAI,uEAAuE,EAChH,IAAMY,EAAiBR,EAAkBI,CAAQ,EAC3CK,EAAUP,EAAkBM,CAAc,GAC/B,MAAMb,EAAQ,CAC3B,KAAM,SACN,KAAM,UACN,QAAS,OAAOc,CAAO,IACvB,QAAS,CAAC,CAAE,MAAO,KAAM,EAAG,CAAE,MAAO,IAAK,CAAC,CAC/C,CAAC,GAEY,UAAY,IACrB,QAAQ,IAAIb,EAAM,QAAQ,WAAW,EAAI,2BAA2B,EACpE,QAAQ,KAAK,CAAC,GAGlB,GAAI,CACAF,EAASe,EAAS,CAAE,MAAO,SAAU,CAAC,EACtC,QAAQ,IAAIb,EAAM,QAAQ,WAAW,EAAI,oBAAsBA,EAAM,MAAMY,CAAc,EAAI,gBAAgB,CACjH,MAAgB,CACZ,QAAQ,IAAIZ,EAAM,QAAQ,WAAW,EAAI,kBAAoBA,EAAM,IAAI,QAAQ,EAAI,SAAWY,EAAiB,GAAG,EAClH,QAAQ,KAAK,CAAC,CAClB,CACJ,CAEA,IAAME,EAAclB,EAAK,QAAQO,EAAW,cAAc,EACpDY,EAAYnB,EAAK,QAAQ,QAAQ,IAAI,EAAG,eAAe,EAExDD,EAAG,WAAWmB,CAAW,IAC1B,QAAQ,IAAId,EAAM,QAAQ,WAAW,EAAI,KAAOA,EAAM,IAAI,4DAA4D,CAAC,EACvH,QAAQ,KAAK,CAAC,GAGlB,QAAQ,IAAIA,EAAM,QAAQ,WAAW,EAAI,uBAAuB,EAE7DL,EAAG,WAAWoB,CAAS,GACRpB,EAAG,YAAYoB,CAAS,EAC7B,OAAS,IACd,QAAQ,IAAIf,EAAM,QAAQ,WAAW,EAAI,0DAA0D,GAClF,MAAMD,EAAQ,CAC3B,KAAM,SACN,KAAM,OACN,QAAS,mBACT,QAAS,CAAC,CAAE,MAAO,KAAM,EAAG,CAAE,MAAO,IAAK,CAAC,CAC/C,CAAC,GAEY,OAAS,IAClB,QAAQ,IAAIC,EAAM,QAAQ,WAAW,EAAI,2BAA2B,EACpE,QAAQ,KAAK,CAAC,GAGlBL,EAAG,aAAaoB,CAAS,GAIjCpB,EAAG,SAASmB,EAAaC,EAAW,CAChC,UAAW,GACX,aAAc,EAClB,CAAC,EACD,QAAQ,IAAIf,EAAM,QAAQ,WAAW,EAAI,KAAOA,EAAM,MAAM,wBAAwB,CAAC","names":["fs","path","dirname","execSync","prompts","chalk","fileURLToPath","__filename","__dirname","getPackageManager","root","getInstallCommand","manager","userRoot","packageJsonPath","packageJson","allDeps","packageManager","command","templateDir","targetDir"]}
|
|
1
|
+
{"version":3,"sources":["../../src/bin/cli.mjs","../../src/bin/commands/init.mjs","../../src/bin/cli_util.mjs","../../src/bin/commands/generate.mjs"],"sourcesContent":["#!/usr/bin/env node\r\n\r\nimport { Command } from \"commander\";\r\nimport initCommand from \"./commands/init.mjs\";\r\nimport generateDefsCommand from \"./commands/generate.mjs\";\r\n\r\nconst program = new Command();\r\nprogram.name(\"getsyntux\").description(\"The declarative generative-UI library.\")\r\nprogram.addCommand(initCommand)\r\nprogram.addCommand(generateDefsCommand)\r\n\r\nconst args = process.argv.slice(2)\r\nif(args.length === 0) process.argv.splice(2, 0, \"init\")\r\n\r\nprogram.parse(process.argv)","/**\r\n * initialization command\r\n */\r\n\r\nimport { Command } from \"commander\";\r\n\r\nimport fs from 'fs-extra';\r\nimport path, { dirname } from 'path';\r\nimport { execSync } from 'child_process';\r\nimport prompts from 'prompts';\r\nimport chalk from 'chalk';\r\n\r\nimport { log } from \"../cli_util.mjs\";\r\n\r\nimport { fileURLToPath } from 'url';\r\n\r\nconst initCommand = new Command(\"init\").description(\"Initialize the project\").action(async () => {\r\n const __filename = fileURLToPath(import.meta.url);\r\n const __dirname = dirname(__filename);\r\n\r\n function getPackageManager(root) {\r\n if (fs.existsSync(path.join(root, 'yarn.lock'))) return 'yarn';\r\n if (fs.existsSync(path.join(root, 'pnpm-lock.yaml'))) return 'pnpm';\r\n return 'npm';\r\n }\r\n\r\n function getInstallCommand(manager) {\r\n if (manager === \"yarn\") return \"yarn add getsyntux\";\r\n if (manager === \"pnpm\") return \"pnpm add getsyntux\";\r\n return \"npm install getsyntux\";\r\n }\r\n\r\n /**\r\n * verifying\r\n */\r\n\r\n const userRoot = process.cwd();\r\n const packageJsonPath = path.join(userRoot, 'package.json');\r\n\r\n if (!fs.existsSync(packageJsonPath)) {\r\n log(chalk.red('Failed to find package.json. Run this command from your project root.'));\r\n process.exit(1);\r\n }\r\n\r\n /**\r\n * installing\r\n */\r\n\r\n const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));\r\n const allDeps = {\r\n ...packageJson.dependencies,\r\n ...packageJson.devDependencies\r\n };\r\n\r\n if (allDeps['getsyntux']) {\r\n log('library has already been installed. Continuing...');\r\n } else {\r\n log('library not detected in package.json. Please install to continue...');\r\n const packageManager = getPackageManager(userRoot);\r\n const command = getInstallCommand(packageManager);\r\n const response = await prompts({\r\n type: 'select',\r\n name: 'install',\r\n message: `Run ${command}?`,\r\n choices: [{ title: 'Yes' }, { title: 'No' }],\r\n })\r\n\r\n if (response.install !== 0) {\r\n log('installation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n try {\r\n execSync(command, { stdio: 'inherit' });\r\n log('installed from ' + chalk.green(packageManager) + ' successfully.');\r\n } catch (error) {\r\n log('installation ' + chalk.red('failed') + ' from ' + packageManager + '.');\r\n process.exit(1);\r\n }\r\n }\r\n\r\n /**\r\n * copying\r\n */\r\n\r\n const templateDir = path.resolve(__dirname, '../templates')\r\n const targetDir = path.resolve(process.cwd(), 'lib/getsyntux');\r\n\r\n if (!fs.existsSync(templateDir)) {\r\n log(chalk.red(\"failed to find template directory. This is not your fault.\"));\r\n process.exit(1);\r\n }\r\n\r\n log('generating files...');\r\n\r\n if (fs.existsSync(targetDir)) {\r\n const files = fs.readdirSync(targetDir);\r\n if (files.length > 0) {\r\n log('target directory lib/getsyntux already contains files.');\r\n const response = await prompts({\r\n type: 'select',\r\n name: 'copy',\r\n message: `Empty directory?`,\r\n choices: [{ title: 'Yes' }, { title: 'No' }],\r\n })\r\n\r\n if (response.copy !== 0) {\r\n log('installation cancelled.');\r\n process.exit(0);\r\n }\r\n\r\n fs.emptyDirSync(targetDir);\r\n }\r\n }\r\n\r\n fs.copySync(templateDir, targetDir, {\r\n overwrite: true,\r\n errorOnExist: false\r\n })\r\n log(chalk.green('installation complete.'));\r\n})\r\n\r\nexport default initCommand;","import chalk from \"chalk\";\r\n\r\nexport function log(msg){\r\n console.log(chalk.magenta('getsyntux') + ': '+ msg)\r\n}","/**\r\n * schema generation command\r\n*/\r\nimport { Command } from \"commander\";\r\n\r\nimport path from \"path\";\r\nimport { withCustomConfig } from \"react-docgen-typescript\";\r\n\r\nimport prompts from 'prompts';\r\nimport chalk from 'chalk';\r\nimport fs from 'fs-extra';\r\n\r\nimport { log } from \"../cli_util.mjs\";\r\n\r\nconst generateDefsCommand = new Command(\"generate-defs\").description(\"Generate a definition for a component\")\r\n .argument('<path>', 'path to component file')\r\n .action(async (rawPath) => {\r\n const userRoot = process.cwd()\r\n const tsConfigPath = path.join(userRoot, \"tsconfig.json\")\r\n\r\n const parser = withCustomConfig(tsConfigPath, {\r\n shouldExtractLiteralValuesFromEnum: true,\r\n })\r\n\r\n const filePath = path.resolve(rawPath);\r\n\r\n if (!fs.existsSync(filePath)) {\r\n log('file [' + filePath + '] ' + chalk.red('not found.'))\r\n process.exit(1)\r\n }\r\n\r\n log('parsing file...')\r\n const docs = parser.parse(filePath);\r\n\r\n if (docs.length == 0) {\r\n log('there are no components with props in that file. Stopping now.')\r\n process.exit(0)\r\n }\r\n\r\n log(`found ${docs.length} component(s) with prop definitions [${docs.map(e => e.displayName).join(', ')}]`)\r\n\r\n function generatePropSignature(props) {\r\n const signature = Object.entries(props).map(([key, value]) => {\r\n return `${key}${value.required ? '' : '?'}: ${value.type.name}`\r\n }).join(', ')\r\n\r\n if (!signature) return '{}' // usually for class components\r\n return '{ ' + signature + ' }';\r\n }\r\n\r\n const userContexts = []\r\n\r\n let index = 0;\r\n for (const component of docs) {\r\n log(chalk.bold(`component #${index + 1}`) + \": \" + component.displayName)\r\n const response = await prompts({\r\n type: 'text',\r\n name: 'userContext',\r\n message: 'What does this component do? (optional)'\r\n })\r\n\r\n userContexts.push(response.userContext.replaceAll('\"', '\\\\\"'))\r\n index++;\r\n }\r\n\r\n function generateSignature(component, props, userContext) {\r\n if (!userContext) {\r\n return `{ name: \"${component.displayName}\", props: \"${props}\", component: ${component.displayName} }`;\r\n } else {\r\n return `{ name: \"${component.displayName}\", props: \"${props}\", component: ${component.displayName}, context: \"${userContext}\" }`;\r\n }\r\n }\r\n\r\n console.log()\r\n log('generated definitions (safe to copy & paste directly):')\r\n docs.forEach((component, index) => {\r\n const props = generatePropSignature(component.props);\r\n console.log(generateSignature(component, props, userContexts[index]) + \", \");\r\n })\r\n })\r\n\r\nexport default generateDefsCommand;"],"mappings":"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","names":["Command","Command","fs","path","dirname","execSync","prompts","chalk","chalk","log","msg","fileURLToPath","initCommand","Command","__filename","__dirname","dirname","getPackageManager","root","fs","path","getInstallCommand","manager","userRoot","packageJsonPath","log","chalk","packageJson","packageManager","command","prompts","execSync","templateDir","targetDir","init_default","Command","path","withCustomConfig","prompts","chalk","fs","generateDefsCommand","Command","rawPath","userRoot","tsConfigPath","path","parser","withCustomConfig","filePath","fs","log","chalk","docs","generatePropSignature","props","signature","key","value","userContexts","index","component","response","prompts","generateSignature","userContext","generate_default","program","Command","init_default","generate_default","args"]}
|
package/dist/client.d.mts
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { StreamableValue } from '@ai-sdk/rsc';
|
|
3
|
-
import react__default, { ComponentType } from 'react';
|
|
3
|
+
import react__default, { JSX, ComponentType } from 'react';
|
|
4
4
|
import { C as ComponentMap, b as ChildrenMap } from './types-DejIW5JZ.mjs';
|
|
5
5
|
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Client wrapper for Renderer that handles streaming and parsing with server.
|
|
8
|
+
*/
|
|
9
|
+
declare function GeneratedClient({ value, allowedComponents, inputStream, placeholder }: {
|
|
7
10
|
value: any;
|
|
8
11
|
allowedComponents: Record<string, react__default.ComponentType<any> | string>;
|
|
9
12
|
inputStream: StreamableValue<string>;
|
|
13
|
+
placeholder?: JSX.Element;
|
|
10
14
|
}): react_jsx_runtime.JSX.Element;
|
|
11
15
|
|
|
12
16
|
interface RendererProps {
|
|
@@ -17,6 +21,9 @@ interface RendererProps {
|
|
|
17
21
|
global: any;
|
|
18
22
|
local: any;
|
|
19
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* Renders a UISchema recursively, in accordance to the spec.
|
|
26
|
+
*/
|
|
20
27
|
declare function Renderer(props: RendererProps): react_jsx_runtime.JSX.Element;
|
|
21
28
|
|
|
22
29
|
export { GeneratedClient, Renderer, type RendererProps };
|
package/dist/client.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
"use client";import{readStreamableValue as
|
|
2
|
-
`);e.length>1&&(e.slice(0,e.length-1).forEach(
|
|
1
|
+
"use client";import{readStreamableValue as N}from"@ai-sdk/rsc";import{useEffect as _,useRef as A,useState as I}from"react";import{Fragment as T}from"react";import{Fragment as C,jsx as d,jsxs as x}from"react/jsx-runtime";import{createElement as v}from"react";var S=(t,n)=>n==="$"?t:n.split(".").reduce((e,r)=>e==null?void 0:e[r],t),g=(t,n,e)=>e.startsWith("$item.")?(e=e.slice(6),S(n,e)):e==="$item"?n:S(t,e),R=(t,n,e)=>e&&("$bind"in e?g(t,n,e.$bind):(Object.keys(e).forEach(r=>{let a=e[r];typeof a=="object"&&(e[r]=R(t,n,a))}),e)),M=(t,n,e)=>typeof e=="object"?g(t,n,e.$bind):e,U=new Set(["area","base","br","col","embed","hr","img","input","link","meta","param","source","track","wbr"]);function h(t){var u;let{id:n,componentMap:e,childrenMap:r,global:a,local:l,allowedComponents:i}=t,o=e[n];if(o.type==="TEXT")return d(C,{children:M(a,l,o.content)});let s=(u=o.props)==null?void 0:u.source;if(o.type==="__ForEach__"&&s){let f=g(a,l,s);if(!Array.isArray(f))return null;let p=r[o.id];return d(C,{children:p==null?void 0:p.map((E,P)=>d(T,{children:f.map(($,k)=>v(h,{...t,id:E,local:$,key:k}))},P))})}let m=i[o.type]||o.type,c=R(a,l,o.props);return typeof m=="string"&&U.has(m)?d(m,{...c}):x(m,{...c,children:[M(a,l,o.content),r[o.id]&&r[o.id].map((f,p)=>d(h,{...t,id:f},p))]})}var y=class{buffer="";schema={childrenMap:{},componentMap:{},root:null};addDelta(n){this.buffer+=n;let e=this.buffer.split(`
|
|
2
|
+
`);e.length>1&&(e.slice(0,e.length-1).forEach(r=>this.handleLine(r)),this.buffer=e[e.length-1])}handleLine(n){try{let e=JSON.parse(n),{childrenMap:r,componentMap:a}=this.schema;a[e.id]=e,e.parentId===null?this.schema.root=e:(r[e.parentId]||(r[e.parentId]=[]),r[e.parentId].push(e.id))}catch{}}finish(){this.handleLine(this.buffer),this.buffer=""}};import{Fragment as w,jsx as b}from"react/jsx-runtime";function H({value:t,allowedComponents:n,inputStream:e,placeholder:r}){let[a,l]=I(""),[i,o]=I(),s=A(null);return _(()=>{s.current||(s.current=new y),(async()=>{for await(let c of N(e))l(u=>u+c),s.current&&c!==void 0&&(s.current.addDelta(c),o(s.current.schema))})()},[e]),b(w,{children:i!=null&&i.root?b(h,{id:i.root.id,componentMap:i.componentMap,childrenMap:i.childrenMap,allowedComponents:n,global:t,local:t}):b(w,{children:r})})}export{H as GeneratedClient,h as Renderer};
|
|
3
3
|
//# sourceMappingURL=client.mjs.map
|
package/dist/client.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/GeneratedClient.tsx","../src/client/Renderer.tsx","../src/ResponseParser.ts"],"sourcesContent":["\"use client\";\r\n\r\nimport { StreamableValue, readStreamableValue } from '@ai-sdk/rsc';\r\nimport React, { useEffect, useRef, useState } from 'react';\r\nimport { Renderer } from './Renderer';\r\nimport { ResponseParser } from '../ResponseParser';\r\nimport { UISchema } from '../types';\r\n\r\nexport function GeneratedClient({\r\n value,\r\n allowedComponents,\r\n inputStream\r\n}: {\r\n value: any,\r\n allowedComponents: Record<string, React.ComponentType<any> | string>,\r\n inputStream: StreamableValue<string>\r\n}) {\r\n const [message, setMessage] = useState('');\r\n const [schema, setUISchema] = useState<UISchema | null>();\r\n const parser = useRef<ResponseParser | null>(null);\r\n\r\n useEffect(() => {\r\n if (!parser.current) {\r\n parser.current = new ResponseParser();\r\n }\r\n\r\n const parseStream = async () => {\r\n for await (const delta of readStreamableValue(inputStream)) {\r\n setMessage((prev) => prev + delta);\r\n if (parser.current && delta !== undefined) {\r\n parser.current.addDelta(delta);\r\n setUISchema(parser.current.schema);\r\n }\r\n }\r\n };\r\n\r\n parseStream();\r\n }, [inputStream]);\r\n\r\n return (\r\n <>\r\n {schema?.root && <Renderer id={schema.root.id} componentMap={schema.componentMap} childrenMap={schema.childrenMap} allowedComponents={allowedComponents} global={value} local={value} />}\r\n </>\r\n )\r\n}\r\n","\"use client\";\r\n\r\nimport { ComponentType, Fragment } from 'react'\r\nimport { ChildrenMap, ComponentMap, SchemaNode } from '../types';\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 props;\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 RendererProps {\r\n id: string;\r\n componentMap: ComponentMap;\r\n childrenMap: ChildrenMap;\r\n allowedComponents: Record<string, ComponentType<any> | string>;\r\n global: any;\r\n local: any;\r\n}\r\n\r\nconst renderContent = (global: any, local: any, content: any) => {\r\n if (typeof content === \"object\") {\r\n return get(global, local, content.$bind);\r\n } else {\r\n return content;\r\n }\r\n}\r\n\r\nconst voidElements = new Set([\r\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\r\n 'link', 'meta', 'param', 'source', 'track', 'wbr'\r\n])\r\n\r\nexport function Renderer(props: RendererProps) {\r\n const {\r\n id, componentMap, childrenMap, global, local, allowedComponents\r\n } = props;\r\n const element = componentMap[id];\r\n\r\n if (element.type === \"TEXT\") return <>{renderContent(global, local, element.content)}</>\r\n\r\n const sourceArrPath = element.props?.source;\r\n if (element.type === '__ForEach__' && sourceArrPath) {\r\n const sourceArr = get(global, local, sourceArrPath)\r\n if (!Array.isArray(sourceArr)) return null;\r\n\r\n const childrenArr = childrenMap[element.id];\r\n return <>{childrenArr?.map((childId: string, index: number) => <Fragment key={index}>\r\n {sourceArr.map((item: any, index1: number) => <Renderer {...props} id={childId} local={item} key={index1} />)}\r\n </Fragment>)}</>\r\n }\r\n\r\n const Component = allowedComponents[element.type] || element.type;\r\n const componentProps = resolveProps(global, local, element.props);\r\n if(typeof Component === \"string\" && voidElements.has(Component)){\r\n return <Component {...componentProps} />\r\n }\r\n\r\n return <Component {...componentProps}>\r\n {renderContent(global, local, element.content)}\r\n {childrenMap[element.id] && childrenMap[element.id].map((childId: string, index: number) => {\r\n return <Renderer\r\n key={index}\r\n {...props}\r\n id={childId}\r\n />\r\n })}\r\n </Component>\r\n}\r\n","import { SchemaNode, UISchema } from \"./types\";\r\n\r\nexport class ResponseParser {\r\n buffer = \"\";\r\n schema: UISchema = {\r\n childrenMap: {},\r\n componentMap: {},\r\n root: null\r\n }\r\n\r\n addDelta(delta: string) {\r\n this.buffer += delta;\r\n const split = this.buffer.split(\"\\n\")\r\n if (split.length > 1) {\r\n split.slice(0, split.length - 1).forEach((line) => this.handleLine(line));\r\n this.buffer = split[split.length - 1];\r\n }\r\n }\r\n\r\n handleLine(line: string) {\r\n try {\r\n const node: SchemaNode = JSON.parse(line);\r\n\r\n const { childrenMap, componentMap } = this.schema;\r\n\r\n componentMap[node.id] = node;\r\n if (node.parentId === null) {\r\n this.schema.root = node;\r\n } else {\r\n if (!childrenMap[node.parentId]) childrenMap[node.parentId] = []\r\n childrenMap[node.parentId].push(node.id)\r\n }\r\n } catch (err) { /* probably markdown or generation inconsistency */ }\r\n }\r\n\r\n finish(){\r\n this.handleLine(this.buffer);\r\n this.buffer = \"\";\r\n }\r\n}"],"mappings":"aAEA,OAA0B,uBAAAA,MAA2B,cACrD,OAAgB,aAAAC,EAAW,UAAAC,EAAQ,YAAAC,MAAgB,QCDnD,OAAwB,YAAAC,MAAgB,QA0DA,mBAAAA,EAAA,OAAAC,EAmB7B,QAAAC,MAnB6B,oBASkB,wBAAAC,MAAA,QAhE1D,IAAMC,EAAc,CAACC,EAAUC,IACvBA,IAAS,IAAYD,EAClBC,EAAK,MAAM,GAAG,EAAE,OAAO,CAACC,EAAKC,IAASD,GAAA,YAAAA,EAAMC,GAAOH,CAAG,EAG3DI,EAAM,CAACC,EAAaC,EAAYL,IAC9BA,EAAK,WAAW,QAAQ,GACxBA,EAAOA,EAAK,MAAM,CAAC,EACZF,EAAYO,EAAOL,CAAI,GAE1BA,IAAS,QAAgBK,EACtBP,EAAYM,EAAQJ,CAAI,EAIjCM,EAAe,CAACF,EAAaC,EAAYE,IACtCA,IACD,UAAWA,EAAcJ,EAAIC,EAAQC,EAAOE,EAAM,KAAK,GAC3D,OAAO,KAAKA,CAAK,EAAE,QAASC,GAAQ,CAChC,IAAMC,EAAMF,EAAMC,CAAG,EACjB,OAAOC,GAAQ,WACfF,EAAMC,CAAG,EAAIF,EAAaF,EAAQC,EAAOI,CAAG,EAEpD,CAAC,EACMF,IAYLG,EAAgB,CAACN,EAAaC,EAAYM,IACxC,OAAOA,GAAY,SACZR,EAAIC,EAAQC,EAAOM,EAAQ,KAAK,EAEhCA,EAITC,EAAe,IAAI,IAAI,CACzB,OAAQ,OAAQ,KAAM,MAAO,QAAS,KAAM,MAAO,QACnD,OAAQ,OAAQ,QAAS,SAAU,QAAS,KAChD,CAAC,EAEM,SAASC,EAASN,EAAsB,CAtD/C,IAAAO,EAuDI,GAAM,CACF,GAAAC,EAAI,aAAAC,EAAc,YAAAC,EAAa,OAAAb,EAAQ,MAAAC,EAAO,kBAAAa,CAClD,EAAIX,EACEY,EAAUH,EAAaD,CAAE,EAE/B,GAAII,EAAQ,OAAS,OAAQ,OAAOxB,EAAAD,EAAA,CAAG,SAAAgB,EAAcN,EAAQC,EAAOc,EAAQ,OAAO,EAAE,EAErF,IAAMC,GAAgBN,EAAAK,EAAQ,QAAR,YAAAL,EAAe,OACrC,GAAIK,EAAQ,OAAS,eAAiBC,EAAe,CACjD,IAAMC,EAAYlB,EAAIC,EAAQC,EAAOe,CAAa,EAClD,GAAI,CAAC,MAAM,QAAQC,CAAS,EAAG,OAAO,KAEtC,IAAMC,EAAcL,EAAYE,EAAQ,EAAE,EAC1C,OAAOxB,EAAAD,EAAA,CAAG,SAAA4B,GAAA,YAAAA,EAAa,IAAI,CAACC,EAAiBC,IAAkB7B,EAACD,EAAA,CAC3D,SAAA2B,EAAU,IAAI,CAACI,EAAWC,IAAmB7B,EAACgB,EAAA,CAAU,GAAGN,EAAO,GAAIgB,EAAS,MAAOE,EAAM,IAAKC,EAAQ,CAAE,GADlCF,CAE9E,GAAa,CACjB,CAEA,IAAMG,EAAYT,EAAkBC,EAAQ,IAAI,GAAKA,EAAQ,KACvDS,EAAiBtB,EAAaF,EAAQC,EAAOc,EAAQ,KAAK,EAChE,OAAG,OAAOQ,GAAc,UAAYf,EAAa,IAAIe,CAAS,EACnDhC,EAACgC,EAAA,CAAY,GAAGC,EAAgB,EAGpChC,EAAC+B,EAAA,CAAW,GAAGC,EACjB,UAAAlB,EAAcN,EAAQC,EAAOc,EAAQ,OAAO,EAC5CF,EAAYE,EAAQ,EAAE,GAAKF,EAAYE,EAAQ,EAAE,EAAE,IAAI,CAACI,EAAiBC,IAC/D7B,EAACkB,EAAA,CAEH,GAAGN,EACJ,GAAIgB,GAFCC,CAGT,CACH,GACL,CACJ,CCvFO,IAAMK,EAAN,KAAqB,CACxB,OAAS,GACT,OAAmB,CACf,YAAa,CAAC,EACd,aAAc,CAAC,EACf,KAAM,IACV,EAEA,SAASC,EAAe,CACpB,KAAK,QAAUA,EACf,IAAMC,EAAQ,KAAK,OAAO,MAAM;AAAA,CAAI,EAChCA,EAAM,OAAS,IACfA,EAAM,MAAM,EAAGA,EAAM,OAAS,CAAC,EAAE,QAASC,GAAS,KAAK,WAAWA,CAAI,CAAC,EACxE,KAAK,OAASD,EAAMA,EAAM,OAAS,CAAC,EAE5C,CAEA,WAAWC,EAAc,CACrB,GAAI,CACA,IAAMC,EAAmB,KAAK,MAAMD,CAAI,EAElC,CAAE,YAAAE,EAAa,aAAAC,CAAa,EAAI,KAAK,OAE3CA,EAAaF,EAAK,EAAE,EAAIA,EACpBA,EAAK,WAAa,KAClB,KAAK,OAAO,KAAOA,GAEdC,EAAYD,EAAK,QAAQ,IAAGC,EAAYD,EAAK,QAAQ,EAAI,CAAC,GAC/DC,EAAYD,EAAK,QAAQ,EAAE,KAAKA,EAAK,EAAE,EAE/C,MAAc,CAAsD,CACxE,CAEA,QAAQ,CACJ,KAAK,WAAW,KAAK,MAAM,EAC3B,KAAK,OAAS,EAClB,CACJ,EFCI,mBAAAG,EACmB,OAAAC,MADnB,oBAhCG,SAASC,EAAgB,CAC9B,MAAAC,EACA,kBAAAC,EACA,YAAAC,CACF,EAIG,CACD,GAAM,CAACC,EAASC,CAAU,EAAIC,EAAS,EAAE,EACnC,CAACC,EAAQC,CAAW,EAAIF,EAA0B,EAClDG,EAASC,EAA8B,IAAI,EAEjD,OAAAC,EAAU,IAAM,CACTF,EAAO,UACVA,EAAO,QAAU,IAAIG,IAGH,SAAY,CAC9B,cAAiBC,KAASC,EAAoBX,CAAW,EACvDE,EAAYU,GAASA,EAAOF,CAAK,EAC7BJ,EAAO,SAAWI,IAAU,SAC9BJ,EAAO,QAAQ,SAASI,CAAK,EAC7BL,EAAYC,EAAO,QAAQ,MAAM,EAGvC,GAEY,CACd,EAAG,CAACN,CAAW,CAAC,EAGdJ,EAAAD,EAAA,CACG,UAAAS,GAAA,YAAAA,EAAQ,OAAQR,EAACiB,EAAA,CAAS,GAAIT,EAAO,KAAK,GAAI,aAAcA,EAAO,aAAc,YAAaA,EAAO,YAAa,kBAAmBL,EAAmB,OAAQD,EAAO,MAAOA,EAAO,EACxL,CAEJ","names":["readStreamableValue","useEffect","useRef","useState","Fragment","jsx","jsxs","createElement","resolvePath","obj","path","acc","curr","get","global","local","resolveProps","props","key","val","renderContent","content","voidElements","Renderer","_a","id","componentMap","childrenMap","allowedComponents","element","sourceArrPath","sourceArr","childrenArr","childId","index","item","index1","Component","componentProps","ResponseParser","delta","split","line","node","childrenMap","componentMap","Fragment","jsx","GeneratedClient","value","allowedComponents","inputStream","message","setMessage","useState","schema","setUISchema","parser","useRef","useEffect","ResponseParser","delta","readStreamableValue","prev","Renderer"]}
|
|
1
|
+
{"version":3,"sources":["../src/client/GeneratedClient.tsx","../src/client/Renderer.tsx","../src/ResponseParser.ts"],"sourcesContent":["\"use client\";\r\n\r\nimport { StreamableValue, readStreamableValue } from '@ai-sdk/rsc';\r\nimport React, { JSX, useEffect, useRef, useState } from 'react';\r\nimport { Renderer } from './Renderer';\r\nimport { ResponseParser } from '../ResponseParser';\r\nimport { UISchema } from '../types';\r\n\r\n/**\r\n * Client wrapper for Renderer that handles streaming and parsing with server.\r\n */\r\nexport function GeneratedClient({\r\n value,\r\n allowedComponents,\r\n inputStream,\r\n placeholder\r\n}: {\r\n value: any,\r\n allowedComponents: Record<string, React.ComponentType<any> | string>,\r\n inputStream: StreamableValue<string>,\r\n placeholder?: JSX.Element\r\n}) {\r\n const [message, setMessage] = useState('');\r\n const [schema, setUISchema] = useState<UISchema | null>();\r\n const parser = useRef<ResponseParser | null>(null);\r\n\r\n useEffect(() => {\r\n if (!parser.current) {\r\n parser.current = new ResponseParser();\r\n }\r\n\r\n const parseStream = async () => {\r\n for await (const delta of readStreamableValue(inputStream)) {\r\n setMessage((prev) => prev + delta);\r\n if (parser.current && delta !== undefined) {\r\n parser.current.addDelta(delta);\r\n setUISchema(parser.current.schema);\r\n }\r\n }\r\n };\r\n\r\n parseStream();\r\n }, [inputStream]);\r\n\r\n return (\r\n <>\r\n {schema?.root ?\r\n <Renderer id={schema.root.id} componentMap={schema.componentMap} childrenMap={schema.childrenMap} allowedComponents={allowedComponents} global={value} local={value} />\r\n : <>{placeholder}</>}\r\n </>\r\n )\r\n}\r\n","\"use client\";\r\n\r\nimport { ComponentType, Fragment } from 'react'\r\nimport { ChildrenMap, ComponentMap, SchemaNode } from '../types';\r\n\r\n/**\r\n * lightweight implementation of lodash.get\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\n/**\r\n * parses binding protocol and performs property lookup w/ scope resolution\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\n/**\r\n * recursively parses props for bindings, replacing with true values\r\n */\r\nconst resolveProps = (global: any, local: any, props: any) => {\r\n if (!props) return props;\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\n/**\r\n * output node.content, with check for $bind\r\n*/\r\nconst renderContent = (global: any, local: any, content: any) => {\r\n if (typeof content === \"object\") {\r\n return get(global, local, content.$bind);\r\n } else {\r\n return content;\r\n }\r\n}\r\n\r\nconst voidElements = new Set([\r\n 'area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input',\r\n 'link', 'meta', 'param', 'source', 'track', 'wbr'\r\n])\r\n\r\nexport interface RendererProps {\r\n id: string;\r\n componentMap: ComponentMap;\r\n childrenMap: ChildrenMap;\r\n allowedComponents: Record<string, ComponentType<any> | string>;\r\n global: any;\r\n local: any;\r\n}\r\n\r\n/**\r\n * Renders a UISchema recursively, in accordance to the spec.\r\n */\r\nexport function Renderer(props: RendererProps) {\r\n const {\r\n id, componentMap, childrenMap, global, local, allowedComponents\r\n } = props;\r\n const element = componentMap[id];\r\n\r\n if (element.type === \"TEXT\") return <>{renderContent(global, local, element.content)}</>\r\n\r\n const sourceArrPath = element.props?.source;\r\n if (element.type === '__ForEach__' && sourceArrPath) {\r\n const sourceArr = get(global, local, sourceArrPath)\r\n if (!Array.isArray(sourceArr)) return null;\r\n\r\n const childrenArr = childrenMap[element.id];\r\n return <>{childrenArr?.map((childId: string, index: number) => <Fragment key={index}>\r\n {sourceArr.map((item: any, index1: number) => <Renderer {...props} id={childId} local={item} key={index1} />)}\r\n </Fragment>)}</>\r\n }\r\n\r\n const Component = allowedComponents[element.type] || element.type;\r\n const componentProps = resolveProps(global, local, element.props);\r\n if(typeof Component === \"string\" && voidElements.has(Component)){\r\n return <Component {...componentProps} />\r\n }\r\n\r\n return <Component {...componentProps}>\r\n {renderContent(global, local, element.content)}\r\n {childrenMap[element.id] && childrenMap[element.id].map((childId: string, index: number) => {\r\n return <Renderer\r\n key={index}\r\n {...props}\r\n id={childId}\r\n />\r\n })}\r\n </Component>\r\n}\r\n","import { SchemaNode, UISchema } from \"./types\";\r\n\r\n/**\r\n * Utility class for parsing UISchema from stream.\r\n */\r\nexport class ResponseParser {\r\n buffer = \"\"; // unflushed existing deltas w/o newline\r\n \r\n // schema assembled thus far\r\n schema: UISchema = {\r\n childrenMap: {},\r\n componentMap: {},\r\n root: null\r\n }\r\n\r\n /**\r\n * Update schema with latest data chunk.\r\n * \r\n * Handles multiline input gracefully; can be used to load entire schemas from cache.\r\n * @param delta delta from stream.\r\n */\r\n addDelta(delta: string) {\r\n this.buffer += delta;\r\n const split = this.buffer.split(\"\\n\")\r\n if (split.length > 1) {\r\n split.slice(0, split.length - 1).forEach((line) => this.handleLine(line));\r\n this.buffer = split[split.length - 1];\r\n }\r\n }\r\n\r\n /**\r\n * Parses a single line (full JSON object) and updates schema.\r\n * Generally should not be used when streaming data.\r\n */\r\n handleLine(line: string) {\r\n try {\r\n const node: SchemaNode = JSON.parse(line);\r\n\r\n const { childrenMap, componentMap } = this.schema;\r\n\r\n componentMap[node.id] = node;\r\n if (node.parentId === null) {\r\n this.schema.root = node;\r\n } else {\r\n if (!childrenMap[node.parentId]) childrenMap[node.parentId] = []\r\n childrenMap[node.parentId].push(node.id)\r\n }\r\n } catch (err) { /* probably markdown or generation inconsistency */ }\r\n }\r\n\r\n /**\r\n * Clears the buffer and handles any remaining information within.\r\n */\r\n finish(){\r\n this.handleLine(this.buffer);\r\n this.buffer = \"\";\r\n }\r\n}"],"mappings":"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","names":["readStreamableValue","useEffect","useRef","useState","Fragment","jsx","jsxs","createElement","resolvePath","obj","path","acc","curr","get","global","local","resolveProps","props","key","val","renderContent","content","voidElements","Renderer","_a","id","componentMap","childrenMap","allowedComponents","element","sourceArrPath","sourceArr","childrenArr","childId","index","item","index1","Component","componentProps","ResponseParser","delta","split","line","node","childrenMap","componentMap","Fragment","jsx","GeneratedClient","value","allowedComponents","inputStream","placeholder","message","setMessage","useState","schema","setUISchema","parser","useRef","useEffect","ResponseParser","delta","readStreamableValue","prev","Renderer"]}
|
package/dist/index.d.mts
CHANGED
|
@@ -25,11 +25,27 @@ declare function generateComponentMap(allowedComponents: (SyntuxComponent$1 | st
|
|
|
25
25
|
*/
|
|
26
26
|
declare function constructInput({ value, components, hint }: GeneratedContentProps): string;
|
|
27
27
|
|
|
28
|
+
/**
|
|
29
|
+
* Utility class for parsing UISchema from stream.
|
|
30
|
+
*/
|
|
28
31
|
declare class ResponseParser {
|
|
29
32
|
buffer: string;
|
|
30
33
|
schema: UISchema;
|
|
34
|
+
/**
|
|
35
|
+
* Update schema with latest data chunk.
|
|
36
|
+
*
|
|
37
|
+
* Handles multiline input gracefully; can be used to load entire schemas from cache.
|
|
38
|
+
* @param delta delta from stream.
|
|
39
|
+
*/
|
|
31
40
|
addDelta(delta: string): void;
|
|
41
|
+
/**
|
|
42
|
+
* Parses a single line (full JSON object) and updates schema.
|
|
43
|
+
* Generally should not be used when streaming data.
|
|
44
|
+
*/
|
|
32
45
|
handleLine(line: string): void;
|
|
46
|
+
/**
|
|
47
|
+
* Clears the buffer and handles any remaining information within.
|
|
48
|
+
*/
|
|
33
49
|
finish(): void;
|
|
34
50
|
}
|
|
35
51
|
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/util.ts","../src/ResponseParser.ts"],"sourcesContent":["import { GeneratedContentProps } from \"./templates/GeneratedUI\";\r\nimport { SyntuxComponent } from \"./types\";\r\n\r\n/**\r\n * Converts a list of components into a dictionary for fast-retrieval\r\n * during rendering.\r\n */\r\nexport function generateComponentMap(allowedComponents: (SyntuxComponent | string)[]){\r\n return allowedComponents.reduce((acc: Record<string, React.ComponentType<any> | string>, curr: SyntuxComponent | string) => {\r\n if(typeof curr === \"string\"){\r\n acc[curr] = curr;\r\n return acc;\r\n }\r\n\r\n acc[curr.name] = curr.component;\r\n return acc;\r\n }, {})\r\n}\r\n\r\n/**\r\n * Creates LLM input in accordance to the spec\r\n */\r\nexport function constructInput({\r\n value, components, hint\r\n} : GeneratedContentProps){\r\n const allowedComponents = components?.map((item: SyntuxComponent | string) => {\r\n if(typeof item === \"string\") return item;\r\n return item.name;\r\n }).join(',') || \"\"\r\n\r\n const customComponents = components?.filter((item): item is SyntuxComponent => typeof item !== \"string\");\r\n const componentContext = customComponents?.map((item) => {\r\n if(!item.context){\r\n return `${item.name} [props: ${item.props}]`\r\n } else {\r\n return `${item.name} [props: ${item.props}, details: ${item.context}]`\r\n }\r\n }).join(',') || \"\"\r\n\r\n const userContext = hint;\r\n const inputValue = JSON.stringify(value)\r\n\r\n return `<AllowedComponents>${allowedComponents}</AllowedComponents>\\n<ComponentContext>${componentContext}</ComponentContext>\\n<UserContext>${userContext || \"\"}</UserContext>\\n<Value>\\n${inputValue}</Value>`\r\n}","import { SchemaNode, UISchema } from \"./types\";\r\n\r\nexport class ResponseParser {\r\n buffer = \"\"
|
|
1
|
+
{"version":3,"sources":["../src/util.ts","../src/ResponseParser.ts"],"sourcesContent":["import { GeneratedContentProps } from \"./templates/GeneratedUI\";\r\nimport { SyntuxComponent } from \"./types\";\r\n\r\n/**\r\n * Converts a list of components into a dictionary for fast-retrieval\r\n * during rendering.\r\n */\r\nexport function generateComponentMap(allowedComponents: (SyntuxComponent | string)[]){\r\n return allowedComponents.reduce((acc: Record<string, React.ComponentType<any> | string>, curr: SyntuxComponent | string) => {\r\n if(typeof curr === \"string\"){\r\n acc[curr] = curr;\r\n return acc;\r\n }\r\n\r\n acc[curr.name] = curr.component;\r\n return acc;\r\n }, {})\r\n}\r\n\r\n/**\r\n * Creates LLM input in accordance to the spec\r\n */\r\nexport function constructInput({\r\n value, components, hint\r\n} : GeneratedContentProps){\r\n const allowedComponents = components?.map((item: SyntuxComponent | string) => {\r\n if(typeof item === \"string\") return item;\r\n return item.name;\r\n }).join(',') || \"\"\r\n\r\n const customComponents = components?.filter((item): item is SyntuxComponent => typeof item !== \"string\");\r\n const componentContext = customComponents?.map((item) => {\r\n if(!item.context){\r\n return `${item.name} [props: ${item.props}]`\r\n } else {\r\n return `${item.name} [props: ${item.props}, details: ${item.context}]`\r\n }\r\n }).join(',') || \"\"\r\n\r\n const userContext = hint;\r\n const inputValue = JSON.stringify(value)\r\n\r\n return `<AllowedComponents>${allowedComponents}</AllowedComponents>\\n<ComponentContext>${componentContext}</ComponentContext>\\n<UserContext>${userContext || \"\"}</UserContext>\\n<Value>\\n${inputValue}</Value>`\r\n}","import { SchemaNode, UISchema } from \"./types\";\r\n\r\n/**\r\n * Utility class for parsing UISchema from stream.\r\n */\r\nexport class ResponseParser {\r\n buffer = \"\"; // unflushed existing deltas w/o newline\r\n \r\n // schema assembled thus far\r\n schema: UISchema = {\r\n childrenMap: {},\r\n componentMap: {},\r\n root: null\r\n }\r\n\r\n /**\r\n * Update schema with latest data chunk.\r\n * \r\n * Handles multiline input gracefully; can be used to load entire schemas from cache.\r\n * @param delta delta from stream.\r\n */\r\n addDelta(delta: string) {\r\n this.buffer += delta;\r\n const split = this.buffer.split(\"\\n\")\r\n if (split.length > 1) {\r\n split.slice(0, split.length - 1).forEach((line) => this.handleLine(line));\r\n this.buffer = split[split.length - 1];\r\n }\r\n }\r\n\r\n /**\r\n * Parses a single line (full JSON object) and updates schema.\r\n * Generally should not be used when streaming data.\r\n */\r\n handleLine(line: string) {\r\n try {\r\n const node: SchemaNode = JSON.parse(line);\r\n\r\n const { childrenMap, componentMap } = this.schema;\r\n\r\n componentMap[node.id] = node;\r\n if (node.parentId === null) {\r\n this.schema.root = node;\r\n } else {\r\n if (!childrenMap[node.parentId]) childrenMap[node.parentId] = []\r\n childrenMap[node.parentId].push(node.id)\r\n }\r\n } catch (err) { /* probably markdown or generation inconsistency */ }\r\n }\r\n\r\n /**\r\n * Clears the buffer and handles any remaining information within.\r\n */\r\n finish(){\r\n this.handleLine(this.buffer);\r\n this.buffer = \"\";\r\n }\r\n}"],"mappings":"AAOO,SAASA,EAAqBC,EAAgD,CACjF,OAAOA,EAAkB,OAAO,CAACC,EAAwDC,IAClF,OAAOA,GAAS,UACfD,EAAIC,CAAI,EAAIA,EACLD,IAGXA,EAAIC,EAAK,IAAI,EAAIA,EAAK,UACfD,GACR,CAAC,CAAC,CACT,CAKO,SAASE,EAAe,CAC3B,MAAAC,EAAO,WAAAC,EAAY,KAAAC,CACvB,EAA0B,CACtB,IAAMN,GAAoBK,GAAA,YAAAA,EAAY,IAAKE,GACpC,OAAOA,GAAS,SAAiBA,EAC7BA,EAAK,MACb,KAAK,OAAQ,GAEVC,EAAmBH,GAAA,YAAAA,EAAY,OAAQE,GAAkC,OAAOA,GAAS,UACzFE,GAAmBD,GAAA,YAAAA,EAAkB,IAAKD,GACxCA,EAAK,QAGG,GAAGA,EAAK,IAAI,YAAYA,EAAK,KAAK,cAAcA,EAAK,OAAO,IAF5D,GAAGA,EAAK,IAAI,YAAYA,EAAK,KAAK,KAI/C,KAAK,OAAQ,GAEVG,EAAcJ,EACdK,EAAa,KAAK,UAAUP,CAAK,EAEvC,MAAO,sBAAsBJ,CAAiB;AAAA,oBAA2CS,CAAgB;AAAA,eAAqCC,GAAe,EAAE;AAAA;AAAA,EAA4BC,CAAU,UACzM,CCtCO,IAAMC,EAAN,KAAqB,CACxB,OAAS,GAGT,OAAmB,CACf,YAAa,CAAC,EACd,aAAc,CAAC,EACf,KAAM,IACV,EAQA,SAASC,EAAe,CACpB,KAAK,QAAUA,EACf,IAAMC,EAAQ,KAAK,OAAO,MAAM;AAAA,CAAI,EAChCA,EAAM,OAAS,IACfA,EAAM,MAAM,EAAGA,EAAM,OAAS,CAAC,EAAE,QAASC,GAAS,KAAK,WAAWA,CAAI,CAAC,EACxE,KAAK,OAASD,EAAMA,EAAM,OAAS,CAAC,EAE5C,CAMA,WAAWC,EAAc,CACrB,GAAI,CACA,IAAMC,EAAmB,KAAK,MAAMD,CAAI,EAElC,CAAE,YAAAE,EAAa,aAAAC,CAAa,EAAI,KAAK,OAE3CA,EAAaF,EAAK,EAAE,EAAIA,EACpBA,EAAK,WAAa,KAClB,KAAK,OAAO,KAAOA,GAEdC,EAAYD,EAAK,QAAQ,IAAGC,EAAYD,EAAK,QAAQ,EAAI,CAAC,GAC/DC,EAAYD,EAAK,QAAQ,EAAE,KAAKA,EAAK,EAAE,EAE/C,MAAc,CAAsD,CACxE,CAKA,QAAQ,CACJ,KAAK,WAAW,KAAK,MAAM,EAC3B,KAAK,OAAS,EAClB,CACJ","names":["generateComponentMap","allowedComponents","acc","curr","constructInput","value","components","hint","item","customComponents","componentContext","userContext","inputValue","ResponseParser","delta","split","line","node","childrenMap","componentMap"]}
|
package/dist/metafile-esm.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"inputs":{"src/types.ts":{"bytes":583,"imports":[],"format":"esm"},"src/util.ts":{"bytes":1656,"imports":[{"path":"./templates/GeneratedUI","kind":"import-statement","external":true},{"path":"./types","kind":"import-statement","external":true}],"format":"esm"},"src/ResponseParser.ts":{"bytes":
|
|
1
|
+
{"inputs":{"src/types.ts":{"bytes":583,"imports":[],"format":"esm"},"src/util.ts":{"bytes":1656,"imports":[{"path":"./templates/GeneratedUI","kind":"import-statement","external":true},{"path":"./types","kind":"import-statement","external":true}],"format":"esm"},"src/ResponseParser.ts":{"bytes":1744,"imports":[{"path":"./types","kind":"import-statement","external":true}],"format":"esm"},"src/index.ts":{"bytes":84,"imports":[{"path":"src/types.ts","kind":"import-statement","original":"./types"},{"path":"src/util.ts","kind":"import-statement","original":"./util"},{"path":"src/ResponseParser.ts","kind":"import-statement","original":"./ResponseParser"}],"format":"esm"},"src/client/Renderer.tsx":{"bytes":3397,"imports":[{"path":"react","kind":"import-statement","external":true},{"path":"../types","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true}],"format":"esm"},"src/client/GeneratedClient.tsx":{"bytes":1552,"imports":[{"path":"@ai-sdk/rsc","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"src/client/Renderer.tsx","kind":"import-statement","original":"./Renderer"},{"path":"src/ResponseParser.ts","kind":"import-statement","original":"../ResponseParser"},{"path":"../types","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true}],"format":"esm"},"src/client.ts":{"bytes":92,"imports":[{"path":"src/client/GeneratedClient.tsx","kind":"import-statement","original":"./client/GeneratedClient"},{"path":"src/client/Renderer.tsx","kind":"import-statement","original":"./client/Renderer"}],"format":"esm"},"src/bin/cli_util.mjs":{"bytes":115,"imports":[{"path":"chalk","kind":"import-statement","external":true}],"format":"esm"},"src/bin/commands/init.mjs":{"bytes":3700,"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"child_process","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"src/bin/cli_util.mjs","kind":"import-statement","original":"../cli_util.mjs"},{"path":"url","kind":"import-statement","external":true}],"format":"esm"},"src/bin/commands/generate.mjs":{"bytes":2933,"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"react-docgen-typescript","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true},{"path":"src/bin/cli_util.mjs","kind":"import-statement","original":"../cli_util.mjs"}],"format":"esm"},"src/bin/cli.mjs":{"bytes":482,"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"src/bin/commands/init.mjs","kind":"import-statement","original":"./commands/init.mjs"},{"path":"src/bin/commands/generate.mjs","kind":"import-statement","original":"./commands/generate.mjs"}],"format":"esm"}},"outputs":{"dist/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":5351},"dist/index.mjs":{"imports":[],"exports":["ResponseParser","constructInput","generateComponentMap"],"entryPoint":"src/index.ts","inputs":{"src/index.ts":{"bytesInOutput":0},"src/util.ts":{"bytesInOutput":578},"src/ResponseParser.ts":{"bytesInOutput":473}},"bytes":1126},"dist/client.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":11337},"dist/client.mjs":{"imports":[{"path":"@ai-sdk/rsc","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true},{"path":"react","kind":"import-statement","external":true},{"path":"react/jsx-runtime","kind":"import-statement","external":true}],"exports":["GeneratedClient","Renderer"],"entryPoint":"src/client.ts","inputs":{"src/client/GeneratedClient.tsx":{"bytesInOutput":595},"src/client/Renderer.tsx":{"bytesInOutput":1153},"src/ResponseParser.ts":{"bytesInOutput":473},"src/client.ts":{"bytesInOutput":0}},"bytes":2278},"dist/bin/cli.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":12417},"dist/bin/cli.mjs":{"imports":[{"path":"commander","kind":"import-statement","external":true},{"path":"commander","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"child_process","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"url","kind":"import-statement","external":true},{"path":"commander","kind":"import-statement","external":true},{"path":"path","kind":"import-statement","external":true},{"path":"react-docgen-typescript","kind":"import-statement","external":true},{"path":"prompts","kind":"import-statement","external":true},{"path":"chalk","kind":"import-statement","external":true},{"path":"fs-extra","kind":"import-statement","external":true}],"exports":[],"entryPoint":"src/bin/cli.mjs","inputs":{"src/bin/cli.mjs":{"bytesInOutput":250},"src/bin/commands/init.mjs":{"bytesInOutput":1851},"src/bin/cli_util.mjs":{"bytesInOutput":78},"src/bin/commands/generate.mjs":{"bytesInOutput":1443}},"bytes":3643}}}
|
|
@@ -31,7 +31,7 @@ export interface GeneratedContentProps {
|
|
|
31
31
|
export async function GeneratedUI(props: GeneratedContentProps) {
|
|
32
32
|
const input = constructInput(props);
|
|
33
33
|
|
|
34
|
-
const { value, model, components, cached, onGenerate } = props;
|
|
34
|
+
const { value, model, components, placeholder, cached, onGenerate } = props;
|
|
35
35
|
|
|
36
36
|
const allowedComponents = generateComponentMap(components || []);
|
|
37
37
|
|
|
@@ -72,5 +72,5 @@ export async function GeneratedUI(props: GeneratedContentProps) {
|
|
|
72
72
|
if(onGenerate) onGenerate(total);
|
|
73
73
|
})()
|
|
74
74
|
|
|
75
|
-
return <GeneratedClient value={value} allowedComponents={allowedComponents} inputStream={stream.value} />
|
|
75
|
+
return <GeneratedClient value={value} allowedComponents={allowedComponents} inputStream={stream.value} placeholder={placeholder} />
|
|
76
76
|
}
|
package/dist/templates/spec.md
CHANGED
|
@@ -19,7 +19,7 @@ type UINode = {
|
|
|
19
19
|
content?: string | { "$bind": string }; // Optional text content or data binding
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
Output
|
|
22
|
+
Output visually (depth first). Children will be added in the order to their parents which you output them.
|
|
23
23
|
Example: Output the Container, then the Header, then the Header's text, then the Footer.
|
|
24
24
|
|
|
25
25
|
To display a raw text node, set type = "TEXT".
|
|
@@ -48,7 +48,7 @@ In the example above, card_1 is the template that repeats for every author. It s
|
|
|
48
48
|
<input_processing_rules>
|
|
49
49
|
1. Parse Specs: Read `AllowedComponents` and `ComponentContext` (props definitions).
|
|
50
50
|
* `AllowedComponents` is a comma-separated list, lowercase for Native HTML tags, Uppercase for Custom React Components. If none are provided, you can use any HTML tag. If they are, only use them to the best of your ability.
|
|
51
|
-
* `ComponentContext` defines the Typescript interface for custom components. 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. DO NOT hallucinate props. Use the details to better your
|
|
51
|
+
* `ComponentContext` defines the Typescript interface for custom components. 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. DO NOT hallucinate props. Use the details to better your understanding of how to generate the UI.
|
|
52
52
|
2. Parse Context: Read `UserContext` for specific design requests.
|
|
53
53
|
3. Parse Data: Analyze `Value` to determine structure.
|
|
54
54
|
</input_processing_rules>
|
package/dist/templates/spec.ts
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IMPORTANT:
|
|
3
|
+
* Edit *this file* to change the default system prompt.
|
|
4
|
+
* spec.md is provided for ease of reading; editing it will not affect the prompt.
|
|
5
|
+
*/
|
|
6
|
+
|
|
1
7
|
const spec = `<system_persona>
|
|
2
8
|
You are the UI Stream Engine. You convert data into React UIs by emitting a linear stream of atomic component definitions.
|
|
3
9
|
</system_persona>
|
|
@@ -19,7 +25,7 @@ type UINode = {
|
|
|
19
25
|
content?: string | { "$bind": string }; // Optional text content or data binding
|
|
20
26
|
}
|
|
21
27
|
|
|
22
|
-
Output
|
|
28
|
+
Output visually (depth first). Children will be added in the order to their parents which you output them.
|
|
23
29
|
Example: Output the Container, then the Header, then the Header's text, then the Footer.
|
|
24
30
|
|
|
25
31
|
To display a raw text node, set type = "TEXT".
|
|
@@ -48,7 +54,7 @@ In the example above, card_1 is the template that repeats for every author. It s
|
|
|
48
54
|
<input_processing_rules>
|
|
49
55
|
1. Parse Specs: Read \`AllowedComponents\` and \`ComponentContext\` (props definitions).
|
|
50
56
|
* \`AllowedComponents\` is a comma-separated list, lowercase for Native HTML tags, Uppercase for Custom React Components. If none are provided, you can use any HTML tag. If they are, only use them to the best of your ability.
|
|
51
|
-
* \`ComponentContext\` defines the Typescript interface for custom components. 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. DO NOT hallucinate props. Use the details to better your
|
|
57
|
+
* \`ComponentContext\` defines the Typescript interface for custom components. 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. DO NOT hallucinate props. Use the details to better your understanding of how to generate the UI.
|
|
52
58
|
2. Parse Context: Read \`UserContext\` for specific design requests.
|
|
53
59
|
3. Parse Data: Analyze \`Value\` to determine structure.
|
|
54
60
|
</input_processing_rules>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "getsyntux",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "The declarative generative-UI library.",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": {
|
|
@@ -33,8 +33,10 @@
|
|
|
33
33
|
"@types/react": "^19.2.7",
|
|
34
34
|
"ai": "^6.0.3",
|
|
35
35
|
"chalk": "^5.6.2",
|
|
36
|
+
"commander": "^14.0.2",
|
|
36
37
|
"fs-extra": "^11.3.3",
|
|
37
38
|
"prompts": "^2.4.2",
|
|
39
|
+
"react-docgen-typescript": "^2.4.0",
|
|
38
40
|
"tsup": "^8.5.1",
|
|
39
41
|
"typescript": "^5.9.3"
|
|
40
42
|
},
|
|
@@ -48,7 +50,7 @@
|
|
|
48
50
|
],
|
|
49
51
|
"devDependencies": {
|
|
50
52
|
"@ai-sdk/anthropic": "^3.0.1",
|
|
51
|
-
"esbuild-plugin-preserve-directives": "^0.0.
|
|
53
|
+
"esbuild-plugin-preserve-directives": "^0.0.7",
|
|
52
54
|
"tsx": "^4.21.0"
|
|
53
55
|
}
|
|
54
56
|
}
|