@doki-land/nifty 0.0.12 → 0.1.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/cli/nifty.mjs +2 -2
- package/locales/en-US/cli.json +1 -1
- 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 +81 -81
- package/src/cli/change-logs-cmd.ts +26 -26
- package/src/cli/cli.ts +3 -3
- package/src/cli/commit-cmd.ts +77 -77
- package/src/cli/commit-lint-report.ts +44 -44
- 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 +49 -49
- package/src/cli/options.ts +16 -16
- package/src/cli/publish-cmd.ts +18 -16
- 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 +13 -10
- package/src/cli/trust.ts +30 -27
- 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 +132 -132
- package/src/cli/workspace.ts +49 -49
- package/src/config/authorMap.ts +4 -4
- package/src/config/defineConfig.ts +5 -5
- package/src/config/detectProject.ts +46 -46
- package/src/config/formatPresets.ts +26 -26
- package/src/config/index.ts +3 -0
- package/src/config/loadConfig.ts +35 -35
- package/src/config/trustPayload.ts +14 -0
- package/src/config/types.ts +60 -37
- package/src/git.ts +14 -14
- package/src/github.ts +54 -54
- package/src/gitmoji.ts +18 -18
- package/src/index.ts +3 -0
- package/src/native.ts +601 -591
- package/src/nifty.ts +30 -30
- package/src/types.ts +17 -17
package/src/git.ts
CHANGED
|
@@ -2,60 +2,60 @@ import type { CommitRecord, RangeInfo, TagInfo } from "./types.js";
|
|
|
2
2
|
import { loadNiftyNative, mapCommitRecord, mapRangeInfo, mapTagInfo, type GitExports } from "./native.js";
|
|
3
3
|
|
|
4
4
|
export type ResolveRangeOptions = {
|
|
5
|
-
version
|
|
6
|
-
fromRef
|
|
7
|
-
toRef
|
|
5
|
+
version ? : string;
|
|
6
|
+
fromRef ? : string;
|
|
7
|
+
toRef ? : string;
|
|
8
8
|
};
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Read-only git repository helpers (gix via Node-API, no `git` subprocess).
|
|
12
12
|
*/
|
|
13
13
|
export class Git {
|
|
14
|
-
constructor(private readonly wasm: GitExports)
|
|
14
|
+
constructor(private readonly wasm : GitExports){ }
|
|
15
15
|
|
|
16
|
-
static open(): Git {
|
|
16
|
+
static open() : Git {
|
|
17
17
|
const native = loadNiftyNative();
|
|
18
18
|
return new Git(native.git);
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/** Walk upward from `startPath` to find the working tree root containing `.git`. */
|
|
22
|
-
discoverRoot(startPath: string): string {
|
|
22
|
+
discoverRoot(startPath : string) : string {
|
|
23
23
|
return this.wasm["discover-root"](startPath);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/** List `v*` tags sorted by semver. */
|
|
27
|
-
listVersionTags(repoRoot: string): string[]
|
|
27
|
+
listVersionTags(repoRoot : string) : string[]{
|
|
28
28
|
return this.wasm["list-version-tags"](repoRoot);
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
listTagInfos(repoRoot: string): TagInfo[]
|
|
31
|
+
listTagInfos(repoRoot : string) : TagInfo[]{
|
|
32
32
|
return this.wasm["list-tag-infos"](repoRoot).map(mapTagInfo);
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
formatTagList(repoRoot: string): string {
|
|
35
|
+
formatTagList(repoRoot : string) : string {
|
|
36
36
|
return this.wasm["format-tag-list"](repoRoot);
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
resolveRange(repoRoot: string, options: ResolveRangeOptions = {}): RangeInfo {
|
|
39
|
+
resolveRange(repoRoot : string, options : ResolveRangeOptions = { }) : RangeInfo {
|
|
40
40
|
return mapRangeInfo(
|
|
41
41
|
this.wasm["resolve-range"](repoRoot, options.version, options.fromRef, options.toRef),
|
|
42
42
|
);
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
/** Collect non-merge commits in `fromRef..toRef` (exclusive..inclusive). */
|
|
46
|
-
collectCommits(repoRoot: string, fromRef: string | undefined, toRef: string): CommitRecord[]
|
|
46
|
+
collectCommits(repoRoot : string, fromRef : string | undefined, toRef : string) : CommitRecord[]{
|
|
47
47
|
return this.wasm["collect-commits"](repoRoot, fromRef, toRef).map(mapCommitRecord);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
detectGithubRepo(repoRoot: string): string | undefined {
|
|
50
|
+
detectGithubRepo(repoRoot : string) : string | undefined {
|
|
51
51
|
return this.wasm["detect-github-repo"](repoRoot);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
parseGithubRemote(url: string): string | undefined {
|
|
54
|
+
parseGithubRemote(url : string) : string | undefined {
|
|
55
55
|
return this.wasm["parse-github-remote"](url);
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
export function createGit(): Git {
|
|
59
|
+
export function createGit() : Git {
|
|
60
60
|
return Git.open();
|
|
61
61
|
}
|
package/src/github.ts
CHANGED
|
@@ -3,130 +3,130 @@ import type { GithubAuthor } from "./types.js";
|
|
|
3
3
|
const USER_AGENT = "nifty-github";
|
|
4
4
|
const ACCEPT = "application/vnd.github+json";
|
|
5
5
|
|
|
6
|
-
function parseUserJson(body: Record<string, unknown>, fallbackLogin
|
|
6
|
+
function parseUserJson(body : Record<string, unknown>, fallbackLogin ? : string) : GithubAuthor {
|
|
7
7
|
const id = typeof body.id === "number" ? BigInt(body.id) : undefined;
|
|
8
8
|
const login = typeof body.login === "string" ? body.login : fallbackLogin;
|
|
9
|
-
if
|
|
9
|
+
if(id === undefined && login === undefined){
|
|
10
10
|
throw new Error("GitHub user response missing id and login");
|
|
11
11
|
}
|
|
12
12
|
return { id, login };
|
|
13
13
|
}
|
|
14
14
|
|
|
15
|
-
async function getJson(url: string, token
|
|
16
|
-
const headers: Record<string, string> = {
|
|
17
|
-
Accept: ACCEPT,
|
|
18
|
-
"User-Agent": USER_AGENT,
|
|
15
|
+
async function getJson(url : string, token ? : string) : Promise<Record<string, unknown>>{
|
|
16
|
+
const headers : Record<string, string> = {
|
|
17
|
+
Accept : ACCEPT,
|
|
18
|
+
"User-Agent" : USER_AGENT,
|
|
19
19
|
};
|
|
20
|
-
if
|
|
20
|
+
if(token ?.trim()){
|
|
21
21
|
headers.Authorization = `Bearer ${token.trim()}`;
|
|
22
22
|
}
|
|
23
23
|
const response = await fetch(url, { headers });
|
|
24
|
-
if
|
|
24
|
+
if(response.status === 404){
|
|
25
25
|
throw new Error("GitHub resource not found");
|
|
26
26
|
}
|
|
27
|
-
if
|
|
27
|
+
if(!response.ok){
|
|
28
28
|
throw new Error(`GitHub API error: ${response.status} ${response.statusText}`);
|
|
29
29
|
}
|
|
30
|
-
return
|
|
30
|
+
return(await response.json())as Record<string, unknown>;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
-
function parseNoreplyEmail(email: string): GithubAuthor | undefined {
|
|
33
|
+
function parseNoreplyEmail(email : string) : GithubAuthor | undefined {
|
|
34
34
|
const trimmed = email.trim();
|
|
35
35
|
const suffix = "@users.noreply.github.com";
|
|
36
36
|
const lower = trimmed.toLowerCase();
|
|
37
|
-
if
|
|
37
|
+
if(!lower.endsWith(suffix)){
|
|
38
38
|
return undefined;
|
|
39
39
|
}
|
|
40
|
-
const local = trimmed.slice(0, -suffix.length);
|
|
40
|
+
const local = trimmed.slice(0, - suffix.length);
|
|
41
41
|
const plus = local.indexOf("+");
|
|
42
|
-
if
|
|
42
|
+
if(plus>= 0){
|
|
43
43
|
const idPart = local.slice(0, plus);
|
|
44
44
|
const login = local.slice(plus + 1);
|
|
45
|
-
if
|
|
45
|
+
if(!login){
|
|
46
46
|
return undefined;
|
|
47
47
|
}
|
|
48
|
-
return { id: BigInt(idPart), login };
|
|
48
|
+
return { id : BigInt(idPart), login };
|
|
49
49
|
}
|
|
50
|
-
if
|
|
50
|
+
if(!local){
|
|
51
51
|
return undefined;
|
|
52
52
|
}
|
|
53
|
-
return { login: local };
|
|
53
|
+
return { login : local };
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
function loadAuthorMap(json: string): Map<string, GithubAuthor>
|
|
56
|
+
function loadAuthorMap(json : string) : Map<string, GithubAuthor>{
|
|
57
57
|
const map = new Map<string, GithubAuthor>();
|
|
58
|
-
if
|
|
58
|
+
if(!json.trim()){
|
|
59
59
|
return map;
|
|
60
60
|
}
|
|
61
|
-
const parsed = JSON.parse(json)
|
|
62
|
-
for
|
|
63
|
-
const author: GithubAuthor = {};
|
|
64
|
-
if
|
|
61
|
+
const parsed = JSON.parse(json)as Record<string, { id ? : number; login ? : string }>;
|
|
62
|
+
for(const[email, entry]of Object.entries(parsed)){
|
|
63
|
+
const author : GithubAuthor = { };
|
|
64
|
+
if(typeof entry.id === "number"){
|
|
65
65
|
author.id = BigInt(entry.id);
|
|
66
66
|
}
|
|
67
|
-
if
|
|
67
|
+
if(typeof entry.login === "string" && entry.login.trim()){
|
|
68
68
|
author.login = entry.login.trim();
|
|
69
69
|
}
|
|
70
|
-
if
|
|
70
|
+
if(author.id!== undefined || author.login!== undefined){
|
|
71
71
|
map.set(email.trim().toLowerCase(), author);
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
return map;
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
function mergeAuthors(existing: GithubAuthor, incoming: GithubAuthor): GithubAuthor {
|
|
77
|
+
function mergeAuthors(existing : GithubAuthor, incoming : GithubAuthor) : GithubAuthor {
|
|
78
78
|
return {
|
|
79
|
-
id: existing.id ?? incoming.id,
|
|
80
|
-
login: existing.login ?? incoming.login,
|
|
79
|
+
id : existing.id ?? incoming.id,
|
|
80
|
+
login : existing.login ?? incoming.login,
|
|
81
81
|
};
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
-
async function enrichAuthor(author: GithubAuthor, token
|
|
85
|
-
if
|
|
84
|
+
async function enrichAuthor(author : GithubAuthor, token ? : string, fetch = false) : Promise<GithubAuthor>{
|
|
85
|
+
if(!fetch && author.id!== undefined && author.login!== undefined){
|
|
86
86
|
return author;
|
|
87
87
|
}
|
|
88
|
-
if
|
|
88
|
+
if(!fetch && author.id!== undefined){
|
|
89
89
|
return author;
|
|
90
90
|
}
|
|
91
|
-
if
|
|
91
|
+
if(author.login && (author.id === undefined || fetch)){
|
|
92
92
|
const fetched = await userByLoginFetch(author.login, token);
|
|
93
93
|
return mergeAuthors(author, fetched);
|
|
94
94
|
}
|
|
95
95
|
return author;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
async function userByLoginFetch(login: string, token
|
|
98
|
+
async function userByLoginFetch(login : string, token ? : string) : Promise<GithubAuthor>{
|
|
99
99
|
const trimmed = login.trim();
|
|
100
|
-
if
|
|
100
|
+
if(!trimmed){
|
|
101
101
|
throw new Error("login must not be empty");
|
|
102
102
|
}
|
|
103
103
|
const body = await getJson(`https://api.github.com/users/${trimmed}`, token);
|
|
104
104
|
return parseUserJson(body, trimmed);
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
async function searchUserByEmailFetch(email: string, token: string): Promise<GithubAuthor | undefined>
|
|
107
|
+
async function searchUserByEmailFetch(email : string, token : string) : Promise<GithubAuthor | undefined>{
|
|
108
108
|
const trimmed = email.trim();
|
|
109
109
|
const auth = token.trim();
|
|
110
|
-
if
|
|
110
|
+
if(!trimmed){
|
|
111
111
|
throw new Error("email must not be empty");
|
|
112
112
|
}
|
|
113
|
-
if
|
|
113
|
+
if(!auth){
|
|
114
114
|
throw new Error("GitHub token is required for email search");
|
|
115
115
|
}
|
|
116
116
|
const query = encodeURIComponent(`${trimmed} in:email`);
|
|
117
117
|
const body = await getJson(`https://api.github.com/search/users?q=${query}`, auth);
|
|
118
118
|
const items = body.items;
|
|
119
|
-
if
|
|
119
|
+
if(!Array.isArray(items) || items.length === 0){
|
|
120
120
|
return undefined;
|
|
121
121
|
}
|
|
122
|
-
const first = items[0]
|
|
122
|
+
const first = items[0]as Record<string, unknown>;
|
|
123
123
|
return parseUserJson(first);
|
|
124
124
|
}
|
|
125
125
|
|
|
126
126
|
export type LookupUserOptions = {
|
|
127
|
-
authorMapJson
|
|
128
|
-
token
|
|
129
|
-
fetch
|
|
127
|
+
authorMapJson ? : string;
|
|
128
|
+
token ? : string;
|
|
129
|
+
fetch ? : boolean;
|
|
130
130
|
};
|
|
131
131
|
|
|
132
132
|
/**
|
|
@@ -134,43 +134,43 @@ export type LookupUserOptions = {
|
|
|
134
134
|
* Rust equivalent: `nifty-github` crate.
|
|
135
135
|
*/
|
|
136
136
|
export class Github {
|
|
137
|
-
constructor(private readonly token
|
|
137
|
+
constructor(private readonly token ? : string){ }
|
|
138
138
|
|
|
139
|
-
static open(token
|
|
139
|
+
static open(token ? : string) : Github {
|
|
140
140
|
return new Github(token);
|
|
141
141
|
}
|
|
142
142
|
|
|
143
|
-
async userByLogin(login: string, token
|
|
143
|
+
async userByLogin(login : string, token ? : string) : Promise<GithubAuthor>{
|
|
144
144
|
return userByLoginFetch(login, token ?? this.token);
|
|
145
145
|
}
|
|
146
146
|
|
|
147
|
-
async searchUserByEmail(email: string, token
|
|
147
|
+
async searchUserByEmail(email : string, token ? : string) : Promise<GithubAuthor | undefined>{
|
|
148
148
|
const auth = token ?? this.token;
|
|
149
|
-
if
|
|
149
|
+
if(!auth){
|
|
150
150
|
throw new Error("GitHub token is required for email search");
|
|
151
151
|
}
|
|
152
152
|
return searchUserByEmailFetch(email, auth);
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
-
async lookupUserByEmail(email: string, options: LookupUserOptions = {}): Promise<GithubAuthor | undefined>
|
|
155
|
+
async lookupUserByEmail(email : string, options : LookupUserOptions = { }) : Promise<GithubAuthor | undefined>{
|
|
156
156
|
const token = options.token ?? this.token;
|
|
157
157
|
const fetch = options.fetch ?? false;
|
|
158
158
|
const mapJson = options.authorMapJson ?? "{}";
|
|
159
159
|
|
|
160
160
|
const fromNoreply = parseNoreplyEmail(email);
|
|
161
|
-
if
|
|
161
|
+
if(fromNoreply){
|
|
162
162
|
return enrichAuthor(fromNoreply, token, fetch);
|
|
163
163
|
}
|
|
164
164
|
|
|
165
165
|
const map = loadAuthorMap(mapJson);
|
|
166
166
|
const mapped = map.get(email.trim().toLowerCase());
|
|
167
|
-
if
|
|
167
|
+
if(mapped){
|
|
168
168
|
return enrichAuthor(mapped, token, fetch);
|
|
169
169
|
}
|
|
170
170
|
|
|
171
|
-
if
|
|
171
|
+
if(token){
|
|
172
172
|
const found = await searchUserByEmailFetch(email, token);
|
|
173
|
-
if
|
|
173
|
+
if(found){
|
|
174
174
|
return enrichAuthor(found, token, fetch);
|
|
175
175
|
}
|
|
176
176
|
}
|
|
@@ -179,6 +179,6 @@ export class Github {
|
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
|
|
182
|
-
export function createGithub(token
|
|
182
|
+
export function createGithub(token ? : string) : Github {
|
|
183
183
|
return Github.open(token);
|
|
184
184
|
}
|
package/src/gitmoji.ts
CHANGED
|
@@ -6,72 +6,72 @@ import { loadNiftyNative, type GitmojiExports } from "./native.js";
|
|
|
6
6
|
*/
|
|
7
7
|
export class Gitmoji {
|
|
8
8
|
constructor(
|
|
9
|
-
private readonly wasm: GitmojiExports,
|
|
9
|
+
private readonly wasm : GitmojiExports,
|
|
10
10
|
private readonly defaultAuthorMapJson = "{}",
|
|
11
|
-
)
|
|
11
|
+
){ }
|
|
12
12
|
|
|
13
|
-
static open(authorMapJson = "{}"): Gitmoji {
|
|
13
|
+
static open(authorMapJson = "{}") : Gitmoji {
|
|
14
14
|
const native = loadNiftyNative();
|
|
15
15
|
return new Gitmoji(native.gitmoji, authorMapJson);
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
knownGitmojis(): string[]
|
|
18
|
+
knownGitmojis() : string[]{
|
|
19
19
|
return this.wasm["known-gitmojis"]();
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
validateSubject(subject: string): boolean {
|
|
22
|
+
validateSubject(subject : string) : boolean {
|
|
23
23
|
return this.wasm["validate-subject"](subject);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
parseSubject(subject: string): ParsedSubject {
|
|
26
|
+
parseSubject(subject : string) : ParsedSubject {
|
|
27
27
|
return this.wasm["parse-subject"](subject);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
formatSubject(gitmoji: string, body: string): string {
|
|
30
|
+
formatSubject(gitmoji : string, body : string) : string {
|
|
31
31
|
return this.wasm["format-subject"](gitmoji, body);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
stripGitmoji(subject: string): string {
|
|
34
|
+
stripGitmoji(subject : string) : string {
|
|
35
35
|
return this.wasm["strip-gitmoji"](subject);
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
-
leadingGitmoji(subject: string): string | undefined {
|
|
38
|
+
leadingGitmoji(subject : string) : string | undefined {
|
|
39
39
|
return this.wasm["leading-gitmoji"](subject);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
-
sectionForGitmoji(gitmoji
|
|
42
|
+
sectionForGitmoji(gitmoji ? : string) : ReleaseSection {
|
|
43
43
|
return this.wasm["section-for-gitmoji"](gitmoji);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
parseNoreplyEmail(email: string): GithubAuthor | undefined {
|
|
46
|
+
parseNoreplyEmail(email : string) : GithubAuthor | undefined {
|
|
47
47
|
return this.wasm["parse-noreply-email"](email);
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
resolveGithubAuthor(email: string, authorMapJson = this.defaultAuthorMapJson): GithubAuthor | undefined {
|
|
50
|
+
resolveGithubAuthor(email : string, authorMapJson = this.defaultAuthorMapJson) : GithubAuthor | undefined {
|
|
51
51
|
return this.wasm["resolve-github-author"](email, authorMapJson);
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
displayLogin(author: GithubAuthor): string {
|
|
54
|
+
displayLogin(author : GithubAuthor) : string {
|
|
55
55
|
return this.wasm["display-login"](author);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
profileUrl(author: GithubAuthor): string {
|
|
58
|
+
profileUrl(author : GithubAuthor) : string {
|
|
59
59
|
return this.wasm["profile-url"](author);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
avatarUrl(author: GithubAuthor): string {
|
|
62
|
+
avatarUrl(author : GithubAuthor) : string {
|
|
63
63
|
return this.wasm["avatar-url"](author);
|
|
64
64
|
}
|
|
65
65
|
|
|
66
|
-
authorMention(email: string, authorName: string, authorMapJson = this.defaultAuthorMapJson): string {
|
|
66
|
+
authorMention(email : string, authorName : string, authorMapJson = this.defaultAuthorMapJson) : string {
|
|
67
67
|
return this.wasm["author-mention"](email, authorName, authorMapJson);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
commitBullet(body: string, email: string, authorName: string, authorMapJson = this.defaultAuthorMapJson): string {
|
|
70
|
+
commitBullet(body : string, email : string, authorName : string, authorMapJson = this.defaultAuthorMapJson) : string {
|
|
71
71
|
return this.wasm["commit-bullet"](body, email, authorName, authorMapJson);
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
export function createGitmoji(): Gitmoji {
|
|
75
|
+
export function createGitmoji() : Gitmoji {
|
|
76
76
|
return Gitmoji.open();
|
|
77
77
|
}
|
package/src/index.ts
CHANGED