screw-up 0.7.1 → 0.9.1

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 CHANGED
@@ -48,6 +48,8 @@ To insert banner header each bundled source files (`dist/index.js` and etc.):
48
48
  * Flexible output: Specify exactly which keys to include and in what order.
49
49
  * Nested object support: Handles nested objects like `author.name`, `repository.url`.
50
50
  * Customizable: Choose which metadata fields to include in your banner.
51
+ * TypeScript metadata generation: Automatically generates TypeScript files with metadata constants for use in your source code.
52
+ * Supported pack/publish CLI interface. When publishing using this feature, the package is generated after applying the above processing to `package.json`.
51
53
 
52
54
  ## Installation
53
55
 
@@ -155,6 +157,66 @@ Results in:
155
157
  */
156
158
  ```
157
159
 
160
+ ### TypeScript Metadata Generation
161
+
162
+ The plugin can generate TypeScript files containing metadata constants that you can import and use in your source code:
163
+
164
+ ```typescript
165
+ import { defineConfig } from 'vite';
166
+ import screwUp from 'screw-up';
167
+
168
+ export default defineConfig({
169
+ plugins: [
170
+ screwUp({
171
+ outputMetadataFile: true, // Enable metadata file generation
172
+ outputMetadataFilePath: 'src/generated/packageMetadata.ts', // Custom path (optional)
173
+ outputMetadataKeys: ['name', 'version', 'description', 'author', 'license'] // Keys to include
174
+ })
175
+ ],
176
+ build: {
177
+ lib: {
178
+ entry: 'src/index.ts',
179
+ name: 'MyLibrary',
180
+ fileName: 'index'
181
+ }
182
+ }
183
+ });
184
+ ```
185
+
186
+ This generates `src/generated/packageMetadata.ts` with sanitized TypeScript constants:
187
+
188
+ ```typescript
189
+ // This file is auto-generated by screw-up plugin
190
+ // Do not edit manually
191
+
192
+ export const name = "my-awesome-library";
193
+ export const version = "2.1.0";
194
+ export const description = "An awesome TypeScript library";
195
+ export const author = "Jane Developer <jane@example.com>";
196
+ export const license = "Apache-2.0";
197
+ ```
198
+
199
+ You can then import and use these constants in your source code:
200
+
201
+ ```typescript
202
+ import { name, version } from './generated/packageMetadata.js';
203
+
204
+ console.log(`${name} v${version}`);
205
+ // Output: my-awesome-library v2.1.0
206
+
207
+ export function getLibraryInfo() {
208
+ return { name, version };
209
+ }
210
+ ```
211
+
212
+ #### Key Sanitization
213
+
214
+ Keys with special characters are automatically sanitized to valid TypeScript identifiers:
215
+
216
+ - `repository.url` → `repository_url`
217
+ - `custom-key` → `custom_key`
218
+ - `123invalid` → `_123invalid`
219
+
158
220
  ----
159
221
 
160
222
  ## Advanced Usage
@@ -234,6 +296,84 @@ The plugin automatically detects and supports:
234
296
 
235
297
  ----
236
298
 
299
+ ## CLI Usage
300
+
301
+ The `screw-up` package includes a command-line interface for packaging and publishing your projects.
302
+
303
+ ### Pack Command
304
+
305
+ Create a tar archive of your project:
306
+
307
+ ```bash
308
+ # Pack current directory
309
+ screw-up pack
310
+
311
+ # Pack specific directory
312
+ screw-up pack ./my-project
313
+
314
+ # Pack to specific output directory
315
+ screw-up pack --pack-destination ./dist
316
+ ```
317
+
318
+ The pack command:
319
+
320
+ - Automatically reads `package.json` for metadata and file inclusion rules
321
+ - Respects the `files` field in your `package.json`
322
+ - Supports workspace inheritance (inherits metadata from parent packages)
323
+ - Creates a compressed `.tgz` archive with format: `{name}-{version}.tgz`
324
+
325
+ ### Publish Command
326
+
327
+ Publish your project to registry server:
328
+
329
+ ```bash
330
+ # Publish current directory (creates archive and publishes)
331
+ screw-up publish
332
+
333
+ # Publish specific directory
334
+ screw-up publish ./my-project
335
+
336
+ # Publish existing tarball
337
+ screw-up publish package.tgz
338
+
339
+ # Publish with npm options (all npm publish options are supported)
340
+ screw-up publish --dry-run --tag beta --access public
341
+ ```
342
+
343
+ The publish command:
344
+
345
+ - Supports all `npm publish` options transparently
346
+ - Can publish from directory (automatically creates archive) or existing tarball
347
+ - Handles workspace packages with proper metadata inheritance
348
+ - Uses the same packaging logic as the pack command
349
+
350
+ ### Examples
351
+
352
+ ```bash
353
+ # Build and publish with dry run
354
+ screw-up publish --dry-run
355
+
356
+ # Publish to beta channel
357
+ screw-up publish --tag beta
358
+
359
+ # Publish scoped package as public
360
+ screw-up publish --access public
361
+
362
+ # Pack to custom directory then publish
363
+ screw-up pack --pack-destination ./release
364
+ screw-up publish ./release/my-package-1.0.0.tgz
365
+ ```
366
+
367
+ For help with any command:
368
+
369
+ ```bash
370
+ screw-up --help
371
+ screw-up pack --help
372
+ screw-up publish --help
373
+ ```
374
+
375
+ ----
376
+
237
377
  ## License
238
378
 
239
- Under MIT
379
+ Under MIT
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Pack assets into a tar archive
3
+ * @param targetDir - Target directory to pack
4
+ * @param outputDir - Output directory to write the tarball
5
+ * @returns Package metadata (package.json) or undefined if failed
6
+ */
7
+ export declare const packAssets: (targetDir: string, outputDir: string) => Promise<any>;
8
+ export interface ParsedArgs {
9
+ command?: string;
10
+ positional: string[];
11
+ options: Record<string, string | boolean>;
12
+ }
13
+ export declare const parseArgs: (argv: string[]) => ParsedArgs;
14
+ //# sourceMappingURL=cli-internal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli-internal.d.ts","sourceRoot":"","sources":["../src/cli-internal.ts"],"names":[],"mappings":"AAyCA;;;;;GAKG;AACH,eAAO,MAAM,UAAU,GAAU,WAAW,MAAM,EAAE,WAAW,MAAM,KAAI,OAAO,CAAC,GAAG,CA2EnF,CAAC;AAIF,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC;CAC3C;AAED,eAAO,MAAM,SAAS,GAAI,MAAM,MAAM,EAAE,KAAG,UAoE1C,CAAC"}
package/dist/cli.cjs ADDED
@@ -0,0 +1,343 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ const path = require("path");
4
+ const fs = require("fs");
5
+ const promises = require("fs/promises");
6
+ const child_process = require("child_process");
7
+ const glob = require("glob");
8
+ const internal = require("./internal-BJ2gdqpB.cjs");
9
+ const tar = require("tar-stream");
10
+ const zlib = require("zlib");
11
+ const addPackContentEntry = async (pack, name, content) => {
12
+ pack.entry({
13
+ name,
14
+ type: "file",
15
+ mode: 420,
16
+ mtime: /* @__PURE__ */ new Date(),
17
+ size: Buffer.byteLength(content, "utf8")
18
+ }, content);
19
+ };
20
+ const addPackFileEntry = async (pack, baseDir, path$1, stat) => {
21
+ const writer = pack.entry({
22
+ name: path$1,
23
+ mode: stat.mode,
24
+ mtime: stat.mtime,
25
+ size: stat.size
26
+ });
27
+ const stream = fs.createReadStream(path.resolve(baseDir, path$1));
28
+ stream.pipe(writer);
29
+ return new Promise((resolve2, reject) => {
30
+ stream.on("end", resolve2);
31
+ stream.on("error", reject);
32
+ writer.on("error", reject);
33
+ });
34
+ };
35
+ const packAssets = async (targetDir, outputDir) => {
36
+ var _a, _b, _c, _d;
37
+ if (!fs.existsSync(targetDir)) {
38
+ return void 0;
39
+ }
40
+ let resolvedPackageJson;
41
+ try {
42
+ resolvedPackageJson = await internal.resolveRawPackageJson(targetDir);
43
+ } catch (error) {
44
+ return void 0;
45
+ }
46
+ if (resolvedPackageJson == null ? void 0 : resolvedPackageJson.private) {
47
+ return void 0;
48
+ }
49
+ const outputFileName = `${(_b = (_a = resolvedPackageJson == null ? void 0 : resolvedPackageJson.name) == null ? void 0 : _a.replace("/", "-")) != null ? _b : "package"}-${(_c = resolvedPackageJson == null ? void 0 : resolvedPackageJson.version) != null ? _c : "0.0.0"}.tgz`;
50
+ const pack = tar.pack();
51
+ try {
52
+ const packageJsonContent = JSON.stringify(resolvedPackageJson, null, 2);
53
+ await addPackContentEntry(pack, "package.json", packageJsonContent);
54
+ const distributionFileGlobs = (_d = resolvedPackageJson == null ? void 0 : resolvedPackageJson.files) != null ? _d : ["**/*"];
55
+ const packingFilePaths = distributionFileGlobs.map((fg) => glob.glob.sync(fg, { cwd: targetDir })).flat();
56
+ for (const packingFilePath of packingFilePaths) {
57
+ const fullPath = path.resolve(targetDir, packingFilePath);
58
+ const stat = await promises.lstat(fullPath);
59
+ if (stat.isFile() && packingFilePath !== "package.json") {
60
+ await addPackFileEntry(pack, targetDir, packingFilePath, stat);
61
+ }
62
+ }
63
+ pack.finalize();
64
+ if (!fs.existsSync(outputDir)) {
65
+ await promises.mkdir(outputDir, { recursive: true });
66
+ }
67
+ const outputFile = path.resolve(outputDir, outputFileName);
68
+ const outputStream = fs.createWriteStream(outputFile);
69
+ const gzip = zlib.createGzip();
70
+ await new Promise((resolve2, reject) => {
71
+ pack.pipe(gzip).pipe(outputStream);
72
+ outputStream.on("finish", () => resolve2());
73
+ outputStream.on("error", reject);
74
+ pack.on("error", reject);
75
+ gzip.on("error", reject);
76
+ });
77
+ } finally {
78
+ pack.destroy();
79
+ }
80
+ return resolvedPackageJson;
81
+ };
82
+ const parseArgs = (argv) => {
83
+ const args = argv.slice(2);
84
+ const result = {
85
+ positional: [],
86
+ options: {}
87
+ };
88
+ if (args.length === 0) {
89
+ return result;
90
+ }
91
+ if (args[0].startsWith("-")) {
92
+ let i2 = 0;
93
+ while (i2 < args.length) {
94
+ const arg = args[i2];
95
+ if (arg.startsWith("--")) {
96
+ const optionName = arg.slice(2);
97
+ const nextArg = args[i2 + 1];
98
+ if (nextArg && !nextArg.startsWith("-")) {
99
+ result.options[optionName] = nextArg;
100
+ i2 += 2;
101
+ } else {
102
+ result.options[optionName] = true;
103
+ i2 += 1;
104
+ }
105
+ } else if (arg.startsWith("-")) {
106
+ const optionName = arg.slice(1);
107
+ result.options[optionName] = true;
108
+ i2 += 1;
109
+ } else {
110
+ result.positional.push(arg);
111
+ i2 += 1;
112
+ }
113
+ }
114
+ return result;
115
+ }
116
+ result.command = args[0];
117
+ let i = 1;
118
+ while (i < args.length) {
119
+ const arg = args[i];
120
+ if (arg.startsWith("--")) {
121
+ const optionName = arg.slice(2);
122
+ const nextArg = args[i + 1];
123
+ if (nextArg && !nextArg.startsWith("-")) {
124
+ result.options[optionName] = nextArg;
125
+ i += 2;
126
+ } else {
127
+ result.options[optionName] = true;
128
+ i += 1;
129
+ }
130
+ } else if (arg.startsWith("-")) {
131
+ const optionName = arg.slice(1);
132
+ result.options[optionName] = true;
133
+ i += 1;
134
+ } else {
135
+ result.positional.push(arg);
136
+ i += 1;
137
+ }
138
+ }
139
+ return result;
140
+ };
141
+ const showHelp = () => {
142
+ console.log(`screw-up - Easy package metadata inserter CLI [${"0.9.1"}]
143
+ Copyright (c) ${"Kouji Matsui (@kekyo@mi.kekyo.net)"}
144
+ Repository: ${"https://github.com/kekyo/screw-up.git"}
145
+ License: ${"MIT"}
146
+
147
+ Usage: screw-up <command> [options]
148
+
149
+ Commands:
150
+ pack [directory] Pack the project into a tar archive
151
+ publish [directory|package.tgz] Publish the project
152
+
153
+ Options:
154
+ -h, --help Show help
155
+
156
+ Pack Options:
157
+ --pack-destination <path> Directory to write the tarball
158
+
159
+ Publish Options:
160
+ All npm publish options are supported (e.g., --dry-run, --tag, --access, --registry)
161
+
162
+ Examples:
163
+ screw-up pack # Pack current directory
164
+ screw-up pack ./my-project # Pack specific directory
165
+ screw-up pack --pack-destination ./dist # Pack to specific output directory
166
+ screw-up publish # Publish current directory
167
+ screw-up publish ./my-project # Publish specific directory
168
+ screw-up publish package.tgz # Publish existing tarball
169
+ screw-up publish --dry-run --tag beta # Publish with npm options
170
+ `);
171
+ };
172
+ const showPackHelp = () => {
173
+ console.log(`Usage: screw-up pack [options] [directory]
174
+
175
+ Pack the project into a tar archive
176
+
177
+ Arguments:
178
+ directory Directory to pack (default: current directory)
179
+
180
+ Options:
181
+ --pack-destination <path> Directory to write the tarball
182
+ -h, --help Show help for pack command
183
+ `);
184
+ };
185
+ const showPublishHelp = () => {
186
+ console.log(`Usage: screw-up publish [options] [directory|package.tgz]
187
+
188
+ Publish the project
189
+
190
+ Arguments:
191
+ directory|package.tgz Directory to pack and publish, or existing tarball to publish
192
+
193
+ Options:
194
+ All npm publish options are supported, including:
195
+ --dry-run Perform a dry run
196
+ --tag <tag> Tag for the published version
197
+ --access <access> Access level (public or restricted)
198
+ --registry <registry> Registry URL
199
+ -h, --help Show help for publish command
200
+
201
+ Examples:
202
+ screw-up publish # Publish current directory
203
+ screw-up publish ./my-project # Publish specific directory
204
+ screw-up publish package.tgz # Publish existing tarball
205
+ screw-up publish --dry-run --tag beta # Publish with options
206
+ `);
207
+ };
208
+ const packCommand = async (args) => {
209
+ if (args.options.help || args.options.h) {
210
+ showPackHelp();
211
+ return;
212
+ }
213
+ const directory = args.positional[0];
214
+ const packDestination = args.options["pack-destination"];
215
+ const targetDir = path.resolve(directory != null ? directory : process.cwd());
216
+ const outputDir = packDestination ? path.resolve(packDestination) : process.cwd();
217
+ console.log(`[screw-up/cli]: pack: Creating archive of ${targetDir}...`);
218
+ try {
219
+ const metadata = await packAssets(targetDir, outputDir);
220
+ if (metadata) {
221
+ console.log(`[screw-up/cli]: pack: Archive created successfully: ${outputDir}`);
222
+ } else {
223
+ console.error(`[screw-up/cli]: pack: Unable to find any files to pack: ${targetDir}`);
224
+ process.exit(1);
225
+ }
226
+ } catch (error) {
227
+ console.error("[screw-up/cli]: pack: Failed to create archive:", error);
228
+ process.exit(1);
229
+ }
230
+ };
231
+ const publishCommand = async (args) => {
232
+ if (args.options.help || args.options.h) {
233
+ showPublishHelp();
234
+ return;
235
+ }
236
+ const runNpmPublish = async (tarballPath, npmOptions2 = []) => {
237
+ console.log(`[screw-up/cli]: publish: Publishing ${tarballPath} to npm...`);
238
+ const publishArgs = ["publish", tarballPath, ...npmOptions2];
239
+ if (process.env.SCREW_UP_TEST_MODE === "true") {
240
+ console.log(`[screw-up/cli]: TEST_MODE: Would execute: npm ${publishArgs.join(" ")}`);
241
+ console.log(`[screw-up/cli]: TEST_MODE: Tarball path: ${tarballPath}`);
242
+ console.log(`[screw-up/cli]: TEST_MODE: Options: ${npmOptions2.join(" ")}`);
243
+ console.log(`[screw-up/cli]: publish: Successfully published ${tarballPath}`);
244
+ return;
245
+ }
246
+ const npmProcess = child_process.spawn("npm", publishArgs, { stdio: "inherit" });
247
+ return new Promise((resolve2, reject) => {
248
+ npmProcess.on("close", (code) => {
249
+ if (code === 0) {
250
+ console.log(`[screw-up/cli]: publish: Successfully published ${tarballPath}`);
251
+ resolve2();
252
+ } else {
253
+ reject(new Error(`npm publish failed with exit code ${code}`));
254
+ }
255
+ });
256
+ npmProcess.on("error", reject);
257
+ });
258
+ };
259
+ const path$1 = args.positional[0];
260
+ const npmOptions = [];
261
+ Object.entries(args.options).forEach(([key, value]) => {
262
+ if (key === "help" || key === "h") return;
263
+ if (value === true) {
264
+ npmOptions.push(`--${key}`);
265
+ } else {
266
+ npmOptions.push(`--${key}`, value);
267
+ }
268
+ });
269
+ try {
270
+ if (!path$1) {
271
+ const targetDir = process.cwd();
272
+ const outputDir = await promises.mkdtemp("screw-up-publish-");
273
+ console.log(`[screw-up/cli]: publish: Creating archive of ${targetDir}...`);
274
+ try {
275
+ const metadata = await packAssets(targetDir, outputDir);
276
+ if (metadata) {
277
+ const archiveName = `${metadata.name}-${metadata.version}.tgz`;
278
+ const archivePath = path.join(outputDir, archiveName);
279
+ await runNpmPublish(archivePath, npmOptions);
280
+ } else {
281
+ console.error(`[screw-up/cli]: publish: Unable to find any files to pack: ${targetDir}`);
282
+ process.exit(1);
283
+ }
284
+ } finally {
285
+ await promises.rm(outputDir, { recursive: true, force: true });
286
+ }
287
+ } else if (fs.existsSync(path$1)) {
288
+ const pathStat = await promises.stat(path$1);
289
+ if (pathStat.isFile() && (path$1.endsWith(".tgz") || path$1.endsWith(".tar.gz"))) {
290
+ await runNpmPublish(path.resolve(path$1), npmOptions);
291
+ } else if (pathStat.isDirectory()) {
292
+ const targetDir = path.resolve(path$1);
293
+ const outputDir = await promises.mkdtemp("screw-up-publish-");
294
+ console.log(`[screw-up/cli]: publish: Creating archive of ${targetDir}...`);
295
+ try {
296
+ const metadata = await packAssets(targetDir, outputDir);
297
+ if (metadata) {
298
+ const archiveName = `${metadata.name}-${metadata.version}.tgz`;
299
+ const archivePath = path.join(outputDir, archiveName);
300
+ await runNpmPublish(archivePath, npmOptions);
301
+ } else {
302
+ console.error(`[screw-up/cli]: publish: Unable to find any files to pack: ${targetDir}`);
303
+ process.exit(1);
304
+ }
305
+ } finally {
306
+ await promises.rm(outputDir, { recursive: true, force: true });
307
+ }
308
+ } else {
309
+ console.error(`[screw-up/cli]: publish: Invalid path - must be a directory or .tgz/.tar.gz file: ${path$1}`);
310
+ process.exit(1);
311
+ }
312
+ } else {
313
+ console.error(`[screw-up/cli]: publish: Path does not exist: ${path$1}`);
314
+ process.exit(1);
315
+ }
316
+ } catch (error) {
317
+ console.error("[screw-up/cli]: publish: Failed to publish:", error);
318
+ process.exit(1);
319
+ }
320
+ };
321
+ const main = async () => {
322
+ const args = parseArgs(process.argv);
323
+ if (args.options.help || args.options.h || !args.command || args.command === "help" || args.command === "--help") {
324
+ showHelp();
325
+ return;
326
+ }
327
+ switch (args.command) {
328
+ case "pack":
329
+ await packCommand(args);
330
+ break;
331
+ case "publish":
332
+ await publishCommand(args);
333
+ break;
334
+ default:
335
+ console.error(`Unknown command: ${args.command}`);
336
+ console.error('Run "screw-up --help" for usage information.');
337
+ process.exit(1);
338
+ }
339
+ };
340
+ main().catch((error) => {
341
+ console.error("CLI error:", error);
342
+ process.exit(1);
343
+ });
package/dist/cli.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}