@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.
- package/README.md +38 -14
- package/bin/weft.mjs +8 -1
- package/docs/async.md +16 -6
- package/docs/browser.md +22 -8
- package/docs/config.md +39 -9
- package/docs/core.md +30 -0
- package/docs/deploy.md +108 -0
- package/docs/design.md +12 -3
- package/docs/entrypoints.md +79 -0
- package/docs/fonts.md +12 -2
- package/docs/icons.md +13 -7
- package/docs/lists.md +3 -1
- package/docs/meta.md +13 -3
- package/docs/plugins.md +32 -9
- package/docs/props.md +13 -2
- package/docs/reactivity.md +26 -0
- package/docs/rules.md +19 -12
- package/docs/rust.md +47 -17
- package/docs/start-short.md +3 -2
- package/docs/start.md +226 -52
- package/docs/state.md +33 -7
- package/docs/style.md +31 -8
- package/docs/surface.md +61 -15
- package/docs/testing.md +15 -5
- package/docs/theme.md +182 -0
- package/docs/ui-state.md +19 -6
- package/docs/verify.md +13 -0
- package/package.json +13 -4
- package/src/add/config.mjs +93 -0
- package/src/add/errors.mjs +2 -0
- package/src/add/setup.mjs +88 -0
- package/src/add-rust.mjs +82 -27
- package/src/add.mjs +209 -181
- package/src/agents-md.mjs +144 -43
- package/src/alias.mjs +16 -5
- package/src/audit/page.mjs +313 -0
- package/src/audit/report.mjs +69 -0
- package/src/audit/utils.mjs +5 -0
- package/src/audit.mjs +174 -188
- package/src/browser/cli.mjs +24 -5
- package/src/browser/client.mjs +189 -25
- package/src/browser/commands.mjs +166 -51
- package/src/catalog/audit.mjs +129 -0
- package/src/catalog/auth.mjs +40 -0
- package/src/catalog/compiler.mjs +337 -0
- package/src/catalog/contracts.mjs +18 -0
- package/src/catalog/database.mjs +52 -0
- package/src/catalog/deploy.mjs +117 -0
- package/src/catalog/design.mjs +159 -0
- package/src/catalog/forms.mjs +25 -0
- package/src/catalog/hydration.mjs +29 -0
- package/src/catalog/icons.mjs +24 -0
- package/src/catalog/media.mjs +163 -0
- package/src/catalog/metadata.mjs +116 -0
- package/src/catalog/plugins.mjs +228 -0
- package/src/catalog/realtime.mjs +195 -0
- package/src/catalog/rust.mjs +75 -0
- package/src/catalog/server-functions.mjs +92 -0
- package/src/catalog/state.mjs +39 -0
- package/src/catalog/style-groups.mjs +54 -0
- package/src/catalog/tests.mjs +127 -0
- package/src/catalog/text.mjs +200 -0
- package/src/catalog/ui-state.mjs +42 -0
- package/src/catalog.mjs +68 -444
- package/src/check/runtime.mjs +280 -0
- package/src/check.mjs +199 -207
- package/src/cli/authoring.mjs +213 -0
- package/src/cli/project.mjs +302 -0
- package/src/cli.mjs +228 -224
- package/src/config.mjs +1 -1
- package/src/contributions.mjs +75 -25
- package/src/db-layer.mjs +13 -5
- package/src/deploy/cdn.mjs +142 -0
- package/src/deploy/files.mjs +266 -0
- package/src/deploy/fit.mjs +166 -0
- package/src/deploy/hosts.mjs +126 -0
- package/src/deploy/index/cli.mjs +20 -0
- package/src/deploy/index/environment.mjs +69 -0
- package/src/deploy/index/steps.mjs +87 -0
- package/src/deploy/index.mjs +387 -0
- package/src/deploy/needs.mjs +149 -0
- package/src/design-checks/accessible-names.mjs +62 -0
- package/src/design-checks/contrast.mjs +43 -0
- package/src/design-checks/csp.mjs +60 -0
- package/src/design-checks/files.mjs +59 -0
- package/src/design-checks/heading-links.mjs +61 -0
- package/src/design-checks/interaction.mjs +65 -0
- package/src/design-checks/jsx.mjs +67 -0
- package/src/design-checks/layout-values.mjs +68 -0
- package/src/design-checks/native-controls.mjs +48 -0
- package/src/design-checks/outline.mjs +39 -0
- package/src/design-checks/reporter.mjs +37 -0
- package/src/design-checks/rules.mjs +274 -0
- package/src/design-checks/values.mjs +262 -0
- package/src/design-checks.mjs +10 -400
- package/src/diag.mjs +32 -8
- package/src/docs.mjs +138 -42
- package/src/doctor.mjs +20 -8
- package/src/files.mjs +18 -5
- package/src/fix.mjs +10 -2
- package/src/gate/after.mjs +40 -0
- package/src/gate/before.mjs +54 -0
- package/src/gate/classify.mjs +72 -0
- package/src/gate/mutation.mjs +209 -0
- package/src/gate/resolve-cases.mjs +22 -0
- package/src/gate/result.mjs +63 -0
- package/src/gate/run.mjs +75 -0
- package/src/gate.mjs +104 -202
- package/src/infer/box-props.cjs +140 -0
- package/src/infer/core-boxes.cjs +46 -0
- package/src/infer/derived-writes.cjs +95 -0
- package/src/infer/engine/checks.cjs +193 -0
- package/src/infer/engine/flow.cjs +293 -0
- package/src/infer/engine/report.cjs +158 -0
- package/src/infer/engine/utils.cjs +15 -0
- package/src/infer/engine.cjs +108 -368
- package/src/infer/facts/sites.cjs +114 -0
- package/src/infer/facts.cjs +210 -117
- package/src/infer/hosts.cjs +69 -22
- package/src/infer/lsp.mjs +149 -40
- package/src/infer/session.cjs +73 -17
- package/src/infer/shadow.cjs +13 -5
- package/src/infer/worker.cjs +57 -9
- package/src/jsx-scan.mjs +63 -21
- package/src/load-config/schema.mjs +281 -0
- package/src/load-config.mjs +144 -116
- package/src/map.mjs +93 -26
- package/src/mcp/browser-tools.mjs +155 -0
- package/src/mcp.mjs +147 -69
- package/src/meta-table.mjs +43 -8
- package/src/mutate.mjs +120 -36
- package/src/plugin-checks.mjs +52 -23
- package/src/plugins.mjs +125 -39
- package/src/project.mjs +170 -79
- package/src/props-checks.mjs +24 -6
- package/src/props-listener.mjs +27 -9
- package/src/react-checks.mjs +35 -4
- package/src/server-state-checks.mjs +34 -0
- package/src/share-checks.mjs +121 -37
- package/src/site.mjs +33 -6
- package/src/slots.mjs +104 -19
- package/src/start/build.mjs +116 -0
- package/src/start/routes.mjs +38 -0
- package/src/start.mjs +194 -92
- package/src/state-checks/core-state.mjs +223 -0
- package/src/state-checks/modules.mjs +17 -0
- package/src/state-checks/scan.mjs +232 -0
- package/src/state-checks/server-graph.mjs +65 -0
- package/src/state-checks.mjs +109 -133
- package/src/style/find.mjs +121 -0
- package/src/style.mjs +133 -127
- package/src/surface-checks.mjs +212 -46
- package/src/tailwind.mjs +5 -4
- package/src/tasks.mjs +189 -27
- package/src/test-rules/context.mjs +109 -0
- package/src/test-rules/file-rules.mjs +279 -0
- package/src/test-rules/rule-helpers.mjs +244 -0
- package/src/test-rules/syntax.mjs +223 -0
- package/src/test-rules/test-rules.mjs +127 -0
- package/src/testdiff.mjs +94 -32
- package/src/tests.mjs +31 -483
- package/src/text-checks.mjs +229 -69
- package/src/tokens.mjs +12 -4
- package/src/trust/scan.mjs +95 -0
- package/src/trust.mjs +214 -102
- package/src/weft.mjs +41 -9
- package/src/workspace.mjs +96 -19
- package/ts-plugin/context.js +57 -0
- package/ts-plugin/index.js +4 -124
- package/ts-plugin/mapping.js +65 -0
- package/ts-plugin/proxy.js +144 -0
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
export async function commandMap({ formatMap, writeMap, args, print, say }) {
|
|
2
|
+
const map = await writeMap(args.root)
|
|
3
|
+
if (args.json) print(map)
|
|
4
|
+
else if (args.stdout) process.stdout.write(formatMap(map))
|
|
5
|
+
else say(`.weft/map.md: ${map.rows.length} rows`)
|
|
6
|
+
return 0
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function commandIcons({
|
|
10
|
+
createRequire,
|
|
11
|
+
join,
|
|
12
|
+
resolve,
|
|
13
|
+
pathToFileURL,
|
|
14
|
+
args,
|
|
15
|
+
print,
|
|
16
|
+
say,
|
|
17
|
+
}) {
|
|
18
|
+
if (args.positional[0] !== 'publish' || !args.positional[1]) {
|
|
19
|
+
say('usage: weft icons publish <dir>')
|
|
20
|
+
return 1
|
|
21
|
+
}
|
|
22
|
+
const { publish } = await import(
|
|
23
|
+
pathToFileURL(
|
|
24
|
+
createRequire(join(args.root, 'package.json')).resolve('@weft-js/warp-icons/compile'),
|
|
25
|
+
).href
|
|
26
|
+
)
|
|
27
|
+
const out = await publish(resolve(args.root, args.positional[1]))
|
|
28
|
+
if (args.json) print(out)
|
|
29
|
+
else
|
|
30
|
+
say(
|
|
31
|
+
`${out.files} files for ${out.icons} icons in ${out.dir}. Nothing was uploaded: host that folder, then set icons({ source }).`,
|
|
32
|
+
)
|
|
33
|
+
return 0
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export async function commandAdd({ addCommand, args, print, say }) {
|
|
37
|
+
const result = await addCommand(args.root, args.positional[0], {
|
|
38
|
+
dryRun: args.flags['dry-run'],
|
|
39
|
+
install: !args.flags['no-install'],
|
|
40
|
+
engine: args.positional[1],
|
|
41
|
+
layer: args.flags.layer,
|
|
42
|
+
remote: args.flags.remote,
|
|
43
|
+
})
|
|
44
|
+
if (args.json) print(result)
|
|
45
|
+
else
|
|
46
|
+
say(
|
|
47
|
+
result.already
|
|
48
|
+
? `${result.package} is already in ${result.config}`
|
|
49
|
+
: result.actions.map((a) => `${args.flags['dry-run'] ? 'would ' : ''}${a}`).join('\n'),
|
|
50
|
+
)
|
|
51
|
+
return 0
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export async function commandPlugins({
|
|
55
|
+
formatHuman,
|
|
56
|
+
explain,
|
|
57
|
+
list,
|
|
58
|
+
sync,
|
|
59
|
+
approveCommand,
|
|
60
|
+
auditCommand,
|
|
61
|
+
formatTrust,
|
|
62
|
+
loadConfig,
|
|
63
|
+
args,
|
|
64
|
+
print,
|
|
65
|
+
say,
|
|
66
|
+
}) {
|
|
67
|
+
const sub = args.positional[0] ?? 'list'
|
|
68
|
+
if (sub === 'list') {
|
|
69
|
+
const result = await list(args.root)
|
|
70
|
+
if (args.json) print(result)
|
|
71
|
+
else
|
|
72
|
+
say(
|
|
73
|
+
result.plugins
|
|
74
|
+
.map(
|
|
75
|
+
(p) =>
|
|
76
|
+
`${p.name}@${p.version ?? '?'} ${p.provides.map((s) => `${s.slot}${s.key ? `[${s.key}]` : ''}${s.bound ? '' : ' (not bound)'}`).join(', ') || 'no slots'}${p.tokens ? ` tokens --${p.tokens}-*` : ''}`,
|
|
77
|
+
)
|
|
78
|
+
.join('\n') || 'no plugins',
|
|
79
|
+
)
|
|
80
|
+
say(formatHuman(result.diagnostics))
|
|
81
|
+
return result.ok ? 0 : 1
|
|
82
|
+
}
|
|
83
|
+
if (sub === 'explain') {
|
|
84
|
+
const result = await explain(args.root, args.positional[1])
|
|
85
|
+
if (args.json) print(result)
|
|
86
|
+
else say(JSON.stringify(result.binding, null, 2))
|
|
87
|
+
return 0
|
|
88
|
+
}
|
|
89
|
+
if (sub === 'sync') {
|
|
90
|
+
const loaded = await loadConfig(args.root)
|
|
91
|
+
const errors = loaded.diagnostics.filter((d) => d.severity === 'error')
|
|
92
|
+
const written = loaded.diagnostics.some((d) => d.code === 'P007') ? [] : sync(args.root, loaded)
|
|
93
|
+
if (args.json) print({ ok: errors.length === 0, written, diagnostics: loaded.diagnostics })
|
|
94
|
+
say(formatHuman(loaded.diagnostics))
|
|
95
|
+
say(`weft plugins sync: ${written.length} files written`)
|
|
96
|
+
return errors.length ? 1 : 0
|
|
97
|
+
}
|
|
98
|
+
if (sub === 'audit') {
|
|
99
|
+
const loaded = await loadConfig(args.root)
|
|
100
|
+
const result = auditCommand(args.root, loaded)
|
|
101
|
+
if (args.json) print(result)
|
|
102
|
+
else say(result.plugins.map(formatTrust).join('\n') || 'no plugins')
|
|
103
|
+
say(formatHuman(result.diagnostics))
|
|
104
|
+
return result.ok ? 0 : 1
|
|
105
|
+
}
|
|
106
|
+
if (sub === 'approve') {
|
|
107
|
+
const result = approveCommand(args.root, await loadConfig(args.root), {
|
|
108
|
+
names: args.positional.slice(1),
|
|
109
|
+
all: !!args.flags.all,
|
|
110
|
+
})
|
|
111
|
+
if (args.json) print(result)
|
|
112
|
+
else
|
|
113
|
+
say(
|
|
114
|
+
[
|
|
115
|
+
...(result.written ? result.approved : result.pending).map(formatTrust),
|
|
116
|
+
result.written
|
|
117
|
+
? `${result.lock}: ${result.approved.length} approved`
|
|
118
|
+
: result.pending.length
|
|
119
|
+
? 'nothing written: name a plugin, or pass --all'
|
|
120
|
+
: 'nothing waiting',
|
|
121
|
+
...(result.written ? result.pending.map((p) => `still waiting: ${p.name}`) : []),
|
|
122
|
+
...(result.gitignore ? ['.gitignore: the lock is no longer ignored, so commit it'] : []),
|
|
123
|
+
].join('\n'),
|
|
124
|
+
)
|
|
125
|
+
return result.ok ? 0 : 1
|
|
126
|
+
}
|
|
127
|
+
throw Object.assign(new Error(`unknown plugins subcommand ${String(sub)}`), {
|
|
128
|
+
code: 'E_USAGE',
|
|
129
|
+
})
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export async function commandFix({ fix, args, print, say }) {
|
|
133
|
+
const result = await fix(args.root, { files: args.positional })
|
|
134
|
+
if (args.json) print(result)
|
|
135
|
+
else
|
|
136
|
+
say(
|
|
137
|
+
result.applied.length
|
|
138
|
+
? result.applied.map((a) => `${a.file}:${a.span[0]}:${a.span[1]} ${a.code}`).join('\n')
|
|
139
|
+
: 'nothing to fix',
|
|
140
|
+
)
|
|
141
|
+
return 0
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export async function commandTokens({ writeTokens, args, print, say }) {
|
|
145
|
+
const result = await writeTokens(args.root)
|
|
146
|
+
if (args.json) print(result)
|
|
147
|
+
else say(`${result.dir}: ${result.files.length} files`)
|
|
148
|
+
return 0
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export async function commandStyle({
|
|
152
|
+
explainTarget,
|
|
153
|
+
findGroups,
|
|
154
|
+
formatExplain,
|
|
155
|
+
formatFind,
|
|
156
|
+
styleMatrix,
|
|
157
|
+
writeMatrixFile,
|
|
158
|
+
args,
|
|
159
|
+
print,
|
|
160
|
+
say,
|
|
161
|
+
}) {
|
|
162
|
+
const sub = args.positional[0]
|
|
163
|
+
if (sub === 'find') {
|
|
164
|
+
const result = findGroups(
|
|
165
|
+
(await styleMatrix(args.root)).matrix,
|
|
166
|
+
args.positional.slice(1).join(' '),
|
|
167
|
+
)
|
|
168
|
+
if (args.json) print(result)
|
|
169
|
+
else say(formatFind(result))
|
|
170
|
+
return 0
|
|
171
|
+
}
|
|
172
|
+
if (sub === 'explain') {
|
|
173
|
+
const accent = args.flags.accent
|
|
174
|
+
? Object.fromEntries(
|
|
175
|
+
args.flags.accent
|
|
176
|
+
.split(/[\s,]+/)
|
|
177
|
+
.filter(Boolean)
|
|
178
|
+
.map((w) => w.split(':')),
|
|
179
|
+
)
|
|
180
|
+
: undefined
|
|
181
|
+
const states = args.flags.states
|
|
182
|
+
?.split(',')
|
|
183
|
+
.map((s) => s.trim())
|
|
184
|
+
.filter(Boolean)
|
|
185
|
+
const result = explainTarget(await styleMatrix(args.root), args.positional.slice(1).join(' '), {
|
|
186
|
+
axes: args.flags.axes,
|
|
187
|
+
states,
|
|
188
|
+
accent,
|
|
189
|
+
part: args.flags.part,
|
|
190
|
+
})
|
|
191
|
+
if (args.json) print(result)
|
|
192
|
+
else say(formatExplain(result))
|
|
193
|
+
return 0
|
|
194
|
+
}
|
|
195
|
+
if (sub === 'matrix') {
|
|
196
|
+
const { matrix } = await styleMatrix(args.root)
|
|
197
|
+
const written = args.stdout ? false : writeMatrixFile(args.root, matrix)
|
|
198
|
+
if (args.stdout || args.json) print(matrix)
|
|
199
|
+
say(
|
|
200
|
+
`.weft/styles.json: ${Object.keys(matrix.groups).length} groups, ${matrix.diagnostics.length} diagnostics, ${args.stdout ? 'not written' : written ? 'written' : 'current'}`,
|
|
201
|
+
)
|
|
202
|
+
return 0
|
|
203
|
+
}
|
|
204
|
+
throw Object.assign(
|
|
205
|
+
new Error(`weft style ${sub ?? ''}: use find <query>, explain <group|selector> or matrix`),
|
|
206
|
+
{ code: 'E_USAGE' },
|
|
207
|
+
)
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export async function commandMcp({ serve, args }) {
|
|
211
|
+
await serve(args.root)
|
|
212
|
+
return 0
|
|
213
|
+
}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
export async function commandLsp({ args }) {
|
|
2
|
+
const { lsp } = await import('../infer/lsp.mjs')
|
|
3
|
+
const out = lsp(args.root)
|
|
4
|
+
return await new Promise((ok) => {
|
|
5
|
+
out.server.on('exit', () => ok(0))
|
|
6
|
+
})
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export async function commandTsc({ formatHuman, sortDiagnostics, args, print, say }) {
|
|
10
|
+
const { propTsc } = await import('../props-checks.mjs')
|
|
11
|
+
const diagnostics = sortDiagnostics(await propTsc(args.root))
|
|
12
|
+
if (args.json) print({ ok: !diagnostics.some((d) => d.severity === 'error'), diagnostics })
|
|
13
|
+
say(formatHuman(diagnostics))
|
|
14
|
+
say(`weft tsc: ${diagnostics.filter((d) => d.severity === 'error').length} errors`)
|
|
15
|
+
return diagnostics.some((d) => d.severity === 'error') ? 1 : 0
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export async function commandCheck({ check, formatHuman, compilerLine, doctor, args, print, say }) {
|
|
19
|
+
const result = await check(args.root, { files: args.positional, preset: args.flags.preset })
|
|
20
|
+
if (args.json) print(result)
|
|
21
|
+
say(formatHuman(result.diagnostics))
|
|
22
|
+
if (args.flags.verbose) say(compilerLine(doctor(args.root).compiler))
|
|
23
|
+
say(
|
|
24
|
+
`weft check: ${result.summary.files} files, ${result.summary.errors} errors, ${result.summary.warnings} warnings (${result.ms} ms)`,
|
|
25
|
+
)
|
|
26
|
+
return result.ok ? 0 : 1
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function commandDoctor({
|
|
30
|
+
existsSync,
|
|
31
|
+
join,
|
|
32
|
+
formatHuman,
|
|
33
|
+
doctor,
|
|
34
|
+
formatDoctor,
|
|
35
|
+
loadConfig,
|
|
36
|
+
doctorCommand,
|
|
37
|
+
formatHosts,
|
|
38
|
+
hostsCommand,
|
|
39
|
+
args,
|
|
40
|
+
print,
|
|
41
|
+
say,
|
|
42
|
+
}) {
|
|
43
|
+
// What this install compiles with, always; what live data does on the target, for an app that has any.
|
|
44
|
+
const result = doctor(args.root)
|
|
45
|
+
const plan =
|
|
46
|
+
args.flags.preset || existsSync(join(args.root, 'src/realtime.server.ts'))
|
|
47
|
+
? await doctorCommand(args.root, {
|
|
48
|
+
preset: args.flags.preset,
|
|
49
|
+
runtime: args.flags.runtime,
|
|
50
|
+
})
|
|
51
|
+
: undefined
|
|
52
|
+
const hosts = hostsCommand(args.root, (await loadConfig(args.root)).config)
|
|
53
|
+
if (args.json) print({ ...result, live: plan, deploy: hosts })
|
|
54
|
+
else
|
|
55
|
+
say(
|
|
56
|
+
`${formatDoctor(result)}\n\nweft doctor: deploy${hosts.target ? ` (target ${hosts.target})` : ''}\n${formatHosts(hosts).replace(/^/gm, ' ')}`,
|
|
57
|
+
)
|
|
58
|
+
if (!plan) return 0
|
|
59
|
+
say(
|
|
60
|
+
`weft doctor: ${plan.preset} (${plan.host})\n live mode: ${plan.mode}\n ${plan.says}${plan.required.length ? `\n required: ${plan.required.join(', ')}` : ''}${plan.options.length ? `\n options:\n${plan.options.map((o) => ` - ${o}`).join('\n')}` : ''}`,
|
|
61
|
+
)
|
|
62
|
+
say(formatHuman(plan.diagnostics))
|
|
63
|
+
return plan.diagnostics.some((d) => d.severity === 'error') ? 1 : 0
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export async function commandTest({ formatHuman, formatGate, gate, args, print, say }) {
|
|
67
|
+
if (!args.flags.gate)
|
|
68
|
+
throw Object.assign(
|
|
69
|
+
new Error('`weft test` runs the gate with --gate; run the suite itself with vitest'),
|
|
70
|
+
{ code: 'E_USAGE' },
|
|
71
|
+
)
|
|
72
|
+
const num = (name) => (args.flags[name] === undefined ? undefined : Number(args.flags[name]))
|
|
73
|
+
const result = await gate(args.root, {
|
|
74
|
+
base: args.flags.base,
|
|
75
|
+
budgetSec: num('budget'),
|
|
76
|
+
maxMutants: num('max-mutants'),
|
|
77
|
+
concurrency: num('concurrency'),
|
|
78
|
+
refactor: !!args.flags.refactor,
|
|
79
|
+
mutation: !args.flags['no-mutation'],
|
|
80
|
+
log: (line) => say(line),
|
|
81
|
+
})
|
|
82
|
+
if (args.json) print(result)
|
|
83
|
+
say(formatHuman(result.diagnostics))
|
|
84
|
+
say(formatGate(result))
|
|
85
|
+
say(
|
|
86
|
+
`weft test --gate: ${result.ok ? 'pass' : 'fail'}, ${result.summary.changedTests} changed tests, ${result.summary.errors} errors, ${result.summary.warnings} warnings (${result.ms} ms)`,
|
|
87
|
+
)
|
|
88
|
+
return result.ok ? 0 : 1
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export async function commandBrowser({ browserCommand, args, print, say, io }) {
|
|
92
|
+
return await browserCommand(args, { print, say, io })
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export async function commandDev({ devCommand, args, say }) {
|
|
96
|
+
const server = await devCommand(args.root, {
|
|
97
|
+
port: args.flags.port && Number(args.flags.port),
|
|
98
|
+
})
|
|
99
|
+
say(`weft dev: ${server.resolvedUrls.local[0]}`)
|
|
100
|
+
await new Promise((ok) => {
|
|
101
|
+
process.once('SIGINT', ok)
|
|
102
|
+
})
|
|
103
|
+
await server.close()
|
|
104
|
+
return 0
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export async function commandBuild({ formatHuman, buildCommand, args, print, say }) {
|
|
108
|
+
const result = await buildCommand(args.root, {
|
|
109
|
+
preset: args.flags.preset,
|
|
110
|
+
runtime: args.flags.runtime,
|
|
111
|
+
unsafeAllow: args.flags['unsafe-allow'],
|
|
112
|
+
})
|
|
113
|
+
if (args.json) print(result)
|
|
114
|
+
say(formatHuman(result.diagnostics))
|
|
115
|
+
say(
|
|
116
|
+
`weft build: ${result.preset} → ${result.output}, ${result.functions} functions in the contract, ${result.audited} pages audited (${result.ms} ms)`,
|
|
117
|
+
)
|
|
118
|
+
for (const note of result.notes ?? []) say(note)
|
|
119
|
+
if (!result.ok)
|
|
120
|
+
say(
|
|
121
|
+
'weft build: failed. The output is written, but fix the errors above before it ships, or `--unsafe-allow <code>` to force it.',
|
|
122
|
+
)
|
|
123
|
+
return result.ok ? 0 : 1
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export async function commandAudit({ formatHuman, audit, args, print, say }) {
|
|
127
|
+
const result = await audit(args.root, {
|
|
128
|
+
url: args.flags.url,
|
|
129
|
+
indexing: args.flags.indexing,
|
|
130
|
+
routes: args.positional.length ? args.positional : undefined,
|
|
131
|
+
all: !!args.flags.all,
|
|
132
|
+
max: args.flags.max && Number(args.flags.max),
|
|
133
|
+
})
|
|
134
|
+
if (args.json) print(result)
|
|
135
|
+
say(formatHuman(result.diagnostics))
|
|
136
|
+
say(
|
|
137
|
+
`weft audit: ${result.skipped ?? `${result.pages.length} pages at a phone's and a desktop's width, ${result.diagnostics.length} findings (${result.ms} ms)`}`,
|
|
138
|
+
)
|
|
139
|
+
return result.ok ? 0 : 1
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export async function commandDeploy({
|
|
143
|
+
formatHuman,
|
|
144
|
+
loadConfig,
|
|
145
|
+
buildCommand,
|
|
146
|
+
unsafeAllowed,
|
|
147
|
+
deployCommand,
|
|
148
|
+
formatHosts,
|
|
149
|
+
hostsCommand,
|
|
150
|
+
initCommand,
|
|
151
|
+
args,
|
|
152
|
+
print,
|
|
153
|
+
say,
|
|
154
|
+
}) {
|
|
155
|
+
const loaded = await loadConfig(args.root)
|
|
156
|
+
const sub = args.positional[0]
|
|
157
|
+
if (sub === 'hosts') {
|
|
158
|
+
const result = hostsCommand(args.root, loaded.config)
|
|
159
|
+
if (args.json) print(result)
|
|
160
|
+
else say(formatHosts(result))
|
|
161
|
+
return 0
|
|
162
|
+
}
|
|
163
|
+
const unsafe = unsafeAllowed(args.flags['unsafe-allow'], loaded.config)
|
|
164
|
+
if (sub === 'init') {
|
|
165
|
+
const result = initCommand(args.root, loaded.config, {
|
|
166
|
+
target: args.positional[1] ?? args.flags.target,
|
|
167
|
+
dryRun: !!args.flags['dry-run'],
|
|
168
|
+
force: !!args.flags.force,
|
|
169
|
+
unsafe,
|
|
170
|
+
})
|
|
171
|
+
if (args.json) print(result)
|
|
172
|
+
say(formatHuman(result.findings))
|
|
173
|
+
say(
|
|
174
|
+
[
|
|
175
|
+
`weft deploy init ${result.target}${result.dryRun ? ' (dry run: nothing written)' : ''}:`,
|
|
176
|
+
...result.actions.map((a) => ` ${a}`),
|
|
177
|
+
'',
|
|
178
|
+
'then, once:',
|
|
179
|
+
...result.next.map((n) => ` ${n}`),
|
|
180
|
+
].join('\n'),
|
|
181
|
+
)
|
|
182
|
+
return 0
|
|
183
|
+
}
|
|
184
|
+
if (sub !== undefined)
|
|
185
|
+
throw Object.assign(
|
|
186
|
+
new Error(
|
|
187
|
+
`weft deploy ${String(sub)}: use \`weft deploy\`, \`weft deploy hosts\` or \`weft deploy init [target]\``,
|
|
188
|
+
),
|
|
189
|
+
{ code: 'E_USAGE' },
|
|
190
|
+
)
|
|
191
|
+
const result = await deployCommand(args.root, loaded.config, {
|
|
192
|
+
target: args.flags.target,
|
|
193
|
+
prod: !!args.flags.prod,
|
|
194
|
+
yes: !!args.flags.yes,
|
|
195
|
+
unsafe,
|
|
196
|
+
build: (root, o) => buildCommand(root, { ...o, unsafeAllow: args.flags['unsafe-allow'] }),
|
|
197
|
+
})
|
|
198
|
+
if (args.json) print(result)
|
|
199
|
+
say(formatHuman(result.diagnostics))
|
|
200
|
+
if (result.dryRun)
|
|
201
|
+
say(
|
|
202
|
+
[
|
|
203
|
+
`weft deploy: a dry run for ${result.target}${result.prod ? ' (production)' : ' (a preview)'}. With --yes it runs:`,
|
|
204
|
+
...result.steps.map(
|
|
205
|
+
(s) =>
|
|
206
|
+
` ${s.what}${s.reads.length ? `\n reads ${s.reads.join(', ')} from the environment` : ''}`,
|
|
207
|
+
),
|
|
208
|
+
].join('\n'),
|
|
209
|
+
)
|
|
210
|
+
else
|
|
211
|
+
say(
|
|
212
|
+
`weft deploy: ${result.target}${result.prod ? ' (production)' : ''} → ${result.url ?? 'deployed; the host printed no URL'}`,
|
|
213
|
+
)
|
|
214
|
+
return 0
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
export async function commandStart({ startCommand, args }) {
|
|
218
|
+
return await startCommand(args.root, { runtime: args.flags.runtime })
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export async function commandDb({ dbCommand, args, print, say }) {
|
|
222
|
+
const result = await dbCommand(args.root, args.positional[0], args.positional[1])
|
|
223
|
+
if (args.json) print(result)
|
|
224
|
+
say(result.output)
|
|
225
|
+
return 0
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export async function commandRoutes({ formatHuman, metaTable, routesCommand, args, print, say }) {
|
|
229
|
+
const result = await routesCommand(args.root, {
|
|
230
|
+
meta: !!args.flags.meta,
|
|
231
|
+
preset: args.flags.preset,
|
|
232
|
+
})
|
|
233
|
+
if (args.json) print(result)
|
|
234
|
+
else
|
|
235
|
+
say(
|
|
236
|
+
args.flags.meta
|
|
237
|
+
? metaTable(result)
|
|
238
|
+
: result.routes.map((r) => `${r.path.padEnd(24)} ${r.file}`).join('\n'),
|
|
239
|
+
)
|
|
240
|
+
say(formatHuman(result.diagnostics))
|
|
241
|
+
return result.ok ? 0 : 1
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function commandSurfaces({ listSurfaces, args, print, say }) {
|
|
245
|
+
const surfaces = listSurfaces(args.root)
|
|
246
|
+
if (args.json) print({ surfaces })
|
|
247
|
+
else
|
|
248
|
+
say(
|
|
249
|
+
surfaces.length
|
|
250
|
+
? surfaces
|
|
251
|
+
.map(
|
|
252
|
+
(x) =>
|
|
253
|
+
`${String(x.name).padEnd(20)} ${String(x.kind).padEnd(10)} ${x.file}:${x.line} props: ${x.props.join(', ') || '(none)'}`,
|
|
254
|
+
)
|
|
255
|
+
.join('\n')
|
|
256
|
+
: 'No surfaces yet: `weft docs surface`.',
|
|
257
|
+
)
|
|
258
|
+
return 0
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export async function commandTasks({ formatHuman, tasks, args, print, say }) {
|
|
262
|
+
const result = await tasks(args.root)
|
|
263
|
+
if (args.json) print(result)
|
|
264
|
+
else
|
|
265
|
+
say(
|
|
266
|
+
result.tasks
|
|
267
|
+
.map((t) => `${t.available ? ' ' : '·'} ${t.name.padEnd(10)} ${t.description ?? ''}`)
|
|
268
|
+
.join('\n'),
|
|
269
|
+
)
|
|
270
|
+
say(formatHuman(result.diagnostics))
|
|
271
|
+
return result.ok ? 0 : 1
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export async function commandRun({ runTask, args }) {
|
|
275
|
+
if (!args.positional[0]) throw Object.assign(new Error('weft run <task>'), { code: 'E_USAGE' })
|
|
276
|
+
return await runTask(args.root, args.positional[0])
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export async function commandDocs({ docs, args, print, io }) {
|
|
280
|
+
const page = await docs(args.root, args.positional[0])
|
|
281
|
+
if (args.json) print(page)
|
|
282
|
+
else io.stdout.write(`${page.text}\n`)
|
|
283
|
+
return 0
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
export async function commandAgentsMd({ writeAgentsMd, args, print, say, io }) {
|
|
287
|
+
const out = await writeAgentsMd(args.root, { check: args.check || args.stdout })
|
|
288
|
+
if (args.stdout) io.stdout.write(out.text)
|
|
289
|
+
if (args.json)
|
|
290
|
+
print({
|
|
291
|
+
path: out.path,
|
|
292
|
+
bytes: out.bytes,
|
|
293
|
+
limit: 9216,
|
|
294
|
+
overLimit: out.overLimit,
|
|
295
|
+
current: out.current,
|
|
296
|
+
written: out.written,
|
|
297
|
+
})
|
|
298
|
+
say(
|
|
299
|
+
`AGENTS.md: ${out.bytes} bytes${out.overLimit ? ' (over the 9 KB limit)' : ''}, ${out.written ? 'written' : out.current ? 'current' : 'stale'}`,
|
|
300
|
+
)
|
|
301
|
+
return (args.check && !out.current) || out.overLimit ? 1 : 0
|
|
302
|
+
}
|