@kamaalio/codemod-kit 0.0.26 → 0.0.28
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/dist/codemods/types.d.ts +14 -4
- package/dist/codemods/utils.d.ts +5 -9
- package/dist/index.cjs +31 -4
- package/dist/index.js +31 -4
- package/dist/utils/arrays.d.ts +1 -0
- package/dist/utils/type-utils.d.ts +0 -1
- package/package.json +1 -1
package/dist/codemods/types.d.ts
CHANGED
|
@@ -1,11 +1,21 @@
|
|
|
1
1
|
import type { Edit, Rule, SgNode, SgRoot } from '@ast-grep/napi';
|
|
2
2
|
import type { NapiLang } from '@ast-grep/napi/types/lang.js';
|
|
3
3
|
import type { Kinds, TypesMap } from '@ast-grep/napi/types/staticTypes.js';
|
|
4
|
-
import type {
|
|
4
|
+
import type { types } from '@kamaalio/kamaal';
|
|
5
|
+
export type RunCodemodOkResult = {
|
|
6
|
+
hasChanges: boolean;
|
|
7
|
+
content: string;
|
|
8
|
+
fullPath: string;
|
|
9
|
+
root: string;
|
|
10
|
+
};
|
|
5
11
|
export type Codemod = {
|
|
6
12
|
name: string;
|
|
7
13
|
languages: Set<NapiLang> | Array<NapiLang>;
|
|
8
|
-
transformer: (content: string, filename?: Optional<string>) => Promise<string>;
|
|
14
|
+
transformer: (content: string, filename?: types.Optional<string>) => Promise<string>;
|
|
15
|
+
postTransform?: (rootPath: {
|
|
16
|
+
root: string;
|
|
17
|
+
results: Array<RunCodemodOkResult>;
|
|
18
|
+
}) => Promise<void>;
|
|
9
19
|
};
|
|
10
20
|
export type ModificationsReport = {
|
|
11
21
|
changesApplied: number;
|
|
@@ -14,10 +24,10 @@ export type Modifications = {
|
|
|
14
24
|
ast: SgRoot<TypesMap>;
|
|
15
25
|
report: ModificationsReport;
|
|
16
26
|
lang: NapiLang;
|
|
17
|
-
filename: Optional<string>;
|
|
27
|
+
filename: types.Optional<string>;
|
|
18
28
|
history: Array<SgRoot<TypesMap>>;
|
|
19
29
|
};
|
|
20
30
|
export type FindAndReplaceConfig = {
|
|
21
31
|
rule: Rule<TypesMap>;
|
|
22
|
-
transformer: ((node: SgNode<TypesMap, Kinds<TypesMap>>, rule: Rule<TypesMap>) => Optional<Edit | string> | Array<Edit | string>) | string;
|
|
32
|
+
transformer: ((node: SgNode<TypesMap, Kinds<TypesMap>>, rule: Rule<TypesMap>) => types.Optional<Edit | string> | Array<Edit | string>) | string;
|
|
23
33
|
};
|
package/dist/codemods/utils.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { type Edit, type SgRoot, type SgNode } from '@ast-grep/napi';
|
|
|
3
3
|
import type { Kinds, TypesMap } from '@ast-grep/napi/types/staticTypes.js';
|
|
4
4
|
import type { NapiLang } from '@ast-grep/napi/types/lang.js';
|
|
5
5
|
import { type types } from '@kamaalio/kamaal';
|
|
6
|
-
import type { Codemod, FindAndReplaceConfig, Modifications } from './types.js';
|
|
6
|
+
import type { Codemod, FindAndReplaceConfig, Modifications, RunCodemodOkResult } from './types.js';
|
|
7
7
|
type RunCodemodHooks<C extends Codemod> = {
|
|
8
8
|
targetFiltering?: (filepath: string, codemod: C) => boolean;
|
|
9
9
|
preCodemodRun?: (codemod: C) => Promise<void>;
|
|
@@ -13,15 +13,11 @@ type RunCodemodOptions<C extends Codemod> = {
|
|
|
13
13
|
hooks?: RunCodemodHooks<C>;
|
|
14
14
|
log?: boolean;
|
|
15
15
|
dry?: boolean;
|
|
16
|
+
rootPaths?: Array<string>;
|
|
16
17
|
};
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
}, Error>>>>;
|
|
21
|
-
export declare function runCodemod<C extends Codemod>(codemod: C, transformationPath: string, options?: RunCodemodOptions<C>): Promise<Array<Result<{
|
|
22
|
-
hasChanges: boolean;
|
|
23
|
-
content: string;
|
|
24
|
-
}, Error>>>;
|
|
18
|
+
type RunCodemodResult = Result<RunCodemodOkResult, Error>;
|
|
19
|
+
export declare function runCodemods<C extends Codemod>(codemods: Array<C>, transformationPath: string, options?: RunCodemodOptions<C>): Promise<Record<string, Array<RunCodemodResult>>>;
|
|
20
|
+
export declare function runCodemod<C extends Codemod>(codemod: C, transformationPath: string, options?: RunCodemodOptions<C>): Promise<Array<RunCodemodResult>>;
|
|
25
21
|
export declare function traverseUp(node: SgNode<TypesMap, Kinds<TypesMap>>, until: (node: SgNode<TypesMap, Kinds<TypesMap>>) => boolean): types.Optional<SgNode<TypesMap, Kinds<TypesMap>>>;
|
|
26
22
|
export declare function findAndReplaceConfigModifications(modifications: Modifications, config: Array<FindAndReplaceConfig>): Promise<Modifications>;
|
|
27
23
|
export declare function findAndReplaceConfig(content: SgRoot<TypesMap>, lang: NapiLang, config: Array<FindAndReplaceConfig>): Promise<string>;
|
package/dist/index.cjs
CHANGED
|
@@ -83,13 +83,26 @@ function getCollectionCount(collection) {
|
|
|
83
83
|
function collectionIsEmpty(collection) {
|
|
84
84
|
return 0 === getCollectionCount(collection);
|
|
85
85
|
}
|
|
86
|
+
function groupBy(array, key) {
|
|
87
|
+
const arrayCopy = [
|
|
88
|
+
...array
|
|
89
|
+
];
|
|
90
|
+
return arrayCopy.reduce((acc, current)=>{
|
|
91
|
+
const keyValue = String(current[key]);
|
|
92
|
+
if (null == acc[keyValue]) acc[keyValue] = [
|
|
93
|
+
current
|
|
94
|
+
];
|
|
95
|
+
else acc[keyValue].push(current);
|
|
96
|
+
return acc;
|
|
97
|
+
}, {});
|
|
98
|
+
}
|
|
86
99
|
async function runCodemods(codemods, transformationPath, options) {
|
|
87
100
|
const results = {};
|
|
88
101
|
for (const codemod of codemods)results[codemod.name] = await runCodemod(codemod, transformationPath, options);
|
|
89
102
|
return results;
|
|
90
103
|
}
|
|
91
104
|
async function runCodemod(codemod, transformationPath, options) {
|
|
92
|
-
const { hooks, log: enableLogging, dry: runInDryMode } = defaultedOptions(options);
|
|
105
|
+
const { hooks, log: enableLogging, dry: runInDryMode, rootPaths } = defaultedOptions(options);
|
|
93
106
|
await hooks.preCodemodRun(codemod);
|
|
94
107
|
const globItems = await external_fast_glob_default().glob([
|
|
95
108
|
'**/*'
|
|
@@ -107,7 +120,7 @@ async function runCodemod(codemod, transformationPath, options) {
|
|
|
107
120
|
});
|
|
108
121
|
if (0 === targets.length) return [];
|
|
109
122
|
if (enableLogging) console.log(`\u{1F9C9} '${codemod.name}' targeting ${targets.length} ${1 === targets.length ? 'file' : 'files'} to transform, chill and grab some mat\xe9`);
|
|
110
|
-
|
|
123
|
+
const results = await Promise.all(targets.map(async (filepath)=>{
|
|
111
124
|
const fullPath = external_node_path_default().join(transformationPath, filepath);
|
|
112
125
|
try {
|
|
113
126
|
const content = await promises_default().readFile(fullPath, {
|
|
@@ -124,13 +137,26 @@ async function runCodemod(codemod, transformationPath, options) {
|
|
|
124
137
|
}
|
|
125
138
|
return (0, external_neverthrow_namespaceObject.ok)({
|
|
126
139
|
hasChanges,
|
|
127
|
-
content: modifiedContent
|
|
140
|
+
content: modifiedContent,
|
|
141
|
+
fullPath,
|
|
142
|
+
root: filepath.split('/')[0]
|
|
128
143
|
});
|
|
129
144
|
} catch (error) {
|
|
130
145
|
if (enableLogging) console.error(`\u{274C} '${codemod.name}' failed to parse file`, filepath, error);
|
|
131
146
|
return (0, external_neverthrow_namespaceObject.err)(error);
|
|
132
147
|
}
|
|
133
148
|
}));
|
|
149
|
+
const successes = kamaal_namespaceObject.arrays.compactMap(results, (result)=>{
|
|
150
|
+
if (result.isErr()) return null;
|
|
151
|
+
return result.value;
|
|
152
|
+
});
|
|
153
|
+
const successesGroupedByRoot = groupBy(successes, 'root');
|
|
154
|
+
const rootPathsWithResults = rootPaths.map((root)=>({
|
|
155
|
+
root,
|
|
156
|
+
results: successesGroupedByRoot[root] ?? []
|
|
157
|
+
}));
|
|
158
|
+
await Promise.all(rootPathsWithResults.map((r)=>(codemod.postTransform ?? (async ()=>{}))(r)));
|
|
159
|
+
return results;
|
|
134
160
|
}
|
|
135
161
|
function traverseUp(node, until) {
|
|
136
162
|
let current = node.parent();
|
|
@@ -262,7 +288,8 @@ function defaultedOptions(options) {
|
|
|
262
288
|
return {
|
|
263
289
|
hooks: defaultedHooks(options?.hooks),
|
|
264
290
|
log: options?.log ?? true,
|
|
265
|
-
dry: options?.dry ?? false
|
|
291
|
+
dry: options?.dry ?? false,
|
|
292
|
+
rootPaths: options?.rootPaths ?? []
|
|
266
293
|
};
|
|
267
294
|
}
|
|
268
295
|
function defaultedHooks(hooks) {
|
package/dist/index.js
CHANGED
|
@@ -36,13 +36,26 @@ function getCollectionCount(collection) {
|
|
|
36
36
|
function collectionIsEmpty(collection) {
|
|
37
37
|
return 0 === getCollectionCount(collection);
|
|
38
38
|
}
|
|
39
|
+
function groupBy(array, key) {
|
|
40
|
+
const arrayCopy = [
|
|
41
|
+
...array
|
|
42
|
+
];
|
|
43
|
+
return arrayCopy.reduce((acc, current)=>{
|
|
44
|
+
const keyValue = String(current[key]);
|
|
45
|
+
if (null == acc[keyValue]) acc[keyValue] = [
|
|
46
|
+
current
|
|
47
|
+
];
|
|
48
|
+
else acc[keyValue].push(current);
|
|
49
|
+
return acc;
|
|
50
|
+
}, {});
|
|
51
|
+
}
|
|
39
52
|
async function runCodemods(codemods, transformationPath, options) {
|
|
40
53
|
const results = {};
|
|
41
54
|
for (const codemod of codemods)results[codemod.name] = await runCodemod(codemod, transformationPath, options);
|
|
42
55
|
return results;
|
|
43
56
|
}
|
|
44
57
|
async function runCodemod(codemod, transformationPath, options) {
|
|
45
|
-
const { hooks, log: enableLogging, dry: runInDryMode } = defaultedOptions(options);
|
|
58
|
+
const { hooks, log: enableLogging, dry: runInDryMode, rootPaths } = defaultedOptions(options);
|
|
46
59
|
await hooks.preCodemodRun(codemod);
|
|
47
60
|
const globItems = await fast_glob.glob([
|
|
48
61
|
'**/*'
|
|
@@ -60,7 +73,7 @@ async function runCodemod(codemod, transformationPath, options) {
|
|
|
60
73
|
});
|
|
61
74
|
if (0 === targets.length) return [];
|
|
62
75
|
if (enableLogging) console.log(`\u{1F9C9} '${codemod.name}' targeting ${targets.length} ${1 === targets.length ? 'file' : 'files'} to transform, chill and grab some mat\xe9`);
|
|
63
|
-
|
|
76
|
+
const results = await Promise.all(targets.map(async (filepath)=>{
|
|
64
77
|
const fullPath = node_path.join(transformationPath, filepath);
|
|
65
78
|
try {
|
|
66
79
|
const content = await promises.readFile(fullPath, {
|
|
@@ -77,13 +90,26 @@ async function runCodemod(codemod, transformationPath, options) {
|
|
|
77
90
|
}
|
|
78
91
|
return ok({
|
|
79
92
|
hasChanges,
|
|
80
|
-
content: modifiedContent
|
|
93
|
+
content: modifiedContent,
|
|
94
|
+
fullPath,
|
|
95
|
+
root: filepath.split('/')[0]
|
|
81
96
|
});
|
|
82
97
|
} catch (error) {
|
|
83
98
|
if (enableLogging) console.error(`\u{274C} '${codemod.name}' failed to parse file`, filepath, error);
|
|
84
99
|
return err(error);
|
|
85
100
|
}
|
|
86
101
|
}));
|
|
102
|
+
const successes = arrays.compactMap(results, (result)=>{
|
|
103
|
+
if (result.isErr()) return null;
|
|
104
|
+
return result.value;
|
|
105
|
+
});
|
|
106
|
+
const successesGroupedByRoot = groupBy(successes, 'root');
|
|
107
|
+
const rootPathsWithResults = rootPaths.map((root)=>({
|
|
108
|
+
root,
|
|
109
|
+
results: successesGroupedByRoot[root] ?? []
|
|
110
|
+
}));
|
|
111
|
+
await Promise.all(rootPathsWithResults.map((r)=>(codemod.postTransform ?? (async ()=>{}))(r)));
|
|
112
|
+
return results;
|
|
87
113
|
}
|
|
88
114
|
function traverseUp(node, until) {
|
|
89
115
|
let current = node.parent();
|
|
@@ -215,7 +241,8 @@ function defaultedOptions(options) {
|
|
|
215
241
|
return {
|
|
216
242
|
hooks: defaultedHooks(options?.hooks),
|
|
217
243
|
log: options?.log ?? true,
|
|
218
|
-
dry: options?.dry ?? false
|
|
244
|
+
dry: options?.dry ?? false,
|
|
245
|
+
rootPaths: options?.rootPaths ?? []
|
|
219
246
|
};
|
|
220
247
|
}
|
|
221
248
|
function defaultedHooks(hooks) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function groupBy<T, K extends keyof T>(array: Array<T>, key: K): Record<string, Array<T>>;
|