ts-repo-utils 1.2.1 → 2.0.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 +5 -0
- package/dist/functions/assert-ext.d.mts.map +1 -1
- package/dist/functions/assert-ext.mjs +2 -5
- package/dist/functions/assert-ext.mjs.map +1 -1
- package/dist/functions/assert-repo-is-dirty.d.mts.map +1 -1
- package/dist/functions/assert-repo-is-dirty.mjs +8 -6
- package/dist/functions/assert-repo-is-dirty.mjs.map +1 -1
- package/dist/functions/diff.d.mts +16 -0
- package/dist/functions/diff.d.mts.map +1 -0
- package/dist/functions/diff.mjs +47 -0
- package/dist/functions/diff.mjs.map +1 -0
- package/dist/functions/exec-async.d.mts +5 -9
- package/dist/functions/exec-async.d.mts.map +1 -1
- package/dist/functions/exec-async.mjs +3 -2
- package/dist/functions/exec-async.mjs.map +1 -1
- package/dist/functions/format.d.mts +3 -2
- package/dist/functions/format.d.mts.map +1 -1
- package/dist/functions/format.mjs +27 -43
- package/dist/functions/format.mjs.map +1 -1
- package/dist/functions/gen-index.d.mts.map +1 -1
- package/dist/functions/gen-index.mjs +3 -2
- package/dist/functions/gen-index.mjs.map +1 -1
- package/dist/functions/index.d.mts +1 -0
- package/dist/functions/index.d.mts.map +1 -1
- package/dist/functions/index.mjs +2 -1
- package/dist/functions/index.mjs.map +1 -1
- package/dist/index.mjs +2 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -2
- package/src/functions/assert-ext.mts +4 -7
- package/src/functions/assert-repo-is-dirty.mts +9 -6
- package/src/functions/diff.mts +62 -0
- package/src/functions/diff.test.mts +152 -0
- package/src/functions/exec-async.mts +6 -8
- package/src/functions/format.mts +26 -49
- package/src/functions/format.test.mts +1 -21
- package/src/functions/gen-index.mts +3 -2
- package/src/functions/index.mts +1 -0
package/README.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# ts-repo-utils
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/ts-repo-utils)
|
|
4
|
+
[](https://www.npmjs.com/package/ts-repo-utils)
|
|
5
|
+
[](./LICENSE)
|
|
6
|
+
[](https://codecov.io/gh/noshiro-pf/ts-repo-utils)
|
|
7
|
+
|
|
3
8
|
Utilities for TypeScript Repositories.
|
|
4
9
|
|
|
5
10
|
A comprehensive toolkit for managing TypeScript projects with strict ESM support, providing essential utilities for file validation, code formatting, git operations, and project automation.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assert-ext.d.mts","sourceRoot":"","sources":["../../src/functions/assert-ext.mts"],"names":[],"mappings":"AAAA,OAAO,oBAAoB,CAAC;AAG5B;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,YAAY,CAAC;IACxC,6DAA6D;IAC7D,WAAW,EAAE;QACX,8BAA8B;QAC9B,IAAI,EAAE,MAAM,CAAC;QACb,kDAAkD;QAClD,SAAS,EAAE,MAAM,CAAC;QAClB,sFAAsF;QACtF,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;KAC3B,EAAE,CAAC;CACL,CAAC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAU,QAAQ,cAAc,KAAG,OAAO,CAAC,IAAI,
|
|
1
|
+
{"version":3,"file":"assert-ext.d.mts","sourceRoot":"","sources":["../../src/functions/assert-ext.mts"],"names":[],"mappings":"AAAA,OAAO,oBAAoB,CAAC;AAG5B;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,YAAY,CAAC;IACxC,6DAA6D;IAC7D,WAAW,EAAE;QACX,8BAA8B;QAC9B,IAAI,EAAE,MAAM,CAAC;QACb,kDAAkD;QAClD,SAAS,EAAE,MAAM,CAAC;QAClB,sFAAsF;QACtF,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;KAC3B,EAAE,CAAC;CACL,CAAC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,SAAS,GAAU,QAAQ,cAAc,KAAG,OAAO,CAAC,IAAI,CAyDpE,CAAC"}
|
|
@@ -7,7 +7,6 @@ import { assertPathExists } from './assert-path-exists.mjs';
|
|
|
7
7
|
* @param config - Configuration specifying directories and expected extensions.
|
|
8
8
|
*/
|
|
9
9
|
const assertExt = async (config) => {
|
|
10
|
-
const allIncorrectFiles = [];
|
|
11
10
|
// Check all directories in parallel
|
|
12
11
|
const results = await Promise.all(config.directories.map(async ({ path: dir, extension, ignorePatterns }) => {
|
|
13
12
|
try {
|
|
@@ -19,9 +18,7 @@ const assertExt = async (config) => {
|
|
|
19
18
|
}
|
|
20
19
|
}));
|
|
21
20
|
// Collect all incorrect files
|
|
22
|
-
results.
|
|
23
|
-
allIncorrectFiles.push(...incorrectFiles);
|
|
24
|
-
});
|
|
21
|
+
const allIncorrectFiles = results.flat();
|
|
25
22
|
if (allIncorrectFiles.length > 0) {
|
|
26
23
|
const generateErrorMessage = () => {
|
|
27
24
|
// Group directories by extension for a cleaner message
|
|
@@ -34,7 +31,7 @@ const assertExt = async (config) => {
|
|
|
34
31
|
extensionGroups.get(extension)?.push(relativePath);
|
|
35
32
|
}
|
|
36
33
|
// Generate message parts for each extension
|
|
37
|
-
const messageParts = Array.from(extensionGroups.entries()
|
|
34
|
+
const messageParts = Array.from(extensionGroups.entries(), ([ext, dirs]) => {
|
|
38
35
|
const dirList = dirs.length === 1 ? dirs[0] : dirs.join(', ');
|
|
39
36
|
return `${dirList} should have ${ext} extension`;
|
|
40
37
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assert-ext.mjs","sources":["../../src/functions/assert-ext.mts"],"sourcesContent":[null],"names":[],"mappings":";;;AAkBA;;;;AAIG;MACU,SAAS,GAAG,OAAO,MAAsB,KAAmB
|
|
1
|
+
{"version":3,"file":"assert-ext.mjs","sources":["../../src/functions/assert-ext.mts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assert-repo-is-dirty.d.mts","sourceRoot":"","sources":["../../src/functions/assert-repo-is-dirty.mts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"assert-repo-is-dirty.d.mts","sourceRoot":"","sources":["../../src/functions/assert-repo-is-dirty.mts"],"names":[],"mappings":"AACA,OAAO,oBAAoB,CAAC;AAE5B;;;;GAIG;AACH,eAAO,MAAM,WAAW,QAAa,OAAO,CAAC,OAAO,CAGnD,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAAC,IAAI,CA6BtD,CAAC"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Result } from 'ts-data-forge';
|
|
1
2
|
import '../node-global.mjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -25,11 +26,11 @@ const assertRepoIsDirty = async () => {
|
|
|
25
26
|
echo(status.stdout);
|
|
26
27
|
// Show files not tracked by git and unstaged changes
|
|
27
28
|
const addResult = await $('git add -N .');
|
|
28
|
-
if (addResult
|
|
29
|
+
if (Result.isErr(addResult)) {
|
|
29
30
|
echo('Warning: Failed to add untracked files for diff\n');
|
|
30
31
|
}
|
|
31
32
|
const diffResult = await $('git diff');
|
|
32
|
-
if (diffResult
|
|
33
|
+
if (Result.isErr(diffResult)) {
|
|
33
34
|
echo('Warning: Failed to show diff\n');
|
|
34
35
|
}
|
|
35
36
|
process.exit(1);
|
|
@@ -45,12 +46,13 @@ const assertRepoIsDirty = async () => {
|
|
|
45
46
|
*/
|
|
46
47
|
const getGitStatus = async () => {
|
|
47
48
|
const res = await $('git status --porcelain');
|
|
48
|
-
if (res
|
|
49
|
-
throw new Error(`Failed to get git status: ${res.
|
|
49
|
+
if (Result.isErr(res)) {
|
|
50
|
+
throw new Error(`Failed to get git status: ${res.value.message}`);
|
|
50
51
|
}
|
|
52
|
+
const { stdout } = res.value;
|
|
51
53
|
return {
|
|
52
|
-
isDirty:
|
|
53
|
-
stdout
|
|
54
|
+
isDirty: stdout.trim() !== '',
|
|
55
|
+
stdout,
|
|
54
56
|
};
|
|
55
57
|
};
|
|
56
58
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assert-repo-is-dirty.mjs","sources":["../../src/functions/assert-repo-is-dirty.mts"],"sourcesContent":[null],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"assert-repo-is-dirty.mjs","sources":["../../src/functions/assert-repo-is-dirty.mts"],"sourcesContent":[null],"names":[],"mappings":";;;AAGA;;;;AAIG;AACI,MAAM,WAAW,GAAG,YAA6B;AACtD,IAAA,MAAM,MAAM,GAAG,MAAM,YAAY,EAAE;IACnC,OAAO,MAAM,CAAC,OAAO;AACvB;AAEA;;;AAGG;AACI,MAAM,iBAAiB,GAAG,YAA0B;AACzD,IAAA,IAAI;AACF,QAAA,MAAM,MAAM,GAAG,MAAM,YAAY,EAAE;AAEnC,QAAA,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE;YACnB,IAAI,CAAC,iBAAiB,CAAC;YACvB;;QAGF,IAAI,CAAC,iBAAiB,CAAC;QACvB,IAAI,CAAC,kBAAkB,CAAC;AACxB,QAAA,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC;;AAGnB,QAAA,MAAM,SAAS,GAAG,MAAM,CAAC,CAAC,cAAc,CAAC;AACzC,QAAA,IAAI,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE;YAC3B,IAAI,CAAC,mDAAmD,CAAC;;AAG3D,QAAA,MAAM,UAAU,GAAG,MAAM,CAAC,CAAC,UAAU,CAAC;AACtC,QAAA,IAAI,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE;YAC5B,IAAI,CAAC,gCAAgC,CAAC;;AAGxC,QAAA,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;;IACf,OAAO,KAAK,EAAE;QACd,IAAI,CAAC,qCAAqC,MAAM,CAAC,KAAK,CAAC,CAAA,EAAA,CAAI,CAAC;AAC5D,QAAA,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;;AAEnB;AAEA;;;AAGG;AACH,MAAM,YAAY,GAAG,YAGhB;AACH,IAAA,MAAM,GAAG,GAAG,MAAM,CAAC,CAAC,wBAAwB,CAAC;AAE7C,IAAA,IAAI,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;QACrB,MAAM,IAAI,KAAK,CAAC,CAAA,0BAAA,EAA6B,GAAG,CAAC,KAAK,CAAC,OAAO,CAAA,CAAE,CAAC;;AAGnE,IAAA,MAAM,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC,KAAK;IAE5B,OAAO;AACL,QAAA,OAAO,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE;QAC7B,MAAM;KACP;AACH,CAAC;;;;"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { type ExecException } from 'node:child_process';
|
|
2
|
+
import { Result } from 'ts-data-forge';
|
|
3
|
+
import '../node-global.mjs';
|
|
4
|
+
/**
|
|
5
|
+
* Get files that have been changed (git status).
|
|
6
|
+
*/
|
|
7
|
+
export declare const getUntrackedFiles: () => Promise<Result<readonly string[], ExecException | Readonly<{
|
|
8
|
+
message: string;
|
|
9
|
+
}>>>;
|
|
10
|
+
/**
|
|
11
|
+
* Get files that differ from the specified base branch or commit
|
|
12
|
+
*/
|
|
13
|
+
export declare const getDiffFrom: (base: string) => Promise<Result<readonly string[], ExecException | Readonly<{
|
|
14
|
+
message: string;
|
|
15
|
+
}>>>;
|
|
16
|
+
//# sourceMappingURL=diff.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.d.mts","sourceRoot":"","sources":["../../src/functions/diff.mts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AACvC,OAAO,oBAAoB,CAAC;AAE5B;;GAEG;AACH,eAAO,MAAM,iBAAiB,QAAa,OAAO,CAChD,MAAM,CAAC,SAAS,MAAM,EAAE,EAAE,aAAa,GAAG,QAAQ,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CA2BzE,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,GACtB,MAAM,MAAM,KACX,OAAO,CACR,MAAM,CAAC,SAAS,MAAM,EAAE,EAAE,aAAa,GAAG,QAAQ,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAkBzE,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Result } from 'ts-data-forge';
|
|
2
|
+
import '../node-global.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Get files that have been changed (git status).
|
|
6
|
+
*/
|
|
7
|
+
const getUntrackedFiles = async () => {
|
|
8
|
+
// Get changed files from git status
|
|
9
|
+
const result = await $('git status --porcelain');
|
|
10
|
+
if (Result.isErr(result)) {
|
|
11
|
+
return result;
|
|
12
|
+
}
|
|
13
|
+
const { stdout } = result.value;
|
|
14
|
+
// Parse git status output
|
|
15
|
+
const files = stdout
|
|
16
|
+
.split('\n')
|
|
17
|
+
.filter((line) => line.trim() !== '')
|
|
18
|
+
.map((line) => {
|
|
19
|
+
// Status format: "XY filename" where X and Y are status codes
|
|
20
|
+
const match = /^..\s+(.+)$/u.exec(line);
|
|
21
|
+
return match?.[1];
|
|
22
|
+
})
|
|
23
|
+
.filter((file) =>
|
|
24
|
+
// Filter out deleted files (status starts with 'D')
|
|
25
|
+
file !== undefined && !stdout.includes(`D ${file}`));
|
|
26
|
+
return Result.ok(files);
|
|
27
|
+
};
|
|
28
|
+
/**
|
|
29
|
+
* Get files that differ from the specified base branch or commit
|
|
30
|
+
*/
|
|
31
|
+
const getDiffFrom = async (base) => {
|
|
32
|
+
// Get files that differ from base branch/commit (excluding deleted files)
|
|
33
|
+
const result = await $(`git diff --name-only ${base} --diff-filter=d`);
|
|
34
|
+
if (Result.isErr(result)) {
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
37
|
+
const { stdout } = result.value;
|
|
38
|
+
// Parse git diff output
|
|
39
|
+
const files = stdout
|
|
40
|
+
.split('\n')
|
|
41
|
+
.map((line) => line.trim())
|
|
42
|
+
.filter((line) => line !== '');
|
|
43
|
+
return Result.ok(files);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export { getDiffFrom, getUntrackedFiles };
|
|
47
|
+
//# sourceMappingURL=diff.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"diff.mjs","sources":["../../src/functions/diff.mts"],"sourcesContent":[null],"names":[],"mappings":";;;AAIA;;AAEG;AACI,MAAM,iBAAiB,GAAG,YAE7B;;AAEF,IAAA,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,wBAAwB,CAAC;AAEhD,IAAA,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;AACxB,QAAA,OAAO,MAAM;;AAGf,IAAA,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK;;IAG/B,MAAM,KAAK,GAAG;SACX,KAAK,CAAC,IAAI;AACV,SAAA,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;AACnC,SAAA,GAAG,CAAC,CAAC,IAAI,KAAI;;QAEZ,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC;AACvC,QAAA,OAAO,KAAK,GAAG,CAAC,CAAC;AACnB,KAAC;AACA,SAAA,MAAM,CACL,CAAC,IAAI;;AAEH,IAAA,IAAI,KAAK,SAAS,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAA,GAAA,EAAM,IAAI,CAAA,CAAE,CAAC,CACvD;AAEH,IAAA,OAAO,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC;AACzB;AAEA;;AAEG;MACU,WAAW,GAAG,OACzB,IAAY,KAGV;;IAEF,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAA,qBAAA,EAAwB,IAAI,CAAA,gBAAA,CAAkB,CAAC;AAEtE,IAAA,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE;AACxB,QAAA,OAAO,MAAM;;AAGf,IAAA,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,CAAC,KAAK;;IAG/B,MAAM,KAAK,GAAG;SACX,KAAK,CAAC,IAAI;SACV,GAAG,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI,EAAE;SACzB,MAAM,CAAC,CAAC,IAAI,KAAK,IAAI,KAAK,EAAE,CAAC;AAEhC,IAAA,OAAO,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC;AACzB;;;;"}
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import { type ExecException } from 'node:child_process';
|
|
2
|
-
|
|
3
|
-
type: 'ok';
|
|
4
|
-
stdout: string;
|
|
5
|
-
stderr: string;
|
|
6
|
-
} | {
|
|
7
|
-
type: 'error';
|
|
8
|
-
exception: ExecException;
|
|
9
|
-
}>;
|
|
2
|
+
import { Result } from 'ts-data-forge';
|
|
10
3
|
/**
|
|
11
4
|
* Executes a shell command asynchronously.
|
|
12
5
|
* @param cmd - The command to execute.
|
|
@@ -16,5 +9,8 @@ export type ExecResult = Readonly<{
|
|
|
16
9
|
export declare const $: (cmd: string, options?: Readonly<{
|
|
17
10
|
silent?: boolean;
|
|
18
11
|
timeout?: number;
|
|
19
|
-
}>) => Promise<
|
|
12
|
+
}>) => Promise<Result<Readonly<{
|
|
13
|
+
stdout: string;
|
|
14
|
+
stderr: string;
|
|
15
|
+
}>, ExecException>>;
|
|
20
16
|
//# sourceMappingURL=exec-async.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec-async.d.mts","sourceRoot":"","sources":["../../src/functions/exec-async.mts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"exec-async.d.mts","sourceRoot":"","sources":["../../src/functions/exec-async.mts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAEvC;;;;;GAKG;AACH,eAAO,MAAM,CAAC,GACZ,KAAK,MAAM,EACX,UAAS,QAAQ,CAAC;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,CAAM,KAC7D,OAAO,CACR,MAAM,CAAC,QAAQ,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,EAAE,aAAa,CAAC,CA4BpE,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { exec } from 'node:child_process';
|
|
2
|
+
import { Result } from 'ts-data-forge';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Executes a shell command asynchronously.
|
|
@@ -23,10 +24,10 @@ const $ = (cmd, options = {}) => {
|
|
|
23
24
|
}
|
|
24
25
|
}
|
|
25
26
|
if (error !== null) {
|
|
26
|
-
resolve(
|
|
27
|
+
resolve(Result.err(error));
|
|
27
28
|
}
|
|
28
29
|
else {
|
|
29
|
-
resolve({
|
|
30
|
+
resolve(Result.ok({ stdout, stderr }));
|
|
30
31
|
}
|
|
31
32
|
});
|
|
32
33
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exec-async.mjs","sources":["../../src/functions/exec-async.mts"],"sourcesContent":[null],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"exec-async.mjs","sources":["../../src/functions/exec-async.mts"],"sourcesContent":[null],"names":[],"mappings":";;;AAGA;;;;;AAKG;AACI,MAAM,CAAC,GAAG,CACf,GAAW,EACX,OAAA,GAA4D,EAAE,KAG5D;IACF,MAAM,EAAE,MAAM,GAAG,KAAK,EAAE,OAAO,GAAG,KAAK,EAAE,GAAG,OAAO;IAEnD,IAAI,CAAC,MAAM,EAAE;AACX,QAAA,OAAO,CAAC,GAAG,CAAC,KAAK,GAAG,CAAA,CAAE,CAAC;;AAGzB,IAAA,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,KAAI;AAC7B,QAAA,MAAM,WAAW,GAAG,EAAE,OAAO,EAAE;AAE/B,QAAA,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,KAAI;YAC/C,IAAI,CAAC,MAAM,EAAE;AACX,gBAAA,IAAI,MAAM,KAAK,EAAE,EAAE;AACjB,oBAAA,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC;;AAErB,gBAAA,IAAI,MAAM,KAAK,EAAE,EAAE;AACjB,oBAAA,OAAO,CAAC,KAAK,CAAC,MAAM,CAAC;;;AAIzB,YAAA,IAAI,KAAK,KAAK,IAAI,EAAE;gBAClB,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;;iBACrB;AACL,gBAAA,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;;AAE1C,SAAC,CAAC;AACJ,KAAC,CAAC;AACJ;;;;"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import '../node-global.mjs';
|
|
1
2
|
/**
|
|
2
3
|
* Format files matching the given glob pattern using Prettier
|
|
3
4
|
* @param pathGlob - Glob pattern to match files
|
|
@@ -8,11 +9,11 @@ export declare const formatFiles: (pathGlob: string) => Promise<"ok" | "err">;
|
|
|
8
9
|
* Format only files that have been changed (git status)
|
|
9
10
|
* @returns 'ok' if successful, 'err' if any errors occurred
|
|
10
11
|
*/
|
|
11
|
-
export declare const
|
|
12
|
+
export declare const formatUntracked: () => Promise<"ok" | "err">;
|
|
12
13
|
/**
|
|
13
14
|
* Format only files that differ from the specified base branch or commit
|
|
14
15
|
* @param base - Base branch name or commit hash to compare against (defaults to 'main')
|
|
15
16
|
* @returns 'ok' if successful, 'err' if any errors occurred
|
|
16
17
|
*/
|
|
17
|
-
export declare const formatDiffFrom: (base
|
|
18
|
+
export declare const formatDiffFrom: (base: string) => Promise<"ok" | "err">;
|
|
18
19
|
//# sourceMappingURL=format.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.d.mts","sourceRoot":"","sources":["../../src/functions/format.mts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"format.d.mts","sourceRoot":"","sources":["../../src/functions/format.mts"],"names":[],"mappings":"AAIA,OAAO,oBAAoB,CAAC;AAG5B;;;;GAIG;AACH,eAAO,MAAM,WAAW,GAAU,UAAU,MAAM,KAAG,OAAO,CAAC,IAAI,GAAG,KAAK,CA6DxE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,eAAe,QAAa,OAAO,CAAC,IAAI,GAAG,KAAK,CAmE5D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,cAAc,GAAU,MAAM,MAAM,KAAG,OAAO,CAAC,IAAI,GAAG,KAAK,CAgEvE,CAAC"}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import glob_ from 'fast-glob';
|
|
2
|
-
import { exec } from 'node:child_process';
|
|
3
2
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
4
|
-
import { promisify } from 'node:util';
|
|
5
3
|
import * as prettier from 'prettier';
|
|
4
|
+
import { Result } from 'ts-data-forge';
|
|
5
|
+
import '../node-global.mjs';
|
|
6
|
+
import { getUntrackedFiles, getDiffFrom } from './diff.mjs';
|
|
6
7
|
|
|
7
|
-
const execAsync = promisify(exec);
|
|
8
8
|
/**
|
|
9
9
|
* Format files matching the given glob pattern using Prettier
|
|
10
10
|
* @param pathGlob - Glob pattern to match files
|
|
@@ -19,10 +19,10 @@ const formatFiles = async (pathGlob) => {
|
|
|
19
19
|
dot: true,
|
|
20
20
|
});
|
|
21
21
|
if (files.length === 0) {
|
|
22
|
-
|
|
22
|
+
echo('No files found matching pattern:', pathGlob);
|
|
23
23
|
return 'ok';
|
|
24
24
|
}
|
|
25
|
-
|
|
25
|
+
echo(`Formatting ${files.length} files...`);
|
|
26
26
|
// Format each file
|
|
27
27
|
const results = await Promise.allSettled(files.map(async (filePath) => {
|
|
28
28
|
try {
|
|
@@ -35,7 +35,7 @@ const formatFiles = async (pathGlob) => {
|
|
|
35
35
|
ignorePath: '.prettierignore',
|
|
36
36
|
});
|
|
37
37
|
if (fileInfo.ignored) {
|
|
38
|
-
|
|
38
|
+
echo(`Skipping ignored file: ${filePath}`);
|
|
39
39
|
return;
|
|
40
40
|
}
|
|
41
41
|
// Format the content
|
|
@@ -46,7 +46,7 @@ const formatFiles = async (pathGlob) => {
|
|
|
46
46
|
// Only write if content changed
|
|
47
47
|
if (formatted !== content) {
|
|
48
48
|
await writeFile(filePath, formatted, 'utf8');
|
|
49
|
-
|
|
49
|
+
echo(`Formatted: ${filePath}`);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
catch (error) {
|
|
@@ -67,38 +67,26 @@ const formatFiles = async (pathGlob) => {
|
|
|
67
67
|
* Format only files that have been changed (git status)
|
|
68
68
|
* @returns 'ok' if successful, 'err' if any errors occurred
|
|
69
69
|
*/
|
|
70
|
-
const
|
|
70
|
+
const formatUntracked = async () => {
|
|
71
71
|
try {
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
console.error('Git error:', stderr);
|
|
72
|
+
const untrackedFilesResult = await getUntrackedFiles();
|
|
73
|
+
if (Result.isErr(untrackedFilesResult)) {
|
|
74
|
+
console.error('Error getting changed files:', untrackedFilesResult.value);
|
|
76
75
|
return 'err';
|
|
77
76
|
}
|
|
78
|
-
|
|
79
|
-
const files = stdout
|
|
80
|
-
.split('\n')
|
|
81
|
-
.filter((line) => line.trim() !== '')
|
|
82
|
-
.map((line) => {
|
|
83
|
-
// Status format: "XY filename" where X and Y are status codes
|
|
84
|
-
const match = /^..\s+(.+)$/u.exec(line);
|
|
85
|
-
return match?.[1];
|
|
86
|
-
})
|
|
87
|
-
.filter((file) =>
|
|
88
|
-
// Filter out deleted files (status starts with 'D')
|
|
89
|
-
file !== undefined && !stdout.includes(`D ${file}`));
|
|
77
|
+
const files = untrackedFilesResult.value;
|
|
90
78
|
if (files.length === 0) {
|
|
91
|
-
|
|
79
|
+
echo('No changed files to format');
|
|
92
80
|
return 'ok';
|
|
93
81
|
}
|
|
94
|
-
|
|
82
|
+
echo('Formatting changed files:', files);
|
|
95
83
|
// Format each changed file
|
|
96
84
|
const results = await Promise.allSettled(files.map(async (filePath) => {
|
|
97
85
|
try {
|
|
98
86
|
// Check if file exists and is not deleted
|
|
99
87
|
const content = await readFile(filePath, 'utf8').catch(() => null);
|
|
100
88
|
if (content === null) {
|
|
101
|
-
|
|
89
|
+
echo(`Skipping non-existent file: ${filePath}`);
|
|
102
90
|
return;
|
|
103
91
|
}
|
|
104
92
|
// Resolve prettier config for this file
|
|
@@ -108,7 +96,7 @@ const formatChanged = async () => {
|
|
|
108
96
|
ignorePath: '.prettierignore',
|
|
109
97
|
});
|
|
110
98
|
if (fileInfo.ignored) {
|
|
111
|
-
|
|
99
|
+
echo(`Skipping ignored file: ${filePath}`);
|
|
112
100
|
return;
|
|
113
101
|
}
|
|
114
102
|
// Format the content
|
|
@@ -119,7 +107,7 @@ const formatChanged = async () => {
|
|
|
119
107
|
// Only write if content changed
|
|
120
108
|
if (formatted !== content) {
|
|
121
109
|
await writeFile(filePath, formatted, 'utf8');
|
|
122
|
-
|
|
110
|
+
echo(`Formatted: ${filePath}`);
|
|
123
111
|
}
|
|
124
112
|
}
|
|
125
113
|
catch (error) {
|
|
@@ -141,24 +129,20 @@ const formatChanged = async () => {
|
|
|
141
129
|
* @param base - Base branch name or commit hash to compare against (defaults to 'main')
|
|
142
130
|
* @returns 'ok' if successful, 'err' if any errors occurred
|
|
143
131
|
*/
|
|
144
|
-
const formatDiffFrom = async (base
|
|
132
|
+
const formatDiffFrom = async (base) => {
|
|
145
133
|
try {
|
|
146
134
|
// Get files that differ from base branch/commit (excluding deleted files)
|
|
147
|
-
const
|
|
148
|
-
if (
|
|
149
|
-
console.error('
|
|
135
|
+
const diffFromBaseResult = await getDiffFrom(base);
|
|
136
|
+
if (Result.isErr(diffFromBaseResult)) {
|
|
137
|
+
console.error('Error getting changed files:', diffFromBaseResult.value);
|
|
150
138
|
return 'err';
|
|
151
139
|
}
|
|
152
|
-
|
|
153
|
-
const files = stdout
|
|
154
|
-
.split('\n')
|
|
155
|
-
.map((line) => line.trim())
|
|
156
|
-
.filter((line) => line !== '');
|
|
140
|
+
const files = diffFromBaseResult.value;
|
|
157
141
|
if (files.length === 0) {
|
|
158
|
-
|
|
142
|
+
echo(`No files differ from ${base}`);
|
|
159
143
|
return 'ok';
|
|
160
144
|
}
|
|
161
|
-
|
|
145
|
+
echo(`Formatting files that differ from ${base}:`, files);
|
|
162
146
|
// Format each file
|
|
163
147
|
const results = await Promise.allSettled(files.map(async (filePath) => {
|
|
164
148
|
try {
|
|
@@ -171,7 +155,7 @@ const formatDiffFrom = async (base = 'main') => {
|
|
|
171
155
|
ignorePath: '.prettierignore',
|
|
172
156
|
});
|
|
173
157
|
if (fileInfo.ignored) {
|
|
174
|
-
|
|
158
|
+
echo(`Skipping ignored file: ${filePath}`);
|
|
175
159
|
return;
|
|
176
160
|
}
|
|
177
161
|
// Format the content
|
|
@@ -182,7 +166,7 @@ const formatDiffFrom = async (base = 'main') => {
|
|
|
182
166
|
// Only write if content changed
|
|
183
167
|
if (formatted !== content) {
|
|
184
168
|
await writeFile(filePath, formatted, 'utf8');
|
|
185
|
-
|
|
169
|
+
echo(`Formatted: ${filePath}`);
|
|
186
170
|
}
|
|
187
171
|
}
|
|
188
172
|
catch (error) {
|
|
@@ -200,5 +184,5 @@ const formatDiffFrom = async (base = 'main') => {
|
|
|
200
184
|
}
|
|
201
185
|
};
|
|
202
186
|
|
|
203
|
-
export {
|
|
187
|
+
export { formatDiffFrom, formatFiles, formatUntracked };
|
|
204
188
|
//# sourceMappingURL=format.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"format.mjs","sources":["../../src/functions/format.mts"],"sourcesContent":[null],"names":["glob"],"mappings":"
|
|
1
|
+
{"version":3,"file":"format.mjs","sources":["../../src/functions/format.mts"],"sourcesContent":[null],"names":["glob"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gen-index.d.mts","sourceRoot":"","sources":["../../src/functions/gen-index.mts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"gen-index.d.mts","sourceRoot":"","sources":["../../src/functions/gen-index.mts"],"names":[],"mappings":"AAEA,OAAO,oBAAoB,CAAC;AAG5B;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,YAAY,CAAC;IACxC,kFAAkF;IAClF,eAAe,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IAEnC,iEAAiE;IACjE,eAAe,CAAC,EAAE,IAAI,MAAM,EAAE,CAAC;IAE/B,mEAAmE;IACnE,eAAe,CAAC,EAAE,IAAI,MAAM,EAAE,CAAC;IAE/B,gGAAgG;IAChG,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B,CAAC,CAAC;AAEH;;;;GAIG;AACH,eAAO,MAAM,QAAQ,GAAU,QAAQ,cAAc,KAAG,OAAO,CAAC,IAAI,CA0CnE,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import micromatch from 'micromatch';
|
|
2
|
+
import { Result } from 'ts-data-forge';
|
|
2
3
|
import '../node-global.mjs';
|
|
3
4
|
import { assertPathExists } from './assert-path-exists.mjs';
|
|
4
5
|
|
|
@@ -33,8 +34,8 @@ const genIndex = async (config) => {
|
|
|
33
34
|
// Step 3: Format generated files
|
|
34
35
|
echo('3. Formatting generated files...');
|
|
35
36
|
const fmtResult = await $('npm run fmt');
|
|
36
|
-
if (fmtResult
|
|
37
|
-
throw new Error(`Formatting failed: ${fmtResult.
|
|
37
|
+
if (Result.isErr(fmtResult)) {
|
|
38
|
+
throw new Error(`Formatting failed: ${fmtResult.value.message}`);
|
|
38
39
|
}
|
|
39
40
|
echo('✓ Formatting completed\n');
|
|
40
41
|
echo('✅ Index file generation completed successfully!\n');
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gen-index.mjs","sources":["../../src/functions/gen-index.mts"],"sourcesContent":[null],"names":[],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"gen-index.mjs","sources":["../../src/functions/gen-index.mts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/functions/index.mts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../src/functions/index.mts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC;AACjC,cAAc,0BAA0B,CAAC;AACzC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,YAAY,CAAC;AAC3B,cAAc,kBAAkB,CAAC;AACjC,cAAc,cAAc,CAAC;AAC7B,cAAc,iBAAiB,CAAC"}
|
package/dist/functions/index.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { assertExt } from './assert-ext.mjs';
|
|
2
2
|
export { assertPathExists, pathExists } from './assert-path-exists.mjs';
|
|
3
3
|
export { assertRepoIsDirty, repoIsDirty } from './assert-repo-is-dirty.mjs';
|
|
4
|
+
export { getDiffFrom, getUntrackedFiles } from './diff.mjs';
|
|
4
5
|
export { $ } from './exec-async.mjs';
|
|
5
|
-
export {
|
|
6
|
+
export { formatDiffFrom, formatFiles, formatUntracked } from './format.mjs';
|
|
6
7
|
export { genIndex } from './gen-index.mjs';
|
|
7
8
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
export { assertExt } from './functions/assert-ext.mjs';
|
|
2
2
|
export { assertPathExists, pathExists } from './functions/assert-path-exists.mjs';
|
|
3
3
|
export { assertRepoIsDirty, repoIsDirty } from './functions/assert-repo-is-dirty.mjs';
|
|
4
|
+
export { getDiffFrom, getUntrackedFiles } from './functions/diff.mjs';
|
|
4
5
|
export { $ } from './functions/exec-async.mjs';
|
|
5
|
-
export {
|
|
6
|
+
export { formatDiffFrom, formatFiles, formatUntracked } from './functions/format.mjs';
|
|
6
7
|
export { genIndex } from './functions/gen-index.mjs';
|
|
7
8
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-repo-utils",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript"
|
|
@@ -57,7 +57,8 @@
|
|
|
57
57
|
"@types/micromatch": "^4.0.9",
|
|
58
58
|
"fast-glob": "^3.3.3",
|
|
59
59
|
"micromatch": "^4.0.8",
|
|
60
|
-
"prettier": "^3.5.3"
|
|
60
|
+
"prettier": "^3.5.3",
|
|
61
|
+
"ts-data-forge": "^1.0.2"
|
|
61
62
|
},
|
|
62
63
|
"devDependencies": {
|
|
63
64
|
"@eslint/js": "^9.29.0",
|
|
@@ -22,8 +22,6 @@ export type CheckExtConfig = DeepReadonly<{
|
|
|
22
22
|
* @param config - Configuration specifying directories and expected extensions.
|
|
23
23
|
*/
|
|
24
24
|
export const assertExt = async (config: CheckExtConfig): Promise<void> => {
|
|
25
|
-
const allIncorrectFiles: string[] = [];
|
|
26
|
-
|
|
27
25
|
// Check all directories in parallel
|
|
28
26
|
const results = await Promise.all(
|
|
29
27
|
config.directories.map(async ({ path: dir, extension, ignorePatterns }) => {
|
|
@@ -41,9 +39,7 @@ export const assertExt = async (config: CheckExtConfig): Promise<void> => {
|
|
|
41
39
|
);
|
|
42
40
|
|
|
43
41
|
// Collect all incorrect files
|
|
44
|
-
results.
|
|
45
|
-
allIncorrectFiles.push(...incorrectFiles);
|
|
46
|
-
});
|
|
42
|
+
const allIncorrectFiles: readonly string[] = results.flat();
|
|
47
43
|
|
|
48
44
|
if (allIncorrectFiles.length > 0) {
|
|
49
45
|
const generateErrorMessage = (): string => {
|
|
@@ -59,7 +55,8 @@ export const assertExt = async (config: CheckExtConfig): Promise<void> => {
|
|
|
59
55
|
}
|
|
60
56
|
|
|
61
57
|
// Generate message parts for each extension
|
|
62
|
-
const messageParts = Array.from(
|
|
58
|
+
const messageParts = Array.from(
|
|
59
|
+
extensionGroups.entries(),
|
|
63
60
|
([ext, dirs]) => {
|
|
64
61
|
const dirList = dirs.length === 1 ? dirs[0] : dirs.join(', ');
|
|
65
62
|
return `${dirList} should have ${ext} extension`;
|
|
@@ -94,7 +91,7 @@ const getFilesWithIncorrectExtension = async (
|
|
|
94
91
|
dir: string,
|
|
95
92
|
expectedExtension: string,
|
|
96
93
|
ignorePatterns?: readonly string[],
|
|
97
|
-
): Promise<string[]> => {
|
|
94
|
+
): Promise<readonly string[]> => {
|
|
98
95
|
await assertPathExists(dir, 'Directory');
|
|
99
96
|
|
|
100
97
|
const defaultIgnorePatterns = ['tsconfig.json', 'globals.d.*'];
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Result } from 'ts-data-forge';
|
|
1
2
|
import '../node-global.mjs';
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -29,12 +30,12 @@ export const assertRepoIsDirty = async (): Promise<void> => {
|
|
|
29
30
|
|
|
30
31
|
// Show files not tracked by git and unstaged changes
|
|
31
32
|
const addResult = await $('git add -N .');
|
|
32
|
-
if (addResult
|
|
33
|
+
if (Result.isErr(addResult)) {
|
|
33
34
|
echo('Warning: Failed to add untracked files for diff\n');
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
const diffResult = await $('git diff');
|
|
37
|
-
if (diffResult
|
|
38
|
+
if (Result.isErr(diffResult)) {
|
|
38
39
|
echo('Warning: Failed to show diff\n');
|
|
39
40
|
}
|
|
40
41
|
|
|
@@ -55,12 +56,14 @@ const getGitStatus = async (): Promise<{
|
|
|
55
56
|
}> => {
|
|
56
57
|
const res = await $('git status --porcelain');
|
|
57
58
|
|
|
58
|
-
if (res
|
|
59
|
-
throw new Error(`Failed to get git status: ${res.
|
|
59
|
+
if (Result.isErr(res)) {
|
|
60
|
+
throw new Error(`Failed to get git status: ${res.value.message}`);
|
|
60
61
|
}
|
|
61
62
|
|
|
63
|
+
const { stdout } = res.value;
|
|
64
|
+
|
|
62
65
|
return {
|
|
63
|
-
isDirty:
|
|
64
|
-
stdout
|
|
66
|
+
isDirty: stdout.trim() !== '',
|
|
67
|
+
stdout,
|
|
65
68
|
};
|
|
66
69
|
};
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { type ExecException } from 'node:child_process';
|
|
2
|
+
import { Result } from 'ts-data-forge';
|
|
3
|
+
import '../node-global.mjs';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Get files that have been changed (git status).
|
|
7
|
+
*/
|
|
8
|
+
export const getUntrackedFiles = async (): Promise<
|
|
9
|
+
Result<readonly string[], ExecException | Readonly<{ message: string }>>
|
|
10
|
+
> => {
|
|
11
|
+
// Get changed files from git status
|
|
12
|
+
const result = await $('git status --porcelain');
|
|
13
|
+
|
|
14
|
+
if (Result.isErr(result)) {
|
|
15
|
+
return result;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const { stdout } = result.value;
|
|
19
|
+
|
|
20
|
+
// Parse git status output
|
|
21
|
+
const files = stdout
|
|
22
|
+
.split('\n')
|
|
23
|
+
.filter((line) => line.trim() !== '')
|
|
24
|
+
.map((line) => {
|
|
25
|
+
// Status format: "XY filename" where X and Y are status codes
|
|
26
|
+
const match = /^..\s+(.+)$/u.exec(line);
|
|
27
|
+
return match?.[1];
|
|
28
|
+
})
|
|
29
|
+
.filter(
|
|
30
|
+
(file): file is string =>
|
|
31
|
+
// Filter out deleted files (status starts with 'D')
|
|
32
|
+
file !== undefined && !stdout.includes(`D ${file}`),
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
return Result.ok(files);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Get files that differ from the specified base branch or commit
|
|
40
|
+
*/
|
|
41
|
+
export const getDiffFrom = async (
|
|
42
|
+
base: string,
|
|
43
|
+
): Promise<
|
|
44
|
+
Result<readonly string[], ExecException | Readonly<{ message: string }>>
|
|
45
|
+
> => {
|
|
46
|
+
// Get files that differ from base branch/commit (excluding deleted files)
|
|
47
|
+
const result = await $(`git diff --name-only ${base} --diff-filter=d`);
|
|
48
|
+
|
|
49
|
+
if (Result.isErr(result)) {
|
|
50
|
+
return result;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const { stdout } = result.value;
|
|
54
|
+
|
|
55
|
+
// Parse git diff output
|
|
56
|
+
const files = stdout
|
|
57
|
+
.split('\n')
|
|
58
|
+
.map((line) => line.trim())
|
|
59
|
+
.filter((line) => line !== '');
|
|
60
|
+
|
|
61
|
+
return Result.ok(files);
|
|
62
|
+
};
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { rm, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { Result } from 'ts-data-forge';
|
|
4
|
+
import '../node-global.mjs';
|
|
5
|
+
import { getUntrackedFiles } from './diff.mjs';
|
|
6
|
+
|
|
7
|
+
describe('diff', () => {
|
|
8
|
+
// Use project root for test files to ensure git tracking
|
|
9
|
+
const testFiles: string[] = [];
|
|
10
|
+
|
|
11
|
+
afterEach(async () => {
|
|
12
|
+
// Clean up test files
|
|
13
|
+
for (const file of testFiles) {
|
|
14
|
+
try {
|
|
15
|
+
// eslint-disable-next-line no-await-in-loop
|
|
16
|
+
await rm(file, { force: true });
|
|
17
|
+
} catch {
|
|
18
|
+
// Ignore cleanup errors
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
testFiles.length = 0;
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('getUntrackedFiles', () => {
|
|
25
|
+
test('should return empty array when no files are changed', async () => {
|
|
26
|
+
const result = await getUntrackedFiles();
|
|
27
|
+
|
|
28
|
+
expect(Result.isOk(result)).toBe(true);
|
|
29
|
+
if (Result.isOk(result)) {
|
|
30
|
+
expect(Array.isArray(result.value)).toBe(true);
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test('should detect newly created files', async () => {
|
|
35
|
+
// Create a new file in project root
|
|
36
|
+
const testFileName = 'test-new-file.tmp';
|
|
37
|
+
const testFilePath = join(process.cwd(), testFileName);
|
|
38
|
+
testFiles.push(testFilePath);
|
|
39
|
+
|
|
40
|
+
await writeFile(testFilePath, 'test content');
|
|
41
|
+
|
|
42
|
+
const result = await getUntrackedFiles();
|
|
43
|
+
|
|
44
|
+
expect(Result.isOk(result)).toBe(true);
|
|
45
|
+
if (Result.isOk(result)) {
|
|
46
|
+
const files = result.value;
|
|
47
|
+
expect(files.some((file) => file.includes(testFileName))).toBe(true);
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('should detect modified existing files', async () => {
|
|
52
|
+
// Use an existing file in the project that we can modify safely
|
|
53
|
+
const testFileName = 'test-modify-file.tmp';
|
|
54
|
+
const testFilePath = join(process.cwd(), testFileName);
|
|
55
|
+
testFiles.push(testFilePath);
|
|
56
|
+
|
|
57
|
+
// Create and commit the file first
|
|
58
|
+
await writeFile(testFilePath, 'initial content');
|
|
59
|
+
|
|
60
|
+
// Add to git to track it
|
|
61
|
+
await $(`git add ${testFileName}`);
|
|
62
|
+
|
|
63
|
+
// Modify the file
|
|
64
|
+
await writeFile(testFilePath, 'modified content');
|
|
65
|
+
|
|
66
|
+
const result = await getUntrackedFiles();
|
|
67
|
+
|
|
68
|
+
expect(Result.isOk(result)).toBe(true);
|
|
69
|
+
if (Result.isOk(result)) {
|
|
70
|
+
const files = result.value;
|
|
71
|
+
expect(files.some((file) => file.includes(testFileName))).toBe(true);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Reset git state
|
|
75
|
+
await $(`git reset HEAD ${testFileName}`);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
test('should detect multiple types of changes', async () => {
|
|
79
|
+
// Create multiple test files
|
|
80
|
+
const newFile = join(process.cwd(), 'test-new-file.tmp');
|
|
81
|
+
const modifyFile = join(process.cwd(), 'test-modify-file.tmp');
|
|
82
|
+
testFiles.push(newFile, modifyFile);
|
|
83
|
+
|
|
84
|
+
// Create new file
|
|
85
|
+
await writeFile(newFile, 'new file content');
|
|
86
|
+
|
|
87
|
+
// Create and track another file
|
|
88
|
+
await writeFile(modifyFile, 'initial content');
|
|
89
|
+
await $(`git add test-modify-file.tmp`);
|
|
90
|
+
|
|
91
|
+
// Modify the tracked file
|
|
92
|
+
await writeFile(modifyFile, 'modified content');
|
|
93
|
+
|
|
94
|
+
const result = await getUntrackedFiles();
|
|
95
|
+
|
|
96
|
+
expect(Result.isOk(result)).toBe(true);
|
|
97
|
+
if (Result.isOk(result)) {
|
|
98
|
+
const files = result.value;
|
|
99
|
+
expect(files.some((file) => file.includes('test-new-file.tmp'))).toBe(
|
|
100
|
+
true,
|
|
101
|
+
);
|
|
102
|
+
expect(
|
|
103
|
+
files.some((file) => file.includes('test-modify-file.tmp')),
|
|
104
|
+
).toBe(true);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Reset git state
|
|
108
|
+
await $(`git reset HEAD test-modify-file.tmp`);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
test('should exclude deleted files from results', async () => {
|
|
112
|
+
// This test is more complex as it requires simulating git state
|
|
113
|
+
// For now, we'll test that the function executes successfully
|
|
114
|
+
const result = await getUntrackedFiles();
|
|
115
|
+
|
|
116
|
+
expect(Result.isOk(result)).toBe(true);
|
|
117
|
+
if (Result.isOk(result)) {
|
|
118
|
+
const files = result.value;
|
|
119
|
+
// Verify no deleted files are included (status 'D')
|
|
120
|
+
files.forEach((file) => {
|
|
121
|
+
expect(typeof file).toBe('string');
|
|
122
|
+
expect(file.length).toBeGreaterThan(0);
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
test('should handle git command errors gracefully', async () => {
|
|
128
|
+
// This test would require mocking git command failure
|
|
129
|
+
// For now, we'll ensure the function returns a Result type
|
|
130
|
+
const result = await getUntrackedFiles();
|
|
131
|
+
|
|
132
|
+
// Should always return a Result, either Ok or Err
|
|
133
|
+
expect(Result.isOk(result) || Result.isErr(result)).toBe(true);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test('should parse git status output correctly', async () => {
|
|
137
|
+
const result = await getUntrackedFiles();
|
|
138
|
+
|
|
139
|
+
expect(Result.isOk(result)).toBe(true);
|
|
140
|
+
if (Result.isOk(result)) {
|
|
141
|
+
const files = result.value;
|
|
142
|
+
|
|
143
|
+
// Each file should be a non-empty string
|
|
144
|
+
files.forEach((file) => {
|
|
145
|
+
expect(typeof file).toBe('string');
|
|
146
|
+
expect(file.trim()).toBe(file); // No leading/trailing whitespace
|
|
147
|
+
expect(file.length).toBeGreaterThan(0);
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
});
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { exec, type ExecException } from 'node:child_process';
|
|
2
|
-
|
|
3
|
-
export type ExecResult = Readonly<
|
|
4
|
-
| { type: 'ok'; stdout: string; stderr: string }
|
|
5
|
-
| { type: 'error'; exception: ExecException }
|
|
6
|
-
>;
|
|
2
|
+
import { Result } from 'ts-data-forge';
|
|
7
3
|
|
|
8
4
|
/**
|
|
9
5
|
* Executes a shell command asynchronously.
|
|
@@ -14,7 +10,9 @@ export type ExecResult = Readonly<
|
|
|
14
10
|
export const $ = (
|
|
15
11
|
cmd: string,
|
|
16
12
|
options: Readonly<{ silent?: boolean; timeout?: number }> = {},
|
|
17
|
-
): Promise<
|
|
13
|
+
): Promise<
|
|
14
|
+
Result<Readonly<{ stdout: string; stderr: string }>, ExecException>
|
|
15
|
+
> => {
|
|
18
16
|
const { silent = false, timeout = 30000 } = options;
|
|
19
17
|
|
|
20
18
|
if (!silent) {
|
|
@@ -35,9 +33,9 @@ export const $ = (
|
|
|
35
33
|
}
|
|
36
34
|
|
|
37
35
|
if (error !== null) {
|
|
38
|
-
resolve(
|
|
36
|
+
resolve(Result.err(error));
|
|
39
37
|
} else {
|
|
40
|
-
resolve({
|
|
38
|
+
resolve(Result.ok({ stdout, stderr }));
|
|
41
39
|
}
|
|
42
40
|
});
|
|
43
41
|
});
|
package/src/functions/format.mts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import glob from 'fast-glob';
|
|
2
|
-
import { exec } from 'node:child_process';
|
|
3
2
|
import { readFile, writeFile } from 'node:fs/promises';
|
|
4
|
-
import { promisify } from 'node:util';
|
|
5
3
|
import * as prettier from 'prettier';
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
import { Result } from 'ts-data-forge';
|
|
5
|
+
import '../node-global.mjs';
|
|
6
|
+
import { getDiffFrom, getUntrackedFiles } from './diff.mjs';
|
|
8
7
|
|
|
9
8
|
/**
|
|
10
9
|
* Format files matching the given glob pattern using Prettier
|
|
@@ -21,11 +20,11 @@ export const formatFiles = async (pathGlob: string): Promise<'ok' | 'err'> => {
|
|
|
21
20
|
});
|
|
22
21
|
|
|
23
22
|
if (files.length === 0) {
|
|
24
|
-
|
|
23
|
+
echo('No files found matching pattern:', pathGlob);
|
|
25
24
|
return 'ok';
|
|
26
25
|
}
|
|
27
26
|
|
|
28
|
-
|
|
27
|
+
echo(`Formatting ${files.length} files...`);
|
|
29
28
|
|
|
30
29
|
// Format each file
|
|
31
30
|
const results = await Promise.allSettled(
|
|
@@ -43,7 +42,7 @@ export const formatFiles = async (pathGlob: string): Promise<'ok' | 'err'> => {
|
|
|
43
42
|
});
|
|
44
43
|
|
|
45
44
|
if (fileInfo.ignored) {
|
|
46
|
-
|
|
45
|
+
echo(`Skipping ignored file: ${filePath}`);
|
|
47
46
|
return;
|
|
48
47
|
}
|
|
49
48
|
|
|
@@ -56,7 +55,7 @@ export const formatFiles = async (pathGlob: string): Promise<'ok' | 'err'> => {
|
|
|
56
55
|
// Only write if content changed
|
|
57
56
|
if (formatted !== content) {
|
|
58
57
|
await writeFile(filePath, formatted, 'utf8');
|
|
59
|
-
|
|
58
|
+
echo(`Formatted: ${filePath}`);
|
|
60
59
|
}
|
|
61
60
|
} catch (error) {
|
|
62
61
|
console.error(`Error formatting ${filePath}:`, error);
|
|
@@ -78,37 +77,23 @@ export const formatFiles = async (pathGlob: string): Promise<'ok' | 'err'> => {
|
|
|
78
77
|
* Format only files that have been changed (git status)
|
|
79
78
|
* @returns 'ok' if successful, 'err' if any errors occurred
|
|
80
79
|
*/
|
|
81
|
-
export const
|
|
80
|
+
export const formatUntracked = async (): Promise<'ok' | 'err'> => {
|
|
82
81
|
try {
|
|
83
|
-
|
|
84
|
-
const { stdout, stderr } = await execAsync('git status --porcelain');
|
|
82
|
+
const untrackedFilesResult = await getUntrackedFiles();
|
|
85
83
|
|
|
86
|
-
if (
|
|
87
|
-
console.error('
|
|
84
|
+
if (Result.isErr(untrackedFilesResult)) {
|
|
85
|
+
console.error('Error getting changed files:', untrackedFilesResult.value);
|
|
88
86
|
return 'err';
|
|
89
87
|
}
|
|
90
88
|
|
|
91
|
-
|
|
92
|
-
const files = stdout
|
|
93
|
-
.split('\n')
|
|
94
|
-
.filter((line) => line.trim() !== '')
|
|
95
|
-
.map((line) => {
|
|
96
|
-
// Status format: "XY filename" where X and Y are status codes
|
|
97
|
-
const match = /^..\s+(.+)$/u.exec(line);
|
|
98
|
-
return match?.[1];
|
|
99
|
-
})
|
|
100
|
-
.filter(
|
|
101
|
-
(file): file is string =>
|
|
102
|
-
// Filter out deleted files (status starts with 'D')
|
|
103
|
-
file !== undefined && !stdout.includes(`D ${file}`),
|
|
104
|
-
);
|
|
89
|
+
const files = untrackedFilesResult.value;
|
|
105
90
|
|
|
106
91
|
if (files.length === 0) {
|
|
107
|
-
|
|
92
|
+
echo('No changed files to format');
|
|
108
93
|
return 'ok';
|
|
109
94
|
}
|
|
110
95
|
|
|
111
|
-
|
|
96
|
+
echo('Formatting changed files:', files);
|
|
112
97
|
|
|
113
98
|
// Format each changed file
|
|
114
99
|
const results = await Promise.allSettled(
|
|
@@ -117,7 +102,7 @@ export const formatChanged = async (): Promise<'ok' | 'err'> => {
|
|
|
117
102
|
// Check if file exists and is not deleted
|
|
118
103
|
const content = await readFile(filePath, 'utf8').catch(() => null);
|
|
119
104
|
if (content === null) {
|
|
120
|
-
|
|
105
|
+
echo(`Skipping non-existent file: ${filePath}`);
|
|
121
106
|
return;
|
|
122
107
|
}
|
|
123
108
|
|
|
@@ -130,7 +115,7 @@ export const formatChanged = async (): Promise<'ok' | 'err'> => {
|
|
|
130
115
|
});
|
|
131
116
|
|
|
132
117
|
if (fileInfo.ignored) {
|
|
133
|
-
|
|
118
|
+
echo(`Skipping ignored file: ${filePath}`);
|
|
134
119
|
return;
|
|
135
120
|
}
|
|
136
121
|
|
|
@@ -143,7 +128,7 @@ export const formatChanged = async (): Promise<'ok' | 'err'> => {
|
|
|
143
128
|
// Only write if content changed
|
|
144
129
|
if (formatted !== content) {
|
|
145
130
|
await writeFile(filePath, formatted, 'utf8');
|
|
146
|
-
|
|
131
|
+
echo(`Formatted: ${filePath}`);
|
|
147
132
|
}
|
|
148
133
|
} catch (error) {
|
|
149
134
|
console.error(`Error formatting ${filePath}:`, error);
|
|
@@ -166,32 +151,24 @@ export const formatChanged = async (): Promise<'ok' | 'err'> => {
|
|
|
166
151
|
* @param base - Base branch name or commit hash to compare against (defaults to 'main')
|
|
167
152
|
* @returns 'ok' if successful, 'err' if any errors occurred
|
|
168
153
|
*/
|
|
169
|
-
export const formatDiffFrom = async (
|
|
170
|
-
base: string = 'main',
|
|
171
|
-
): Promise<'ok' | 'err'> => {
|
|
154
|
+
export const formatDiffFrom = async (base: string): Promise<'ok' | 'err'> => {
|
|
172
155
|
try {
|
|
173
156
|
// Get files that differ from base branch/commit (excluding deleted files)
|
|
174
|
-
const
|
|
175
|
-
`git diff --name-only ${base} --diff-filter=d`,
|
|
176
|
-
);
|
|
157
|
+
const diffFromBaseResult = await getDiffFrom(base);
|
|
177
158
|
|
|
178
|
-
if (
|
|
179
|
-
console.error('
|
|
159
|
+
if (Result.isErr(diffFromBaseResult)) {
|
|
160
|
+
console.error('Error getting changed files:', diffFromBaseResult.value);
|
|
180
161
|
return 'err';
|
|
181
162
|
}
|
|
182
163
|
|
|
183
|
-
|
|
184
|
-
const files = stdout
|
|
185
|
-
.split('\n')
|
|
186
|
-
.map((line) => line.trim())
|
|
187
|
-
.filter((line) => line !== '');
|
|
164
|
+
const files = diffFromBaseResult.value;
|
|
188
165
|
|
|
189
166
|
if (files.length === 0) {
|
|
190
|
-
|
|
167
|
+
echo(`No files differ from ${base}`);
|
|
191
168
|
return 'ok';
|
|
192
169
|
}
|
|
193
170
|
|
|
194
|
-
|
|
171
|
+
echo(`Formatting files that differ from ${base}:`, files);
|
|
195
172
|
|
|
196
173
|
// Format each file
|
|
197
174
|
const results = await Promise.allSettled(
|
|
@@ -209,7 +186,7 @@ export const formatDiffFrom = async (
|
|
|
209
186
|
});
|
|
210
187
|
|
|
211
188
|
if (fileInfo.ignored) {
|
|
212
|
-
|
|
189
|
+
echo(`Skipping ignored file: ${filePath}`);
|
|
213
190
|
return;
|
|
214
191
|
}
|
|
215
192
|
|
|
@@ -222,7 +199,7 @@ export const formatDiffFrom = async (
|
|
|
222
199
|
// Only write if content changed
|
|
223
200
|
if (formatted !== content) {
|
|
224
201
|
await writeFile(filePath, formatted, 'utf8');
|
|
225
|
-
|
|
202
|
+
echo(`Formatted: ${filePath}`);
|
|
226
203
|
}
|
|
227
204
|
} catch (error) {
|
|
228
205
|
console.error(`Error formatting ${filePath}:`, error);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import dedent from 'dedent';
|
|
2
2
|
import { mkdir, rm, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
|
-
import {
|
|
4
|
+
import { formatFiles } from './format.mjs';
|
|
5
5
|
|
|
6
6
|
describe('formatFiles', () => {
|
|
7
7
|
const testDir = join(process.cwd(), 'test-format-files');
|
|
@@ -116,23 +116,3 @@ describe('formatFiles', () => {
|
|
|
116
116
|
}
|
|
117
117
|
});
|
|
118
118
|
});
|
|
119
|
-
|
|
120
|
-
describe('formatDiffFrom', () => {
|
|
121
|
-
test('should use default base branch "main"', () => {
|
|
122
|
-
// This test would require a git repository setup, so we'll just verify the function exists
|
|
123
|
-
// and can be called with no arguments
|
|
124
|
-
expect(typeof formatDiffFrom).toBe('function');
|
|
125
|
-
expect(formatDiffFrom.length).toBe(0); // Function has default parameter
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
test('should accept custom base branch or commit', () => {
|
|
129
|
-
// Verify the function can be called with a custom base
|
|
130
|
-
const customBases = ['develop', 'feature/test', 'abc123'];
|
|
131
|
-
|
|
132
|
-
for (const base of customBases) {
|
|
133
|
-
// This would normally test against a real git repo, but we're just verifying
|
|
134
|
-
// the function signature accepts the parameter
|
|
135
|
-
expect(() => formatDiffFrom(base)).not.toThrow();
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
});
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import micromatch from 'micromatch';
|
|
2
|
+
import { Result } from 'ts-data-forge';
|
|
2
3
|
import '../node-global.mjs';
|
|
3
4
|
import { assertPathExists } from './assert-path-exists.mjs';
|
|
4
5
|
|
|
@@ -56,8 +57,8 @@ export const genIndex = async (config: GenIndexConfig): Promise<void> => {
|
|
|
56
57
|
// Step 3: Format generated files
|
|
57
58
|
echo('3. Formatting generated files...');
|
|
58
59
|
const fmtResult = await $('npm run fmt');
|
|
59
|
-
if (fmtResult
|
|
60
|
-
throw new Error(`Formatting failed: ${fmtResult.
|
|
60
|
+
if (Result.isErr(fmtResult)) {
|
|
61
|
+
throw new Error(`Formatting failed: ${fmtResult.value.message}`);
|
|
61
62
|
}
|
|
62
63
|
echo('✓ Formatting completed\n');
|
|
63
64
|
|
package/src/functions/index.mts
CHANGED