ts-codemod-lib 1.0.1 → 1.1.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 +428 -6
- package/dist/cmd/append-as-const.d.mts +3 -0
- package/dist/cmd/append-as-const.d.mts.map +1 -0
- package/dist/cmd/append-as-const.mjs +138 -0
- package/dist/cmd/append-as-const.mjs.map +1 -0
- package/dist/cmd/convert-interface-to-type.d.mts +3 -0
- package/dist/cmd/convert-interface-to-type.d.mts.map +1 -0
- package/dist/cmd/convert-interface-to-type.mjs +138 -0
- package/dist/cmd/convert-interface-to-type.mjs.map +1 -0
- package/dist/cmd/convert-to-readonly.mjs +3 -2
- package/dist/cmd/convert-to-readonly.mjs.map +1 -1
- package/dist/cmd/replace-any-with-unknown.d.mts +3 -0
- package/dist/cmd/replace-any-with-unknown.d.mts.map +1 -0
- package/dist/cmd/replace-any-with-unknown.mjs +138 -0
- package/dist/cmd/replace-any-with-unknown.mjs.map +1 -0
- package/dist/cmd/replace-record-with-unknown-record.d.mts +3 -0
- package/dist/cmd/replace-record-with-unknown-record.d.mts.map +1 -0
- package/dist/cmd/replace-record-with-unknown-record.mjs +138 -0
- package/dist/cmd/replace-record-with-unknown-record.mjs.map +1 -0
- package/dist/entry-point.mjs +2 -0
- package/dist/entry-point.mjs.map +1 -1
- package/dist/functions/ast-transformers/append-as-const.d.mts +13 -0
- package/dist/functions/ast-transformers/append-as-const.d.mts.map +1 -0
- package/dist/functions/ast-transformers/append-as-const.mjs +98 -0
- package/dist/functions/ast-transformers/append-as-const.mjs.map +1 -0
- package/dist/functions/ast-transformers/index.d.mts +2 -0
- package/dist/functions/ast-transformers/index.d.mts.map +1 -1
- package/dist/functions/ast-transformers/index.mjs +2 -0
- package/dist/functions/ast-transformers/index.mjs.map +1 -1
- package/dist/functions/ast-transformers/replace-any-with-unknown.d.mts +3 -0
- package/dist/functions/ast-transformers/replace-any-with-unknown.d.mts.map +1 -0
- package/dist/functions/ast-transformers/replace-any-with-unknown.mjs +38 -0
- package/dist/functions/ast-transformers/replace-any-with-unknown.mjs.map +1 -0
- package/dist/functions/index.mjs +2 -0
- package/dist/functions/index.mjs.map +1 -1
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -1
- package/package.json +60 -56
- package/src/cmd/append-as-const.mts +197 -0
- package/src/cmd/convert-interface-to-type.mts +197 -0
- package/src/cmd/convert-to-readonly.mts +3 -1
- package/src/cmd/replace-any-with-unknown.mts +197 -0
- package/src/cmd/replace-record-with-unknown-record.mts +197 -0
- package/src/functions/ast-transformers/append-as-const.mts +154 -0
- package/src/functions/ast-transformers/append-as-const.test.mts +339 -0
- package/src/functions/ast-transformers/convert-to-readonly-type.test.mts +3 -3
- package/src/functions/ast-transformers/index.mts +2 -0
- package/src/functions/ast-transformers/replace-any-with-unknown.mts +49 -0
- package/src/functions/ast-transformers/replace-any-with-unknown.test.mts +140 -0
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
export * from './append-as-const.mjs';
|
|
1
2
|
export * from './convert-interface-to-type.mjs';
|
|
2
3
|
export * from './convert-to-readonly-type.mjs';
|
|
3
4
|
export * from './readonly-transformer-helpers/index.mjs';
|
|
5
|
+
export * from './replace-any-with-unknown.mjs';
|
|
4
6
|
export * from './replace-record-with-unknown-record.mjs';
|
|
5
7
|
export * from './transform-source-code.mjs';
|
|
6
8
|
export * from './types.mjs';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../../src/functions/ast-transformers/index.mts"],"names":[],"mappings":"AAAA,cAAc,iCAAiC,CAAC;AAChD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0CAA0C,CAAC;AACzD,cAAc,0CAA0C,CAAC;AACzD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.mts","sourceRoot":"","sources":["../../../src/functions/ast-transformers/index.mts"],"names":[],"mappings":"AAAA,cAAc,uBAAuB,CAAC;AACtC,cAAc,iCAAiC,CAAC;AAChD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0CAA0C,CAAC;AACzD,cAAc,gCAAgC,CAAC;AAC/C,cAAc,0CAA0C,CAAC;AACzD,cAAc,6BAA6B,CAAC;AAC5C,cAAc,aAAa,CAAC"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
export { appendAsConstTransformer } from './append-as-const.mjs';
|
|
1
2
|
export { convertInterfaceToTypeTransformer } from './convert-interface-to-type.mjs';
|
|
2
3
|
export { convertToReadonlyTypeTransformer } from './convert-to-readonly-type.mjs';
|
|
3
4
|
export { compareUnionIntersectionTypes } from './readonly-transformer-helpers/compare-union-types.mjs';
|
|
4
5
|
export { invalidDeepReadonlyTypeName } from './readonly-transformer-helpers/constants.mjs';
|
|
5
6
|
export { groupUnionIntersectionTypes } from './readonly-transformer-helpers/group-union-types.mjs';
|
|
6
7
|
export { nextReadonlyContext } from './readonly-transformer-helpers/readonly-context.mjs';
|
|
8
|
+
export { replaceAnyWithUnknownTransformer } from './replace-any-with-unknown.mjs';
|
|
7
9
|
export { replaceRecordWithUnknownRecordTransformer } from './replace-record-with-unknown-record.mjs';
|
|
8
10
|
export { transformSourceCode } from './transform-source-code.mjs';
|
|
9
11
|
//# 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":";;;;;;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replace-any-with-unknown.d.mts","sourceRoot":"","sources":["../../../src/functions/ast-transformers/replace-any-with-unknown.mts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,eAAO,MAAM,gCAAgC,QAAO,kBAA0B,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as tsm from 'ts-morph';
|
|
2
|
+
import { hasDisableNextLineComment } from '../functions/has-disable-next-line-comment.mjs';
|
|
3
|
+
import '../functions/is-primitive-type-node.mjs';
|
|
4
|
+
import 'ts-data-forge';
|
|
5
|
+
import { isSpreadParameterNode, isSpreadNamedTupleMemberNode } from '../functions/is-spread-parameter-node.mjs';
|
|
6
|
+
|
|
7
|
+
const replaceAnyWithUnknownTransformer = () => body;
|
|
8
|
+
const body = (sourceAst) => {
|
|
9
|
+
for (const node of sourceAst.getChildren()) {
|
|
10
|
+
transformNode(node);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
const transformNode = (node) => {
|
|
14
|
+
if (hasDisableNextLineComment(node)) {
|
|
15
|
+
console.debug('skipped by disable-next-line comment');
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
if (node.isKind(tsm.SyntaxKind.AnyKeyword)) {
|
|
19
|
+
const anyKeywordNode = node;
|
|
20
|
+
const parent = anyKeywordNode.getParent();
|
|
21
|
+
if (parent !== undefined &&
|
|
22
|
+
// `(...args: any) => any` -> `(...args: unknown[]) => any`
|
|
23
|
+
(isSpreadParameterNode(parent) ||
|
|
24
|
+
// `[name: E0, ...args: any)]` -> `[name: E0, ...args: unknown[]]`
|
|
25
|
+
isSpreadNamedTupleMemberNode(parent))) {
|
|
26
|
+
anyKeywordNode.replaceWithText('readonly unknown[]');
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
anyKeywordNode.replaceWithText('unknown');
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
for (const child of node.getChildren()) {
|
|
33
|
+
transformNode(child);
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export { replaceAnyWithUnknownTransformer };
|
|
38
|
+
//# sourceMappingURL=replace-any-with-unknown.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replace-any-with-unknown.mjs","sources":["../../../src/functions/ast-transformers/replace-any-with-unknown.mts"],"sourcesContent":[null],"names":[],"mappings":";;;;;;MAQa,gCAAgC,GAAG,MAA0B;AAE1E,MAAM,IAAI,GAAuB,CAAC,SAAS,KAAI;IAC7C,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,WAAW,EAAE,EAAE;QAC1C,aAAa,CAAC,IAAI,CAAC;IACrB;AACF,CAAC;AAED,MAAM,aAAa,GAAG,CAAC,IAAc,KAAU;AAC7C,IAAA,IAAI,yBAAyB,CAAC,IAAI,CAAC,EAAE;AACnC,QAAA,OAAO,CAAC,KAAK,CAAC,sCAAsC,CAAC;QAErD;IACF;IAEA,IAAI,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;QAC1C,MAAM,cAAc,GAAG,IAAI;AAE3B,QAAA,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,EAAE;QAEzC,IACE,MAAM,KAAK,SAAS;;aAEnB,qBAAqB,CAAC,MAAM,CAAC;;AAE5B,gBAAA,4BAA4B,CAAC,MAAM,CAAC,CAAC,EACvC;AACA,YAAA,cAAc,CAAC,eAAe,CAAC,oBAAoB,CAAC;YAEpD;QACF;AAEA,QAAA,cAAc,CAAC,eAAe,CAAC,SAAS,CAAC;QAEzC;IACF;IAEA,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE;QACtC,aAAa,CAAC,KAAK,CAAC;IACtB;AACF,CAAC;;;;"}
|
package/dist/functions/index.mjs
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
|
+
export { appendAsConstTransformer } from './ast-transformers/append-as-const.mjs';
|
|
1
2
|
export { convertInterfaceToTypeTransformer } from './ast-transformers/convert-interface-to-type.mjs';
|
|
2
3
|
export { convertToReadonlyTypeTransformer } from './ast-transformers/convert-to-readonly-type.mjs';
|
|
3
4
|
export { compareUnionIntersectionTypes } from './ast-transformers/readonly-transformer-helpers/compare-union-types.mjs';
|
|
4
5
|
export { invalidDeepReadonlyTypeName } from './ast-transformers/readonly-transformer-helpers/constants.mjs';
|
|
5
6
|
export { groupUnionIntersectionTypes } from './ast-transformers/readonly-transformer-helpers/group-union-types.mjs';
|
|
6
7
|
export { nextReadonlyContext } from './ast-transformers/readonly-transformer-helpers/readonly-context.mjs';
|
|
8
|
+
export { replaceAnyWithUnknownTransformer } from './ast-transformers/replace-any-with-unknown.mjs';
|
|
7
9
|
export { replaceRecordWithUnknownRecordTransformer } from './ast-transformers/replace-record-with-unknown-record.mjs';
|
|
8
10
|
export { transformSourceCode } from './ast-transformers/transform-source-code.mjs';
|
|
9
11
|
export { IGNORE_FILE_COMMENT_TEXT, IGNORE_LINE_COMMENT_TEXT } from './constants/ignore-comment-text.mjs';
|
|
@@ -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,9 +1,11 @@
|
|
|
1
|
+
export { appendAsConstTransformer } from './functions/ast-transformers/append-as-const.mjs';
|
|
1
2
|
export { convertInterfaceToTypeTransformer } from './functions/ast-transformers/convert-interface-to-type.mjs';
|
|
2
3
|
export { convertToReadonlyTypeTransformer } from './functions/ast-transformers/convert-to-readonly-type.mjs';
|
|
3
4
|
export { compareUnionIntersectionTypes } from './functions/ast-transformers/readonly-transformer-helpers/compare-union-types.mjs';
|
|
4
5
|
export { invalidDeepReadonlyTypeName } from './functions/ast-transformers/readonly-transformer-helpers/constants.mjs';
|
|
5
6
|
export { groupUnionIntersectionTypes } from './functions/ast-transformers/readonly-transformer-helpers/group-union-types.mjs';
|
|
6
7
|
export { nextReadonlyContext } from './functions/ast-transformers/readonly-transformer-helpers/readonly-context.mjs';
|
|
8
|
+
export { replaceAnyWithUnknownTransformer } from './functions/ast-transformers/replace-any-with-unknown.mjs';
|
|
7
9
|
export { replaceRecordWithUnknownRecordTransformer } from './functions/ast-transformers/replace-record-with-unknown-record.mjs';
|
|
8
10
|
export { transformSourceCode } from './functions/ast-transformers/transform-source-code.mjs';
|
|
9
11
|
export { IGNORE_FILE_COMMENT_TEXT, IGNORE_LINE_COMMENT_TEXT } from './functions/constants/ignore-comment-text.mjs';
|
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-codemod-lib",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -27,8 +27,10 @@
|
|
|
27
27
|
"module": "./dist/entry-point.mjs",
|
|
28
28
|
"types": "./dist/types.d.mts",
|
|
29
29
|
"bin": {
|
|
30
|
+
"append-as-const": "./dist/cmd/append-as-const.mjs",
|
|
30
31
|
"convert-interface-to-type": "./dist/cmd/convert-interface-to-type.mjs",
|
|
31
32
|
"convert-to-readonly": "./dist/cmd/convert-to-readonly.mjs",
|
|
33
|
+
"replace-any-with-unknown": "./dist/cmd/replace-any-with-unknown.mjs",
|
|
32
34
|
"replace-record-with-unknown-record": "./dist/cmd/replace-record-with-unknown-record.mjs"
|
|
33
35
|
},
|
|
34
36
|
"files": [
|
|
@@ -37,6 +39,48 @@
|
|
|
37
39
|
"README.md",
|
|
38
40
|
"LICENSE"
|
|
39
41
|
],
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsx ./scripts/cmd/build.mts",
|
|
44
|
+
"build:min": "tsx ./scripts/cmd/build.mts --skip-check",
|
|
45
|
+
"check-all": "tsx ./scripts/cmd/check-all.mts",
|
|
46
|
+
"check:ext": "tsx ./scripts/cmd/check-ext.mts",
|
|
47
|
+
"clean": "pnpm run /clean:.*/",
|
|
48
|
+
"clean:logs": "npx rimraf ./*.log",
|
|
49
|
+
"cspell": "cspell \"**\" --gitignore --gitignore-root ./ --no-progress",
|
|
50
|
+
"doc": "tsx ./scripts/cmd/gen-docs.mts",
|
|
51
|
+
"doc:embed": "tsx ./scripts/cmd/embed-samples.mts",
|
|
52
|
+
"doc:preview": "vite preview --config ./configs/vite.doc.config.mts",
|
|
53
|
+
"doc:watch": "typedoc --options ./configs/typedoc.config.mjs --watch",
|
|
54
|
+
"fmt": "format-uncommitted",
|
|
55
|
+
"fmt:diff": "format-diff-from origin/main",
|
|
56
|
+
"fmt:full": "prettier --write .",
|
|
57
|
+
"gh:apply-all": "gh-apply-all",
|
|
58
|
+
"gh:apply-repository-settings": "gh-apply-repository-settings",
|
|
59
|
+
"gh:apply-rulesets": "gh-apply-rulesets",
|
|
60
|
+
"gh:apply-variables": "gh-apply-variables",
|
|
61
|
+
"gh:backup-all": "gh-backup-all",
|
|
62
|
+
"gh:backup-repository-settings": "gh-backup-repository-settings",
|
|
63
|
+
"gh:backup-rulesets": "gh-backup-rulesets",
|
|
64
|
+
"gi": "run-s gi:src fmt",
|
|
65
|
+
"gi:src": "gen-index-ts ./src --index-ext .mts --export-ext .mjs --target-ext .mts --target-ext .tsx --exclude entry-point.mts --exclude cmd",
|
|
66
|
+
"lint": "eslint .",
|
|
67
|
+
"lint:fix": "eslint . --fix",
|
|
68
|
+
"md": "markdownlint-cli2",
|
|
69
|
+
"run:cmd": "tsx ./src/cmd/convert-to-readonly.mts ./test/sample1.mts",
|
|
70
|
+
"run:test": "tsx ./scripts/test-code/transform-test-code.mts",
|
|
71
|
+
"test": "pnpm run z:vitest:node run",
|
|
72
|
+
"test:browser": "pnpm run z:vitest --project='Browser' run",
|
|
73
|
+
"test:cov": "pnpm run z:vitest:node run --coverage",
|
|
74
|
+
"test:cov:ui": "vite preview --outDir ./coverage",
|
|
75
|
+
"test:ui": "pnpm run z:vitest:node --ui",
|
|
76
|
+
"testw": "pnpm run z:vitest:node watch",
|
|
77
|
+
"tsc": "tsc --noEmit",
|
|
78
|
+
"tscw": "tsc --noEmit --watch -p ./tsconfig.json",
|
|
79
|
+
"type-check": "tsc --noEmit",
|
|
80
|
+
"update-packages": "pnpm update --latest",
|
|
81
|
+
"z:vitest": "vitest --config ./configs/vitest.config.mts",
|
|
82
|
+
"z:vitest:node": "pnpm run z:vitest --project='Node.js'"
|
|
83
|
+
},
|
|
40
84
|
"dependencies": {
|
|
41
85
|
"cmd-ts": "0.14.3",
|
|
42
86
|
"dedent": "1.7.1",
|
|
@@ -54,81 +98,41 @@
|
|
|
54
98
|
"@semantic-release/github": "12.0.2",
|
|
55
99
|
"@semantic-release/npm": "13.1.3",
|
|
56
100
|
"@semantic-release/release-notes-generator": "14.1.0",
|
|
57
|
-
"@types/node": "25.0.
|
|
58
|
-
"@vitest/browser-playwright": "4.0.
|
|
59
|
-
"@vitest/coverage-v8": "4.0.
|
|
60
|
-
"@vitest/ui": "4.0.
|
|
101
|
+
"@types/node": "25.0.9",
|
|
102
|
+
"@vitest/browser-playwright": "4.0.17",
|
|
103
|
+
"@vitest/coverage-v8": "4.0.17",
|
|
104
|
+
"@vitest/ui": "4.0.17",
|
|
61
105
|
"conventional-changelog-conventionalcommits": "9.1.0",
|
|
62
|
-
"cspell": "9.
|
|
106
|
+
"cspell": "9.6.0",
|
|
63
107
|
"eslint": "9.39.2",
|
|
64
|
-
"eslint-config-typed": "4.
|
|
65
|
-
"github-settings-as-code": "1.0.
|
|
108
|
+
"eslint-config-typed": "4.5.0",
|
|
109
|
+
"github-settings-as-code": "1.0.11",
|
|
66
110
|
"jiti": "2.6.1",
|
|
67
111
|
"markdownlint": "0.40.0",
|
|
68
112
|
"markdownlint-cli2": "0.20.0",
|
|
69
113
|
"npm-run-all2": "8.0.4",
|
|
70
114
|
"playwright": "1.57.0",
|
|
71
|
-
"prettier": "3.
|
|
115
|
+
"prettier": "3.8.0",
|
|
72
116
|
"prettier-plugin-organize-imports": "4.3.0",
|
|
73
|
-
"prettier-plugin-packagejson": "2.5.
|
|
74
|
-
"rollup": "4.
|
|
117
|
+
"prettier-plugin-packagejson": "2.5.21",
|
|
118
|
+
"rollup": "4.55.1",
|
|
75
119
|
"semantic-release": "25.0.2",
|
|
76
120
|
"ts-data-forge": "6.2.1",
|
|
77
121
|
"ts-type-forge": "2.3.0",
|
|
78
122
|
"tslib": "2.8.1",
|
|
79
123
|
"tsx": "4.21.0",
|
|
80
|
-
"typedoc": "0.28.
|
|
124
|
+
"typedoc": "0.28.16",
|
|
81
125
|
"typedoc-github-theme": "0.3.1",
|
|
82
126
|
"typescript": "5.9.3",
|
|
83
|
-
"vite": "7.3.
|
|
84
|
-
"vitest": "4.0.
|
|
127
|
+
"vite": "7.3.1",
|
|
128
|
+
"vitest": "4.0.17"
|
|
85
129
|
},
|
|
130
|
+
"packageManager": "pnpm@10.27.0",
|
|
86
131
|
"engines": {
|
|
87
132
|
"node": ">=22",
|
|
88
133
|
"pnpm": ">=8.0.0"
|
|
89
134
|
},
|
|
90
135
|
"volta": {
|
|
91
136
|
"node": "25.2.1"
|
|
92
|
-
},
|
|
93
|
-
"scripts": {
|
|
94
|
-
"build": "tsx ./scripts/cmd/build.mts",
|
|
95
|
-
"build:min": "tsx ./scripts/cmd/build.mts --skip-check",
|
|
96
|
-
"check-all": "tsx ./scripts/cmd/check-all.mts",
|
|
97
|
-
"check:ext": "tsx ./scripts/cmd/check-ext.mts",
|
|
98
|
-
"clean": "pnpm run /clean:.*/",
|
|
99
|
-
"clean:logs": "npx rimraf ./*.log",
|
|
100
|
-
"cspell": "cspell \"**\" --gitignore --gitignore-root ./ --no-progress",
|
|
101
|
-
"doc": "tsx ./scripts/cmd/gen-docs.mts",
|
|
102
|
-
"doc:embed": "tsx ./scripts/cmd/embed-samples.mts",
|
|
103
|
-
"doc:preview": "vite preview --config ./configs/vite.doc.config.mts",
|
|
104
|
-
"doc:watch": "typedoc --options ./configs/typedoc.config.mjs --watch",
|
|
105
|
-
"fmt": "format-uncommitted",
|
|
106
|
-
"fmt:diff": "format-diff-from origin/main",
|
|
107
|
-
"fmt:full": "prettier --write .",
|
|
108
|
-
"gh:apply-all": "gh-apply-all",
|
|
109
|
-
"gh:apply-repository-settings": "gh-apply-repository-settings",
|
|
110
|
-
"gh:apply-rulesets": "gh-apply-rulesets",
|
|
111
|
-
"gh:apply-variables": "gh-apply-variables",
|
|
112
|
-
"gh:backup-all": "gh-backup-all",
|
|
113
|
-
"gh:backup-repository-settings": "gh-backup-repository-settings",
|
|
114
|
-
"gh:backup-rulesets": "gh-backup-rulesets",
|
|
115
|
-
"gi": "run-s gi:src fmt",
|
|
116
|
-
"gi:src": "gen-index-ts ./src --index-ext .mts --export-ext .mjs --target-ext .mts --target-ext .tsx --exclude entry-point.mts --exclude cmd",
|
|
117
|
-
"lint": "eslint .",
|
|
118
|
-
"lint:fix": "eslint . --fix",
|
|
119
|
-
"md": "markdownlint-cli2",
|
|
120
|
-
"run:cmd": "tsx ./src/cmd/convert-to-readonly.mts ./test/convert-to-readonly.mts",
|
|
121
|
-
"test": "pnpm run z:vitest:node run",
|
|
122
|
-
"test:browser": "pnpm run z:vitest --project='Browser' run",
|
|
123
|
-
"test:cov": "pnpm run z:vitest:node run --coverage",
|
|
124
|
-
"test:cov:ui": "vite preview --outDir ./coverage",
|
|
125
|
-
"test:ui": "pnpm run z:vitest:node --ui",
|
|
126
|
-
"testw": "pnpm run z:vitest:node watch",
|
|
127
|
-
"tsc": "tsc --noEmit",
|
|
128
|
-
"tscw": "tsc --noEmit --watch -p ./tsconfig.json",
|
|
129
|
-
"type-check": "tsc --noEmit",
|
|
130
|
-
"update-packages": "pnpm update --latest",
|
|
131
|
-
"z:vitest": "vitest --config ./configs/vitest.config.mts",
|
|
132
|
-
"z:vitest:node": "vitest --config ./configs/vitest.config.mts --project='Node.js'"
|
|
133
137
|
}
|
|
134
|
-
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable no-await-in-loop */
|
|
3
|
+
|
|
4
|
+
import * as cmd from 'cmd-ts';
|
|
5
|
+
import dedent from 'dedent';
|
|
6
|
+
import { castMutable, Result, unknownToString } from 'ts-data-forge';
|
|
7
|
+
import 'ts-repo-utils';
|
|
8
|
+
import {
|
|
9
|
+
appendAsConstTransformer,
|
|
10
|
+
transformSourceCode,
|
|
11
|
+
} from '../functions/index.mjs';
|
|
12
|
+
|
|
13
|
+
const cmdDef = cmd.command({
|
|
14
|
+
name: 'append-as-const-cli',
|
|
15
|
+
version: '1.0.0',
|
|
16
|
+
args: {
|
|
17
|
+
baseDir: cmd.positional({
|
|
18
|
+
type: cmd.string,
|
|
19
|
+
displayName: 'baseDir',
|
|
20
|
+
description: 'The base directory in which to perform the conversion',
|
|
21
|
+
}),
|
|
22
|
+
exclude: cmd.multioption({
|
|
23
|
+
long: 'exclude',
|
|
24
|
+
type: cmd.optional(cmd.array(cmd.string)),
|
|
25
|
+
description:
|
|
26
|
+
'Glob patterns of files to exclude from the base directory (e.g., "src/generated/**/*.mts")',
|
|
27
|
+
}),
|
|
28
|
+
silent: cmd.flag({
|
|
29
|
+
long: 'silent',
|
|
30
|
+
type: cmd.optional(cmd.boolean),
|
|
31
|
+
description: 'If true, suppresses output messages (default: false)',
|
|
32
|
+
}),
|
|
33
|
+
},
|
|
34
|
+
handler: (args) => {
|
|
35
|
+
appendAsConstCLI({
|
|
36
|
+
baseDir: args.baseDir,
|
|
37
|
+
exclude: args.exclude ?? [],
|
|
38
|
+
silent: args.silent ?? false,
|
|
39
|
+
}).catch((error: unknown) => {
|
|
40
|
+
console.error('An error occurred:', error);
|
|
41
|
+
|
|
42
|
+
process.exit(1);
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
type Args = Readonly<{
|
|
48
|
+
baseDir: string;
|
|
49
|
+
exclude: readonly string[];
|
|
50
|
+
silent: boolean;
|
|
51
|
+
}>;
|
|
52
|
+
|
|
53
|
+
const appendAsConstCLI = async (
|
|
54
|
+
args: Args,
|
|
55
|
+
): Promise<Result<undefined, undefined>> => {
|
|
56
|
+
const echoIfNotSilent = args.silent ? () => {} : echo;
|
|
57
|
+
|
|
58
|
+
const errorIfNotSilent = args.silent ? () => {} : console.error;
|
|
59
|
+
|
|
60
|
+
// Find all files matching the glob
|
|
61
|
+
const globResult = await glob(args.baseDir, {
|
|
62
|
+
ignore: castMutable(args.exclude),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (Result.isErr(globResult)) {
|
|
66
|
+
errorIfNotSilent('Error finding files matching pattern:', globResult.value);
|
|
67
|
+
|
|
68
|
+
return Result.err(undefined);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const files = globResult.value;
|
|
72
|
+
|
|
73
|
+
if (files.length === 0) {
|
|
74
|
+
echoIfNotSilent('No files found matching pattern:', args.baseDir);
|
|
75
|
+
|
|
76
|
+
return Result.ok(undefined);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const { errorFiles, transformedCount, unchangedCount } = await transformFiles(
|
|
80
|
+
files,
|
|
81
|
+
args.silent,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const hr = '='.repeat(50);
|
|
85
|
+
|
|
86
|
+
echoIfNotSilent(dedent`
|
|
87
|
+
${hr}
|
|
88
|
+
Summary:
|
|
89
|
+
✅ Transformed: ${transformedCount}
|
|
90
|
+
⏭️ Unchanged: ${unchangedCount}
|
|
91
|
+
❌ Errors: ${errorFiles.length}
|
|
92
|
+
📊 Total: ${files.length}
|
|
93
|
+
`);
|
|
94
|
+
|
|
95
|
+
if (errorFiles.length > 0) {
|
|
96
|
+
echoIfNotSilent('\nFiles with errors:');
|
|
97
|
+
|
|
98
|
+
for (const fileName of errorFiles) {
|
|
99
|
+
echoIfNotSilent(` - ${fileName}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
echoIfNotSilent(hr);
|
|
104
|
+
|
|
105
|
+
if (errorFiles.length > 0) {
|
|
106
|
+
return Result.err(undefined);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return Result.ok(undefined);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const transformFiles = async (
|
|
113
|
+
filePaths: readonly string[],
|
|
114
|
+
silent: boolean,
|
|
115
|
+
): Promise<
|
|
116
|
+
Readonly<{
|
|
117
|
+
transformedCount: number;
|
|
118
|
+
unchangedCount: number;
|
|
119
|
+
errorFiles: readonly string[];
|
|
120
|
+
}>
|
|
121
|
+
> => {
|
|
122
|
+
let mut_transformedCount: number = 0;
|
|
123
|
+
|
|
124
|
+
let mut_unchangedCount: number = 0;
|
|
125
|
+
|
|
126
|
+
const mut_errorFiles: string[] = [];
|
|
127
|
+
|
|
128
|
+
for (const filePath of filePaths) {
|
|
129
|
+
const result = await transformOneFile(filePath, silent);
|
|
130
|
+
|
|
131
|
+
if (Result.isOk(result)) {
|
|
132
|
+
switch (result.value) {
|
|
133
|
+
case 'transformed':
|
|
134
|
+
mut_transformedCount += 1;
|
|
135
|
+
|
|
136
|
+
break;
|
|
137
|
+
|
|
138
|
+
case 'unchanged':
|
|
139
|
+
mut_unchangedCount += 1;
|
|
140
|
+
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
mut_errorFiles.push(path.basename(filePath));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
transformedCount: mut_transformedCount,
|
|
150
|
+
unchangedCount: mut_unchangedCount,
|
|
151
|
+
errorFiles: mut_errorFiles,
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const transformOneFile = async (
|
|
156
|
+
filePath: string,
|
|
157
|
+
silent: boolean,
|
|
158
|
+
): Promise<Result<'unchanged' | 'transformed', string>> => {
|
|
159
|
+
const echoIfNotSilent = silent ? () => {} : echo;
|
|
160
|
+
|
|
161
|
+
const errorIfNotSilent = silent ? () => {} : console.error;
|
|
162
|
+
|
|
163
|
+
const fileName = path.basename(filePath);
|
|
164
|
+
|
|
165
|
+
const isTsx = fileName.endsWith('.tsx') || fileName.endsWith('.jsx');
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const originalCode = await fs.readFile(filePath, 'utf8');
|
|
169
|
+
|
|
170
|
+
// Transform the code with all transformers
|
|
171
|
+
const transformedCode = transformSourceCode(originalCode, isTsx, [
|
|
172
|
+
appendAsConstTransformer(),
|
|
173
|
+
]);
|
|
174
|
+
|
|
175
|
+
// Check if the code was actually changed
|
|
176
|
+
if (transformedCode === originalCode) {
|
|
177
|
+
echoIfNotSilent(`⏭️ ${fileName} - no changes needed`);
|
|
178
|
+
|
|
179
|
+
return Result.ok('unchanged');
|
|
180
|
+
} else {
|
|
181
|
+
// Write back the transformed code
|
|
182
|
+
await fs.writeFile(filePath, transformedCode, 'utf8');
|
|
183
|
+
|
|
184
|
+
echoIfNotSilent(`✅ ${fileName} - transformed`);
|
|
185
|
+
|
|
186
|
+
return Result.ok('transformed');
|
|
187
|
+
}
|
|
188
|
+
} catch (error) {
|
|
189
|
+
const errStr = unknownToString(error);
|
|
190
|
+
|
|
191
|
+
errorIfNotSilent(`❌ ${fileName} - error: ${errStr}`);
|
|
192
|
+
|
|
193
|
+
return Result.err(errStr);
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
await cmd.run(cmdDef, process.argv.slice(2));
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable no-await-in-loop */
|
|
3
|
+
|
|
4
|
+
import * as cmd from 'cmd-ts';
|
|
5
|
+
import dedent from 'dedent';
|
|
6
|
+
import { castMutable, Result, unknownToString } from 'ts-data-forge';
|
|
7
|
+
import 'ts-repo-utils';
|
|
8
|
+
import {
|
|
9
|
+
convertInterfaceToTypeTransformer,
|
|
10
|
+
transformSourceCode,
|
|
11
|
+
} from '../functions/index.mjs';
|
|
12
|
+
|
|
13
|
+
const cmdDef = cmd.command({
|
|
14
|
+
name: 'convert-interface-to-type-cli',
|
|
15
|
+
version: '1.0.0',
|
|
16
|
+
args: {
|
|
17
|
+
baseDir: cmd.positional({
|
|
18
|
+
type: cmd.string,
|
|
19
|
+
displayName: 'baseDir',
|
|
20
|
+
description: 'The base directory in which to perform the conversion',
|
|
21
|
+
}),
|
|
22
|
+
exclude: cmd.multioption({
|
|
23
|
+
long: 'exclude',
|
|
24
|
+
type: cmd.optional(cmd.array(cmd.string)),
|
|
25
|
+
description:
|
|
26
|
+
'Glob patterns of files to exclude from the base directory (e.g., "src/generated/**/*.mts")',
|
|
27
|
+
}),
|
|
28
|
+
silent: cmd.flag({
|
|
29
|
+
long: 'silent',
|
|
30
|
+
type: cmd.optional(cmd.boolean),
|
|
31
|
+
description: 'If true, suppresses output messages (default: false)',
|
|
32
|
+
}),
|
|
33
|
+
},
|
|
34
|
+
handler: (args) => {
|
|
35
|
+
convertInterfaceToTypeCLI({
|
|
36
|
+
baseDir: args.baseDir,
|
|
37
|
+
exclude: args.exclude ?? [],
|
|
38
|
+
silent: args.silent ?? false,
|
|
39
|
+
}).catch((error: unknown) => {
|
|
40
|
+
console.error('An error occurred:', error);
|
|
41
|
+
|
|
42
|
+
process.exit(1);
|
|
43
|
+
});
|
|
44
|
+
},
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
type Args = Readonly<{
|
|
48
|
+
baseDir: string;
|
|
49
|
+
exclude: readonly string[];
|
|
50
|
+
silent: boolean;
|
|
51
|
+
}>;
|
|
52
|
+
|
|
53
|
+
const convertInterfaceToTypeCLI = async (
|
|
54
|
+
args: Args,
|
|
55
|
+
): Promise<Result<undefined, undefined>> => {
|
|
56
|
+
const echoIfNotSilent = args.silent ? () => {} : echo;
|
|
57
|
+
|
|
58
|
+
const errorIfNotSilent = args.silent ? () => {} : console.error;
|
|
59
|
+
|
|
60
|
+
// Find all files matching the glob
|
|
61
|
+
const globResult = await glob(args.baseDir, {
|
|
62
|
+
ignore: castMutable(args.exclude),
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
if (Result.isErr(globResult)) {
|
|
66
|
+
errorIfNotSilent('Error finding files matching pattern:', globResult.value);
|
|
67
|
+
|
|
68
|
+
return Result.err(undefined);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const files = globResult.value;
|
|
72
|
+
|
|
73
|
+
if (files.length === 0) {
|
|
74
|
+
echoIfNotSilent('No files found matching pattern:', args.baseDir);
|
|
75
|
+
|
|
76
|
+
return Result.ok(undefined);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const { errorFiles, transformedCount, unchangedCount } = await transformFiles(
|
|
80
|
+
files,
|
|
81
|
+
args.silent,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const hr = '='.repeat(50);
|
|
85
|
+
|
|
86
|
+
echoIfNotSilent(dedent`
|
|
87
|
+
${hr}
|
|
88
|
+
Summary:
|
|
89
|
+
✅ Transformed: ${transformedCount}
|
|
90
|
+
⏭️ Unchanged: ${unchangedCount}
|
|
91
|
+
❌ Errors: ${errorFiles.length}
|
|
92
|
+
📊 Total: ${files.length}
|
|
93
|
+
`);
|
|
94
|
+
|
|
95
|
+
if (errorFiles.length > 0) {
|
|
96
|
+
echoIfNotSilent('\nFiles with errors:');
|
|
97
|
+
|
|
98
|
+
for (const fileName of errorFiles) {
|
|
99
|
+
echoIfNotSilent(` - ${fileName}`);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
echoIfNotSilent(hr);
|
|
104
|
+
|
|
105
|
+
if (errorFiles.length > 0) {
|
|
106
|
+
return Result.err(undefined);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return Result.ok(undefined);
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const transformFiles = async (
|
|
113
|
+
filePaths: readonly string[],
|
|
114
|
+
silent: boolean,
|
|
115
|
+
): Promise<
|
|
116
|
+
Readonly<{
|
|
117
|
+
transformedCount: number;
|
|
118
|
+
unchangedCount: number;
|
|
119
|
+
errorFiles: readonly string[];
|
|
120
|
+
}>
|
|
121
|
+
> => {
|
|
122
|
+
let mut_transformedCount: number = 0;
|
|
123
|
+
|
|
124
|
+
let mut_unchangedCount: number = 0;
|
|
125
|
+
|
|
126
|
+
const mut_errorFiles: string[] = [];
|
|
127
|
+
|
|
128
|
+
for (const filePath of filePaths) {
|
|
129
|
+
const result = await transformOneFile(filePath, silent);
|
|
130
|
+
|
|
131
|
+
if (Result.isOk(result)) {
|
|
132
|
+
switch (result.value) {
|
|
133
|
+
case 'transformed':
|
|
134
|
+
mut_transformedCount += 1;
|
|
135
|
+
|
|
136
|
+
break;
|
|
137
|
+
|
|
138
|
+
case 'unchanged':
|
|
139
|
+
mut_unchangedCount += 1;
|
|
140
|
+
|
|
141
|
+
break;
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
mut_errorFiles.push(path.basename(filePath));
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return {
|
|
149
|
+
transformedCount: mut_transformedCount,
|
|
150
|
+
unchangedCount: mut_unchangedCount,
|
|
151
|
+
errorFiles: mut_errorFiles,
|
|
152
|
+
};
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const transformOneFile = async (
|
|
156
|
+
filePath: string,
|
|
157
|
+
silent: boolean,
|
|
158
|
+
): Promise<Result<'unchanged' | 'transformed', string>> => {
|
|
159
|
+
const echoIfNotSilent = silent ? () => {} : echo;
|
|
160
|
+
|
|
161
|
+
const errorIfNotSilent = silent ? () => {} : console.error;
|
|
162
|
+
|
|
163
|
+
const fileName = path.basename(filePath);
|
|
164
|
+
|
|
165
|
+
const isTsx = fileName.endsWith('.tsx') || fileName.endsWith('.jsx');
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
const originalCode = await fs.readFile(filePath, 'utf8');
|
|
169
|
+
|
|
170
|
+
// Transform the code with all transformers
|
|
171
|
+
const transformedCode = transformSourceCode(originalCode, isTsx, [
|
|
172
|
+
convertInterfaceToTypeTransformer(),
|
|
173
|
+
]);
|
|
174
|
+
|
|
175
|
+
// Check if the code was actually changed
|
|
176
|
+
if (transformedCode === originalCode) {
|
|
177
|
+
echoIfNotSilent(`⏭️ ${fileName} - no changes needed`);
|
|
178
|
+
|
|
179
|
+
return Result.ok('unchanged');
|
|
180
|
+
} else {
|
|
181
|
+
// Write back the transformed code
|
|
182
|
+
await fs.writeFile(filePath, transformedCode, 'utf8');
|
|
183
|
+
|
|
184
|
+
echoIfNotSilent(`✅ ${fileName} - transformed`);
|
|
185
|
+
|
|
186
|
+
return Result.ok('transformed');
|
|
187
|
+
}
|
|
188
|
+
} catch (error) {
|
|
189
|
+
const errStr = unknownToString(error);
|
|
190
|
+
|
|
191
|
+
errorIfNotSilent(`❌ ${fileName} - error: ${errStr}`);
|
|
192
|
+
|
|
193
|
+
return Result.err(errStr);
|
|
194
|
+
}
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
await cmd.run(cmdDef, process.argv.slice(2));
|