@valancex/cli 0.13.0 → 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.
Files changed (50) hide show
  1. package/README.md +33 -6
  2. package/dist/budgets.json +175 -0
  3. package/dist/build.d.ts +8 -0
  4. package/dist/build.js +38 -9
  5. package/dist/check.js +6 -1
  6. package/dist/cli.js +164 -6
  7. package/dist/compile.d.ts +8 -0
  8. package/dist/compile.js +135 -16
  9. package/dist/config.d.ts +12 -0
  10. package/dist/config.js +34 -1
  11. package/dist/contract.d.ts +18 -1
  12. package/dist/contract.js +92 -3
  13. package/dist/dev.d.ts +5 -0
  14. package/dist/dev.js +60 -26
  15. package/dist/emit.d.ts +3 -1
  16. package/dist/emit.js +56 -17
  17. package/dist/libraries.d.ts +41 -0
  18. package/dist/libraries.js +169 -0
  19. package/dist/library.d.ts +32 -0
  20. package/dist/library.js +333 -0
  21. package/dist/package.js +8 -4
  22. package/dist/recording-guard.d.ts +5 -0
  23. package/dist/recording-guard.js +28 -0
  24. package/dist/replay.d.ts +15 -0
  25. package/dist/replay.js +59 -0
  26. package/dist/rules.d.ts +23 -0
  27. package/dist/rules.js +123 -0
  28. package/dist/runtime-guard.d.ts +11 -0
  29. package/dist/runtime-guard.js +62 -0
  30. package/dist/security.d.ts +2 -0
  31. package/dist/security.js +8 -1
  32. package/dist/size.d.ts +54 -0
  33. package/dist/size.js +153 -0
  34. package/dist/theme.d.ts +41 -0
  35. package/dist/theme.js +84 -0
  36. package/dist/tree.d.ts +14 -2
  37. package/dist/tree.js +16 -1
  38. package/dist/ui/report.js +1 -1
  39. package/dist/ui/run.d.ts +1 -0
  40. package/dist/ui/run.js +13 -0
  41. package/dist/vite.js +17 -3
  42. package/package.json +13 -8
  43. package/schemas/valance.schema.json +76 -0
  44. package/templates/desktop/gitignore +3 -0
  45. package/templates/multi/src/web/layout.mprx +2 -2
  46. package/templates/web/gitignore +3 -0
  47. package/templates/web/src/layout.mprx +2 -2
  48. package/views/block.mprx +1 -1
  49. package/views/layout.mprx +2 -2
  50. package/views/list-items.mprx +1 -1
package/dist/ui/run.d.ts CHANGED
@@ -14,4 +14,5 @@ export declare const drawDev: (root: string, options: {
14
14
  readonly target?: TargetId;
15
15
  readonly port?: number;
16
16
  readonly host?: string;
17
+ readonly record?: string;
17
18
  }) => Promise<void>;
package/dist/ui/run.js CHANGED
@@ -35,14 +35,27 @@ export const drawCheck = async (root) => {
35
35
  export const drawBuild = async (root, targets = []) => {
36
36
  const started = Date.now();
37
37
  const shown = show(_jsx(BuildProgress, { current: "configuration" }));
38
+ let measured = [];
38
39
  try {
39
40
  const built = await runBuild(root, {
40
41
  ...(targets.length === 0 ? {} : { targets }),
42
+ onReport: (report) => {
43
+ measured = report;
44
+ },
41
45
  onStage: ((stage) => shown.rerender(_jsx(BuildProgress, { current: stage }))),
42
46
  });
43
47
  shown.rerender(_jsx(BuildResult, { built: built, seconds: (Date.now() - started) / 1000 }));
44
48
  return built;
45
49
  }
50
+ catch (error) {
51
+ // A budget error stops the build after the bundle is measured: the report says by how much.
52
+ if (measured.length > 0) {
53
+ shown.unmount();
54
+ await shown.waitUntilExit();
55
+ measured.forEach((line) => console.error(line));
56
+ }
57
+ throw error;
58
+ }
46
59
  finally {
47
60
  shown.unmount();
48
61
  await shown.waitUntilExit();
package/dist/vite.js CHANGED
@@ -1,5 +1,6 @@
1
- import { createLogger, createServer } from "vite";
1
+ import { createLogger, createServer, defaultClientConditions, defaultServerConditions } from "vite";
2
2
  import { join, relative, sep } from "node:path";
3
+ import { CONDITION, librariesOf } from "./libraries.js";
3
4
  import { GENERATED_DIR, OUTPUT_DIR } from "./project.js";
4
5
  export const CLIENT_ENTRY = `${GENERATED_DIR}/client.ts`;
5
6
  export const SERVER_ENTRY = `/${GENERATED_DIR}/server.ts`;
@@ -30,7 +31,19 @@ export const templates = (root) => ({
30
31
  // The module is only the file's address, so a change to the template changes nothing the browser holds; the rebuild (dev.ts) recompiles it and reloads once, with the overlay if it fails.
31
32
  handleHotUpdate: ({ file }) => (file.endsWith(".mprx") ? [] : undefined),
32
33
  });
34
+ /**
35
+ * What marked packages (libraries, K4) need from the bundler: the `valance` export condition resolved, for the browser and for the server, and the packages processed by Vite instead of loaded by
36
+ * Node, which does not know `.mprx` or `.css`. Added for every project, with nothing to write: a project with no library has no package that has the condition.
37
+ */
38
+ const librarySettings = (root) => {
39
+ const names = librariesOf(root).libraries.map((each) => each.name);
40
+ return {
41
+ resolve: { conditions: [CONDITION, ...defaultClientConditions] },
42
+ ssr: { noExternal: names, resolve: { conditions: [CONDITION, ...defaultServerConditions] } },
43
+ };
44
+ };
33
45
  export const baseConfig = (root, config, out = OUTPUT_DIR) => ({
46
+ ...librarySettings(root),
34
47
  root,
35
48
  configFile: false,
36
49
  base: config.web.base,
@@ -41,9 +54,10 @@ export const baseConfig = (root, config, out = OUTPUT_DIR) => ({
41
54
  cacheDir: join(root, GENERATED_DIR, "cache"),
42
55
  customLogger: logger,
43
56
  clearScreen: false,
44
- build: { outDir: join(root, out), emptyOutDir: true, target: "esnext", manifest: true, chunkSizeWarningLimit: 1500, rollupOptions: { input: join(root, CLIENT_ENTRY) } },
57
+ build: { outDir: join(root, out), emptyOutDir: true, target: "esnext", manifest: true, rollupOptions: { input: join(root, CLIENT_ENTRY) } },
45
58
  // The MESH runtime refers to node:fs/promises on a path the browser never takes.
46
- optimizeDeps: { exclude: ["@valancex/mesh-runtime", "@valancex/cli", "@valancex/common"] },
59
+ // (a library's package is not prebundled either: its templates are the build's to compile)
60
+ optimizeDeps: { exclude: ["@valancex/mesh-runtime", "@valancex/cli", "@valancex/common", ...librariesOf(root).libraries.map((each) => each.name)] },
47
61
  });
48
62
  /** A Vite server that serves nothing: it loads the author's TypeScript and the generated server entry in Node. Used by build and check. */
49
63
  export const createLoader = async (root, config) => createServer({ ...baseConfig(root, config), optimizeDeps: { noDiscovery: true, include: [] }, server: { middlewareMode: true, hmr: false, watch: null, ws: false } });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@valancex/cli",
3
- "version": "0.13.0",
3
+ "version": "0.15.0",
4
4
  "description": "vlx, the VALANCE command: make an application (vlx init), serve it as you edit (vlx dev), build it to a static site (vlx build), check it (vlx check). Content, layout, components and styles in, a website out.",
5
5
  "keywords": [
6
6
  "valance",
@@ -49,27 +49,32 @@
49
49
  "provenance": true
50
50
  },
51
51
  "dependencies": {
52
- "@valancex/mesh-compiler": "^0.11.0",
53
- "@valancex/port-desktop-vocabulary": "^0.6.0",
52
+ "@valancex/mesh-compiler": "^0.15.0 || ^0.16.0 || ^0.17.0",
53
+ "@valancex/port-desktop-vocabulary": "^0.12.0 || ^0.13.0 || ^0.14.0",
54
54
  "effect": "^3.10.0",
55
55
  "ink": "7.1.1",
56
56
  "postject": "1.0.0-alpha.6",
57
57
  "react": "19.2.8",
58
58
  "vite": "7.3.6",
59
- "@valancex/valance": "^0.13.0",
60
- "@valancex/common": "^0.13.0"
59
+ "@valancex/common": "^0.15.0",
60
+ "@valancex/style": "^0.15.0",
61
+ "@valancex/valance": "^0.15.0"
61
62
  },
62
63
  "devDependencies": {
64
+ "@types/jsdom": "^21.1.7",
63
65
  "@types/node": "^22.0.0",
64
66
  "@types/react": "19.2.18",
65
- "@valancex/mesh-runtime": "^0.11.0",
67
+ "@valancex/mesh-runtime": "^0.17.0",
68
+ "dom-accessibility-api": "^0.7.0",
66
69
  "ink-testing-library": "4.0.0",
70
+ "jsdom": "^26.0.0",
67
71
  "playwright": "1.56.1",
68
72
  "typescript": "^5.6.0",
69
- "vitest": "^3.2.0"
73
+ "vitest": "^3.2.0",
74
+ "vnu-jar": "^26.10.12"
70
75
  },
71
76
  "scripts": {
72
- "build": "tsc -p tsconfig.json",
77
+ "build": "tsc -p tsconfig.json && node scripts/copy-data.mjs",
73
78
  "typecheck": "tsc -p tsconfig.typecheck.json",
74
79
  "test": "vitest run"
75
80
  }
@@ -27,6 +27,82 @@
27
27
  "pattern": "^[^{}]*(\\{page\\}|\\{site\\})[^{}]*(\\{page\\}|\\{site\\}|[^{}])*$",
28
28
  "maxLength": 120,
29
29
  "description": "How a document's title is written: \"{page}\" is the page's title and \"{site}\" the name above. Must contain \"{page}\". A page whose title is the site's name is that name alone."
30
+ },
31
+ "record": {
32
+ "type": "object",
33
+ "additionalProperties": false,
34
+ "required": [
35
+ "redact"
36
+ ],
37
+ "description": "What `vlx dev --record` leaves out of a session log. A log holds what was typed and seen; a value marked here is never written (its place holds a digest) and the log still replays.",
38
+ "properties": {
39
+ "redact": {
40
+ "type": "object",
41
+ "additionalProperties": false,
42
+ "properties": {
43
+ "scope": {
44
+ "type": "array",
45
+ "description": "Paths into the page's scope whose values are replaced by a digest; \"*\" is any list index or field name.",
46
+ "items": {
47
+ "type": "array",
48
+ "minItems": 1,
49
+ "items": {
50
+ "type": "string",
51
+ "minLength": 1
52
+ }
53
+ }
54
+ },
55
+ "commands": {
56
+ "type": "array",
57
+ "description": "Commands (\"component/name\") whose parameters are not recorded.",
58
+ "items": {
59
+ "type": "string",
60
+ "pattern": "^[\\w-]+/[\\w-]+$"
61
+ }
62
+ }
63
+ }
64
+ }
65
+ }
66
+ },
67
+ "theme": {
68
+ "type": "string",
69
+ "pattern": "^(@[a-z0-9][a-z0-9._-]*/)?[a-z0-9][a-z0-9._-]*$",
70
+ "description": "The theme package this project uses in place of the default theme: an installed package whose `valance` field is { \"kind\": \"theme\", \"theme\": \"./theme/theme.json\" }. A project with both this and a `theme/` directory is refused."
71
+ },
72
+ "budgets": {
73
+ "type": "array",
74
+ "description": "The size budgets `vlx build` holds the production build to (never `vlx dev`). A type, a warning and an error threshold in bytes: 500000, \"500kB\" or \"1MB\" (1 kB is 1,000 bytes). With none, the framework's start-up budgets apply.",
75
+ "items": {
76
+ "type": "object",
77
+ "additionalProperties": false,
78
+ "required": [
79
+ "type"
80
+ ],
81
+ "properties": {
82
+ "type": {
83
+ "enum": [
84
+ "initial",
85
+ "runtime",
86
+ "startup",
87
+ "afterStart",
88
+ "anyChunk"
89
+ ],
90
+ "description": "initial: the start-up JavaScript and CSS; runtime: the WebAssembly runtime; startup: the whole start-up set; afterStart: what loads once the application runs; anyChunk: the largest JavaScript chunk. Brotli bytes."
91
+ },
92
+ "warning": {
93
+ "type": [
94
+ "string",
95
+ "number"
96
+ ]
97
+ },
98
+ "error": {
99
+ "type": [
100
+ "string",
101
+ "number"
102
+ ]
103
+ }
104
+ }
105
+ }
30
106
  }
31
107
  }
32
108
  }
@@ -1,4 +1,7 @@
1
1
  node_modules
2
2
  dist
3
3
  .valance
4
+ # session recordings (vlx dev --record) hold what was typed: never commit them
5
+ .valance/sessions/
6
+ *.session.jsonl
4
7
  .work*
@@ -7,10 +7,10 @@
7
7
  <nav class="sidebar" label="Pages">
8
8
  {#each sections as s (s.id)}
9
9
  <section>
10
- {#if s.title != ""}<para class="nav-title">{s.title}</para>{/if}
10
+ {#if s.title != ""}<paragraph class="nav-title">{s.title}</paragraph>{/if}
11
11
  <list class="nav-list">
12
12
  {#each s.items as n (n.id)}
13
- <item><link class="nav-link" href={n.href} current={n.current}>{n.label}</link></item>
13
+ <listitem><link class="nav-link" href={n.href} current={n.current}>{n.label}</link></listitem>
14
14
  {/each}
15
15
  </list>
16
16
  </section>
@@ -1,4 +1,7 @@
1
1
  node_modules
2
2
  dist
3
3
  .valance
4
+ # session recordings (vlx dev --record) hold what was typed: never commit them
5
+ .valance/sessions/
6
+ *.session.jsonl
4
7
  .work*
@@ -7,10 +7,10 @@
7
7
  <nav class="sidebar" label="Pages">
8
8
  {#each sections as s (s.id)}
9
9
  <section>
10
- {#if s.title != ""}<para class="nav-title">{s.title}</para>{/if}
10
+ {#if s.title != ""}<paragraph class="nav-title">{s.title}</paragraph>{/if}
11
11
  <list class="nav-list">
12
12
  {#each s.items as n (n.id)}
13
- <item><link class="nav-link" href={n.href} current={n.current}>{n.label}</link></item>
13
+ <listitem><link class="nav-link" href={n.href} current={n.current}>{n.label}</link></listitem>
14
14
  {/each}
15
15
  </list>
16
16
  </section>
package/views/block.mprx CHANGED
@@ -1,3 +1,3 @@
1
1
  <mesh-fragment>
2
- {#if b.kind == "heading"}<heading-block level={b.level} anchor={b.anchor} spans={b.spans} />{:else if b.kind == "list"}<list-block ordered={b.ordered} items={b.items} />{:else if b.kind == "code"}<pre class="code" tabindex="0"><code>{b.text}</code></pre>{:else if b.kind == "quote"}<quote class="quote"><runs spans={b.spans} /></quote>{:else if b.kind == "image"}<image class="picture" src={b.src} alt={b.alt} loading="lazy" />{:else}<para class="prose"><runs spans={b.spans} /></para>{/if}
2
+ {#if b.kind == "heading"}<heading-block level={b.level} anchor={b.anchor} spans={b.spans} />{:else if b.kind == "list"}<list-block ordered={b.ordered} items={b.items} />{:else if b.kind == "code"}<pre class="code" tabindex="0"><code>{b.text}</code></pre>{:else if b.kind == "quote"}<blockquote class="quote"><runs spans={b.spans} /></blockquote>{:else if b.kind == "image"}<image class="picture" src={b.src} alt={b.alt} loading="lazy" />{:else}<paragraph class="prose"><runs spans={b.spans} /></paragraph>{/if}
3
3
  </mesh-fragment>
package/views/layout.mprx CHANGED
@@ -6,10 +6,10 @@
6
6
  <nav class="sidebar" label="Pages">
7
7
  {#each sections as s (s.id)}
8
8
  <section>
9
- {#if s.title != ""}<para class="nav-title">{s.title}</para>{/if}
9
+ {#if s.title != ""}<paragraph class="nav-title">{s.title}</paragraph>{/if}
10
10
  <list class="nav-list">
11
11
  {#each s.items as n (n.id)}
12
- <item><link class="nav-link" href={n.href} current={n.current}>{n.label}</link></item>
12
+ <listitem><link class="nav-link" href={n.href} current={n.current}>{n.label}</link></listitem>
13
13
  {/each}
14
14
  </list>
15
15
  </section>
@@ -1,3 +1,3 @@
1
1
  <mesh-fragment>
2
- {#each items as i (i.id)}<item><runs spans={i.spans} /></item>{/each}
2
+ {#each items as i (i.id)}<listitem><runs spans={i.spans} /></listitem>{/each}
3
3
  </mesh-fragment>