@doki-land/nifty 0.1.1 → 0.1.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.
- package/cli/nifty.mjs +2 -2
- package/package.json +6 -6
- package/src/cli/authArgs.ts +29 -29
- package/src/cli/bump-cmd.ts +15 -15
- package/src/cli/bump.ts +79 -79
- package/src/cli/change-logs-cmd.ts +26 -26
- package/src/cli/cli.ts +3 -3
- package/src/cli/commit-cmd.ts +76 -78
- package/src/cli/commit-lint-report.ts +46 -48
- package/src/cli/context.ts +9 -9
- package/src/cli/format-cmd.ts +6 -6
- package/src/cli/format.ts +15 -15
- package/src/cli/install-native-cmd.ts +4 -4
- package/src/cli/install-native.ts +24 -24
- package/src/cli/lint-cmd.ts +11 -11
- package/src/cli/lint.ts +48 -52
- package/src/cli/options.ts +14 -14
- package/src/cli/publish-cmd.ts +12 -18
- package/src/cli/publish.ts +38 -38
- package/src/cli/resolveNpm.ts +3 -3
- package/src/cli/retime-cmd.ts +18 -18
- package/src/cli/trust-cmd.ts +11 -11
- package/src/cli/trust.ts +26 -26
- package/src/cli/update-cmd.ts +5 -5
- package/src/cli/update.ts +12 -12
- package/src/cli/upload-cmd.ts +17 -17
- package/src/cli/upload.ts +131 -131
- package/src/cli/workspace.ts +46 -46
- package/src/config/authorMap.ts +4 -8
- package/src/config/defineConfig.ts +5 -5
- package/src/config/detectProject.ts +46 -46
- package/src/config/formatPresets.ts +24 -24
- package/src/config/loadConfig.ts +35 -35
- package/src/config/trustPayload.ts +6 -6
- package/src/config/types.ts +37 -37
- package/src/git.ts +14 -14
- package/src/github.ts +54 -54
- package/src/gitmoji.ts +18 -18
- package/src/native.ts +595 -599
- package/src/nifty.ts +29 -31
- package/src/types.ts +17 -17
package/src/cli/upload.ts
CHANGED
|
@@ -9,37 +9,37 @@ import { loadNiftyNative } from "../native.js";
|
|
|
9
9
|
const USER_AGENT = "nifty-upload";
|
|
10
10
|
|
|
11
11
|
export type UploadOptions = {
|
|
12
|
-
release
|
|
13
|
-
pages
|
|
14
|
-
both
|
|
15
|
-
dir
|
|
16
|
-
tag
|
|
17
|
-
repo
|
|
18
|
-
token
|
|
19
|
-
name
|
|
20
|
-
notes
|
|
21
|
-
notesFile
|
|
22
|
-
draft
|
|
23
|
-
generateNotes
|
|
24
|
-
githubAction
|
|
25
|
-
cwd
|
|
12
|
+
release: boolean;
|
|
13
|
+
pages: boolean;
|
|
14
|
+
both: boolean;
|
|
15
|
+
dir: string;
|
|
16
|
+
tag?: string;
|
|
17
|
+
repo?: string;
|
|
18
|
+
token?: string;
|
|
19
|
+
name?: string;
|
|
20
|
+
notes?: string;
|
|
21
|
+
notesFile?: string;
|
|
22
|
+
draft: boolean;
|
|
23
|
+
generateNotes: boolean;
|
|
24
|
+
githubAction: boolean;
|
|
25
|
+
cwd?: string;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
28
|
type GithubRelease = {
|
|
29
|
-
id
|
|
29
|
+
id: number;
|
|
30
30
|
};
|
|
31
31
|
|
|
32
|
-
export async function runUpload(argv
|
|
32
|
+
export async function runUpload(argv: string[]): Promise < void> {
|
|
33
33
|
await uploadFromOptions(parseUploadArgs(argv));
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
export async function uploadFromOptions(options
|
|
37
|
-
if(options.githubAction){
|
|
36
|
+
export async function uploadFromOptions(options: UploadOptions): Promise < void> {
|
|
37
|
+
if (options.githubAction) {
|
|
38
38
|
applyGithubActionDefaults(options);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
const token = options.token ?? process.env.GITHUB_TOKEN;
|
|
42
|
-
if(!token){
|
|
42
|
+
if (!token) {
|
|
43
43
|
throw new Error("GitHub token is required (set --token or GITHUB_TOKEN)");
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -50,117 +50,117 @@ export async function uploadFromOptions(options : UploadOptions) : Promise<void>
|
|
|
50
50
|
options.repo ??
|
|
51
51
|
native.git["detect-github-repo"](layout.root) ??
|
|
52
52
|
process.env.GITHUB_REPOSITORY;
|
|
53
|
-
if(!repo){
|
|
53
|
+
if (!repo) {
|
|
54
54
|
throw new Error("could not detect GitHub repo (use --repo owner/name)");
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
const tag = options.tag ?? process.env.GITHUB_REF_NAME;
|
|
58
|
-
if(!tag){
|
|
58
|
+
if (!tag) {
|
|
59
59
|
throw new Error("release tag is required (use --tag or push a git tag)");
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
const target = parseTarget(options);
|
|
63
63
|
const notes = await resolveNotes(options, layout.root, tag, native);
|
|
64
64
|
|
|
65
|
-
if(target === "release" || target === "both"){
|
|
65
|
+
if (target === "release" || target === "both") {
|
|
66
66
|
await uploadReleaseAssets(repo, token, tag, options, notes);
|
|
67
67
|
}
|
|
68
|
-
if(target === "pages" || target === "both"){
|
|
68
|
+
if (target === "pages" || target === "both") {
|
|
69
69
|
await deployGithubPages(repo, token, options.dir);
|
|
70
70
|
}
|
|
71
71
|
}
|
|
72
72
|
|
|
73
|
-
function parseUploadArgs(argv
|
|
74
|
-
const options
|
|
75
|
-
release
|
|
76
|
-
pages
|
|
77
|
-
both
|
|
78
|
-
dir
|
|
79
|
-
draft
|
|
80
|
-
generateNotes
|
|
81
|
-
githubAction
|
|
73
|
+
function parseUploadArgs(argv: string[]): UploadOptions {
|
|
74
|
+
const options: UploadOptions = {
|
|
75
|
+
release: false,
|
|
76
|
+
pages: false,
|
|
77
|
+
both: false,
|
|
78
|
+
dir: "dist",
|
|
79
|
+
draft: false,
|
|
80
|
+
generateNotes: true,
|
|
81
|
+
githubAction: false,
|
|
82
82
|
};
|
|
83
83
|
|
|
84
|
-
for(let i = 0; i<argv.length; i += 1){
|
|
84
|
+
for (let i = 0; i < argv.length; i += 1) {
|
|
85
85
|
const arg = argv[i];
|
|
86
|
-
if(arg === "--release")options.release = true;
|
|
87
|
-
else if(arg === "--pages")options.pages = true;
|
|
88
|
-
else if(arg === "--both")options.both = true;
|
|
89
|
-
else if(arg === "-d" || arg === "--dir")options.dir = argv[
|
|
90
|
-
else if(arg === "-h" || arg === "--help"){
|
|
86
|
+
if (arg === "--release")options.release = true;
|
|
87
|
+
else if (arg === "--pages")options.pages = true;
|
|
88
|
+
else if (arg === "--both")options.both = true;
|
|
89
|
+
else if (arg === "-d" || arg === "--dir")options.dir = argv[++i];
|
|
90
|
+
else if (arg === "-h" || arg === "--help") {
|
|
91
91
|
printUploadHelp();
|
|
92
92
|
process.exit(0);
|
|
93
93
|
}
|
|
94
|
-
else if(arg === "-t" || arg === "--tag")options.tag = argv[
|
|
95
|
-
else if(arg === "--repo")options.repo = argv[
|
|
96
|
-
else if(arg === "--token")options.token = argv[
|
|
97
|
-
else if(arg === "--name")options.name = argv[
|
|
98
|
-
else if(arg === "--notes")options.notes = argv[
|
|
99
|
-
else if(arg === "--notes-file")options.notesFile = argv[
|
|
100
|
-
else if(arg === "--draft")options.draft = true;
|
|
101
|
-
else if(arg === "--no-generate-notes")options.generateNotes = false;
|
|
102
|
-
else if(arg === "--github-action")options.githubAction = true;
|
|
103
|
-
else if(arg === "-C" || arg === "--cwd")options.cwd = argv[
|
|
94
|
+
else if (arg === "-t" || arg === "--tag")options.tag = argv[++i];
|
|
95
|
+
else if (arg === "--repo")options.repo = argv[++i];
|
|
96
|
+
else if (arg === "--token")options.token = argv[++i];
|
|
97
|
+
else if (arg === "--name")options.name = argv[++i];
|
|
98
|
+
else if (arg === "--notes")options.notes = argv[++i];
|
|
99
|
+
else if (arg === "--notes-file")options.notesFile = argv[++i];
|
|
100
|
+
else if (arg === "--draft")options.draft = true;
|
|
101
|
+
else if (arg === "--no-generate-notes")options.generateNotes = false;
|
|
102
|
+
else if (arg === "--github-action")options.githubAction = true;
|
|
103
|
+
else if (arg === "-C" || arg === "--cwd")options.cwd = argv[++i];
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
return options;
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
function parseTarget(options
|
|
110
|
-
if(options.both)return "both";
|
|
111
|
-
if(options.pages)return "pages";
|
|
112
|
-
if(options.release)return "release";
|
|
109
|
+
function parseTarget(options: UploadOptions): "release" | "pages" | "both" {
|
|
110
|
+
if (options.both)return "both";
|
|
111
|
+
if (options.pages)return "pages";
|
|
112
|
+
if (options.release)return "release";
|
|
113
113
|
throw new Error("specify --release, --pages, or --both");
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
function applyGithubActionDefaults(options
|
|
117
|
-
options.token
|
|
118
|
-
options.repo
|
|
119
|
-
options.tag
|
|
120
|
-
options.cwd
|
|
116
|
+
function applyGithubActionDefaults(options: UploadOptions): void {
|
|
117
|
+
options.token??= process.env.GITHUB_TOKEN;
|
|
118
|
+
options.repo??= process.env.GITHUB_REPOSITORY;
|
|
119
|
+
options.tag??= process.env.GITHUB_REF_NAME;
|
|
120
|
+
options.cwd??= process.env.GITHUB_WORKSPACE;
|
|
121
121
|
}
|
|
122
122
|
|
|
123
123
|
async function resolveNotes(
|
|
124
|
-
options
|
|
125
|
-
repoRoot
|
|
126
|
-
tag
|
|
127
|
-
native
|
|
128
|
-
)
|
|
129
|
-
if(options.notes)return options.notes;
|
|
130
|
-
if(options.notesFile)return readFileSync(options.notesFile, "utf8");
|
|
131
|
-
if(!options.generateNotes)return "";
|
|
124
|
+
options: UploadOptions,
|
|
125
|
+
repoRoot: string,
|
|
126
|
+
tag: string,
|
|
127
|
+
native: ReturnType < typeof loadNiftyNative > ,
|
|
128
|
+
): Promise < string> {
|
|
129
|
+
if (options.notes)return options.notes;
|
|
130
|
+
if (options.notesFile)return readFileSync(options.notesFile, "utf8");
|
|
131
|
+
if (!options.generateNotes)return "";
|
|
132
132
|
try {
|
|
133
|
-
const range = native.git["resolve-range"](repoRoot, tag.replace(
|
|
133
|
+
const range = native.git["resolve-range"](repoRoot, tag.replace(/^v/, ""), undefined, tag);
|
|
134
134
|
const commits = native.git["collect-commits"](repoRoot, range["from-ref"], range["to-ref"]);
|
|
135
|
-
return commits.map((commit)
|
|
135
|
+
return commits.map((commit) => `- ${commit.body}`).join("\n");
|
|
136
136
|
} catch {
|
|
137
137
|
return "";
|
|
138
138
|
}
|
|
139
139
|
}
|
|
140
140
|
|
|
141
141
|
async function uploadReleaseAssets(
|
|
142
|
-
repo
|
|
143
|
-
token
|
|
144
|
-
tag
|
|
145
|
-
options
|
|
146
|
-
notes
|
|
147
|
-
)
|
|
142
|
+
repo: string,
|
|
143
|
+
token: string,
|
|
144
|
+
tag: string,
|
|
145
|
+
options: UploadOptions,
|
|
146
|
+
notes: string,
|
|
147
|
+
): Promise < void> {
|
|
148
148
|
const[owner, name] = splitRepo(repo);
|
|
149
149
|
let release = await apiReleaseByTag(owner, name, tag, token);
|
|
150
|
-
if(!release){
|
|
150
|
+
if (!release) {
|
|
151
151
|
release = await apiCreateRelease(owner, name, tag, options.name ?? tag, notes, options.draft, token);
|
|
152
152
|
}
|
|
153
153
|
const cwd = options.cwd ?? process.cwd();
|
|
154
154
|
const files = collectFiles(resolve(cwd, options.dir));
|
|
155
|
-
for(const file of files){
|
|
155
|
+
for (const file of files) {
|
|
156
156
|
const asset =
|
|
157
|
-
relative(resolve(cwd, options.dir), file).split(
|
|
157
|
+
relative(resolve(cwd, options.dir), file).split(/[/\\]/).join("-") || basename(file);
|
|
158
158
|
await apiUploadAsset(owner, name, release.id, asset, file, token);
|
|
159
159
|
console.log(`release: uploaded ${asset}`);
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
-
function printUploadHelp()
|
|
163
|
+
function printUploadHelp(): void {
|
|
164
164
|
console.log(`nifty upload — GitHub Release assets and/or GitHub Pages
|
|
165
165
|
|
|
166
166
|
Usage:
|
|
@@ -178,13 +178,13 @@ Options:
|
|
|
178
178
|
`);
|
|
179
179
|
}
|
|
180
180
|
|
|
181
|
-
async function deployGithubPages(repo
|
|
181
|
+
async function deployGithubPages(repo: string, token: string, dir: string): Promise < void> {
|
|
182
182
|
const[owner, name] = splitRepo(repo);
|
|
183
183
|
const source = resolve(dir);
|
|
184
184
|
const work = mkdtempSync(join(tmpdir(), "nifty-pages-"));
|
|
185
|
-
cpSync(source, work, { recursive
|
|
185
|
+
cpSync(source, work, { recursive: true });
|
|
186
186
|
const nojekyll = join(work, ".nojekyll");
|
|
187
|
-
if(!existsSync(nojekyll)){
|
|
187
|
+
if (!existsSync(nojekyll)) {
|
|
188
188
|
writeFileSync(nojekyll, "");
|
|
189
189
|
}
|
|
190
190
|
git(work, ["init"]);
|
|
@@ -198,21 +198,21 @@ async function deployGithubPages(repo : string, token : string, dir : string) :
|
|
|
198
198
|
console.log(`pages: pushed ${source} to gh-pages`);
|
|
199
199
|
}
|
|
200
200
|
|
|
201
|
-
function collectFiles(dir
|
|
202
|
-
const out
|
|
203
|
-
for(const entry of walk(dir)){
|
|
204
|
-
if(statSync(entry).isFile()){
|
|
201
|
+
function collectFiles(dir: string): string[] {
|
|
202
|
+
const out: string[] = [];
|
|
203
|
+
for (const entry of walk(dir)) {
|
|
204
|
+
if (statSync(entry).isFile()) {
|
|
205
205
|
out.push(entry);
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
return out;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
function walk(dir
|
|
212
|
-
const files
|
|
213
|
-
for(const entry of readdirSync(dir)){
|
|
211
|
+
function walk(dir: string): string[] {
|
|
212
|
+
const files: string[] = [];
|
|
213
|
+
for (const entry of readdirSync(dir)) {
|
|
214
214
|
const path = join(dir, entry);
|
|
215
|
-
if(statSync(path).isDirectory()){
|
|
215
|
+
if (statSync(path).isDirectory()) {
|
|
216
216
|
files.push(...walk(path));
|
|
217
217
|
} else {
|
|
218
218
|
files.push(path);
|
|
@@ -221,93 +221,93 @@ function walk(dir : string) : string[]{
|
|
|
221
221
|
return files;
|
|
222
222
|
}
|
|
223
223
|
|
|
224
|
-
function splitRepo(repo
|
|
224
|
+
function splitRepo(repo: string): [string, string] {
|
|
225
225
|
const parts = repo.split("/");
|
|
226
|
-
if(parts.length!== 2 || !parts[0] || !parts[1]){
|
|
226
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) {
|
|
227
227
|
throw new Error(`invalid repo ${repo}, expected owner/name`);
|
|
228
228
|
}
|
|
229
229
|
return[parts[0], parts[1]];
|
|
230
230
|
}
|
|
231
231
|
|
|
232
232
|
async function apiReleaseByTag(
|
|
233
|
-
owner
|
|
234
|
-
name
|
|
235
|
-
tag
|
|
236
|
-
token
|
|
237
|
-
)
|
|
233
|
+
owner: string,
|
|
234
|
+
name: string,
|
|
235
|
+
tag: string,
|
|
236
|
+
token: string,
|
|
237
|
+
): Promise < GithubRelease | null > {
|
|
238
238
|
const response = await fetch(
|
|
239
239
|
`https://api.github.com/repos/${owner}/${name}/releases/tags/${encodeURIComponent(tag)}`,
|
|
240
|
-
{ headers
|
|
240
|
+
{ headers: githubHeaders(token) },
|
|
241
241
|
);
|
|
242
|
-
if(response.status === 404)return null;
|
|
243
|
-
if(!response.ok){
|
|
242
|
+
if (response.status === 404)return null;
|
|
243
|
+
if (!response.ok) {
|
|
244
244
|
throw new Error(`GitHub API ${response.status}: ${await response.text()}`);
|
|
245
245
|
}
|
|
246
246
|
return(await response.json())as GithubRelease;
|
|
247
247
|
}
|
|
248
248
|
|
|
249
249
|
async function apiCreateRelease(
|
|
250
|
-
owner
|
|
251
|
-
name
|
|
252
|
-
tag
|
|
253
|
-
title
|
|
254
|
-
body
|
|
255
|
-
draft
|
|
256
|
-
token
|
|
257
|
-
)
|
|
250
|
+
owner: string,
|
|
251
|
+
name: string,
|
|
252
|
+
tag: string,
|
|
253
|
+
title: string,
|
|
254
|
+
body: string,
|
|
255
|
+
draft: boolean,
|
|
256
|
+
token: string,
|
|
257
|
+
): Promise < GithubRelease> {
|
|
258
258
|
const response = await fetch(`https://api.github.com/repos/${owner}/${name}/releases`, {
|
|
259
|
-
method
|
|
260
|
-
headers
|
|
261
|
-
body
|
|
259
|
+
method: "POST",
|
|
260
|
+
headers: { ...githubHeaders(token), "Content-Type": "application/json" },
|
|
261
|
+
body: JSON.stringify({ tag_name: tag, name: title, body, draft }),
|
|
262
262
|
});
|
|
263
|
-
if(!response.ok){
|
|
263
|
+
if (!response.ok) {
|
|
264
264
|
throw new Error(`GitHub API ${response.status}: ${await response.text()}`);
|
|
265
265
|
}
|
|
266
266
|
return(await response.json())as GithubRelease;
|
|
267
267
|
}
|
|
268
268
|
|
|
269
269
|
async function apiUploadAsset(
|
|
270
|
-
owner
|
|
271
|
-
name
|
|
272
|
-
releaseId
|
|
273
|
-
assetName
|
|
274
|
-
filePath
|
|
275
|
-
token
|
|
276
|
-
)
|
|
270
|
+
owner: string,
|
|
271
|
+
name: string,
|
|
272
|
+
releaseId: number,
|
|
273
|
+
assetName: string,
|
|
274
|
+
filePath: string,
|
|
275
|
+
token: string,
|
|
276
|
+
): Promise < void> {
|
|
277
277
|
const url = `https://uploads.github.com/repos/${owner}/${name}/releases/${releaseId}/assets?name=${encodeURIComponent(assetName)}`;
|
|
278
278
|
const body = readFileSync(filePath);
|
|
279
279
|
const response = await fetch(url, {
|
|
280
|
-
method
|
|
281
|
-
headers
|
|
280
|
+
method: "POST",
|
|
281
|
+
headers: {
|
|
282
282
|
...githubHeaders(token),
|
|
283
|
-
"Content-Type"
|
|
284
|
-
"Content-Length"
|
|
283
|
+
"Content-Type": "application/octet-stream",
|
|
284
|
+
"Content-Length": String(body.length),
|
|
285
285
|
},
|
|
286
286
|
body,
|
|
287
287
|
});
|
|
288
288
|
const text = await response.text();
|
|
289
|
-
if(response.ok){
|
|
289
|
+
if (response.ok) {
|
|
290
290
|
return;
|
|
291
291
|
}
|
|
292
|
-
if(response.status === 422 && text.includes("already_exists")){
|
|
292
|
+
if (response.status === 422 && text.includes("already_exists")) {
|
|
293
293
|
console.log(`release: skip ${assetName} (already uploaded)`);
|
|
294
294
|
return;
|
|
295
295
|
}
|
|
296
296
|
throw new Error(`GitHub upload ${response.status}: ${text}`);
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
-
function githubHeaders(token
|
|
299
|
+
function githubHeaders(token: string): Record < string, string > {
|
|
300
300
|
return {
|
|
301
|
-
Accept
|
|
302
|
-
Authorization
|
|
303
|
-
"User-Agent"
|
|
304
|
-
"X-GitHub-Api-Version"
|
|
301
|
+
Accept: "application/vnd.github+json",
|
|
302
|
+
Authorization: `Bearer ${token}`,
|
|
303
|
+
"User-Agent": USER_AGENT,
|
|
304
|
+
"X-GitHub-Api-Version": "2022-11-28",
|
|
305
305
|
};
|
|
306
306
|
}
|
|
307
307
|
|
|
308
|
-
function git(cwd
|
|
309
|
-
const result = spawnSync("git", args, { cwd, stdio
|
|
310
|
-
if(result.status!== 0){
|
|
308
|
+
function git(cwd: string, args: string[]): void {
|
|
309
|
+
const result = spawnSync("git", args, { cwd, stdio: "inherit" });
|
|
310
|
+
if (result.status !== 0) {
|
|
311
311
|
throw new Error(`git ${args.join(" ")} failed`);
|
|
312
312
|
}
|
|
313
313
|
}
|
package/src/cli/workspace.ts
CHANGED
|
@@ -4,22 +4,22 @@ import { join, resolve } from "node:path";
|
|
|
4
4
|
import { detectProjectLayout } from "../config/detectProject.js";
|
|
5
5
|
|
|
6
6
|
export type WorkspacePackage = {
|
|
7
|
-
name
|
|
8
|
-
version
|
|
9
|
-
dir
|
|
10
|
-
manifestPath
|
|
11
|
-
private
|
|
12
|
-
manifest
|
|
7
|
+
name: string;
|
|
8
|
+
version: string;
|
|
9
|
+
dir: string;
|
|
10
|
+
manifestPath: string;
|
|
11
|
+
private: boolean;
|
|
12
|
+
manifest: PackageManifest;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
export type PackageManifest = {
|
|
16
|
-
name
|
|
17
|
-
version
|
|
18
|
-
private
|
|
19
|
-
dependencies
|
|
20
|
-
devDependencies
|
|
21
|
-
optionalDependencies
|
|
22
|
-
peerDependencies
|
|
16
|
+
name: string;
|
|
17
|
+
version: string;
|
|
18
|
+
private?: boolean;
|
|
19
|
+
dependencies?: Record < string, string > ;
|
|
20
|
+
devDependencies?: Record < string, string > ;
|
|
21
|
+
optionalDependencies?: Record < string, string > ;
|
|
22
|
+
peerDependencies?: Record < string, string > ;
|
|
23
23
|
};
|
|
24
24
|
|
|
25
25
|
const DEPENDENCY_FIELDS = [
|
|
@@ -29,68 +29,68 @@ const DEPENDENCY_FIELDS = [
|
|
|
29
29
|
"peerDependencies",
|
|
30
30
|
]as const;
|
|
31
31
|
|
|
32
|
-
export function findWorkspaceRoot(cwd
|
|
32
|
+
export function findWorkspaceRoot(cwd: string): string {
|
|
33
33
|
const layout = detectProjectLayout(cwd);
|
|
34
34
|
const candidates = [layout.root, resolve(cwd)];
|
|
35
|
-
for(const candidate of candidates){
|
|
35
|
+
for (const candidate of candidates) {
|
|
36
36
|
const crates = join(candidate, "projects", "crates");
|
|
37
37
|
const packages = join(candidate, "projects", "packages");
|
|
38
|
-
if(existsSync(crates) && existsSync(packages)){
|
|
38
|
+
if (existsSync(crates) && existsSync(packages)) {
|
|
39
39
|
return candidate;
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
throw new Error("could not find Nifty workspace (expected projects/crates and projects/packages)");
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
export function listWorkspacePackages(root
|
|
45
|
+
export function listWorkspacePackages(root: string): WorkspacePackage[] {
|
|
46
46
|
const packagesDir = join(root, "projects", "packages");
|
|
47
|
-
if(!existsSync(packagesDir)){
|
|
47
|
+
if (!existsSync(packagesDir)) {
|
|
48
48
|
return[];
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
const packages
|
|
52
|
-
for(const entry of readdirSync(packagesDir, { withFileTypes
|
|
53
|
-
if(!entry.isDirectory() || entry.name === "node_modules"){
|
|
51
|
+
const packages: WorkspacePackage[] = [];
|
|
52
|
+
for (const entry of readdirSync(packagesDir, { withFileTypes: true })) {
|
|
53
|
+
if (!entry.isDirectory() || entry.name === "node_modules") {
|
|
54
54
|
continue;
|
|
55
55
|
}
|
|
56
56
|
const manifestPath = join(packagesDir, entry.name, "package.json");
|
|
57
|
-
if(!existsSync(manifestPath)){
|
|
57
|
+
if (!existsSync(manifestPath)) {
|
|
58
58
|
continue;
|
|
59
59
|
}
|
|
60
60
|
const manifest = JSON.parse(readFileSync(manifestPath, "utf8"))as PackageManifest;
|
|
61
|
-
if(!manifest.name || !manifest.version){
|
|
61
|
+
if (!manifest.name || !manifest.version) {
|
|
62
62
|
throw new Error(`package.json missing name or version: ${manifestPath}`);
|
|
63
63
|
}
|
|
64
64
|
packages.push({
|
|
65
|
-
name
|
|
66
|
-
version
|
|
67
|
-
dir
|
|
65
|
+
name: manifest.name,
|
|
66
|
+
version: manifest.version,
|
|
67
|
+
dir: join(packagesDir, entry.name),
|
|
68
68
|
manifestPath,
|
|
69
|
-
private
|
|
69
|
+
private: manifest.private === true,
|
|
70
70
|
manifest,
|
|
71
71
|
});
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
-
return packages.sort((a, b) =>a.name.localeCompare(b.name));
|
|
74
|
+
return packages.sort((a, b) => a.name.localeCompare(b.name));
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
export function collectInternalDependencyNames(
|
|
78
|
-
pkg
|
|
79
|
-
byName
|
|
80
|
-
)
|
|
81
|
-
const deps = new Set<string>();
|
|
82
|
-
for(const field of DEPENDENCY_FIELDS){
|
|
78
|
+
pkg: WorkspacePackage,
|
|
79
|
+
byName: Map < string, WorkspacePackage > ,
|
|
80
|
+
): Set < string> {
|
|
81
|
+
const deps = new Set < string> ();
|
|
82
|
+
for (const field of DEPENDENCY_FIELDS) {
|
|
83
83
|
const entries = pkg.manifest[field];
|
|
84
|
-
if(!entries){
|
|
84
|
+
if (!entries) {
|
|
85
85
|
continue;
|
|
86
86
|
}
|
|
87
|
-
for(const[depName, spec]of Object.entries(entries)){
|
|
88
|
-
if(byName.has(depName)){
|
|
87
|
+
for (const[depName, spec]of Object.entries(entries)) {
|
|
88
|
+
if (byName.has(depName)) {
|
|
89
89
|
deps.add(depName);
|
|
90
90
|
continue;
|
|
91
91
|
}
|
|
92
92
|
const resolved = resolveWorkspaceDependencyName(spec, pkg.dir, byName);
|
|
93
|
-
if(resolved){
|
|
93
|
+
if (resolved) {
|
|
94
94
|
deps.add(resolved);
|
|
95
95
|
}
|
|
96
96
|
}
|
|
@@ -99,24 +99,24 @@ export function collectInternalDependencyNames(
|
|
|
99
99
|
}
|
|
100
100
|
|
|
101
101
|
function resolveWorkspaceDependencyName(
|
|
102
|
-
spec
|
|
103
|
-
packageDir
|
|
104
|
-
byName
|
|
105
|
-
)
|
|
106
|
-
if(spec.startsWith("workspace:")){
|
|
102
|
+
spec: string,
|
|
103
|
+
packageDir: string,
|
|
104
|
+
byName: Map < string, WorkspacePackage > ,
|
|
105
|
+
): string | undefined {
|
|
106
|
+
if (spec.startsWith("workspace:")) {
|
|
107
107
|
return undefined;
|
|
108
108
|
}
|
|
109
|
-
if(!spec.startsWith("file:")){
|
|
109
|
+
if (!spec.startsWith("file:")) {
|
|
110
110
|
return undefined;
|
|
111
111
|
}
|
|
112
112
|
const targetDir = resolve(packageDir, spec.slice("file:".length));
|
|
113
|
-
for(const candidate of byName.values()){
|
|
114
|
-
if(candidate.dir === targetDir){
|
|
113
|
+
for (const candidate of byName.values()) {
|
|
114
|
+
if (candidate.dir === targetDir) {
|
|
115
115
|
return candidate.name;
|
|
116
116
|
}
|
|
117
117
|
}
|
|
118
118
|
const manifestPath = join(targetDir, "package.json");
|
|
119
|
-
if(!existsSync(manifestPath)){
|
|
119
|
+
if (!existsSync(manifestPath)) {
|
|
120
120
|
return undefined;
|
|
121
121
|
}
|
|
122
122
|
const manifest = JSON.parse(readFileSync(manifestPath, "utf8"))as PackageManifest;
|
package/src/config/authorMap.ts
CHANGED
|
@@ -7,19 +7,15 @@ import type { NiftyConfig } from "./types.js";
|
|
|
7
7
|
export const DEFAULT_AUTHOR_MAP_PATH = "documentation/maintenance/author-github.json";
|
|
8
8
|
|
|
9
9
|
/** Resolve configured author map path to an absolute filesystem path. */
|
|
10
|
-
export function resolveAuthorMapPath(config
|
|
10
|
+
export function resolveAuthorMapPath(config: NiftyConfig, repoRoot: string): string {
|
|
11
11
|
const configured = config.authorMap ?? DEFAULT_AUTHOR_MAP_PATH;
|
|
12
12
|
return isAbsolute(configured) ? configured : join(repoRoot, configured);
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
/** Load author map file contents for native helpers expecting JSON text. */
|
|
16
|
-
export function loadAuthorMapJson(repoRoot
|
|
17
|
-
const abs = authorMapPath
|
|
18
|
-
|
|
19
|
-
? authorMapPath
|
|
20
|
-
: join(repoRoot, authorMapPath)
|
|
21
|
-
: resolveAuthorMapPath({ }, repoRoot);
|
|
22
|
-
if(!existsSync(abs)){
|
|
16
|
+
export function loadAuthorMapJson(repoRoot: string, authorMapPath?: string) : string {
|
|
17
|
+
const abs = authorMapPath ? isAbsolute(authorMapPath) ? authorMapPath : join(repoRoot, authorMapPath) : resolveAuthorMapPath({ }, repoRoot);
|
|
18
|
+
if (!existsSync(abs)) {
|
|
23
19
|
return "{}";
|
|
24
20
|
}
|
|
25
21
|
return readFileSync(abs, "utf8");
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { NiftyConfig, NiftyConfigEnv } from "./types.js";
|
|
2
2
|
|
|
3
3
|
/** Type-safe helper for `nifty.config.ts` / `nifty.config.js`. */
|
|
4
|
-
export function defineConfig(config
|
|
4
|
+
export function defineConfig(config: NiftyConfig): NiftyConfig;
|
|
5
5
|
export function defineConfig(
|
|
6
|
-
config
|
|
7
|
-
)
|
|
6
|
+
config: (env: NiftyConfigEnv) => NiftyConfig | Promise < NiftyConfig> ,
|
|
7
|
+
): (env: NiftyConfigEnv) => NiftyConfig | Promise < NiftyConfig> ;
|
|
8
8
|
export function defineConfig(
|
|
9
|
-
config
|
|
10
|
-
)
|
|
9
|
+
config: NiftyConfig | ((env: NiftyConfigEnv) => NiftyConfig | Promise < NiftyConfig> ),
|
|
10
|
+
): NiftyConfig | ((env: NiftyConfigEnv) => NiftyConfig | Promise < NiftyConfig> ) {
|
|
11
11
|
return config;
|
|
12
12
|
}
|