@embeddables/cli 0.8.0 → 0.8.2

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.
Files changed (235) hide show
  1. package/dist/auth/index.d.ts +43 -0
  2. package/dist/auth/index.d.ts.map +1 -0
  3. package/dist/auth/index.js +102 -0
  4. package/dist/cli.d.ts +2 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +210 -0
  7. package/dist/commands/branch.d.ts +4 -0
  8. package/dist/commands/branch.d.ts.map +1 -0
  9. package/dist/commands/branch.js +67 -0
  10. package/dist/commands/build-workbench.d.ts +5 -0
  11. package/dist/commands/build-workbench.d.ts.map +1 -0
  12. package/dist/commands/build-workbench.js +116 -0
  13. package/dist/commands/build.d.ts +8 -0
  14. package/dist/commands/build.d.ts.map +1 -0
  15. package/dist/commands/build.js +60 -0
  16. package/dist/commands/builder-open.d.ts +4 -0
  17. package/dist/commands/builder-open.d.ts.map +1 -0
  18. package/dist/commands/builder-open.js +74 -0
  19. package/dist/commands/dev.d.ts +12 -0
  20. package/dist/commands/dev.d.ts.map +1 -0
  21. package/dist/commands/dev.js +226 -0
  22. package/dist/commands/experiments-connect.d.ts +6 -0
  23. package/dist/commands/experiments-connect.d.ts.map +1 -0
  24. package/dist/commands/experiments-connect.js +140 -0
  25. package/dist/commands/init.d.ts +5 -0
  26. package/dist/commands/init.d.ts.map +1 -0
  27. package/dist/commands/init.js +384 -0
  28. package/dist/commands/inspect.d.ts +9 -0
  29. package/dist/commands/inspect.d.ts.map +1 -0
  30. package/dist/commands/inspect.js +293 -0
  31. package/dist/commands/login.d.ts +2 -0
  32. package/dist/commands/login.d.ts.map +1 -0
  33. package/dist/commands/login.js +117 -0
  34. package/dist/commands/logout.d.ts +2 -0
  35. package/dist/commands/logout.d.ts.map +1 -0
  36. package/dist/commands/logout.js +19 -0
  37. package/dist/commands/pull.d.ts +16 -0
  38. package/dist/commands/pull.d.ts.map +1 -0
  39. package/dist/commands/pull.js +395 -0
  40. package/dist/commands/save.d.ts +30 -0
  41. package/dist/commands/save.d.ts.map +1 -0
  42. package/dist/commands/save.js +597 -0
  43. package/dist/commands/upgrade.d.ts +2 -0
  44. package/dist/commands/upgrade.d.ts.map +1 -0
  45. package/dist/commands/upgrade.js +50 -0
  46. package/dist/compiler/errors.d.ts +20 -0
  47. package/dist/compiler/errors.d.ts.map +1 -0
  48. package/dist/compiler/errors.js +35 -0
  49. package/dist/compiler/evalStatic.d.ts +3 -0
  50. package/dist/compiler/evalStatic.d.ts.map +1 -0
  51. package/dist/compiler/evalStatic.js +57 -0
  52. package/dist/compiler/helpers/duplicateIds.d.ts +9 -0
  53. package/dist/compiler/helpers/duplicateIds.d.ts.map +1 -0
  54. package/dist/compiler/helpers/duplicateIds.js +71 -0
  55. package/dist/compiler/helpers/numericLeadingKeys.d.ts +8 -0
  56. package/dist/compiler/helpers/numericLeadingKeys.d.ts.map +1 -0
  57. package/dist/compiler/helpers/numericLeadingKeys.js +17 -0
  58. package/dist/compiler/index.d.ts +18 -0
  59. package/dist/compiler/index.d.ts.map +1 -0
  60. package/dist/compiler/index.js +1272 -0
  61. package/dist/compiler/parsePage.d.ts +15 -0
  62. package/dist/compiler/parsePage.d.ts.map +1 -0
  63. package/dist/compiler/parsePage.js +654 -0
  64. package/dist/compiler/registry.d.ts +4 -0
  65. package/dist/compiler/registry.d.ts.map +1 -0
  66. package/dist/compiler/registry.js +44 -0
  67. package/dist/compiler/reverse.d.ts +23 -0
  68. package/dist/compiler/reverse.d.ts.map +1 -0
  69. package/dist/compiler/reverse.js +1938 -0
  70. package/dist/compiler/types.d.ts +21 -0
  71. package/dist/compiler/types.d.ts.map +1 -0
  72. package/dist/compiler/types.js +1 -0
  73. package/dist/components/index.d.ts +21 -0
  74. package/dist/components/index.d.ts.map +1 -0
  75. package/dist/components/index.js +21 -0
  76. package/dist/components/primitives/BaseComponent.d.ts +33 -0
  77. package/dist/components/primitives/BaseComponent.d.ts.map +1 -0
  78. package/dist/components/primitives/BaseComponent.js +26 -0
  79. package/dist/components/primitives/BookMeeting.d.ts +18 -0
  80. package/dist/components/primitives/BookMeeting.d.ts.map +1 -0
  81. package/dist/components/primitives/BookMeeting.js +5 -0
  82. package/dist/components/primitives/Chart.d.ts +41 -0
  83. package/dist/components/primitives/Chart.d.ts.map +1 -0
  84. package/dist/components/primitives/Chart.js +5 -0
  85. package/dist/components/primitives/Container.d.ts +8 -0
  86. package/dist/components/primitives/Container.d.ts.map +1 -0
  87. package/dist/components/primitives/Container.js +5 -0
  88. package/dist/components/primitives/CustomButton.d.ts +37 -0
  89. package/dist/components/primitives/CustomButton.d.ts.map +1 -0
  90. package/dist/components/primitives/CustomButton.js +10 -0
  91. package/dist/components/primitives/CustomHTML.d.ts +8 -0
  92. package/dist/components/primitives/CustomHTML.d.ts.map +1 -0
  93. package/dist/components/primitives/CustomHTML.js +5 -0
  94. package/dist/components/primitives/FileUpload.d.ts +18 -0
  95. package/dist/components/primitives/FileUpload.d.ts.map +1 -0
  96. package/dist/components/primitives/FileUpload.js +16 -0
  97. package/dist/components/primitives/InputBox.d.ts +34 -0
  98. package/dist/components/primitives/InputBox.d.ts.map +1 -0
  99. package/dist/components/primitives/InputBox.js +25 -0
  100. package/dist/components/primitives/Lottie.d.ts +11 -0
  101. package/dist/components/primitives/Lottie.d.ts.map +1 -0
  102. package/dist/components/primitives/Lottie.js +5 -0
  103. package/dist/components/primitives/MediaEmbed.d.ts +13 -0
  104. package/dist/components/primitives/MediaEmbed.d.ts.map +1 -0
  105. package/dist/components/primitives/MediaEmbed.js +6 -0
  106. package/dist/components/primitives/MediaImage.d.ts +8 -0
  107. package/dist/components/primitives/MediaImage.d.ts.map +1 -0
  108. package/dist/components/primitives/MediaImage.js +5 -0
  109. package/dist/components/primitives/OptionSelector.d.ts +38 -0
  110. package/dist/components/primitives/OptionSelector.d.ts.map +1 -0
  111. package/dist/components/primitives/OptionSelector.js +8 -0
  112. package/dist/components/primitives/PaypalCheckout.d.ts +25 -0
  113. package/dist/components/primitives/PaypalCheckout.d.ts.map +1 -0
  114. package/dist/components/primitives/PaypalCheckout.js +5 -0
  115. package/dist/components/primitives/PlainText.d.ts +6 -0
  116. package/dist/components/primitives/PlainText.d.ts.map +1 -0
  117. package/dist/components/primitives/PlainText.js +5 -0
  118. package/dist/components/primitives/ProgressBar.d.ts +15 -0
  119. package/dist/components/primitives/ProgressBar.d.ts.map +1 -0
  120. package/dist/components/primitives/ProgressBar.js +5 -0
  121. package/dist/components/primitives/RichText.d.ts +6 -0
  122. package/dist/components/primitives/RichText.d.ts.map +1 -0
  123. package/dist/components/primitives/RichText.js +5 -0
  124. package/dist/components/primitives/RichTextMarkdown.d.ts +6 -0
  125. package/dist/components/primitives/RichTextMarkdown.d.ts.map +1 -0
  126. package/dist/components/primitives/RichTextMarkdown.js +5 -0
  127. package/dist/components/primitives/Rive.d.ts +16 -0
  128. package/dist/components/primitives/Rive.d.ts.map +1 -0
  129. package/dist/components/primitives/Rive.js +8 -0
  130. package/dist/components/primitives/StripeCheckout.d.ts +52 -0
  131. package/dist/components/primitives/StripeCheckout.d.ts.map +1 -0
  132. package/dist/components/primitives/StripeCheckout.js +5 -0
  133. package/dist/components/primitives/StripeCheckout2.d.ts +30 -0
  134. package/dist/components/primitives/StripeCheckout2.d.ts.map +1 -0
  135. package/dist/components/primitives/StripeCheckout2.js +7 -0
  136. package/dist/config/index.d.ts +23 -0
  137. package/dist/config/index.d.ts.map +1 -0
  138. package/dist/config/index.js +42 -0
  139. package/dist/constants.d.ts +9 -0
  140. package/dist/constants.d.ts.map +1 -0
  141. package/dist/constants.js +9 -0
  142. package/dist/helpers/dates.d.ts +5 -0
  143. package/dist/helpers/dates.d.ts.map +1 -0
  144. package/dist/helpers/dates.js +7 -0
  145. package/dist/helpers/json.d.ts +47 -0
  146. package/dist/helpers/json.d.ts.map +1 -0
  147. package/dist/helpers/json.js +622 -0
  148. package/dist/helpers/prompt.d.ts +15 -0
  149. package/dist/helpers/prompt.d.ts.map +1 -0
  150. package/dist/helpers/prompt.js +35 -0
  151. package/dist/helpers/utils.d.ts +13 -0
  152. package/dist/helpers/utils.d.ts.map +1 -0
  153. package/dist/helpers/utils.js +28 -0
  154. package/dist/logger.d.ts +11 -0
  155. package/dist/logger.d.ts.map +1 -0
  156. package/dist/logger.js +21 -0
  157. package/dist/patches/prompts-escape.d.ts +14 -0
  158. package/dist/patches/prompts-escape.d.ts.map +1 -0
  159. package/dist/patches/prompts-escape.js +23 -0
  160. package/dist/prompts/branches.d.ts +20 -0
  161. package/dist/prompts/branches.d.ts.map +1 -0
  162. package/dist/prompts/branches.js +86 -0
  163. package/dist/prompts/embeddables.d.ts +43 -0
  164. package/dist/prompts/embeddables.d.ts.map +1 -0
  165. package/dist/prompts/embeddables.js +200 -0
  166. package/dist/prompts/experiments.d.ts +28 -0
  167. package/dist/prompts/experiments.d.ts.map +1 -0
  168. package/dist/prompts/experiments.js +89 -0
  169. package/dist/prompts/index.d.ts +11 -0
  170. package/dist/prompts/index.d.ts.map +1 -0
  171. package/dist/prompts/index.js +6 -0
  172. package/dist/prompts/projects.d.ts +22 -0
  173. package/dist/prompts/projects.d.ts.map +1 -0
  174. package/dist/prompts/projects.js +92 -0
  175. package/dist/prompts/versions.d.ts +18 -0
  176. package/dist/prompts/versions.d.ts.map +1 -0
  177. package/dist/prompts/versions.js +95 -0
  178. package/dist/proxy/injectApiInterceptor.d.ts +6 -0
  179. package/dist/proxy/injectApiInterceptor.d.ts.map +1 -0
  180. package/dist/proxy/injectApiInterceptor.js +66 -0
  181. package/dist/proxy/injectReload.d.ts +2 -0
  182. package/dist/proxy/injectReload.d.ts.map +1 -0
  183. package/dist/proxy/injectReload.js +14 -0
  184. package/dist/proxy/injectWorkbench.d.ts +5 -0
  185. package/dist/proxy/injectWorkbench.d.ts.map +1 -0
  186. package/dist/proxy/injectWorkbench.js +22 -0
  187. package/dist/proxy/server.d.ts +11 -0
  188. package/dist/proxy/server.d.ts.map +1 -0
  189. package/dist/proxy/server.js +304 -0
  190. package/dist/proxy/sse.d.ts +5 -0
  191. package/dist/proxy/sse.d.ts.map +1 -0
  192. package/dist/proxy/sse.js +17 -0
  193. package/dist/sentry-context.d.ts +48 -0
  194. package/dist/sentry-context.d.ts.map +1 -0
  195. package/dist/sentry-context.js +156 -0
  196. package/dist/stdout.d.ts +61 -0
  197. package/dist/stdout.d.ts.map +1 -0
  198. package/dist/stdout.js +163 -0
  199. package/dist/types-builder.d.ts +800 -0
  200. package/dist/types-builder.d.ts.map +1 -0
  201. package/dist/types-builder.js +20 -0
  202. package/dist/workbench/ActionsPanel.d.ts +6 -0
  203. package/dist/workbench/ActionsPanel.d.ts.map +1 -0
  204. package/dist/workbench/ActionsPanel.js +47 -0
  205. package/dist/workbench/AutofillPanel.d.ts +6 -0
  206. package/dist/workbench/AutofillPanel.d.ts.map +1 -0
  207. package/dist/workbench/AutofillPanel.js +543 -0
  208. package/dist/workbench/ComputedFieldsPanel.d.ts +6 -0
  209. package/dist/workbench/ComputedFieldsPanel.d.ts.map +1 -0
  210. package/dist/workbench/ComputedFieldsPanel.js +31 -0
  211. package/dist/workbench/ExperimentsPanel.d.ts +6 -0
  212. package/dist/workbench/ExperimentsPanel.d.ts.map +1 -0
  213. package/dist/workbench/ExperimentsPanel.js +182 -0
  214. package/dist/workbench/FieldEditorPanel.d.ts +9 -0
  215. package/dist/workbench/FieldEditorPanel.d.ts.map +1 -0
  216. package/dist/workbench/FieldEditorPanel.js +650 -0
  217. package/dist/workbench/InspectorPanel.d.ts +6 -0
  218. package/dist/workbench/InspectorPanel.d.ts.map +1 -0
  219. package/dist/workbench/InspectorPanel.js +341 -0
  220. package/dist/workbench/PageNavigator.d.ts +6 -0
  221. package/dist/workbench/PageNavigator.d.ts.map +1 -0
  222. package/dist/workbench/PageNavigator.js +123 -0
  223. package/dist/workbench/SchemaPanel.d.ts +6 -0
  224. package/dist/workbench/SchemaPanel.d.ts.map +1 -0
  225. package/dist/workbench/SchemaPanel.js +222 -0
  226. package/dist/workbench/UserDataPanel.d.ts +6 -0
  227. package/dist/workbench/UserDataPanel.d.ts.map +1 -0
  228. package/dist/workbench/UserDataPanel.js +350 -0
  229. package/dist/workbench/WorkbenchApp.d.ts +7 -0
  230. package/dist/workbench/WorkbenchApp.d.ts.map +1 -0
  231. package/dist/workbench/WorkbenchApp.js +193 -0
  232. package/dist/workbench/index.d.ts +10 -0
  233. package/dist/workbench/index.d.ts.map +1 -0
  234. package/dist/workbench/index.js +44 -0
  235. package/package.json +2 -1
@@ -0,0 +1,15 @@
1
+ import type { ComponentJson, PageJson } from './types.js';
2
+ export declare function parsePageFromFile(args: {
3
+ code: string;
4
+ filePath: string;
5
+ pageKey: string;
6
+ }): PageJson;
7
+ /**
8
+ * Parses a global component file and returns the components.
9
+ * Similar to parsePageFromFile but simpler - no pageKey needed, just returns components.
10
+ */
11
+ export declare function parseGlobalComponentsFromFile(args: {
12
+ code: string;
13
+ filePath: string;
14
+ }): ComponentJson[];
15
+ //# sourceMappingURL=parsePage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parsePage.d.ts","sourceRoot":"","sources":["../../src/compiler/parsePage.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AAezD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE;IACtC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;CAChB,GAAG,QAAQ,CAuHX;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE;IAClD,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;CACjB,GAAG,aAAa,EAAE,CAqGlB"}
@@ -0,0 +1,654 @@
1
+ import { parse } from '@babel/parser';
2
+ import traverseImport from '@babel/traverse';
3
+ import { ALLOWED_PRIMITIVES, TYPE_MAP, DEFAULTS_BY_TYPE } from './registry.js';
4
+ import { CompileError } from './errors.js';
5
+ import { evalStatic } from './evalStatic.js';
6
+ const traverse = (traverseImport.default ?? traverseImport);
7
+ export function parsePageFromFile(args) {
8
+ let ast;
9
+ try {
10
+ ast = parse(args.code, {
11
+ sourceType: 'module',
12
+ plugins: ['typescript', 'jsx'],
13
+ sourceFilename: args.filePath,
14
+ });
15
+ }
16
+ catch (error) {
17
+ // Babel parser errors have loc property with line/column
18
+ const line = error.loc?.line ?? error.loc?.start?.line;
19
+ const column = error.loc?.column ?? error.loc?.start?.column;
20
+ throw new CompileError(error.message || 'Syntax error', {
21
+ file: args.filePath,
22
+ line,
23
+ column,
24
+ pageKey: args.pageKey,
25
+ });
26
+ }
27
+ // collect static consts in module scope + inside page function (v1: module scope only is fine)
28
+ const constEnv = new Map();
29
+ traverse(ast, {
30
+ VariableDeclarator(path) {
31
+ const id = path.node.id;
32
+ const init = path.node.init;
33
+ if (id.type === 'Identifier' && init) {
34
+ // only accept if init is statically evaluable
35
+ try {
36
+ const v = evalStatic(init, constEnv, args.filePath);
37
+ constEnv.set(id.name, v);
38
+ }
39
+ catch {
40
+ // ignore non-static consts
41
+ }
42
+ }
43
+ },
44
+ });
45
+ // find exported function and its return JSX + collect function declarations for custom_validation_function
46
+ // Supports both default exports (preferred) and named exports
47
+ let rootJsx = null;
48
+ let rootFragment = null;
49
+ const validationFunctionSource = new Map();
50
+ // Helper to extract JSX from a function body and collect inner function declarations
51
+ const extractJsxAndFunctions = (fnBody, code) => {
52
+ const ret = fnBody.body.find((s) => s.type === 'ReturnStatement');
53
+ const arg = ret?.argument;
54
+ if (arg) {
55
+ if (arg.type === 'JSXElement') {
56
+ rootJsx = arg;
57
+ }
58
+ else if (arg.type === 'JSXFragment') {
59
+ rootFragment = arg;
60
+ }
61
+ }
62
+ for (const stmt of fnBody.body) {
63
+ if (stmt.type === 'FunctionDeclaration' && stmt.id?.name) {
64
+ const start = stmt.start ?? 0;
65
+ const end = stmt.end ?? code.length;
66
+ validationFunctionSource.set(stmt.id.name, code.slice(start, end));
67
+ }
68
+ }
69
+ };
70
+ traverse(ast, {
71
+ // Handle: export default function PageName() { ... }
72
+ ExportDefaultDeclaration(path) {
73
+ const decl = path.node.declaration;
74
+ if (decl.type === 'FunctionDeclaration') {
75
+ extractJsxAndFunctions(decl.body, args.code);
76
+ }
77
+ },
78
+ // Handle: export function PageName() { ... } (legacy support)
79
+ ExportNamedDeclaration(path) {
80
+ const decl = path.node.declaration;
81
+ if (!decl)
82
+ return;
83
+ if (decl.type === 'FunctionDeclaration' && decl.id?.name) {
84
+ extractJsxAndFunctions(decl.body, args.code);
85
+ }
86
+ },
87
+ });
88
+ const components = [];
89
+ if (rootJsx) {
90
+ // Single root element
91
+ const tree = jsxToTree(rootJsx, constEnv, args.filePath, validationFunctionSource);
92
+ flatten(tree, null, components, args.pageKey, args.filePath);
93
+ }
94
+ else if (rootFragment) {
95
+ // Multiple root elements (fragment) - allow empty fragments for blank pages
96
+ const fragmentChildren = [];
97
+ const fragment = rootFragment;
98
+ for (const c of fragment.children) {
99
+ if (c.type === 'JSXElement') {
100
+ fragmentChildren.push(c);
101
+ }
102
+ }
103
+ // Allow blank pages - if fragment has no JSXElement children, components array stays empty
104
+ for (const child of fragmentChildren) {
105
+ const tree = jsxToTree(child, constEnv, args.filePath, validationFunctionSource);
106
+ flatten(tree, null, components, args.pageKey, args.filePath);
107
+ }
108
+ }
109
+ else {
110
+ // Allow blank pages - if no JSX found, components array stays empty
111
+ // This handles pages that return null, undefined, or have no return statement
112
+ }
113
+ return {
114
+ key: args.pageKey,
115
+ showNav: true,
116
+ tags: [],
117
+ id: `page_${args.pageKey}`,
118
+ components,
119
+ };
120
+ }
121
+ /**
122
+ * Parses a global component file and returns the components.
123
+ * Similar to parsePageFromFile but simpler - no pageKey needed, just returns components.
124
+ */
125
+ export function parseGlobalComponentsFromFile(args) {
126
+ let ast;
127
+ try {
128
+ ast = parse(args.code, {
129
+ sourceType: 'module',
130
+ plugins: ['typescript', 'jsx'],
131
+ sourceFilename: args.filePath,
132
+ });
133
+ }
134
+ catch (error) {
135
+ // Babel parser errors have loc property with line/column
136
+ const line = error.loc?.line ?? error.loc?.start?.line;
137
+ const column = error.loc?.column ?? error.loc?.start?.column;
138
+ throw new CompileError(error.message || 'Syntax error', {
139
+ file: args.filePath,
140
+ line,
141
+ column,
142
+ });
143
+ }
144
+ // collect static consts in module scope
145
+ const constEnv = new Map();
146
+ traverse(ast, {
147
+ VariableDeclarator(path) {
148
+ const id = path.node.id;
149
+ const init = path.node.init;
150
+ if (id.type === 'Identifier' && init) {
151
+ try {
152
+ const v = evalStatic(init, constEnv, args.filePath);
153
+ constEnv.set(id.name, v);
154
+ }
155
+ catch {
156
+ // ignore non-static consts
157
+ }
158
+ }
159
+ },
160
+ });
161
+ // find exported function and its return JSX + collect function declarations for custom_validation_function
162
+ let rootJsx = null;
163
+ let rootFragment = null;
164
+ const validationFunctionSource = new Map();
165
+ const extractJsxAndFunctions = (fnBody, code) => {
166
+ const ret = fnBody.body.find((s) => s.type === 'ReturnStatement');
167
+ const arg = ret?.argument;
168
+ if (arg) {
169
+ if (arg.type === 'JSXElement') {
170
+ rootJsx = arg;
171
+ }
172
+ else if (arg.type === 'JSXFragment') {
173
+ rootFragment = arg;
174
+ }
175
+ }
176
+ for (const stmt of fnBody.body) {
177
+ if (stmt.type === 'FunctionDeclaration' && stmt.id?.name) {
178
+ const start = stmt.start ?? 0;
179
+ const end = stmt.end ?? code.length;
180
+ validationFunctionSource.set(stmt.id.name, code.slice(start, end));
181
+ }
182
+ }
183
+ };
184
+ traverse(ast, {
185
+ ExportDefaultDeclaration(path) {
186
+ const decl = path.node.declaration;
187
+ if (decl.type === 'FunctionDeclaration') {
188
+ extractJsxAndFunctions(decl.body, args.code);
189
+ }
190
+ },
191
+ ExportNamedDeclaration(path) {
192
+ const decl = path.node.declaration;
193
+ if (!decl)
194
+ return;
195
+ if (decl.type === 'FunctionDeclaration' && decl.id?.name) {
196
+ extractJsxAndFunctions(decl.body, args.code);
197
+ }
198
+ },
199
+ });
200
+ const components = [];
201
+ if (rootJsx) {
202
+ const tree = jsxToTree(rootJsx, constEnv, args.filePath, validationFunctionSource);
203
+ flatten(tree, null, components, '', args.filePath);
204
+ }
205
+ else if (rootFragment) {
206
+ const fragmentChildren = [];
207
+ const fragment = rootFragment;
208
+ for (const c of fragment.children) {
209
+ if (c.type === 'JSXElement') {
210
+ fragmentChildren.push(c);
211
+ }
212
+ }
213
+ for (const child of fragmentChildren) {
214
+ const tree = jsxToTree(child, constEnv, args.filePath, validationFunctionSource);
215
+ flatten(tree, null, components, '', args.filePath);
216
+ }
217
+ }
218
+ return components;
219
+ }
220
+ function jsxToTree(el, constEnv, filePath, validationFunctionSource) {
221
+ const opening = el.openingElement;
222
+ const tagName = getJsxTagName(opening.name);
223
+ if (!ALLOWED_PRIMITIVES.has(tagName)) {
224
+ throw new CompileError(`Unknown/unsupported primitive <${tagName}>.`, loc(filePath, opening));
225
+ }
226
+ const jsonType = TYPE_MAP[tagName];
227
+ const attrs = attrsToProps(opening.attributes, constEnv, filePath, validationFunctionSource);
228
+ const id = requireString(attrs, 'id', filePath, opening);
229
+ const key = requireString(attrs, 'key', filePath, opening);
230
+ const tags = (attrs.tags ?? []);
231
+ if (!Array.isArray(tags) || tags.some((t) => typeof t !== 'string')) {
232
+ throw new CompileError(`Prop "tags" must be an array of strings.`, loc(filePath, opening));
233
+ }
234
+ delete attrs.id;
235
+ delete attrs.key;
236
+ delete attrs.tags;
237
+ // For CustomHTML, convert all children (including text) to HTML string
238
+ if (tagName === 'CustomHTML') {
239
+ // Check if there are any children (including text nodes and fragments)
240
+ const hasChildren = el.children.some((c) => c.type === 'JSXElement' ||
241
+ c.type === 'JSXFragment' ||
242
+ (c.type === 'JSXText' && c.value.trim().length > 0) ||
243
+ c.type === 'JSXExpressionContainer');
244
+ if (hasChildren) {
245
+ // Convert JSX children to HTML string
246
+ const htmlString = jsxChildrenToHTML(el.children, constEnv, filePath);
247
+ attrs.text = htmlString;
248
+ }
249
+ // Return with empty children array since we've converted them to HTML
250
+ return {
251
+ tag: tagName,
252
+ type: jsonType,
253
+ id,
254
+ key,
255
+ tags,
256
+ props: attrs,
257
+ children: [],
258
+ loc: loc(filePath, opening),
259
+ };
260
+ }
261
+ // children JSXElements only (ignore whitespace text nodes)
262
+ const children = el.children
263
+ .filter((c) => c.type === 'JSXElement')
264
+ .map((c) => jsxToTree(c, constEnv, filePath, validationFunctionSource));
265
+ // v1 rule: only Container can have children (CustomHTML handled above)
266
+ if (children.length > 0 && tagName !== 'Container') {
267
+ throw new CompileError(`<${tagName}> cannot have children. Only <Container> and <CustomHTML> may contain children.`, loc(filePath, opening));
268
+ }
269
+ // enforce OptionSelector uses buttons
270
+ if (tagName === 'OptionSelector' && 'options' in attrs) {
271
+ throw new CompileError(`OptionSelector does not support prop "options". Use "buttons".`, loc(filePath, opening));
272
+ }
273
+ return {
274
+ tag: tagName,
275
+ type: jsonType,
276
+ id,
277
+ key,
278
+ tags,
279
+ props: attrs,
280
+ children,
281
+ loc: loc(filePath, opening),
282
+ };
283
+ }
284
+ function flatten(node, parentId, out, pageKey, filePath) {
285
+ const base = {
286
+ type: node.type,
287
+ id: node.id,
288
+ key: node.key,
289
+ tags: node.tags,
290
+ };
291
+ if (parentId)
292
+ base.parent_id = parentId;
293
+ const defaults = DEFAULTS_BY_TYPE[node.type] ?? {};
294
+ // Extract extra props from props={...} (round-trip from reverse compiler) and merge into component
295
+ // Extract languages prop separately to expand into lang-- properties
296
+ const { props: extraProps, languages, ...restProps } = node.props;
297
+ const mergedExtra = extraProps != null && typeof extraProps === 'object' && !Array.isArray(extraProps)
298
+ ? extraProps
299
+ : {};
300
+ // Expand languages prop into flat lang--{langCode}--{attrKey} properties
301
+ const langProps = {};
302
+ if (languages != null && typeof languages === 'object' && !Array.isArray(languages)) {
303
+ for (const [langCode, attrs] of Object.entries(languages)) {
304
+ if (attrs != null && typeof attrs === 'object' && !Array.isArray(attrs)) {
305
+ for (const [attrKey, value] of Object.entries(attrs)) {
306
+ langProps[`lang--${langCode}--${attrKey}`] = value;
307
+ }
308
+ }
309
+ }
310
+ }
311
+ const json = {
312
+ ...base,
313
+ ...defaults,
314
+ ...restProps,
315
+ ...mergedExtra,
316
+ ...langProps,
317
+ };
318
+ // Helper to create errors with component context
319
+ const createError = (message, loc) => {
320
+ return new CompileError(message, {
321
+ ...loc,
322
+ pageKey,
323
+ componentId: node.id,
324
+ componentKey: node.key,
325
+ });
326
+ };
327
+ // Normalize OptionSelector buttons: generate IDs + defaults
328
+ if (json.type === 'OptionSelector') {
329
+ const buttons = json.buttons;
330
+ if (buttons != null) {
331
+ if (!Array.isArray(buttons)) {
332
+ throw createError(`OptionSelector requires "buttons" as an array. Got: ${typeof buttons}`, node.loc);
333
+ }
334
+ json.buttons = buttons.map((b) => {
335
+ if (!b || typeof b !== 'object') {
336
+ throw createError(`Each button must be an object.`, node.loc);
337
+ }
338
+ // key can be string or null, text is optional
339
+ if (b.key !== null && typeof b.key !== 'string') {
340
+ throw createError(`Each button requires "key" to be a string or null. Got: ${typeof b.key}`, node.loc);
341
+ }
342
+ if (b.text != null && typeof b.text !== 'string') {
343
+ throw createError(`Button "text" must be a string if provided. Got: ${typeof b.text}`, node.loc);
344
+ }
345
+ // Preserve all OptionSelectorButton properties from the input
346
+ // Required properties
347
+ const result = {
348
+ id: typeof b.id === 'string' ? b.id : `option_${b.key}`,
349
+ key: b.key,
350
+ };
351
+ // Optional properties - only include if present
352
+ if (b.text != null)
353
+ result.text = b.text;
354
+ if (b.description != null)
355
+ result.description = b.description;
356
+ // triggerEvent defaults to 'no-action' if not provided
357
+ result.triggerEvent = typeof b.triggerEvent === 'string' ? b.triggerEvent : 'no-action';
358
+ if (b.conditions != null)
359
+ result.conditions = b.conditions;
360
+ if (b.openUrlInNewTab != null)
361
+ result.openUrlInNewTab = b.openUrlInNewTab;
362
+ if (b.url != null)
363
+ result.url = b.url;
364
+ if (b.single_select != null)
365
+ result.single_select = b.single_select;
366
+ if (b.icon != null)
367
+ result.icon = b.icon;
368
+ if (b.emojiIcon != null)
369
+ result.emojiIcon = b.emojiIcon;
370
+ if (b.imageUrl != null)
371
+ result.imageUrl = b.imageUrl;
372
+ if (b.imageAltText != null)
373
+ result.imageAltText = b.imageAltText;
374
+ if (b.hide != null)
375
+ result.hide = b.hide;
376
+ if (b.is_repeatable_button != null)
377
+ result.is_repeatable_button = b.is_repeatable_button;
378
+ // Expand languages prop into flat lang--{langCode}--{attrKey} properties
379
+ if (b.languages != null && typeof b.languages === 'object' && !Array.isArray(b.languages)) {
380
+ for (const [langCode, attrs] of Object.entries(b.languages)) {
381
+ if (attrs != null && typeof attrs === 'object' && !Array.isArray(attrs)) {
382
+ for (const [attrKey, value] of Object.entries(attrs)) {
383
+ result[`lang--${langCode}--${attrKey}`] = value;
384
+ }
385
+ }
386
+ }
387
+ }
388
+ return result;
389
+ });
390
+ }
391
+ // If buttons is null/undefined, leave it as is (optional prop)
392
+ }
393
+ out.push(json);
394
+ for (const child of node.children) {
395
+ flatten(child, node.id, out, pageKey, filePath);
396
+ }
397
+ }
398
+ /**
399
+ * Normalize validation function source for embeddable.json: use name "validate" and strip TS (param types).
400
+ */
401
+ function normalizeValidationFunctionSource(source) {
402
+ // 1. Rename function to "validate"
403
+ let out = source.replace(/function\s+\w+\s*\(/, 'function validate(');
404
+ // 2. Strip parameter type annotations in the first parameter list (e.g. value: string -> value)
405
+ const openParen = out.indexOf('(', out.indexOf('function'));
406
+ if (openParen !== -1) {
407
+ let depth = 1;
408
+ let i = openParen + 1;
409
+ while (depth > 0 && i < out.length) {
410
+ if (out[i] === '(')
411
+ depth++;
412
+ else if (out[i] === ')')
413
+ depth--;
414
+ i++;
415
+ }
416
+ const params = out.slice(openParen, i);
417
+ const paramsNoTypes = params.replace(/:\s*[^,)]+/g, '');
418
+ out = out.slice(0, openParen) + paramsNoTypes + out.slice(i);
419
+ }
420
+ return out;
421
+ }
422
+ function attrsToProps(attrs, constEnv, filePath, validationFunctionSource) {
423
+ const out = {};
424
+ for (const a of attrs) {
425
+ if (a.type === 'JSXSpreadAttribute') {
426
+ throw new CompileError('JSX spread props are not supported.', loc(filePath, a));
427
+ }
428
+ const name = a.name.type === 'JSXIdentifier' ? a.name.name : `${a.name.namespace.name}:${a.name.name.name}`;
429
+ if (!a.value) {
430
+ // <X disabled />
431
+ out[name] = true;
432
+ continue;
433
+ }
434
+ if (a.value.type === 'StringLiteral') {
435
+ out[name] = a.value.value;
436
+ continue;
437
+ }
438
+ if (a.value.type === 'JSXExpressionContainer') {
439
+ const expr = a.value.expression;
440
+ // custom_validation_function: resolve to source and normalize to "validate" + JS for embeddable.json
441
+ if (name === 'custom_validation_function' &&
442
+ expr.type === 'Identifier' &&
443
+ validationFunctionSource?.has(expr.name)) {
444
+ out[name] = normalizeValidationFunctionSource(validationFunctionSource.get(expr.name));
445
+ continue;
446
+ }
447
+ out[name] = evalStatic(expr, constEnv, filePath);
448
+ continue;
449
+ }
450
+ throw new CompileError(`Unsupported JSX attribute value for "${name}".`, loc(filePath, a));
451
+ }
452
+ // When validation_formula is not "custom", custom_validation_function is ignored and omitted (removed on save).
453
+ if (out.validation_formula != null && out.validation_formula !== 'custom' && 'custom_validation_function' in out) {
454
+ delete out.custom_validation_function;
455
+ }
456
+ return out;
457
+ }
458
+ function getJsxTagName(n) {
459
+ if (n.type === 'JSXIdentifier')
460
+ return n.name;
461
+ throw new CompileError('Only simple JSX identifiers are supported (no member expressions).');
462
+ }
463
+ function requireString(obj, prop, filePath, node) {
464
+ const v = obj[prop];
465
+ if (typeof v !== 'string' || v.length === 0) {
466
+ throw new CompileError(`Missing required string prop "${prop}".`, loc(filePath, node));
467
+ }
468
+ return v;
469
+ }
470
+ function loc(file, node) {
471
+ return { file, line: node.loc?.start?.line, column: node.loc?.start?.column };
472
+ }
473
+ /**
474
+ * Converts JSX children to HTML string.
475
+ * Handles JSXElements, JSXText, JSXExpressions, and JSXFragments.
476
+ * @param preserveWhitespace If true, preserves all whitespace (for <style> and <script> tags)
477
+ */
478
+ function jsxChildrenToHTML(children, constEnv, filePath, preserveWhitespace = false) {
479
+ let html = '';
480
+ for (const child of children) {
481
+ if (child.type === 'JSXElement') {
482
+ html += jsxElementToHTML(child, constEnv, filePath);
483
+ }
484
+ else if (child.type === 'JSXText') {
485
+ const text = child.value;
486
+ // For <style> and <script> tags, preserve all whitespace
487
+ // For other tags, skip whitespace-only text (it's likely indentation)
488
+ if (preserveWhitespace || text.trim().length > 0) {
489
+ html += escapeHTML(text);
490
+ }
491
+ }
492
+ else if (child.type === 'JSXExpressionContainer') {
493
+ // Try to evaluate static expressions
494
+ try {
495
+ const value = evalStatic(child.expression, constEnv, filePath);
496
+ if (typeof value === 'string') {
497
+ html += escapeHTML(value);
498
+ }
499
+ else if (value != null) {
500
+ html += escapeHTML(String(value));
501
+ }
502
+ }
503
+ catch {
504
+ throw new CompileError('CustomHTML children must be static. Dynamic expressions are not supported.', loc(filePath, child));
505
+ }
506
+ }
507
+ else if (child.type === 'JSXFragment') {
508
+ // Handle fragments by recursively processing their children
509
+ html += jsxChildrenToHTML(child.children, constEnv, filePath, preserveWhitespace);
510
+ }
511
+ // Ignore JSXSpreadChild and other unsupported types
512
+ }
513
+ return html;
514
+ }
515
+ /**
516
+ * HTML5 void elements - these are the only elements that can be self-closing in HTML.
517
+ * For all other elements, we must emit explicit closing tags even if they're self-closing in JSX.
518
+ * See: https://html.spec.whatwg.org/multipage/syntax.html#void-elements
519
+ */
520
+ const HTML_VOID_ELEMENTS = new Set([
521
+ 'area',
522
+ 'base',
523
+ 'br',
524
+ 'col',
525
+ 'embed',
526
+ 'hr',
527
+ 'img',
528
+ 'input',
529
+ 'link',
530
+ 'meta',
531
+ 'param',
532
+ 'source',
533
+ 'track',
534
+ 'wbr',
535
+ ]);
536
+ /**
537
+ * Map React/JSX attribute names to HTML attribute names so serialized HTML
538
+ * uses valid attributes (e.g. class for CSS, not className).
539
+ */
540
+ function jsxAttrNameToHTMLAttrName(jsxName) {
541
+ switch (jsxName) {
542
+ case 'className':
543
+ return 'class';
544
+ case 'htmlFor':
545
+ return 'for';
546
+ case 'tabIndex':
547
+ return 'tabindex';
548
+ default:
549
+ return jsxName;
550
+ }
551
+ }
552
+ /**
553
+ * Converts a JSX element to HTML string.
554
+ */
555
+ function jsxElementToHTML(el, constEnv, filePath) {
556
+ const opening = el.openingElement;
557
+ const tagName = getJsxTagName(opening.name);
558
+ // Build attributes string (use HTML attribute names so class selectors work)
559
+ const attrs = [];
560
+ for (const attr of opening.attributes) {
561
+ if (attr.type === 'JSXAttribute') {
562
+ const name = attr.name.type === 'JSXIdentifier'
563
+ ? attr.name.name
564
+ : `${attr.name.namespace.name}:${attr.name.name.name}`;
565
+ const htmlName = jsxAttrNameToHTMLAttrName(name);
566
+ if (!attr.value) {
567
+ // Boolean attribute
568
+ attrs.push(htmlName);
569
+ }
570
+ else if (attr.value.type === 'StringLiteral') {
571
+ attrs.push(`${htmlName}="${escapeHTMLAttribute(attr.value.value)}"`);
572
+ }
573
+ else if (attr.value.type === 'JSXExpressionContainer') {
574
+ try {
575
+ const value = evalStatic(attr.value.expression, constEnv, filePath);
576
+ if (name === 'style' && typeof value === 'object' && value !== null) {
577
+ // Convert style object to CSS string
578
+ const cssString = styleObjectToCSS(value);
579
+ attrs.push(`${htmlName}="${escapeHTMLAttribute(cssString)}"`);
580
+ }
581
+ else if (typeof value === 'string') {
582
+ attrs.push(`${htmlName}="${escapeHTMLAttribute(value)}"`);
583
+ }
584
+ else if (typeof value === 'number' || typeof value === 'boolean') {
585
+ attrs.push(`${htmlName}="${String(value)}"`);
586
+ }
587
+ }
588
+ catch {
589
+ throw new CompileError('CustomHTML attribute values must be static. Dynamic expressions are not supported.', loc(filePath, attr));
590
+ }
591
+ }
592
+ }
593
+ }
594
+ const attrsStr = attrs.length > 0 ? ' ' + attrs.join(' ') : '';
595
+ // For <style> and <script> tags, preserve all whitespace to maintain CSS/JS formatting
596
+ const isRawTextTag = tagName.toLowerCase() === 'style' || tagName.toLowerCase() === 'script';
597
+ const childrenHTML = jsxChildrenToHTML(el.children, constEnv, filePath, isRawTextTag);
598
+ if (el.closingElement) {
599
+ return `<${tagName}${attrsStr}>${childrenHTML}</${tagName}>`;
600
+ }
601
+ else {
602
+ // Self-closing in JSX - check if it's an HTML void element
603
+ const isVoidElement = HTML_VOID_ELEMENTS.has(tagName.toLowerCase());
604
+ if (isVoidElement) {
605
+ // Void elements can be self-closing in HTML
606
+ return `<${tagName}${attrsStr} />`;
607
+ }
608
+ else {
609
+ // Non-void elements MUST have explicit closing tags in HTML
610
+ // Otherwise browsers interpret <div /> as <div> (unclosed)
611
+ return `<${tagName}${attrsStr}></${tagName}>`;
612
+ }
613
+ }
614
+ }
615
+ /**
616
+ * Escapes HTML entities in text content.
617
+ */
618
+ function escapeHTML(text) {
619
+ return text
620
+ .replace(/&/g, '&amp;')
621
+ .replace(/</g, '&lt;')
622
+ .replace(/>/g, '&gt;')
623
+ .replace(/"/g, '&quot;')
624
+ .replace(/'/g, '&#39;');
625
+ }
626
+ /**
627
+ * Escapes HTML entities in attribute values.
628
+ */
629
+ function escapeHTMLAttribute(text) {
630
+ return text
631
+ .replace(/&/g, '&amp;')
632
+ .replace(/</g, '&lt;')
633
+ .replace(/>/g, '&gt;')
634
+ .replace(/"/g, '&quot;');
635
+ }
636
+ /**
637
+ * Converts a JSX style object to CSS string.
638
+ * Example: { margin: 0, padding: 0, color: "#171717" } -> "margin: 0; padding: 0; color: #171717;"
639
+ */
640
+ function styleObjectToCSS(styleObj) {
641
+ const cssParts = [];
642
+ for (const [key, value] of Object.entries(styleObj)) {
643
+ // Preserve CSS custom properties (e.g., --ta, --my-variable) as-is
644
+ if (key.startsWith('--')) {
645
+ cssParts.push(`${key}: ${value};`);
646
+ }
647
+ else {
648
+ // Convert camelCase to kebab-case (e.g., lineHeight -> line-height)
649
+ const cssKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
650
+ cssParts.push(`${cssKey}: ${value};`);
651
+ }
652
+ }
653
+ return cssParts.join(' ');
654
+ }
@@ -0,0 +1,4 @@
1
+ export declare const ALLOWED_PRIMITIVES: Set<string>;
2
+ export declare const TYPE_MAP: Record<string, string>;
3
+ export declare const DEFAULTS_BY_TYPE: Record<string, Record<string, any>>;
4
+ //# sourceMappingURL=registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/compiler/registry.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,aAoB7B,CAAA;AAGF,eAAO,MAAM,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAoB3C,CAAA;AAED,eAAO,MAAM,gBAAgB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAM,CAAA"}