getsyntux 0.2.1 → 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 CHANGED
@@ -18,6 +18,47 @@ https://github.com/user-attachments/assets/a930d35d-92ab-45f4-9f71-f7bc0380c4f1
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,50 +89,77 @@ export default function Home(){
48
89
  }
49
90
  ```
50
91
 
51
- <sup>Note: <i>syntux</i> is built for Next.js. It likely works on other React frameworks, but isn't guaranteed.</sup>
52
-
53
- ---
54
-
55
- ### Installation
92
+ Use custom React components:
56
93
 
57
- In the root of your project:
94
+ ```jsx
95
+ import { CustomOne, CustomTwo } from '@/my_components'
96
+ export default function Home(){
97
+ const valueToDisplay = { ... };
58
98
 
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
+ }
59
104
  ```
60
- $ npx getsyntux@latest
61
- ```
62
-
63
- This will automatically install the required components in the `lib/getsyntux` folder.
64
105
 
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
- **How does generation work?**
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
  ![](https://raw.githubusercontent.com/puffinsoft/syntux/HEAD/docs/images/workflow.png)
122
+ </details>
79
123
 
124
+ <details>
125
+ <summary>How does caching work?</summary>
80
126
 
81
- Generated designs are designed to be *reusable* and *cacheable*.
127
+ The generated UI is determined by the React Interface Schema (see the above question).
82
128
 
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.
129
+ Thus, if the same schema is provided, the same UI will be generated.
84
130
 
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/templates/spec.md).
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
- Non-stateful components should be wrapped in stateful components, then passed to *syntux* to generate.
139
+ Generating state is an anti-pattern and leads to poorly performing, insecure applications.
140
+
141
+ If you need to handle state, wrap non-stateful components in stateful ones, then pass those as custom components to *syntux*.
142
+ </details>
143
+
144
+ <details>
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`.
148
+
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).
150
+
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
+ ```
93
161
 
94
- Dynamic state generation violates the semi-deterministic paradigm of <i>syntux</i>, and is thus not supported by design.
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).
95
163
  </details>
96
164
 
97
165
  ---
@@ -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
- const __filename$1 = fileURLToPath(import.meta.url);
10
- const __dirname$1 = dirname(__filename$1);
11
-
12
- function getPackageManager(root) {
13
- if (fs.existsSync(path.join(root, 'yarn.lock'))) return 'yarn';
14
- if (fs.existsSync(path.join(root, 'pnpm-lock.yaml'))) return 'pnpm';
15
- return 'npm';
16
- }
17
-
18
- function getInstallCommand(manager) {
19
- if (manager === "yarn") return "yarn add getsyntux";
20
- if (manager === "pnpm") return "pnpm add getsyntux";
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
- if (response.install !== 0) {
52
- console.log(chalk.magenta('getsyntux') + ': installation cancelled.');
53
- process.exit(0);
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
- try {
57
- execSync(command, { stdio: 'inherit' });
58
- console.log(chalk.magenta('getsyntux') + ': installed from ' + chalk.green(packageManager) + ' successfully.');
59
- } catch (error) {
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
- const templateDir = path.resolve(__dirname$1, '../templates');
66
- const targetDir = path.resolve(process.cwd(), 'lib/getsyntux');
36
+ /**
37
+ * verifying
38
+ */
67
39
 
68
- if (!fs.existsSync(templateDir)) {
69
- console.log(chalk.magenta('getsyntux') + ': ' + chalk.red("failed to find template directory. This is not your fault."));
70
- process.exit(1);
71
- }
40
+ const userRoot = process.cwd();
41
+ const packageJsonPath = path.join(userRoot, 'package.json');
72
42
 
73
- console.log(chalk.magenta('getsyntux') + ': generating files...');
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
- if(fs.existsSync(targetDir)){
76
- const files = fs.readdirSync(targetDir);
77
- if(files.length > 0){
78
- console.log(chalk.magenta('getsyntux') + `: target directory lib/getsyntux already contains files.`);
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: 'copy',
82
- message: `Empty directory?`,
66
+ name: 'install',
67
+ message: `Run ${command}?`,
83
68
  choices: [{ title: 'Yes' }, { title: 'No' }],
84
69
  });
85
-
86
- if (response.copy !== 0) {
87
- console.log(chalk.magenta('getsyntux') + ': installation cancelled.');
70
+
71
+ if (response.install !== 0) {
72
+ log('installation cancelled.');
88
73
  process.exit(0);
89
74
  }
90
75
 
91
- fs.emptyDirSync(targetDir);
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
- fs.copySync(templateDir, targetDir, {
96
- overwrite: true,
97
- errorOnExist: false
98
- });
99
- console.log(chalk.magenta('getsyntux') + ': ' + chalk.green('installation complete.'));
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 n from"fs-extra";import s,{dirname as m}from"path";import{execSync as p}from"child_process";import r from"prompts";import e from"chalk";import{fileURLToPath as y}from"url";var d=y(import.meta.url),u=m(d);function f(t){return n.existsSync(s.join(t,"yarn.lock"))?"yarn":n.existsSync(s.join(t,"pnpm-lock.yaml"))?"pnpm":"npm"}function x(t){return t==="yarn"?"yarn add getsyntux":t==="pnpm"?"pnpm add getsyntux":"npm install getsyntux"}var l=process.cwd(),c=s.join(l,"package.json");n.existsSync(c)||(console.log(e.magenta("getsyntux")+": "+e.red("Failed to find package.json. Run this command from your project root.")),process.exit(1));var i=JSON.parse(n.readFileSync(c,"utf8")),h={...i.dependencies,...i.devDependencies};if(h.getsyntux)console.log(e.magenta("getsyntux")+": library has already been installed. Continuing...");else{console.log(e.magenta("getsyntux")+": library not detected in package.json. Please install to continue...");let t=f(l),a=x(t);(await r({type:"select",name:"install",message:`Run ${a}?`,choices:[{title:"Yes"},{title:"No"}]})).install!==0&&(console.log(e.magenta("getsyntux")+": installation cancelled."),process.exit(0));try{p(a,{stdio:"inherit"}),console.log(e.magenta("getsyntux")+": installed from "+e.green(t)+" successfully.")}catch{console.log(e.magenta("getsyntux")+": installation "+e.red("failed")+" from "+t+"."),process.exit(1)}}var g=s.resolve(u,"../templates"),o=s.resolve(process.cwd(),"lib/getsyntux");n.existsSync(g)||(console.log(e.magenta("getsyntux")+": "+e.red("failed to find template directory. This is not your fault.")),process.exit(1));console.log(e.magenta("getsyntux")+": generating files...");n.existsSync(o)&&n.readdirSync(o).length>0&&(console.log(e.magenta("getsyntux")+": target directory lib/getsyntux already contains files."),(await r({type:"select",name:"copy",message:"Empty directory?",choices:[{title:"Yes"},{title:"No"}]})).copy!==0&&(console.log(e.magenta("getsyntux")+": installation cancelled."),process.exit(0)),n.emptyDirSync(o));n.copySync(g,o,{overwrite:!0,errorOnExist:!1});console.log(e.magenta("getsyntux")+": "+e.green("installation complete."));
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
@@ -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
@@ -3,6 +3,9 @@ import { StreamableValue } from '@ai-sdk/rsc';
3
3
  import react__default, { JSX, ComponentType } from 'react';
4
4
  import { C as ComponentMap, b as ChildrenMap } from './types-DejIW5JZ.mjs';
5
5
 
6
+ /**
7
+ * Client wrapper for Renderer that handles streaming and parsing with server.
8
+ */
6
9
  declare function GeneratedClient({ value, allowedComponents, inputStream, placeholder }: {
7
10
  value: any;
8
11
  allowedComponents: Record<string, react__default.ComponentType<any> | string>;
@@ -18,6 +21,9 @@ interface RendererProps {
18
21
  global: any;
19
22
  local: any;
20
23
  }
24
+ /**
25
+ * Renders a UISchema recursively, in accordance to the spec.
26
+ */
21
27
  declare function Renderer(props: RendererProps): react_jsx_runtime.JSX.Element;
22
28
 
23
29
  export { GeneratedClient, Renderer, type RendererProps };
@@ -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, { JSX, 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 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 ? <Renderer id={schema.root.id} componentMap={schema.componentMap} childrenMap={schema.childrenMap} allowedComponents={allowedComponents} global={value} local={value} /> : <>{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\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":"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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"]}
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
 
@@ -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 = \"\";\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":"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,CCzCO,IAAMC,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","names":["generateComponentMap","allowedComponents","acc","curr","constructInput","value","components","hint","item","customComponents","componentContext","userContext","inputValue","ResponseParser","delta","split","line","node","childrenMap","componentMap"]}
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"]}
@@ -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":1163,"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":3047,"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":1444,"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.mjs":{"bytes":3494,"imports":[{"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":"url","kind":"import-statement","external":true}],"format":"esm"}},"outputs":{"dist/index.mjs.map":{"imports":[],"exports":[],"inputs":{},"bytes":4734},"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":10224},"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":6062},"dist/bin/cli.mjs":{"imports":[{"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":"url","kind":"import-statement","external":true}],"exports":[],"entryPoint":"src/bin/cli.mjs","inputs":{"src/bin/cli.mjs":{"bytesInOutput":2132}},"bytes":2153}}}
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}}}
@@ -19,7 +19,7 @@ type UINode = {
19
19
  content?: string | { "$bind": string }; // Optional text content or data binding
20
20
  }
21
21
 
22
- Output visualy (depth first). Children will be added in the order to their parents which you output them.
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 understand of how to generate the UI.
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>
@@ -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 visualy (depth first). Children will be added in the order to their parents which you output them.
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 understand of how to generate the UI.
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.2.1",
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.11",
53
+ "esbuild-plugin-preserve-directives": "^0.0.7",
52
54
  "tsx": "^4.21.0"
53
55
  }
54
56
  }