@cynodia/axiom-compiler 0.5.0-alpha.1 → 0.5.2-alpha.1

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
@@ -9,11 +9,14 @@ Validates an Application Graph, normalizes it into a runtime-ready IR, and emits
9
9
  self-contained HTML page with the runtime inlined.
10
10
 
11
11
  Normalization resolves presentation once — renderer defaults, theme, inheritance, semantic
12
- inference, node declarations and responsive overrides — and puts the result in the IR,
13
- still as roles and tokens rather than CSS. `createThemeStylesheet` is the web renderer's
12
+ inference, node declarations and responsive overrides — and puts the result in the IR, still
13
+ as roles and tokens rather than CSS. `createThemeStylesheet` is the web renderer's
14
14
  translation of a theme into CSS custom properties and rules, and is the only place in the
15
15
  framework that decides a role is a colour.
16
16
 
17
+ Main exports: `compileToIR`, `compileToHtml`, `createThemeStylesheet`,
18
+ `GraphValidationError`.
19
+
17
20
  ## Installation
18
21
 
19
22
  ```bash
@@ -26,6 +29,13 @@ Most applications should install the facade package instead, which re-exports th
26
29
  npm install @cynodia/axiom@alpha
27
30
  ```
28
31
 
32
+
33
+ ## Documentation
34
+
35
+ The canonical operational contract lives in the `docs/` directory of the
36
+ [`@cynodia/axiom`](https://www.npmjs.com/package/@cynodia/axiom) package, and in
37
+ [the repository](https://github.com/cynodia/axiom). Start with `docs/AGENT_REFERENCE.md`.
38
+
29
39
  ## License
30
40
 
31
41
  MIT
package/dist/normalize.js CHANGED
@@ -1,4 +1,4 @@
1
- import { actionGuards, inferLocationType, locationFieldIds, locationRootStateId, resolvePresentationMap, semanticContextFromGraph, validateGraph, } from '@cynodia/axiom-core';
1
+ import { actionGuards, inferExpressionType, inferLocationType, itemTypeOf, locationFieldIds, locationRootStateId, resolvePresentationMap, semanticContextFromGraph, validateGraph, } from '@cynodia/axiom-core';
2
2
  import { isUINode } from '@cynodia/axiom-core';
3
3
  export class GraphValidationError extends Error {
4
4
  problems;
@@ -112,6 +112,24 @@ export function compileToIR(graph, options = {}) {
112
112
  ? graph.getField(addressed)?.field.required === true
113
113
  : resolved !== undefined && resolved.kind !== 'optional';
114
114
  }
115
+ // Which field distinguishes the members of each repeat, so the renderer can give every
116
+ // rendered instance a stable identity without inferring anything itself.
117
+ const repeatIdentityFields = {};
118
+ for (const node of Object.values(uiNodes)) {
119
+ if (node.kind !== 'repeat') {
120
+ continue;
121
+ }
122
+ const sourceType = inferExpressionType(node.source, semantics);
123
+ const item = itemTypeOf(sourceType);
124
+ const resolved = item?.kind === 'optional' ? item.valueType : item;
125
+ if (resolved?.kind !== 'entity') {
126
+ continue;
127
+ }
128
+ const identity = graph.getNode(resolved.entityId)?.identityFieldId;
129
+ if (identity) {
130
+ repeatIdentityFields[node.id] = identity;
131
+ }
132
+ }
115
133
  // Presentation is normalized here, once: renderer defaults, theme, inheritance,
116
134
  // semantic inference, node declarations and responsive overrides are all decided before
117
135
  // a renderer sees them. What lands in the IR is still semantic — roles and tokens, not
@@ -135,6 +153,7 @@ export function compileToIR(graph, options = {}) {
135
153
  locationTypes,
136
154
  locationRoots,
137
155
  locationRequired,
156
+ repeatIdentityFields,
138
157
  theme,
139
158
  presentation,
140
159
  };
@@ -308,7 +308,7 @@ body {
308
308
  .axiom-input-description { color: var(--axiom-color-text-muted); font-size: ${theme.typography.roles.caption.size}px; }
309
309
  .axiom-required-marker { color: var(--axiom-color-destructive); margin-left: 2px; }
310
310
 
311
- .axiom-control {
311
+ input.axiom-control, select.axiom-control, textarea.axiom-control, .axiom-control {
312
312
  font: inherit;
313
313
  color: var(--axiom-color-text);
314
314
  background: var(--axiom-color-surface);
@@ -327,24 +327,33 @@ input[type="checkbox"].axiom-control { width: 1.15em; height: 1.15em; min-height
327
327
  .axiom-control:disabled { opacity: 0.6; }
328
328
  .axiom-control[aria-invalid="true"] { border-color: var(--axiom-color-destructive); }
329
329
 
330
- .axiom-button {
330
+ button.axiom-button {
331
331
  font: inherit;
332
332
  font-weight: 560;
333
+ /* The internal arrangement comes from the theme's button metrics, so no application
334
+ has to restate layout and padding on every control. */
333
335
  display: inline-flex;
334
- align-items: center;
335
- justify-content: center;
336
- gap: ${space('xsmall')};
336
+ flex-direction: ${theme.buttons.layout === 'vertical' ? 'column' : 'row'};
337
+ align-items: ${ALIGN_VALUES[theme.buttons.align]};
338
+ justify-content: ${JUSTIFY_VALUES[theme.buttons.justify]};
339
+ gap: ${space(theme.buttons.gap)};
337
340
  min-height: var(--axiom-control-height);
338
- padding: 0 calc(var(--axiom-control-padding-x) * 1.15);
341
+ padding: 0 calc(var(--axiom-control-padding-x) * ${theme.buttons.paddingScale});
339
342
  border: var(--axiom-control-border) solid transparent;
340
343
  border-radius: var(--axiom-control-radius);
341
344
  background: var(--axiom-color-surface);
342
345
  color: var(--axiom-color-text);
343
346
  cursor: pointer;
344
347
  white-space: nowrap;
348
+ text-align: center;
345
349
  }
346
- .axiom-button:hover { filter: brightness(0.96); }
347
- .axiom-button:active { transform: translateY(1px); }
350
+ button.axiom-button:hover { filter: brightness(0.96); }
351
+ button.axiom-button:active { transform: translateY(1px); }
352
+ /* A button's own contents are laid out by the theme; a layout token on the node refines
353
+ the direction without giving up the control's metrics. */
354
+ button.axiom-button.axiom-layout-vertical { flex-direction: column; }
355
+ button.axiom-button.axiom-layout-horizontal { flex-direction: row; }
356
+ .axiom-button > .axiom-button-label { white-space: nowrap; }
348
357
 
349
358
  :focus-visible { outline: var(--axiom-focus-width) solid var(--axiom-color-focus); outline-offset: 1px; }
350
359
 
@@ -352,6 +361,8 @@ input[type="checkbox"].axiom-control { width: 1.15em; height: 1.15em; min-height
352
361
  .axiom-ux-empty-state { text-align: center; }
353
362
  .axiom-ux-form-section + .axiom-ux-form-section { padding-top: ${space('small')}; border-top: 1px solid var(--axiom-color-border); }
354
363
 
364
+ .axiom-diagnostic[data-empty="true"] { display: none; }
365
+ .axiom-diagnostic-entry { color: inherit; }
355
366
  .axiom-no-route { padding: ${space('large')}; background: var(--axiom-color-surface); border-radius: var(--axiom-radius-medium); }
356
367
  .axiom-diagnostics { list-style: none; margin: 0; padding: 0; }
357
368
  `.trim();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cynodia/axiom-compiler",
3
- "version": "0.5.0-alpha.1",
3
+ "version": "0.5.2-alpha.1",
4
4
  "description": "Normalizes an Axiom application graph and emits a self-contained page.",
5
5
  "license": "MIT",
6
6
  "author": "AskTech AS",
@@ -31,8 +31,8 @@
31
31
  }
32
32
  },
33
33
  "dependencies": {
34
- "@cynodia/axiom-core": "0.5.0-alpha.1",
35
- "@cynodia/axiom-runtime": "0.5.0-alpha.1"
34
+ "@cynodia/axiom-core": "0.5.2-alpha.1",
35
+ "@cynodia/axiom-runtime": "0.5.2-alpha.1"
36
36
  },
37
37
  "scripts": {
38
38
  "build": "tsc -b tsconfig.json tsconfig.test.json",