eser 0.1.5 → 0.8.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.
@@ -0,0 +1,411 @@
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
+ import * as cliParseArgs from "@std/cli/parse-args";
19
+ import * as fmtColors from "@std/fmt/colors";
20
+ import * as standardsRuntime from "@eser/standards/runtime";
21
+ import * as checkCircularDeps from "@eser/codebase/check-circular-deps";
22
+ import * as checkModExports from "@eser/codebase/check-mod-exports";
23
+ import * as checkExportNames from "@eser/codebase/check-export-names";
24
+ import * as checkDocs from "@eser/codebase/check-docs";
25
+ import * as checkLicenses from "@eser/codebase/check-licenses";
26
+ import * as checkPackageConfigs from "@eser/codebase/check-package-configs";
27
+ import * as versions from "@eser/codebase/versions";
28
+
29
+ type SubcommandDef = {
30
+ description: string;
31
+ usage: string;
32
+ options: Array<{ flag: string; description: string }>;
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`);
39
+ if (def.options.length > 0) {
40
+ console.log("Options:");
41
+ for (const opt of def.options) {
42
+ console.log(` ${opt.flag.padEnd(20)} ${opt.description}`);
43
+ }
44
+ }
45
+ };
46
+
47
+ const subcommands: Record<string, SubcommandDef> = {
48
+ "check-circular-deps": {
49
+ description: "Detect circular package dependencies",
50
+ usage: "eser codebase check-circular-deps [options]",
51
+ options: [
52
+ {
53
+ flag: "--root <path>",
54
+ description: "Root directory (default: current)",
55
+ },
56
+ { flag: "-h, --help", description: "Show this help message" },
57
+ ],
58
+ handler: async (_args, flags) => {
59
+ const root = flags["root"] as string | undefined;
60
+ console.log("Checking for circular dependencies...\n");
61
+
62
+ const result = await checkCircularDeps.checkCircularDeps({ root });
63
+
64
+ console.log(`Checked ${result.packagesChecked} packages.`);
65
+
66
+ if (result.hasCycles) {
67
+ console.log(
68
+ fmtColors.red(
69
+ `\nFound ${result.cycles.length} circular dependencies:\n`,
70
+ ),
71
+ );
72
+ for (const cycle of result.cycles) {
73
+ console.log(fmtColors.yellow(` ${cycle.join(" → ")}`));
74
+ }
75
+ standardsRuntime.runtime.process.exit(1);
76
+ } else {
77
+ console.log(fmtColors.green("\nNo circular dependencies found."));
78
+ }
79
+ },
80
+ },
81
+
82
+ "check-mod-exports": {
83
+ description: "Validate mod.ts exports all public files",
84
+ usage: "eser codebase check-mod-exports [options]",
85
+ options: [
86
+ {
87
+ flag: "--root <path>",
88
+ description: "Root directory (default: current)",
89
+ },
90
+ { flag: "-h, --help", description: "Show this help message" },
91
+ ],
92
+ handler: async (_args, flags) => {
93
+ const root = flags["root"] as string | undefined;
94
+ console.log("Checking mod.ts exports...\n");
95
+
96
+ const result = await checkModExports.checkModExports({ root });
97
+
98
+ console.log(`Checked ${result.packagesChecked} packages.`);
99
+
100
+ if (!result.isComplete) {
101
+ console.log(
102
+ fmtColors.red(
103
+ `\nFound ${result.missingExports.length} missing exports:\n`,
104
+ ),
105
+ );
106
+ for (const missing of result.missingExports) {
107
+ console.log(
108
+ fmtColors.yellow(` ${missing.packageName}: ${missing.file}`),
109
+ );
110
+ }
111
+ standardsRuntime.runtime.process.exit(1);
112
+ } else {
113
+ console.log(fmtColors.green("\nAll mod.ts exports are complete."));
114
+ }
115
+ },
116
+ },
117
+
118
+ "check-export-names": {
119
+ description: "Validate export naming conventions",
120
+ usage: "eser codebase check-export-names [options]",
121
+ options: [
122
+ {
123
+ flag: "--root <path>",
124
+ description: "Root directory (default: current)",
125
+ },
126
+ { flag: "-h, --help", description: "Show this help message" },
127
+ ],
128
+ handler: async (_args, flags) => {
129
+ const root = flags["root"] as string | undefined;
130
+ console.log("Checking export naming conventions...\n");
131
+
132
+ const result = await checkExportNames.checkExportNames({ root });
133
+
134
+ console.log(`Checked ${result.packagesChecked} packages.`);
135
+
136
+ if (!result.isValid) {
137
+ console.log(
138
+ fmtColors.red(
139
+ `\nFound ${result.violations.length} naming violations:\n`,
140
+ ),
141
+ );
142
+ for (const violation of result.violations) {
143
+ console.log(fmtColors.yellow(` ${violation.packageName}:`));
144
+ console.log(` Export: ${violation.exportPath}`);
145
+ console.log(` Suggestion: ${violation.suggestion}`);
146
+ }
147
+ standardsRuntime.runtime.process.exit(1);
148
+ } else {
149
+ console.log(fmtColors.green("\nAll export names follow conventions."));
150
+ }
151
+ },
152
+ },
153
+
154
+ "check-docs": {
155
+ description: "Validate JSDoc documentation",
156
+ usage: "eser codebase check-docs [options]",
157
+ options: [
158
+ {
159
+ flag: "--root <path>",
160
+ description: "Root directory (default: current)",
161
+ },
162
+ { flag: "-h, --help", description: "Show this help message" },
163
+ ],
164
+ handler: async (_args, flags) => {
165
+ const root = flags["root"] as string | undefined;
166
+ console.log("Checking documentation...\n");
167
+
168
+ const result = await checkDocs.checkDocs({ root });
169
+
170
+ console.log(
171
+ `Checked ${result.filesChecked} files, ${result.symbolsChecked} symbols.`,
172
+ );
173
+
174
+ if (!result.isValid) {
175
+ console.log(
176
+ fmtColors.red(
177
+ `\nFound ${result.issues.length} documentation issues:\n`,
178
+ ),
179
+ );
180
+
181
+ // Group by file
182
+ const byFile = new Map<string, checkDocs.DocIssue[]>();
183
+ for (const issue of result.issues) {
184
+ const existing = byFile.get(issue.file) ?? [];
185
+ existing.push(issue);
186
+ byFile.set(issue.file, existing);
187
+ }
188
+
189
+ for (const [file, fileIssues] of byFile) {
190
+ console.log(fmtColors.yellow(`\n${file}:`));
191
+ for (const issue of fileIssues) {
192
+ const lineInfo = issue.line !== undefined ? `:${issue.line}` : "";
193
+ console.log(` ${issue.symbol}${lineInfo}: ${issue.issue}`);
194
+ }
195
+ }
196
+
197
+ standardsRuntime.runtime.process.exit(1);
198
+ } else {
199
+ console.log(fmtColors.green("\nAll documentation is valid."));
200
+ }
201
+ },
202
+ },
203
+
204
+ "check-licenses": {
205
+ description: "Validate license headers in source files",
206
+ usage: "eser codebase check-licenses [options]",
207
+ options: [
208
+ { flag: "--fix", description: "Auto-fix missing or incorrect headers" },
209
+ { flag: "-h, --help", description: "Show this help message" },
210
+ ],
211
+ handler: async (_args, flags) => {
212
+ const fix = flags["fix"] as boolean | undefined;
213
+ console.log("Validating license headers...\n");
214
+
215
+ const result = await checkLicenses.validateLicenses({ fix });
216
+
217
+ if (result.issues.length === 0) {
218
+ console.log(
219
+ `Checked ${result.checked} files. All licenses are valid.`,
220
+ );
221
+ return;
222
+ }
223
+
224
+ if (fix) {
225
+ for (const issue of result.issues) {
226
+ if (issue.fixed) {
227
+ console.log(`Fixed ${issue.issue} header: ${issue.path}`);
228
+ }
229
+ }
230
+ console.log(`Fixed ${result.fixedCount} files.`);
231
+ } else {
232
+ for (const issue of result.issues) {
233
+ console.error(
234
+ fmtColors.red(
235
+ `${
236
+ issue.issue === "missing" ? "Missing" : "Incorrect"
237
+ } copyright header: ${issue.path}`,
238
+ ),
239
+ );
240
+ }
241
+ console.log(
242
+ fmtColors.yellow(
243
+ `\nCopyright header should be "// Copyright YYYY-present Eser Ozvataf and other contributors. All rights reserved. Apache-2.0 license."`,
244
+ ),
245
+ );
246
+ standardsRuntime.runtime.process.exit(1);
247
+ }
248
+ },
249
+ },
250
+
251
+ "check-package-configs": {
252
+ description: "Validate deno.json and package.json consistency",
253
+ usage: "eser codebase check-package-configs [options]",
254
+ options: [
255
+ {
256
+ flag: "--root <path>",
257
+ description: "Root directory (default: current)",
258
+ },
259
+ { flag: "-h, --help", description: "Show this help message" },
260
+ ],
261
+ handler: async (_args, flags) => {
262
+ const root = flags["root"] as string | undefined;
263
+ console.log("Checking package config consistency...\n");
264
+
265
+ const result = await checkPackageConfigs.checkPackageConfigs({ root });
266
+
267
+ console.log(`Checked ${result.packagesChecked} packages.`);
268
+
269
+ if (!result.isConsistent) {
270
+ console.log(
271
+ fmtColors.red(
272
+ `\nFound ${result.inconsistencies.length} inconsistencies:\n`,
273
+ ),
274
+ );
275
+
276
+ // Group by package
277
+ const byPackage = new Map<
278
+ string,
279
+ checkPackageConfigs.ConfigInconsistency[]
280
+ >();
281
+ for (const inc of result.inconsistencies) {
282
+ const existing = byPackage.get(inc.packageName) ?? [];
283
+ existing.push(inc);
284
+ byPackage.set(inc.packageName, existing);
285
+ }
286
+
287
+ for (const [pkgName, inconsistencies] of byPackage) {
288
+ console.log(fmtColors.yellow(`${pkgName}:`));
289
+ for (const inc of inconsistencies) {
290
+ console.log(fmtColors.red(` ⚠ ${inc.field} mismatch:`));
291
+ console.log(` deno.json: ${JSON.stringify(inc.denoValue)}`);
292
+ console.log(
293
+ ` package.json: ${JSON.stringify(inc.packageValue)}`,
294
+ );
295
+ }
296
+ }
297
+
298
+ standardsRuntime.runtime.process.exit(1);
299
+ } else {
300
+ console.log(fmtColors.green("\nAll package configs are consistent."));
301
+ }
302
+ },
303
+ },
304
+
305
+ versions: {
306
+ description: "Manage workspace package versions",
307
+ usage: "eser codebase versions [command] [options]",
308
+ options: [
309
+ { flag: "sync", description: "Sync all packages to root version" },
310
+ { flag: "patch", description: "Bump patch version (0.0.x)" },
311
+ { flag: "minor", description: "Bump minor version (0.x.0)" },
312
+ { flag: "major", description: "Bump major version (x.0.0)" },
313
+ { flag: "--dry-run", description: "Preview changes without applying" },
314
+ { flag: "-h, --help", description: "Show this help message" },
315
+ ],
316
+ handler: async (args, flags) => {
317
+ const command = args[0] as versions.VersionCommand | undefined;
318
+ const dryRun = flags["dry-run"] as boolean | undefined;
319
+
320
+ if (command === undefined) {
321
+ const result = await versions.showVersions();
322
+ console.table(result.packages);
323
+ return;
324
+ }
325
+
326
+ const validCommands = ["sync", "patch", "minor", "major"];
327
+ if (!validCommands.includes(command)) {
328
+ console.error(fmtColors.red(`Invalid command: ${command}`));
329
+ console.error(
330
+ "Usage: eser codebase versions [sync|patch|minor|major] [--dry-run]",
331
+ );
332
+ standardsRuntime.runtime.process.exit(1);
333
+ }
334
+
335
+ if (command === "sync") {
336
+ console.log("Syncing all versions...");
337
+ } else {
338
+ console.log(`Bumping all versions (${command})...`);
339
+ }
340
+
341
+ const result = await versions.versions(command, { dryRun });
342
+
343
+ console.log(`Target version: ${result.targetVersion}`);
344
+ console.table(result.updates);
345
+
346
+ if (result.dryRun) {
347
+ console.log(
348
+ fmtColors.cyan(
349
+ `Dry run - ${result.changedCount} packages would be modified.`,
350
+ ),
351
+ );
352
+ } else {
353
+ console.log(`Done. Updated ${result.changedCount} packages.`);
354
+ }
355
+ },
356
+ },
357
+ };
358
+
359
+ const showHelp = (): void => {
360
+ console.log("eser codebase - Codebase validation tools\n");
361
+ console.log("Usage: eser codebase <subcommand> [options]\n");
362
+ console.log("Subcommands:");
363
+ console.log(" check-circular-deps Detect circular package dependencies");
364
+ console.log(" check-mod-exports Validate mod.ts exports all files");
365
+ console.log(" check-export-names Validate export naming conventions");
366
+ console.log(" check-docs Validate JSDoc documentation");
367
+ console.log(" check-licenses Validate license headers");
368
+ console.log(
369
+ " check-package-configs Validate deno.json/package.json consistency",
370
+ );
371
+ console.log(" versions Manage workspace versions");
372
+ console.log(
373
+ "\nRun 'eser codebase <subcommand> --help' for subcommand options.",
374
+ );
375
+ };
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)
382
+ const parsed = cliParseArgs.parseArgs(rawArgs, {
383
+ boolean: ["help", "dry-run", "fix"],
384
+ string: ["root"],
385
+ alias: { h: "help" },
386
+ });
387
+
388
+ const subcommand = parsed._[0] as string | undefined;
389
+
390
+ // Show main help if no subcommand or help without subcommand
391
+ if (subcommand === undefined) {
392
+ showHelp();
393
+ return;
394
+ }
395
+
396
+ const def = subcommands[subcommand];
397
+ if (def === undefined) {
398
+ console.error(fmtColors.red(`Unknown subcommand: ${subcommand}`));
399
+ console.log("");
400
+ showHelp();
401
+ standardsRuntime.runtime.process.exit(1);
402
+ }
403
+
404
+ // Show subcommand help if --help flag
405
+ if (parsed.help) {
406
+ showSubcommandHelp(subcommand, def);
407
+ return;
408
+ }
409
+
410
+ await def.handler(parsed._.slice(1) as string[], parsed);
411
+ };
package/deno.json ADDED
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "@eser/cli",
3
+ "version": "0.8.2",
4
+ "exports": "./main.ts",
5
+ "imports": {
6
+ "@std/cli": "jsr:@std/cli@^1.0.25",
7
+ "@std/fmt": "jsr:@std/fmt@^1.0.8",
8
+ "@std/path": "jsr:@std/path@^1.1.4"
9
+ }
10
+ }
package/main.ts ADDED
@@ -0,0 +1,78 @@
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
+
23
+ type CommandHandler = (
24
+ args: string[],
25
+ flags: Record<string, unknown>,
26
+ ) => Promise<void>;
27
+
28
+ const commands: Record<string, CommandHandler> = {
29
+ codebase: codebaseCommand,
30
+ };
31
+
32
+ const showHelp = (): void => {
33
+ console.log("eser - Versatile development CLI\n");
34
+ console.log("Usage: eser <command> [subcommand] [options]\n");
35
+ console.log("Commands:");
36
+ console.log(" codebase Codebase validation and management tools");
37
+ console.log("\nOptions:");
38
+ console.log(" -h, --help Show this help message");
39
+ console.log(" -v, --version Show version number");
40
+ console.log("\nRun 'eser <command> --help' for command-specific help.");
41
+ };
42
+
43
+ const main = async (): Promise<void> => {
44
+ // @ts-ignore parseArgs doesn't mutate the array, readonly is safe
45
+ const args = cliParseArgs.parseArgs(standardsRuntime.runtime.process.args, {
46
+ boolean: ["help", "version"],
47
+ alias: { h: "help", v: "version" },
48
+ stopEarly: true, // Stop parsing at first non-option to pass rest to subcommand
49
+ });
50
+
51
+ if (args.version) {
52
+ console.log("eser 0.8.0");
53
+ return;
54
+ }
55
+
56
+ const command = args._[0] as string | undefined;
57
+
58
+ // Show main help only if no command or help without command
59
+ if (command === undefined) {
60
+ showHelp();
61
+ return;
62
+ }
63
+
64
+ const handler = commands[command];
65
+ if (handler === undefined) {
66
+ console.error(`Unknown command: ${command}`);
67
+ console.log("");
68
+ showHelp();
69
+ standardsRuntime.runtime.process.exit(1);
70
+ }
71
+
72
+ // Pass remaining args to command handler
73
+ await handler(args._.slice(1) as string[], args);
74
+ };
75
+
76
+ if (import.meta.main) {
77
+ await main();
78
+ }
package/package.json CHANGED
@@ -1,52 +1,16 @@
1
1
  {
2
2
  "name": "eser",
3
- "description": "JavaScript Coding Convention",
4
- "keywords": [
5
- "eser",
6
- "ozvataf",
7
- "eslintconfig"
8
- ],
9
- "version": "0.1.5",
10
- "homepage": "",
11
- "author": "Eser Ozvataf <eser@ozvataf.com>",
12
- "contributors": [
13
- {
14
- "name": "Eser Ozvataf",
15
- "email": "eser@ozvataf.com",
16
- "url": "http://eser.ozvataf.com/"
17
- }
18
- ],
19
- "repository": {
20
- "type": "git",
21
- "url": "git+https://github.com/eserozvataf/eser.git"
22
- },
23
- "bugs": {
24
- "url": "https://github.com/eserozvataf/eser/issues",
25
- "email": "eser@ozvataf.com"
26
- },
27
- "license": "Apache-2.0",
28
- "preferGlobal": true,
29
- "main": "./lib/index.js",
30
- "engines": {
31
- "node": ">=4.2.0"
32
- },
33
- "scripts": {},
34
- "directories": {
35
- "lib": "./lib"
36
- },
37
- "files": [
38
- "lib",
39
- "bin",
40
- ".eslintrc.json",
41
- ".csscomb.json"
42
- ],
3
+ "version": "0.8.2",
4
+ "type": "module",
5
+ "exports": "./main.ts",
43
6
  "bin": {
44
- "eser": "./bin/eser"
7
+ "eser": "./main.ts"
45
8
  },
46
9
  "dependencies": {
47
- "eslint": "^3.8.1",
48
- "standard-engine": "^5.1.1",
49
- "update-notifier": "^1.0.2"
50
- },
51
- "devDependencies": {}
10
+ "@eser/codebase": "npm:@jsr/eser__codebase@^0.8.2",
11
+ "@eser/standards": "npm:@jsr/eser__standards@^0.8.2",
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
+ }
52
16
  }
@@ -0,0 +1,16 @@
1
+ {
2
+ "name": "@eser/cli",
3
+ "version": "0.8.2",
4
+ "type": "module",
5
+ "exports": "./main.ts",
6
+ "bin": {
7
+ "eser": "./main.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
+ }
@@ -0,0 +1,123 @@
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();