@klyper/cli 0.3.0
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 +54 -0
- package/dist/index.cjs +260 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.js +256 -0
- package/package.json +45 -0
package/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# @klyper/cli
|
|
2
|
+
|
|
3
|
+
Command line tools for managing the Klyper monorepo.
|
|
4
|
+
|
|
5
|
+
## Commands
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm run build --workspace @klyper/cli
|
|
9
|
+
npm run check --workspace @klyper/cli
|
|
10
|
+
npm run lint --workspace @klyper/cli
|
|
11
|
+
npm test --workspace @klyper/cli
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
`build` uses Rollup for the package output. `check` runs TypeScript without emitting files.
|
|
15
|
+
|
|
16
|
+
## Create a Package
|
|
17
|
+
|
|
18
|
+
Create a new package template:
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
npm exec klyper create package utils
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Alternative syntax:
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
npm exec klyper package create utils
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The command creates `packages/utils` with:
|
|
31
|
+
|
|
32
|
+
- `package.json`
|
|
33
|
+
- `tsconfig.json`
|
|
34
|
+
- `README.md`
|
|
35
|
+
- `src/index.ts`
|
|
36
|
+
- `src/index.test.ts`
|
|
37
|
+
|
|
38
|
+
The generated `package.json` follows the public package convention used by the
|
|
39
|
+
monorepo:
|
|
40
|
+
|
|
41
|
+
- `main` points to the CommonJS bundle at `./dist/index.cjs`
|
|
42
|
+
- `module` and `exports.import` point to the ESM bundle at `./dist/index.js`
|
|
43
|
+
- `types` and `exports.types` point to `./dist/index.d.ts`
|
|
44
|
+
- `exports.require` points to the CommonJS bundle
|
|
45
|
+
- `sideEffects` is `false`
|
|
46
|
+
- `prepublishOnly` runs `npm run build && npm test`
|
|
47
|
+
|
|
48
|
+
The root build runs each package through npm workspaces, so new packages do not need root TypeScript project references.
|
|
49
|
+
|
|
50
|
+
Use a custom scope:
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
npm exec klyper create package auth --scope @klyper
|
|
54
|
+
```
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*!
|
|
3
|
+
* @klyper/cli v0.3.0
|
|
4
|
+
* Command line tools for the Klyper monorepo.
|
|
5
|
+
* (c) 2026 Andrew Caires
|
|
6
|
+
* @license: MIT
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
var node_fs = require('node:fs');
|
|
12
|
+
var node_url = require('node:url');
|
|
13
|
+
var promises = require('node:fs/promises');
|
|
14
|
+
var node_path = require('node:path');
|
|
15
|
+
|
|
16
|
+
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
17
|
+
const defaultScope = "@klyper";
|
|
18
|
+
const packageNamePattern = /^[a-z][a-z0-9-]*$/;
|
|
19
|
+
const scopePattern = /^@[a-z][a-z0-9-]*$/;
|
|
20
|
+
const helpText = `Klyper CLI
|
|
21
|
+
|
|
22
|
+
Usage:
|
|
23
|
+
klyper create package <name> [--scope @scope]
|
|
24
|
+
klyper package create <name> [--scope @scope]
|
|
25
|
+
|
|
26
|
+
Examples:
|
|
27
|
+
klyper create package utils
|
|
28
|
+
klyper create package auth --scope @klyper
|
|
29
|
+
`;
|
|
30
|
+
const runCli = async (args, io) => {
|
|
31
|
+
try {
|
|
32
|
+
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
33
|
+
io.stdout.write(helpText);
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
const command = parseCreatePackageCommand(args);
|
|
37
|
+
const result = await createPackageTemplate({
|
|
38
|
+
cwd: io.cwd,
|
|
39
|
+
name: command.name,
|
|
40
|
+
scope: command.scope
|
|
41
|
+
});
|
|
42
|
+
io.stdout.write(`Created ${result.packageName} in packages/${result.directoryName}\n`);
|
|
43
|
+
return 0;
|
|
44
|
+
}
|
|
45
|
+
catch (error) {
|
|
46
|
+
io.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
47
|
+
return 1;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
const createPackageTemplate = async (options) => {
|
|
51
|
+
const identifier = parsePackageIdentifier(options.name, options.scope ?? defaultScope);
|
|
52
|
+
const packageRoot = node_path.join(options.cwd, "packages", identifier.directoryName);
|
|
53
|
+
if (await pathExists(packageRoot)) {
|
|
54
|
+
throw new Error(`Package directory already exists: packages/${identifier.directoryName}`);
|
|
55
|
+
}
|
|
56
|
+
const files = buildPackageFiles(identifier);
|
|
57
|
+
await promises.mkdir(node_path.join(packageRoot, "src"), { recursive: true });
|
|
58
|
+
await Promise.all(files.map((file) => promises.writeFile(node_path.join(packageRoot, file.path), file.content)));
|
|
59
|
+
return {
|
|
60
|
+
directoryName: identifier.directoryName,
|
|
61
|
+
packageName: identifier.packageName,
|
|
62
|
+
packageRoot,
|
|
63
|
+
files: files.map((file) => node_path.join(packageRoot, file.path))
|
|
64
|
+
};
|
|
65
|
+
};
|
|
66
|
+
const parseCreatePackageCommand = (args) => {
|
|
67
|
+
const [first, second, third, ...rest] = args;
|
|
68
|
+
const isCreatePackage = first === "create" && second === "package";
|
|
69
|
+
const isPackageCreate = first === "package" && second === "create";
|
|
70
|
+
if (!isCreatePackage && !isPackageCreate) {
|
|
71
|
+
throw new Error("Unknown command. Run `klyper --help` for usage.");
|
|
72
|
+
}
|
|
73
|
+
if (!third) {
|
|
74
|
+
throw new Error("Missing package name.");
|
|
75
|
+
}
|
|
76
|
+
const scope = readScopeOption(rest);
|
|
77
|
+
return { name: third, scope };
|
|
78
|
+
};
|
|
79
|
+
const readScopeOption = (args) => {
|
|
80
|
+
if (args.length === 0) {
|
|
81
|
+
return defaultScope;
|
|
82
|
+
}
|
|
83
|
+
if (args.length === 2 && args[0] === "--scope") {
|
|
84
|
+
return args[1] ?? defaultScope;
|
|
85
|
+
}
|
|
86
|
+
throw new Error(`Unknown option: ${args.join(" ")}`);
|
|
87
|
+
};
|
|
88
|
+
const parsePackageIdentifier = (name, scope) => {
|
|
89
|
+
const trimmedName = name.trim();
|
|
90
|
+
const trimmedScope = scope.trim();
|
|
91
|
+
if (trimmedName.startsWith("@")) {
|
|
92
|
+
const [providedScope, packageName, extra] = trimmedName.split("/");
|
|
93
|
+
if (extra || !providedScope || !packageName) {
|
|
94
|
+
throw new Error("Scoped package names must use the @scope/name format.");
|
|
95
|
+
}
|
|
96
|
+
validateScope(providedScope);
|
|
97
|
+
validatePackageName(packageName);
|
|
98
|
+
return {
|
|
99
|
+
directoryName: packageName,
|
|
100
|
+
packageName: `${providedScope}/${packageName}`
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
validateScope(trimmedScope);
|
|
104
|
+
validatePackageName(trimmedName);
|
|
105
|
+
return {
|
|
106
|
+
directoryName: trimmedName,
|
|
107
|
+
packageName: `${trimmedScope}/${trimmedName}`
|
|
108
|
+
};
|
|
109
|
+
};
|
|
110
|
+
const validatePackageName = (name) => {
|
|
111
|
+
if (!packageNamePattern.test(name)) {
|
|
112
|
+
throw new Error("Package names must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens.");
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
const validateScope = (scope) => {
|
|
116
|
+
if (!scopePattern.test(scope)) {
|
|
117
|
+
throw new Error("Package scopes must use @scope and contain only lowercase letters, numbers, and hyphens.");
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
const buildPackageFiles = (identifier) => {
|
|
121
|
+
return [
|
|
122
|
+
{
|
|
123
|
+
path: "package.json",
|
|
124
|
+
content: `${JSON.stringify({
|
|
125
|
+
name: identifier.packageName,
|
|
126
|
+
version: "0.0.0",
|
|
127
|
+
description: `Klyper ${identifier.directoryName} package.`,
|
|
128
|
+
author: "Andrew Caires",
|
|
129
|
+
license: "MIT",
|
|
130
|
+
repository: {
|
|
131
|
+
type: "git",
|
|
132
|
+
url: "git+https://github.com/andrewcaires/klyper.git"
|
|
133
|
+
},
|
|
134
|
+
type: "module",
|
|
135
|
+
main: "./dist/index.cjs",
|
|
136
|
+
module: "./dist/index.js",
|
|
137
|
+
types: "./dist/index.d.ts",
|
|
138
|
+
exports: {
|
|
139
|
+
".": {
|
|
140
|
+
types: "./dist/index.d.ts",
|
|
141
|
+
import: "./dist/index.js",
|
|
142
|
+
require: "./dist/index.cjs",
|
|
143
|
+
default: "./dist/index.js"
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
sideEffects: false,
|
|
147
|
+
files: ["dist"],
|
|
148
|
+
scripts: {
|
|
149
|
+
build: "npm run clean && npm run check && npm run bundle",
|
|
150
|
+
bundle: "rollup --bundleConfigAsCjs -c ../../rollup.config.js",
|
|
151
|
+
check: "npm run lint && npm run typecheck",
|
|
152
|
+
clean: "rm -rf dist",
|
|
153
|
+
lint: "eslint .",
|
|
154
|
+
"lint:fix": "eslint . --fix",
|
|
155
|
+
prepublishOnly: "npm run build && npm test",
|
|
156
|
+
test: "node --import tsx --test \"src/**/*.test.ts\"",
|
|
157
|
+
"test:watch": "node --import tsx --test --watch \"src/**/*.test.ts\"",
|
|
158
|
+
typecheck: "tsc -p tsconfig.json --noEmit"
|
|
159
|
+
},
|
|
160
|
+
publishConfig: {
|
|
161
|
+
access: "public"
|
|
162
|
+
}
|
|
163
|
+
}, null, 2)}\n`
|
|
164
|
+
},
|
|
165
|
+
{
|
|
166
|
+
path: "README.md",
|
|
167
|
+
content: `# ${identifier.packageName}
|
|
168
|
+
|
|
169
|
+
Klyper ${identifier.directoryName} package.
|
|
170
|
+
|
|
171
|
+
## Installation
|
|
172
|
+
|
|
173
|
+
\`\`\`sh
|
|
174
|
+
npm install ${identifier.packageName}
|
|
175
|
+
\`\`\`
|
|
176
|
+
|
|
177
|
+
This package is published as an ES module package and also exposes a CommonJS
|
|
178
|
+
entry through \`main\` and \`exports.require\`.
|
|
179
|
+
|
|
180
|
+
## Commands
|
|
181
|
+
|
|
182
|
+
\`\`\`sh
|
|
183
|
+
npm run build --workspace ${identifier.packageName}
|
|
184
|
+
npm run check --workspace ${identifier.packageName}
|
|
185
|
+
npm run lint --workspace ${identifier.packageName}
|
|
186
|
+
npm test --workspace ${identifier.packageName}
|
|
187
|
+
\`\`\`
|
|
188
|
+
|
|
189
|
+
\`build\` uses Rollup for the package output. \`check\` runs TypeScript without emitting files.
|
|
190
|
+
\`prepublishOnly\` runs the package build and test suite before npm publish.
|
|
191
|
+
|
|
192
|
+
## API
|
|
193
|
+
|
|
194
|
+
\`\`\`ts
|
|
195
|
+
import { getPackageName } from "${identifier.packageName}";
|
|
196
|
+
|
|
197
|
+
getPackageName();
|
|
198
|
+
\`\`\`
|
|
199
|
+
`
|
|
200
|
+
},
|
|
201
|
+
{
|
|
202
|
+
path: "tsconfig.json",
|
|
203
|
+
content: `${JSON.stringify({
|
|
204
|
+
extends: "../../tsconfig.base.json",
|
|
205
|
+
compilerOptions: {
|
|
206
|
+
outDir: "dist",
|
|
207
|
+
rootDir: "src"
|
|
208
|
+
},
|
|
209
|
+
include: ["src/**/*.ts"],
|
|
210
|
+
}, null, 2)}\n`
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
path: "src/index.ts",
|
|
214
|
+
content: `export const getPackageName = (): string => {
|
|
215
|
+
return "${identifier.packageName}";
|
|
216
|
+
};
|
|
217
|
+
`
|
|
218
|
+
},
|
|
219
|
+
{
|
|
220
|
+
path: "src/index.test.ts",
|
|
221
|
+
content: `import { equal } from "node:assert/strict";
|
|
222
|
+
import test from "node:test";
|
|
223
|
+
|
|
224
|
+
import { getPackageName } from "./index.js";
|
|
225
|
+
|
|
226
|
+
test("getPackageName returns the package name", () => {
|
|
227
|
+
equal(getPackageName(), "${identifier.packageName}");
|
|
228
|
+
});
|
|
229
|
+
`
|
|
230
|
+
}
|
|
231
|
+
];
|
|
232
|
+
};
|
|
233
|
+
const pathExists = async (path) => {
|
|
234
|
+
try {
|
|
235
|
+
await promises.stat(path);
|
|
236
|
+
return true;
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
throw error;
|
|
243
|
+
}
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const isCliEntryPoint = () => {
|
|
247
|
+
return !!process.argv[1] && node_fs.realpathSync(process.argv[1]) === node_url.fileURLToPath((typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.cjs', document.baseURI).href)));
|
|
248
|
+
};
|
|
249
|
+
if (isCliEntryPoint()) {
|
|
250
|
+
void runCli(process.argv.slice(2), {
|
|
251
|
+
cwd: process.cwd(),
|
|
252
|
+
stdout: process.stdout,
|
|
253
|
+
stderr: process.stderr
|
|
254
|
+
}).then((exitCode) => {
|
|
255
|
+
process.exitCode = exitCode;
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
exports.createPackageTemplate = createPackageTemplate;
|
|
260
|
+
exports.runCli = runCli;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* @klyper/cli v0.3.0
|
|
3
|
+
* Command line tools for the Klyper monorepo.
|
|
4
|
+
* (c) 2026 Andrew Caires
|
|
5
|
+
* @license: MIT
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
type Writable = {
|
|
9
|
+
write: (_chunk: string) => void;
|
|
10
|
+
};
|
|
11
|
+
type CliIo = {
|
|
12
|
+
cwd: string;
|
|
13
|
+
stdout: Writable;
|
|
14
|
+
stderr: Writable;
|
|
15
|
+
};
|
|
16
|
+
type PackageTemplateResult = {
|
|
17
|
+
directoryName: string;
|
|
18
|
+
packageName: string;
|
|
19
|
+
packageRoot: string;
|
|
20
|
+
files: string[];
|
|
21
|
+
};
|
|
22
|
+
declare const runCli: (args: string[], io: CliIo) => Promise<number>;
|
|
23
|
+
declare const createPackageTemplate: (options: {
|
|
24
|
+
cwd: string;
|
|
25
|
+
name: string;
|
|
26
|
+
scope?: string;
|
|
27
|
+
}) => Promise<PackageTemplateResult>;
|
|
28
|
+
|
|
29
|
+
export { createPackageTemplate, runCli };
|
|
30
|
+
export type { CliIo, PackageTemplateResult };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/*!
|
|
3
|
+
* @klyper/cli v0.3.0
|
|
4
|
+
* Command line tools for the Klyper monorepo.
|
|
5
|
+
* (c) 2026 Andrew Caires
|
|
6
|
+
* @license: MIT
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { realpathSync } from 'node:fs';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
11
|
+
import { mkdir, writeFile, stat } from 'node:fs/promises';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
|
|
14
|
+
const defaultScope = "@klyper";
|
|
15
|
+
const packageNamePattern = /^[a-z][a-z0-9-]*$/;
|
|
16
|
+
const scopePattern = /^@[a-z][a-z0-9-]*$/;
|
|
17
|
+
const helpText = `Klyper CLI
|
|
18
|
+
|
|
19
|
+
Usage:
|
|
20
|
+
klyper create package <name> [--scope @scope]
|
|
21
|
+
klyper package create <name> [--scope @scope]
|
|
22
|
+
|
|
23
|
+
Examples:
|
|
24
|
+
klyper create package utils
|
|
25
|
+
klyper create package auth --scope @klyper
|
|
26
|
+
`;
|
|
27
|
+
const runCli = async (args, io) => {
|
|
28
|
+
try {
|
|
29
|
+
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
30
|
+
io.stdout.write(helpText);
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
const command = parseCreatePackageCommand(args);
|
|
34
|
+
const result = await createPackageTemplate({
|
|
35
|
+
cwd: io.cwd,
|
|
36
|
+
name: command.name,
|
|
37
|
+
scope: command.scope
|
|
38
|
+
});
|
|
39
|
+
io.stdout.write(`Created ${result.packageName} in packages/${result.directoryName}\n`);
|
|
40
|
+
return 0;
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
io.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
|
44
|
+
return 1;
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const createPackageTemplate = async (options) => {
|
|
48
|
+
const identifier = parsePackageIdentifier(options.name, options.scope ?? defaultScope);
|
|
49
|
+
const packageRoot = join(options.cwd, "packages", identifier.directoryName);
|
|
50
|
+
if (await pathExists(packageRoot)) {
|
|
51
|
+
throw new Error(`Package directory already exists: packages/${identifier.directoryName}`);
|
|
52
|
+
}
|
|
53
|
+
const files = buildPackageFiles(identifier);
|
|
54
|
+
await mkdir(join(packageRoot, "src"), { recursive: true });
|
|
55
|
+
await Promise.all(files.map((file) => writeFile(join(packageRoot, file.path), file.content)));
|
|
56
|
+
return {
|
|
57
|
+
directoryName: identifier.directoryName,
|
|
58
|
+
packageName: identifier.packageName,
|
|
59
|
+
packageRoot,
|
|
60
|
+
files: files.map((file) => join(packageRoot, file.path))
|
|
61
|
+
};
|
|
62
|
+
};
|
|
63
|
+
const parseCreatePackageCommand = (args) => {
|
|
64
|
+
const [first, second, third, ...rest] = args;
|
|
65
|
+
const isCreatePackage = first === "create" && second === "package";
|
|
66
|
+
const isPackageCreate = first === "package" && second === "create";
|
|
67
|
+
if (!isCreatePackage && !isPackageCreate) {
|
|
68
|
+
throw new Error("Unknown command. Run `klyper --help` for usage.");
|
|
69
|
+
}
|
|
70
|
+
if (!third) {
|
|
71
|
+
throw new Error("Missing package name.");
|
|
72
|
+
}
|
|
73
|
+
const scope = readScopeOption(rest);
|
|
74
|
+
return { name: third, scope };
|
|
75
|
+
};
|
|
76
|
+
const readScopeOption = (args) => {
|
|
77
|
+
if (args.length === 0) {
|
|
78
|
+
return defaultScope;
|
|
79
|
+
}
|
|
80
|
+
if (args.length === 2 && args[0] === "--scope") {
|
|
81
|
+
return args[1] ?? defaultScope;
|
|
82
|
+
}
|
|
83
|
+
throw new Error(`Unknown option: ${args.join(" ")}`);
|
|
84
|
+
};
|
|
85
|
+
const parsePackageIdentifier = (name, scope) => {
|
|
86
|
+
const trimmedName = name.trim();
|
|
87
|
+
const trimmedScope = scope.trim();
|
|
88
|
+
if (trimmedName.startsWith("@")) {
|
|
89
|
+
const [providedScope, packageName, extra] = trimmedName.split("/");
|
|
90
|
+
if (extra || !providedScope || !packageName) {
|
|
91
|
+
throw new Error("Scoped package names must use the @scope/name format.");
|
|
92
|
+
}
|
|
93
|
+
validateScope(providedScope);
|
|
94
|
+
validatePackageName(packageName);
|
|
95
|
+
return {
|
|
96
|
+
directoryName: packageName,
|
|
97
|
+
packageName: `${providedScope}/${packageName}`
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
validateScope(trimmedScope);
|
|
101
|
+
validatePackageName(trimmedName);
|
|
102
|
+
return {
|
|
103
|
+
directoryName: trimmedName,
|
|
104
|
+
packageName: `${trimmedScope}/${trimmedName}`
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
const validatePackageName = (name) => {
|
|
108
|
+
if (!packageNamePattern.test(name)) {
|
|
109
|
+
throw new Error("Package names must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens.");
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
const validateScope = (scope) => {
|
|
113
|
+
if (!scopePattern.test(scope)) {
|
|
114
|
+
throw new Error("Package scopes must use @scope and contain only lowercase letters, numbers, and hyphens.");
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
const buildPackageFiles = (identifier) => {
|
|
118
|
+
return [
|
|
119
|
+
{
|
|
120
|
+
path: "package.json",
|
|
121
|
+
content: `${JSON.stringify({
|
|
122
|
+
name: identifier.packageName,
|
|
123
|
+
version: "0.0.0",
|
|
124
|
+
description: `Klyper ${identifier.directoryName} package.`,
|
|
125
|
+
author: "Andrew Caires",
|
|
126
|
+
license: "MIT",
|
|
127
|
+
repository: {
|
|
128
|
+
type: "git",
|
|
129
|
+
url: "git+https://github.com/andrewcaires/klyper.git"
|
|
130
|
+
},
|
|
131
|
+
type: "module",
|
|
132
|
+
main: "./dist/index.cjs",
|
|
133
|
+
module: "./dist/index.js",
|
|
134
|
+
types: "./dist/index.d.ts",
|
|
135
|
+
exports: {
|
|
136
|
+
".": {
|
|
137
|
+
types: "./dist/index.d.ts",
|
|
138
|
+
import: "./dist/index.js",
|
|
139
|
+
require: "./dist/index.cjs",
|
|
140
|
+
default: "./dist/index.js"
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
sideEffects: false,
|
|
144
|
+
files: ["dist"],
|
|
145
|
+
scripts: {
|
|
146
|
+
build: "npm run clean && npm run check && npm run bundle",
|
|
147
|
+
bundle: "rollup --bundleConfigAsCjs -c ../../rollup.config.js",
|
|
148
|
+
check: "npm run lint && npm run typecheck",
|
|
149
|
+
clean: "rm -rf dist",
|
|
150
|
+
lint: "eslint .",
|
|
151
|
+
"lint:fix": "eslint . --fix",
|
|
152
|
+
prepublishOnly: "npm run build && npm test",
|
|
153
|
+
test: "node --import tsx --test \"src/**/*.test.ts\"",
|
|
154
|
+
"test:watch": "node --import tsx --test --watch \"src/**/*.test.ts\"",
|
|
155
|
+
typecheck: "tsc -p tsconfig.json --noEmit"
|
|
156
|
+
},
|
|
157
|
+
publishConfig: {
|
|
158
|
+
access: "public"
|
|
159
|
+
}
|
|
160
|
+
}, null, 2)}\n`
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
path: "README.md",
|
|
164
|
+
content: `# ${identifier.packageName}
|
|
165
|
+
|
|
166
|
+
Klyper ${identifier.directoryName} package.
|
|
167
|
+
|
|
168
|
+
## Installation
|
|
169
|
+
|
|
170
|
+
\`\`\`sh
|
|
171
|
+
npm install ${identifier.packageName}
|
|
172
|
+
\`\`\`
|
|
173
|
+
|
|
174
|
+
This package is published as an ES module package and also exposes a CommonJS
|
|
175
|
+
entry through \`main\` and \`exports.require\`.
|
|
176
|
+
|
|
177
|
+
## Commands
|
|
178
|
+
|
|
179
|
+
\`\`\`sh
|
|
180
|
+
npm run build --workspace ${identifier.packageName}
|
|
181
|
+
npm run check --workspace ${identifier.packageName}
|
|
182
|
+
npm run lint --workspace ${identifier.packageName}
|
|
183
|
+
npm test --workspace ${identifier.packageName}
|
|
184
|
+
\`\`\`
|
|
185
|
+
|
|
186
|
+
\`build\` uses Rollup for the package output. \`check\` runs TypeScript without emitting files.
|
|
187
|
+
\`prepublishOnly\` runs the package build and test suite before npm publish.
|
|
188
|
+
|
|
189
|
+
## API
|
|
190
|
+
|
|
191
|
+
\`\`\`ts
|
|
192
|
+
import { getPackageName } from "${identifier.packageName}";
|
|
193
|
+
|
|
194
|
+
getPackageName();
|
|
195
|
+
\`\`\`
|
|
196
|
+
`
|
|
197
|
+
},
|
|
198
|
+
{
|
|
199
|
+
path: "tsconfig.json",
|
|
200
|
+
content: `${JSON.stringify({
|
|
201
|
+
extends: "../../tsconfig.base.json",
|
|
202
|
+
compilerOptions: {
|
|
203
|
+
outDir: "dist",
|
|
204
|
+
rootDir: "src"
|
|
205
|
+
},
|
|
206
|
+
include: ["src/**/*.ts"],
|
|
207
|
+
}, null, 2)}\n`
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
path: "src/index.ts",
|
|
211
|
+
content: `export const getPackageName = (): string => {
|
|
212
|
+
return "${identifier.packageName}";
|
|
213
|
+
};
|
|
214
|
+
`
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
path: "src/index.test.ts",
|
|
218
|
+
content: `import { equal } from "node:assert/strict";
|
|
219
|
+
import test from "node:test";
|
|
220
|
+
|
|
221
|
+
import { getPackageName } from "./index.js";
|
|
222
|
+
|
|
223
|
+
test("getPackageName returns the package name", () => {
|
|
224
|
+
equal(getPackageName(), "${identifier.packageName}");
|
|
225
|
+
});
|
|
226
|
+
`
|
|
227
|
+
}
|
|
228
|
+
];
|
|
229
|
+
};
|
|
230
|
+
const pathExists = async (path) => {
|
|
231
|
+
try {
|
|
232
|
+
await stat(path);
|
|
233
|
+
return true;
|
|
234
|
+
}
|
|
235
|
+
catch (error) {
|
|
236
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
const isCliEntryPoint = () => {
|
|
244
|
+
return !!process.argv[1] && realpathSync(process.argv[1]) === fileURLToPath(import.meta.url);
|
|
245
|
+
};
|
|
246
|
+
if (isCliEntryPoint()) {
|
|
247
|
+
void runCli(process.argv.slice(2), {
|
|
248
|
+
cwd: process.cwd(),
|
|
249
|
+
stdout: process.stdout,
|
|
250
|
+
stderr: process.stderr
|
|
251
|
+
}).then((exitCode) => {
|
|
252
|
+
process.exitCode = exitCode;
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
export { createPackageTemplate, runCli };
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@klyper/cli",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Command line tools for the Klyper monorepo.",
|
|
5
|
+
"author": "Andrew Caires",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/andrewcaires/klyper.git"
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"bin": {
|
|
13
|
+
"klyper": "dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"main": "./dist/index.cjs",
|
|
16
|
+
"module": "./dist/index.js",
|
|
17
|
+
"types": "./dist/index.d.ts",
|
|
18
|
+
"exports": {
|
|
19
|
+
".": {
|
|
20
|
+
"types": "./dist/index.d.ts",
|
|
21
|
+
"import": "./dist/index.js",
|
|
22
|
+
"require": "./dist/index.cjs",
|
|
23
|
+
"default": "./dist/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"sideEffects": false,
|
|
27
|
+
"files": [
|
|
28
|
+
"dist"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"build": "npm run clean && npm run check && npm run bundle",
|
|
32
|
+
"bundle": "rollup --bundleConfigAsCjs -c ../../rollup.config.js && chmod +x dist/index.js",
|
|
33
|
+
"check": "npm run lint && npm run typecheck",
|
|
34
|
+
"clean": "rm -rf dist",
|
|
35
|
+
"lint": "eslint .",
|
|
36
|
+
"lint:fix": "eslint . --fix",
|
|
37
|
+
"prepublishOnly": "npm run build && npm test",
|
|
38
|
+
"test": "node --import tsx --test \"src/**/*.test.ts\"",
|
|
39
|
+
"test:watch": "node --import tsx --test --watch \"src/**/*.test.ts\"",
|
|
40
|
+
"typecheck": "tsc -p tsconfig.json --noEmit"
|
|
41
|
+
},
|
|
42
|
+
"publishConfig": {
|
|
43
|
+
"access": "public"
|
|
44
|
+
}
|
|
45
|
+
}
|