screw-up 0.1.0 → 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 +131 -61
- package/dist/index.cjs +114 -32
- package/dist/index.d.ts +8 -30
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +115 -32
- package/dist/internal.d.ts +34 -0
- package/dist/internal.d.ts.map +1 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ Simply package metadata inserter for Vite plugins.
|
|
|
10
10
|
|
|
11
11
|
## What is this?
|
|
12
12
|
|
|
13
|
-
This is a Vite plugin that automatically inserts banner comments containing package metadata (name, version, description, author, license) into your bundled JavaScript/CSS files.
|
|
13
|
+
This is a Vite plugin that automatically inserts banner comments containing package metadata (name, version, description, author, license, etc.) into your bundled JavaScript/CSS files.
|
|
14
14
|
|
|
15
15
|
This will automatically read metadata from your `package.json`:
|
|
16
16
|
|
|
@@ -20,7 +20,10 @@ This will automatically read metadata from your `package.json`:
|
|
|
20
20
|
"version": "2.1.0",
|
|
21
21
|
"description": "An awesome TypeScript library",
|
|
22
22
|
"author": "Jane Developer <jane@example.com>",
|
|
23
|
-
"license": "Apache-2.0"
|
|
23
|
+
"license": "Apache-2.0",
|
|
24
|
+
"repository": {
|
|
25
|
+
"url": "https://github.com/user/my-awesome-library"
|
|
26
|
+
}
|
|
24
27
|
}
|
|
25
28
|
```
|
|
26
29
|
|
|
@@ -28,17 +31,23 @@ To insert banner header each bundled source files (`dist/index.js` and etc.):
|
|
|
28
31
|
|
|
29
32
|
```javascript
|
|
30
33
|
/*!
|
|
31
|
-
* my-awesome-library
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
34
|
+
* name: my-awesome-library
|
|
35
|
+
* version: 2.1.0
|
|
36
|
+
* description: An awesome TypeScript library
|
|
37
|
+
* author: Jane Developer <jane@example.com>
|
|
38
|
+
* license: Apache-2.0
|
|
39
|
+
* repository.url: https://github.com/user/my-awesome-library
|
|
35
40
|
*/
|
|
36
41
|
// Your bundled code here...
|
|
37
42
|
```
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
*
|
|
44
|
+
## Key Features
|
|
45
|
+
|
|
46
|
+
* Automatic metadata extraction: Reads metadata from `package.json` automatically.
|
|
47
|
+
* Workspace support: Works with monorepos and automatically inherits metadata from parent packages.
|
|
48
|
+
* Flexible output: Specify exactly which keys to include and in what order.
|
|
49
|
+
* Nested object support: Handles nested objects like `author.name`, `repository.url`.
|
|
50
|
+
* Customizable: Choose which metadata fields to include in your banner.
|
|
42
51
|
|
|
43
52
|
## Installation
|
|
44
53
|
|
|
@@ -56,11 +65,11 @@ Add the plugin to your `vite.config.ts`:
|
|
|
56
65
|
|
|
57
66
|
```typescript
|
|
58
67
|
import { defineConfig } from 'vite';
|
|
59
|
-
import { screwUp } from 'screw-up';
|
|
68
|
+
import { screwUp } from 'screw-up';
|
|
60
69
|
|
|
61
70
|
export default defineConfig({
|
|
62
71
|
plugins: [
|
|
63
|
-
screwUp()
|
|
72
|
+
screwUp() // Uses default output keys
|
|
64
73
|
],
|
|
65
74
|
build: {
|
|
66
75
|
lib: {
|
|
@@ -72,9 +81,9 @@ export default defineConfig({
|
|
|
72
81
|
});
|
|
73
82
|
```
|
|
74
83
|
|
|
75
|
-
### Custom
|
|
84
|
+
### Custom Output Keys
|
|
76
85
|
|
|
77
|
-
You can
|
|
86
|
+
You can specify which metadata fields to include and in what order:
|
|
78
87
|
|
|
79
88
|
```typescript
|
|
80
89
|
import { defineConfig } from 'vite';
|
|
@@ -83,7 +92,7 @@ import { screwUp } from 'screw-up';
|
|
|
83
92
|
export default defineConfig({
|
|
84
93
|
plugins: [
|
|
85
94
|
screwUp({
|
|
86
|
-
|
|
95
|
+
outputKeys: ['name', 'version', 'license'] // Only include these fields
|
|
87
96
|
})
|
|
88
97
|
],
|
|
89
98
|
build: {
|
|
@@ -96,79 +105,140 @@ export default defineConfig({
|
|
|
96
105
|
});
|
|
97
106
|
```
|
|
98
107
|
|
|
99
|
-
|
|
108
|
+
This will generate a banner with only the specified fields:
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
/*!
|
|
112
|
+
* name: my-awesome-library
|
|
113
|
+
* version: 2.1.0
|
|
114
|
+
* license: Apache-2.0
|
|
115
|
+
*/
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
#### Default Output Keys
|
|
100
119
|
|
|
101
|
-
|
|
120
|
+
When no `outputKeys` are specified, the plugin uses these default keys:
|
|
102
121
|
|
|
103
122
|
```typescript
|
|
104
|
-
|
|
105
|
-
|
|
123
|
+
['name', 'version', 'description', 'author', 'license', 'repository.url']
|
|
124
|
+
```
|
|
106
125
|
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
126
|
+
### Working with Nested Objects
|
|
127
|
+
|
|
128
|
+
The plugin automatically flattens nested objects using dot notation:
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"name": "my-package",
|
|
133
|
+
"author": {
|
|
134
|
+
"name": "Jane Developer",
|
|
135
|
+
"email": "jane@example.com"
|
|
136
|
+
},
|
|
137
|
+
"repository": {
|
|
138
|
+
"type": "git",
|
|
139
|
+
"url": "https://github.com/user/my-package"
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
You can reference nested fields in your `outputKeys`:
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
screwUp({
|
|
148
|
+
outputKeys: ['name', 'author.name', 'author.email', 'repository.url']
|
|
149
|
+
})
|
|
114
150
|
```
|
|
115
151
|
|
|
152
|
+
Results in:
|
|
153
|
+
|
|
154
|
+
```javascript
|
|
155
|
+
/*!
|
|
156
|
+
* name: my-package
|
|
157
|
+
* author.name: Jane Developer
|
|
158
|
+
* author.email: jane@example.com
|
|
159
|
+
* repository.url: https://github.com/user/my-package
|
|
160
|
+
*/
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
----
|
|
164
|
+
|
|
116
165
|
## Advanced Usage
|
|
117
166
|
|
|
118
|
-
###
|
|
167
|
+
### Monorepo Support
|
|
119
168
|
|
|
120
|
-
|
|
169
|
+
The plugin automatically detects workspace configurations and inherits metadata from parent packages:
|
|
121
170
|
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
|
|
171
|
+
```
|
|
172
|
+
my-monorepo/
|
|
173
|
+
├── package.json # Root package with shared metadata
|
|
174
|
+
├── packages/
|
|
175
|
+
│ ├── ui/
|
|
176
|
+
│ │ └── package.json # Child package
|
|
177
|
+
│ └── core/
|
|
178
|
+
│ └── package.json # Child package
|
|
179
|
+
```
|
|
125
180
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
181
|
+
Child packages automatically inherit metadata from the root package, with the ability to override specific fields:
|
|
182
|
+
|
|
183
|
+
```json
|
|
184
|
+
// Root package.json
|
|
185
|
+
{
|
|
186
|
+
"name": "my-monorepo",
|
|
187
|
+
"version": "1.0.0",
|
|
188
|
+
"author": "Company Team",
|
|
189
|
+
"license": "MIT"
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
// packages/ui/package.json
|
|
193
|
+
{
|
|
194
|
+
"name": "@my-monorepo/ui",
|
|
195
|
+
"description": "UI components library"
|
|
196
|
+
}
|
|
140
197
|
```
|
|
141
198
|
|
|
142
|
-
|
|
199
|
+
When building the UI package, the banner will include:
|
|
200
|
+
|
|
201
|
+
```javascript
|
|
202
|
+
/*!
|
|
203
|
+
* name: @my-monorepo/ui
|
|
204
|
+
* version: 1.0.0
|
|
205
|
+
* description: UI components library
|
|
206
|
+
* author: Company Team
|
|
207
|
+
* license: MIT
|
|
208
|
+
*/
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Programmatic Usage
|
|
143
212
|
|
|
144
213
|
You can also use the utility functions directly:
|
|
145
214
|
|
|
146
215
|
```typescript
|
|
147
|
-
import { generateBanner, readPackageMetadata } from 'screw-up';
|
|
216
|
+
import { generateBanner, readPackageMetadata } from 'screw-up/internal';
|
|
148
217
|
|
|
149
218
|
// Read package metadata
|
|
150
|
-
const metadata = readPackageMetadata('./package.json');
|
|
151
|
-
|
|
152
|
-
// Generate banner
|
|
153
|
-
const banner = generateBanner(
|
|
154
|
-
name: 'my-package',
|
|
155
|
-
version: '1.0.0',
|
|
156
|
-
description: 'A great package',
|
|
157
|
-
author: 'Developer Name',
|
|
158
|
-
license: 'MIT'
|
|
159
|
-
});
|
|
219
|
+
const metadata = await readPackageMetadata('./package.json');
|
|
220
|
+
|
|
221
|
+
// Generate banner with custom keys
|
|
222
|
+
const banner = generateBanner(metadata, ['name', 'version', 'license']);
|
|
160
223
|
|
|
161
224
|
console.log(banner);
|
|
162
225
|
// /*!
|
|
163
|
-
// * my-package
|
|
164
|
-
// *
|
|
165
|
-
// *
|
|
166
|
-
// * License: MIT
|
|
226
|
+
// * name: my-package
|
|
227
|
+
// * version: 1.0.0
|
|
228
|
+
// * license: MIT
|
|
167
229
|
// */
|
|
168
230
|
```
|
|
169
231
|
|
|
232
|
+
## Supported Workspace Types
|
|
233
|
+
|
|
234
|
+
The plugin automatically detects and supports:
|
|
235
|
+
|
|
236
|
+
- npm/yarn workspaces: Detected via `workspaces` field in `package.json`
|
|
237
|
+
- pnpm workspaces: Detected via `pnpm-workspace.yaml` file
|
|
238
|
+
- Lerna: Detected via `lerna.json` file
|
|
239
|
+
|
|
170
240
|
----
|
|
171
241
|
|
|
172
242
|
## License
|
|
173
243
|
|
|
174
|
-
Under MIT
|
|
244
|
+
Under MIT
|
package/dist/index.cjs
CHANGED
|
@@ -1,60 +1,142 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
const fs = require("fs");
|
|
2
|
+
const promises = require("fs/promises");
|
|
4
3
|
const path = require("path");
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
if (typeof
|
|
12
|
-
|
|
4
|
+
const fs = require("fs");
|
|
5
|
+
const flattenObject = (obj, prefix = "", map) => {
|
|
6
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
7
|
+
if (!value)
|
|
8
|
+
continue;
|
|
9
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
10
|
+
if (typeof value === "string") {
|
|
11
|
+
map[fullKey] = value;
|
|
12
|
+
} else if (Array.isArray(value)) {
|
|
13
|
+
map[fullKey] = value.map((v) => String(v)).join(",");
|
|
14
|
+
} else if (typeof value === "object") {
|
|
15
|
+
flattenObject(value, fullKey, map);
|
|
13
16
|
} else {
|
|
14
|
-
|
|
17
|
+
map[fullKey] = String(value);
|
|
15
18
|
}
|
|
16
19
|
}
|
|
17
|
-
const license = metadata.license || "";
|
|
18
|
-
const parts = [
|
|
19
|
-
`${name} ${version}`,
|
|
20
|
-
description && `${description}`,
|
|
21
|
-
author && `Author: ${author}`,
|
|
22
|
-
license && `License: ${license}`
|
|
23
|
-
].filter(Boolean);
|
|
24
|
-
return `/*!
|
|
25
|
-
* ${parts.join("\n * ")}
|
|
26
|
-
*/`;
|
|
27
20
|
};
|
|
28
|
-
const readPackageMetadata = (packagePath) => {
|
|
21
|
+
const readPackageMetadata = async (packagePath) => {
|
|
29
22
|
try {
|
|
30
|
-
const content =
|
|
31
|
-
|
|
23
|
+
const content = await promises.readFile(packagePath, "utf-8");
|
|
24
|
+
const json = JSON.parse(content);
|
|
25
|
+
const map = {};
|
|
26
|
+
flattenObject(json, "", map);
|
|
27
|
+
return map;
|
|
32
28
|
} catch (error) {
|
|
33
29
|
console.warn(`Failed to read package.json from ${packagePath}:`, error);
|
|
34
30
|
return {};
|
|
35
31
|
}
|
|
36
32
|
};
|
|
33
|
+
const findWorkspaceRoot = async (startPath) => {
|
|
34
|
+
let currentPath = startPath;
|
|
35
|
+
while (currentPath !== path.dirname(currentPath)) {
|
|
36
|
+
const packageJsonPath = path.join(currentPath, "package.json");
|
|
37
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
38
|
+
try {
|
|
39
|
+
const content = await promises.readFile(packageJsonPath, "utf-8");
|
|
40
|
+
const packageJson = JSON.parse(content);
|
|
41
|
+
if (packageJson.workspaces || fs.existsSync(path.join(currentPath, "pnpm-workspace.yaml")) || fs.existsSync(path.join(currentPath, "lerna.json"))) {
|
|
42
|
+
return currentPath;
|
|
43
|
+
}
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.warn(`Failed to parse package.json at ${packageJsonPath}:`, error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
currentPath = path.dirname(currentPath);
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
};
|
|
52
|
+
const mergePackageMetadata = (parentMetadata, childMetadata) => {
|
|
53
|
+
const merged = {};
|
|
54
|
+
for (const key in parentMetadata) {
|
|
55
|
+
const value = parentMetadata[key];
|
|
56
|
+
if (value !== void 0) {
|
|
57
|
+
merged[key] = value;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
for (const key in childMetadata) {
|
|
61
|
+
const value = childMetadata[key];
|
|
62
|
+
if (value !== void 0) {
|
|
63
|
+
merged[key] = value;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return merged;
|
|
67
|
+
};
|
|
68
|
+
const resolvePackageMetadata = async (projectRoot) => {
|
|
69
|
+
const workspaceRoot = await findWorkspaceRoot(projectRoot);
|
|
70
|
+
if (!workspaceRoot) {
|
|
71
|
+
const localPackagePath = path.join(projectRoot, "package.json");
|
|
72
|
+
return await readPackageMetadata(localPackagePath);
|
|
73
|
+
}
|
|
74
|
+
const projectPackagePath = path.join(projectRoot, "package.json");
|
|
75
|
+
const rootPackagePath = path.join(workspaceRoot, "package.json");
|
|
76
|
+
let metadata = await readPackageMetadata(rootPackagePath);
|
|
77
|
+
if (projectPackagePath !== rootPackagePath && fs.existsSync(projectPackagePath)) {
|
|
78
|
+
const projectMetadata = await readPackageMetadata(projectPackagePath);
|
|
79
|
+
metadata = mergePackageMetadata(metadata, projectMetadata);
|
|
80
|
+
}
|
|
81
|
+
return metadata;
|
|
82
|
+
};
|
|
83
|
+
const generateBanner = (metadata, outputKeys) => {
|
|
84
|
+
const parts = [];
|
|
85
|
+
for (const key of outputKeys) {
|
|
86
|
+
const value = metadata[key];
|
|
87
|
+
if (value) {
|
|
88
|
+
parts.push(`${key}: ${value}`);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return parts.length > 0 ? `/*!
|
|
92
|
+
* ${parts.join("\n * ")}
|
|
93
|
+
*/` : "";
|
|
94
|
+
};
|
|
37
95
|
const screwUp = (options = {}) => {
|
|
38
|
-
const {
|
|
96
|
+
const {
|
|
97
|
+
outputKeys = ["name", "version", "description", "author", "license", "repository.url"],
|
|
98
|
+
assetFilters = ["\\.d\\.ts$"]
|
|
99
|
+
} = options;
|
|
100
|
+
const assetFiltersRegex = assetFilters.map((filter) => new RegExp(filter));
|
|
39
101
|
let banner;
|
|
40
102
|
return {
|
|
41
103
|
name: "screw-up",
|
|
42
104
|
apply: "build",
|
|
43
|
-
configResolved(config) {
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
banner = bannerTemplate || generateBanner(metadata);
|
|
105
|
+
async configResolved(config) {
|
|
106
|
+
const metadata = await resolvePackageMetadata(config.root);
|
|
107
|
+
banner = generateBanner(metadata, outputKeys);
|
|
47
108
|
},
|
|
48
109
|
generateBundle(_options, bundle) {
|
|
49
110
|
for (const fileName in bundle) {
|
|
50
111
|
const chunk = bundle[fileName];
|
|
51
112
|
if (chunk.type === "chunk") {
|
|
52
113
|
chunk.code = banner + "\n" + chunk.code;
|
|
114
|
+
} else if (chunk.type === "asset" && assetFiltersRegex.some((filter) => filter.test(fileName))) {
|
|
115
|
+
if (typeof chunk.source === "string") {
|
|
116
|
+
chunk.source = banner + "\n\n" + chunk.source;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
},
|
|
121
|
+
async writeBundle(options2) {
|
|
122
|
+
if (!options2.dir) return;
|
|
123
|
+
try {
|
|
124
|
+
const files = await promises.readdir(options2.dir, { recursive: true });
|
|
125
|
+
for (const file of files) {
|
|
126
|
+
const filePath = path.join(options2.dir, file);
|
|
127
|
+
if (assetFiltersRegex.some((filter) => filter.test(file))) {
|
|
128
|
+
try {
|
|
129
|
+
const content = await promises.readFile(filePath, "utf-8");
|
|
130
|
+
if (!content.includes(banner)) {
|
|
131
|
+
await promises.writeFile(filePath, banner + "\n\n" + content);
|
|
132
|
+
}
|
|
133
|
+
} catch (error) {
|
|
134
|
+
}
|
|
135
|
+
}
|
|
53
136
|
}
|
|
137
|
+
} catch (error) {
|
|
54
138
|
}
|
|
55
139
|
}
|
|
56
140
|
};
|
|
57
141
|
};
|
|
58
|
-
exports
|
|
59
|
-
exports.readPackageMetadata = readPackageMetadata;
|
|
60
|
-
exports.screwUp = screwUp;
|
|
142
|
+
module.exports = screwUp;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,44 +1,22 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
2
|
|
|
3
|
-
interface PackageMetadata {
|
|
4
|
-
name?: string;
|
|
5
|
-
version?: string;
|
|
6
|
-
description?: string;
|
|
7
|
-
author?: string | {
|
|
8
|
-
name: string;
|
|
9
|
-
email?: string;
|
|
10
|
-
};
|
|
11
|
-
license?: string;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Generate banner string from package.json metadata
|
|
15
|
-
* @param metadata - Package metadata
|
|
16
|
-
* @returns Banner string
|
|
17
|
-
*/
|
|
18
|
-
export declare const generateBanner: (metadata: PackageMetadata) => string;
|
|
19
|
-
/**
|
|
20
|
-
* Read and parse package.json file
|
|
21
|
-
* @param packagePath - Path to package.json
|
|
22
|
-
* @returns Package metadata
|
|
23
|
-
*/
|
|
24
|
-
export declare const readPackageMetadata: (packagePath: string) => PackageMetadata;
|
|
25
3
|
export interface ScrewUpOptions {
|
|
26
4
|
/**
|
|
27
|
-
*
|
|
28
|
-
* @default
|
|
5
|
+
* Array of keys to output in banner in the specified order
|
|
6
|
+
* @default ['name', 'version', 'description', 'author', 'license', 'repository.url']
|
|
29
7
|
*/
|
|
30
|
-
|
|
8
|
+
outputKeys?: string[];
|
|
31
9
|
/**
|
|
32
|
-
*
|
|
33
|
-
* @default
|
|
10
|
+
* Array of asset file regex to add banner to
|
|
11
|
+
* @default ['\.d\.ts$']
|
|
34
12
|
*/
|
|
35
|
-
|
|
13
|
+
assetFilters?: string[];
|
|
36
14
|
}
|
|
37
15
|
/**
|
|
38
16
|
* Vite plugin that adds banner to the bundled code
|
|
39
17
|
* @param options - Plugin options
|
|
40
18
|
* @returns Vite plugin
|
|
41
19
|
*/
|
|
42
|
-
|
|
43
|
-
export
|
|
20
|
+
declare const screwUp: (options?: ScrewUpOptions) => Plugin;
|
|
21
|
+
export default screwUp;
|
|
44
22
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAKnC,MAAM,WAAW,cAAc;IAC7B;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AAED;;;;GAIG;AACH,QAAA,MAAM,OAAO,GAAI,UAAS,cAAmB,KAAG,MA2D/C,CAAC;AAEF,eAAe,OAAO,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,60 +1,143 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
if (typeof
|
|
10
|
-
|
|
1
|
+
import { readFile, readdir, writeFile } from "fs/promises";
|
|
2
|
+
import { join, dirname } from "path";
|
|
3
|
+
import { existsSync } from "fs";
|
|
4
|
+
const flattenObject = (obj, prefix = "", map) => {
|
|
5
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
6
|
+
if (!value)
|
|
7
|
+
continue;
|
|
8
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
9
|
+
if (typeof value === "string") {
|
|
10
|
+
map[fullKey] = value;
|
|
11
|
+
} else if (Array.isArray(value)) {
|
|
12
|
+
map[fullKey] = value.map((v) => String(v)).join(",");
|
|
13
|
+
} else if (typeof value === "object") {
|
|
14
|
+
flattenObject(value, fullKey, map);
|
|
11
15
|
} else {
|
|
12
|
-
|
|
16
|
+
map[fullKey] = String(value);
|
|
13
17
|
}
|
|
14
18
|
}
|
|
15
|
-
const license = metadata.license || "";
|
|
16
|
-
const parts = [
|
|
17
|
-
`${name} ${version}`,
|
|
18
|
-
description && `${description}`,
|
|
19
|
-
author && `Author: ${author}`,
|
|
20
|
-
license && `License: ${license}`
|
|
21
|
-
].filter(Boolean);
|
|
22
|
-
return `/*!
|
|
23
|
-
* ${parts.join("\n * ")}
|
|
24
|
-
*/`;
|
|
25
19
|
};
|
|
26
|
-
const readPackageMetadata = (packagePath) => {
|
|
20
|
+
const readPackageMetadata = async (packagePath) => {
|
|
27
21
|
try {
|
|
28
|
-
const content =
|
|
29
|
-
|
|
22
|
+
const content = await readFile(packagePath, "utf-8");
|
|
23
|
+
const json = JSON.parse(content);
|
|
24
|
+
const map = {};
|
|
25
|
+
flattenObject(json, "", map);
|
|
26
|
+
return map;
|
|
30
27
|
} catch (error) {
|
|
31
28
|
console.warn(`Failed to read package.json from ${packagePath}:`, error);
|
|
32
29
|
return {};
|
|
33
30
|
}
|
|
34
31
|
};
|
|
32
|
+
const findWorkspaceRoot = async (startPath) => {
|
|
33
|
+
let currentPath = startPath;
|
|
34
|
+
while (currentPath !== dirname(currentPath)) {
|
|
35
|
+
const packageJsonPath = join(currentPath, "package.json");
|
|
36
|
+
if (existsSync(packageJsonPath)) {
|
|
37
|
+
try {
|
|
38
|
+
const content = await readFile(packageJsonPath, "utf-8");
|
|
39
|
+
const packageJson = JSON.parse(content);
|
|
40
|
+
if (packageJson.workspaces || existsSync(join(currentPath, "pnpm-workspace.yaml")) || existsSync(join(currentPath, "lerna.json"))) {
|
|
41
|
+
return currentPath;
|
|
42
|
+
}
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.warn(`Failed to parse package.json at ${packageJsonPath}:`, error);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
currentPath = dirname(currentPath);
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
};
|
|
51
|
+
const mergePackageMetadata = (parentMetadata, childMetadata) => {
|
|
52
|
+
const merged = {};
|
|
53
|
+
for (const key in parentMetadata) {
|
|
54
|
+
const value = parentMetadata[key];
|
|
55
|
+
if (value !== void 0) {
|
|
56
|
+
merged[key] = value;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
for (const key in childMetadata) {
|
|
60
|
+
const value = childMetadata[key];
|
|
61
|
+
if (value !== void 0) {
|
|
62
|
+
merged[key] = value;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return merged;
|
|
66
|
+
};
|
|
67
|
+
const resolvePackageMetadata = async (projectRoot) => {
|
|
68
|
+
const workspaceRoot = await findWorkspaceRoot(projectRoot);
|
|
69
|
+
if (!workspaceRoot) {
|
|
70
|
+
const localPackagePath = join(projectRoot, "package.json");
|
|
71
|
+
return await readPackageMetadata(localPackagePath);
|
|
72
|
+
}
|
|
73
|
+
const projectPackagePath = join(projectRoot, "package.json");
|
|
74
|
+
const rootPackagePath = join(workspaceRoot, "package.json");
|
|
75
|
+
let metadata = await readPackageMetadata(rootPackagePath);
|
|
76
|
+
if (projectPackagePath !== rootPackagePath && existsSync(projectPackagePath)) {
|
|
77
|
+
const projectMetadata = await readPackageMetadata(projectPackagePath);
|
|
78
|
+
metadata = mergePackageMetadata(metadata, projectMetadata);
|
|
79
|
+
}
|
|
80
|
+
return metadata;
|
|
81
|
+
};
|
|
82
|
+
const generateBanner = (metadata, outputKeys) => {
|
|
83
|
+
const parts = [];
|
|
84
|
+
for (const key of outputKeys) {
|
|
85
|
+
const value = metadata[key];
|
|
86
|
+
if (value) {
|
|
87
|
+
parts.push(`${key}: ${value}`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return parts.length > 0 ? `/*!
|
|
91
|
+
* ${parts.join("\n * ")}
|
|
92
|
+
*/` : "";
|
|
93
|
+
};
|
|
35
94
|
const screwUp = (options = {}) => {
|
|
36
|
-
const {
|
|
95
|
+
const {
|
|
96
|
+
outputKeys = ["name", "version", "description", "author", "license", "repository.url"],
|
|
97
|
+
assetFilters = ["\\.d\\.ts$"]
|
|
98
|
+
} = options;
|
|
99
|
+
const assetFiltersRegex = assetFilters.map((filter) => new RegExp(filter));
|
|
37
100
|
let banner;
|
|
38
101
|
return {
|
|
39
102
|
name: "screw-up",
|
|
40
103
|
apply: "build",
|
|
41
|
-
configResolved(config) {
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
banner = bannerTemplate || generateBanner(metadata);
|
|
104
|
+
async configResolved(config) {
|
|
105
|
+
const metadata = await resolvePackageMetadata(config.root);
|
|
106
|
+
banner = generateBanner(metadata, outputKeys);
|
|
45
107
|
},
|
|
46
108
|
generateBundle(_options, bundle) {
|
|
47
109
|
for (const fileName in bundle) {
|
|
48
110
|
const chunk = bundle[fileName];
|
|
49
111
|
if (chunk.type === "chunk") {
|
|
50
112
|
chunk.code = banner + "\n" + chunk.code;
|
|
113
|
+
} else if (chunk.type === "asset" && assetFiltersRegex.some((filter) => filter.test(fileName))) {
|
|
114
|
+
if (typeof chunk.source === "string") {
|
|
115
|
+
chunk.source = banner + "\n\n" + chunk.source;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
async writeBundle(options2) {
|
|
121
|
+
if (!options2.dir) return;
|
|
122
|
+
try {
|
|
123
|
+
const files = await readdir(options2.dir, { recursive: true });
|
|
124
|
+
for (const file of files) {
|
|
125
|
+
const filePath = join(options2.dir, file);
|
|
126
|
+
if (assetFiltersRegex.some((filter) => filter.test(file))) {
|
|
127
|
+
try {
|
|
128
|
+
const content = await readFile(filePath, "utf-8");
|
|
129
|
+
if (!content.includes(banner)) {
|
|
130
|
+
await writeFile(filePath, banner + "\n\n" + content);
|
|
131
|
+
}
|
|
132
|
+
} catch (error) {
|
|
133
|
+
}
|
|
134
|
+
}
|
|
51
135
|
}
|
|
136
|
+
} catch (error) {
|
|
52
137
|
}
|
|
53
138
|
}
|
|
54
139
|
};
|
|
55
140
|
};
|
|
56
141
|
export {
|
|
57
|
-
|
|
58
|
-
readPackageMetadata,
|
|
59
|
-
screwUp
|
|
142
|
+
screwUp as default
|
|
60
143
|
};
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
export type PackageMetadata = Record<string, string>;
|
|
2
|
+
/**
|
|
3
|
+
* Read and parse package.json file
|
|
4
|
+
* @param packagePath - Path to package.json
|
|
5
|
+
* @returns Promise resolving to package metadata
|
|
6
|
+
*/
|
|
7
|
+
export declare const readPackageMetadata: (packagePath: string) => Promise<PackageMetadata>;
|
|
8
|
+
/**
|
|
9
|
+
* Find workspace root by looking for workspace configuration files
|
|
10
|
+
* @param startPath - Starting directory path
|
|
11
|
+
* @returns Promise resolving to workspace root path or null if not found
|
|
12
|
+
*/
|
|
13
|
+
export declare const findWorkspaceRoot: (startPath: string) => Promise<string | null>;
|
|
14
|
+
/**
|
|
15
|
+
* Merge package metadata with inheritance (child overrides parent)
|
|
16
|
+
* @param parentMetadata - Parent package metadata
|
|
17
|
+
* @param childMetadata - Child package metadata
|
|
18
|
+
* @returns Merged metadata
|
|
19
|
+
*/
|
|
20
|
+
export declare const mergePackageMetadata: (parentMetadata: PackageMetadata, childMetadata: PackageMetadata) => PackageMetadata;
|
|
21
|
+
/**
|
|
22
|
+
* Resolve package metadata for current project with workspace inheritance
|
|
23
|
+
* @param projectRoot - Current project root
|
|
24
|
+
* @returns Promise resolving to resolved package metadata
|
|
25
|
+
*/
|
|
26
|
+
export declare const resolvePackageMetadata: (projectRoot: string) => Promise<PackageMetadata>;
|
|
27
|
+
/**
|
|
28
|
+
* Generate banner string from package.json metadata
|
|
29
|
+
* @param metadata - Package metadata
|
|
30
|
+
* @param outputKeys - Array of keys to output in specified order
|
|
31
|
+
* @returns Banner string
|
|
32
|
+
*/
|
|
33
|
+
export declare const generateBanner: (metadata: PackageMetadata, outputKeys: string[]) => string;
|
|
34
|
+
//# sourceMappingURL=internal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"internal.d.ts","sourceRoot":"","sources":["../src/internal.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AA2BrD;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,GAAU,aAAa,MAAM,KAAG,OAAO,CAAC,eAAe,CAWtF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,GAAU,WAAW,MAAM,KAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CA0BhF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,oBAAoB,GAC/B,gBAAgB,eAAe,EAC/B,eAAe,eAAe,KAC7B,eAoBF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GAAU,aAAa,MAAM,KAAG,OAAO,CAAC,eAAe,CAsBzF,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,cAAc,GAAI,UAAU,eAAe,EAAE,YAAY,MAAM,EAAE,KAAG,MAWhF,CAAC"}
|