@weft-js/cli 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (171) hide show
  1. package/README.md +38 -14
  2. package/bin/weft.mjs +8 -1
  3. package/docs/async.md +16 -6
  4. package/docs/browser.md +22 -8
  5. package/docs/config.md +39 -9
  6. package/docs/core.md +30 -0
  7. package/docs/deploy.md +108 -0
  8. package/docs/design.md +12 -3
  9. package/docs/entrypoints.md +79 -0
  10. package/docs/fonts.md +12 -2
  11. package/docs/icons.md +13 -7
  12. package/docs/lists.md +3 -1
  13. package/docs/meta.md +13 -3
  14. package/docs/plugins.md +32 -9
  15. package/docs/props.md +13 -2
  16. package/docs/reactivity.md +26 -0
  17. package/docs/rules.md +19 -12
  18. package/docs/rust.md +47 -17
  19. package/docs/start-short.md +3 -2
  20. package/docs/start.md +226 -52
  21. package/docs/state.md +33 -7
  22. package/docs/style.md +31 -8
  23. package/docs/surface.md +61 -15
  24. package/docs/testing.md +15 -5
  25. package/docs/theme.md +182 -0
  26. package/docs/ui-state.md +19 -6
  27. package/docs/verify.md +13 -0
  28. package/package.json +13 -4
  29. package/src/add/config.mjs +93 -0
  30. package/src/add/errors.mjs +2 -0
  31. package/src/add/setup.mjs +88 -0
  32. package/src/add-rust.mjs +82 -27
  33. package/src/add.mjs +209 -181
  34. package/src/agents-md.mjs +144 -43
  35. package/src/alias.mjs +16 -5
  36. package/src/audit/page.mjs +313 -0
  37. package/src/audit/report.mjs +69 -0
  38. package/src/audit/utils.mjs +5 -0
  39. package/src/audit.mjs +174 -188
  40. package/src/browser/cli.mjs +24 -5
  41. package/src/browser/client.mjs +189 -25
  42. package/src/browser/commands.mjs +166 -51
  43. package/src/catalog/audit.mjs +129 -0
  44. package/src/catalog/auth.mjs +40 -0
  45. package/src/catalog/compiler.mjs +337 -0
  46. package/src/catalog/contracts.mjs +18 -0
  47. package/src/catalog/database.mjs +52 -0
  48. package/src/catalog/deploy.mjs +117 -0
  49. package/src/catalog/design.mjs +159 -0
  50. package/src/catalog/forms.mjs +25 -0
  51. package/src/catalog/hydration.mjs +29 -0
  52. package/src/catalog/icons.mjs +24 -0
  53. package/src/catalog/media.mjs +163 -0
  54. package/src/catalog/metadata.mjs +116 -0
  55. package/src/catalog/plugins.mjs +228 -0
  56. package/src/catalog/realtime.mjs +195 -0
  57. package/src/catalog/rust.mjs +75 -0
  58. package/src/catalog/server-functions.mjs +92 -0
  59. package/src/catalog/state.mjs +39 -0
  60. package/src/catalog/style-groups.mjs +54 -0
  61. package/src/catalog/tests.mjs +127 -0
  62. package/src/catalog/text.mjs +200 -0
  63. package/src/catalog/ui-state.mjs +42 -0
  64. package/src/catalog.mjs +68 -444
  65. package/src/check/runtime.mjs +280 -0
  66. package/src/check.mjs +199 -207
  67. package/src/cli/authoring.mjs +213 -0
  68. package/src/cli/project.mjs +302 -0
  69. package/src/cli.mjs +228 -224
  70. package/src/config.mjs +1 -1
  71. package/src/contributions.mjs +75 -25
  72. package/src/db-layer.mjs +13 -5
  73. package/src/deploy/cdn.mjs +142 -0
  74. package/src/deploy/files.mjs +266 -0
  75. package/src/deploy/fit.mjs +166 -0
  76. package/src/deploy/hosts.mjs +126 -0
  77. package/src/deploy/index/cli.mjs +20 -0
  78. package/src/deploy/index/environment.mjs +69 -0
  79. package/src/deploy/index/steps.mjs +87 -0
  80. package/src/deploy/index.mjs +387 -0
  81. package/src/deploy/needs.mjs +149 -0
  82. package/src/design-checks/accessible-names.mjs +62 -0
  83. package/src/design-checks/contrast.mjs +43 -0
  84. package/src/design-checks/csp.mjs +60 -0
  85. package/src/design-checks/files.mjs +59 -0
  86. package/src/design-checks/heading-links.mjs +61 -0
  87. package/src/design-checks/interaction.mjs +65 -0
  88. package/src/design-checks/jsx.mjs +67 -0
  89. package/src/design-checks/layout-values.mjs +68 -0
  90. package/src/design-checks/native-controls.mjs +48 -0
  91. package/src/design-checks/outline.mjs +39 -0
  92. package/src/design-checks/reporter.mjs +37 -0
  93. package/src/design-checks/rules.mjs +274 -0
  94. package/src/design-checks/values.mjs +262 -0
  95. package/src/design-checks.mjs +10 -400
  96. package/src/diag.mjs +32 -8
  97. package/src/docs.mjs +138 -42
  98. package/src/doctor.mjs +20 -8
  99. package/src/files.mjs +18 -5
  100. package/src/fix.mjs +10 -2
  101. package/src/gate/after.mjs +40 -0
  102. package/src/gate/before.mjs +54 -0
  103. package/src/gate/classify.mjs +72 -0
  104. package/src/gate/mutation.mjs +209 -0
  105. package/src/gate/resolve-cases.mjs +22 -0
  106. package/src/gate/result.mjs +63 -0
  107. package/src/gate/run.mjs +75 -0
  108. package/src/gate.mjs +104 -202
  109. package/src/infer/box-props.cjs +140 -0
  110. package/src/infer/core-boxes.cjs +46 -0
  111. package/src/infer/derived-writes.cjs +95 -0
  112. package/src/infer/engine/checks.cjs +193 -0
  113. package/src/infer/engine/flow.cjs +293 -0
  114. package/src/infer/engine/report.cjs +158 -0
  115. package/src/infer/engine/utils.cjs +15 -0
  116. package/src/infer/engine.cjs +108 -368
  117. package/src/infer/facts/sites.cjs +114 -0
  118. package/src/infer/facts.cjs +210 -117
  119. package/src/infer/hosts.cjs +69 -22
  120. package/src/infer/lsp.mjs +149 -40
  121. package/src/infer/session.cjs +73 -17
  122. package/src/infer/shadow.cjs +13 -5
  123. package/src/infer/worker.cjs +57 -9
  124. package/src/jsx-scan.mjs +63 -21
  125. package/src/load-config/schema.mjs +281 -0
  126. package/src/load-config.mjs +144 -116
  127. package/src/map.mjs +93 -26
  128. package/src/mcp/browser-tools.mjs +155 -0
  129. package/src/mcp.mjs +147 -69
  130. package/src/meta-table.mjs +43 -8
  131. package/src/mutate.mjs +120 -36
  132. package/src/plugin-checks.mjs +52 -23
  133. package/src/plugins.mjs +125 -39
  134. package/src/project.mjs +170 -79
  135. package/src/props-checks.mjs +24 -6
  136. package/src/props-listener.mjs +27 -9
  137. package/src/react-checks.mjs +35 -4
  138. package/src/server-state-checks.mjs +34 -0
  139. package/src/share-checks.mjs +121 -37
  140. package/src/site.mjs +33 -6
  141. package/src/slots.mjs +104 -19
  142. package/src/start/build.mjs +116 -0
  143. package/src/start/routes.mjs +38 -0
  144. package/src/start.mjs +194 -92
  145. package/src/state-checks/core-state.mjs +223 -0
  146. package/src/state-checks/modules.mjs +17 -0
  147. package/src/state-checks/scan.mjs +232 -0
  148. package/src/state-checks/server-graph.mjs +65 -0
  149. package/src/state-checks.mjs +109 -133
  150. package/src/style/find.mjs +121 -0
  151. package/src/style.mjs +133 -127
  152. package/src/surface-checks.mjs +212 -46
  153. package/src/tailwind.mjs +5 -4
  154. package/src/tasks.mjs +189 -27
  155. package/src/test-rules/context.mjs +109 -0
  156. package/src/test-rules/file-rules.mjs +279 -0
  157. package/src/test-rules/rule-helpers.mjs +244 -0
  158. package/src/test-rules/syntax.mjs +223 -0
  159. package/src/test-rules/test-rules.mjs +127 -0
  160. package/src/testdiff.mjs +94 -32
  161. package/src/tests.mjs +31 -483
  162. package/src/text-checks.mjs +229 -69
  163. package/src/tokens.mjs +12 -4
  164. package/src/trust/scan.mjs +95 -0
  165. package/src/trust.mjs +214 -102
  166. package/src/weft.mjs +41 -9
  167. package/src/workspace.mjs +96 -19
  168. package/ts-plugin/context.js +57 -0
  169. package/ts-plugin/index.js +4 -124
  170. package/ts-plugin/mapping.js +65 -0
  171. package/ts-plugin/proxy.js +144 -0
package/src/add-rust.mjs CHANGED
@@ -6,28 +6,39 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
6
6
  import { dirname, join, relative } from 'node:path'
7
7
  import { start } from './start.mjs'
8
8
 
9
- const refused = message => Object.assign(new Error(message), { code: 'E_ADD' })
10
- const usage = message => Object.assign(new Error(message), { code: 'E_USAGE' })
9
+ const refused = (message) => Object.assign(new Error(message), { code: 'E_ADD' })
10
+ const usage = (message) => Object.assign(new Error(message), { code: 'E_USAGE' })
11
11
  const TOOLCHAIN = '1.99.1'
12
12
 
13
- const camel = name => name.replace(/[-_](.)/g, (_, c) => c.toUpperCase())
14
- const pascal = name => { const c = camel(name); return c[0].toUpperCase() + c.slice(1) }
15
- const lib = name => name.replaceAll('-', '_')
13
+ const camel = (name) => name.replace(/[-_](.)/g, (_, c) => c.toUpperCase())
14
+ const pascal = (name) => {
15
+ const c = camel(name)
16
+ return c[0].toUpperCase() + c.slice(1)
17
+ }
18
+ const lib = (name) => name.replaceAll('-', '_')
16
19
 
17
20
  const manifest = (name, crate, remote) => `[package]
18
21
  name = "${name}"
19
22
  version = "0.0.0"
20
23
  edition = "2024"
21
24
  publish = false
22
- ${remote ? '' : `
25
+ ${
26
+ remote
27
+ ? ''
28
+ : `
23
29
  [lib]
24
30
  crate-type = ["cdylib"]
25
- `}
31
+ `
32
+ }
26
33
  [dependencies]
27
34
  serde = { version = "1", features = ["derive"] }
28
35
  serde_json = "1"
29
- ${remote ? `tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
30
- weft = { path = "${crate}" }` : `weft = { path = "${crate}", default-features = false, features = ["native"] }`}
36
+ ${
37
+ remote
38
+ ? `tokio = { version = "1", features = ["macros", "rt-multi-thread"] }
39
+ weft = { path = "${crate}" }`
40
+ : `weft = { path = "${crate}", default-features = false, features = ["native"] }`
41
+ }
31
42
 
32
43
  [build-dependencies]
33
44
  weft = { path = "${crate}", default-features = false, features = ["build"] }
@@ -43,7 +54,10 @@ codegen-units = 1
43
54
  [workspace]
44
55
  `
45
56
 
46
- const body = (name, remote) => `weft::contract!(); // types and a \`Service\` trait, generated from your Zod: never hand-written
57
+ const body = (
58
+ name,
59
+ remote,
60
+ ) => `weft::contract!(); // types and a \`Service\` trait, generated from your Zod: never hand-written
47
61
  use contract::*;
48
62
 
49
63
  struct ${pascal(name)};
@@ -54,14 +68,18 @@ impl Service for ${pascal(name)} {
54
68
  Ok(DigestOutput { bytes: input.text.len() as i64, hash: format!("{hash:08x}") })
55
69
  }
56
70
  }
57
- ${remote ? `
71
+ ${
72
+ remote
73
+ ? `
58
74
  #[tokio::main]
59
75
  async fn main() -> std::io::Result<()> {
60
76
  weft::serve(weft::router(contract::functions(${pascal(name)}))).await
61
77
  }
62
- ` : `
78
+ `
79
+ : `
63
80
  weft::native!(contract::functions(${pascal(name)}));
64
- `}`
81
+ `
82
+ }`
65
83
 
66
84
  const fn = (name, binding) => `import { query } from '@weft-js/start/data'
67
85
  import { z } from 'zod'
@@ -78,33 +96,63 @@ export const digest = query({
78
96
  /** The path Cargo gets. `crate/` is in a packed @weft-js/start; a linked one is in this repository, next to the crates. */
79
97
  async function weftCrate(root, dir) {
80
98
  const { startDir } = await start(root, 'vite')
81
- const found = [join(startDir, '..', 'crate'), join(startDir, '..', '..', '..', 'crates', 'weft')].find(d => existsSync(join(d, 'Cargo.toml')))
99
+ const found = [
100
+ join(startDir, '..', 'crate'),
101
+ join(startDir, '..', '..', '..', 'crates', 'weft'),
102
+ ].find((d) => existsSync(join(d, 'Cargo.toml')))
82
103
  if (!found) throw refused('this @weft-js/start has no `weft` crate in it. Nothing was changed.')
83
104
  return relative(dir, found).replaceAll('\\', '/')
84
105
  }
85
106
 
86
- export async function addRust(root, name = 'media', { remote = false, dryRun = false, install, installSpecs }) {
87
- if (!/^[a-z][a-z0-9_-]*$/.test(name)) throw usage(`\`${name}\` isn't a service name: lower case, then letters, digits, \`-\` or \`_\``)
88
- if (!existsSync(join(root, 'package.json'))) throw refused('`weft add rust` needs a package.json. Nothing was changed.')
107
+ export async function addRust(
108
+ root,
109
+ name = 'media',
110
+ { remote = false, dryRun = false, install, installSpecs },
111
+ ) {
112
+ if (!/^[a-z][a-z0-9_-]*$/.test(name))
113
+ throw usage(
114
+ `\`${name}\` isn't a service name: lower case, then letters, digits, \`-\` or \`_\``,
115
+ )
116
+ if (!existsSync(join(root, 'package.json')))
117
+ throw refused('`weft add rust` needs a package.json. Nothing was changed.')
89
118
  const dir = join(root, 'crates', name)
90
119
  const module = join(root, 'src', 'server', `${name}.ts`)
91
- const taken = [dir, module].filter(existsSync).map(f => relative(root, f))
92
- if (taken.length) throw refused(`${taken.join(', ')} already exist${taken.length > 1 ? '' : 's'}. Pick another name: \`weft add rust <name>\`. Nothing was changed.`)
120
+ const taken = [dir, module].filter(existsSync).map((f) => relative(root, f))
121
+ if (taken.length)
122
+ throw refused(
123
+ `${taken.join(', ')} already exist${taken.length > 1 ? '' : 's'}. Pick another name: \`weft add rust <name>\`. Nothing was changed.`,
124
+ )
93
125
  const binding = camel(name)
94
126
  const factory = remote ? 'remote' : 'native'
95
127
  const call = remote ? `remote('rust://${name}')` : `native('${name}')`
96
128
  const rustFile = join(root, 'src', 'server', 'rust.ts')
97
- const had = existsSync(rustFile) ? readFileSync(rustFile, 'utf8') : '// The only place Rust targets are named.\n'
98
- if (new RegExp(`\\b${binding}\\b`).test(had)) throw refused(`src/server/rust.ts already names \`${binding}\`. Nothing was changed.`)
99
- const imported = new RegExp(`import\\s*\\{[^}]*\\b${factory}\\b[^}]*\\}\\s*from\\s*['"]@weft-js/start/rust['"]`).test(had)
129
+ const had = existsSync(rustFile)
130
+ ? readFileSync(rustFile, 'utf8')
131
+ : '// The only place Rust targets are named.\n'
132
+ if (new RegExp(`\\b${binding}\\b`).test(had))
133
+ throw refused(`src/server/rust.ts already names \`${binding}\`. Nothing was changed.`)
134
+ const imported = new RegExp(
135
+ `import\\s*\\{[^}]*\\b${factory}\\b[^}]*\\}\\s*from\\s*['"]@weft-js/start/rust['"]`,
136
+ ).test(had)
100
137
  const nextRust = `${imported ? had : had.replace(/^((?:\/\/.*\n)*)/, `$1import { ${factory} } from '@weft-js/start/rust'\n`)}${had.endsWith('\n') ? '' : '\n'}\nexport const ${binding} = ${call}\n`
101
138
 
102
139
  const pkg = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8'))
103
140
  const needsZod = !pkg.dependencies?.zod && !pkg.devDependencies?.zod
104
141
  const gitignore = join(root, '.gitignore')
105
- const ignored = existsSync(gitignore) && /^\/?target\/?$|^\*\*\/target\/?$/m.test(readFileSync(gitignore, 'utf8'))
106
- const actions = [`create crates/${name}`, `create src/server/${name}.ts`, `add \`${binding}\` to src/server/rust.ts`, ...(needsZod && install ? ['install zod'] : []), ...(ignored ? [] : ['ignore target/']), 'this crate needs Rust (`cargo`, from rustup.rs); the rest of weft does not', 'next: `weft check`, then `weft dev`']
107
- if (dryRun) return { ok: true, feature: 'rust', service: name, kind: factory, actions, dryRun: true }
142
+ const ignored =
143
+ existsSync(gitignore) &&
144
+ /^\/?target\/?$|^\*\*\/target\/?$/m.test(readFileSync(gitignore, 'utf8'))
145
+ const actions = [
146
+ `create crates/${name}`,
147
+ `create src/server/${name}.ts`,
148
+ `add \`${binding}\` to src/server/rust.ts`,
149
+ ...(needsZod && install ? ['install zod'] : []),
150
+ ...(ignored ? [] : ['ignore target/']),
151
+ 'this crate needs Rust (`cargo`, from rustup.rs); the rest of weft does not',
152
+ 'next: `weft check`, then `weft dev`',
153
+ ]
154
+ if (dryRun)
155
+ return { ok: true, feature: 'rust', service: name, kind: factory, actions, dryRun: true }
108
156
 
109
157
  const crate = await weftCrate(root, dir)
110
158
  const write = (file, text) => {
@@ -113,11 +161,18 @@ export async function addRust(root, name = 'media', { remote = false, dryRun = f
113
161
  }
114
162
  write(join(dir, 'Cargo.toml'), manifest(name, crate, remote))
115
163
  write(join(dir, 'build.rs'), `fn main() {\n weft::build::generate("${name}");\n}\n`)
116
- write(join(dir, 'rust-toolchain.toml'), `[toolchain]\nchannel = "${TOOLCHAIN}"\n${remote ? '' : 'targets = ["wasm32-unknown-unknown"]\n'}`)
164
+ write(
165
+ join(dir, 'rust-toolchain.toml'),
166
+ `[toolchain]\nchannel = "${TOOLCHAIN}"\n${remote ? '' : 'targets = ["wasm32-unknown-unknown"]\n'}`,
167
+ )
117
168
  write(join(dir, 'src', remote ? 'main.rs' : 'lib.rs'), body(lib(name), remote))
118
169
  write(module, fn(name, binding))
119
170
  write(rustFile, nextRust)
120
- if (!ignored) writeFileSync(gitignore, `${existsSync(gitignore) ? readFileSync(gitignore, 'utf8').replace(/\n?$/, '\n') : ''}target/\n`)
171
+ if (!ignored)
172
+ writeFileSync(
173
+ gitignore,
174
+ `${existsSync(gitignore) ? readFileSync(gitignore, 'utf8').replace(/\n?$/, '\n') : ''}target/\n`,
175
+ )
121
176
  if (needsZod && install) installSpecs(['zod'])
122
177
  return { ok: true, feature: 'rust', service: name, kind: factory, actions }
123
178
  }