@constela/compiler 0.14.6 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Program, ConstelaError, Expression, LayoutProgram, ComponentDef, ViewNode } from '@constela/core';
1
+ import { Program, ConstelaError, Expression, IslandStrategy, IslandStrategyOptions, LayoutProgram, ComponentDef, ViewNode } from '@constela/core';
2
2
  export { createUndefinedVarError } from '@constela/core';
3
3
 
4
4
  /**
@@ -21,6 +21,7 @@ interface AnalysisContext {
21
21
  dataNames: Set<string>;
22
22
  refNames: Set<string>;
23
23
  styleNames: Set<string>;
24
+ islandIds: Set<string>;
24
25
  }
25
26
  interface AnalyzePassSuccess {
26
27
  ok: true;
@@ -102,7 +103,7 @@ interface CompiledAction {
102
103
  name: string;
103
104
  steps: CompiledActionStep[];
104
105
  }
105
- type CompiledActionStep = CompiledSetStep | CompiledUpdateStep | CompiledSetPathStep | CompiledFetchStep | CompiledStorageStep | CompiledClipboardStep | CompiledNavigateStep | CompiledImportStep | CompiledCallStep | CompiledSubscribeStep | CompiledDisposeStep | CompiledDomStep | CompiledIfStep | CompiledSendStep | CompiledCloseStep | CompiledDelayStep | CompiledIntervalStep | CompiledClearTimerStep | CompiledFocusStep;
106
+ type CompiledActionStep = CompiledSetStep | CompiledUpdateStep | CompiledSetPathStep | CompiledFetchStep | CompiledStorageStep | CompiledClipboardStep | CompiledNavigateStep | CompiledImportStep | CompiledCallStep | CompiledSubscribeStep | CompiledDisposeStep | CompiledDomStep | CompiledIfStep | CompiledSendStep | CompiledCloseStep | CompiledDelayStep | CompiledIntervalStep | CompiledClearTimerStep | CompiledFocusStep | CompiledGenerateStep | CompiledSSEConnectStep | CompiledSSECloseStep | CompiledOptimisticStep | CompiledConfirmStep | CompiledRejectStep | CompiledBindStep | CompiledUnbindStep;
106
107
  interface CompiledSetStep {
107
108
  do: 'set';
108
109
  target: string;
@@ -265,6 +266,90 @@ interface CompiledFocusStep {
265
266
  onSuccess?: CompiledActionStep[];
266
267
  onError?: CompiledActionStep[];
267
268
  }
269
+ /**
270
+ * Compiled generate step for AI generation
271
+ */
272
+ interface CompiledGenerateStep {
273
+ do: 'generate';
274
+ provider: 'anthropic' | 'openai';
275
+ prompt: CompiledExpression;
276
+ output: 'component' | 'view';
277
+ result: string;
278
+ model?: string;
279
+ onSuccess?: CompiledActionStep[];
280
+ onError?: CompiledActionStep[];
281
+ }
282
+ /**
283
+ * Compiled SSE connect step
284
+ */
285
+ interface CompiledSSEConnectStep {
286
+ do: 'sseConnect';
287
+ connection: string;
288
+ url: CompiledExpression;
289
+ eventTypes?: string[];
290
+ reconnect?: {
291
+ enabled: boolean;
292
+ strategy: string;
293
+ maxRetries: number;
294
+ baseDelay: number;
295
+ maxDelay?: number;
296
+ };
297
+ onOpen?: CompiledActionStep[];
298
+ onMessage?: CompiledActionStep[];
299
+ onError?: CompiledActionStep[];
300
+ }
301
+ /**
302
+ * Compiled SSE close step
303
+ */
304
+ interface CompiledSSECloseStep {
305
+ do: 'sseClose';
306
+ connection: string;
307
+ }
308
+ /**
309
+ * Compiled optimistic step
310
+ */
311
+ interface CompiledOptimisticStep {
312
+ do: 'optimistic';
313
+ target: string;
314
+ path?: CompiledExpression;
315
+ value: CompiledExpression;
316
+ result?: string;
317
+ timeout?: number;
318
+ }
319
+ /**
320
+ * Compiled confirm step
321
+ */
322
+ interface CompiledConfirmStep {
323
+ do: 'confirm';
324
+ id: CompiledExpression;
325
+ }
326
+ /**
327
+ * Compiled reject step
328
+ */
329
+ interface CompiledRejectStep {
330
+ do: 'reject';
331
+ id: CompiledExpression;
332
+ }
333
+ /**
334
+ * Compiled bind step
335
+ */
336
+ interface CompiledBindStep {
337
+ do: 'bind';
338
+ connection: string;
339
+ eventType?: string;
340
+ target: string;
341
+ path?: CompiledExpression;
342
+ transform?: CompiledExpression;
343
+ patch?: boolean;
344
+ }
345
+ /**
346
+ * Compiled unbind step
347
+ */
348
+ interface CompiledUnbindStep {
349
+ do: 'unbind';
350
+ connection: string;
351
+ target: string;
352
+ }
268
353
  /**
269
354
  * Compiled local action
270
355
  */
@@ -284,7 +369,39 @@ interface CompiledLocalStateNode {
284
369
  actions: Record<string, CompiledLocalAction>;
285
370
  child: CompiledNode;
286
371
  }
287
- type CompiledNode = CompiledElementNode | CompiledTextNode | CompiledIfNode | CompiledEachNode | CompiledMarkdownNode | CompiledCodeNode | CompiledSlotNode | CompiledPortalNode | CompiledLocalStateNode;
372
+ /**
373
+ * Compiled island node - represents an interactive island in the Islands Architecture
374
+ */
375
+ interface CompiledIslandNode {
376
+ kind: 'island';
377
+ id: string;
378
+ strategy: IslandStrategy;
379
+ strategyOptions?: IslandStrategyOptions;
380
+ content: CompiledNode;
381
+ state?: Record<string, {
382
+ type: string;
383
+ initial: unknown;
384
+ }>;
385
+ actions?: Record<string, CompiledAction>;
386
+ }
387
+ /**
388
+ * Compiled suspense node - represents an async boundary with fallback
389
+ */
390
+ interface CompiledSuspenseNode {
391
+ kind: 'suspense';
392
+ id: string;
393
+ fallback: CompiledNode;
394
+ content: CompiledNode;
395
+ }
396
+ /**
397
+ * Compiled error boundary node - represents an error handling boundary
398
+ */
399
+ interface CompiledErrorBoundaryNode {
400
+ kind: 'errorBoundary';
401
+ fallback: CompiledNode;
402
+ content: CompiledNode;
403
+ }
404
+ type CompiledNode = CompiledElementNode | CompiledTextNode | CompiledIfNode | CompiledEachNode | CompiledMarkdownNode | CompiledCodeNode | CompiledSlotNode | CompiledPortalNode | CompiledLocalStateNode | CompiledIslandNode | CompiledSuspenseNode | CompiledErrorBoundaryNode;
288
405
  interface CompiledElementNode {
289
406
  kind: 'element';
290
407
  tag: string;
@@ -563,4 +680,4 @@ declare function transformLayoutPass(layout: LayoutProgram, _context: LayoutAnal
563
680
  */
564
681
  declare function composeLayoutWithPage(layout: CompiledProgram, page: CompiledProgram, layoutParams?: Record<string, Expression>, slots?: Record<string, ViewNode>): CompiledProgram;
565
682
 
566
- export { type AnalysisContext, type AnalyzePassFailure, type AnalyzePassResult, type AnalyzePassSuccess, type CompileFailure, type CompileResult, type CompileSuccess, type CompiledAction, type CompiledActionStep, type CompiledArrayExpr, type CompiledBinExpr, type CompiledCallExpr, type CompiledCallStep, type CompiledClearTimerStep, type CompiledClipboardStep, type CompiledCloseStep, type CompiledCodeNode, type CompiledConcatExpr, type CompiledCondExpr, type CompiledDataExpr, type CompiledDelayStep, type CompiledDisposeStep, type CompiledDomStep, type CompiledEachNode, type CompiledElementNode, type CompiledEventHandler, type CompiledEventHandlerOptions, type CompiledExpression, type CompiledFetchStep, type CompiledFocusStep, type CompiledGetExpr, type CompiledIfNode, type CompiledIfStep, type CompiledImportExpr, type CompiledImportStep, type CompiledIndexExpr, type CompiledIntervalStep, type CompiledLambdaExpr, type CompiledLayoutProgram, type CompiledLifecycleHooks, type CompiledLitExpr, type CompiledLocalAction, type CompiledLocalStateNode, type CompiledMarkdownNode, type CompiledNavigateStep, type CompiledNode, type CompiledNotExpr, type CompiledParamExpr, type CompiledPortalNode, type CompiledProgram, type CompiledRefExpr, type CompiledRouteDefinition, type CompiledRouteExpr, type CompiledSendStep, type CompiledSetPathStep, type CompiledSetStep, type CompiledSlotNode, type CompiledStateExpr, type CompiledStorageStep, type CompiledStyleExpr, type CompiledSubscribeStep, type CompiledTextNode, type CompiledUpdateStep, type CompiledValidityExpr, type CompiledVarExpr, type LayoutAnalysisContext, type LayoutAnalysisFailure, type LayoutAnalysisResult, type LayoutAnalysisSuccess, type ValidatePassFailure, type ValidatePassResult, type ValidatePassSuccess, analyzeLayoutPass, analyzePass, compile, composeLayoutWithPage, transformLayoutPass, transformPass, validatePass };
683
+ export { type AnalysisContext, type AnalyzePassFailure, type AnalyzePassResult, type AnalyzePassSuccess, type CompileFailure, type CompileResult, type CompileSuccess, type CompiledAction, type CompiledActionStep, type CompiledArrayExpr, type CompiledBinExpr, type CompiledBindStep, type CompiledCallExpr, type CompiledCallStep, type CompiledClearTimerStep, type CompiledClipboardStep, type CompiledCloseStep, type CompiledCodeNode, type CompiledConcatExpr, type CompiledCondExpr, type CompiledConfirmStep, type CompiledDataExpr, type CompiledDelayStep, type CompiledDisposeStep, type CompiledDomStep, type CompiledEachNode, type CompiledElementNode, type CompiledErrorBoundaryNode, type CompiledEventHandler, type CompiledEventHandlerOptions, type CompiledExpression, type CompiledFetchStep, type CompiledFocusStep, type CompiledGenerateStep, type CompiledGetExpr, type CompiledIfNode, type CompiledIfStep, type CompiledImportExpr, type CompiledImportStep, type CompiledIndexExpr, type CompiledIntervalStep, type CompiledIslandNode, type CompiledLambdaExpr, type CompiledLayoutProgram, type CompiledLifecycleHooks, type CompiledLitExpr, type CompiledLocalAction, type CompiledLocalStateNode, type CompiledMarkdownNode, type CompiledNavigateStep, type CompiledNode, type CompiledNotExpr, type CompiledOptimisticStep, type CompiledParamExpr, type CompiledPortalNode, type CompiledProgram, type CompiledRefExpr, type CompiledRejectStep, type CompiledRouteDefinition, type CompiledRouteExpr, type CompiledSSECloseStep, type CompiledSSEConnectStep, type CompiledSendStep, type CompiledSetPathStep, type CompiledSetStep, type CompiledSlotNode, type CompiledStateExpr, type CompiledStorageStep, type CompiledStyleExpr, type CompiledSubscribeStep, type CompiledSuspenseNode, type CompiledTextNode, type CompiledUnbindStep, type CompiledUpdateStep, type CompiledValidityExpr, type CompiledVarExpr, type LayoutAnalysisContext, type LayoutAnalysisFailure, type LayoutAnalysisResult, type LayoutAnalysisSuccess, type ValidatePassFailure, type ValidatePassResult, type ValidatePassSuccess, analyzeLayoutPass, analyzePass, compile, composeLayoutWithPage, transformLayoutPass, transformPass, validatePass };
package/dist/index.js CHANGED
@@ -46,6 +46,7 @@ import {
46
46
  createUndefinedVariantError,
47
47
  createUndefinedLocalStateError,
48
48
  createLocalActionInvalidStepError,
49
+ createDuplicateIslandIdError,
49
50
  findSimilarNames,
50
51
  isEventHandler,
51
52
  DATA_SOURCE_TYPES,
@@ -141,7 +142,8 @@ function collectContext(programAst) {
141
142
  const styleNames = new Set(
142
143
  programAst.styles ? Object.keys(programAst.styles) : []
143
144
  );
144
- return { stateNames, actionNames, componentNames, routeParams, importNames, dataNames, refNames, styleNames };
145
+ const islandIds = /* @__PURE__ */ new Set();
146
+ return { stateNames, actionNames, componentNames, routeParams, importNames, dataNames, refNames, styleNames, islandIds };
145
147
  }
146
148
  function checkDuplicateActions(ast2) {
147
149
  const errors = [];
@@ -911,6 +913,57 @@ function validateViewNode(node, path, context, scope, options = { insideComponen
911
913
  );
912
914
  }
913
915
  break;
916
+ case "island": {
917
+ if (context.islandIds.has(node.id)) {
918
+ errors.push(createDuplicateIslandIdError(node.id, path));
919
+ } else {
920
+ context.islandIds.add(node.id);
921
+ }
922
+ const islandStateNames = new Set(
923
+ node.state ? Object.keys(node.state) : []
924
+ );
925
+ const islandActionNames = new Set(
926
+ node.actions ? node.actions.map((a) => a.name) : []
927
+ );
928
+ const islandParamScope = {
929
+ params: /* @__PURE__ */ new Set(),
930
+ componentName: `island:${node.id}`,
931
+ localStateNames: islandStateNames,
932
+ localActionNames: islandActionNames
933
+ };
934
+ errors.push(
935
+ ...validateViewNode(
936
+ node.content,
937
+ buildPath(path, "content"),
938
+ context,
939
+ scope,
940
+ { ...options, paramScope: islandParamScope }
941
+ )
942
+ );
943
+ if (node.actions) {
944
+ for (let i = 0; i < node.actions.length; i++) {
945
+ const action = node.actions[i];
946
+ if (!action) continue;
947
+ for (let j = 0; j < action.steps.length; j++) {
948
+ const step = action.steps[j];
949
+ if (!step) continue;
950
+ if (step.do === "set" || step.do === "update" || step.do === "setPath") {
951
+ const target = step.target;
952
+ if (!islandStateNames.has(target) && !context.stateNames.has(target)) {
953
+ errors.push(
954
+ createUndefinedStateError(
955
+ target,
956
+ buildPath(path, "actions", i, "steps", j, "target"),
957
+ createErrorOptionsWithSuggestion(target, /* @__PURE__ */ new Set([...islandStateNames, ...context.stateNames]))
958
+ )
959
+ );
960
+ }
961
+ }
962
+ }
963
+ }
964
+ }
965
+ break;
966
+ }
914
967
  }
915
968
  return errors;
916
969
  }
@@ -1667,6 +1720,82 @@ function transformActionStep(step) {
1667
1720
  }
1668
1721
  return compiledIfStep;
1669
1722
  }
1723
+ case "generate": {
1724
+ const generateStep = step;
1725
+ const compiledGenerateStep = {
1726
+ do: "generate",
1727
+ provider: generateStep.provider,
1728
+ prompt: transformExpression(generateStep.prompt, emptyContext),
1729
+ output: generateStep.output,
1730
+ result: generateStep.result
1731
+ };
1732
+ if (generateStep.model) {
1733
+ compiledGenerateStep.model = generateStep.model;
1734
+ }
1735
+ if (generateStep.onSuccess) {
1736
+ compiledGenerateStep.onSuccess = generateStep.onSuccess.map(transformActionStep);
1737
+ }
1738
+ if (generateStep.onError) {
1739
+ compiledGenerateStep.onError = generateStep.onError.map(transformActionStep);
1740
+ }
1741
+ return compiledGenerateStep;
1742
+ }
1743
+ // ==================== Realtime Steps ====================
1744
+ case "sseConnect": {
1745
+ const sseStep = step;
1746
+ const compiled = {
1747
+ do: "sseConnect",
1748
+ connection: sseStep.connection,
1749
+ url: transformExpression(sseStep.url, emptyContext)
1750
+ };
1751
+ if (sseStep.eventTypes) compiled.eventTypes = sseStep.eventTypes;
1752
+ if (sseStep.reconnect) compiled.reconnect = sseStep.reconnect;
1753
+ if (sseStep.onOpen) compiled.onOpen = sseStep.onOpen.map(transformActionStep);
1754
+ if (sseStep.onMessage) compiled.onMessage = sseStep.onMessage.map(transformActionStep);
1755
+ if (sseStep.onError) compiled.onError = sseStep.onError.map(transformActionStep);
1756
+ return compiled;
1757
+ }
1758
+ case "sseClose": {
1759
+ const sseCloseStep = step;
1760
+ return { do: "sseClose", connection: sseCloseStep.connection };
1761
+ }
1762
+ case "optimistic": {
1763
+ const optStep = step;
1764
+ const compiled = {
1765
+ do: "optimistic",
1766
+ target: optStep.target,
1767
+ value: transformExpression(optStep.value, emptyContext)
1768
+ };
1769
+ if (optStep.path) compiled.path = transformExpression(optStep.path, emptyContext);
1770
+ if (optStep.result) compiled.result = optStep.result;
1771
+ if (optStep.timeout) compiled.timeout = optStep.timeout;
1772
+ return compiled;
1773
+ }
1774
+ case "confirm": {
1775
+ const confirmStep = step;
1776
+ return { do: "confirm", id: transformExpression(confirmStep.id, emptyContext) };
1777
+ }
1778
+ case "reject": {
1779
+ const rejectStep = step;
1780
+ return { do: "reject", id: transformExpression(rejectStep.id, emptyContext) };
1781
+ }
1782
+ case "bind": {
1783
+ const bindStep = step;
1784
+ const compiled = {
1785
+ do: "bind",
1786
+ connection: bindStep.connection,
1787
+ target: bindStep.target
1788
+ };
1789
+ if (bindStep.eventType) compiled.eventType = bindStep.eventType;
1790
+ if (bindStep.path) compiled.path = transformExpression(bindStep.path, emptyContext);
1791
+ if (bindStep.transform) compiled.transform = transformExpression(bindStep.transform, emptyContext);
1792
+ if (bindStep.patch) compiled.patch = bindStep.patch;
1793
+ return compiled;
1794
+ }
1795
+ case "unbind": {
1796
+ const unbindStep = step;
1797
+ return { do: "unbind", connection: unbindStep.connection, target: unbindStep.target };
1798
+ }
1670
1799
  }
1671
1800
  }
1672
1801
  function flattenSlotChildren(children, ctx) {
@@ -1811,6 +1940,46 @@ function transformViewNode(node, ctx) {
1811
1940
  children: compiledChildren
1812
1941
  };
1813
1942
  }
1943
+ case "island": {
1944
+ const islandNode = node;
1945
+ const compiledIsland = {
1946
+ kind: "island",
1947
+ id: islandNode.id,
1948
+ strategy: islandNode.strategy,
1949
+ content: transformViewNode(islandNode.content, ctx)
1950
+ };
1951
+ if (islandNode.strategyOptions) {
1952
+ compiledIsland.strategyOptions = islandNode.strategyOptions;
1953
+ }
1954
+ if (islandNode.state) {
1955
+ compiledIsland.state = transformState(islandNode.state);
1956
+ }
1957
+ if (islandNode.actions && islandNode.actions.length > 0) {
1958
+ compiledIsland.actions = transformActions(islandNode.actions);
1959
+ }
1960
+ return compiledIsland;
1961
+ }
1962
+ case "suspense": {
1963
+ const suspenseNode = node;
1964
+ return {
1965
+ kind: "suspense",
1966
+ id: suspenseNode.id,
1967
+ fallback: transformViewNode(suspenseNode.fallback, ctx),
1968
+ content: transformViewNode(suspenseNode.content, ctx)
1969
+ };
1970
+ }
1971
+ case "errorBoundary": {
1972
+ const errorBoundaryNode = node;
1973
+ return {
1974
+ kind: "errorBoundary",
1975
+ fallback: transformViewNode(errorBoundaryNode.fallback, ctx),
1976
+ content: transformViewNode(errorBoundaryNode.content, ctx)
1977
+ };
1978
+ }
1979
+ default: {
1980
+ const _exhaustiveCheck = node;
1981
+ throw new Error(`Unknown node kind: ${JSON.stringify(_exhaustiveCheck)}`);
1982
+ }
1814
1983
  }
1815
1984
  }
1816
1985
  function transformState(state) {
@@ -2652,6 +2821,52 @@ function transformViewNode2(node, ctx) {
2652
2821
  (child) => transformViewNode2(child, ctx)
2653
2822
  )
2654
2823
  };
2824
+ case "island": {
2825
+ const islandNode = node;
2826
+ const compiledIsland = {
2827
+ kind: "island",
2828
+ id: islandNode.id,
2829
+ strategy: islandNode.strategy,
2830
+ content: transformViewNode2(islandNode.content, ctx)
2831
+ };
2832
+ if (islandNode.strategyOptions) {
2833
+ compiledIsland.strategyOptions = islandNode.strategyOptions;
2834
+ }
2835
+ if (islandNode.state) {
2836
+ compiledIsland.state = transformLocalState2(islandNode.state);
2837
+ }
2838
+ if (islandNode.actions && islandNode.actions.length > 0) {
2839
+ compiledIsland.actions = {};
2840
+ for (const action of islandNode.actions) {
2841
+ compiledIsland.actions[action.name] = {
2842
+ name: action.name,
2843
+ steps: action.steps.map((s) => transformActionStep2(s))
2844
+ };
2845
+ }
2846
+ }
2847
+ return compiledIsland;
2848
+ }
2849
+ case "suspense": {
2850
+ const suspenseNode = node;
2851
+ return {
2852
+ kind: "suspense",
2853
+ id: suspenseNode.id,
2854
+ fallback: transformViewNode2(suspenseNode.fallback, ctx),
2855
+ content: transformViewNode2(suspenseNode.content, ctx)
2856
+ };
2857
+ }
2858
+ case "errorBoundary": {
2859
+ const errorBoundaryNode = node;
2860
+ return {
2861
+ kind: "errorBoundary",
2862
+ fallback: transformViewNode2(errorBoundaryNode.fallback, ctx),
2863
+ content: transformViewNode2(errorBoundaryNode.content, ctx)
2864
+ };
2865
+ }
2866
+ default: {
2867
+ const _exhaustiveCheck = node;
2868
+ throw new Error(`Unknown node kind: ${JSON.stringify(_exhaustiveCheck)}`);
2869
+ }
2655
2870
  }
2656
2871
  }
2657
2872
  function transformLayoutPass(layout, _context) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@constela/compiler",
3
- "version": "0.14.6",
3
+ "version": "0.15.0",
4
4
  "description": "Compiler for Constela UI framework - AST to Program transformation",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -15,7 +15,7 @@
15
15
  "dist"
16
16
  ],
17
17
  "dependencies": {
18
- "@constela/core": "0.16.1"
18
+ "@constela/core": "0.17.0"
19
19
  },
20
20
  "devDependencies": {
21
21
  "@types/node": "^20.10.0",