@miyaoka/fsss 0.3.0 → 0.3.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/dist/cli.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAkBA,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,GAAG;IACX,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAgFD,iBAAS,SAAS,CAAC,OAAO,EAAE,UAAU,GAAG,GAAG,CAoJ3C;AAED,OAAO,EAAE,SAAS,EAAE,CAAC;AACrB,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC"}
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAkBA,UAAU,aAAa;IACrB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,aAAa,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,UAAU,GAAG;IACX,GAAG,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC1B;AAgFD,iBAAS,SAAS,CAAC,OAAO,EAAE,UAAU,GAAG,GAAG,CAgJ3C;AAED,OAAO,EAAE,SAAS,EAAE,CAAC;AACrB,YAAY,EAAE,GAAG,EAAE,UAAU,EAAE,CAAC"}
package/dist/codegen.js CHANGED
@@ -1,18 +1,19 @@
1
1
  #!/usr/bin/env node
2
- import { join, relative } from "node:path";
3
- import { mkdir, readFile, readdir, writeFile } from "node:fs/promises";
4
- import { parseArgs } from "node:util";
5
- var PLUGINS_DIR_NAME = "_plugins", PLUGIN_FILE_EXTENSION = ".ts", INTERFACE_NAME_PATTERN = /export\s+interface\s+(\w+)/g;
6
- async function findAllPluginFiles(t) {
2
+ import { join as e, relative as t } from "node:path";
3
+ import { mkdir as n, readFile as r, readdir as i, writeFile as a } from "node:fs/promises";
4
+ import { parseArgs as o } from "node:util";
5
+ //#region src/codegen.ts
6
+ var s = "_plugins", c = ".ts", l = /export\s+interface\s+(\w+)/g;
7
+ async function u(t) {
7
8
  let n = [];
8
9
  async function r(t) {
9
- let a = await readdir(t, { withFileTypes: !0 });
10
+ let a = await i(t, { withFileTypes: !0 });
10
11
  for (let o of a) {
11
12
  if (!o.isDirectory()) continue;
12
- let a = join(t, o.name);
13
- if (o.name === PLUGINS_DIR_NAME) {
14
- let t = await readdir(a, { withFileTypes: !0 });
15
- for (let r of t) r.isFile() && r.name.endsWith(PLUGIN_FILE_EXTENSION) && n.push(join(a, r.name));
13
+ let a = e(t, o.name);
14
+ if (o.name === s) {
15
+ let t = await i(a, { withFileTypes: !0 });
16
+ for (let r of t) r.isFile() && r.name.endsWith(c) && n.push(e(a, r.name));
16
17
  continue;
17
18
  }
18
19
  await r(a);
@@ -20,17 +21,17 @@ async function findAllPluginFiles(t) {
20
21
  }
21
22
  return await r(t), n.sort();
22
23
  }
23
- async function extractInterfaceNames(e) {
24
- let t = await readFile(e, "utf-8"), n = [], i = INTERFACE_NAME_PATTERN.exec(t);
25
- for (; i !== null;) n.push(i[1]), i = INTERFACE_NAME_PATTERN.exec(t);
24
+ async function d(e) {
25
+ let t = await r(e, "utf-8"), n = [], i = l.exec(t);
26
+ for (; i !== null;) n.push(i[1]), i = l.exec(t);
26
27
  return n;
27
28
  }
28
- async function generateExtensionsType(r, i) {
29
- let o = await findAllPluginFiles(r), s = [];
29
+ async function f(r, i) {
30
+ let o = await u(r), s = [];
30
31
  for (let e of o) {
31
- let n = await extractInterfaceNames(e);
32
+ let n = await d(e);
32
33
  if (n.length === 0) continue;
33
- let r = relative(i, e).replace(/\.ts$/, ""), a = r.startsWith(".") ? r : `./${r}`;
34
+ let r = t(i, e).replace(/\.ts$/, ""), a = r.startsWith(".") ? r : `./${r}`;
34
35
  s.push({
35
36
  importPath: a,
36
37
  interfaceNames: n
@@ -46,12 +47,13 @@ async function generateExtensionsType(r, i) {
46
47
  let e = s.flatMap((e) => e.interfaceNames);
47
48
  c.push("", "declare module \"@miyaoka/fsss\" {", ` interface Extensions extends ${e.join(", ")} {}`, "}", "");
48
49
  }
49
- await mkdir(i, { recursive: !0 });
50
- let l = join(i, "extensions.d.ts");
51
- await writeFile(l, c.join("\n"), "utf-8"), console.log(`Generated ${l}`);
50
+ await n(i, { recursive: !0 });
51
+ let l = e(i, "extensions.d.ts");
52
+ await a(l, c.join("\n"), "utf-8"), console.log(`Generated ${l}`);
52
53
  }
53
- var { values } = parseArgs({ options: {
54
+ var { values: p } = o({ options: {
54
55
  commandsDir: { type: "string" },
55
56
  outDir: { type: "string" }
56
57
  } });
57
- (values.commandsDir === void 0 || values.outDir === void 0) && (console.error("Usage: bun run codegen.ts --commandsDir <path> --outDir <path>"), process.exit(1)), await generateExtensionsType(values.commandsDir, values.outDir);
58
+ (p.commandsDir === void 0 || p.outDir === void 0) && (console.error("Usage: bun run codegen.ts --commandsDir <path> --outDir <path>"), process.exit(1)), await f(p.commandsDir, p.outDir);
59
+ //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAU,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGhD,UAAU,UAAU;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAkED,iBAAS,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA8DhD;AAGD,UAAU,oBAAoB;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,gBAAgB,EAAE,cAAc,EAAE,CAAC;CACpC;AAED,iBAAS,sBAAsB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAuBpE;AAID,iBAAS,2BAA2B,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAG/E;AAID,UAAU,wBAAwB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,cAAc,EAAE,CAAC;CACpC;AAED,iBAAS,0BAA0B,CAAC,MAAM,EAAE,wBAAwB,GAAG,MAAM,CAiE5E;AAED,OAAO,EACL,0BAA0B,EAC1B,YAAY,EACZ,sBAAsB,EACtB,2BAA2B,GAC5B,CAAC;AACF,YAAY,EAAE,wBAAwB,EAAE,UAAU,EAAE,oBAAoB,EAAE,CAAC"}
1
+ {"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../src/help.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAC/C,OAAO,KAAK,EAAU,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGhD,UAAU,UAAU;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAgFD,iBAAS,YAAY,CAAC,MAAM,EAAE,UAAU,GAAG,MAAM,CA8DhD;AAGD,UAAU,oBAAoB;IAC5B,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,gBAAgB,EAAE,cAAc,EAAE,CAAC;CACpC;AAED,iBAAS,sBAAsB,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,CAuBpE;AAID,iBAAS,2BAA2B,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAG/E;AAID,UAAU,wBAAwB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,QAAQ,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,cAAc,EAAE,CAAC;CACpC;AAED,iBAAS,0BAA0B,CAAC,MAAM,EAAE,wBAAwB,GAAG,MAAM,CAiE5E;AAED,OAAO,EACL,0BAA0B,EAC1B,YAAY,EACZ,sBAAsB,EACtB,2BAA2B,GAC5B,CAAC;AACF,YAAY,EAAE,wBAAwB,EAAE,UAAU,EAAE,oBAAoB,EAAE,CAAC"}
package/dist/index.js CHANGED
@@ -1,95 +1,111 @@
1
- import { join, relative, resolve } from "node:path";
2
- import { ZodBoolean, ZodError, ZodNumber, z } from "zod";
3
- import { readFile, readdir, stat } from "node:fs/promises";
4
- import { homedir } from "node:os";
5
- function isRecord(e) {
1
+ import { join as e, relative as t, resolve as n } from "node:path";
2
+ import { ZodBoolean as r, ZodError as i, ZodNumber as a, z as o } from "zod";
3
+ import { readFile as s, readdir as c, stat as l } from "node:fs/promises";
4
+ import { homedir as u } from "node:os";
5
+ //#region src/config.ts
6
+ function d(e) {
6
7
  return typeof e == "object" && !!e;
7
8
  }
8
- function getByDotPath(e, t) {
9
+ function f(e, t) {
9
10
  let n = t.split("."), r = e;
10
11
  for (let e of n) {
11
- if (!isRecord(r)) return;
12
+ if (!d(r)) return;
12
13
  r = r[e];
13
14
  }
14
15
  return r;
15
16
  }
16
- async function loadConfig(e) {
17
+ async function p(e) {
17
18
  try {
18
- let t = await readFile(e, "utf-8");
19
+ let t = await s(e, "utf-8");
19
20
  return JSON.parse(t);
20
21
  } catch {
21
22
  return;
22
23
  }
23
24
  }
24
- function deepMerge(e, t) {
25
+ function m(e, t) {
25
26
  let n = { ...e };
26
27
  for (let [e, r] of Object.entries(t)) {
27
28
  let t = n[e];
28
- if (isRecord(t) && isRecord(r)) {
29
- n[e] = deepMerge(t, r);
29
+ if (d(t) && d(r)) {
30
+ n[e] = m(t, r);
30
31
  continue;
31
32
  }
32
33
  n[e] = r;
33
34
  }
34
35
  return n;
35
36
  }
36
- function resolveConfigPaths(t, n) {
37
+ function h(t, n) {
37
38
  let r = [];
38
- return r.push(join(homedir(), ".config", t, "config.json")), r.push(join(process.cwd(), `${t}.config.json`)), n !== void 0 && r.push(n), r;
39
+ return r.push(e(u(), ".config", t, "config.json")), r.push(e(process.cwd(), `${t}.config.json`)), n !== void 0 && r.push(n), r;
39
40
  }
40
- async function loadMergedConfig(e, t) {
41
- let n = resolveConfigPaths(e, t), r;
41
+ async function g(e, t) {
42
+ let n = h(e, t), r;
42
43
  for (let e of n) {
43
- let t = await loadConfig(e);
44
+ let t = await p(e);
44
45
  if (t !== void 0) {
45
46
  if (r === void 0) {
46
47
  r = t;
47
48
  continue;
48
49
  }
49
- r = deepMerge(r, t);
50
+ r = m(r, t);
50
51
  }
51
52
  }
52
53
  return r;
53
54
  }
54
- function deriveEnvName(e, t, n) {
55
+ //#endregion
56
+ //#region src/auto-mapping.ts
57
+ function _(e, t, n) {
55
58
  return [
56
59
  e,
57
60
  ...t,
58
61
  n
59
62
  ].join("_").toUpperCase();
60
63
  }
61
- function deriveConfigPath(e, t) {
64
+ function v(e, t) {
62
65
  return [...e, t].join(".");
63
66
  }
64
- function isBooleanSchema(e) {
65
- return e instanceof ZodBoolean;
67
+ //#endregion
68
+ //#region src/zod-utils.ts
69
+ function y(e) {
70
+ return e instanceof r;
66
71
  }
67
- function isNumberSchema(e) {
68
- return e instanceof ZodNumber;
72
+ function b(e) {
73
+ return e instanceof a;
69
74
  }
70
- var INDENT = " ", COLUMN_GAP = 2;
71
- function resolveEnvNameForHelp(e, t, n, r) {
75
+ //#endregion
76
+ //#region src/help.ts
77
+ var x = " ", S = 2;
78
+ function C(e, t, n, r) {
72
79
  if (e.env !== void 0) return e.env;
73
- if (t !== void 0) return deriveEnvName(t, n, r);
80
+ if (t !== void 0) return _(t, n, r);
81
+ }
82
+ function w(e) {
83
+ switch (typeof e) {
84
+ case "string":
85
+ case "number":
86
+ case "boolean":
87
+ case "bigint": return String(e);
88
+ default: return JSON.stringify(e);
89
+ }
74
90
  }
75
- function formatOptionMeta(e, t) {
91
+ function ee(e, t) {
76
92
  let n = [];
77
- return t !== void 0 && n.push(`env: ${t}`), "default" in e && e.default !== void 0 && n.push(`default: ${String(e.default)}`), n.length === 0 ? "" : ` (${n.join(", ")})`;
93
+ return t !== void 0 && n.push(`env: ${t}`), "default" in e && e.default !== void 0 && n.push(`default: ${w(e.default)}`), n.length === 0 ? "" : ` (${n.join(", ")})`;
78
94
  }
79
- function formatOptionLine(e, t, n, r) {
80
- let i = isBooleanSchema(t.type) ? "" : ` <${e}>`, a = `${t.alias === void 0 ? " " : `-${t.alias}, `}--${e}${i}`, o = resolveEnvNameForHelp(t, n, r, e);
95
+ function T(e, t, n, r) {
96
+ let i = y(t.type) ? "" : ` <${e}>`, a = `${t.alias === void 0 ? " " : `-${t.alias}, `}--${e}${i}`, o = C(t, n, r, e);
81
97
  return {
82
98
  left: a,
83
- right: `${t.description}${formatOptionMeta(t, o)}`
99
+ right: `${t.description}${ee(t, o)}`
84
100
  };
85
101
  }
86
- function formatHelpLine() {
102
+ function E() {
87
103
  return {
88
104
  left: "-h, --help",
89
105
  right: "ヘルプを表示する"
90
106
  };
91
107
  }
92
- function generateHelp(e) {
108
+ function D(e) {
93
109
  let { programName: t, commandPath: n, description: r, argsDefs: i, envPrefix: a } = e, o = [];
94
110
  r !== void 0 && (o.push(r), o.push(""));
95
111
  let s = [t, ...n];
@@ -105,51 +121,51 @@ function generateHelp(e) {
105
121
  let c = Object.entries(i).filter(([, e]) => e.positional !== !0);
106
122
  if (c.length === 0) {
107
123
  o.push("Options:");
108
- let e = formatHelpLine();
109
- return o.push(`${INDENT}${e.left} ${e.right}`), o.join("\n");
124
+ let e = E();
125
+ return o.push(`${x}${e.left} ${e.right}`), o.join("\n");
110
126
  }
111
127
  o.push("Options:");
112
- let l = c.map(([e, t]) => formatOptionLine(e, t, a, n));
113
- l.push(formatHelpLine());
128
+ let l = c.map(([e, t]) => T(e, t, a, n));
129
+ l.push(E());
114
130
  let u = Math.max(...l.map((e) => e.left.length));
115
131
  for (let e of l) {
116
- let t = " ".repeat(u - e.left.length + COLUMN_GAP);
117
- o.push(`${INDENT}${e.left}${t}${e.right}`);
132
+ let t = " ".repeat(u - e.left.length + S);
133
+ o.push(`${x}${e.left}${t}${e.right}`);
118
134
  }
119
135
  return o.join("\n");
120
136
  }
121
- function generateSubcommandHelp(e) {
137
+ function te(e) {
122
138
  let { programName: t, commandPath: n, availableEntries: r } = e, i = [], a = [t, ...n].join(" ");
123
139
  if (i.push(`Usage: ${a} <command>`), i.push(""), r.length === 0) return i.push("No available commands."), i.join("\n");
124
140
  i.push("Available commands:");
125
141
  for (let e of r) {
126
142
  if (e.isDynamic) {
127
- i.push(`${INDENT}<${e.paramName}>`);
143
+ i.push(`${x}<${e.paramName}>`);
128
144
  continue;
129
145
  }
130
- i.push(`${INDENT}${e.name}`);
146
+ i.push(`${x}${e.name}`);
131
147
  }
132
148
  return i.join("\n");
133
149
  }
134
- function generateValidationErrorHelp(e, t) {
150
+ function O(e, t) {
135
151
  return [
136
152
  `Error: ${t.join(", ")}`,
137
153
  "",
138
154
  e
139
155
  ].join("\n");
140
156
  }
141
- function generateDefaultCommandHelp(e) {
157
+ function k(e) {
142
158
  let { programName: t, defaultCommandName: n, commandPath: r, description: i, argsDefs: a, envPrefix: o, availableEntries: s } = e, c = [];
143
159
  if (i !== void 0 && (c.push(i), c.push("")), a !== void 0 && Object.entries(a).some(([, e]) => e.positional !== !0) ? c.push(`Usage: ${t} [options]`) : c.push(`Usage: ${t}`), c.push(` ${t} <command>`), c.push(""), a !== void 0) {
144
160
  let e = Object.entries(a).filter(([, e]) => e.positional !== !0);
145
161
  if (e.length > 0) {
146
162
  c.push("Options:");
147
- let t = e.map(([e, t]) => formatOptionLine(e, t, o, r));
148
- t.push(formatHelpLine());
163
+ let t = e.map(([e, t]) => T(e, t, o, r));
164
+ t.push(E());
149
165
  let n = Math.max(...t.map((e) => e.left.length));
150
166
  for (let e of t) {
151
- let t = " ".repeat(n - e.left.length + COLUMN_GAP);
152
- c.push(`${INDENT}${e.left}${t}${e.right}`);
167
+ let t = " ".repeat(n - e.left.length + S);
168
+ c.push(`${x}${e.left}${t}${e.right}`);
153
169
  }
154
170
  c.push("");
155
171
  }
@@ -158,17 +174,19 @@ function generateDefaultCommandHelp(e) {
158
174
  c.push("Available commands:");
159
175
  for (let e of s) {
160
176
  if (e.isDynamic) {
161
- c.push(`${INDENT}<${e.paramName}>`);
177
+ c.push(`${x}<${e.paramName}>`);
162
178
  continue;
163
179
  }
164
180
  let t = e.name === n ? " (default)" : "";
165
- c.push(`${INDENT}${e.name}${t}`);
181
+ c.push(`${x}${e.name}${t}`);
166
182
  }
167
183
  }
168
184
  return c.join("\n");
169
185
  }
170
- var LONG_FLAG_PREFIX = "--", SHORT_FLAG_PREFIX = "-", DOUBLE_DASH = "--", NEGATION_PREFIX = "--no-", BOOLEAN_TRUE = "true", BOOLEAN_FALSE = "false";
171
- function addFlag(e, t, n) {
186
+ //#endregion
187
+ //#region src/parser.ts
188
+ var A = "--", j = "-", ne = "--", re = "--no-", M = "true", N = "false";
189
+ function P(e, t, n) {
172
190
  let r = e.get(t);
173
191
  if (r) {
174
192
  r.push(n);
@@ -176,51 +194,51 @@ function addFlag(e, t, n) {
176
194
  }
177
195
  e.set(t, [n]);
178
196
  }
179
- function isNextTokenAvailable(e, t) {
180
- return t + 1 >= e.length ? !1 : !e[t + 1].startsWith(SHORT_FLAG_PREFIX);
197
+ function F(e, t) {
198
+ return t + 1 >= e.length ? !1 : !e[t + 1].startsWith(j);
181
199
  }
182
- function parseTokens(e, t) {
200
+ function I(e, t) {
183
201
  let n = /* @__PURE__ */ new Map(), r = [], i = [], a = 0;
184
202
  for (; a < e.length;) {
185
203
  let o = e[a];
186
- if (o === DOUBLE_DASH) {
204
+ if (o === ne) {
187
205
  i = e.slice(a + 1);
188
206
  break;
189
207
  }
190
- if (o.startsWith(NEGATION_PREFIX)) {
191
- addFlag(n, o.slice(5), BOOLEAN_FALSE), a++;
208
+ if (o.startsWith(re)) {
209
+ P(n, o.slice(5), N), a++;
192
210
  continue;
193
211
  }
194
- if (o.startsWith(LONG_FLAG_PREFIX) && o.includes("=")) {
212
+ if (o.startsWith(A) && o.includes("=")) {
195
213
  let e = o.indexOf("=");
196
- addFlag(n, o.slice(2, e), o.slice(e + 1)), a++;
214
+ P(n, o.slice(2, e), o.slice(e + 1)), a++;
197
215
  continue;
198
216
  }
199
- if (o.startsWith(LONG_FLAG_PREFIX)) {
217
+ if (o.startsWith(A)) {
200
218
  let r = o.slice(2);
201
219
  if (t.booleanFlags.has(r)) {
202
- addFlag(n, r, BOOLEAN_TRUE), a++;
220
+ P(n, r, M), a++;
203
221
  continue;
204
222
  }
205
- if (isNextTokenAvailable(e, a)) {
206
- addFlag(n, r, e[a + 1]), a += 2;
223
+ if (F(e, a)) {
224
+ P(n, r, e[a + 1]), a += 2;
207
225
  continue;
208
226
  }
209
227
  throw Error(`Flag --${r} requires a value`);
210
228
  }
211
- if (o.startsWith(SHORT_FLAG_PREFIX) && !o.startsWith(LONG_FLAG_PREFIX) && o.includes("=")) {
229
+ if (o.startsWith(j) && !o.startsWith(A) && o.includes("=")) {
212
230
  let e = o.indexOf("="), r = o.slice(1, e), i = o.slice(e + 1);
213
- addFlag(n, t.aliases.get(r) ?? r, i), a++;
231
+ P(n, t.aliases.get(r) ?? r, i), a++;
214
232
  continue;
215
233
  }
216
- if (o.startsWith(SHORT_FLAG_PREFIX) && !o.startsWith(LONG_FLAG_PREFIX)) {
234
+ if (o.startsWith(j) && !o.startsWith(A)) {
217
235
  let r = o.slice(1), i = t.aliases.get(r) ?? r;
218
236
  if (t.booleanFlags.has(i)) {
219
- addFlag(n, i, BOOLEAN_TRUE), a++;
237
+ P(n, i, M), a++;
220
238
  continue;
221
239
  }
222
- if (isNextTokenAvailable(e, a)) {
223
- addFlag(n, i, e[a + 1]), a += 2;
240
+ if (F(e, a)) {
241
+ P(n, i, e[a + 1]), a += 2;
224
242
  continue;
225
243
  }
226
244
  throw Error(`Flag -${r} requires a value`);
@@ -233,11 +251,13 @@ function parseTokens(e, t) {
233
251
  doubleDashArgs: i
234
252
  };
235
253
  }
236
- var PLUGINS_DIR_NAME = "_plugins", PLUGIN_FILE_EXTENSION = ".ts";
237
- function definePlugin(e) {
254
+ //#endregion
255
+ //#region src/plugin.ts
256
+ var L = "_plugins", R = ".ts";
257
+ function z(e) {
238
258
  return e;
239
259
  }
240
- async function resolvePlugins(e, t) {
260
+ async function B(e, t) {
241
261
  let n = {}, r = [];
242
262
  for (let i of e) {
243
263
  let e = await i(t);
@@ -248,7 +268,7 @@ async function resolvePlugins(e, t) {
248
268
  middlewares: r
249
269
  };
250
270
  }
251
- function buildMiddlewareChain(e, t) {
271
+ function V(e, t) {
252
272
  let n = t;
253
273
  for (let t = e.length - 1; t >= 0; t--) {
254
274
  let r = e[t], i = n;
@@ -256,29 +276,31 @@ function buildMiddlewareChain(e, t) {
256
276
  }
257
277
  return n;
258
278
  }
259
- async function scanPluginsAlongPath(t, n) {
279
+ async function H(t, n) {
260
280
  let r = [];
261
281
  for (let n of t) {
262
- let t = join(n, PLUGINS_DIR_NAME), i;
282
+ let t = e(n, L), i;
263
283
  try {
264
- i = await readdir(t, { withFileTypes: !0 });
284
+ i = await c(t, { withFileTypes: !0 });
265
285
  } catch {
266
286
  continue;
267
287
  }
268
- let a = i.filter((e) => e.isFile() && e.name.endsWith(PLUGIN_FILE_EXTENSION)).sort((e, t) => e.name.localeCompare(t.name));
288
+ let a = i.filter((e) => e.isFile() && e.name.endsWith(R)).sort((e, t) => e.name.localeCompare(t.name));
269
289
  for (let n of a) {
270
- let i = join(t, n.name), a = (await import(i)).default;
290
+ let i = e(t, n.name), a = (await import(i)).default;
271
291
  if (a === void 0) throw Error(`Plugin file ${i} does not have a default export`);
272
292
  r.push(a);
273
293
  }
274
294
  }
275
- return resolvePlugins(r, n);
295
+ return B(r, n);
276
296
  }
277
- function resolveEnvName(e, t, n, r) {
297
+ //#endregion
298
+ //#region src/resolver.ts
299
+ function U(e, t, n, r) {
278
300
  if (e !== void 0) return e;
279
- if (t !== void 0) return deriveEnvName(t, n, r);
301
+ if (t !== void 0) return _(t, n, r);
280
302
  }
281
- function resolveValues(e) {
303
+ function W(e) {
282
304
  let { argsDefs: t, parsedTokens: n, env: r, config: i, commandPath: a, envPrefix: o } = e, s = {}, c = 0;
283
305
  for (let [e, l] of Object.entries(t)) {
284
306
  let t = n.flags.get(e);
@@ -294,7 +316,7 @@ function resolveValues(e) {
294
316
  s[e] = n.positionals[c], c++;
295
317
  continue;
296
318
  }
297
- let u = resolveEnvName(l.env, o, a, e);
319
+ let u = U(l.env, o, a, e);
298
320
  if (u !== void 0) {
299
321
  let t = r[u];
300
322
  if (t !== void 0) {
@@ -303,7 +325,7 @@ function resolveValues(e) {
303
325
  }
304
326
  }
305
327
  if (i !== void 0) {
306
- let t = getByDotPath(i, l.config ?? deriveConfigPath(a, e));
328
+ let t = f(i, l.config ?? v(a, e));
307
329
  if (t !== void 0) {
308
330
  s[e] = t;
309
331
  continue;
@@ -316,29 +338,39 @@ function resolveValues(e) {
316
338
  }
317
339
  return s;
318
340
  }
319
- var DYNAMIC_SEGMENT_PATTERN = /^\[(.+)]$/, COMMAND_FILE_EXTENSION = ".ts", INDEX_FILE_NAME = "index", INTERNAL_PREFIX = "_";
320
- async function fileExists(e) {
341
+ //#endregion
342
+ //#region src/router.ts
343
+ var G = /^\[(.+)]$/, K = [".ts", ".js"], q = "index", J = "_";
344
+ function Y(e) {
345
+ return K.find((t) => e.endsWith(t));
346
+ }
347
+ function ie(e, t) {
348
+ return e.slice(0, -t.length);
349
+ }
350
+ async function ae(e) {
321
351
  try {
322
- return (await stat(e)).isFile();
352
+ return (await l(e)).isFile();
323
353
  } catch {
324
354
  return !1;
325
355
  }
326
356
  }
327
- async function listAvailableEntries(e) {
357
+ async function oe(e) {
328
358
  try {
329
- let t = await readdir(e, { withFileTypes: !0 }), n = [];
330
- for (let e of t) if (!e.name.startsWith(INTERNAL_PREFIX)) {
331
- if (e.isFile() && e.name.endsWith(COMMAND_FILE_EXTENSION)) {
332
- let t = e.name.slice(0, -3);
333
- if (t === INDEX_FILE_NAME) continue;
334
- n.push({
335
- name: t,
359
+ let t = (await c(e, { withFileTypes: !0 })).toSorted((e, t) => (e.isFile() ? K.indexOf(Y(e.name) ?? "") : -1) - (t.isFile() ? K.indexOf(Y(t.name) ?? "") : -1)), n = [], r = /* @__PURE__ */ new Set();
360
+ for (let e of t) {
361
+ if (e.name.startsWith(J)) continue;
362
+ let t = e.isFile() ? Y(e.name) : void 0;
363
+ if (t !== void 0) {
364
+ let i = ie(e.name, t);
365
+ if (i === q || r.has(i)) continue;
366
+ r.add(i), n.push({
367
+ name: i,
336
368
  isDynamic: !1
337
369
  });
338
370
  continue;
339
371
  }
340
372
  if (e.isDirectory()) {
341
- let t = e.name.match(DYNAMIC_SEGMENT_PATTERN);
373
+ let t = e.name.match(G);
342
374
  if (t !== null) {
343
375
  n.push({
344
376
  name: e.name,
@@ -358,82 +390,88 @@ async function listAvailableEntries(e) {
358
390
  return [];
359
391
  }
360
392
  }
361
- async function resolveRoute(t, r) {
362
- let i = resolve(t), a = {}, o = [i], s = 0;
393
+ async function X(t, r) {
394
+ let i = n(t), a = {}, o = [i], s = 0;
363
395
  for (let t = 0; t < r.length; t++) {
364
396
  let n = r[t];
365
397
  if (n.startsWith("-")) break;
366
- let l = await readdir(i, { withFileTypes: !0 }), u = n + COMMAND_FILE_EXTENSION, d = l.find((e) => e.isFile() && e.name === u);
367
- if (d) return s = t + 1, {
398
+ let l = await c(i, { withFileTypes: !0 }), u = K.reduce((e, t) => e ?? l.find((e) => e.isFile() && e.name === n + t), void 0);
399
+ if (u) return s = t + 1, {
368
400
  kind: "resolved",
369
- filePath: join(i, d.name),
401
+ filePath: e(i, u.name),
370
402
  params: a,
371
403
  remainingTokens: r.slice(s),
372
404
  traversedDirs: o
373
405
  };
374
- let f = l.find((e) => e.isDirectory() && e.name === n);
375
- if (f) {
376
- i = join(i, f.name), o.push(i), s = t + 1;
406
+ let d = l.find((e) => e.isDirectory() && e.name === n);
407
+ if (d) {
408
+ i = e(i, d.name), o.push(i), s = t + 1;
377
409
  continue;
378
410
  }
379
- let p, m = l.find((e) => {
411
+ let f, p = l.find((e) => {
380
412
  if (!e.isDirectory()) return !1;
381
- let t = e.name.match(DYNAMIC_SEGMENT_PATTERN);
382
- return t === null ? !1 : (p = t[1], !0);
413
+ let t = e.name.match(G);
414
+ return t === null ? !1 : (f = t[1], !0);
383
415
  });
384
- if (m && p !== void 0) {
385
- a[p] = n, i = join(i, m.name), o.push(i), s = t + 1;
416
+ if (p && f !== void 0) {
417
+ a[f] = n, i = e(i, p.name), o.push(i), s = t + 1;
386
418
  continue;
387
419
  }
388
420
  break;
389
421
  }
390
- let l = join(i, INDEX_FILE_NAME + COMMAND_FILE_EXTENSION);
391
- if (await fileExists(l)) return {
392
- kind: "resolved",
393
- filePath: l,
394
- params: a,
395
- remainingTokens: r.slice(s),
396
- traversedDirs: o
397
- };
398
- let u = await listAvailableEntries(i);
422
+ for (let t of K) {
423
+ let n = e(i, q + t);
424
+ if (await ae(n)) return {
425
+ kind: "resolved",
426
+ filePath: n,
427
+ params: a,
428
+ remainingTokens: r.slice(s),
429
+ traversedDirs: o
430
+ };
431
+ }
432
+ let l = await oe(i);
399
433
  return {
400
434
  kind: "unresolved",
401
435
  stoppedDir: i,
402
- availableEntries: u
436
+ availableEntries: l
403
437
  };
404
438
  }
405
- function wrapWithStringPreprocess(e) {
406
- return isBooleanSchema(e) ? z.preprocess((e) => typeof e == "string" ? e === "true" || e === "1" : e, e) : isNumberSchema(e) ? z.preprocess((e) => typeof e == "string" ? Number(e) : e, e) : e;
439
+ //#endregion
440
+ //#region src/validator.ts
441
+ function se(e) {
442
+ return y(e) ? o.preprocess((e) => typeof e == "string" ? e === "true" || e === "1" : e, e) : b(e) ? o.preprocess((e) => typeof e == "string" ? Number(e) : e, e) : e;
407
443
  }
408
- function validateArgs(e, t) {
444
+ function ce(e, t) {
409
445
  let n = {};
410
446
  for (let [t, r] of Object.entries(e)) {
411
- let e = wrapWithStringPreprocess(r.type);
447
+ let e = se(r.type);
412
448
  if (r.multiple === !0) {
413
- n[t] = z.array(e);
449
+ n[t] = o.array(e);
414
450
  continue;
415
451
  }
416
452
  n[t] = e;
417
453
  }
418
- return z.object(n).parse(t);
454
+ return o.object(n).parse(t);
419
455
  }
420
- var DEFAULT_COMMANDS_DIR = "commands", ARGV_SKIP = 2, EXIT_CODE_ERROR = 1;
421
- function buildParserConfig(e) {
456
+ //#endregion
457
+ //#region src/cli.ts
458
+ var le = "commands", Z = 2, Q = 1;
459
+ function ue(e) {
422
460
  let t = /* @__PURE__ */ new Set(), n = /* @__PURE__ */ new Map();
423
- for (let [r, i] of Object.entries(e)) isBooleanSchema(i.type) && t.add(r), i.alias !== void 0 && n.set(i.alias, r);
461
+ for (let [r, i] of Object.entries(e)) y(i.type) && t.add(r), i.alias !== void 0 && n.set(i.alias, r);
424
462
  return {
425
463
  booleanFlags: t,
426
464
  aliases: n
427
465
  };
428
466
  }
429
- function extractCommandPath(e, r) {
430
- return relative(resolve(e), r).replace(/\.ts$/, "").split("/").filter((e) => e !== "index" && !e.startsWith("["));
467
+ function $(e, r) {
468
+ return t(n(e), r).replace(/\.ts$/, "").split("/").filter((e) => e !== "index" && !e.startsWith("["));
431
469
  }
432
- function extractPartialCommandPath(e, r) {
433
- let i = relative(resolve(e), r);
470
+ function de(e, r) {
471
+ let i = t(n(e), r);
434
472
  return i === "" || i === "." ? [] : i.split("/").filter((e) => !e.startsWith("["));
435
473
  }
436
- function extractFrameworkFlags(e) {
474
+ function fe(e) {
437
475
  let t, n = [];
438
476
  for (let r = 0; r < e.length; r++) {
439
477
  let i = e[r];
@@ -454,42 +492,39 @@ function extractFrameworkFlags(e) {
454
492
  remainingTokens: n
455
493
  };
456
494
  }
457
- function createCLI(e) {
458
- let t = e.commandsDir ?? DEFAULT_COMMANDS_DIR, r = e.name, a = e.autoEnv?.prefix, o = e.defaultCommand;
495
+ function pe(e) {
496
+ let t = e.commandsDir ?? le, r = e.name, a = e.autoEnv?.prefix, o = e.defaultCommand;
459
497
  async function s() {
460
- let { configPath: e, remainingTokens: s } = extractFrameworkFlags(process.argv.slice(ARGV_SKIP)), c = await resolveRoute(t, s);
461
- if (c.kind === "unresolved") {
462
- let e = resolve(c.stoppedDir) === resolve(t), i = s.length > 0 && !s[0].startsWith("-");
463
- if (e && o !== void 0 && !i) {
464
- if (s.includes("--help") || s.includes("-h")) {
465
- let e = await resolveRoute(t, [o]);
466
- if (e.kind === "unresolved") throw Error(`defaultCommand "${o}" does not match any command file`);
467
- let n = (await import(e.filePath)).default, i = n.args ?? {}, s = generateDefaultCommandHelp({
468
- programName: r,
469
- defaultCommandName: o,
470
- commandPath: extractCommandPath(t, e.filePath),
471
- description: n.description,
472
- argsDefs: Object.keys(i).length > 0 ? i : void 0,
473
- envPrefix: a,
474
- availableEntries: c.availableEntries
475
- });
476
- console.log(s);
477
- return;
478
- }
479
- let e = await resolveRoute(t, [o, ...s]);
498
+ let { configPath: e, remainingTokens: s } = fe(process.argv.slice(Z)), c = await X(t, s);
499
+ if (c.kind === "unresolved") if (n(c.stoppedDir) === n(t) && o !== void 0) {
500
+ if (s.includes("--help") || s.includes("-h")) {
501
+ let e = await X(t, [o]);
480
502
  if (e.kind === "unresolved") throw Error(`defaultCommand "${o}" does not match any command file`);
481
- c = e;
482
- } else {
483
- let e = generateSubcommandHelp({
503
+ let n = (await import(e.filePath)).default, i = n.args ?? {}, s = k({
484
504
  programName: r,
485
- commandPath: extractPartialCommandPath(t, c.stoppedDir),
505
+ defaultCommandName: o,
506
+ commandPath: $(t, e.filePath),
507
+ description: n.description,
508
+ argsDefs: Object.keys(i).length > 0 ? i : void 0,
509
+ envPrefix: a,
486
510
  availableEntries: c.availableEntries
487
511
  });
488
- console.log(e);
512
+ console.log(s);
489
513
  return;
490
514
  }
515
+ let e = await X(t, [o, ...s]);
516
+ if (e.kind === "unresolved") throw Error(`defaultCommand "${o}" does not match any command file`);
517
+ c = e;
518
+ } else {
519
+ let e = te({
520
+ programName: r,
521
+ commandPath: de(t, c.stoppedDir),
522
+ availableEntries: c.availableEntries
523
+ });
524
+ console.log(e);
525
+ return;
491
526
  }
492
- let l = (await import(c.filePath)).default, u = l.args ?? {}, d = extractCommandPath(t, c.filePath), f = generateHelp({
527
+ let l = (await import(c.filePath)).default, u = l.args ?? {}, d = $(t, c.filePath), f = D({
493
528
  programName: r,
494
529
  commandPath: d,
495
530
  description: l.description,
@@ -500,10 +535,10 @@ function createCLI(e) {
500
535
  console.log(f);
501
536
  return;
502
537
  }
503
- let p = buildParserConfig(u), m;
538
+ let p = ue(u), m;
504
539
  try {
505
- let t = parseTokens(c.remainingTokens, p), n = await loadMergedConfig(r, e);
506
- m = validateArgs(u, resolveValues({
540
+ let t = I(c.remainingTokens, p), n = await g(r, e);
541
+ m = ce(u, W({
507
542
  argsDefs: u,
508
543
  parsedTokens: t,
509
544
  env: process.env,
@@ -512,29 +547,32 @@ function createCLI(e) {
512
547
  envPrefix: a
513
548
  }));
514
549
  } catch (e) {
515
- if (e instanceof ZodError) {
550
+ if (e instanceof i) {
516
551
  let t = e.issues.map((e) => `${e.path.join(".")}: ${e.message}`);
517
- console.error(generateValidationErrorHelp(f, t)), process.exit(EXIT_CODE_ERROR);
552
+ console.error(O(f, t)), process.exit(Q);
518
553
  }
519
- throw e instanceof Error && (console.error(generateValidationErrorHelp(f, [e.message])), process.exit(EXIT_CODE_ERROR)), e;
554
+ throw e instanceof Error && (console.error(O(f, [e.message])), process.exit(Q)), e;
520
555
  }
521
- let { extensions: h, middlewares: g } = await scanPluginsAlongPath(c.traversedDirs, { cliName: r }), _ = {
556
+ let { extensions: h, middlewares: _ } = await H(c.traversedDirs, { cliName: r }), v = {
522
557
  commandPath: d,
523
558
  params: c.params,
524
559
  args: m,
525
560
  extensions: h
526
561
  };
527
- await buildMiddlewareChain(g, async (e) => {
562
+ await V(_, async (e) => {
528
563
  await l.run({
529
564
  params: e.params,
530
565
  args: e.args,
531
566
  extensions: e.extensions
532
567
  });
533
- })(_);
568
+ })(v);
534
569
  }
535
570
  return { run: s };
536
571
  }
537
- function defineCommand(e) {
572
+ //#endregion
573
+ //#region src/types.ts
574
+ function me(e) {
538
575
  return e;
539
576
  }
540
- export { createCLI, defineCommand, definePlugin };
577
+ //#endregion
578
+ export { pe as createCLI, me as defineCommand, z as definePlugin };
@@ -1 +1 @@
1
- {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAQA,UAAU,aAAa;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,UAAU,eAAe;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,cAAc,EAAE,CAAC;CACpC;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,KAAK,WAAW,GAAG,aAAa,GAAG,eAAe,CAAC;AAqDnD,iBAAe,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAmFvF;AAED,OAAO,EAAE,YAAY,EAAE,CAAC;AACxB,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC"}
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAiBA,UAAU,aAAa;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,eAAe,EAAE,MAAM,EAAE,CAAC;IAC1B,aAAa,EAAE,MAAM,EAAE,CAAC;CACzB;AAED,UAAU,eAAe;IACvB,IAAI,EAAE,YAAY,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,gBAAgB,EAAE,cAAc,EAAE,CAAC;CACpC;AAED,UAAU,cAAc;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,KAAK,WAAW,GAAG,aAAa,GAAG,eAAe,CAAC;AAsEnD,iBAAe,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,WAAW,CAAC,CAuFvF;AAED,OAAO,EAAE,YAAY,EAAE,CAAC;AACxB,YAAY,EAAE,cAAc,EAAE,aAAa,EAAE,WAAW,EAAE,eAAe,EAAE,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@miyaoka/fsss",
3
- "version": "0.3.0",
3
+ "version": "0.3.2",
4
4
  "description": "A CLI framework where your file structure becomes your command structure, and a single schema gives you typed values whether they come from flags, env vars, or config files.",
5
5
  "type": "module",
6
6
  "author": "miyaoka",
@@ -37,13 +37,13 @@
37
37
  },
38
38
  "devDependencies": {
39
39
  "@tsconfig/node24": "24.0.4",
40
- "@types/bun": "1.3.9",
41
- "oxfmt": "0.31.0",
42
- "oxlint": "1.46.0",
43
- "oxlint-tsgolint": "0.12.0",
40
+ "@types/bun": "1.3.10",
41
+ "oxfmt": "0.37.0",
42
+ "oxlint": "1.52.0",
43
+ "oxlint-tsgolint": "0.16.0",
44
44
  "typescript": "5.9.3",
45
45
  "unplugin-dts": "1.0.0-beta.6",
46
- "vite": "8.0.0-beta.13"
46
+ "vite": "8.0.0-beta.18"
47
47
  },
48
48
  "scripts": {
49
49
  "build": "vite build",