eser 0.8.3 → 0.8.4
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 +58 -0
- package/{bin.ts → bin.js} +2 -2
- package/commands/codebase/{mod.ts → mod.js} +88 -153
- package/main.js +48 -0
- package/package.json +5 -5
- package/deno.json +0 -10
- package/main.ts +0 -79
- package/package.json.template +0 -16
- package/scripts/npm-publish-prepare.ts +0 -123
- package/scripts/npm-publish-revert.ts +0 -30
package/README.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# eser
|
|
2
|
+
|
|
3
|
+
Eser Ozvataf's command-line tooling to access things.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Using npx (no installation required)
|
|
9
|
+
npx eser <command>
|
|
10
|
+
|
|
11
|
+
# Using Deno
|
|
12
|
+
deno run -A jsr:@eser/cli <command>
|
|
13
|
+
|
|
14
|
+
# Global installation via npm
|
|
15
|
+
npm install -g eser
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Commands
|
|
19
|
+
|
|
20
|
+
### codebase
|
|
21
|
+
|
|
22
|
+
Codebase validation and management tools.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
eser codebase <subcommand> [options]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Subcommands:**
|
|
29
|
+
|
|
30
|
+
- `check` - Run all codebase checks
|
|
31
|
+
- `check-circular-deps` - Check for circular dependencies
|
|
32
|
+
- `check-docs` - Check documentation coverage
|
|
33
|
+
- `check-export-names` - Check export naming conventions
|
|
34
|
+
- `check-licenses` - Check license compliance
|
|
35
|
+
- `check-mod-exports` - Check module exports
|
|
36
|
+
- `check-package-configs` - Check package configurations
|
|
37
|
+
|
|
38
|
+
**Options:**
|
|
39
|
+
|
|
40
|
+
- `-h, --help` - Show help message
|
|
41
|
+
- `--root <path>` - Root directory (default: current directory)
|
|
42
|
+
|
|
43
|
+
## Examples
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
# Run all checks on current directory
|
|
47
|
+
eser codebase check
|
|
48
|
+
|
|
49
|
+
# Check for circular dependencies
|
|
50
|
+
eser codebase check-circular-deps
|
|
51
|
+
|
|
52
|
+
# Run checks on a specific directory
|
|
53
|
+
eser codebase check --root ./my-project
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## License
|
|
57
|
+
|
|
58
|
+
Apache-2.0
|
package/{bin.ts → bin.js}
RENAMED
|
@@ -1,20 +1,3 @@
|
|
|
1
|
-
// Copyright 2023-present Eser Ozvataf and other contributors. All rights reserved. Apache-2.0 license.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Codebase command group - validation and management tools
|
|
5
|
-
*
|
|
6
|
-
* Subcommands:
|
|
7
|
-
* check-circular-deps Detect circular package dependencies
|
|
8
|
-
* check-mod-exports Validate mod.ts exports all files
|
|
9
|
-
* check-export-names Validate export naming conventions
|
|
10
|
-
* check-docs Validate JSDoc documentation
|
|
11
|
-
* check-licenses Validate license headers
|
|
12
|
-
* check-package-configs Validate deno.json/package.json consistency
|
|
13
|
-
* versions Manage workspace versions
|
|
14
|
-
*
|
|
15
|
-
* @module
|
|
16
|
-
*/
|
|
17
|
-
|
|
18
1
|
import * as cliParseArgs from "@std/cli/parse-args";
|
|
19
2
|
import * as fmtColors from "@std/fmt/colors";
|
|
20
3
|
import * as standardsRuntime from "@eser/standards/runtime";
|
|
@@ -25,17 +8,11 @@ import * as checkDocs from "@eser/codebase/check-docs";
|
|
|
25
8
|
import * as checkLicenses from "@eser/codebase/check-licenses";
|
|
26
9
|
import * as checkPackageConfigs from "@eser/codebase/check-package-configs";
|
|
27
10
|
import * as versions from "@eser/codebase/versions";
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
handler: (args: string[], flags: Record<string, unknown>) => Promise<void>;
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const showSubcommandHelp = (name: string, def: SubcommandDef): void => {
|
|
37
|
-
console.log(`eser codebase ${name} - ${def.description}\n`);
|
|
38
|
-
console.log(`Usage: ${def.usage}\n`);
|
|
11
|
+
const showSubcommandHelp = (name, def) => {
|
|
12
|
+
console.log(`eser codebase ${name} - ${def.description}
|
|
13
|
+
`);
|
|
14
|
+
console.log(`Usage: ${def.usage}
|
|
15
|
+
`);
|
|
39
16
|
if (def.options.length > 0) {
|
|
40
17
|
console.log("Options:");
|
|
41
18
|
for (const opt of def.options) {
|
|
@@ -43,101 +20,95 @@ const showSubcommandHelp = (name: string, def: SubcommandDef): void => {
|
|
|
43
20
|
}
|
|
44
21
|
}
|
|
45
22
|
};
|
|
46
|
-
|
|
47
|
-
const subcommands: Record<string, SubcommandDef> = {
|
|
23
|
+
const subcommands = {
|
|
48
24
|
"check-circular-deps": {
|
|
49
25
|
description: "Detect circular package dependencies",
|
|
50
26
|
usage: "eser codebase check-circular-deps [options]",
|
|
51
27
|
options: [
|
|
52
28
|
{
|
|
53
29
|
flag: "--root <path>",
|
|
54
|
-
description: "Root directory (default: current)"
|
|
30
|
+
description: "Root directory (default: current)"
|
|
55
31
|
},
|
|
56
|
-
{ flag: "-h, --help", description: "Show this help message" }
|
|
32
|
+
{ flag: "-h, --help", description: "Show this help message" }
|
|
57
33
|
],
|
|
58
34
|
handler: async (_args, flags) => {
|
|
59
|
-
const root = flags["root"]
|
|
35
|
+
const root = flags["root"];
|
|
60
36
|
console.log("Checking for circular dependencies...\n");
|
|
61
|
-
|
|
62
37
|
const result = await checkCircularDeps.checkCircularDeps({ root });
|
|
63
|
-
|
|
64
38
|
console.log(`Checked ${result.packagesChecked} packages.`);
|
|
65
|
-
|
|
66
39
|
if (result.hasCycles) {
|
|
67
40
|
console.log(
|
|
68
41
|
fmtColors.red(
|
|
69
|
-
|
|
70
|
-
|
|
42
|
+
`
|
|
43
|
+
Found ${result.cycles.length} circular dependencies:
|
|
44
|
+
`
|
|
45
|
+
)
|
|
71
46
|
);
|
|
72
47
|
for (const cycle of result.cycles) {
|
|
73
|
-
console.log(fmtColors.yellow(` ${cycle.join("
|
|
48
|
+
console.log(fmtColors.yellow(` ${cycle.join(" \u2192 ")}`));
|
|
74
49
|
}
|
|
75
50
|
standardsRuntime.runtime.process.exit(1);
|
|
76
51
|
} else {
|
|
77
52
|
console.log(fmtColors.green("\nNo circular dependencies found."));
|
|
78
53
|
}
|
|
79
|
-
}
|
|
54
|
+
}
|
|
80
55
|
},
|
|
81
|
-
|
|
82
56
|
"check-mod-exports": {
|
|
83
57
|
description: "Validate mod.ts exports all public files",
|
|
84
58
|
usage: "eser codebase check-mod-exports [options]",
|
|
85
59
|
options: [
|
|
86
60
|
{
|
|
87
61
|
flag: "--root <path>",
|
|
88
|
-
description: "Root directory (default: current)"
|
|
62
|
+
description: "Root directory (default: current)"
|
|
89
63
|
},
|
|
90
|
-
{ flag: "-h, --help", description: "Show this help message" }
|
|
64
|
+
{ flag: "-h, --help", description: "Show this help message" }
|
|
91
65
|
],
|
|
92
66
|
handler: async (_args, flags) => {
|
|
93
|
-
const root = flags["root"]
|
|
67
|
+
const root = flags["root"];
|
|
94
68
|
console.log("Checking mod.ts exports...\n");
|
|
95
|
-
|
|
96
69
|
const result = await checkModExports.checkModExports({ root });
|
|
97
|
-
|
|
98
70
|
console.log(`Checked ${result.packagesChecked} packages.`);
|
|
99
|
-
|
|
100
71
|
if (!result.isComplete) {
|
|
101
72
|
console.log(
|
|
102
73
|
fmtColors.red(
|
|
103
|
-
|
|
104
|
-
|
|
74
|
+
`
|
|
75
|
+
Found ${result.missingExports.length} missing exports:
|
|
76
|
+
`
|
|
77
|
+
)
|
|
105
78
|
);
|
|
106
79
|
for (const missing of result.missingExports) {
|
|
107
80
|
console.log(
|
|
108
|
-
fmtColors.yellow(` ${missing.packageName}: ${missing.file}`)
|
|
81
|
+
fmtColors.yellow(` ${missing.packageName}: ${missing.file}`)
|
|
109
82
|
);
|
|
110
83
|
}
|
|
111
84
|
standardsRuntime.runtime.process.exit(1);
|
|
112
85
|
} else {
|
|
113
86
|
console.log(fmtColors.green("\nAll mod.ts exports are complete."));
|
|
114
87
|
}
|
|
115
|
-
}
|
|
88
|
+
}
|
|
116
89
|
},
|
|
117
|
-
|
|
118
90
|
"check-export-names": {
|
|
119
91
|
description: "Validate export naming conventions",
|
|
120
92
|
usage: "eser codebase check-export-names [options]",
|
|
121
93
|
options: [
|
|
122
94
|
{
|
|
123
95
|
flag: "--root <path>",
|
|
124
|
-
description: "Root directory (default: current)"
|
|
96
|
+
description: "Root directory (default: current)"
|
|
125
97
|
},
|
|
126
|
-
{ flag: "-h, --help", description: "Show this help message" }
|
|
98
|
+
{ flag: "-h, --help", description: "Show this help message" }
|
|
127
99
|
],
|
|
128
100
|
handler: async (_args, flags) => {
|
|
129
|
-
const root = flags["root"]
|
|
101
|
+
const root = flags["root"];
|
|
130
102
|
console.log("Checking export naming conventions...\n");
|
|
131
|
-
|
|
132
103
|
const result = await checkExportNames.checkExportNames({ root });
|
|
133
|
-
|
|
134
104
|
console.log(`Checked ${result.packagesChecked} packages.`);
|
|
135
|
-
|
|
136
105
|
if (!result.isValid) {
|
|
137
106
|
console.log(
|
|
138
107
|
fmtColors.red(
|
|
139
|
-
|
|
140
|
-
|
|
108
|
+
`
|
|
109
|
+
Found ${result.violations.length} naming violations:
|
|
110
|
+
`
|
|
111
|
+
)
|
|
141
112
|
);
|
|
142
113
|
for (const violation of result.violations) {
|
|
143
114
|
console.log(fmtColors.yellow(` ${violation.packageName}:`));
|
|
@@ -148,79 +119,70 @@ const subcommands: Record<string, SubcommandDef> = {
|
|
|
148
119
|
} else {
|
|
149
120
|
console.log(fmtColors.green("\nAll export names follow conventions."));
|
|
150
121
|
}
|
|
151
|
-
}
|
|
122
|
+
}
|
|
152
123
|
},
|
|
153
|
-
|
|
154
124
|
"check-docs": {
|
|
155
125
|
description: "Validate JSDoc documentation",
|
|
156
126
|
usage: "eser codebase check-docs [options]",
|
|
157
127
|
options: [
|
|
158
128
|
{
|
|
159
129
|
flag: "--root <path>",
|
|
160
|
-
description: "Root directory (default: current)"
|
|
130
|
+
description: "Root directory (default: current)"
|
|
161
131
|
},
|
|
162
|
-
{ flag: "-h, --help", description: "Show this help message" }
|
|
132
|
+
{ flag: "-h, --help", description: "Show this help message" }
|
|
163
133
|
],
|
|
164
134
|
handler: async (_args, flags) => {
|
|
165
|
-
const root = flags["root"]
|
|
135
|
+
const root = flags["root"];
|
|
166
136
|
console.log("Checking documentation...\n");
|
|
167
|
-
|
|
168
137
|
const result = await checkDocs.checkDocs({ root });
|
|
169
|
-
|
|
170
138
|
console.log(
|
|
171
|
-
`Checked ${result.filesChecked} files, ${result.symbolsChecked} symbols
|
|
139
|
+
`Checked ${result.filesChecked} files, ${result.symbolsChecked} symbols.`
|
|
172
140
|
);
|
|
173
|
-
|
|
174
141
|
if (!result.isValid) {
|
|
175
142
|
console.log(
|
|
176
143
|
fmtColors.red(
|
|
177
|
-
|
|
178
|
-
|
|
144
|
+
`
|
|
145
|
+
Found ${result.issues.length} documentation issues:
|
|
146
|
+
`
|
|
147
|
+
)
|
|
179
148
|
);
|
|
180
|
-
|
|
181
|
-
// Group by file
|
|
182
|
-
const byFile = new Map<string, checkDocs.DocIssue[]>();
|
|
149
|
+
const byFile = /* @__PURE__ */ new Map();
|
|
183
150
|
for (const issue of result.issues) {
|
|
184
151
|
const existing = byFile.get(issue.file) ?? [];
|
|
185
152
|
existing.push(issue);
|
|
186
153
|
byFile.set(issue.file, existing);
|
|
187
154
|
}
|
|
188
|
-
|
|
189
155
|
for (const [file, fileIssues] of byFile) {
|
|
190
|
-
console.log(fmtColors.yellow(
|
|
156
|
+
console.log(fmtColors.yellow(`
|
|
157
|
+
${file}:`));
|
|
191
158
|
for (const issue of fileIssues) {
|
|
192
|
-
const lineInfo = issue.line !==
|
|
159
|
+
const lineInfo = issue.line !== void 0 ? `:${issue.line}` : "";
|
|
193
160
|
console.log(` ${issue.symbol}${lineInfo}: ${issue.issue}`);
|
|
194
161
|
}
|
|
195
162
|
}
|
|
196
|
-
|
|
197
163
|
standardsRuntime.runtime.process.exit(1);
|
|
198
164
|
} else {
|
|
199
165
|
console.log(fmtColors.green("\nAll documentation is valid."));
|
|
200
166
|
}
|
|
201
|
-
}
|
|
167
|
+
}
|
|
202
168
|
},
|
|
203
|
-
|
|
204
169
|
"check-licenses": {
|
|
205
170
|
description: "Validate license headers in source files",
|
|
206
171
|
usage: "eser codebase check-licenses [options]",
|
|
207
172
|
options: [
|
|
208
173
|
{ flag: "--fix", description: "Auto-fix missing or incorrect headers" },
|
|
209
|
-
{ flag: "-h, --help", description: "Show this help message" }
|
|
174
|
+
{ flag: "-h, --help", description: "Show this help message" }
|
|
210
175
|
],
|
|
211
176
|
handler: async (_args, flags) => {
|
|
212
|
-
const fix = flags["fix"]
|
|
177
|
+
const fix = flags["fix"];
|
|
213
178
|
console.log("Validating license headers...\n");
|
|
214
|
-
|
|
215
179
|
const result = await checkLicenses.validateLicenses({ fix });
|
|
216
|
-
|
|
217
180
|
if (result.issues.length === 0) {
|
|
218
181
|
console.log(
|
|
219
|
-
`Checked ${result.checked} files. All licenses are valid
|
|
182
|
+
`Checked ${result.checked} files. All licenses are valid.`
|
|
220
183
|
);
|
|
221
184
|
return;
|
|
222
185
|
}
|
|
223
|
-
|
|
224
186
|
if (fix) {
|
|
225
187
|
for (const issue of result.issues) {
|
|
226
188
|
if (issue.fixed) {
|
|
@@ -232,76 +194,65 @@ const subcommands: Record<string, SubcommandDef> = {
|
|
|
232
194
|
for (const issue of result.issues) {
|
|
233
195
|
console.error(
|
|
234
196
|
fmtColors.red(
|
|
235
|
-
`${
|
|
236
|
-
|
|
237
|
-
} copyright header: ${issue.path}`,
|
|
238
|
-
),
|
|
197
|
+
`${issue.issue === "missing" ? "Missing" : "Incorrect"} copyright header: ${issue.path}`
|
|
198
|
+
)
|
|
239
199
|
);
|
|
240
200
|
}
|
|
241
201
|
console.log(
|
|
242
202
|
fmtColors.yellow(
|
|
243
|
-
|
|
244
|
-
|
|
203
|
+
`
|
|
204
|
+
Copyright header should be "// Copyright YYYY-present Eser Ozvataf and other contributors. All rights reserved. Apache-2.0 license."`
|
|
205
|
+
)
|
|
245
206
|
);
|
|
246
207
|
standardsRuntime.runtime.process.exit(1);
|
|
247
208
|
}
|
|
248
|
-
}
|
|
209
|
+
}
|
|
249
210
|
},
|
|
250
|
-
|
|
251
211
|
"check-package-configs": {
|
|
252
212
|
description: "Validate deno.json and package.json consistency",
|
|
253
213
|
usage: "eser codebase check-package-configs [options]",
|
|
254
214
|
options: [
|
|
255
215
|
{
|
|
256
216
|
flag: "--root <path>",
|
|
257
|
-
description: "Root directory (default: current)"
|
|
217
|
+
description: "Root directory (default: current)"
|
|
258
218
|
},
|
|
259
|
-
{ flag: "-h, --help", description: "Show this help message" }
|
|
219
|
+
{ flag: "-h, --help", description: "Show this help message" }
|
|
260
220
|
],
|
|
261
221
|
handler: async (_args, flags) => {
|
|
262
|
-
const root = flags["root"]
|
|
222
|
+
const root = flags["root"];
|
|
263
223
|
console.log("Checking package config consistency...\n");
|
|
264
|
-
|
|
265
224
|
const result = await checkPackageConfigs.checkPackageConfigs({ root });
|
|
266
|
-
|
|
267
225
|
console.log(`Checked ${result.packagesChecked} packages.`);
|
|
268
|
-
|
|
269
226
|
if (!result.isConsistent) {
|
|
270
227
|
console.log(
|
|
271
228
|
fmtColors.red(
|
|
272
|
-
|
|
273
|
-
|
|
229
|
+
`
|
|
230
|
+
Found ${result.inconsistencies.length} inconsistencies:
|
|
231
|
+
`
|
|
232
|
+
)
|
|
274
233
|
);
|
|
275
|
-
|
|
276
|
-
// Group by package
|
|
277
|
-
const byPackage = new Map<
|
|
278
|
-
string,
|
|
279
|
-
checkPackageConfigs.ConfigInconsistency[]
|
|
280
|
-
>();
|
|
234
|
+
const byPackage = /* @__PURE__ */ new Map();
|
|
281
235
|
for (const inc of result.inconsistencies) {
|
|
282
236
|
const existing = byPackage.get(inc.packageName) ?? [];
|
|
283
237
|
existing.push(inc);
|
|
284
238
|
byPackage.set(inc.packageName, existing);
|
|
285
239
|
}
|
|
286
|
-
|
|
287
240
|
for (const [pkgName, inconsistencies] of byPackage) {
|
|
288
241
|
console.log(fmtColors.yellow(`${pkgName}:`));
|
|
289
242
|
for (const inc of inconsistencies) {
|
|
290
|
-
console.log(fmtColors.red(`
|
|
243
|
+
console.log(fmtColors.red(` \u26A0 ${inc.field} mismatch:`));
|
|
291
244
|
console.log(` deno.json: ${JSON.stringify(inc.denoValue)}`);
|
|
292
245
|
console.log(
|
|
293
|
-
` package.json: ${JSON.stringify(inc.packageValue)}
|
|
246
|
+
` package.json: ${JSON.stringify(inc.packageValue)}`
|
|
294
247
|
);
|
|
295
248
|
}
|
|
296
249
|
}
|
|
297
|
-
|
|
298
250
|
standardsRuntime.runtime.process.exit(1);
|
|
299
251
|
} else {
|
|
300
252
|
console.log(fmtColors.green("\nAll package configs are consistent."));
|
|
301
253
|
}
|
|
302
|
-
}
|
|
254
|
+
}
|
|
303
255
|
},
|
|
304
|
-
|
|
305
256
|
versions: {
|
|
306
257
|
description: "Manage workspace package versions",
|
|
307
258
|
usage: "eser codebase versions [command] [options]",
|
|
@@ -311,52 +262,45 @@ const subcommands: Record<string, SubcommandDef> = {
|
|
|
311
262
|
{ flag: "minor", description: "Bump minor version (0.x.0)" },
|
|
312
263
|
{ flag: "major", description: "Bump major version (x.0.0)" },
|
|
313
264
|
{ flag: "--dry-run", description: "Preview changes without applying" },
|
|
314
|
-
{ flag: "-h, --help", description: "Show this help message" }
|
|
265
|
+
{ flag: "-h, --help", description: "Show this help message" }
|
|
315
266
|
],
|
|
316
267
|
handler: async (args, flags) => {
|
|
317
|
-
const command = args[0]
|
|
318
|
-
const dryRun = flags["dry-run"]
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
console.table(result.packages);
|
|
268
|
+
const command = args[0];
|
|
269
|
+
const dryRun = flags["dry-run"];
|
|
270
|
+
if (command === void 0) {
|
|
271
|
+
const result2 = await versions.showVersions();
|
|
272
|
+
console.table(result2.packages);
|
|
323
273
|
return;
|
|
324
274
|
}
|
|
325
|
-
|
|
326
275
|
const validCommands = ["sync", "patch", "minor", "major"];
|
|
327
276
|
if (!validCommands.includes(command)) {
|
|
328
277
|
console.error(fmtColors.red(`Invalid command: ${command}`));
|
|
329
278
|
console.error(
|
|
330
|
-
"Usage: eser codebase versions [sync|patch|minor|major] [--dry-run]"
|
|
279
|
+
"Usage: eser codebase versions [sync|patch|minor|major] [--dry-run]"
|
|
331
280
|
);
|
|
332
281
|
standardsRuntime.runtime.process.exit(1);
|
|
333
282
|
}
|
|
334
|
-
|
|
335
283
|
if (command === "sync") {
|
|
336
284
|
console.log("Syncing all versions...");
|
|
337
285
|
} else {
|
|
338
286
|
console.log(`Bumping all versions (${command})...`);
|
|
339
287
|
}
|
|
340
|
-
|
|
341
288
|
const result = await versions.versions(command, { dryRun });
|
|
342
|
-
|
|
343
289
|
console.log(`Target version: ${result.targetVersion}`);
|
|
344
290
|
console.table(result.updates);
|
|
345
|
-
|
|
346
291
|
if (result.dryRun) {
|
|
347
292
|
console.log(
|
|
348
293
|
fmtColors.cyan(
|
|
349
|
-
`Dry run - ${result.changedCount} packages would be modified
|
|
350
|
-
)
|
|
294
|
+
`Dry run - ${result.changedCount} packages would be modified.`
|
|
295
|
+
)
|
|
351
296
|
);
|
|
352
297
|
} else {
|
|
353
298
|
console.log(`Done. Updated ${result.changedCount} packages.`);
|
|
354
299
|
}
|
|
355
|
-
}
|
|
356
|
-
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
357
302
|
};
|
|
358
|
-
|
|
359
|
-
const showHelp = (): void => {
|
|
303
|
+
const showHelp = () => {
|
|
360
304
|
console.log("eser codebase - Codebase validation tools\n");
|
|
361
305
|
console.log("Usage: eser codebase <subcommand> [options]\n");
|
|
362
306
|
console.log("Subcommands:");
|
|
@@ -366,46 +310,37 @@ const showHelp = (): void => {
|
|
|
366
310
|
console.log(" check-docs Validate JSDoc documentation");
|
|
367
311
|
console.log(" check-licenses Validate license headers");
|
|
368
312
|
console.log(
|
|
369
|
-
" check-package-configs Validate deno.json/package.json consistency"
|
|
313
|
+
" check-package-configs Validate deno.json/package.json consistency"
|
|
370
314
|
);
|
|
371
315
|
console.log(" versions Manage workspace versions");
|
|
372
316
|
console.log(
|
|
373
|
-
"\nRun 'eser codebase <subcommand> --help' for subcommand options."
|
|
317
|
+
"\nRun 'eser codebase <subcommand> --help' for subcommand options."
|
|
374
318
|
);
|
|
375
319
|
};
|
|
376
|
-
|
|
377
|
-
export const codebaseCommand = async (
|
|
378
|
-
rawArgs: string[],
|
|
379
|
-
_parentFlags: Record<string, unknown>,
|
|
380
|
-
): Promise<void> => {
|
|
381
|
-
// Parse all flags (don't use stopEarly so --help is always captured)
|
|
320
|
+
const codebaseCommand = async (rawArgs, _parentFlags) => {
|
|
382
321
|
const parsed = cliParseArgs.parseArgs(rawArgs, {
|
|
383
322
|
boolean: ["help", "dry-run", "fix"],
|
|
384
323
|
string: ["root"],
|
|
385
|
-
alias: { h: "help" }
|
|
324
|
+
alias: { h: "help" }
|
|
386
325
|
});
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
// Show main help if no subcommand or help without subcommand
|
|
391
|
-
if (subcommand === undefined) {
|
|
326
|
+
const subcommand = parsed._[0];
|
|
327
|
+
if (subcommand === void 0) {
|
|
392
328
|
showHelp();
|
|
393
329
|
return;
|
|
394
330
|
}
|
|
395
|
-
|
|
396
331
|
const def = subcommands[subcommand];
|
|
397
|
-
if (def ===
|
|
332
|
+
if (def === void 0) {
|
|
398
333
|
console.error(fmtColors.red(`Unknown subcommand: ${subcommand}`));
|
|
399
334
|
console.log("");
|
|
400
335
|
showHelp();
|
|
401
336
|
standardsRuntime.runtime.process.exit(1);
|
|
402
337
|
}
|
|
403
|
-
|
|
404
|
-
// Show subcommand help if --help flag
|
|
405
338
|
if (parsed.help) {
|
|
406
339
|
showSubcommandHelp(subcommand, def);
|
|
407
340
|
return;
|
|
408
341
|
}
|
|
409
|
-
|
|
410
|
-
|
|
342
|
+
await def.handler(parsed._.slice(1), parsed);
|
|
343
|
+
};
|
|
344
|
+
export {
|
|
345
|
+
codebaseCommand
|
|
411
346
|
};
|
package/main.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as cliParseArgs from "@std/cli/parse-args";
|
|
2
|
+
import * as standardsRuntime from "@eser/standards/runtime";
|
|
3
|
+
import { codebaseCommand } from "./commands/codebase/mod.js";
|
|
4
|
+
import config from "./package.json" with { type: "json" };
|
|
5
|
+
const commands = {
|
|
6
|
+
codebase: codebaseCommand
|
|
7
|
+
};
|
|
8
|
+
const showHelp = () => {
|
|
9
|
+
console.log("eser - Eser Ozvataf's command-line tooling to access things\n");
|
|
10
|
+
console.log("Usage: eser <command> [subcommand] [options]\n");
|
|
11
|
+
console.log("Commands:");
|
|
12
|
+
console.log(" codebase Codebase validation and management tools");
|
|
13
|
+
console.log("\nOptions:");
|
|
14
|
+
console.log(" -h, --help Show this help message");
|
|
15
|
+
console.log(" -v, --version Show version number");
|
|
16
|
+
console.log("\nRun 'eser <command> --help' for command-specific help.");
|
|
17
|
+
};
|
|
18
|
+
const main = async () => {
|
|
19
|
+
const args = cliParseArgs.parseArgs(standardsRuntime.runtime.process.args, {
|
|
20
|
+
boolean: ["help", "version"],
|
|
21
|
+
alias: { h: "help", v: "version" },
|
|
22
|
+
stopEarly: true
|
|
23
|
+
// Stop parsing at first non-option to pass rest to subcommand
|
|
24
|
+
});
|
|
25
|
+
if (args.version) {
|
|
26
|
+
console.log(`eser ${config.version}`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const command = args._[0];
|
|
30
|
+
if (command === void 0) {
|
|
31
|
+
showHelp();
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const handler = commands[command];
|
|
35
|
+
if (handler === void 0) {
|
|
36
|
+
console.error(`Unknown command: ${command}`);
|
|
37
|
+
console.log("");
|
|
38
|
+
showHelp();
|
|
39
|
+
standardsRuntime.runtime.process.exit(1);
|
|
40
|
+
}
|
|
41
|
+
await handler(args._.slice(1), args);
|
|
42
|
+
};
|
|
43
|
+
if (import.meta.main) {
|
|
44
|
+
await main();
|
|
45
|
+
}
|
|
46
|
+
export {
|
|
47
|
+
main
|
|
48
|
+
};
|
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "eser",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.4",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"exports": "./main.
|
|
5
|
+
"exports": "./main.js",
|
|
6
6
|
"bin": {
|
|
7
|
-
"eser": "./bin.
|
|
7
|
+
"eser": "./bin.js"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"@eser/codebase": "npm:@jsr/eser__codebase@^0.8.
|
|
11
|
-
"@eser/standards": "npm:@jsr/eser__standards@^0.8.
|
|
10
|
+
"@eser/codebase": "npm:@jsr/eser__codebase@^0.8.4",
|
|
11
|
+
"@eser/standards": "npm:@jsr/eser__standards@^0.8.4",
|
|
12
12
|
"@std/cli": "npm:@jsr/std__cli@^1.0.25",
|
|
13
13
|
"@std/fmt": "npm:@jsr/std__fmt@^1.0.8",
|
|
14
14
|
"@std/path": "npm:@jsr/std__path@^1.1.4"
|
package/deno.json
DELETED
package/main.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
// Copyright 2023-present Eser Ozvataf and other contributors. All rights reserved. Apache-2.0 license.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* eser - Versatile development CLI
|
|
5
|
-
*
|
|
6
|
-
* A multi-purpose command-line tool for development workflows.
|
|
7
|
-
* Similar in design to `gh` (GitHub CLI) or `wrangler` (Cloudflare).
|
|
8
|
-
*
|
|
9
|
-
* Usage:
|
|
10
|
-
* deno run -A ./main.ts <command> [subcommand] [options]
|
|
11
|
-
* dx jsr:@eser/cli <command> [subcommand] [options]
|
|
12
|
-
*
|
|
13
|
-
* Commands:
|
|
14
|
-
* codebase Codebase validation and management tools
|
|
15
|
-
*
|
|
16
|
-
* @module
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
import * as cliParseArgs from "@std/cli/parse-args";
|
|
20
|
-
import * as standardsRuntime from "@eser/standards/runtime";
|
|
21
|
-
import { codebaseCommand } from "./commands/codebase/mod.ts";
|
|
22
|
-
import config from "./deno.json" with { type: "json" };
|
|
23
|
-
|
|
24
|
-
type CommandHandler = (
|
|
25
|
-
args: string[],
|
|
26
|
-
flags: Record<string, unknown>,
|
|
27
|
-
) => Promise<void>;
|
|
28
|
-
|
|
29
|
-
const commands: Record<string, CommandHandler> = {
|
|
30
|
-
codebase: codebaseCommand,
|
|
31
|
-
};
|
|
32
|
-
|
|
33
|
-
const showHelp = (): void => {
|
|
34
|
-
console.log("eser - Versatile development CLI\n");
|
|
35
|
-
console.log("Usage: eser <command> [subcommand] [options]\n");
|
|
36
|
-
console.log("Commands:");
|
|
37
|
-
console.log(" codebase Codebase validation and management tools");
|
|
38
|
-
console.log("\nOptions:");
|
|
39
|
-
console.log(" -h, --help Show this help message");
|
|
40
|
-
console.log(" -v, --version Show version number");
|
|
41
|
-
console.log("\nRun 'eser <command> --help' for command-specific help.");
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
export const main = async (): Promise<void> => {
|
|
45
|
-
// @ts-ignore parseArgs doesn't mutate the array, readonly is safe
|
|
46
|
-
const args = cliParseArgs.parseArgs(standardsRuntime.runtime.process.args, {
|
|
47
|
-
boolean: ["help", "version"],
|
|
48
|
-
alias: { h: "help", v: "version" },
|
|
49
|
-
stopEarly: true, // Stop parsing at first non-option to pass rest to subcommand
|
|
50
|
-
});
|
|
51
|
-
|
|
52
|
-
if (args.version) {
|
|
53
|
-
console.log(`eser ${config.version}`);
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
const command = args._[0] as string | undefined;
|
|
58
|
-
|
|
59
|
-
// Show main help only if no command or help without command
|
|
60
|
-
if (command === undefined) {
|
|
61
|
-
showHelp();
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
const handler = commands[command];
|
|
66
|
-
if (handler === undefined) {
|
|
67
|
-
console.error(`Unknown command: ${command}`);
|
|
68
|
-
console.log("");
|
|
69
|
-
showHelp();
|
|
70
|
-
standardsRuntime.runtime.process.exit(1);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Pass remaining args to command handler
|
|
74
|
-
await handler(args._.slice(1) as string[], args);
|
|
75
|
-
};
|
|
76
|
-
|
|
77
|
-
if (import.meta.main) {
|
|
78
|
-
await main();
|
|
79
|
-
}
|
package/package.json.template
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "@eser/cli",
|
|
3
|
-
"version": "0.8.3",
|
|
4
|
-
"type": "module",
|
|
5
|
-
"exports": "./main.ts",
|
|
6
|
-
"bin": {
|
|
7
|
-
"eser": "./bin.ts"
|
|
8
|
-
},
|
|
9
|
-
"dependencies": {
|
|
10
|
-
"@eser/codebase": "workspace:*",
|
|
11
|
-
"@eser/standards": "workspace:*",
|
|
12
|
-
"@std/cli": "npm:@jsr/std__cli@^1.0.25",
|
|
13
|
-
"@std/fmt": "npm:@jsr/std__fmt@^1.0.8",
|
|
14
|
-
"@std/path": "npm:@jsr/std__path@^1.1.4"
|
|
15
|
-
}
|
|
16
|
-
}
|
|
@@ -1,123 +0,0 @@
|
|
|
1
|
-
// Copyright 2023-present Eser Ozvataf and other contributors. All rights reserved. Apache-2.0 license.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Prepares package.json for npm publishing.
|
|
5
|
-
*
|
|
6
|
-
* Reads package.json.template, replaces workspace:* dependencies with
|
|
7
|
-
* npm:@jsr/eser__<package>@^<version>, sets name to "eser", and writes
|
|
8
|
-
* the result to package.json.
|
|
9
|
-
*
|
|
10
|
-
* @module
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import * as path from "@std/path";
|
|
14
|
-
|
|
15
|
-
type PackageJson = {
|
|
16
|
-
name: string;
|
|
17
|
-
version: string;
|
|
18
|
-
type?: string;
|
|
19
|
-
exports?: string | Record<string, string>;
|
|
20
|
-
bin?: Record<string, string>;
|
|
21
|
-
dependencies?: Record<string, string>;
|
|
22
|
-
devDependencies?: Record<string, string>;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
type DenoJson = {
|
|
26
|
-
name: string;
|
|
27
|
-
version: string;
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
const isWorkspaceDep = (spec: string): boolean => {
|
|
31
|
-
return spec === "workspace:*" || spec.startsWith("workspace:");
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
const extractPackageName = (depName: string): string => {
|
|
35
|
-
// @eser/codebase -> codebase
|
|
36
|
-
const parts = depName.split("/");
|
|
37
|
-
return parts.length > 1 ? parts[1] : depName;
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const getPackageVersion = async (
|
|
41
|
-
pkgDir: string,
|
|
42
|
-
depName: string,
|
|
43
|
-
): Promise<string> => {
|
|
44
|
-
const packageName = extractPackageName(depName);
|
|
45
|
-
const denoJsonPath = path.join(pkgDir, "..", packageName, "deno.json");
|
|
46
|
-
|
|
47
|
-
const content = await Deno.readTextFile(denoJsonPath);
|
|
48
|
-
const denoJson = JSON.parse(content) as DenoJson;
|
|
49
|
-
|
|
50
|
-
return denoJson.version;
|
|
51
|
-
};
|
|
52
|
-
|
|
53
|
-
const convertWorkspaceDep = async (
|
|
54
|
-
pkgDir: string,
|
|
55
|
-
depName: string,
|
|
56
|
-
): Promise<string> => {
|
|
57
|
-
const packageName = extractPackageName(depName);
|
|
58
|
-
const version = await getPackageVersion(pkgDir, depName);
|
|
59
|
-
|
|
60
|
-
// @eser/codebase -> npm:@jsr/eser__codebase@^0.8.0
|
|
61
|
-
return `npm:@jsr/eser__${packageName}@^${version}`;
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
const processDependencies = async (
|
|
65
|
-
pkgDir: string,
|
|
66
|
-
deps: Record<string, string> | undefined,
|
|
67
|
-
): Promise<Record<string, string> | undefined> => {
|
|
68
|
-
if (deps === undefined) {
|
|
69
|
-
return undefined;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
const result: Record<string, string> = {};
|
|
73
|
-
|
|
74
|
-
for (const [name, spec] of Object.entries(deps)) {
|
|
75
|
-
if (isWorkspaceDep(spec)) {
|
|
76
|
-
result[name] = await convertWorkspaceDep(pkgDir, name);
|
|
77
|
-
} else {
|
|
78
|
-
result[name] = spec;
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
return result;
|
|
83
|
-
};
|
|
84
|
-
|
|
85
|
-
const main = async (): Promise<void> => {
|
|
86
|
-
const scriptDir = import.meta.dirname;
|
|
87
|
-
if (scriptDir === undefined) {
|
|
88
|
-
throw new Error("Cannot determine script directory");
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
const pkgDir = path.dirname(scriptDir);
|
|
92
|
-
const templatePath = path.join(pkgDir, "package.json.template");
|
|
93
|
-
const outputPath = path.join(pkgDir, "package.json");
|
|
94
|
-
|
|
95
|
-
// Read template
|
|
96
|
-
const templateContent = await Deno.readTextFile(templatePath);
|
|
97
|
-
const pkg = JSON.parse(templateContent) as PackageJson;
|
|
98
|
-
|
|
99
|
-
// Set name to "eser" for npx
|
|
100
|
-
pkg.name = "eser";
|
|
101
|
-
|
|
102
|
-
// Process dependencies
|
|
103
|
-
pkg.dependencies = await processDependencies(pkgDir, pkg.dependencies);
|
|
104
|
-
pkg.devDependencies = await processDependencies(pkgDir, pkg.devDependencies);
|
|
105
|
-
|
|
106
|
-
// Write output
|
|
107
|
-
const outputContent = JSON.stringify(pkg, null, 2) + "\n";
|
|
108
|
-
await Deno.writeTextFile(outputPath, outputContent);
|
|
109
|
-
|
|
110
|
-
// deno-lint-ignore no-console
|
|
111
|
-
console.log(`Generated ${outputPath}`);
|
|
112
|
-
// deno-lint-ignore no-console
|
|
113
|
-
console.log(` name: ${pkg.name}`);
|
|
114
|
-
|
|
115
|
-
if (pkg.dependencies !== undefined) {
|
|
116
|
-
for (const [name, spec] of Object.entries(pkg.dependencies)) {
|
|
117
|
-
// deno-lint-ignore no-console
|
|
118
|
-
console.log(` ${name}: ${spec}`);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
};
|
|
122
|
-
|
|
123
|
-
main();
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
// Copyright 2023-present Eser Ozvataf and other contributors. All rights reserved. Apache-2.0 license.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Reverts package.json to local development state.
|
|
5
|
-
*
|
|
6
|
-
* Copies package.json.template to package.json to restore workspace:*
|
|
7
|
-
* dependencies for local development.
|
|
8
|
-
*
|
|
9
|
-
* @module
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import * as path from "@std/path";
|
|
13
|
-
|
|
14
|
-
const main = async (): Promise<void> => {
|
|
15
|
-
const scriptDir = import.meta.dirname;
|
|
16
|
-
if (scriptDir === undefined) {
|
|
17
|
-
throw new Error("Cannot determine script directory");
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const pkgDir = path.dirname(scriptDir);
|
|
21
|
-
const templatePath = path.join(pkgDir, "package.json.template");
|
|
22
|
-
const outputPath = path.join(pkgDir, "package.json");
|
|
23
|
-
|
|
24
|
-
await Deno.copyFile(templatePath, outputPath);
|
|
25
|
-
|
|
26
|
-
// deno-lint-ignore no-console
|
|
27
|
-
console.log(`Copied ${templatePath} to ${outputPath}`);
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
main();
|