@superblocksteam/cli 2.0.0-next.7 → 2.0.0-next.9
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
|
@@ -14,7 +14,7 @@ $ npm install -g @superblocksteam/cli
|
|
|
14
14
|
$ superblocks COMMAND
|
|
15
15
|
running command...
|
|
16
16
|
$ superblocks (--version)
|
|
17
|
-
@superblocksteam/cli/2.0.0-next.
|
|
17
|
+
@superblocksteam/cli/2.0.0-next.9 linux-x64 node-v20.19.0
|
|
18
18
|
$ superblocks --help [COMMAND]
|
|
19
19
|
USAGE
|
|
20
20
|
$ superblocks COMMAND
|
|
@@ -24,7 +24,7 @@ init_cjs_shims();
|
|
|
24
24
|
|
|
25
25
|
// ../../../vite-plugin-file-sync/dist/ai-service/prompts/generated/subprompts/superblocks-api.js
|
|
26
26
|
init_cjs_shims();
|
|
27
|
-
var content = '### APIs\n\nThe Superblocks framework allows you to create backend APIs. The high level structure for creating APIs is as follows:\n\n1. APIs are defined using TypeScript files that live inside the apis directory inside the page they are scoped to. Example: /pages/Page1/apis/myApi.ts\n2. This pattern is a declarative workflow builder, where you define each API step, its configuration, and its execution order within the API workflow.\n3. To make the API available for use, you must import it into the scope file and register it with `SbApi()`, then import and destructure it in your page component for use.\n\n#### Example of creating and then registering a Superblocks API:\n\nCRITICAL: The name of the API must be consistent across the API\'s TypeScript definition, the API\'s file name, references in page files, and the key used to register it in the scope file. See the consistent use of \'myApi\' below as an example.\n\nCreate the API by adding the myApi.ts file:\n\n```ts\n// Path to this API definition: /pages/Page1/apis/myApi.ts\n\nimport { Api, JavaScript } from "@superblocksteam/library";\n\nexport default new Api("myApi", [\n new JavaScript("retrieve_orders", {\n fn: () => {\n return [\n {\n id: "ORD-001",\n customerName: "John Smith",\n total: 149.99,\n },\n {\n id: "ORD-002",\n customerName: "Sarah Jones",\n total: 89.5,\n },\n ];\n },\n }),\n]);\n```\n\nThen register the myApi API in the scope file:\n\n```ts\n// /pages/Page1/scope.ts\nimport { createSbScope, SbApi } from "@superblocksteam/library";\n\nexport const Page1Scope = createSbScope(\n () => ({\n // Register the API in the scope\n myApi: SbApi({}),\n }),\n {\n name: "Page1",\n },\n);\n\nexport const Page1 = Page1Scope.entities;\n```\n\nThen use the API in your page component:\n\n```tsx\n// /pages/Page1/index.tsx\n\nimport {\n SbPage,\n SbSection,\n SbColumn,\n SbButton,\n SbTable,\n sbComputed,\n SbEventFlow,\n registerPage,\n} from "@superblocksteam/library";\nimport { Page1, Page1Scope } from "./scope";\n\nconst Page1Component = () => {\n // Destructure the API from the scope entities to access its response\n const { myApi } = Page1;\n\n return (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n <SbButton\n // APIs can be invoked with the SbEventFlow API\n onClick={SbEventFlow.runApis([myApi])}\n label="Fetch Data"\n />\n {/* Access API response using sbComputed */}\n <SbTable tableData={sbComputed(() => myApi.response)} />\n </SbColumn>\n </SbSection>\n </SbPage>\n );\n};\n\nexport default registerPage(Page1Component, Page1Scope);\n```\n\n#### Example 2: API where a step references the output of a previous step\n\nThink hard about how you access the output of previous steps. You MUST use the output property of the previous step variable. There is no other way to access the output of a previous step (other than using a Variable block, but that is not what you want in this case and should only be used in very specific cases).\n\n```ts\n// Path to this api would be: /pages/Page1/apis/getOrders.ts\n\nimport { JavaScript, Api } from "@superblocksteam/library";\n\nexport default new Api("getOrders", [\n new JavaScript("retrieve_orders", {\n fn: () => {\n return [\n {\n id: 1,\n customer: "John Smith",\n date: "2024-01-15",\n total: 199.99,\n status: "Pending",\n },\n {\n id: 2,\n customer: "Jane Doe",\n date: "2024-01-14",\n total: 149.99,\n status: "Shipped",\n },\n {\n id: 3,\n customer: "Bob Wilson",\n date: "2024-01-13",\n total: 299.99,\n status: "Delivered",\n },\n ];\n },\n }),\n new JavaScript("format_orders", {\n fn: ({ retrieve_orders }) => {\n return retrieve_orders.output.map((order) => ({\n ...order,\n date: new Date(order.date).toLocaleDateString(),\n }));\n },\n }),\n]);\n```\n\nThen you would register the API in your scope file and use it in your page component:\n\n```ts\n// /pages/Page1/scope.ts\nexport const Page1Scope = createSbScope(\n () => ({\n getOrders: SbApi({}),\n }),\n {\n name: "Page1",\n },\n);\n```\n\n```tsx\n// /pages/Page1/index.tsx\nimport {\n SbPage,\n SbSection,\n SbColumn,\n SbTable,\n sbComputed,\n registerPage,\n} from "@superblocksteam/library";\nimport { Page1, Page1Scope } from "./scope";\n\nconst Page1Component = () => {\n const { getOrders } = Page1;\n\n return (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n <SbTable tableData={sbComputed(() => getOrders.response)} />\n </SbColumn>\n </SbSection>\n </SbPage>\n );\n};\n\nexport default registerPage(Page1Component, Page1Scope);\n```\n\n#### The Superblocks API TypeScript Type\n\nBelow is the full TypeScript spec for the APIs you create:\n\n````ts\n// @superblocksteam/types\n\nexport type JsonValue =\n | undefined\n | null\n | number\n | string\n | boolean\n | JsonValue[]\n | object;\nexport type State = { [key: string]: JsonValue };\nexport type Binding<T> = T | ((state: State) => T);\ntype Integrations = { id: string; description: string; metadata: JsonValue }[];\n\nclass Block {\n constructor(name: string) {}\n public run(): { output: JsonValue } {\n /* ... */\n }\n}\n\nclass Integration extends Block {\n constructor(name: string, integration_id: string) {}\n}\n\ntype State = Record<string, JsonValue>;\n\nclass JavaScript extends Integration {\n constructor(\n name: string,\n config: {\n fn: (\n {\n /* ... */\n },\n ) => JsonValue;\n },\n ) {\n super(name, "javascript");\n }\n}\n\nclass Python extends Integration {\n constructor(\n name: string,\n config: {\n // We want to just put the python function body here. The scope is the same as it would be if it were a JavaScript integration.\n fn: string;\n },\n ) {\n super(name, "python");\n }\n}\n\nclass Databricks extends Integration {\n static integrations: Integrations = [\n /* ... */\n ];\n\n /**\n * @param {string} name The name of the block.\n * @param {string} integration_id The id of the integration.\n * @param {object} config The config object.\n * @returns {void}\n */\n constructor(\n name: string,\n integration_id: string,\n config: {\n statement: Binding<string>;\n },\n ) {\n super(name, integration_id);\n }\n}\n\nclass Snowflake extends Integration {\n static integrations: Integrations = [\n /* ... */\n ];\n\n /**\n * @param {string} name The name of the block.\n * @param {string} integration_id The id of the integration.\n * @param {object} config The config object.\n * @returns {void}\n */\n constructor(\n name: string,\n integration_id: string,\n config: {\n statement: Binding<string>;\n },\n ) {\n super(name, integration_id);\n }\n}\n\nclass PostgreSQL extends Integration {\n static integrations: Integrations = [\n /* ... */\n ];\n\n /**\n * @param {string} name The name of the block.\n * @param {string} integration_id The id of the integration.\n * @param {object} config The config object.\n * @returns {void}\n */\n constructor(\n name: string,\n integration_id: string,\n config: {\n statement: Binding<string>;\n },\n ) {\n super(name, integration_id);\n }\n}\n\nclass RestApi extends Integration {\n constructor(\n name: string,\n config: {\n method:\n | "GET"\n | "POST"\n | "PUT"\n | "DELETE"\n | "PATCH"\n | "OPTIONS"\n | "HEAD"\n | "TRACE"\n | "CONNECT";\n url:\n | string\n | ((\n {\n /* ... */\n },\n ) => string);\n },\n ) {\n super(name);\n }\n}\n\nclass Email extends Integration {\n constructor(\n name: string,\n config: {\n from: Binding<string>;\n to: Binding<string>;\n subject: Binding<string>;\n cc?: Binding<string>;\n bcc?: Binding<string>;\n body?: Binding<string>;\n },\n ) {\n super(name);\n }\n}\n\nexport type Condition = {\n when: boolean | ((state: State) => boolean);\n then: Block[];\n};\n\nexport type Conditions = {\n if: Condition;\n elif?: Condition[];\n else?: Block[];\n};\n\nclass Conditional extends Block {\n constructor(name: string, config: Conditions) {\n super(name);\n }\n}\n\nclass TryCatch extends Block {\n constructor(\n name: string,\n config: {\n try: Block[];\n catch: Block[];\n finally?: Block[];\n variables: { error: string };\n },\n ) {\n super(name);\n }\n}\n\n/**\n * A Superblocks variable has the following access pattern:\n *\n * How to retrieve the value of a variable:\n * ```ts\n * CORRECT\n * my_variable.value\n *\n * // INCORRECT\n * my_variable\n * ```\n *\n * How to set the value of a variable:\n * ```ts\n * CORRECT\n * my_variable.set(value)\n *\n * // INCORRECT\n * my_variable = value\n * ```\n *\n */\n\nclass Variables extends Block {\n constructor(\n name: string,\n variables: {\n // The name of the variable.\n key: string;\n // The value of the variable.\n value: Binding<JsonValue>;\n }[],\n ) {\n super(name);\n }\n}\n\nclass Loop extends Block {\n constructor(\n name: string,\n config: {\n over: Binding<JsonValue[]>;\n variables: {\n // What the variable name for the current item is.\n item: string;\n // What the variable name for the current index is.\n index: string;\n };\n blocks: Block[];\n },\n ) {\n super(name);\n }\n}\n\nclass Parallel extends Block {\n constructor(\n name: string,\n config: {\n over: Binding<JsonValue[]>;\n variables: {\n // What the variable name for the current item is.\n item: string;\n };\n blocks: Block[];\n },\n ) {\n super(name);\n }\n}\n\nclass Throw extends Block {\n constructor(\n name: string,\n config: {\n error: Binding<JsonValue>;\n },\n ) {\n super(name);\n }\n}\n\nclass Return extends Block {\n constructor(\n name: string,\n config: {\n data: Binding<JsonValue>;\n },\n ) {\n super(name);\n }\n}\n\nclass Api {\n constructor(name: string, steps: Block[]) {}\n public get response(): JsonValue {\n /* ... */\n }\n public get error(): string | undefined {\n /* ... */\n }\n public run(): void {\n /* ... */\n }\n public cancel(): void {\n /* ... */\n }\n}\n````\n\n#### Example Usage\n\nBelow are examples of how you create Superblocks APIs, along with annotations to describe different pieces of functinality and expectations.\n\n##### Example 1: Simple API with conditional\n\n```ts\n// Path to this api would be: /pages/Page1/apis/getOrders.ts\n\nimport {\n Conditional,\n Condition,\n PostgreSQL,\n JavaScript,\n Api,\n} from "@superblocksteam/library";\n\nexport default new Api("getOrders", [\n new Conditional("my_conditional", {\n if: {\n when: true,\n then: [\n new PostgreSQL(\n "retrieve_orders",\n "" /* <- integration uuid goes here */,\n {\n statement: "SELECT * FROM orders",\n },\n ),\n ],\n },\n else: [\n new JavaScript("fallthrough", {\n fn: () => "we did not execute the sql query",\n }),\n ],\n }),\n]);\n```\n\nTo run register and run the API we defined above:\n\n```tsx\n// /pages/Page1/index.tsx\n\nimport {\n SbPage,\n SbApi,\n SbSection,\n SbColumn,\n SbTable,\n SbButton,\n SbEventFlow,\n registerPage,\n showAlert,\n} from "@superblocksteam/library";\n\nimport getOrders from "./apis/getOrders";\n\nconst Page1 = () => (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n <SbButton\n // APIs can be invoked with the SBEventFlow API.\n onClick={SbEventFlow.runApis([getOrders])}\n />\n // ...\n <SbTable>\n // APIs are part of the state object just like components. tableData=\n {(state) => state.getOrders.response}\n </SbTable>\n </SbColumn>\n </SbSection>\n </SbPage>\n);\n\nexport default registerPage(Page1, {\n name: "MyPage",\n // You register APIs just like you would SbVariables.\n getOrders: SbApi(getOrders),\n});\n```\n\n#### Rules for using Superblocks APIs\n\nThink hard about the following important rules for correctly using Superblocks APIs:\n\n- You MUST use a destructured state object as the function parameter for dynamic block fields. The valid keys are (1) Superblocks entities (components, variables, etc) and (2) previous block outputs that are in the lexical scope. Example below:\n\n```ts\n// CORRECT: uses destructured state\n({ Dropdown1, TextInput1 }) => Dropdown1.selectedOptionsValue + TextInput1.value\n\n// INCORRECT: uses state object directly\n(state) => state.Dropdown1.selectedOptionsValue + state.TextInput1.value\n```\n\n- The result of each scope is the result of the last block in that scope. In the following example, the value of `sendEmail.response` is the result of the `return_summary` block. Use this information to carefully ensure that the last block in your API is the one that returns the value you want.\n\n```ts\nexport default new Api("sendEmail", [\n new Email("send_email", {\n from: "noreply@company.com",\n to: "test@test.com",\n subject: "Test Email",\n body: "This is a test email",\n }),\n new JavaScript("return_summary", {\n fn: () => "Email sent successfully!",\n }),\n]);\n```\n\n```tsx\nimport {\n SbPage,\n SbSection,\n SbColumn,\n SbTable,\n sbComputed,\n registerPage,\n SbApi,\n} from "@superblocksteam/library";\n\nconst scope = createSbScope<{\n Table1: any;\n}>({ sendEmail: SbApi({}) }, { name: "Page1" });\n\nexport default registerPage(\n () => (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n // ...\n <SbTable\n bind={scope.entities.Table1}\n tableData={sbComputed(() => API1.response)}\n />\n // ...\n </SbColumn>\n </SbSection>\n </SbPage>\n ),\n scope,\n);\n```\n\n- Block outputs are immutable. Do not mutate the output of a block.\n\n- Do not reference variables that are not in scope. The ONLY things in scope in an API block are the outputs of previous steps and the state object.\n\n- Backend APIs CANNOT mutate frontend state inside of the API\n\n- APIs are registered in scope files using `SbApi()` and then accessed in page components by destructuring from the scope entities. Make sure you name the key used in registerScope the same as the imported API, but do not pass the imported Api into the SbApi() call.\n\n- To access API responses in your UI, use `sbComputed(() => apiName.response)` or `sbComputed(() => apiName.error)`.\n\n- You will not always be told which integrations to use in your API; you will have to determine that yourself based on the data you need to fetch.\n\n- Never add comments to code you (the ai) generate. User added comments are fine - leave those!\n';
|
|
27
|
+
var content = '### APIs\n\nThe Superblocks framework allows you to create backend APIs. The high level structure for creating APIs is as follows:\n\n1. APIs are defined using TypeScript files that live inside the apis directory inside the page they are scoped to. Example: /pages/Page1/apis/myApi.ts\n2. This pattern is a declarative workflow builder, where you define each API step, its configuration, and its execution order within the API workflow.\n3. To make the API available for use, you must import it into the scope file and register it with `SbApi()`, then import and destructure it in your page component for use.\n\n#### Example of creating and then registering a Superblocks API:\n\nCRITICAL: The name of the API must be consistent across the API\'s TypeScript definition, the API\'s file name, references in page files, and the key used to register it in the scope file. See the consistent use of \'myApi\' below as an example.\n\nCreate the API by adding the myApi.ts file:\n\n```ts\n// Path to this API definition: /pages/Page1/apis/myApi.ts\n\nimport { Api, JavaScript } from "@superblocksteam/library";\n\nexport default new Api("myApi", [\n new JavaScript("retrieve_orders", {\n fn: () => {\n return [\n {\n id: "ORD-001",\n customerName: "John Smith",\n total: 149.99,\n },\n {\n id: "ORD-002",\n customerName: "Sarah Jones",\n total: 89.5,\n },\n ];\n },\n }),\n]);\n```\n\nThen register the myApi API in the scope file:\n\n```ts\n// /pages/Page1/scope.ts\nimport { createSbScope, SbApi } from "@superblocksteam/library";\n\nexport const Page1Scope = createSbScope(\n () => ({\n // Register the API in the scope\n myApi: SbApi({}),\n }),\n {\n name: "Page1",\n },\n);\n\nexport const Page1 = Page1Scope.entities;\n```\n\nThen use the API in your page component:\n\n```tsx\n// /pages/Page1/index.tsx\n\nimport {\n SbPage,\n SbSection,\n SbColumn,\n SbButton,\n SbTable,\n sbComputed,\n SbEventFlow,\n registerPage,\n} from "@superblocksteam/library";\nimport { Page1, Page1Scope } from "./scope";\n\nconst Page1Component = () => {\n // Destructure the API from the scope entities to access its response\n const { myApi } = Page1;\n\n return (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n <SbButton\n // APIs can be invoked with the SbEventFlow API\n onClick={SbEventFlow.runApis([myApi])}\n label="Fetch Data"\n />\n {/* Access API response using sbComputed */}\n <SbTable tableData={sbComputed(() => myApi.response)} />\n </SbColumn>\n </SbSection>\n </SbPage>\n );\n};\n\nexport default registerPage(Page1Component, Page1Scope);\n```\n\n#### Example 2: API where a step references the output of a previous step\n\nThink hard about how you access the output of previous steps. You MUST use the output property of the previous step variable. There is no other way to access the output of a previous step (other than using a Variable block, but that is not what you want in this case and should only be used in very specific cases).\n\n```ts\n// Path to this api would be: /pages/Page1/apis/getOrders.ts\n\nimport { JavaScript, Api } from "@superblocksteam/library";\n\nexport default new Api("getOrders", [\n new JavaScript("retrieve_orders", {\n fn: () => {\n return [\n {\n id: 1,\n customer: "John Smith",\n date: "2024-01-15",\n total: 199.99,\n status: "Pending",\n },\n {\n id: 2,\n customer: "Jane Doe",\n date: "2024-01-14",\n total: 149.99,\n status: "Shipped",\n },\n {\n id: 3,\n customer: "Bob Wilson",\n date: "2024-01-13",\n total: 299.99,\n status: "Delivered",\n },\n ];\n },\n }),\n new JavaScript("format_orders", {\n fn: ({ retrieve_orders }) => {\n return retrieve_orders.output.map((order) => ({\n ...order,\n date: new Date(order.date).toLocaleDateString(),\n }));\n },\n }),\n]);\n```\n\nThen you would register the API in your scope file and use it in your page component:\n\n```ts\n// /pages/Page1/scope.ts\nexport const Page1Scope = createSbScope(\n () => ({\n getOrders: SbApi({}),\n }),\n {\n name: "Page1",\n },\n);\n```\n\n```tsx\n// /pages/Page1/index.tsx\nimport {\n SbPage,\n SbSection,\n SbColumn,\n SbTable,\n sbComputed,\n registerPage,\n} from "@superblocksteam/library";\nimport { Page1, Page1Scope } from "./scope";\n\nconst Page1Component = () => {\n const { getOrders } = Page1;\n\n return (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n <SbTable tableData={sbComputed(() => getOrders.response)} />\n </SbColumn>\n </SbSection>\n </SbPage>\n );\n};\n\nexport default registerPage(Page1Component, Page1Scope);\n```\n\n#### The Superblocks API TypeScript Type\n\nBelow is the full TypeScript spec for the APIs you create:\n\n````ts\n// @superblocksteam/types\n\nexport type JsonValue =\n | undefined\n | null\n | number\n | string\n | boolean\n | JsonValue[]\n | object;\nexport type State = { [key: string]: JsonValue };\nexport type Binding<T> = T | ((state: State) => T);\ntype Integrations = { id: string; description: string; metadata: JsonValue }[];\n\nclass Block {\n constructor(name: string) {}\n public run(): { output: JsonValue } {\n /* ... */\n }\n}\n\nclass Integration extends Block {\n constructor(name: string, integration_id: string) {}\n}\n\ntype State = Record<string, JsonValue>;\n\nclass JavaScript extends Integration {\n constructor(\n name: string,\n config: {\n fn: (\n {\n /* ... */\n },\n ) => JsonValue;\n },\n ) {\n super(name, "javascript");\n }\n}\n\nclass Python extends Integration {\n constructor(\n name: string,\n config: {\n // We want to just put the python function body here. The scope is the same as it would be if it were a JavaScript integration.\n fn: string;\n },\n ) {\n super(name, "python");\n }\n}\n\nclass Databricks extends Integration {\n static integrations: Integrations = [\n /* ... */\n ];\n\n /**\n * @param {string} name The name of the block.\n * @param {string} integration_id The id of the integration.\n * @param {object} config The config object.\n * @returns {void}\n */\n constructor(\n name: string,\n integration_id: string,\n config: {\n statement: Binding<string>;\n },\n ) {\n super(name, integration_id);\n }\n}\n\nclass Snowflake extends Integration {\n static integrations: Integrations = [\n /* ... */\n ];\n\n /**\n * @param {string} name The name of the block.\n * @param {string} integration_id The id of the integration.\n * @param {object} config The config object.\n * @returns {void}\n */\n constructor(\n name: string,\n integration_id: string,\n config: {\n statement: Binding<string>;\n },\n ) {\n super(name, integration_id);\n }\n}\n\nclass PostgreSQL extends Integration {\n static integrations: Integrations = [\n /* ... */\n ];\n\n /**\n * @param {string} name The name of the block.\n * @param {string} integration_id The id of the integration.\n * @param {object} config The config object.\n * @returns {void}\n */\n constructor(\n name: string,\n integration_id: string,\n config: {\n statement: Binding<string>;\n },\n ) {\n super(name, integration_id);\n }\n}\n\nclass RestApi extends Integration {\n constructor(\n name: string,\n config: {\n method: string;\n url?: Binding<string>;\n headers?: { key: Binding<string>; value: Binding<string> }[];\n params?: { key: Binding<string>; value: Binding<string> }[];\n body?: Binding<string>;\n },\n ) {\n super(name);\n }\n}\n\nclass Email extends Integration {\n constructor(\n name: string,\n config: {\n from: Binding<string>;\n to: Binding<string>;\n subject: Binding<string>;\n cc?: Binding<string>;\n bcc?: Binding<string>;\n body?: Binding<string>;\n },\n ) {\n super(name);\n }\n}\n\nexport type Condition = {\n when: boolean | ((state: State) => boolean);\n then: Block[];\n};\n\nexport type Conditions = {\n if: Condition;\n elif?: Condition[];\n else?: Block[];\n};\n\nclass Conditional extends Block {\n constructor(name: string, config: Conditions) {\n super(name);\n }\n}\n\nclass TryCatch extends Block {\n constructor(\n name: string,\n config: {\n try: Block[];\n catch: Block[];\n finally?: Block[];\n variables: { error: string };\n },\n ) {\n super(name);\n }\n}\n\n/**\n * A Superblocks variable has the following access pattern:\n *\n * How to retrieve the value of a variable:\n * ```ts\n * CORRECT\n * my_variable.value\n *\n * // INCORRECT\n * my_variable\n * ```\n *\n * How to set the value of a variable:\n * ```ts\n * CORRECT\n * my_variable.set(value)\n *\n * // INCORRECT\n * my_variable = value\n * ```\n *\n */\n\nclass Variables extends Block {\n constructor(\n name: string,\n variables: {\n // The name of the variable.\n key: string;\n // The value of the variable.\n value: Binding<JsonValue>;\n }[],\n ) {\n super(name);\n }\n}\n\nclass Loop extends Block {\n constructor(\n name: string,\n config: {\n over: Binding<JsonValue[]>;\n variables: {\n // What the variable name for the current item is.\n item: string;\n // What the variable name for the current index is.\n index: string;\n };\n blocks: Block[];\n },\n ) {\n super(name);\n }\n}\n\nclass Parallel extends Block {\n constructor(\n name: string,\n config: {\n over: Binding<JsonValue[]>;\n variables: {\n // What the variable name for the current item is.\n item: string;\n };\n blocks: Block[];\n },\n ) {\n super(name);\n }\n}\n\nclass Throw extends Block {\n constructor(\n name: string,\n config: {\n error: Binding<JsonValue>;\n },\n ) {\n super(name);\n }\n}\n\nclass Return extends Block {\n constructor(\n name: string,\n config: {\n data: Binding<JsonValue>;\n },\n ) {\n super(name);\n }\n}\n\nclass Api {\n constructor(name: string, steps: Block[]) {}\n public get response(): JsonValue {\n /* ... */\n }\n public get error(): string | undefined {\n /* ... */\n }\n public run(): void {\n /* ... */\n }\n public cancel(): void {\n /* ... */\n }\n}\n````\n\n#### Example Usage\n\nBelow are examples of how you create Superblocks APIs, along with annotations to describe different pieces of functinality and expectations.\n\n##### Example 1: Simple API with conditional\n\n```ts\n// Path to this api would be: /pages/Page1/apis/getOrders.ts\n\nimport {\n Conditional,\n Condition,\n PostgreSQL,\n JavaScript,\n Api,\n} from "@superblocksteam/library";\n\nexport default new Api("getOrders", [\n new Conditional("my_conditional", {\n if: {\n when: true,\n then: [\n new PostgreSQL(\n "retrieve_orders",\n "" /* <- integration uuid goes here */,\n {\n statement: "SELECT * FROM orders",\n },\n ),\n ],\n },\n else: [\n new JavaScript("fallthrough", {\n fn: () => "we did not execute the sql query",\n }),\n ],\n }),\n]);\n```\n\nTo run register and run the API we defined above:\n\n```tsx\n// /pages/Page1/index.tsx\n\nimport {\n SbPage,\n SbApi,\n SbSection,\n SbColumn,\n SbTable,\n SbButton,\n SbEventFlow,\n registerPage,\n showAlert,\n} from "@superblocksteam/library";\n\nimport getOrders from "./apis/getOrders";\n\nconst Page1 = () => (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n <SbButton\n // APIs can be invoked with the SBEventFlow API.\n onClick={SbEventFlow.runApis([getOrders])}\n />\n // ...\n <SbTable>\n // APIs are part of the state object just like components. tableData=\n {(state) => state.getOrders.response}\n </SbTable>\n </SbColumn>\n </SbSection>\n </SbPage>\n);\n\nexport default registerPage(Page1, {\n name: "MyPage",\n // You register APIs just like you would SbVariables.\n getOrders: SbApi(getOrders),\n});\n```\n\n#### Rules for using Superblocks APIs\n\nThink hard about the following important rules for correctly using Superblocks APIs:\n\n- You MUST use a destructured state object as the function parameter for dynamic block fields. The valid keys are (1) Superblocks entities (components, variables, etc) and (2) previous block outputs that are in the lexical scope. Example below:\n\n```ts\n// CORRECT: uses destructured state\n({ Dropdown1, TextInput1 }) => Dropdown1.selectedOptionsValue + TextInput1.value\n\n// INCORRECT: uses state object directly\n(state) => state.Dropdown1.selectedOptionsValue + state.TextInput1.value\n```\n\n- The result of each scope is the result of the last block in that scope. In the following example, the value of `sendEmail.response` is the result of the `return_summary` block. Use this information to carefully ensure that the last block in your API is the one that returns the value you want.\n\n```ts\nexport default new Api("sendEmail", [\n new Email("send_email", {\n from: "noreply@company.com",\n to: "test@test.com",\n subject: "Test Email",\n body: "This is a test email",\n }),\n new JavaScript("return_summary", {\n fn: () => "Email sent successfully!",\n }),\n]);\n```\n\n```tsx\nimport {\n SbPage,\n SbSection,\n SbColumn,\n SbTable,\n sbComputed,\n registerPage,\n SbApi,\n} from "@superblocksteam/library";\n\nconst scope = createSbScope<{\n Table1: any;\n}>(\n () => ({\n sendEmail: SbApi({}),\n }),\n { name: "Page1" },\n);\n\nexport default registerPage(\n () => (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n // ...\n <SbTable\n bind={scope.entities.Table1}\n tableData={sbComputed(() => API1.response)}\n />\n // ...\n </SbColumn>\n </SbSection>\n </SbPage>\n ),\n scope,\n);\n```\n\n- Block outputs are immutable. Do not mutate the output of a block.\n\n- Do not reference variables that are not in scope. The ONLY things in scope in an API block are the outputs of previous steps and the state object.\n\n- Backend APIs CANNOT mutate frontend state inside of the API\n\n- APIs are registered in scope files using `SbApi()` and then accessed in page components by destructuring from the scope entities. Make sure you name the key used in registerScope the same as the imported API, but do not pass the imported Api into the SbApi() call.\n\n- To access API responses in your UI, use `sbComputed(() => apiName.response)` or `sbComputed(() => apiName.error)`.\n\n- You will not always be told which integrations to use in your API; you will have to determine that yourself based on the data you need to fetch.\n\n- Never add comments to code you (the ai) generate. User added comments are fine - leave those!\n';
|
|
28
28
|
|
|
29
29
|
// ../../../vite-plugin-file-sync/dist/ai-service/prompts/generated/subprompts/superblocks-components-rules.js
|
|
30
30
|
init_cjs_shims();
|
|
@@ -44,7 +44,7 @@ var content5 = '### Layout and Sizing in Superblocks\n\nAll layouts in Superbloc
|
|
|
44
44
|
|
|
45
45
|
// ../../../vite-plugin-file-sync/dist/ai-service/prompts/generated/subprompts/superblocks-page.js
|
|
46
46
|
init_cjs_shims();
|
|
47
|
-
var content6 = '### How to use SbPage\n\n- A page is a file that exports a default React component through the `registerPage` function.\n- Each page consists of two files: `index.tsx` (the page component) and `scope.ts` (the entity definitions).\n- For `export default registerPage(Page1, Page1Scope)`, Page1 is a function that returns a React component, and Page1Scope is the scope containing all entities.\n- A project consists of one or more pages. Each page is a directory in the `pages` directory.\n- Pages are registered in the `routes.json` file.\n\n### Page Structure\n\nEach page should have the following structure:\n\n**scope.ts** - Contains all entity definitions (variables, APIs, etc.):\n\n```ts\nimport {\n createSbScope,\n SbVariable,\n SbVariablePersistence,\n SbApi,\n SbText,\n} from "@superblocksteam/library";\n\nexport const Page1Scope = createSbScope<{\n Text1: any;\n}>(\n {\n // Define your entities here\n myVariable: SbVariable({\n defaultValue: "initial value",\n persistence: SbVariablePersistence.TEMPORARY,\n }),\n myApi: SbApi({}),\n },\n {\n name: "Page1",\n },\n);\n\nexport const Page1 = Page1Scope.entities;\n```\n\n**index.tsx** - Contains the page component:\n\n```tsx\nimport {\n SbPage,\n SbSection,\n SbColumn,\n SbText,\n registerPage,\n} from "@superblocksteam/library";\nimport { Page1, Page1Scope } from "./scope";\n\nfunction Page() {\n // Destructure entities from the scope for easy access\n const { Text1, myVariable, myApi } = Page1;\n\n return (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n {/* Use entities in your components */}\n <SbText bind={Text1} text={sbComputed(() => myVariable.value)} />\n </SbColumn>\n </SbSection>\n </SbPage>\n );\n}\n\nexport default registerPage(Page, Page1Scope);\n```\n\n## How component bindings work\n\nIf you need to reference a component directly to get access to some of its state, you must use a binding inside the page scope.\n\nComponent bindings allow you to:\n\n- Access component properties and state from other components and APIs\n- Create reactive relationships between components\n- Reference component values in `sbComputed` expressions\n\n### Setting up component bindings\n\n1. **Define the binding type in your scope**: Add the component type to the scope\'s type definitions:\n\n```ts\nexport const Page1Scope = createSbScope<{\n Text1: any;\n UserInput: any;\n}>(\n {\n // Your other entities (variables, APIs, etc.)\n myVariable: SbVariable({ defaultValue: "Hello" }),\n },\n {\n name: "Page1",\n },\n);\n```\n\n2. **Bind the component in your JSX**: Use the `bind` prop to connect the component to the binding:\n\n```tsx\nfunction Page() {\n const { Text1, UserInput, myVariable } = Page1;\n\n return (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n <SbInput bind={UserInput} placeholder="Enter your name" />\n <SbText\n bind={Text1}\n text={sbComputed(() => `Hello, ${UserInput.value}!`)}\n />\n </SbColumn>\n </SbSection>\n </SbPage>\n );\n}\n```\n\n3. **Access component state**: Use `sbComputed` to access properties of bound components:\n\n```tsx\n// Access input value\ntext={sbComputed(() => UserInput.value)}\n\n// Access text content\ntext={sbComputed(() => Text1.text)}\n\n// Combine with other state\ntext={sbComputed(() => `${myVariable.value}: ${UserInput.value}`)}\n```\n\n### Common binding use cases\n\n- **Form inputs**: Access user input values to display or validate\n- **Dynamic content**: Reference one component\'s state to update another\n- **Conditional rendering**: Use component state to control visibility or styling\n\n### Page load events\n\nYou can fire callbacks when a page is loaded using the onLoad property of the Page component. You must use the SbEventFlow API for any actions you want to run inside onLoad.\n\nExample:\n\n```tsx\nimport {\n registerPage,\n SbEventFlow,\n SbPage,\n SbSection,\n SbColumn,\n sbComputed,\n} from "@superblocksteam/library";\nimport { Page1, Page1Scope } from "./scope";\n\nconst Page1Component = () => {\n return (\n <SbPage\n name="Page1"\n height={Dim.fill()}\n width={Dim.fill()}\n onLoad={SbEventFlow.runJS(() => {\n console.log("Page loaded");\n })}\n >\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>...</SbColumn>\n </SbSection>\n </SbPage>\n );\n};\n\nexport default registerPage(Page1Component, Page1Scope);\n```\n\nA very common and helpful usage of this callback is to run APIs using SbEventFlow to fetch data when the page loads. Example:\n\n```tsx\nimport {\n SbPage,\n registerPage,\n SbEventFlow,\n SbSection,\n SbColumn,\n sbComputed,\n} from "@superblocksteam/library";\nimport { Page1, Page1Scope } from "./scope";\n\nconst Page1Component = () => {\n return (\n <SbPage\n name="Page1"\n height={Dim.fill()}\n width={Dim.fill()}\n onLoad={SbEventFlow.runApis([getOrders])}\n >\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>...</SbColumn>\n </SbSection>\n </SbPage>\n );\n};\n\nexport default registerPage(Page1Component, Page1Scope);\n```\n\nIn this example, the `getOrders` API would be defined in the scope.ts file like this:\n\n```ts\n// In scope.ts\n\n// We register the api in createSbScope by creating a key\n// with the same name as the file, and SbApi({}) with an empty object\n// Note: We DO NOT import the api file. It\'s not necessary.\nexport const Page1Scope = createSbScope(\n () => ({\n getOrders: SbApi({}),\n }),\n {\n name: "Page1",\n },\n);\n```\n';
|
|
47
|
+
var content6 = '### How to use SbPage\n\n- A page is a file that exports a default React component through the `registerPage` function.\n- Each page consists of two files: `index.tsx` (the page component) and `scope.ts` (the entity definitions).\n- For `export default registerPage(Page1, Page1Scope)`, Page1 is a function that returns a React component, and Page1Scope is the scope containing all entities.\n- A project consists of one or more pages. Each page is a directory in the `pages` directory.\n- Pages are registered in the `routes.json` file.\n\n### Page Structure\n\nEach page should have the following structure:\n\n**scope.ts** - Contains all entity definitions (variables, APIs, etc.):\n\n```ts\nimport {\n createSbScope,\n SbVariable,\n SbVariablePersistence,\n SbApi,\n SbText,\n} from "@superblocksteam/library";\n\nexport const Page1Scope = createSbScope<{\n Text1: any;\n}>(\n () => ({\n // Define your entities here\n myVariable: SbVariable({\n defaultValue: "initial value",\n persistence: SbVariablePersistence.TEMPORARY,\n }),\n myApi: SbApi({}),\n }),\n {\n name: "Page1",\n },\n);\n\nexport const Page1 = Page1Scope.entities;\n```\n\n**index.tsx** - Contains the page component:\n\n```tsx\nimport {\n SbPage,\n SbSection,\n SbColumn,\n SbText,\n registerPage,\n} from "@superblocksteam/library";\nimport { Page1, Page1Scope } from "./scope";\n\nfunction Page() {\n // Destructure entities from the scope for easy access\n const { Text1, myVariable, myApi } = Page1;\n\n return (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n {/* Use entities in your components */}\n <SbText bind={Text1} text={sbComputed(() => myVariable.value)} />\n </SbColumn>\n </SbSection>\n </SbPage>\n );\n}\n\nexport default registerPage(Page, Page1Scope);\n```\n\n## How component bindings work\n\nIf you need to reference a component directly to get access to some of its state, you must use a binding inside the page scope.\n\nComponent bindings allow you to:\n\n- Access component properties and state from other components and APIs\n- Create reactive relationships between components\n- Reference component values in `sbComputed` expressions\n\n### Setting up component bindings\n\n1. **Define the binding type in your scope**: Add the component type to the scope\'s type definitions:\n\n```ts\nexport const Page1Scope = createSbScope<{\n Text1: any;\n UserInput: any;\n}>(\n () => ({\n // Your other entities (variables, APIs, etc.)\n myVariable: SbVariable({ defaultValue: "Hello" }),\n }),\n {\n name: "Page1",\n },\n);\n```\n\n2. **Bind the component in your JSX**: Use the `bind` prop to connect the component to the binding:\n\n```tsx\nfunction Page() {\n const { Text1, UserInput, myVariable } = Page1;\n\n return (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n <SbInput bind={UserInput} placeholder="Enter your name" />\n <SbText\n bind={Text1}\n text={sbComputed(() => `Hello, ${UserInput.value}!`)}\n />\n </SbColumn>\n </SbSection>\n </SbPage>\n );\n}\n```\n\n3. **Access component state**: Use `sbComputed` to access properties of bound components:\n\n```tsx\n// Access input value\ntext={sbComputed(() => UserInput.value)}\n\n// Access text content\ntext={sbComputed(() => Text1.text)}\n\n// Combine with other state\ntext={sbComputed(() => `${myVariable.value}: ${UserInput.value}`)}\n```\n\n### Common binding use cases\n\n- **Form inputs**: Access user input values to display or validate\n- **Dynamic content**: Reference one component\'s state to update another\n- **Conditional rendering**: Use component state to control visibility or styling\n\n### Page load events\n\nYou can fire callbacks when a page is loaded using the onLoad property of the Page component. You must use the SbEventFlow API for any actions you want to run inside onLoad.\n\nExample:\n\n```tsx\nimport {\n registerPage,\n SbEventFlow,\n SbPage,\n SbSection,\n SbColumn,\n sbComputed,\n} from "@superblocksteam/library";\nimport { Page1, Page1Scope } from "./scope";\n\nconst Page1Component = () => {\n return (\n <SbPage\n name="Page1"\n height={Dim.fill()}\n width={Dim.fill()}\n onLoad={SbEventFlow.runJS(() => {\n console.log("Page loaded");\n })}\n >\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>...</SbColumn>\n </SbSection>\n </SbPage>\n );\n};\n\nexport default registerPage(Page1Component, Page1Scope);\n```\n\nA very common and helpful usage of this callback is to run APIs using SbEventFlow to fetch data when the page loads. Example:\n\n```tsx\nimport {\n SbPage,\n registerPage,\n SbEventFlow,\n SbSection,\n SbColumn,\n sbComputed,\n} from "@superblocksteam/library";\nimport { Page1, Page1Scope } from "./scope";\n\nconst Page1Component = () => {\n return (\n <SbPage\n name="Page1"\n height={Dim.fill()}\n width={Dim.fill()}\n onLoad={SbEventFlow.runApis([getOrders])}\n >\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>...</SbColumn>\n </SbSection>\n </SbPage>\n );\n};\n\nexport default registerPage(Page1Component, Page1Scope);\n```\n\nIn this example, the `getOrders` API would be defined in the scope.ts file like this:\n\n```ts\n// In scope.ts\n\n// We register the api in createSbScope by creating a key\n// with the same name as the file, and SbApi({}) with an empty object\n// Note: We DO NOT import the api file. It\'s not necessary.\nexport const Page1Scope = createSbScope(\n () => ({\n getOrders: SbApi({}),\n }),\n {\n name: "Page1",\n },\n);\n```\n';
|
|
48
48
|
|
|
49
49
|
// ../../../vite-plugin-file-sync/dist/ai-service/prompts/generated/subprompts/superblocks-routes.js
|
|
50
50
|
init_cjs_shims();
|
|
@@ -52,7 +52,7 @@ var content7 = '- The `routes.json` file maps URLs to pages.\n Example routes.j
|
|
|
52
52
|
|
|
53
53
|
// ../../../vite-plugin-file-sync/dist/ai-service/prompts/generated/subprompts/superblocks-state.js
|
|
54
54
|
init_cjs_shims();
|
|
55
|
-
var content8 = '**Superblocks State System**\n\nThe Superblocks state system is built around scopes that contain entities (variables, APIs, components). Here\'s how it works:\n\n### 1. Scopes\n\nScopes are defined in separate `scope.ts` files for each page and contain all the page\'s entities.\n\n- **Page scopes** are visible only within the current page\n- **App scopes** can be shared across pages (though you should primarily use page scopes)\n- Entities are accessed by importing and destructuring from the scope\n\n> **Parent \u2192 child rule**: Child scopes can read & write parent entities, but parents cannot reach into children.\n\n### 2. Scope Structure\n\nEach page has its own scope file that defines all entities:\n\n```ts\n// pages/Page1/scope.ts\nimport {\n createSbScope,\n SbVariable,\n SbVariablePersistence,\n SbApi,\n sbComputed,\n} from "@superblocksteam/library";\n\nexport const Page1Scope = createSbScope<{\n OrdersTable: any;\n}>(\n ({ entities: { counter } }) => ({\n // Static state variable with a simple default value\n counter: SbVariable({\n defaultValue: 0,\n persistence: SbVariablePersistence.TEMPORARY,\n }),\n // State variable with computed default value from other entities\n doubledCounter: SbVariable({\n defaultValue: sbComputed(() => counter.value * 2),\n persistence: SbVariablePersistence.TEMPORARY,\n }),\n myApi: SbApi({}),\n }),\n {\n name: "Page1",\n },\n);\n\nexport const Page1 = Page1Scope.entities;\n```\n\nThen in your page component, you import and destructure the entities:\n\n```tsx\n// pages/Page1/index.tsx\nimport {\n SbPage,\n SbSection,\n SbColumn,\n SbText,\n SbButton,\n sbComputed,\n SbEventFlow,\n registerPage,\n} from "@superblocksteam/library";\nimport { Page1, Page1Scope } from "./scope";\n\nfunction Page() {\n // Destructure entities for easy access\n const { counter, doubledCounter, myApi, OrdersTable } = Page1;\n\n return (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n <SbText text={sbComputed(() => `Count: ${counter.value}`)} />\n <SbButton onClick={SbEventFlow.setStateVar("counter", 5)} />\n </SbColumn>\n </SbSection>\n </SbPage>\n );\n}\n\nexport default registerPage(Page, Page1Scope);\n```\n\n_You should NOT create any extra scopes other than page scopes in most cases._\n\n### 3. Computed Default Values\n\nState variables can have their `defaultValue` computed from other entities in the same scope at initialization time.\n\n**Static default value:**\n\n```ts\nstaticVar: SbVariable({\n defaultValue: "Hello World",\n});\n```\n\n**Computed default value:**\n\n```ts\n({ entities: { Input1, staticVar } }) => ({\n computedVar: SbVariable({\n defaultValue: sbComputed(() => `${staticVar.value} - ${Input1.value}`),\n }),\n});\n```\n\nWrap the entire scope object with the entities function and destructure needed entities from the `entities` parameter. This only sets the initial value - it doesn\'t create ongoing updates.\n\n### 4. Entity Types\n\n- **Component state**\n\n - Declared by defining the component type in the scope and using the `bind` prop\n - Accessed by destructuring the component entity and using `sbComputed(() => ComponentName.prop)`\n - Writable if the prop is marked writable in the schema\n\n- **State variable**\n\n - Declared with `SbVariable({ defaultValue })` or within `(({ entities }) => ({ ... }))` wrapper for computed defaults\n - `defaultValue` sets the initial value when the application loads\n - For static variables: Only JSON parsable data structures, no functions\n - For computed variables: Use `sbComputed` within defaultValue to reference other entities\n - Do not call `defaultValue` like a function. Set values with `SbEventFlow.setStateVar()` or read with `sbComputed(() => varName.value)`\n - Accessed with `sbComputed(() => varName.value)` \u2014 **always include `.value`**\n - Writable through SbEventFlow\n\n- **API**\n - Declared with `SbApi({})` in the scope file.\n - Accessed with `sbComputed(() => apiName.response)` or `sbComputed(() => apiName.error)`\n - Read\u2011only\n\n### 5. Reading State with sbComputed\n\n**CRITICAL**: There are two different patterns for accessing data in `sbComputed` depending on what you\'re accessing:\n\n#### 5.1. Scope Entities (Direct Access)\n\nFor entities defined in your scope file (variables, APIs, components), access them **directly** after destructuring:\n\n```tsx\nconst { UserSearchInput, myVariable, myApi } = Page1;\n\n// \u2705 CORRECT - Direct access for scope entities\n<SbText text={sbComputed(() => `Search: ${UserSearchInput.value}`)} />\n<SbText text={sbComputed(() => myVariable.value)} />\n<SbTable tableData={sbComputed(() => myApi.response)} />\n```\n\n#### 4.2. Global State (Import Access)\n\nFor global state like globals, theme, environment, and embedded data, import the globals directly from the library:\n\n```tsx\n// \u2705 CORRECT - Import globals directly\n<SbText\n text={sbComputed(() => `Welcome ${Global.user.name}!`)}\n textStyle={{\n textColor: {\n default: sbComputed(() => Theme.colors.neutral900)\n }\n }}\n/>\n<SbContainer backgroundColor={sbComputed(() => Theme.colors.primary)} />\n```\n\n#### 5.3. Mixed Access\n\nWhen you need both scope entities and global state in the same `sbComputed`:\n\n```tsx\nconst { orders } = Page1;\n\n// \u2705 CORRECT - Combine direct entity access with imported globals\n<SbText\n text={sbComputed(() => `${orders.length} orders for ${Global.user.name}`)}\n/>;\n```\n\n### 6. Writing State\n\nPreferred approach:\n\n```tsx\nSbEventFlow.setStateVar("pageSize", 50);\n```\n\nFallback for complex operations:\n\n```tsx\nSbEventFlow.runJS(() => {\n // Direct assignment works within SbEventFlow.runJS\n pageSize.value = 50;\n});\n```\n\n### 7. CRITICAL Rules\n\n1. **Use component state directly**; NEVER create a state variable for a value that is available directly from a component property.\n2. Use component bindings by defining component types in your scope and using the `bind` prop.\n3. Keep logic declarative \u2014 derive UI from state using `sbComputed` instead of mutating props at runtime.\n4. Always destructure entities from your scope for clean access patterns.\n5. **Use the correct sbComputedz pattern**: Direct access for scope entities, import globals (Global, Theme, Embed, Env) for global access.\n6. Always complete implement all features, don\'t stub out or skip anything.\n\n**\u2705 Example**\n\n```tsx\n// In your scope.ts file\nexport const Page1Scope = createSbScope<{\n ApplicantSelector: any;\n}>(\n {\n applicants: SbVariable({ defaultValue: [] }),\n },\n {\n name: "Page1",\n },\n);\n```\n\n```tsx\n// In your page component after destructuring entities\nconst { ApplicantSelector, applicants } = Page1;\n\n<SbDropdown bind={ApplicantSelector} options={/* ... */} />\n<SbTable tableData={sbComputed(() => applicants[ApplicantSelector.selectedOptionValue])} />\n```\n\n```tsx\n// In your scope.ts file\nexport const Page1Scope = createSbScope<{\n Country: any;\n}>(\n {\n applicants: SbVariable({ defaultValue: [] }),\n },\n FirstName: typeof SbInput;\n LastName: typeof SbInput;\n}>(\n ({ entities: { FirstName, LastName } }) => ({\n fullName: SbVariable({\n defaultValue: sbComputed(() =>\n `${FirstName.value} ${LastName.value}`.trim(),\n ),\n }),\n }),\n {\n name: "Page1",\n },\n);\n```\n\n```tsx\nconst { FirstName, LastName, fullName } = Page1;\n\n<SbInput bind={FirstName} placeholder="First name" />\n<SbInput bind={LastName} placeholder="Last name" />\n<SbText text={sbComputed(() => `Welcome ${fullName.value}!`)} />\n```\n\n```tsx\n{\n /* The user types in the search input, and the value is displayed */\n}\n// In your scope.ts file\nexport const Page1Scope = createSbScope<{\n searchTerm: any;\n}>(\n {},\n {\n name: "Page1",\n },\n);\n```\n\n```tsx\nconst { searchTerm } = Page1;\n\n<SbInput bind={searchTerm} />\n<SbText text={sbComputed(() => searchTerm.value)} />\n```\n\n```tsx\n{\n /* Switch to change into admin mode */\n}\n// In your scope.ts file\nexport const Page1Scope = createSbScope<{\n isAdmin: any;\n}>(\n {},\n {\n name: "Page1",\n },\n);\n```\n\n```tsx\nconst { isAdmin } = Page1;\n\n<SbSwitch bind={isAdmin} label="Use Admin Mode" defaultChecked={false} />;\n{\n /* Only enable the delete button when switched into Admin mode */\n}\n<SbButton\n disabled={sbComputed(() => !isAdmin.isChecked)}\n label="Delete profile"\n/>;\n```\n\n\u2705 ALWAYS USE DIRECT COMPONENT STATE ACCESS WITH sbComputed:\n\n```tsx\n// GOOD - DO THIS\n// In your scope.ts file\nexport const Page1Scope = createSbScope<{\n UserNameInput: any;\n}>(\n {},\n {\n name: "Page1",\n },\n);\n```\n\n```tsx\nconst { UserNameInput } = Page1;\n\n<SbTextInput bind={UserNameInput} />\n<SbText text={sbComputed(() => `Hello, ${UserNameInput.value}!`)} />\n```\n\n\u274C NEVER CREATE REDUNDANT STATE VARIABLES:\n\n```tsx\n// WRONG - DON\'T DO THIS\n<SbTextInput bind={UserNameInput} onChange={SbEventFlow.setStateVar(\'userNameVar\', \'myValue\')} />\n<SbText text={sbComputed(() => `Hello, ${userNameVar.value}!`)} />\n...\n// And then in scope.ts:\n{\n userNameVar: SbVariable({ defaultValue: "" }),\n}\n```\n\nTo reference a property of a component using `sbComputed`, the component must have a binding defined in your scope.\n\nThat\'s why you should ALWAYS define component bindings in your scope for the following component types when you need to access their state:\n\n- SbInput\n- SbDropdown\n- SbDatePicker\n- SbCheckbox\n- SbSwitch\n- SbForm\n- SbRadio\n- SbRichText\n- SbFilePicker\n- SbCodeEditor\n- SbChat\n\n\u274C DO NOT USE STATE VARIABLES AS FUNCTIONS:\n\nState variables are not functions. You cannot call them or store functions in defaultValue.\n\n```tsx\n// WRONG - DON\'T DO THIS\nfunction Page1() {\n const { customerNameFilter, filterOrders } = Page1;\n\n return (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n <SbInput\n bind={customerNameFilter}\n label="Customer Name"\n placeholder="Filter by customer name"\n width={Dim.fill()}\n onTextChanged={SbEventFlow.runJS(() => {\n // This is wrong - you cannot call filterOrders as a function\n filterOrders();\n })}\n />\n </SbColumn>\n </SbSection>\n </SbPage>\n );\n}\n\n// And in scope.ts (WRONG):\n{\n filterOrders: SbVariable({\n defaultValue: () => {\n // This doesn\'t work - state variables are not functions\n const customerNameFilter = customerNameFilter.value.toLowerCase();\n // ... more logic\n },\n });\n}\n```\n\nInstead do the following:\n\n\u2705 COMPUTE VALUES WITH sbComputed AND SET STATE WITH SbEventFlow:\n\n```tsx\n// CORRECT - DO THIS\nimport {\n SbPage,\n SbSection,\n SbColumn,\n SbInput,\n SbButton,\n SbTable,\n sbComputed,\n SbEventFlow,\n registerPage,\n} from "@superblocksteam/library";\n\nfunction Page1() {\n const { customerNameFilter, filteredOrders, orders } = Page1;\n\n return (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n <SbInput\n bind={customerNameFilter}\n label="Customer Name"\n placeholder="Filter by customer name"\n width={Dim.fill()}\n onTextChanged={SbEventFlow.runJS(() => {\n // Repeat the filtering logic inline - do NOT create helper functions\n const filtered = orders.value.filter((order) => {\n return (\n !customerNameFilter.value ||\n order.customerName\n .toLowerCase()\n .includes(customerNameFilter.value.toLowerCase())\n );\n });\n\n // Set the state variable with the computed result\n filteredOrders.value = filtered;\n })}\n />\n {/* If you need the same filtering logic elsewhere, repeat it inline */}\n <SbButton\n label="Apply Filter"\n onClick={SbEventFlow.runJS(() => {\n // Repeat the same filtering logic here - code repetition is preferred\n const filtered = orders.value.filter((order) => {\n return (\n !customerNameFilter.value ||\n order.customerName\n .toLowerCase()\n .includes(customerNameFilter.value.toLowerCase())\n );\n });\n\n filteredOrders.value = filtered;\n })}\n />\n <SbTable tableData={sbComputed(() => filteredOrders.value)} />\n </SbColumn>\n </SbSection>\n </SbPage>\n );\n}\n\nexport default registerPage(Page1, Page1Scope);\n```\n\nAnd in your scope.ts file:\n\n```ts\nexport const Page1Scope = createSbScope<{\n customerNameFilter: any;\n}>(\n {\n orders: SbVariable({\n defaultValue: [\n {\n id: "ORD-1001",\n customerName: "John Smith",\n orderType: "Grocery Delivery",\n },\n {\n id: "ORD-1002",\n customerName: "Emily Johnson",\n orderType: "Express Delivery",\n },\n ],\n persistence: SbVariablePersistence.TEMPORARY,\n }),\n filteredOrders: SbVariable({\n defaultValue: [],\n persistence: SbVariablePersistence.TEMPORARY,\n }),\n },\n {\n name: "Page1",\n },\n);\n```\n';
|
|
55
|
+
var content8 = '**Superblocks State System**\n\nThe Superblocks state system is built around scopes that contain entities (variables, APIs, components). Here\'s how it works:\n\n### 1. Scopes\n\nScopes are defined in separate `scope.ts` files for each page and contain all the page\'s entities.\n\n- **Page scopes** are visible only within the current page\n- **App scopes** can be shared across pages (though you should primarily use page scopes)\n- Entities are accessed by importing and destructuring from the scope\n\n> **Parent \u2192 child rule**: Child scopes can read & write parent entities, but parents cannot reach into children.\n\n### 2. Scope Structure\n\nEach page has its own scope file that defines all entities:\n\n```ts\n// pages/Page1/scope.ts\nimport {\n createSbScope,\n SbVariable,\n SbVariablePersistence,\n SbApi,\n sbComputed,\n} from "@superblocksteam/library";\n\nexport const Page1Scope = createSbScope<{\n OrdersTable: any;\n}>(\n ({ entities: { counter } }) => ({\n // Static state variable with a simple default value\n counter: SbVariable({\n defaultValue: 0,\n persistence: SbVariablePersistence.TEMPORARY,\n }),\n // State variable with computed default value from other entities\n doubledCounter: SbVariable({\n defaultValue: sbComputed(() => counter.value * 2),\n persistence: SbVariablePersistence.TEMPORARY,\n }),\n myApi: SbApi({}),\n }),\n {\n name: "Page1",\n },\n);\n\nexport const Page1 = Page1Scope.entities;\n```\n\nThen in your page component, you import and destructure the entities:\n\n```tsx\n// pages/Page1/index.tsx\nimport {\n SbPage,\n SbSection,\n SbColumn,\n SbText,\n SbButton,\n sbComputed,\n SbEventFlow,\n registerPage,\n} from "@superblocksteam/library";\nimport { Page1, Page1Scope } from "./scope";\n\nfunction Page() {\n // Destructure entities for easy access\n const { counter, doubledCounter, myApi, OrdersTable } = Page1;\n\n return (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n <SbText text={sbComputed(() => `Count: ${counter.value}`)} />\n <SbButton onClick={SbEventFlow.setStateVar("counter", 5)} />\n </SbColumn>\n </SbSection>\n </SbPage>\n );\n}\n\nexport default registerPage(Page, Page1Scope);\n```\n\n_You should NOT create any extra scopes other than page scopes in most cases._\n\n### 3. Computed Default Values\n\nState variables can have their `defaultValue` computed from other entities in the same scope at initialization time.\n\n**Static default value:**\n\n```ts\nstaticVar: SbVariable({\n defaultValue: "Hello World",\n});\n```\n\n**Computed default value:**\n\n```ts\n({ entities: { Input1, staticVar } }) => ({\n computedVar: SbVariable({\n defaultValue: sbComputed(() => `${staticVar.value} - ${Input1.value}`),\n }),\n});\n```\n\nWrap the entire scope object with the entities function and destructure needed entities from the `entities` parameter. This only sets the initial value - it doesn\'t create ongoing updates.\n\n### 4. Entity Types\n\n- **Component state**\n\n - Declared by defining the component type in the scope and using the `bind` prop\n - Accessed by destructuring the component entity and using `sbComputed(() => ComponentName.prop)`\n - Writable if the prop is marked writable in the schema\n\n- **State variable**\n\n - Declared with `SbVariable({ defaultValue })` or within `(({ entities }) => ({ ... }))` wrapper for computed defaults\n - `defaultValue` sets the initial value when the application loads\n - For static variables: Only JSON parsable data structures, no functions\n - For computed variables: Use `sbComputed` within defaultValue to reference other entities\n - Do not call `defaultValue` like a function. Set values with `SbEventFlow.setStateVar()` or read with `sbComputed(() => varName.value)`\n - Accessed with `sbComputed(() => varName.value)` \u2014 **always include `.value`**\n - Writable through SbEventFlow\n\n- **API**\n - Declared with `SbApi({})` in the scope file.\n - Accessed with `sbComputed(() => apiName.response)` or `sbComputed(() => apiName.error)`\n - Read\u2011only\n\n### 5. Reading State with sbComputed\n\n**CRITICAL**: There are two different patterns for accessing data in `sbComputed` depending on what you\'re accessing:\n\n#### 5.1. Scope Entities (Direct Access)\n\nFor entities defined in your scope file (variables, APIs, components), access them **directly** after destructuring:\n\n```tsx\nconst { UserSearchInput, myVariable, myApi } = Page1;\n\n// \u2705 CORRECT - Direct access for scope entities\n<SbText text={sbComputed(() => `Search: ${UserSearchInput.value}`)} />\n<SbText text={sbComputed(() => myVariable.value)} />\n<SbTable tableData={sbComputed(() => myApi.response)} />\n```\n\n#### 4.2. Global State (Import Access)\n\nFor global state like globals, theme, environment, and embedded data, import the globals directly from the library:\n\n```tsx\n// \u2705 CORRECT - Import globals directly\n<SbText\n text={sbComputed(() => `Welcome ${Global.user.name}!`)}\n textStyle={{\n textColor: {\n default: sbComputed(() => Theme.colors.neutral900)\n }\n }}\n/>\n<SbContainer backgroundColor={sbComputed(() => Theme.colors.primary)} />\n```\n\n#### 5.3. Mixed Access\n\nWhen you need both scope entities and global state in the same `sbComputed`:\n\n```tsx\nconst { orders } = Page1;\n\n// \u2705 CORRECT - Combine direct entity access with imported globals\n<SbText\n text={sbComputed(() => `${orders.length} orders for ${Global.user.name}`)}\n/>;\n```\n\n### 6. Writing State\n\nPreferred approach:\n\n```tsx\nSbEventFlow.setStateVar("pageSize", 50);\n```\n\nFallback for complex operations:\n\n```tsx\nSbEventFlow.runJS(() => {\n // Direct assignment works within SbEventFlow.runJS\n pageSize.value = 50;\n});\n```\n\n### 7. CRITICAL Rules\n\n1. **Use component state directly**; NEVER create a state variable for a value that is available directly from a component property.\n2. Use component bindings by defining component types in your scope and using the `bind` prop.\n3. Keep logic declarative \u2014 derive UI from state using `sbComputed` instead of mutating props at runtime.\n4. Always destructure entities from your scope for clean access patterns.\n5. **Use the correct sbComputedz pattern**: Direct access for scope entities, import globals (Global, Theme, Embed, Env) for global access.\n6. Always complete implement all features, don\'t stub out or skip anything.\n\n**\u2705 Example**\n\n```tsx\n// In your scope.ts file\nexport const Page1Scope = createSbScope<{\n ApplicantSelector: any;\n}>(\n () => ({\n applicants: SbVariable({ defaultValue: [] }),\n }),\n {\n name: "Page1",\n },\n);\n```\n\n```tsx\n// In your page component after destructuring entities\nconst { ApplicantSelector, applicants } = Page1;\n\n<SbDropdown bind={ApplicantSelector} options={/* ... */} />\n<SbTable tableData={sbComputed(() => applicants[ApplicantSelector.selectedOptionValue])} />\n```\n\n```tsx\n// In your scope.ts file\nexport const Page1Scope = createSbScope<{\n FirstName: any;\n LastName: any;\n}>(\n ({ entities: { FirstName, LastName } }) => ({\n applicants: SbVariable({ defaultValue: [] }),\n fullName: SbVariable({\n defaultValue: sbComputed(() =>\n `${FirstName.value} ${LastName.value}`.trim(),\n ),\n }),\n }),\n {\n name: "Page1",\n },\n);\n```\n\n```tsx\nconst { FirstName, LastName, fullName } = Page1;\n\n<SbInput bind={FirstName} placeholder="First name" />\n<SbInput bind={LastName} placeholder="Last name" />\n<SbText text={sbComputed(() => `Welcome ${fullName.value}!`)} />\n```\n\n```tsx\n{\n /* The user types in the search input, and the value is displayed */\n}\n// In your scope.ts file\nexport const Page1Scope = createSbScope<{\n searchTerm: any;\n}>(() => ({}), {\n name: "Page1",\n});\n```\n\n```tsx\nconst { searchTerm } = Page1;\n\n<SbInput bind={searchTerm} />\n<SbText text={sbComputed(() => searchTerm.value)} />\n```\n\n```tsx\n{\n /* Switch to change into admin mode */\n}\n// In your scope.ts file\nexport const Page1Scope = createSbScope<{\n isAdmin: any;\n}>(() => ({}), {\n name: "Page1",\n});\n```\n\n```tsx\nconst { isAdmin } = Page1;\n\n<SbSwitch bind={isAdmin} label="Use Admin Mode" defaultChecked={false} />;\n{\n /* Only enable the delete button when switched into Admin mode */\n}\n<SbButton\n disabled={sbComputed(() => !isAdmin.isChecked)}\n label="Delete profile"\n/>;\n```\n\n\u2705 ALWAYS USE DIRECT COMPONENT STATE ACCESS WITH sbComputed:\n\n```tsx\n// GOOD - DO THIS\n// In your scope.ts file\nexport const Page1Scope = createSbScope<{\n UserNameInput: any;\n}>(() => ({}), {\n name: "Page1",\n});\n```\n\n```tsx\nconst { UserNameInput } = Page1;\n\n<SbTextInput bind={UserNameInput} />\n<SbText text={sbComputed(() => `Hello, ${UserNameInput.value}!`)} />\n```\n\n\u274C NEVER CREATE REDUNDANT STATE VARIABLES:\n\n```tsx\n// WRONG - DON\'T DO THIS\n<SbTextInput bind={UserNameInput} onChange={SbEventFlow.setStateVar(\'userNameVar\', \'myValue\')} />\n<SbText text={sbComputed(() => `Hello, ${userNameVar.value}!`)} />\n...\n// And then in scope.ts:\n{\n userNameVar: SbVariable({ defaultValue: "" }),\n}\n```\n\nTo reference a property of a component using `sbComputed`, the component must have a binding defined in your scope.\n\nThat\'s why you should ALWAYS define component bindings in your scope for the following component types when you need to access their state:\n\n- SbInput\n- SbDropdown\n- SbDatePicker\n- SbCheckbox\n- SbSwitch\n- SbForm\n- SbRadio\n- SbRichText\n- SbFilePicker\n- SbCodeEditor\n- SbChat\n\n\u274C DO NOT USE STATE VARIABLES AS FUNCTIONS:\n\nState variables are not functions. You cannot call them or store functions in defaultValue.\n\n```tsx\n// WRONG - DON\'T DO THIS\nfunction Page1() {\n const { customerNameFilter, filterOrders } = Page1;\n\n return (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n <SbInput\n bind={customerNameFilter}\n label="Customer Name"\n placeholder="Filter by customer name"\n width={Dim.fill()}\n onTextChanged={SbEventFlow.runJS(() => {\n // This is wrong - you cannot call filterOrders as a function\n filterOrders();\n })}\n />\n </SbColumn>\n </SbSection>\n </SbPage>\n );\n}\n\n// And in scope.ts (WRONG):\n{\n filterOrders: SbVariable({\n defaultValue: () => {\n // This doesn\'t work - state variables are not functions\n const customerNameFilter = customerNameFilter.value.toLowerCase();\n // ... more logic\n },\n });\n}\n```\n\nInstead do the following:\n\n\u2705 COMPUTE VALUES WITH sbComputed AND SET STATE WITH SbEventFlow:\n\n```tsx\n// CORRECT - DO THIS\nimport {\n SbPage,\n SbSection,\n SbColumn,\n SbInput,\n SbButton,\n SbTable,\n sbComputed,\n SbEventFlow,\n registerPage,\n} from "@superblocksteam/library";\n\nfunction Page1() {\n const { customerNameFilter, filteredOrders, orders } = Page1;\n\n return (\n <SbPage name="Page1" height={Dim.fill()} width={Dim.fill()}>\n <SbSection height={Dim.fill()}>\n <SbColumn width={Dim.fill()}>\n <SbInput\n bind={customerNameFilter}\n label="Customer Name"\n placeholder="Filter by customer name"\n width={Dim.fill()}\n onTextChanged={SbEventFlow.runJS(() => {\n // Repeat the filtering logic inline - do NOT create helper functions\n const filtered = orders.value.filter((order) => {\n return (\n !customerNameFilter.value ||\n order.customerName\n .toLowerCase()\n .includes(customerNameFilter.value.toLowerCase())\n );\n });\n\n // Set the state variable with the computed result\n filteredOrders.value = filtered;\n })}\n />\n {/* If you need the same filtering logic elsewhere, repeat it inline */}\n <SbButton\n label="Apply Filter"\n onClick={SbEventFlow.runJS(() => {\n // Repeat the same filtering logic here - code repetition is preferred\n const filtered = orders.value.filter((order) => {\n return (\n !customerNameFilter.value ||\n order.customerName\n .toLowerCase()\n .includes(customerNameFilter.value.toLowerCase())\n );\n });\n\n filteredOrders.value = filtered;\n })}\n />\n <SbTable tableData={sbComputed(() => filteredOrders.value)} />\n </SbColumn>\n </SbSection>\n </SbPage>\n );\n}\n\nexport default registerPage(Page1, Page1Scope);\n```\n\nAnd in your scope.ts file:\n\n```ts\nexport const Page1Scope = createSbScope<{\n customerNameFilter: any;\n}>(\n () => ({\n orders: SbVariable({\n defaultValue: [\n {\n id: "ORD-1001",\n customerName: "John Smith",\n orderType: "Grocery Delivery",\n },\n {\n id: "ORD-1002",\n customerName: "Emily Johnson",\n orderType: "Express Delivery",\n },\n ],\n persistence: SbVariablePersistence.TEMPORARY,\n }),\n filteredOrders: SbVariable({\n defaultValue: [],\n persistence: SbVariablePersistence.TEMPORARY,\n }),\n }),\n {\n name: "Page1",\n },\n);\n```\n';
|
|
56
56
|
|
|
57
57
|
// ../../../vite-plugin-file-sync/dist/ai-service/prompts/generated/subprompts/superblocks-theming.js
|
|
58
58
|
init_cjs_shims();
|
package/dist/index.js
CHANGED
|
@@ -263726,7 +263726,7 @@ init_esm();
|
|
|
263726
263726
|
// ../sdk/package.json
|
|
263727
263727
|
var package_default = {
|
|
263728
263728
|
name: "@superblocksteam/sdk",
|
|
263729
|
-
version: "2.0.0-next.
|
|
263729
|
+
version: "2.0.0-next.9",
|
|
263730
263730
|
type: "module",
|
|
263731
263731
|
description: "Superblocks JS SDK",
|
|
263732
263732
|
homepage: "https://www.superblocks.com",
|
|
@@ -263763,8 +263763,8 @@ var package_default = {
|
|
|
263763
263763
|
"@rollup/wasm-node": "^4.35.0",
|
|
263764
263764
|
"@superblocksteam/bucketeer-sdk": "0.4.1",
|
|
263765
263765
|
"@superblocksteam/shared": "0.9122.0",
|
|
263766
|
-
"@superblocksteam/util": "2.0.0-next.
|
|
263767
|
-
"@superblocksteam/vite-plugin-file-sync": "2.0.0-next.
|
|
263766
|
+
"@superblocksteam/util": "2.0.0-next.9",
|
|
263767
|
+
"@superblocksteam/vite-plugin-file-sync": "2.0.0-next.9",
|
|
263768
263768
|
"@vitejs/plugin-react": "^4.3.4",
|
|
263769
263769
|
axios: "^1.4.0",
|
|
263770
263770
|
chokidar: "^4.0.3",
|
|
@@ -301862,7 +301862,7 @@ var SbScopeManager = class extends EventEmitter5 {
|
|
|
301862
301862
|
const entityNode = this.sourceTracker.getElementToLocation(entityId);
|
|
301863
301863
|
const filePath = this.sourceTracker.getElementToFilePath(entityId);
|
|
301864
301864
|
if (!entityNode || !(0, import_types20.isObjectProperty)(entityNode.node)) {
|
|
301865
|
-
throw new Error("Entity to update not found" + entityId);
|
|
301865
|
+
throw new Error("Entity to update not found " + entityId);
|
|
301866
301866
|
}
|
|
301867
301867
|
if (!filePath) {
|
|
301868
301868
|
throw new Error("File path not found for entity: " + entityId);
|
|
@@ -301947,7 +301947,12 @@ var SbScopeManager = class extends EventEmitter5 {
|
|
|
301947
301947
|
key2.replaceWith(import_types20.default.identifier(newName));
|
|
301948
301948
|
}
|
|
301949
301949
|
scopeDef.entityNames = scopeDef.entityNames.map((name17) => name17 === oldName ? newName : name17);
|
|
301950
|
-
scopeDef.
|
|
301950
|
+
const newEntityId = getScopeElementId(scopeDef.id, newName);
|
|
301951
|
+
this.sourceTracker.deleteElementToLocation(entityId);
|
|
301952
|
+
this.sourceTracker.deleteElementToFilePath(entityId);
|
|
301953
|
+
scopeDef.scopeNameToEntityId[newName] = newEntityId;
|
|
301954
|
+
this.sourceTracker.setElementToLocation(newEntityId, entityNode);
|
|
301955
|
+
this.sourceTracker.setElementToFilePath(newEntityId, filePath);
|
|
301951
301956
|
delete scopeDef.scopeNameToEntityId[oldName];
|
|
301952
301957
|
const updatedFiles = this.updateScopeUsages(scopeDef.name, scopeDef.entityNames);
|
|
301953
301958
|
updateDestructuredEntitiesParam(scopeDef);
|
|
@@ -308611,7 +308616,7 @@ async function startVite({ app, httpServer: httpServer2, root: root2, mode, port
|
|
|
308611
308616
|
};
|
|
308612
308617
|
const isCustomBuildEnabled2 = await isCustomComponentsEnabled();
|
|
308613
308618
|
const customFolder = path21.join(root2, "custom");
|
|
308614
|
-
const cdnUrl = "https://assets-cdn.superblocks.com/library/2.0.0-next.
|
|
308619
|
+
const cdnUrl = "https://assets-cdn.superblocks.com/library/2.0.0-next.9";
|
|
308615
308620
|
const env3 = loadEnv(mode, root2, "");
|
|
308616
308621
|
const hmrPort = await getFreePort();
|
|
308617
308622
|
const hmrOptions = {
|
|
@@ -314943,7 +314948,7 @@ var templates = {
|
|
|
314943
314948
|
"shim-loader.mjs": 'import path from "path";\nimport { pathToFileURL } from "url";\n\nconst overrideMap = {\n "@superblocksteam/library": "./dist/superblocks-library-shim/index.js",\n};\n\nexport async function resolve(specifier, context, nextResolve) {\n if (overrideMap[specifier]) {\n const fullPath = path.resolve(overrideMap[specifier]);\n return {\n shortCircuit: true,\n url: pathToFileURL(fullPath).href,\n };\n }\n\n return nextResolve(specifier, context);\n}\n',
|
|
314944
314949
|
"src/do-eval-to-sdk.ts": 'import fs from "fs";\nimport path from "path";\nimport { fileURLToPath } from "url";\n\n// finds all JavaScript files in the `dist/apis-to-transform` directory,\n// imports each module, converts its JSON representation to SDK,\n// and outputs a JSON map with filenames as keys and SDK content as values.\n\nasync function main() {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = path.dirname(__filename);\n\n const apisDir = path.resolve(__dirname, "./to-sdk");\n\n const files = fs.readdirSync(apisDir);\n\n const jsFiles = files.filter(\n (file) => file.endsWith(".js") && file !== "__template__.js",\n );\n\n const results: Record<string, string> = {};\n\n for (const jsFile of jsFiles) {\n const filePath = path.join(apisDir, jsFile);\n const absolutePath = path.resolve(filePath);\n\n try {\n const fileUrl = new URL(`file://${absolutePath}`);\n const module = await import(fileUrl.href);\n\n const defaultExport = module.default;\n\n if (defaultExport && typeof defaultExport.toSDK === "function") {\n const sdkData = await defaultExport.toSDK();\n\n results[jsFile] = sdkData;\n } else {\n console.warn(`${jsFile}: Default export doesn\'t have a toSDK method`);\n }\n } catch (error) {\n console.error(`Error processing ${jsFile}:`, error);\n }\n }\n\n console.log(JSON.stringify(results, null, 2));\n}\n\nmain().catch((error) => {\n console.error("Error:", error);\n process.exit(1);\n});\n',
|
|
314945
314950
|
"src/do-eval-to-yaml.ts": 'import fs from "fs";\nimport path from "path";\nimport { fileURLToPath } from "url";\nimport yaml from "yaml";\n\n// finds all JavaScript files in the `dist/apis-to-transform` directory,\n// imports each module, converts its JSON representation to YAML,\n// and outputs a JSON map with filenames as keys and YAML content as values.\n\nasync function main() {\n const __filename = fileURLToPath(import.meta.url);\n const __dirname = path.dirname(__filename);\n\n const apisDir = path.resolve(__dirname, "./to-yaml");\n\n const files = fs.readdirSync(apisDir);\n\n const jsFiles = files.filter((file) => file.endsWith(".js"));\n\n const results: Record<string, string> = {};\n\n for (const jsFile of jsFiles) {\n const filePath = path.join(apisDir, jsFile);\n const absolutePath = path.resolve(filePath);\n\n try {\n const fileUrl = new URL(`file://${absolutePath}`);\n const module = await import(fileUrl.href);\n\n const defaultExport = module.default;\n\n if (defaultExport && typeof defaultExport.toJSON === "function") {\n const jsonData = await defaultExport.toJSON();\n\n const yamlContent = yaml.stringify(jsonData);\n\n results[jsFile] = yamlContent;\n } else {\n console.warn(`${jsFile}: Default export doesn\'t have a toJSON method`);\n }\n } catch (error) {\n console.error(`Error processing ${jsFile}:`, error);\n }\n }\n\n console.log(JSON.stringify(results, null, 2));\n}\n\nmain().catch((error) => {\n console.error("Error:", error);\n process.exit(1);\n});\n',
|
|
314946
|
-
"src/superblocks-library-shim/index.ts": '/* eslint-disable */\nimport typescript_eslint_parser from "@typescript-eslint/parser";\nimport { CallExpression, ExpressionStatement, FunctionExpression, Node, parse, Program, UnaryExpression } from "acorn";\nimport { ESLint } from "eslint";\nimport { format } from "prettier";\n\nexport type JsonValue =\n | undefined\n | null\n | number\n | string\n | boolean\n | Array<JsonValue>\n | { [key: string]: JsonValue };\nexport type State = { [key: string]: JsonValue };\nexport type Binding<T> = T | ((state: State) => T);\n\nexport const code = (\n fn: string,\n options: { iife?: boolean } = { iife: false },\n): string => {\n // Parse the function string\n const ast = parse(fn, {\n ecmaVersion: "latest",\n sourceType: "script",\n });\n\n // Find the function declaration/expression\n let functionNode;\n\n // Walk through the AST to find the function\n if (ast.body[0].type === "FunctionDeclaration") {\n // Function declaration: function name() {}\n functionNode = ast.body[0];\n } else if (\n ast.body[0].type === "ExpressionStatement" &&\n (ast.body[0].expression.type === "FunctionExpression" ||\n ast.body[0].expression.type === "ArrowFunctionExpression")\n ) {\n // Function expression: const name = function() {} or const name = () => {}\n functionNode = ast.body[0].expression;\n } else if (\n ast.body[0].type === "VariableDeclaration" &&\n (ast.body[0].declarations[0]?.init?.type === "FunctionExpression" ||\n ast.body[0].declarations[0]?.init?.type === "ArrowFunctionExpression")\n ) {\n // Variable declaration: const name = function() {} or const name = () => {}\n functionNode = ast.body[0].declarations[0]?.init;\n }\n\n if (!functionNode) {\n throw new Error("Could not find a function in the provided string");\n }\n\n // Get the function body\n const body = functionNode.body;\n\n // Extract the source from the original string\n // For arrow functions with an expression body, we return the expression\n if (\n functionNode.type === "ArrowFunctionExpression" &&\n body.type !== "BlockStatement"\n ) {\n // Arrow function with expression body: () => 42\n const expressionCode = fn.substring(fn.indexOf("=>") + 2).trim();\n return options.iife\n ? `(() => ${expressionCode})()`\n : `return ${expressionCode}`;\n }\n\n // For functions with block bodies, extract content between braces\n const start = body.start + 1; // Skip the opening brace\n const end = body.end - 1; // Skip the closing brace\n\n // Get the raw body content\n const rawBodyLines = fn.substring(start, end).split("\\n");\n\n if (rawBodyLines.length <= 1) {\n // Single line body, just trim it\n const bodyCode = rawBodyLines[0].trim();\n\n if (options.iife) {\n const paramStart = fn.indexOf("(");\n const paramEnd = fn.indexOf(")", paramStart);\n const params = fn.substring(paramStart, paramEnd + 1);\n return `(${params} => { ${bodyCode} })()`;\n }\n\n return bodyCode;\n }\n\n // For multi-line bodies, normalize indentation\n // Find the minimum indentation level (ignoring empty lines)\n let minIndent = Infinity;\n for (const line of rawBodyLines) {\n const trimmedLine = line.trimStart();\n if (trimmedLine.length > 0) {\n const indent = line.length - trimmedLine.length;\n minIndent = Math.min(minIndent, indent);\n }\n }\n\n // Remove the common indentation from each line\n const normalizedLines = rawBodyLines.map((line) => {\n if (line.trimStart().length === 0) return "";\n return line.substring(minIndent);\n });\n\n // Join the normalized lines\n const bodyCode = normalizedLines\n .join(" ")\n .replace(/\\s{2,}/g, " ")\n .trim();\n\n if (options.iife) {\n const paramStart = fn.indexOf("(");\n const paramEnd = fn.indexOf(")", paramStart);\n const params = fn.substring(paramStart, paramEnd + 1);\n return `(${params} => { ${bodyCode} })()`;\n }\n\n return bodyCode;\n};\n\nasync function binding(binding: Binding<string>): Promise<string> {\n if (typeof binding === "function") {\n return await toJS(binding);\n }\n\n return binding;\n}\n\ninterface Codec {\n toJSON(): Promise<JsonValue>;\n toSDK(entities: string[]): Promise<string>;\n}\n\nexport abstract class Block implements Codec {\n protected name: string;\n\n constructor(name: string) {\n this.name = name;\n }\n\n public abstract toJSON(): Promise<JsonValue>;\n public abstract toSDK(entities: string[]): Promise<string>;\n\n public static fromJSON(json: any, entities: string[]): Block {\n if (json?.step) {\n return Integration.fromJSON(json, entities);\n }\n\n if ("conditional" in json) {\n return Conditional.fromJSON(json, entities);\n }\n\n if ("loop" in json) {\n return Loop.fromJSON(json, entities);\n }\n\n if ("parallel" in json) {\n return Parallel.fromJSON(json, entities);\n }\n\n if ("tryCatch" in json) {\n return TryCatch.fromJSON(json, entities);\n }\n\n if ("variables" in json) {\n return Variables.fromJSON(json, entities);\n }\n\n if ("throw" in json) {\n return Throw.fromJSON(json, entities);\n }\n\n if ("return" in json) {\n return Return.fromJSON(json, entities);\n }\n\n throw new Error("mysterious block");\n }\n}\n\nexport abstract class Integration extends Block {\n protected integration: string;\n\n constructor(name: string, integration: string) {\n super(name);\n\n this.integration = integration;\n }\n\n public abstract toJSON(): Promise<JsonValue>;\n public abstract toSDK(entities: string[]): Promise<string>;\n\n public static fromJSON(json: any, entities: string[]): Block {\n if ("javascript" in json?.step) {\n return JavaScript.fromJSON(json, entities);\n }\n\n if ("python" in json?.step) {\n return Python.fromJSON(json, entities);\n }\n\n if ("postgres" in json?.step) {\n return PostgreSQL.fromJSON(json, entities);\n }\n\n if ("databricks" in json?.step) {\n return Databricks.fromJSON(json, entities);\n }\n\n if ("email" in json?.step) {\n return Email.fromJSON(json, entities);\n }\n\n if ("restapi" in json?.step) {\n return RestApi.fromJSON(json, entities);\n }\n\n throw new Error("mysterious integration");\n }\n}\n\nexport class Python extends Integration {\n private fn: string;\n\n constructor(name: string, config: {\n fn: string;\n }) {\n super(name, "python");\n\n this.fn = config.fn;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n step: {\n integration: "python",\n python: {\n body: this.fn,\n },\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new Python("${this.name}", { fn: ${this.fn} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): Python {\n return new Python(json?.name, {\n fn: json?.step?.python?.body,\n });\n }\n}\n\nexport class JavaScript extends Integration {\n private fn: (_: State) => JsonValue;\n\n constructor(\n name: string,\n config: {\n fn: (_: State) => JsonValue;\n },\n ) {\n super(name, "javascript");\n\n this.fn = config.fn;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n step: {\n integration: "javascript",\n javascript: {\n body: await toJSBody(this.fn, { block: false, function: true }),\n },\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new JavaScript("${this.name}", { fn: ${signature(code(this.fn.toString()), entities)} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): JavaScript {\n const args = [json?.step?.javascript?.body]\n const references = referenced(json?.step?.javascript?.body, entities)\n\n if (references.length > 0) {\n args.unshift(`{ ${references.join(", ")} }`)\n }\n\n return new JavaScript(json?.name, {\n fn: new Function(...args) as (_: State) => JsonValue,\n });\n }\n}\n\n// TODO(Frank): There is way too much in common between Snowflake and PostgreSQL. Need to add a parent class for these.\nexport class Snowflake extends Integration {\n private statement: Binding<string>;\n\n constructor(\n name: string,\n integration: string,\n config: {\n statement: Binding<string>;\n },\n ) {\n super(name, integration);\n\n this.statement = config.statement;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n step: {\n integration: this.integration,\n snowflake: {\n body: await binding(this.statement),\n usePreparedSql: false,\n },\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new Snowflake("${this.name}", "${this.integration}", { statement: ${typeof this.statement === "function" ? signatureV2(await toJSBody(this.statement), entities) : `"${this.statement}"`} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): Snowflake {\n return new Snowflake(json?.name, json?.step?.integration, {\n statement: fromBinding(\n json?.step?.snowflake?.body as string | undefined,\n entities,\n ),\n });\n }\n}\n\nexport class PostgreSQL extends Integration {\n private statement: Binding<string>;\n\n constructor(\n name: string,\n integration: string,\n config: {\n statement: Binding<string>;\n },\n ) {\n super(name, integration);\n\n this.statement = config.statement;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n step: {\n integration: this.integration,\n postgres: {\n body: await binding(this.statement),\n usePreparedSql: false,\n operation: "run_sql",\n },\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new PostgreSQL("${this.name}", "${this.integration}", { statement: ${typeof this.statement === "function" ? signatureV2(await toJSBody(this.statement), entities) : `"${this.statement}"`} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): PostgreSQL {\n return new PostgreSQL(json?.name, json?.step?.integration, {\n statement: fromBinding(\n json?.step?.postgres?.body as string | undefined,\n entities,\n ),\n });\n }\n}\n\nexport class RestApi extends Integration {\n private method: string;\n private url: Binding<string>;\n private headers?: { key: Binding<string>; value: Binding<string> }[];\n private params?: { key: Binding<string>; value: Binding<string> }[];\n private body?: Binding<string>;\n\n constructor(\n name: string,\n config: {\n method: string;\n url?: Binding<string>;\n headers?: { key: Binding<string>; value: Binding<string> }[];\n params?: { key: Binding<string>; value: Binding<string> }[];\n body?: Binding<string>;\n },\n ) {\n super(name, "restapi");\n\n this.method = config.method;\n this.url = config.url;\n this.headers = config.headers;\n this.params = config.params;\n this.body = config.body;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n step: {\n integration: "restapi",\n restapi: {\n httpMethod: this.method,\n ...(this.url ? { url: await binding(this.url) } : {}),\n ...(this.headers ? { headers: await Promise.all(this.headers.map(async (header) => ({ key: await binding(header.key), value: await binding(header.value) }))) } : {}),\n ...(this.params ? { params: await Promise.all(this.params.map(async (param) => ({ key: await binding(param.key), value: await binding(param.value) }))) } : {}),\n ...(this.body ? { body: await binding(this.body) } : {}),\n },\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n const parts: string[] = [`method: "${this.method}"`];\n\n if (this.url) {\n parts.push(\n `url: ${\n typeof this.url === "function"\n ? signatureV2(await toJSBody(this.url), entities)\n : `"${this.url}"`\n }`,\n );\n }\n\n if (this.headers) {\n const headers = this.headers\n .map(async (h) =>\n `{ key: ${\n typeof h.key === "function"\n ? signatureV2(await toJSBody(h.key), entities)\n : `"${h.key}"`\n }, value: ${\n typeof h.value === "function"\n ? signatureV2(await toJSBody(h.value), entities)\n : `"${h.value}"`\n } }`,\n )\n .join(", ");\n parts.push(`headers: [${headers}]`);\n }\n\n if (this.params) {\n const params = this.params\n .map(async (p) =>\n `{ key: ${\n typeof p.key === "function"\n ? signatureV2(await toJSBody(p.key), entities)\n : `"${p.key}"`\n }, value: ${\n typeof p.value === "function"\n ? signatureV2(await toJSBody(p.value), entities)\n : `"${p.value}"`\n } }`,\n )\n .join(", ");\n parts.push(`params: [${params}]`);\n }\n\n if (this.body) {\n parts.push(\n `body: ${\n typeof this.body === "function"\n ? signatureV2(await toJSBody(this.body), entities)\n : JSON.stringify(this.body)\n }`,\n );\n }\n\n return `new RestApi("${this.name}", { ${parts.join(", ")} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): RestApi {\n return new RestApi(json?.name, {\n method: json?.step?.restapi?.httpMethod,\n url: fromBinding(json?.step?.restapi?.url, entities),\n headers: json?.step?.restapi?.headers?.map((header: any) => ({ key: fromBinding(header.key, entities), value: fromBinding(header.value, entities) })),\n params: json?.step?.restapi?.params?.map((param: any) => ({ key: fromBinding(param.key, entities), value: fromBinding(param.value, entities) })),\n body: fromBinding(json?.step?.restapi?.body, entities),\n });\n }\n}\n\nexport class Email extends Integration {\n private subject: Binding<string>;\n private from: Binding<string>; // comma separated list\n private to: Binding<string>; // comma separated list\n private cc?: Binding<string>; // comma separated list\n private bcc?: Binding<string>; // comma separated list\n private body: Binding<string>;\n\n constructor(\n name: string,\n config: {\n from: Binding<string>;\n to: Binding<string>;\n subject: Binding<string>;\n cc?: Binding<string>;\n bcc?: Binding<string>;\n body?: Binding<string>;\n },\n ) {\n super(name, "email");\n\n this.from = config.from;\n this.to = config.to;\n this.subject = config.subject;\n this.cc = config.cc;\n this.bcc = config.bcc;\n this.body = config.body;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n step: {\n integration: "email",\n email: {\n ...(this.from ? { emailFrom: await binding(this.from) } : {}),\n ...(this.to ? { emailTo: await binding(this.to) } : {}),\n ...(this.cc ? { emailCc: await binding(this.cc) } : {}),\n ...(this.bcc ? { emailBcc: await binding(this.bcc) } : {}),\n ...(this.subject ? { emailSubject: await binding(this.subject) } : {}),\n ...(this.body ? { emailBody: await binding(this.body) } : {}),\n },\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n const parts: string[] = [];\n\n if (this.from) {\n parts.push(\n `from: ${\n typeof this.from === "function"\n ? signatureV2(code(this.from.toString()), entities)\n : `"${this.from}"`\n }`,\n );\n }\n\n if (this.to) {\n parts.push(\n `to: ${\n typeof this.to === "function"\n ? signatureV2(code(this.to.toString()), entities)\n : `"${this.to}"`\n }`,\n );\n }\n\n if (this.cc) {\n parts.push(\n `cc: ${\n typeof this.cc === "function"\n ? signatureV2(code(this.cc.toString()), entities)\n : `"${this.cc}"`\n }`,\n );\n }\n\n if (this.bcc) {\n parts.push(\n `bcc: ${\n typeof this.bcc === "function"\n ? signatureV2(code(this.bcc.toString()), entities)\n : `"${this.bcc}"`\n }`,\n );\n }\n\n if (this.subject) {\n parts.push(\n `subject: ${\n typeof this.subject === "function"\n ? signatureV2(code(this.subject.toString()), entities)\n : `"${this.subject}"`\n }`,\n );\n }\n\n if (this.body) {\n parts.push(\n `body: ${\n typeof this.body === "function"\n ? signatureV2(code(this.body.toString()), entities)\n : `"${this.body}"`\n }`,\n );\n }\n\n return `new Email("${this.name}", { ${parts.join(", ")} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): Email {\n return new Email(json?.name, {\n from: fromBinding(json?.step?.email?.emailFrom, entities),\n to: fromBinding(json?.step?.email?.emailTo, entities),\n subject: fromBinding(json?.step?.email?.emailSubject, entities),\n body: fromBinding(json?.step?.email?.emailBody, entities),\n cc: json?.step?.email?.emailCc ? fromBinding(json?.step?.email?.emailCc, entities) : undefined,\n bcc: json?.step?.email?.emailBcc ? fromBinding(json?.step?.email?.emailBcc, entities) : undefined,\n });\n }\n}\n\nexport class Databricks extends Integration {\n private statement: Binding<string>;\n\n constructor(\n name: string,\n integration: string,\n config: {\n statement: Binding<string>;\n },\n ) {\n super(name, integration);\n\n this.statement = config.statement;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n step: {\n integration: this.integration,\n databricks: {\n runSql: {\n sqlBody: await binding(this.statement),\n useParameterized: false,\n },\n },\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new Databricks("${this.name}", "${this.integration}", { statement: ${typeof this.statement === "function" ? signatureV2(await toJSBody(this.statement), entities) : `"${this.statement}"`} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): Databricks {\n return new Databricks(json?.name, json?.step?.integration, {\n statement: fromBinding(\n json?.step?.databricks?.runSql?.sqlBody as string,\n entities,\n ),\n });\n }\n}\n\nexport type Condition = {\n when: Binding<boolean>;\n then: Block[];\n};\n\nasync function conditionToSDK(condition: Condition, entities: string[]): Promise<string> {\n return `{ when: ${typeof condition.when === "function" ? signatureV2(await toJSBody(condition.when), entities) : condition.when}, then: [${(await Promise.all(condition.then.map(async (block) => await block.toSDK(entities)))).join(",")}] }`\n}\n\nexport type Conditions = {\n if: Condition;\n elif?: Condition[];\n else?: Block[];\n};\n\nexport class Conditional extends Block {\n public conditions: Conditions;\n\n constructor(name: string, config: Conditions) {\n super(name);\n\n this.conditions = config;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n conditional: {\n if: {\n condition: await toJS<boolean>(this.conditions.if.when),\n blocks: await Promise.all(this.conditions.if.then.map(async (block) => await block.toJSON())),\n },\n ...await (async () =>\n this.conditions.elif\n ? {\n elseIf: await Promise.all(this.conditions.elif.map(async (condition) => ({\n condition: await toJS<boolean>(condition.when),\n blocks: await Promise.all(condition.then.map(async (block) => await block.toJSON())),\n }))),\n }\n : { elseIf: [] })(),\n else: this.conditions.else ? {\n blocks: await Promise.all(this.conditions.else.map(async (block) => await block.toJSON()))\n } : undefined,\n },\n };\n }\n\n public static fromJSON(json: any, entities: string[]): Conditional {\n return new Conditional(json?.name, {\n if: {\n when: fromJS<boolean>(json?.conditional?.if?.condition, entities),\n then: json?.conditional?.if?.blocks.map((block: any) =>\n Block.fromJSON(block, entities),\n ),\n },\n elif: json?.conditional?.elseIf ? json?.conditional?.elseIf?.map((condition: any) => ({\n when: fromJS<boolean>(condition.condition, entities),\n then: condition.blocks.map((block: any) => Block.fromJSON(block, entities)),\n })) : [],\n else: json?.conditional?.else ? json?.conditional?.else?.blocks?.map((block: any) => Block.fromJSON(block, entities)) : [],\n });\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new Conditional("${this.name}", { if: ${await conditionToSDK(this.conditions.if, entities)}, elif: [${this.conditions.elif ? (await Promise.all(this.conditions.elif?.map(async (condition) => await conditionToSDK(condition, entities)))).join(",") : \'\'}], else: ${this.conditions.else ? (await Promise.all(this.conditions.else?.map(async (block) => await block.toSDK(entities)))).join(",") : "undefined"} })`;\n }\n}\n\nexport class Parallel extends Block {\n private over: Binding<JsonValue[]>;\n private blocks: Block[];\n private variables: { item: string };\n\n constructor(\n name: string,\n config: {\n over: Binding<JsonValue[]>;\n variables: { item: string };\n blocks: Block[];\n },\n ) {\n super(name);\n\n this.over = config.over;\n this.blocks = config.blocks;\n this.variables = config.variables;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n parallel: {\n dynamic: {\n blocks: await Promise.all(this.blocks?.map(async (block) => await block.toJSON())),\n paths: await toJS<JsonValue[]>(this.over),\n variables: this.variables,\n },\n wait: "WAIT_ALL",\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new Parallel("${this.name}", { over: ${typeof this.over === "function" ? signatureV2(await toJSBody(this.over), entities) : this.over}, variables: ${this.variables}, blocks: ${await Promise.all(this.blocks.map(async (block) => await block.toSDK(entities)).join(","))} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): Parallel {\n return new Parallel(json?.name, {\n over: fromJS<JsonValue[]>(json?.parallel?.dynamic?.paths, entities),\n variables: {\n item: json?.parallel?.dynamic?.variables?.item,\n },\n blocks: json?.parallel?.dynamic?.blocks.map((block: any) =>\n Block.fromJSON(block, entities),\n ),\n });\n }\n}\n\nexport class Loop extends Block {\n private over: Binding<JsonValue[]>; // NOTE(Frank): Only for each loops are supported at the moment.\n private blocks: Block[];\n private variables: { item: string; index: string };\n\n constructor(\n name: string,\n config: {\n over: Binding<JsonValue[]>;\n variables: { item: string; index: string };\n blocks: Block[];\n },\n ) {\n super(name);\n\n this.over = config.over;\n this.variables = config.variables;\n this.blocks = config.blocks;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n loop: {\n range: await toJS<JsonValue[]>(this.over),\n type: "TYPE_FOREACH",\n variables: this.variables,\n blocks: await Promise.all(this.blocks.map(async (block) => await block.toJSON())),\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new Loop("${this.name}", { over: ${typeof this.over === "function" ? signatureV2(await toJSBody(this.over), entities) : this.over}, variables: ${this.variables}, blocks: ${await Promise.all(this.blocks.map(async (block) => await block.toSDK(entities)).join(","))} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): Loop {\n return new Loop(json?.name, {\n over: fromJS<JsonValue[]>(json?.loop?.range, entities),\n variables: {\n item: json?.loop?.variables?.item,\n index: json?.loop?.variables?.index,\n },\n blocks: json?.loop?.blocks.map((block: any) =>\n Block.fromJSON(block, entities),\n ),\n });\n }\n}\n\nexport class Variables extends Block {\n private variables: { key: string, value: Binding<JsonValue> }[];\n\n constructor(\n name: string,\n variables: { key: string, value: Binding<JsonValue> }[],\n ) {\n super(name);\n\n this.variables = variables;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n variables: {\n items: await Promise.all(this.variables.map(async (variable) => {\n return {\n key: variable.key,\n value: await toJS<JsonValue>(variable.value),\n type: "TYPE_SIMPLE",\n mode: "MODE_READWRITE",\n };\n }))\n },\n };\n }\n \n public async toSDK(entities: string[]): Promise<string> {\n return `new Variables("${this.name}", [${this.variables?.map((variable) => `{ key: "${variable.key}", value: ${typeof variable.value === "function" ? signature(code(variable.value.toString(), { iife: true }), entities) : variable.value} }`).join(",")}])`;\n }\n\n public static fromJSON(json: any, entities: string[]): Variables {\n return new Variables(json?.name, json?.variables?.items?.map((variable: any) => ({\n key: variable.key,\n value: fromBinding(variable.value, entities),\n })));\n }\n}\n\nexport class TryCatch extends Block {\n private try: Block[];\n private catch: Block[];\n private finally?: Block[];\n private variables: { error: string };\n\n constructor(\n name: string,\n config: {\n try: Block[];\n catch: Block[];\n finally?: Block[];\n variables: { error: string };\n },\n ) {\n super(name);\n\n this.try = config.try;\n this.catch = config.catch;\n this.finally = config.finally;\n this.variables = config.variables;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n tryCatch: {\n try: { blocks: await Promise.all(this.try.map(async (block) => await block.toJSON())) },\n catch: { blocks: await Promise.all(this.catch.map(async (block) => await block.toJSON())) },\n finally: { blocks: this.finally ? await Promise.all(this.finally.map(async (block) => await block.toJSON())) : [] },\n variables: this.variables,\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new TryCatch("${this.name}", { try: ${await Promise.all(this.try.map(async (block) => await block.toSDK(entities)).join(","))}, catch: ${await Promise.all(this.catch.map(async (block) => await block.toSDK(entities)).join(","))}, finally: ${this.finally?.map(async (block) => await block.toSDK(entities)).join(", ")} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): TryCatch {\n return new TryCatch(json?.name, {\n try: json?.tryCatch?.try.blocks.map((block: any) => Block.fromJSON(block, entities)),\n catch: json?.tryCatch?.catch.blocks.map((block: any) => Block.fromJSON(block, entities)),\n finally: json?.tryCatch?.finally?.blocks.map((block: any) => Block.fromJSON(block, entities)),\n variables: {\n error: json?.tryCatch?.variables?.error,\n },\n });\n }\n}\n\nexport class Throw extends Block {\n private error: Binding<JsonValue>;\n\n constructor(\n name: string,\n config: {\n error: Binding<JsonValue>;\n },\n ) {\n super(name);\n\n this.error = config.error;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n throw: {\n error: await toJS(this.error),\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new Throw("${this.name}", { error: ${typeof this.error === "function" ? signature(code(this.error.toString()), entities) : JSON.stringify(this.error)} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): Throw {\n return new Throw(json?.name, {\n error: fromJS(json?.throw?.error, entities),\n });\n }\n}\n\nexport class Return extends Block {\n private data: Binding<JsonValue>;\n\n constructor(\n name: string,\n config: {\n data: Binding<JsonValue>;\n },\n ) {\n super(name);\n\n this.data = config.data;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n return: {\n data: await toJS(this.data),\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new Return("${this.name}", { data: ${typeof this.data === "function" ? signature(code(this.data.toString()), entities) : JSON.stringify(this.data)} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): Return {\n return new Return(json?.name, {\n data: fromJS(json?.return?.data, entities),\n });\n }\n}\n\nexport class Api {\n private blocks: Block[];\n private name: string;\n\n constructor(name: string, blocks: Block[]) {\n this.name = name;\n this.blocks = blocks;\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n const imports =\n "import { Api, JavaScript, Python, PostgreSQL, Snowflake, Databricks, Conditional, Parallel, Loop, TryCatch, Variables, Throw, Return } from \'@superblocksteam/library\'";\n return `${imports}\\n\\nexport default new Api("${this.name}", [${(await Promise.all(this.blocks.map(async (block) => await block.toSDK(entities)))).join(",")}])`;\n }\n\n public static fromJSON(json: any, entities: string[]): Api {\n // NOTE(Frank): Would probs unmarshal this into the protobuf types and then do the conversion.\n return new Api(\n json?.metadata?.name as string,\n (json.blocks as any[]).map((block) => Block.fromJSON(block, entities)),\n );\n }\n\n public async toJSON(): Promise<JsonValue> {\n const api: {\n metadata: {\n name: string;\n timestamps: {\n updated: string;\n };\n };\n trigger: {\n application: {};\n };\n blocks: JsonValue[];\n } = {\n metadata: {\n name: this.name,\n timestamps: {\n updated: new Date().toISOString(),\n },\n },\n trigger: {\n application: {},\n },\n blocks: [],\n };\n\n api.blocks = await Promise.all(this.blocks.map(async (block) => await block.toJSON()));\n\n return api;\n }\n}\n\nfunction referenced(data: string, entities: string[]): string[] {\n return entities.reduce((acc: string[], entity: string) => {\n if (data.includes(entity)) {\n acc.push(entity);\n }\n return acc;\n }, []);\n}\n\nfunction signature(data: string, entities: string[]): string {\n return `({ ${referenced(data, entities).join(", ")} }) => {${data}}`;\n}\n\nfunction signatureV2(data: string, entities: string[]): string {\n return `({ ${referenced(data, entities).join(", ")} }) => ${data}`;\n}\n\n/**\n * Converts a string binding, which comprise 99% of dynamic integration fields, into a function returning an interpolated string.\n *\n * fromBinding("https://{{ \'goo\' + \'gle\' }}.com/{{ Dropdown1.value }}", [\'Dropdown1\']) -> ({ Dropdown1 }) => `https://${\'goo\' + \'gle\'}.com/${Dropdown1.value}`\n *\n * @param value - The value to convert.\n * @param entities - The master list of possible entities that could be referenced in the binding.\n *\n * @returns The converted value.\n */\nexport function fromBinding(value: string, entities: string[]): Binding<string> {\n if (!value) {\n return "";\n }\n\n const regex = /\\{\\{\\s*([^}]*)\\s*\\}\\}/g;\n const converted: string = value.replace(regex, (match, content) => `\\${${content.trim()}}`);\n\n // there were no bindings to convert\n if (converted === value) {\n return value;\n }\n\n const args: string[] = [`return \\`${converted}\\``]\n const references: string[] = referenced(converted, entities);\n\n // only add the arguments if we have references\n if (references.length > 0) {\n args.unshift(`{ ${references} }`);\n }\n\n return new Function(...args) as (_: State) => string;\n}\n\nasync function beautifyAndOptionallyCondense<T extends JsonValue>(value: ((state: State) => T), node: Node, options: { condense?: boolean, block?: boolean } = { condense: true, block: true }) {\n let start: number = node.start;\n let end: number = node.end;\n\n if (!options.block) {\n start += 1;\n end -= 1;\n }\n \n const beautified = await beautify(value.toString().slice(start, end))\n\n if (options.condense) {\n return beautified.replace(/\\s*\\n\\s*/g, \' \').replace(/\\s+/g, \' \').trim();\n }\n\n return beautified\n}\n\nfunction createAst(value: string): Program {\n return parse(value, {\n ecmaVersion: "latest",\n sourceType: "script",\n preserveParens: false,\n });\n}\n\nasync function toJSBody<T extends JsonValue>(value: ((state: State) => T), options: { block?: boolean, condense?: boolean, function?: boolean } = { block: true, condense: true, function: false }): Promise<string> {\n if (typeof value !== "function") {\n return `{{ ${JSON.stringify(value)} }}`\n }\n\n // parse the code\n const ast = createAst(value.toString());\n const program = ast.body[0];\n\n switch (program.type) {\n case "ExpressionStatement":\n const body = ((program as ExpressionStatement).expression as FunctionExpression).body;\n\n if (body.type === \'BlockStatement\') {\n return await beautifyAndOptionallyCondense(value, body, options)\n }\n\n return `${options.function ? "return " : ""}${value.toString().slice(body.start, body.end)}`\n case "FunctionDeclaration":\n let contents = value.toString().slice(program.body.start, program.body.end)\n\n if (program.body.type !== \'BlockStatement\') {\n return contents\n }\n \n if (!options.function && program.body.body.length === 1 && program.body.body[0].type === \'ReturnStatement\') {\n return value.toString().slice(program.body.body[0].argument.start, program.body.body[0].argument.end)\n }\n\n return await beautifyAndOptionallyCondense(value, program.body, options)\n\n default:\n throw new Error("you found a case we haven\'t handled yet")\n }\n}\n\nexport async function toJS<T extends JsonValue>(value: Binding<T>): Promise<string> {\n if (typeof value !== "function") {\n return `{{ ${JSON.stringify(value)} }}`\n }\n\n const body = await toJSBody(value)\n return `{{ (() => ${body})() }}`\n}\n\nexport function fromJS<T extends JsonValue>(\n value: string,\n entities: string[] = [],\n): Binding<T> {\n // determine if there are entities referenced in the value\n const refs = referenced(value, entities).join(", ")\n\n\n // remove any surrounding whitespace\n value = value.trim()\n\n // require bindings\n if (!value.startsWith("{{") || !value.endsWith("}}")) {\n throw new Error("bindings must always be wrapped in double curly braces");\n }\n\n // remove the double curly braces and trim whitespace\n value = value.slice(2, -2).trim();\n\n let unaryOps: string[] = [];\n let call = (createAst(value).body[0] as ExpressionStatement).expression;\n\n while (call?.type === \'UnaryExpression\') {\n unaryOps.push((call as UnaryExpression).operator);\n call = (call as unknown as UnaryExpression).argument as CallExpression;\n }\n \n const fn = (call as CallExpression).callee;\n let body = value;\n let prefix = "return ";\n\n // handle iife\n if (fn?.type === "ArrowFunctionExpression") {\n // i\'m not happy with this but I don\'t see another immediate way to handle this.\n // this will result in a correct result but one that isn\'t idemopotent.\n if (unaryOps.length > 0) {\n return new Function(`{ ${refs} }`, `${prefix}${body}`) as (_: State) => T;\n }\n\n\n body = value.slice(fn.body.start, fn.body.end)\n\n if (fn.body.type === \'BlockStatement\') {\n // drop the opening "{" and closing "}"\n body = body.slice(1, -1)\n prefix = ""\n } \n } else if (refs.length === 0) {\n // we\'re not an iife nor do we have references.\n // we might have to revisit this implementation since this technically reduces to a static value down to it\'s most minimal form.\n return eval(value) as T\n }\n\n // we\'re either an iife or a static value with refs.\n return new Function(`{ ${refs} }`, `${prefix}${body}`) as (_: State) => T;\n}\n\nexport async function beautify(code: string): Promise<string> {\n const eslint = new ESLint({\n fix: true,\n overrideConfigFile: true,\n baseConfig: {\n languageOptions: {\n parser: typescript_eslint_parser,\n parserOptions: {\n ecmaVersion: 2020,\n sourceType: "module",\n },\n },\n rules: {\n "arrow-body-style": "error",\n },\n },\n });\n\n code = (await eslint.lintText(code))[0]?.output || code;\n\n return await format(code, {\n parser: "typescript",\n tabWidth: 2,\n // singleQuote: true,\n trailingComma: "none",\n semi: true,\n bracketSpacing: true,\n arrowParens: "always",\n bracketSameLine: false,\n embeddedLanguageFormatting: "auto",\n quoteProps: "as-needed",\n insertPragma: false,\n requirePragma: false,\n useTabs: false,\n endOfLine: "auto",\n arrowFunctionParentheses: "always",\n // plugins: ["prettier-plugin-organize-imports"],\n });\n}\n',
|
|
314951
|
+
"src/superblocks-library-shim/index.ts": '/* eslint-disable */\nimport typescript_eslint_parser from "@typescript-eslint/parser";\nimport { CallExpression, ExpressionStatement, FunctionExpression, Node, parse, Program, UnaryExpression } from "acorn";\nimport { ESLint } from "eslint";\nimport { format } from "prettier";\n\nexport type JsonValue =\n | undefined\n | null\n | number\n | string\n | boolean\n | Array<JsonValue>\n | { [key: string]: JsonValue };\nexport type State = { [key: string]: JsonValue };\nexport type Binding<T> = T | ((state: State) => T);\n\nexport const code = (\n fn: string,\n options: { iife?: boolean } = { iife: false },\n): string => {\n // Parse the function string\n const ast = parse(fn, {\n ecmaVersion: "latest",\n sourceType: "script",\n });\n\n // Find the function declaration/expression\n let functionNode;\n\n // Walk through the AST to find the function\n if (ast.body[0].type === "FunctionDeclaration") {\n // Function declaration: function name() {}\n functionNode = ast.body[0];\n } else if (\n ast.body[0].type === "ExpressionStatement" &&\n (ast.body[0].expression.type === "FunctionExpression" ||\n ast.body[0].expression.type === "ArrowFunctionExpression")\n ) {\n // Function expression: const name = function() {} or const name = () => {}\n functionNode = ast.body[0].expression;\n } else if (\n ast.body[0].type === "VariableDeclaration" &&\n (ast.body[0].declarations[0]?.init?.type === "FunctionExpression" ||\n ast.body[0].declarations[0]?.init?.type === "ArrowFunctionExpression")\n ) {\n // Variable declaration: const name = function() {} or const name = () => {}\n functionNode = ast.body[0].declarations[0]?.init;\n }\n\n if (!functionNode) {\n throw new Error("Could not find a function in the provided string");\n }\n\n // Get the function body\n const body = functionNode.body;\n\n // Extract the source from the original string\n // For arrow functions with an expression body, we return the expression\n if (\n functionNode.type === "ArrowFunctionExpression" &&\n body.type !== "BlockStatement"\n ) {\n // Arrow function with expression body: () => 42\n const expressionCode = fn.substring(fn.indexOf("=>") + 2).trim();\n return options.iife\n ? `(() => ${expressionCode})()`\n : `return ${expressionCode}`;\n }\n\n // For functions with block bodies, extract content between braces\n const start = body.start + 1; // Skip the opening brace\n const end = body.end - 1; // Skip the closing brace\n\n // Get the raw body content\n const rawBodyLines = fn.substring(start, end).split("\\n");\n\n if (rawBodyLines.length <= 1) {\n // Single line body, just trim it\n const bodyCode = rawBodyLines[0].trim();\n\n if (options.iife) {\n const paramStart = fn.indexOf("(");\n const paramEnd = fn.indexOf(")", paramStart);\n const params = fn.substring(paramStart, paramEnd + 1);\n return `(${params} => { ${bodyCode} })()`;\n }\n\n return bodyCode;\n }\n\n // For multi-line bodies, normalize indentation\n // Find the minimum indentation level (ignoring empty lines)\n let minIndent = Infinity;\n for (const line of rawBodyLines) {\n const trimmedLine = line.trimStart();\n if (trimmedLine.length > 0) {\n const indent = line.length - trimmedLine.length;\n minIndent = Math.min(minIndent, indent);\n }\n }\n\n // Remove the common indentation from each line\n const normalizedLines = rawBodyLines.map((line) => {\n if (line.trimStart().length === 0) return "";\n return line.substring(minIndent);\n });\n\n // Join the normalized lines\n const bodyCode = normalizedLines\n .join(" ")\n .replace(/\\s{2,}/g, " ")\n .trim();\n\n if (options.iife) {\n const paramStart = fn.indexOf("(");\n const paramEnd = fn.indexOf(")", paramStart);\n const params = fn.substring(paramStart, paramEnd + 1);\n return `(${params} => { ${bodyCode} })()`;\n }\n\n return bodyCode;\n};\n\nasync function binding(binding: Binding<string>): Promise<string> {\n if (typeof binding === "function") {\n return await toJS(binding);\n }\n\n return binding;\n}\n\ninterface Codec {\n toJSON(): Promise<JsonValue>;\n toSDK(entities: string[]): Promise<string>;\n}\n\nexport abstract class Block implements Codec {\n protected name: string;\n\n constructor(name: string) {\n this.name = name;\n }\n\n public abstract toJSON(): Promise<JsonValue>;\n public abstract toSDK(entities: string[]): Promise<string>;\n\n public static fromJSON(json: any, entities: string[]): Block {\n if (json?.step) {\n return Integration.fromJSON(json, entities);\n }\n\n if ("conditional" in json) {\n return Conditional.fromJSON(json, entities);\n }\n\n if ("loop" in json) {\n return Loop.fromJSON(json, entities);\n }\n\n if ("parallel" in json) {\n return Parallel.fromJSON(json, entities);\n }\n\n if ("tryCatch" in json) {\n return TryCatch.fromJSON(json, entities);\n }\n\n if ("variables" in json) {\n return Variables.fromJSON(json, entities);\n }\n\n if ("throw" in json) {\n return Throw.fromJSON(json, entities);\n }\n\n if ("return" in json) {\n return Return.fromJSON(json, entities);\n }\n\n throw new Error("mysterious block");\n }\n}\n\nexport abstract class Integration extends Block {\n protected integration: string;\n\n constructor(name: string, integration: string) {\n super(name);\n\n this.integration = integration;\n }\n\n public abstract toJSON(): Promise<JsonValue>;\n public abstract toSDK(entities: string[]): Promise<string>;\n\n public static fromJSON(json: any, entities: string[]): Block {\n if ("javascript" in json?.step) {\n return JavaScript.fromJSON(json, entities);\n }\n\n if ("python" in json?.step) {\n return Python.fromJSON(json, entities);\n }\n\n if ("postgres" in json?.step) {\n return PostgreSQL.fromJSON(json, entities);\n }\n\n if ("databricks" in json?.step) {\n return Databricks.fromJSON(json, entities);\n }\n\n if ("email" in json?.step) {\n return Email.fromJSON(json, entities);\n }\n\n if ("restapi" in json?.step) {\n return RestApi.fromJSON(json, entities);\n }\n\n throw new Error("mysterious integration");\n }\n}\n\nexport class Python extends Integration {\n private fn: string;\n\n constructor(name: string, config: {\n fn: string;\n }) {\n super(name, "python");\n\n this.fn = config.fn;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n step: {\n integration: "python",\n python: {\n body: this.fn,\n },\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new Python("${this.name}", { fn: ${this.fn} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): Python {\n return new Python(json?.name, {\n fn: json?.step?.python?.body,\n });\n }\n}\n\nexport class JavaScript extends Integration {\n private fn: (_: State) => JsonValue;\n\n constructor(\n name: string,\n config: {\n fn: (_: State) => JsonValue;\n },\n ) {\n super(name, "javascript");\n\n this.fn = config.fn;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n step: {\n integration: "javascript",\n javascript: {\n body: await toJSBody(this.fn, { block: false, function: true }),\n },\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new JavaScript("${this.name}", { fn: ${signature(code(this.fn.toString()), entities)} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): JavaScript {\n const args = [json?.step?.javascript?.body]\n const references = referenced(json?.step?.javascript?.body, entities)\n\n if (references.length > 0) {\n args.unshift(`{ ${references.join(", ")} }`)\n }\n\n return new JavaScript(json?.name, {\n fn: new Function(...args) as (_: State) => JsonValue,\n });\n }\n}\n\n// TODO(Frank): There is way too much in common between Snowflake and PostgreSQL. Need to add a parent class for these.\nexport class Snowflake extends Integration {\n private statement: Binding<string>;\n\n constructor(\n name: string,\n integration: string,\n config: {\n statement: Binding<string>;\n },\n ) {\n super(name, integration);\n\n this.statement = config.statement;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n step: {\n integration: this.integration,\n snowflake: {\n body: await binding(this.statement),\n usePreparedSql: false,\n },\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new Snowflake("${this.name}", "${this.integration}", { statement: ${typeof this.statement === "function" ? signatureV2(await toJSBody(this.statement), entities) : `"${this.statement}"`} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): Snowflake {\n return new Snowflake(json?.name, json?.step?.integration, {\n statement: fromBinding(\n json?.step?.snowflake?.body as string | undefined,\n entities,\n ),\n });\n }\n}\n\nexport class PostgreSQL extends Integration {\n private statement: Binding<string>;\n\n constructor(\n name: string,\n integration: string,\n config: {\n statement: Binding<string>;\n },\n ) {\n super(name, integration);\n\n this.statement = config.statement;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n step: {\n integration: this.integration,\n postgres: {\n body: await binding(this.statement),\n usePreparedSql: false,\n operation: "run_sql",\n },\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new PostgreSQL("${this.name}", "${this.integration}", { statement: ${typeof this.statement === "function" ? signatureV2(await toJSBody(this.statement), entities) : `"${this.statement}"`} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): PostgreSQL {\n return new PostgreSQL(json?.name, json?.step?.integration, {\n statement: fromBinding(\n json?.step?.postgres?.body as string | undefined,\n entities,\n ),\n });\n }\n}\n\nexport class RestApi extends Integration {\n private method: string;\n private url: Binding<string>;\n private headers?: { key: Binding<string>; value: Binding<string> }[];\n private params?: { key: Binding<string>; value: Binding<string> }[];\n private body?: Binding<string>;\n\n constructor(\n name: string,\n config: {\n method: string;\n url?: Binding<string>;\n headers?: { key: Binding<string>; value: Binding<string> }[];\n params?: { key: Binding<string>; value: Binding<string> }[];\n body?: Binding<string>;\n },\n ) {\n super(name, "restapi");\n\n this.method = config.method;\n this.url = config.url;\n this.headers = config.headers;\n this.params = config.params;\n this.body = config.body;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n step: {\n integration: "restapi",\n restapi: {\n httpMethod: this.method,\n ...(this.url ? { path: await binding(this.url) } : {}),\n ...(this.headers ? { headers: await Promise.all(this.headers.map(async (header) => ({ key: await binding(header.key), value: await binding(header.value) }))) } : {}),\n ...(this.params ? { params: await Promise.all(this.params.map(async (param) => ({ key: await binding(param.key), value: await binding(param.value) }))) } : {}),\n ...(this.body ? { body: await binding(this.body) } : {}),\n },\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n const parts: string[] = [`method: "${this.method}"`];\n\n if (this.url) {\n parts.push(\n `url: ${\n typeof this.url === "function"\n ? signatureV2(await toJSBody(this.url), entities)\n : `"${this.url}"`\n }`,\n );\n }\n\n if (this.headers) {\n const headers = this.headers\n .map(async (h) =>\n `{ key: ${\n typeof h.key === "function"\n ? signatureV2(await toJSBody(h.key), entities)\n : `"${h.key}"`\n }, value: ${\n typeof h.value === "function"\n ? signatureV2(await toJSBody(h.value), entities)\n : `"${h.value}"`\n } }`,\n )\n .join(", ");\n parts.push(`headers: [${headers}]`);\n }\n\n if (this.params) {\n const params = this.params\n .map(async (p) =>\n `{ key: ${\n typeof p.key === "function"\n ? signatureV2(await toJSBody(p.key), entities)\n : `"${p.key}"`\n }, value: ${\n typeof p.value === "function"\n ? signatureV2(await toJSBody(p.value), entities)\n : `"${p.value}"`\n } }`,\n )\n .join(", ");\n parts.push(`params: [${params}]`);\n }\n\n if (this.body) {\n parts.push(\n `body: ${\n typeof this.body === "function"\n ? signatureV2(await toJSBody(this.body), entities)\n : JSON.stringify(this.body)\n }`,\n );\n }\n\n return `new RestApi("${this.name}", { ${parts.join(", ")} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): RestApi {\n return new RestApi(json?.name, {\n method: json?.step?.restapi?.httpMethod,\n url: fromBinding(json?.step?.restapi?.path, entities),\n headers: json?.step?.restapi?.headers?.map((header: any) => ({ key: fromBinding(header.key, entities), value: fromBinding(header.value, entities) })),\n params: json?.step?.restapi?.params?.map((param: any) => ({ key: fromBinding(param.key, entities), value: fromBinding(param.value, entities) })),\n body: fromBinding(json?.step?.restapi?.body, entities),\n });\n }\n}\n\nexport class Email extends Integration {\n private subject: Binding<string>;\n private from: Binding<string>; // comma separated list\n private to: Binding<string>; // comma separated list\n private cc?: Binding<string>; // comma separated list\n private bcc?: Binding<string>; // comma separated list\n private body: Binding<string>;\n\n constructor(\n name: string,\n config: {\n from: Binding<string>;\n to: Binding<string>;\n subject: Binding<string>;\n cc?: Binding<string>;\n bcc?: Binding<string>;\n body?: Binding<string>;\n },\n ) {\n super(name, "email");\n\n this.from = config.from;\n this.to = config.to;\n this.subject = config.subject;\n this.cc = config.cc;\n this.bcc = config.bcc;\n this.body = config.body;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n step: {\n integration: "email",\n email: {\n ...(this.from ? { emailFrom: await binding(this.from) } : {}),\n ...(this.to ? { emailTo: await binding(this.to) } : {}),\n ...(this.cc ? { emailCc: await binding(this.cc) } : {}),\n ...(this.bcc ? { emailBcc: await binding(this.bcc) } : {}),\n ...(this.subject ? { emailSubject: await binding(this.subject) } : {}),\n ...(this.body ? { emailBody: await binding(this.body) } : {}),\n },\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n const parts: string[] = [];\n\n if (this.from) {\n parts.push(\n `from: ${\n typeof this.from === "function"\n ? signatureV2(code(this.from.toString()), entities)\n : `"${this.from}"`\n }`,\n );\n }\n\n if (this.to) {\n parts.push(\n `to: ${\n typeof this.to === "function"\n ? signatureV2(code(this.to.toString()), entities)\n : `"${this.to}"`\n }`,\n );\n }\n\n if (this.cc) {\n parts.push(\n `cc: ${\n typeof this.cc === "function"\n ? signatureV2(code(this.cc.toString()), entities)\n : `"${this.cc}"`\n }`,\n );\n }\n\n if (this.bcc) {\n parts.push(\n `bcc: ${\n typeof this.bcc === "function"\n ? signatureV2(code(this.bcc.toString()), entities)\n : `"${this.bcc}"`\n }`,\n );\n }\n\n if (this.subject) {\n parts.push(\n `subject: ${\n typeof this.subject === "function"\n ? signatureV2(code(this.subject.toString()), entities)\n : `"${this.subject}"`\n }`,\n );\n }\n\n if (this.body) {\n parts.push(\n `body: ${\n typeof this.body === "function"\n ? signatureV2(code(this.body.toString()), entities)\n : `"${this.body}"`\n }`,\n );\n }\n\n return `new Email("${this.name}", { ${parts.join(", ")} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): Email {\n return new Email(json?.name, {\n from: fromBinding(json?.step?.email?.emailFrom, entities),\n to: fromBinding(json?.step?.email?.emailTo, entities),\n subject: fromBinding(json?.step?.email?.emailSubject, entities),\n body: fromBinding(json?.step?.email?.emailBody, entities),\n cc: json?.step?.email?.emailCc ? fromBinding(json?.step?.email?.emailCc, entities) : undefined,\n bcc: json?.step?.email?.emailBcc ? fromBinding(json?.step?.email?.emailBcc, entities) : undefined,\n });\n }\n}\n\nexport class Databricks extends Integration {\n private statement: Binding<string>;\n\n constructor(\n name: string,\n integration: string,\n config: {\n statement: Binding<string>;\n },\n ) {\n super(name, integration);\n\n this.statement = config.statement;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n step: {\n integration: this.integration,\n databricks: {\n runSql: {\n sqlBody: await binding(this.statement),\n useParameterized: false,\n },\n },\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new Databricks("${this.name}", "${this.integration}", { statement: ${typeof this.statement === "function" ? signatureV2(await toJSBody(this.statement), entities) : `"${this.statement}"`} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): Databricks {\n return new Databricks(json?.name, json?.step?.integration, {\n statement: fromBinding(\n json?.step?.databricks?.runSql?.sqlBody as string,\n entities,\n ),\n });\n }\n}\n\nexport type Condition = {\n when: Binding<boolean>;\n then: Block[];\n};\n\nasync function conditionToSDK(condition: Condition, entities: string[]): Promise<string> {\n return `{ when: ${typeof condition.when === "function" ? signatureV2(await toJSBody(condition.when), entities) : condition.when}, then: [${(await Promise.all(condition.then.map(async (block) => await block.toSDK(entities)))).join(",")}] }`\n}\n\nexport type Conditions = {\n if: Condition;\n elif?: Condition[];\n else?: Block[];\n};\n\nexport class Conditional extends Block {\n public conditions: Conditions;\n\n constructor(name: string, config: Conditions) {\n super(name);\n\n this.conditions = config;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n conditional: {\n if: {\n condition: await toJS<boolean>(this.conditions.if.when),\n blocks: await Promise.all(this.conditions.if.then.map(async (block) => await block.toJSON())),\n },\n ...await (async () =>\n this.conditions.elif\n ? {\n elseIf: await Promise.all(this.conditions.elif.map(async (condition) => ({\n condition: await toJS<boolean>(condition.when),\n blocks: await Promise.all(condition.then.map(async (block) => await block.toJSON())),\n }))),\n }\n : { elseIf: [] })(),\n else: this.conditions.else ? {\n blocks: await Promise.all(this.conditions.else.map(async (block) => await block.toJSON()))\n } : undefined,\n },\n };\n }\n\n public static fromJSON(json: any, entities: string[]): Conditional {\n return new Conditional(json?.name, {\n if: {\n when: fromJS<boolean>(json?.conditional?.if?.condition, entities),\n then: json?.conditional?.if?.blocks.map((block: any) =>\n Block.fromJSON(block, entities),\n ),\n },\n elif: json?.conditional?.elseIf ? json?.conditional?.elseIf?.map((condition: any) => ({\n when: fromJS<boolean>(condition.condition, entities),\n then: condition.blocks.map((block: any) => Block.fromJSON(block, entities)),\n })) : [],\n else: json?.conditional?.else ? json?.conditional?.else?.blocks?.map((block: any) => Block.fromJSON(block, entities)) : [],\n });\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new Conditional("${this.name}", { if: ${await conditionToSDK(this.conditions.if, entities)}, elif: [${this.conditions.elif ? (await Promise.all(this.conditions.elif?.map(async (condition) => await conditionToSDK(condition, entities)))).join(",") : \'\'}], else: ${this.conditions.else ? (await Promise.all(this.conditions.else?.map(async (block) => await block.toSDK(entities)))).join(",") : "undefined"} })`;\n }\n}\n\nexport class Parallel extends Block {\n private over: Binding<JsonValue[]>;\n private blocks: Block[];\n private variables: { item: string };\n\n constructor(\n name: string,\n config: {\n over: Binding<JsonValue[]>;\n variables: { item: string };\n blocks: Block[];\n },\n ) {\n super(name);\n\n this.over = config.over;\n this.blocks = config.blocks;\n this.variables = config.variables;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n parallel: {\n dynamic: {\n blocks: await Promise.all(this.blocks?.map(async (block) => await block.toJSON())),\n paths: await toJS<JsonValue[]>(this.over),\n variables: this.variables,\n },\n wait: "WAIT_ALL",\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new Parallel("${this.name}", { over: ${typeof this.over === "function" ? signatureV2(await toJSBody(this.over), entities) : this.over}, variables: ${this.variables}, blocks: ${await Promise.all(this.blocks.map(async (block) => await block.toSDK(entities)).join(","))} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): Parallel {\n return new Parallel(json?.name, {\n over: fromJS<JsonValue[]>(json?.parallel?.dynamic?.paths, entities),\n variables: {\n item: json?.parallel?.dynamic?.variables?.item,\n },\n blocks: json?.parallel?.dynamic?.blocks.map((block: any) =>\n Block.fromJSON(block, entities),\n ),\n });\n }\n}\n\nexport class Loop extends Block {\n private over: Binding<JsonValue[]>; // NOTE(Frank): Only for each loops are supported at the moment.\n private blocks: Block[];\n private variables: { item: string; index: string };\n\n constructor(\n name: string,\n config: {\n over: Binding<JsonValue[]>;\n variables: { item: string; index: string };\n blocks: Block[];\n },\n ) {\n super(name);\n\n this.over = config.over;\n this.variables = config.variables;\n this.blocks = config.blocks;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n loop: {\n range: await toJS<JsonValue[]>(this.over),\n type: "TYPE_FOREACH",\n variables: this.variables,\n blocks: await Promise.all(this.blocks.map(async (block) => await block.toJSON())),\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new Loop("${this.name}", { over: ${typeof this.over === "function" ? signatureV2(await toJSBody(this.over), entities) : this.over}, variables: ${this.variables}, blocks: ${await Promise.all(this.blocks.map(async (block) => await block.toSDK(entities)).join(","))} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): Loop {\n return new Loop(json?.name, {\n over: fromJS<JsonValue[]>(json?.loop?.range, entities),\n variables: {\n item: json?.loop?.variables?.item,\n index: json?.loop?.variables?.index,\n },\n blocks: json?.loop?.blocks.map((block: any) =>\n Block.fromJSON(block, entities),\n ),\n });\n }\n}\n\nexport class Variables extends Block {\n private variables: { key: string, value: Binding<JsonValue> }[];\n\n constructor(\n name: string,\n variables: { key: string, value: Binding<JsonValue> }[],\n ) {\n super(name);\n\n this.variables = variables;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n variables: {\n items: await Promise.all(this.variables.map(async (variable) => {\n return {\n key: variable.key,\n value: await toJS<JsonValue>(variable.value),\n type: "TYPE_SIMPLE",\n mode: "MODE_READWRITE",\n };\n }))\n },\n };\n }\n \n public async toSDK(entities: string[]): Promise<string> {\n return `new Variables("${this.name}", [${this.variables?.map((variable) => `{ key: "${variable.key}", value: ${typeof variable.value === "function" ? signature(code(variable.value.toString(), { iife: true }), entities) : variable.value} }`).join(",")}])`;\n }\n\n public static fromJSON(json: any, entities: string[]): Variables {\n return new Variables(json?.name, json?.variables?.items?.map((variable: any) => ({\n key: variable.key,\n value: fromBinding(variable.value, entities),\n })));\n }\n}\n\nexport class TryCatch extends Block {\n private try: Block[];\n private catch: Block[];\n private finally?: Block[];\n private variables: { error: string };\n\n constructor(\n name: string,\n config: {\n try: Block[];\n catch: Block[];\n finally?: Block[];\n variables: { error: string };\n },\n ) {\n super(name);\n\n this.try = config.try;\n this.catch = config.catch;\n this.finally = config.finally;\n this.variables = config.variables;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n tryCatch: {\n try: { blocks: await Promise.all(this.try.map(async (block) => await block.toJSON())) },\n catch: { blocks: await Promise.all(this.catch.map(async (block) => await block.toJSON())) },\n finally: { blocks: this.finally ? await Promise.all(this.finally.map(async (block) => await block.toJSON())) : [] },\n variables: this.variables,\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new TryCatch("${this.name}", { try: ${await Promise.all(this.try.map(async (block) => await block.toSDK(entities)).join(","))}, catch: ${await Promise.all(this.catch.map(async (block) => await block.toSDK(entities)).join(","))}, finally: ${this.finally?.map(async (block) => await block.toSDK(entities)).join(", ")} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): TryCatch {\n return new TryCatch(json?.name, {\n try: json?.tryCatch?.try.blocks.map((block: any) => Block.fromJSON(block, entities)),\n catch: json?.tryCatch?.catch.blocks.map((block: any) => Block.fromJSON(block, entities)),\n finally: json?.tryCatch?.finally?.blocks.map((block: any) => Block.fromJSON(block, entities)),\n variables: {\n error: json?.tryCatch?.variables?.error,\n },\n });\n }\n}\n\nexport class Throw extends Block {\n private error: Binding<JsonValue>;\n\n constructor(\n name: string,\n config: {\n error: Binding<JsonValue>;\n },\n ) {\n super(name);\n\n this.error = config.error;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n throw: {\n error: await toJS(this.error),\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new Throw("${this.name}", { error: ${typeof this.error === "function" ? signature(code(this.error.toString()), entities) : JSON.stringify(this.error)} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): Throw {\n return new Throw(json?.name, {\n error: fromJS(json?.throw?.error, entities),\n });\n }\n}\n\nexport class Return extends Block {\n private data: Binding<JsonValue>;\n\n constructor(\n name: string,\n config: {\n data: Binding<JsonValue>;\n },\n ) {\n super(name);\n\n this.data = config.data;\n }\n\n public async toJSON(): Promise<JsonValue> {\n return {\n name: this.name,\n return: {\n data: await toJS(this.data),\n },\n };\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n return `new Return("${this.name}", { data: ${typeof this.data === "function" ? signature(code(this.data.toString()), entities) : JSON.stringify(this.data)} })`;\n }\n\n public static fromJSON(json: any, entities: string[]): Return {\n return new Return(json?.name, {\n data: fromJS(json?.return?.data, entities),\n });\n }\n}\n\nexport class Api {\n private blocks: Block[];\n private name: string;\n\n constructor(name: string, blocks: Block[]) {\n this.name = name;\n this.blocks = blocks;\n }\n\n public async toSDK(entities: string[]): Promise<string> {\n const imports =\n "import { Api, JavaScript, Python, PostgreSQL, Snowflake, Databricks, Conditional, Parallel, Loop, TryCatch, Variables, Throw, Return } from \'@superblocksteam/library\'";\n return `${imports}\\n\\nexport default new Api("${this.name}", [${(await Promise.all(this.blocks.map(async (block) => await block.toSDK(entities)))).join(",")}])`;\n }\n\n public static fromJSON(json: any, entities: string[]): Api {\n // NOTE(Frank): Would probs unmarshal this into the protobuf types and then do the conversion.\n return new Api(\n json?.metadata?.name as string,\n (json.blocks as any[]).map((block) => Block.fromJSON(block, entities)),\n );\n }\n\n public async toJSON(): Promise<JsonValue> {\n const api: {\n metadata: {\n name: string;\n timestamps: {\n updated: string;\n };\n };\n trigger: {\n application: {};\n };\n blocks: JsonValue[];\n } = {\n metadata: {\n name: this.name,\n timestamps: {\n updated: new Date().toISOString(),\n },\n },\n trigger: {\n application: {},\n },\n blocks: [],\n };\n\n api.blocks = await Promise.all(this.blocks.map(async (block) => await block.toJSON()));\n\n return api;\n }\n}\n\nfunction referenced(data: string, entities: string[]): string[] {\n return entities.reduce((acc: string[], entity: string) => {\n if (data.includes(entity)) {\n acc.push(entity);\n }\n return acc;\n }, []);\n}\n\nfunction signature(data: string, entities: string[]): string {\n return `({ ${referenced(data, entities).join(", ")} }) => {${data}}`;\n}\n\nfunction signatureV2(data: string, entities: string[]): string {\n return `({ ${referenced(data, entities).join(", ")} }) => ${data}`;\n}\n\n/**\n * Converts a string binding, which comprise 99% of dynamic integration fields, into a function returning an interpolated string.\n *\n * fromBinding("https://{{ \'goo\' + \'gle\' }}.com/{{ Dropdown1.value }}", [\'Dropdown1\']) -> ({ Dropdown1 }) => `https://${\'goo\' + \'gle\'}.com/${Dropdown1.value}`\n *\n * @param value - The value to convert.\n * @param entities - The master list of possible entities that could be referenced in the binding.\n *\n * @returns The converted value.\n */\nexport function fromBinding(value: string, entities: string[]): Binding<string> {\n if (!value) {\n return "";\n }\n\n const regex = /\\{\\{\\s*([^}]*)\\s*\\}\\}/g;\n const converted: string = value.replace(regex, (match, content) => `\\${${content.trim()}}`);\n\n // there were no bindings to convert\n if (converted === value) {\n return value;\n }\n\n const args: string[] = [`return \\`${converted}\\``]\n const references: string[] = referenced(converted, entities);\n\n // only add the arguments if we have references\n if (references.length > 0) {\n args.unshift(`{ ${references} }`);\n }\n\n return new Function(...args) as (_: State) => string;\n}\n\nasync function beautifyAndOptionallyCondense<T extends JsonValue>(value: ((state: State) => T), node: Node, options: { condense?: boolean, block?: boolean } = { condense: true, block: true }) {\n let start: number = node.start;\n let end: number = node.end;\n\n if (!options.block) {\n start += 1;\n end -= 1;\n }\n \n const beautified = await beautify(value.toString().slice(start, end))\n\n if (options.condense) {\n return beautified.replace(/\\s*\\n\\s*/g, \' \').replace(/\\s+/g, \' \').trim();\n }\n\n return beautified\n}\n\nfunction createAst(value: string): Program {\n return parse(value, {\n ecmaVersion: "latest",\n sourceType: "script",\n preserveParens: false,\n });\n}\n\nasync function toJSBody<T extends JsonValue>(value: ((state: State) => T), options: { block?: boolean, condense?: boolean, function?: boolean } = { block: true, condense: true, function: false }): Promise<string> {\n if (typeof value !== "function") {\n return `{{ ${JSON.stringify(value)} }}`\n }\n\n // parse the code\n const ast = createAst(value.toString());\n const program = ast.body[0];\n\n switch (program.type) {\n case "ExpressionStatement":\n const body = ((program as ExpressionStatement).expression as FunctionExpression).body;\n\n if (body.type === \'BlockStatement\') {\n return await beautifyAndOptionallyCondense(value, body, options)\n }\n\n return `${options.function ? "return " : ""}${value.toString().slice(body.start, body.end)}`\n case "FunctionDeclaration":\n let contents = value.toString().slice(program.body.start, program.body.end)\n\n if (program.body.type !== \'BlockStatement\') {\n return contents\n }\n \n if (!options.function && program.body.body.length === 1 && program.body.body[0].type === \'ReturnStatement\') {\n return value.toString().slice(program.body.body[0].argument.start, program.body.body[0].argument.end)\n }\n\n return await beautifyAndOptionallyCondense(value, program.body, options)\n\n default:\n throw new Error("you found a case we haven\'t handled yet")\n }\n}\n\nexport async function toJS<T extends JsonValue>(value: Binding<T>): Promise<string> {\n if (typeof value !== "function") {\n return `{{ ${JSON.stringify(value)} }}`\n }\n\n const body = await toJSBody(value)\n return `{{ (() => ${body})() }}`\n}\n\nexport function fromJS<T extends JsonValue>(\n value: string,\n entities: string[] = [],\n): Binding<T> {\n // determine if there are entities referenced in the value\n const refs = referenced(value, entities).join(", ")\n\n\n // remove any surrounding whitespace\n value = value.trim()\n\n // require bindings\n if (!value.startsWith("{{") || !value.endsWith("}}")) {\n throw new Error("bindings must always be wrapped in double curly braces");\n }\n\n // remove the double curly braces and trim whitespace\n value = value.slice(2, -2).trim();\n\n let unaryOps: string[] = [];\n let call = (createAst(value).body[0] as ExpressionStatement).expression;\n\n while (call?.type === \'UnaryExpression\') {\n unaryOps.push((call as UnaryExpression).operator);\n call = (call as unknown as UnaryExpression).argument as CallExpression;\n }\n \n const fn = (call as CallExpression).callee;\n let body = value;\n let prefix = "return ";\n\n // handle iife\n if (fn?.type === "ArrowFunctionExpression") {\n // i\'m not happy with this but I don\'t see another immediate way to handle this.\n // this will result in a correct result but one that isn\'t idemopotent.\n if (unaryOps.length > 0) {\n return new Function(`{ ${refs} }`, `${prefix}${body}`) as (_: State) => T;\n }\n\n\n body = value.slice(fn.body.start, fn.body.end)\n\n if (fn.body.type === \'BlockStatement\') {\n // drop the opening "{" and closing "}"\n body = body.slice(1, -1)\n prefix = ""\n } \n } else if (refs.length === 0) {\n // we\'re not an iife nor do we have references.\n // we might have to revisit this implementation since this technically reduces to a static value down to it\'s most minimal form.\n return eval(value) as T\n }\n\n // we\'re either an iife or a static value with refs.\n return new Function(`{ ${refs} }`, `${prefix}${body}`) as (_: State) => T;\n}\n\nexport async function beautify(code: string): Promise<string> {\n const eslint = new ESLint({\n fix: true,\n overrideConfigFile: true,\n baseConfig: {\n languageOptions: {\n parser: typescript_eslint_parser,\n parserOptions: {\n ecmaVersion: 2020,\n sourceType: "module",\n },\n },\n rules: {\n "arrow-body-style": "error",\n },\n },\n });\n\n code = (await eslint.lintText(code))[0]?.output || code;\n\n return await format(code, {\n parser: "typescript",\n tabWidth: 2,\n // singleQuote: true,\n trailingComma: "none",\n semi: true,\n bracketSpacing: true,\n arrowParens: "always",\n bracketSameLine: false,\n embeddedLanguageFormatting: "auto",\n quoteProps: "as-needed",\n insertPragma: false,\n requirePragma: false,\n useTabs: false,\n endOfLine: "auto",\n arrowFunctionParentheses: "always",\n // plugins: ["prettier-plugin-organize-imports"],\n });\n}\n',
|
|
314947
314952
|
"src/to-sdk/__template__.ts": 'import { Api } from "@superblocksteam/library";\n\nconst json = {};\n\nconst entities = [];\n\nconst api = Api.fromJSON(json, entities);\n\nexport default {\n toSDK: async () => await api.toSDK(entities),\n};\n',
|
|
314948
314953
|
"tsconfig.json": '{\n "compilerOptions": {\n "target": "ES2020",\n "module": "ESNext",\n "moduleResolution": "bundler",\n "baseUrl": ".",\n "outDir": "dist",\n "rootDir": "src",\n "esModuleInterop": true,\n "resolveJsonModule": true,\n "skipLibCheck": true,\n "types": [\n "node"\n ],\n "paths": {\n "@superblocksteam/library": [\n "src/superblocks-library-shim"\n ]\n }\n },\n "include": [\n "src"\n ],\n "exclude": [\n "node_modules",\n "dist",\n ]\n}'
|
|
314949
314954
|
}
|
|
@@ -315334,7 +315339,7 @@ init_cjs_shims();
|
|
|
315334
315339
|
init_cjs_shims();
|
|
315335
315340
|
var generated = {};
|
|
315336
315341
|
try {
|
|
315337
|
-
generated = await import("./generated-
|
|
315342
|
+
generated = await import("./generated-3GKPEXCV.js");
|
|
315338
315343
|
} catch (_error) {
|
|
315339
315344
|
getLogger().warn("[ai-service] Generated markdown modules not found. Run `pnpm generate:markdown` first.");
|
|
315340
315345
|
}
|
package/oclif.manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@superblocksteam/cli",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Official Superblocks CLI",
|
|
6
6
|
"homepage": "https://www.superblocks.com",
|
|
@@ -42,9 +42,9 @@
|
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@eslint/js": "^9.16.0",
|
|
44
44
|
"@oclif/test": "^4.1.11",
|
|
45
|
-
"@superblocksteam/sdk": "2.0.0-next.
|
|
45
|
+
"@superblocksteam/sdk": "2.0.0-next.9",
|
|
46
46
|
"@superblocksteam/shared": "0.9122.0",
|
|
47
|
-
"@superblocksteam/util": "2.0.0-next.
|
|
47
|
+
"@superblocksteam/util": "2.0.0-next.9",
|
|
48
48
|
"@types/babel__core": "^7.20.0",
|
|
49
49
|
"@types/chai": "^4",
|
|
50
50
|
"@types/fs-extra": "^11.0.1",
|