@waniwani/kit 0.1.6 → 0.1.8
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 +67 -35
- package/dist/cli/codegen.js +1105 -0
- package/dist/cli/codegen.js.map +1 -0
- package/{cli/env.mjs → dist/cli/env.js} +5 -6
- package/dist/cli/env.js.map +1 -0
- package/{cli/framework.mjs → dist/cli/framework.js} +112 -115
- package/dist/cli/framework.js.map +1 -0
- package/dist/cli/index.js +378 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.js +642 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/log.js +156 -0
- package/dist/cli/log.js.map +1 -0
- package/dist/cli/manifest.js +57 -0
- package/dist/cli/manifest.js.map +1 -0
- package/{cli/peers.mjs → dist/cli/peers.js} +77 -88
- package/dist/cli/peers.js.map +1 -0
- package/dist/cli/scan.js +100 -0
- package/dist/cli/scan.js.map +1 -0
- package/dist/cli/template.js +173 -0
- package/dist/cli/template.js.map +1 -0
- package/dist/cli/types.js +14 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli/validate.js +328 -0
- package/dist/cli/validate.js.map +1 -0
- package/dist/cli/vercel.js +103 -0
- package/dist/cli/vercel.js.map +1 -0
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +0 -1
- package/dist/server.js.map +1 -1
- package/dist/web.d.ts +8 -7
- package/dist/web.d.ts.map +1 -1
- package/dist/web.js +7 -6
- package/dist/web.js.map +1 -1
- package/package.json +13 -9
- package/src/server.ts +7 -9
- package/src/web.tsx +12 -13
- package/cli/codegen.mjs +0 -1267
- package/cli/index.mjs +0 -409
- package/cli/init.mjs +0 -575
- package/cli/log.mjs +0 -178
- package/cli/scan.mjs +0 -112
- package/cli/template.mjs +0 -190
- package/cli/validate.mjs +0 -391
package/dist/cli/log.js
ADDED
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/** Build output formatting. Errors point at a file and say how to fix it. */
|
|
2
|
+
/** ESC by char code: a raw control byte in source is invisible and fragile. */
|
|
3
|
+
const ESC = String.fromCharCode(27);
|
|
4
|
+
const useColor = process.stdout.isTTY && !process.env.NO_COLOR;
|
|
5
|
+
const wrap = (code) => (text) => useColor ? `${ESC}[${code}m${text}${ESC}[0m` : text;
|
|
6
|
+
export const red = wrap("31");
|
|
7
|
+
export const green = wrap("32");
|
|
8
|
+
export const yellow = wrap("33");
|
|
9
|
+
export const dim = wrap("2");
|
|
10
|
+
export const bold = wrap("1");
|
|
11
|
+
/**
|
|
12
|
+
* The wordmark, at half the height of the art `waniwani login` prints.
|
|
13
|
+
*
|
|
14
|
+
* Same letterforms: the tall version is six rows of full blocks with a box-glyph
|
|
15
|
+
* drop shadow, and each row here folds two of those together — `▀` where only
|
|
16
|
+
* the upper row had ink, `▄` where only the lower did, `█` where both. Three
|
|
17
|
+
* rows instead of six, at the same width, and nothing about the shapes changes.
|
|
18
|
+
*
|
|
19
|
+
* One colour per row rather than per glyph: a vertical ramp needs three escape
|
|
20
|
+
* sequences instead of two hundred, and reads the same.
|
|
21
|
+
*/
|
|
22
|
+
const LOGO = [
|
|
23
|
+
"██ ██ ▄█▀▀▀█▄ ███▄ ██ ██ ██ ██ ▄█▀▀▀█▄ ███▄ ██ ██",
|
|
24
|
+
"██ ▄█▄ ██ ██▀▀▀██ ██ ▀█▄ ██ ██ ██ ▄█▄ ██ ██▀▀▀██ ██ ▀█▄ ██ ██",
|
|
25
|
+
" ▀▀▀ ▀▀▀ ▀▀ ▀▀ ▀▀ ▀▀▀▀ ▀▀ ▀▀▀ ▀▀▀ ▀▀ ▀▀ ▀▀ ▀▀▀▀ ▀▀",
|
|
26
|
+
];
|
|
27
|
+
const LOGO_WIDTH = 65;
|
|
28
|
+
/** The brand accent, `#04d916`. */
|
|
29
|
+
const ACCENT = [4, 217, 22];
|
|
30
|
+
/** How far the first and last rows are mixed toward white and black. */
|
|
31
|
+
const LIGHTEN = 0.42;
|
|
32
|
+
const DARKEN = 0.35;
|
|
33
|
+
/**
|
|
34
|
+
* The ramp stop for one row: a tint of the accent at the top, the accent itself
|
|
35
|
+
* in the middle, a shade of it at the bottom — so the wordmark reads as one
|
|
36
|
+
* object lit from above.
|
|
37
|
+
*
|
|
38
|
+
* Interpolated from the row count rather than written out, so the art and the
|
|
39
|
+
* ramp cannot drift apart when either changes.
|
|
40
|
+
*/
|
|
41
|
+
function rampStop(index, rows) {
|
|
42
|
+
// -1 on the first row, 0 in the middle, +1 on the last.
|
|
43
|
+
const position = rows === 1 ? 0 : (index / (rows - 1)) * 2 - 1;
|
|
44
|
+
if (position <= 0) {
|
|
45
|
+
const mix = LIGHTEN * -position;
|
|
46
|
+
return ACCENT.map((channel) => Math.round(channel + (255 - channel) * mix));
|
|
47
|
+
}
|
|
48
|
+
return ACCENT.map((channel) => Math.round(channel * (1 - DARKEN * position)));
|
|
49
|
+
}
|
|
50
|
+
/** 24-bit colour is used only where the terminal says it has it. */
|
|
51
|
+
const truecolor = ["truecolor", "24bit"].includes(process.env.COLORTERM ?? "");
|
|
52
|
+
/** The six levels each channel can take in the xterm 256-colour cube. */
|
|
53
|
+
const CUBE_LEVELS = [0, 95, 135, 175, 215, 255];
|
|
54
|
+
/** The nearest cube entry, for a terminal that does not announce 24-bit colour. */
|
|
55
|
+
function cube([r, g, b]) {
|
|
56
|
+
const nearest = (channel) => CUBE_LEVELS.reduce((best, level, index) => Math.abs(level - channel) < Math.abs(CUBE_LEVELS[best] - channel)
|
|
57
|
+
? index
|
|
58
|
+
: best, 0);
|
|
59
|
+
return 16 + 36 * nearest(r) + 6 * nearest(g) + nearest(b);
|
|
60
|
+
}
|
|
61
|
+
/** The foreground escape for one row of the ramp. */
|
|
62
|
+
function ramp(index, rows) {
|
|
63
|
+
const rgb = rampStop(index, rows);
|
|
64
|
+
if (!truecolor) {
|
|
65
|
+
return `${ESC}[38;5;${cube(rgb)}m`;
|
|
66
|
+
}
|
|
67
|
+
return `${ESC}[38;2;${rgb.join(";")}m`;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Print the banner a command opens with.
|
|
71
|
+
*
|
|
72
|
+
* The art needs 65 columns and a terminal that wants colour. A narrower one, a
|
|
73
|
+
* pipe, a CI log or `NO_COLOR` gets the wordmark on one line instead — the same
|
|
74
|
+
* information, and nothing that turns into wrapped garbage in a build log.
|
|
75
|
+
*/
|
|
76
|
+
export function banner(version) {
|
|
77
|
+
// `||`, not `??`: a pty whose window size was never set reports 0 columns,
|
|
78
|
+
// which is unknown rather than narrow.
|
|
79
|
+
const columns = process.stdout.columns || 80;
|
|
80
|
+
if (!useColor || columns < LOGO_WIDTH) {
|
|
81
|
+
// The wordmark still carries the accent — it is the same banner, narrowed.
|
|
82
|
+
const mark = useColor ? `${ramp(0, 1)}${ESC}[1mwaniwani${ESC}[0m` : "waniwani";
|
|
83
|
+
console.log(`\n${mark} ${dim(`v${version}`)}`);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
console.log("");
|
|
87
|
+
for (const [index, line] of LOGO.entries()) {
|
|
88
|
+
console.log(`${ramp(index, LOGO.length)}${line}${ESC}[0m`);
|
|
89
|
+
}
|
|
90
|
+
console.log(dim(`v${version}`.padStart(LOGO_WIDTH)));
|
|
91
|
+
console.log("");
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* One URL a command hands the developer, in the shape every command uses for
|
|
95
|
+
* them. The label is padded so a list of endpoints aligns whether the framework
|
|
96
|
+
* printed the line or this CLI did.
|
|
97
|
+
*/
|
|
98
|
+
export function endpoint(label, url) {
|
|
99
|
+
return ` ${dim(label.padEnd(8))} ${green(url)}`;
|
|
100
|
+
}
|
|
101
|
+
function printGroup(entries, marker, color) {
|
|
102
|
+
const byFile = new Map();
|
|
103
|
+
for (const entry of entries) {
|
|
104
|
+
const list = byFile.get(entry.where) ?? [];
|
|
105
|
+
list.push(entry);
|
|
106
|
+
byFile.set(entry.where, list);
|
|
107
|
+
}
|
|
108
|
+
for (const [where, list] of byFile) {
|
|
109
|
+
console.log(` ${bold(where)}`);
|
|
110
|
+
for (const entry of list) {
|
|
111
|
+
console.log(` ${color(marker)} ${entry.message}`);
|
|
112
|
+
if (entry.hint) {
|
|
113
|
+
console.log(` ${dim(entry.hint)}`);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
console.log("");
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
export function printReport(app, report) {
|
|
120
|
+
if (!report.ok) {
|
|
121
|
+
console.log(`\n${red("✗")} ${bold("Build check failed")}\n`);
|
|
122
|
+
printGroup(report.errors, "└", red);
|
|
123
|
+
if (report.warnings.length > 0) {
|
|
124
|
+
printGroup(report.warnings, "└", yellow);
|
|
125
|
+
}
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const counts = [
|
|
129
|
+
[app.widgets.length, "widget"],
|
|
130
|
+
[app.tools.length, "tool"],
|
|
131
|
+
[app.flows.length, "flow"],
|
|
132
|
+
[app.endpoints.length, "endpoint"],
|
|
133
|
+
]
|
|
134
|
+
.filter(([count]) => count > 0)
|
|
135
|
+
.map(([count, label]) => `${count} ${label}${count === 1 ? "" : "s"}`);
|
|
136
|
+
console.log(`${green("✓")} ${bold("Build check passed")} ${dim(`— ${counts.join(", ")}`)}`);
|
|
137
|
+
for (const widget of app.widgets) {
|
|
138
|
+
console.log(` ${dim("widget")} ${widget.name}`);
|
|
139
|
+
}
|
|
140
|
+
for (const tool of app.tools) {
|
|
141
|
+
console.log(` ${dim("tool ")} ${tool.name}`);
|
|
142
|
+
}
|
|
143
|
+
for (const flow of app.flows) {
|
|
144
|
+
console.log(` ${dim("flow ")} ${flow.name}`);
|
|
145
|
+
}
|
|
146
|
+
// The path, not the filename: what a widget writes into a `fetch()` is the
|
|
147
|
+
// thing worth checking against this line.
|
|
148
|
+
for (const endpoint of app.endpoints) {
|
|
149
|
+
console.log(` ${dim("api ")} ${endpoint.path}`);
|
|
150
|
+
}
|
|
151
|
+
if (report.warnings.length > 0) {
|
|
152
|
+
console.log("");
|
|
153
|
+
printGroup(report.warnings, "└", yellow);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../cli/log.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This package's own `package.json`, read once.
|
|
3
|
+
*
|
|
4
|
+
* Four modules needed it and each computed the path itself, as
|
|
5
|
+
* `join(dirname(fileURLToPath(import.meta.url)), "..")`. That traversal was
|
|
6
|
+
* correct only while the CLI ran from `cli/` next to the manifest, and the
|
|
7
|
+
* compiled output lands in `dist/cli/` one level deeper — so the same four
|
|
8
|
+
* lines would have had to disagree between a source run and an installed one.
|
|
9
|
+
*
|
|
10
|
+
* Walking up for the manifest that names this package answers from either
|
|
11
|
+
* depth, and from anywhere else a bundler or a symlink might put the file. It
|
|
12
|
+
* depends on nothing but the directory tree.
|
|
13
|
+
*
|
|
14
|
+
* Reading this at import time is deliberate: every version the generator forces
|
|
15
|
+
* on an app comes out of here (see `declared()` in `./codegen.ts`), so a
|
|
16
|
+
* manifest that cannot be found should stop the CLI before it writes anything,
|
|
17
|
+
* not halfway through generating a project.
|
|
18
|
+
*/
|
|
19
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
20
|
+
import { dirname, join } from "node:path";
|
|
21
|
+
import { fileURLToPath } from "node:url";
|
|
22
|
+
const PACKAGE_NAME = "@waniwani/kit";
|
|
23
|
+
function findPackageRoot(from) {
|
|
24
|
+
let current = from;
|
|
25
|
+
while (true) {
|
|
26
|
+
const candidate = join(current, "package.json");
|
|
27
|
+
if (existsSync(candidate)) {
|
|
28
|
+
try {
|
|
29
|
+
const parsed = JSON.parse(readFileSync(candidate, "utf-8"));
|
|
30
|
+
if (parsed.name === PACKAGE_NAME)
|
|
31
|
+
return current;
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
// A package.json that does not parse belongs to somebody else's
|
|
35
|
+
// directory on the way up. Keep walking.
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const parent = dirname(current);
|
|
39
|
+
if (parent === current) {
|
|
40
|
+
throw new Error(`cannot find the ${PACKAGE_NAME} package root above ${from} — ` +
|
|
41
|
+
"this CLI reads its own manifest for every version it pins");
|
|
42
|
+
}
|
|
43
|
+
current = parent;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/** The directory holding this package's manifest, `src/` and `dist/`. */
|
|
47
|
+
export const PACKAGE_ROOT = findPackageRoot(dirname(fileURLToPath(import.meta.url)));
|
|
48
|
+
/** This package's manifest, which is where every version the generator pins comes from. */
|
|
49
|
+
export const MANIFEST = JSON.parse(readFileSync(join(PACKAGE_ROOT, "package.json"), "utf-8"));
|
|
50
|
+
export const PACKAGE_VERSION = MANIFEST.version ?? "0.0.0";
|
|
51
|
+
/**
|
|
52
|
+
* The runtime's source, shipped so `waniwani eject` has readable source to
|
|
53
|
+
* vendor. Nothing resolves through it: Node refuses to strip types under
|
|
54
|
+
* `node_modules/`, which is why `dist/` exists.
|
|
55
|
+
*/
|
|
56
|
+
export const RUNTIME_SRC = join(PACKAGE_ROOT, "src");
|
|
57
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../cli/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAGzC,MAAM,YAAY,GAAG,eAAe,CAAC;AAErC,SAAS,eAAe,CAAC,IAAY;IACpC,IAAI,OAAO,GAAG,IAAI,CAAC;IACnB,OAAO,IAAI,EAAE,CAAC;QACb,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,cAAc,CAAC,CAAC;QAChD,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACJ,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAoB,CAAC;gBAC/E,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY;oBAAE,OAAO,OAAO,CAAC;YAClD,CAAC;YAAC,MAAM,CAAC;gBACR,gEAAgE;gBAChE,yCAAyC;YAC1C,CAAC;QACF,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QAChC,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YACxB,MAAM,IAAI,KAAK,CACd,mBAAmB,YAAY,uBAAuB,IAAI,KAAK;gBAC9D,2DAA2D,CAC5D,CAAC;QACH,CAAC;QACD,OAAO,GAAG,MAAM,CAAC;IAClB,CAAC;AACF,CAAC;AAED,yEAAyE;AACzE,MAAM,CAAC,MAAM,YAAY,GAAG,eAAe,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAErF,2FAA2F;AAC3F,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CACjC,YAAY,CAAC,IAAI,CAAC,YAAY,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CACtC,CAAC;AAErB,MAAM,CAAC,MAAM,eAAe,GAAG,QAAQ,CAAC,OAAO,IAAI,OAAO,CAAC;AAE3D;;;;GAIG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,CAAC"}
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
* `@waniwani/sdk`, react, react-dom and zod reach an app as peers rather than
|
|
5
5
|
* as this package's own dependencies, so the app holds one copy and this
|
|
6
6
|
* package states only the floor underneath it. Three callers need that floor
|
|
7
|
-
* and each needs it differently: `init.
|
|
8
|
-
* new app, `validate.
|
|
9
|
-
* `codegen.
|
|
7
|
+
* and each needs it differently: `init.ts` writes an installable range into a
|
|
8
|
+
* new app, `validate.ts` checks the range an existing app already wrote, and
|
|
9
|
+
* `codegen.ts` fills one in when neither the app nor the template declared
|
|
10
10
|
* one. One module so the parsing exists once.
|
|
11
11
|
*
|
|
12
12
|
* Deliberately not a semver dependency. What appears in a real app's manifest
|
|
@@ -14,15 +14,7 @@
|
|
|
14
14
|
* against a floor is the whole job. Anything this cannot parse is reported as
|
|
15
15
|
* unknown rather than guessed at — see `compare`.
|
|
16
16
|
*/
|
|
17
|
-
|
|
18
|
-
import { readFileSync } from "node:fs";
|
|
19
|
-
import { dirname, join } from "node:path";
|
|
20
|
-
import { fileURLToPath } from "node:url";
|
|
21
|
-
|
|
22
|
-
const MANIFEST = JSON.parse(
|
|
23
|
-
readFileSync(join(dirname(fileURLToPath(import.meta.url)), "..", "package.json"), "utf-8"),
|
|
24
|
-
);
|
|
25
|
-
|
|
17
|
+
import { MANIFEST } from "./manifest.js";
|
|
26
18
|
/**
|
|
27
19
|
* A peer range this package declares, read back out so it is stated once.
|
|
28
20
|
*
|
|
@@ -30,16 +22,13 @@ const MANIFEST = JSON.parse(
|
|
|
30
22
|
* pass vacuously, which is worse than the rename that removed it.
|
|
31
23
|
*/
|
|
32
24
|
export function peerRange(name) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
return range;
|
|
25
|
+
const range = MANIFEST.peerDependencies?.[name];
|
|
26
|
+
if (!range) {
|
|
27
|
+
throw new Error(`@waniwani/kit declares no peerDependencies.${name}, and its own tooling reads that floor — ` +
|
|
28
|
+
"add it back to packages/kit/package.json, or drop the entry that reads it");
|
|
29
|
+
}
|
|
30
|
+
return range;
|
|
41
31
|
}
|
|
42
|
-
|
|
43
32
|
/**
|
|
44
33
|
* A peer range turned into something an app can depend on.
|
|
45
34
|
*
|
|
@@ -53,31 +42,32 @@ export function peerRange(name) {
|
|
|
53
42
|
* prerelease reachable and still stops at `0.20.0`.
|
|
54
43
|
*/
|
|
55
44
|
export function installable(name) {
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
45
|
+
const range = peerRange(name);
|
|
46
|
+
const floor = /^>=\s*(\d+)(?:\.(\d+))?(?:\.(\d+))?(-[0-9A-Za-z.-]+)?$/.exec(range.trim());
|
|
47
|
+
return floor ? `^${floor[1]}.${floor[2] ?? 0}.${floor[3] ?? 0}${floor[4] ?? ""}` : range;
|
|
59
48
|
}
|
|
60
|
-
|
|
61
49
|
/** `1.2.3-beta.0` → `{ parts: [1,2,3], prerelease: "beta.0" }` */
|
|
62
50
|
function parseVersion(input) {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
51
|
+
const match = /^(\d+)(?:\.(\d+))?(?:\.(\d+))?(?:-([0-9A-Za-z.-]+))?$/.exec(input.trim());
|
|
52
|
+
if (!match)
|
|
53
|
+
return null;
|
|
54
|
+
return {
|
|
55
|
+
parts: [Number(match[1]), Number(match[2] ?? 0), Number(match[3] ?? 0)],
|
|
56
|
+
prerelease: match[4],
|
|
57
|
+
};
|
|
69
58
|
}
|
|
70
|
-
|
|
71
59
|
/** Ordering on major.minor.patch, with a prerelease sorting below its release. */
|
|
72
60
|
function order(a, b) {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
61
|
+
for (let i = 0; i < 3; i++) {
|
|
62
|
+
if (a.parts[i] !== b.parts[i])
|
|
63
|
+
return a.parts[i] < b.parts[i] ? -1 : 1;
|
|
64
|
+
}
|
|
65
|
+
if (a.prerelease && !b.prerelease)
|
|
66
|
+
return -1;
|
|
67
|
+
if (!a.prerelease && b.prerelease)
|
|
68
|
+
return 1;
|
|
69
|
+
return 0;
|
|
79
70
|
}
|
|
80
|
-
|
|
81
71
|
/**
|
|
82
72
|
* The window a dependency spec opens, as `{ low, high }`, where `high` is
|
|
83
73
|
* exclusive and `null` means unbounded.
|
|
@@ -86,31 +76,28 @@ function order(a, b) {
|
|
|
86
76
|
* `^0.19.5` stops at `0.20.0`, so an SDK minor is a breaking change.
|
|
87
77
|
*/
|
|
88
78
|
function window(spec) {
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
: { parts: [major + 1, 0, 0], prerelease: undefined };
|
|
111
|
-
return { low, high };
|
|
79
|
+
const trimmed = spec.trim();
|
|
80
|
+
if (trimmed === "*" || trimmed === "" || trimmed === "latest") {
|
|
81
|
+
return { low: { parts: [0, 0, 0] }, high: null };
|
|
82
|
+
}
|
|
83
|
+
const ranged = /^(\^|~|>=)\s*(.+)$/.exec(trimmed);
|
|
84
|
+
if (!ranged) {
|
|
85
|
+
const exact = parseVersion(trimmed.replace(/^=\s*/, ""));
|
|
86
|
+
return exact ? { low: exact, high: exact, exact: true } : null;
|
|
87
|
+
}
|
|
88
|
+
const low = parseVersion(ranged[2]);
|
|
89
|
+
if (!low)
|
|
90
|
+
return null;
|
|
91
|
+
if (ranged[1] === ">=")
|
|
92
|
+
return { low, high: null };
|
|
93
|
+
const [major, minor] = low.parts;
|
|
94
|
+
// `~1.2.3` caps at the next minor. `^1.2.3` caps at the next major, except
|
|
95
|
+
// under 0.x where the minor is the compatibility boundary.
|
|
96
|
+
const high = ranged[1] === "~" || major === 0
|
|
97
|
+
? { parts: [major, minor + 1, 0] }
|
|
98
|
+
: { parts: [major + 1, 0, 0] };
|
|
99
|
+
return { low, high };
|
|
112
100
|
}
|
|
113
|
-
|
|
114
101
|
/**
|
|
115
102
|
* How a dependency spec sits against a peer floor.
|
|
116
103
|
*
|
|
@@ -128,43 +115,45 @@ function window(spec) {
|
|
|
128
115
|
* URL, `workspace:*`). Reported as-is rather than assumed to be either.
|
|
129
116
|
*/
|
|
130
117
|
export function compare(spec, name) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
118
|
+
const range = peerRange(name);
|
|
119
|
+
const floorMatch = /^>=\s*(.+)$/.exec(range.trim());
|
|
120
|
+
const floor = parseVersion(floorMatch ? floorMatch[1] : range.replace(/^[\^~=]\s*/, ""));
|
|
121
|
+
const allowed = spec == null ? null : window(spec);
|
|
122
|
+
if (!floor || !allowed)
|
|
123
|
+
return "unknown";
|
|
124
|
+
// A prerelease is opt-in under semver: `0.19.9-beta.0` does not satisfy
|
|
125
|
+
// `>=0.19.8`, because the range names no prerelease at that version. The
|
|
126
|
+
// floor carrying one of its own is someone pinning a prerelease on purpose,
|
|
127
|
+
// and then the plain comparison is what they asked for.
|
|
128
|
+
if (allowed.low.prerelease && !floor.prerelease)
|
|
129
|
+
return "prerelease";
|
|
130
|
+
if (order(allowed.low, floor) >= 0)
|
|
131
|
+
return "ok";
|
|
132
|
+
if (allowed.high === null || order(allowed.high, floor) > 0)
|
|
133
|
+
return "reachable";
|
|
134
|
+
return "below";
|
|
145
135
|
}
|
|
146
|
-
|
|
147
136
|
/** The floor itself, for a message that has to name it. */
|
|
148
137
|
export function floorOf(name) {
|
|
149
|
-
|
|
138
|
+
return peerRange(name);
|
|
150
139
|
}
|
|
151
|
-
|
|
152
140
|
/**
|
|
153
141
|
* The lowest version a spec allows, normalised, or null if unparseable.
|
|
154
142
|
*
|
|
155
|
-
* `scripts/bump-deps.
|
|
143
|
+
* `scripts/bump-deps.ts` asks the question this answers, and it is the mirror
|
|
156
144
|
* of `compare`: that one checks a spec against this package's floor, while a
|
|
157
145
|
* floor bump needs to know whether the *template's* floor has risen above it.
|
|
158
146
|
*/
|
|
159
147
|
export function floorVersion(spec) {
|
|
160
|
-
|
|
161
|
-
|
|
148
|
+
const allowed = spec == null ? null : window(spec);
|
|
149
|
+
return allowed?.low ? allowed.low.parts.join(".") : null;
|
|
162
150
|
}
|
|
163
|
-
|
|
164
151
|
/** Ordering on two version strings, for a caller with no window to compare. */
|
|
165
152
|
export function compareVersions(a, b) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
153
|
+
const left = parseVersion(a);
|
|
154
|
+
const right = parseVersion(b);
|
|
155
|
+
if (!left || !right)
|
|
156
|
+
return null;
|
|
157
|
+
return order(left, right);
|
|
170
158
|
}
|
|
159
|
+
//# sourceMappingURL=peers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peers.js","sourceRoot":"","sources":["../../cli/peers.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/scan.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discover an app by walking its folders. Convention, not configuration.
|
|
3
|
+
*
|
|
4
|
+
* waniwani.config.ts
|
|
5
|
+
* tools/<name>.ts
|
|
6
|
+
* widgets/<name>/{widget.ts,ui.tsx}
|
|
7
|
+
* flows/<name>.ts
|
|
8
|
+
* api/<path>.ts
|
|
9
|
+
*
|
|
10
|
+
* There is no CSS in that list. Styling is Tailwind, from the distribution
|
|
11
|
+
* template's `src/index.css` — its `@theme` tokens and its `dark` variant — and
|
|
12
|
+
* a widget writes utility classes in `ui.tsx`. Stray `styles.css` files are
|
|
13
|
+
* collected only so the build check can tell an author they are dead.
|
|
14
|
+
*/
|
|
15
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
16
|
+
import { basename, extname, join } from "node:path";
|
|
17
|
+
const CODE_EXT = new Set([".ts", ".tsx", ".mts"]);
|
|
18
|
+
function listFiles(dir) {
|
|
19
|
+
if (!existsSync(dir))
|
|
20
|
+
return [];
|
|
21
|
+
return readdirSync(dir)
|
|
22
|
+
.filter((entry) => !entry.startsWith(".") && !entry.startsWith("_"))
|
|
23
|
+
.map((entry) => join(dir, entry))
|
|
24
|
+
.filter((path) => statSync(path).isFile());
|
|
25
|
+
}
|
|
26
|
+
function listDirs(dir) {
|
|
27
|
+
if (!existsSync(dir))
|
|
28
|
+
return [];
|
|
29
|
+
return readdirSync(dir)
|
|
30
|
+
.filter((entry) => !entry.startsWith(".") && !entry.startsWith("_"))
|
|
31
|
+
.map((entry) => join(dir, entry))
|
|
32
|
+
.filter((path) => statSync(path).isDirectory());
|
|
33
|
+
}
|
|
34
|
+
function stripExt(path) {
|
|
35
|
+
return basename(path, extname(path));
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Every code file under `dir`, depth first, as `{ file, segments }` where
|
|
39
|
+
* `segments` is its path below `dir` with the extension gone.
|
|
40
|
+
*
|
|
41
|
+
* `api/` is the one convention folder that nests: an HTTP path has more than
|
|
42
|
+
* one segment, and the only place it can come from without a registry is the
|
|
43
|
+
* filesystem.
|
|
44
|
+
*/
|
|
45
|
+
function listTree(dir, trail = []) {
|
|
46
|
+
if (!existsSync(dir))
|
|
47
|
+
return [];
|
|
48
|
+
return readdirSync(dir)
|
|
49
|
+
.filter((entry) => !entry.startsWith(".") && !entry.startsWith("_"))
|
|
50
|
+
.flatMap((entry) => {
|
|
51
|
+
const path = join(dir, entry);
|
|
52
|
+
if (statSync(path).isDirectory()) {
|
|
53
|
+
return listTree(path, [...trail, entry]);
|
|
54
|
+
}
|
|
55
|
+
if (!CODE_EXT.has(extname(path)))
|
|
56
|
+
return [];
|
|
57
|
+
return [{ file: path, segments: [...trail, stripExt(path)] }];
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* The URL an endpoint file is served at: its position under the app root,
|
|
62
|
+
* `/api` included, since that is the folder's name.
|
|
63
|
+
*
|
|
64
|
+
* `index` names the directory itself, so `api/cal/index.ts` answers `/api/cal`
|
|
65
|
+
* — the one place a filename is not taken verbatim, and the convention every
|
|
66
|
+
* web framework already uses.
|
|
67
|
+
*/
|
|
68
|
+
function endpointPath(segments) {
|
|
69
|
+
const parts = segments.at(-1) === "index" ? segments.slice(0, -1) : segments;
|
|
70
|
+
return `/api/${parts.join("/")}`.replace(/\/$/, "") || "/api";
|
|
71
|
+
}
|
|
72
|
+
export function scanApp(root) {
|
|
73
|
+
const configFile = [join(root, "waniwani.config.ts"), join(root, "waniwani.config.js")].find(existsSync);
|
|
74
|
+
const tools = listFiles(join(root, "tools"))
|
|
75
|
+
.filter((file) => CODE_EXT.has(extname(file)))
|
|
76
|
+
.map((file) => ({ name: stripExt(file), file }));
|
|
77
|
+
const widgets = listDirs(join(root, "widgets")).map((dir) => {
|
|
78
|
+
const name = basename(dir);
|
|
79
|
+
const contract = [join(dir, "widget.ts"), join(dir, "widget.tsx")].find(existsSync);
|
|
80
|
+
const ui = [join(dir, "ui.tsx"), join(dir, "ui.jsx")].find(existsSync);
|
|
81
|
+
return { name, dir, contract, ui };
|
|
82
|
+
});
|
|
83
|
+
const flows = listFiles(join(root, "flows"))
|
|
84
|
+
.filter((file) => CODE_EXT.has(extname(file)))
|
|
85
|
+
.map((file) => ({ name: stripExt(file), file }));
|
|
86
|
+
const endpoints = listTree(join(root, "api")).map(({ file, segments }) => ({
|
|
87
|
+
path: endpointPath(segments),
|
|
88
|
+
segments,
|
|
89
|
+
file,
|
|
90
|
+
}));
|
|
91
|
+
// The two paths an author is most likely to expect the kit to pick up. It
|
|
92
|
+
// imports neither, so a file at either one is styling that never reaches the
|
|
93
|
+
// browser — the kind of silent no-op the build check exists to name.
|
|
94
|
+
const strayStyles = [
|
|
95
|
+
join(root, "styles.css"),
|
|
96
|
+
...widgets.map((widget) => join(widget.dir, "styles.css")),
|
|
97
|
+
].filter(existsSync);
|
|
98
|
+
return { root, configFile, tools, widgets, flows, endpoints, strayStyles };
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=scan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scan.js","sourceRoot":"","sources":["../../cli/scan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGpD,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAElD,SAAS,SAAS,CAAC,GAAW;IAC7B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,WAAW,CAAC,GAAG,CAAC;SACrB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;SACnE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;SAChC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,QAAQ,CAAC,GAAW;IAC5B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAChC,OAAO,WAAW,CAAC,GAAG,CAAC;SACrB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;SACnE,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;SAChC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,SAAS,QAAQ,CAAC,IAAY;IAC7B,OAAO,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;AACtC,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,QAAQ,CAAC,GAAW,EAAE,QAAkB,EAAE;IAClD,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;QAAE,OAAO,EAAE,CAAC;IAEhC,OAAO,WAAW,CAAC,GAAG,CAAC;SACrB,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;SACnE,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;QAClB,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC9B,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YAClC,OAAO,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC;QAC1C,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YAAE,OAAO,EAAE,CAAC;QAC5C,OAAO,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,GAAG,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,YAAY,CAAC,QAAkB;IACvC,MAAM,KAAK,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAC7E,OAAO,QAAQ,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,MAAM,CAAC;AAC/D,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,IAAY;IACnC,MAAM,UAAU,GAAG,CAAC,IAAI,CAAC,IAAI,EAAE,oBAAoB,CAAC,EAAE,IAAI,CAAC,IAAI,EAAE,oBAAoB,CAAC,CAAC,CAAC,IAAI,CAC3F,UAAU,CACV,CAAC;IAEF,MAAM,KAAK,GAAgB,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;SACvD,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;SAC7C,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAElD,MAAM,OAAO,GAAgB,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACxE,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC3B,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACpF,MAAM,EAAE,GAAG,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QACvE,OAAO,EAAE,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,MAAM,KAAK,GAAgB,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;SACvD,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;SAC7C,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;IAElD,MAAM,SAAS,GAAkB,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC,CAAC;QACzF,IAAI,EAAE,YAAY,CAAC,QAAQ,CAAC;QAC5B,QAAQ;QACR,IAAI;KACJ,CAAC,CAAC,CAAC;IAEJ,0EAA0E;IAC1E,6EAA6E;IAC7E,qEAAqE;IACrE,MAAM,WAAW,GAAG;QACnB,IAAI,CAAC,IAAI,EAAE,YAAY,CAAC;QACxB,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;KAC1D,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IAErB,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,CAAC;AAC5E,CAAC"}
|