redlint 3.19.1 → 3.21.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/ChangeLog +11 -0
- package/bin/redlint.js +18 -1
- package/lib/choose.js +2 -0
- package/lib/edit/README.md +3 -0
- package/lib/edit/edit.js +47 -0
- package/lib/edit/read-directory/get-filenames/index.js +45 -0
- package/lib/edit/read-directory/index.js +27 -0
- package/lib/edit/rename-files/index.js +40 -0
- package/lib/edit/rename-files/rename-files-plugin/index.js +80 -0
- package/lib/edit/write-tmp-file.js +31 -0
- package/lib/lint/lint.js +3 -5
- package/lib/menu.js +2 -0
- package/package.json +1 -1
package/ChangeLog
CHANGED
package/bin/redlint.js
CHANGED
|
@@ -28,6 +28,7 @@ import {convert} from '../lib/convert/convert.js';
|
|
|
28
28
|
import {masterConvert} from '../lib/convert/master.js';
|
|
29
29
|
import {askFilename} from '../lib/dialog.js';
|
|
30
30
|
import {masterRename} from '../lib/rename/master.js';
|
|
31
|
+
import {edit} from '../lib/edit/edit.js';
|
|
31
32
|
import {
|
|
32
33
|
isScan,
|
|
33
34
|
isScanDebug,
|
|
@@ -52,6 +53,7 @@ import {
|
|
|
52
53
|
isExit,
|
|
53
54
|
isBundleDebug,
|
|
54
55
|
isConvertRCToFlat,
|
|
56
|
+
isEdit,
|
|
55
57
|
} from '../lib/menu.js';
|
|
56
58
|
|
|
57
59
|
const {log} = console;
|
|
@@ -59,7 +61,7 @@ const {exit} = process;
|
|
|
59
61
|
|
|
60
62
|
const {stringify} = JSON;
|
|
61
63
|
|
|
62
|
-
const [arg] = process.argv.slice(2);
|
|
64
|
+
const [arg, ...argOptions] = process.argv.slice(2);
|
|
63
65
|
let header = true;
|
|
64
66
|
|
|
65
67
|
await uiLoop(arg);
|
|
@@ -126,6 +128,21 @@ async function uiLoop(arg) {
|
|
|
126
128
|
|
|
127
129
|
const filesystem = lintJSON(stringify(result));
|
|
128
130
|
|
|
131
|
+
if (isEdit(arg)) {
|
|
132
|
+
const spinner = ora(`🪶edit filesystem`).start();
|
|
133
|
+
const args = argOptions.join('');
|
|
134
|
+
const recursive = /-r|--recursive/.test(args);
|
|
135
|
+
const full = /-f|--full/.test(args);
|
|
136
|
+
|
|
137
|
+
spinner.succeed();
|
|
138
|
+
return edit(filesystem, {
|
|
139
|
+
dir: CWD,
|
|
140
|
+
type: 'rename',
|
|
141
|
+
full,
|
|
142
|
+
recursive,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
129
146
|
if (isConvertChosen(arg)) {
|
|
130
147
|
let filename = '.eslintrc.json';
|
|
131
148
|
|
package/lib/choose.js
CHANGED
package/lib/edit/edit.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import process from 'node:process';
|
|
2
|
+
import {execSync} from 'node:child_process';
|
|
3
|
+
import {readFileSync} from 'node:fs';
|
|
4
|
+
import {readDirectory} from './read-directory/index.js';
|
|
5
|
+
import {writeTmpFile as _writeTmpFile} from './write-tmp-file.js';
|
|
6
|
+
import {renameFiles as _renameFiles} from './rename-files/index.js';
|
|
7
|
+
|
|
8
|
+
export const edit = (filesystem, {dir, recursive, full}, overrides = {}) => {
|
|
9
|
+
const {
|
|
10
|
+
execute = execSync,
|
|
11
|
+
readFileContent = readFileSync,
|
|
12
|
+
writeTmpFile = _writeTmpFile,
|
|
13
|
+
renameFiles = _renameFiles,
|
|
14
|
+
env = process.env,
|
|
15
|
+
} = overrides;
|
|
16
|
+
|
|
17
|
+
const {EDITOR} = env;
|
|
18
|
+
|
|
19
|
+
const names = readDirectory(filesystem, {
|
|
20
|
+
dir,
|
|
21
|
+
recursive,
|
|
22
|
+
full,
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const from = names.join('\n');
|
|
26
|
+
const [tmpFile, removeTmpFile] = writeTmpFile(from);
|
|
27
|
+
|
|
28
|
+
const editor = EDITOR || 'vim';
|
|
29
|
+
execute(`${editor} ${tmpFile}`, {
|
|
30
|
+
stdio: [
|
|
31
|
+
0,
|
|
32
|
+
1,
|
|
33
|
+
2,
|
|
34
|
+
'pipe',
|
|
35
|
+
],
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const to = readFileContent(tmpFile, 'utf8');
|
|
39
|
+
const newNames = to.split('\n');
|
|
40
|
+
|
|
41
|
+
removeTmpFile();
|
|
42
|
+
renameFiles(filesystem, {
|
|
43
|
+
dir,
|
|
44
|
+
from: names,
|
|
45
|
+
to: newNames,
|
|
46
|
+
});
|
|
47
|
+
};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import {basename, dirname} from 'node:path';
|
|
2
|
+
import {operator} from 'putout';
|
|
3
|
+
|
|
4
|
+
const {getFilename} = operator;
|
|
5
|
+
|
|
6
|
+
export const report = (path, {name}) => name;
|
|
7
|
+
export const fix = () => {};
|
|
8
|
+
export const scan = (path, {push, trackFile, options}) => {
|
|
9
|
+
const {
|
|
10
|
+
dir = '/',
|
|
11
|
+
full,
|
|
12
|
+
recursive,
|
|
13
|
+
} = options;
|
|
14
|
+
|
|
15
|
+
for (const file of trackFile(path, '*')) {
|
|
16
|
+
const path = getFilename(file);
|
|
17
|
+
const currentDir = dirname(path);
|
|
18
|
+
|
|
19
|
+
if (dir === path)
|
|
20
|
+
continue;
|
|
21
|
+
|
|
22
|
+
if (!recursive && currentDir !== dir)
|
|
23
|
+
continue;
|
|
24
|
+
|
|
25
|
+
if (!full && recursive) {
|
|
26
|
+
const name = path
|
|
27
|
+
.replace(dir, '')
|
|
28
|
+
.replace(/^\//, '');
|
|
29
|
+
|
|
30
|
+
if (!name)
|
|
31
|
+
continue;
|
|
32
|
+
|
|
33
|
+
push(file, {
|
|
34
|
+
name,
|
|
35
|
+
});
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const name = full ? path : basename(path);
|
|
40
|
+
|
|
41
|
+
push(file, {
|
|
42
|
+
name,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import {parse, transform} from 'putout';
|
|
2
|
+
import {__filesystem, toJS} from '@putout/operator-json';
|
|
3
|
+
import * as getFileNames from './get-filenames/index.js';
|
|
4
|
+
|
|
5
|
+
const getMessage = ({message}) => message;
|
|
6
|
+
|
|
7
|
+
export const readDirectory = (filesystem, {dir, recursive, full}) => {
|
|
8
|
+
const source = toJS(filesystem, __filesystem);
|
|
9
|
+
const ast = parse(source);
|
|
10
|
+
|
|
11
|
+
const places = transform(ast, filesystem, {
|
|
12
|
+
fix: true,
|
|
13
|
+
fixCount: 1,
|
|
14
|
+
rules: {
|
|
15
|
+
'get-filenames': ['on', {
|
|
16
|
+
dir,
|
|
17
|
+
full,
|
|
18
|
+
recursive,
|
|
19
|
+
}],
|
|
20
|
+
},
|
|
21
|
+
plugins: [
|
|
22
|
+
['get-filenames', getFileNames],
|
|
23
|
+
],
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
return places.map(getMessage);
|
|
27
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import {
|
|
2
|
+
parse,
|
|
3
|
+
print,
|
|
4
|
+
transform,
|
|
5
|
+
} from 'putout';
|
|
6
|
+
import {
|
|
7
|
+
branch as originalBranch,
|
|
8
|
+
merge as originalMerge,
|
|
9
|
+
} from '@putout/processor-filesystem';
|
|
10
|
+
import * as renameFilesPlugin from './rename-files-plugin/index.js';
|
|
11
|
+
|
|
12
|
+
export const renameFiles = (filesystem, {dir, from, to}, overrides = {}) => {
|
|
13
|
+
const {
|
|
14
|
+
branch = originalBranch,
|
|
15
|
+
merge = originalMerge,
|
|
16
|
+
} = overrides;
|
|
17
|
+
|
|
18
|
+
const [{source}] = branch(filesystem);
|
|
19
|
+
|
|
20
|
+
const ast = parse(source);
|
|
21
|
+
|
|
22
|
+
transform(ast, filesystem, {
|
|
23
|
+
fix: true,
|
|
24
|
+
fixCount: 1,
|
|
25
|
+
rules: {
|
|
26
|
+
'rename-files': ['on', {
|
|
27
|
+
dir,
|
|
28
|
+
from,
|
|
29
|
+
to,
|
|
30
|
+
}],
|
|
31
|
+
},
|
|
32
|
+
plugins: [
|
|
33
|
+
['rename-files', renameFilesPlugin],
|
|
34
|
+
],
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const code = print(ast);
|
|
38
|
+
|
|
39
|
+
return merge(filesystem, [code]);
|
|
40
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {join} from 'node:path';
|
|
2
|
+
import {operator} from 'putout';
|
|
3
|
+
|
|
4
|
+
const {renameFile} = operator;
|
|
5
|
+
|
|
6
|
+
export const report = (filePath, {from, to}) => `Rename '${from}' to '${to}'`;
|
|
7
|
+
|
|
8
|
+
export const fix = (filePath, {to}) => {
|
|
9
|
+
renameFile(filePath, to);
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const addFromTo = (namesFrom, namesTo) => (a, i) => [
|
|
13
|
+
namesFrom[i],
|
|
14
|
+
namesTo[i],
|
|
15
|
+
a,
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
export const scan = (path, {push, trackFile, options}) => {
|
|
19
|
+
const {
|
|
20
|
+
from = [],
|
|
21
|
+
to = [],
|
|
22
|
+
dir = '/',
|
|
23
|
+
} = options;
|
|
24
|
+
|
|
25
|
+
if (isEqual(from, to))
|
|
26
|
+
return;
|
|
27
|
+
|
|
28
|
+
const [fullNames, fromNames, toNames] = getRenamedFiles(dir, from, to);
|
|
29
|
+
const convertToTuple = addFromTo(fromNames, toNames);
|
|
30
|
+
const trackFileIterator = trackFile(path, fullNames).map(convertToTuple);
|
|
31
|
+
|
|
32
|
+
for (const [from, to, currentFile] of trackFileIterator) {
|
|
33
|
+
push(currentFile, {
|
|
34
|
+
from,
|
|
35
|
+
to,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
function getRenamedFiles(dir, a, b) {
|
|
41
|
+
const from = [];
|
|
42
|
+
const to = [];
|
|
43
|
+
const full = [];
|
|
44
|
+
const n = a.length;
|
|
45
|
+
let i = -1;
|
|
46
|
+
|
|
47
|
+
while (++i < n) {
|
|
48
|
+
if (a[i] !== b[i]) {
|
|
49
|
+
const currentFrom = a[i];
|
|
50
|
+
const currentTo = b[i];
|
|
51
|
+
|
|
52
|
+
full.push(join(
|
|
53
|
+
dir,
|
|
54
|
+
currentFrom,
|
|
55
|
+
));
|
|
56
|
+
from.push(currentFrom);
|
|
57
|
+
to.push(currentTo);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return [
|
|
62
|
+
full,
|
|
63
|
+
from,
|
|
64
|
+
to,
|
|
65
|
+
];
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function isEqual(a, b) {
|
|
69
|
+
if (a.length !== b.length)
|
|
70
|
+
return false;
|
|
71
|
+
|
|
72
|
+
let i = a.length;
|
|
73
|
+
|
|
74
|
+
while (--i >= 0) {
|
|
75
|
+
if (a[i] !== b[i])
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return true;
|
|
80
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {join} from 'node:path';
|
|
2
|
+
import {tmpdir} from 'node:os';
|
|
3
|
+
import {
|
|
4
|
+
mkdtempSync,
|
|
5
|
+
writeFileSync,
|
|
6
|
+
rmSync,
|
|
7
|
+
} from 'node:fs';
|
|
8
|
+
|
|
9
|
+
const createRemoveTmpFile = (tmpDir, removeDirectory) => () => {
|
|
10
|
+
removeDirectory(tmpDir, {
|
|
11
|
+
recursive: true,
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export const writeTmpFile = (content, overrides = {}) => {
|
|
16
|
+
const {
|
|
17
|
+
createTmpDirectory = mkdtempSync,
|
|
18
|
+
writeFileContent = writeFileSync,
|
|
19
|
+
generateTmpName = tmpdir,
|
|
20
|
+
removeDirectory = rmSync,
|
|
21
|
+
} = overrides;
|
|
22
|
+
|
|
23
|
+
const tmpDir = createTmpDirectory(join(generateTmpName(), 'redlint-'));
|
|
24
|
+
const tmpFile = join(tmpDir, 'edit.tmp');
|
|
25
|
+
|
|
26
|
+
writeFileContent(tmpFile, content);
|
|
27
|
+
|
|
28
|
+
const removeTmpFile = createRemoveTmpFile(tmpDir, removeDirectory);
|
|
29
|
+
|
|
30
|
+
return [tmpFile, removeTmpFile];
|
|
31
|
+
};
|
package/lib/lint/lint.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {transformAsync, parse} from 'putout';
|
|
2
2
|
import parseOptions from 'putout/parse-options';
|
|
3
3
|
import {createProgress} from '@putout/engine-runner/progress';
|
|
4
|
-
import {init} from '@putout/operator-filesystem';
|
|
4
|
+
import {deinit, init} from '@putout/operator-filesystem';
|
|
5
5
|
import {toJS, __filesystem} from '@putout/operator-json';
|
|
6
6
|
import filesystemCLI from '@putout/cli-filesystem';
|
|
7
7
|
|
|
@@ -12,8 +12,7 @@ export const lint = async (filesystem, overrides = {}) => {
|
|
|
12
12
|
progress = createProgress(),
|
|
13
13
|
} = overrides;
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
init(filesystemCLI);
|
|
15
|
+
!test && init(filesystemCLI);
|
|
17
16
|
|
|
18
17
|
const source = toJS(filesystem, __filesystem);
|
|
19
18
|
|
|
@@ -30,8 +29,7 @@ export const lint = async (filesystem, overrides = {}) => {
|
|
|
30
29
|
progress,
|
|
31
30
|
});
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
init(filesystemCLI);
|
|
32
|
+
!test && deinit(filesystemCLI);
|
|
35
33
|
|
|
36
34
|
return places;
|
|
37
35
|
};
|
package/lib/menu.js
CHANGED
|
@@ -3,6 +3,7 @@ export const SCAN_DEBUG = '🔍 scan: debug';
|
|
|
3
3
|
export const BUNDLE = 'bundle';
|
|
4
4
|
export const BUNDLE_DEBUG = '🧺 bundle';
|
|
5
5
|
export const FIX = '🔨 fix';
|
|
6
|
+
export const EDIT = '🪶 edit';
|
|
6
7
|
export const FIX_DEBUG = '🔨 fix: debug';
|
|
7
8
|
export const PACK = '🔬 pack';
|
|
8
9
|
export const PACK_DEBUG = '🔬 pack: debug';
|
|
@@ -47,6 +48,7 @@ export const isBack = (a) => a === BACK || a === 'back';
|
|
|
47
48
|
export const isExit = (a) => a === EXIT || a === 'exit';
|
|
48
49
|
export const isConvert = (a) => a === CONVERT || a === 'convert';
|
|
49
50
|
export const isRename = (a) => a === RENAME || a === 'rename';
|
|
51
|
+
export const isEdit = (a) => a === EDIT || a === 'edit';
|
|
50
52
|
export const isConvertChosen = (a) => {
|
|
51
53
|
return [
|
|
52
54
|
CONVERT_JSON_TO_JS,
|