@yaohaixiao/renames.js 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/.editorconfig +9 -0
  2. package/.husky/commit-msg +4 -0
  3. package/.husky/pre-commit +3 -0
  4. package/.prettierignore +28 -0
  5. package/.prettierrc.js +41 -0
  6. package/LICENSE +21 -0
  7. package/README.md +239 -0
  8. package/bin/renames.js +415 -0
  9. package/commitlint.config.js +42 -0
  10. package/config/default.config.json +20 -0
  11. package/eslint.config.js +196 -0
  12. package/index.js +14 -0
  13. package/jest.config.js +51 -0
  14. package/jsconfig.json +9 -0
  15. package/lib/batch-rename.js +190 -0
  16. package/lib/create-config.js +265 -0
  17. package/lib/generate-filename.js +182 -0
  18. package/lib/read-list.js +87 -0
  19. package/lib/utils/get-basename.js +18 -0
  20. package/lib/utils/get-extension.js +20 -0
  21. package/lib/utils/is-empty-object.js +23 -0
  22. package/lib/utils/is-file-exists.js +26 -0
  23. package/lib/utils/is-function.js +29 -0
  24. package/lib/utils/pad-start.js +31 -0
  25. package/lib/utils/pad-zero.js +24 -0
  26. package/lib/utils/read-dir.js +73 -0
  27. package/lib/utils/read-file.js +56 -0
  28. package/lib/utils/remove-file.js +60 -0
  29. package/lib/utils/rename.js +74 -0
  30. package/lib/utils/replace-index-chapter.js +53 -0
  31. package/lib/utils/show-warning-log.js +20 -0
  32. package/lib/utils/sort-files.js +157 -0
  33. package/lib/utils/strip-non-digit.js +16 -0
  34. package/lib/utils/terminal-link.js +16 -0
  35. package/lib/utils/to-index-chapter.js +19 -0
  36. package/lib/utils/write-file.js +35 -0
  37. package/package.json +114 -0
  38. package/tests/batch-rename.spec.js +123 -0
  39. package/tests/get-basename.spec.js +23 -0
  40. package/tests/get-extension.spec.js +24 -0
  41. package/tests/is-empty-object.spec.js +73 -0
  42. package/tests/is-file-exsits.spec.js +17 -0
  43. package/tests/is-function.spec.js +63 -0
  44. package/tests/pad-start.spec.js +27 -0
  45. package/tests/pad-zero.spec.js +15 -0
  46. package/tests/read-dir.spec.js +42 -0
  47. package/tests/read-file.spec.js +52 -0
  48. package/tests/read-list.spec.js +91 -0
  49. package/tests/rename.spec.js +50 -0
  50. package/tests/replace-index-chapter.spec.js +40 -0
  51. package/tests/sort-files.spec.js +221 -0
  52. package/tests/strip-non-digit.spec.js +15 -0
  53. package/tests/to-index-chapter.spec.js +31 -0
  54. package/tests/write-file.spec.js +34 -0
@@ -0,0 +1,27 @@
1
+ import padStart from '@/lib/utils/pad-start.js';
2
+
3
+ describe('padStart() 方法:', () => {
4
+ it(`padStart(1),返回:' 1'`, () => {
5
+ expect(padStart(1)).toEqual(' 1');
6
+ });
7
+
8
+ it(`padStart('1', '0'),返回:'01'`, () => {
9
+ expect(padStart('1', '0')).toEqual('01');
10
+ });
11
+
12
+ it(`padStart(1, '0'),返回:'01'`, () => {
13
+ expect(padStart(1, '0')).toEqual('01');
14
+ });
15
+
16
+ it(`padStart(1, 3, '0'),返回:'001'`, () => {
17
+ expect(padStart(1, 3, '0')).toEqual('001');
18
+ });
19
+
20
+ it(`padStart(1, 3, ''),返回:'1'`, () => {
21
+ expect(padStart(1, 3, '')).toEqual('1');
22
+ });
23
+
24
+ it(`padStart(128, 2, '0'),返回:'128'`, () => {
25
+ expect(padStart(128, 2, '0')).toEqual('128');
26
+ });
27
+ });
@@ -0,0 +1,15 @@
1
+ import padZero from '@/lib/utils/pad-zero.js';
2
+
3
+ describe('padZero() 方法:', () => {
4
+ it(`padZero(1),返回:'01'`, () => {
5
+ expect(padZero(1)).toEqual('01');
6
+ });
7
+
8
+ it(`padZero("1"),返回:'01'`, () => {
9
+ expect(padZero('1')).toEqual('01');
10
+ });
11
+
12
+ it(`padZero(1, 0),返回:'1'`, () => {
13
+ expect(padZero(1, 0)).toEqual('1');
14
+ });
15
+ });
@@ -0,0 +1,42 @@
1
+ import path from 'node:path';
2
+
3
+ import readDir from '@/lib/utils/read-dir.js';
4
+
5
+ const { resolve } = path;
6
+
7
+ const TESTS_DIR = './tests';
8
+ const ABSOLUTE_PATH = resolve(process.cwd(), TESTS_DIR);
9
+ const FILE_PATH = resolve(process.cwd(), `${TESTS_DIR}/sort-files.spec.js`);
10
+
11
+ const NOT_EXISTS_PATH = resolve(process.cwd(), './demo/case');
12
+
13
+ describe(`readDir() 方法:`, () => {
14
+ it(`readDir('${ABSOLUTE_PATH}', 'utf8', (files) => {console.log(files.length)}),返回:true`, () => {
15
+ const result = readDir(ABSOLUTE_PATH, 'utf8', (files) => {
16
+ console.log(files.length);
17
+ });
18
+ expect(result.length > 0).toBe(true);
19
+ });
20
+
21
+ it(`readDir('${ABSOLUTE_PATH}', { encoding: 'md' }),返回:true`, () => {
22
+ const result = readDir(ABSOLUTE_PATH, { encoding: 'md' });
23
+ expect(result.length > 0).toBe(true);
24
+ });
25
+
26
+ it(`readDir('${ABSOLUTE_PATH}', (files) => {console.log(files.length)}),返回:true`, () => {
27
+ const result = readDir(ABSOLUTE_PATH, (files) => {
28
+ console.log(files.length);
29
+ });
30
+ expect(result.length > 0).toBe(true);
31
+ });
32
+
33
+ it(`readDir('${FILE_PATH}'),读取文件,获取的文件列表长度,返回:0`, () => {
34
+ const result = readDir(FILE_PATH);
35
+ expect(result.length).toEqual(0);
36
+ });
37
+
38
+ it(`readDir('${NOT_EXISTS_PATH}'),读取不存在的文件加路径,获取的文件列表长度,返回:0`, () => {
39
+ const result = readDir(NOT_EXISTS_PATH);
40
+ expect(result.length).toEqual(0);
41
+ });
42
+ });
@@ -0,0 +1,52 @@
1
+ import path from 'node:path';
2
+
3
+ import writeFile from '@/lib/utils/write-file.js';
4
+ import readFile from '@/lib/utils/read-file.js';
5
+ import removeFile from '@/lib/utils/remove-file.js';
6
+
7
+ const { resolve, dirname } = path;
8
+
9
+ const FILE_NAME = 'default.config.json';
10
+ const TEMPLATE_DIR = './tests/read';
11
+ const ABSOLUTE_PATH = resolve(process.cwd(), `${TEMPLATE_DIR}/${FILE_NAME}`);
12
+ const CONTENT_FOLDER = '{"folderPath": "./tests"}';
13
+ const OPTIONS = { encoding: 'utf8' };
14
+
15
+ const afterRead = () => {
16
+ console.log('已经读取数据完成!');
17
+ };
18
+
19
+ describe(`readFile() 方法:`, () => {
20
+ beforeEach(() => {
21
+ writeFile(ABSOLUTE_PATH, CONTENT_FOLDER, () => {
22
+ console.log('已写入完成!');
23
+ });
24
+ });
25
+
26
+ afterEach(() => {
27
+ // 删除临时文件,确保单测代码干净
28
+ removeFile(dirname(ABSOLUTE_PATH));
29
+ });
30
+
31
+ it(`readFile('${ABSOLUTE_PATH}','utf8'),返回:"${CONTENT_FOLDER}"`, () => {
32
+ const config = readFile(ABSOLUTE_PATH, 'utf8');
33
+ expect(config).toEqual(CONTENT_FOLDER);
34
+ });
35
+
36
+ it(`readFile('${ABSOLUTE_PATH}','${OPTIONS}'),返回:"${CONTENT_FOLDER}"`, () => {
37
+ const config = readFile(ABSOLUTE_PATH, OPTIONS, () => {
38
+ console.log('读取完成!');
39
+ });
40
+ expect(config).toEqual(CONTENT_FOLDER);
41
+ });
42
+
43
+ it(`readFile('${ABSOLUTE_PATH}',${afterRead}),返回:"${CONTENT_FOLDER}"`, () => {
44
+ const config = readFile(ABSOLUTE_PATH, afterRead);
45
+ expect(config).toEqual(CONTENT_FOLDER);
46
+ });
47
+
48
+ it(`readFile('../help.json','utf8'),返回:""`, () => {
49
+ const config = readFile('../help.json', 'utf8');
50
+ expect(config).toEqual('');
51
+ });
52
+ });
@@ -0,0 +1,91 @@
1
+ import path from 'node:path';
2
+ import writeFile from '@/lib/utils/write-file.js';
3
+ import removeFile from '@/lib/utils/remove-file.js';
4
+
5
+ import readList from '@/lib/read-list.js';
6
+
7
+ const { resolve, dirname } = path;
8
+
9
+ const TXT_PATH = resolve('./tests/txt/names.txt');
10
+ const NOT_EXISTS_PATH = resolve('./not_exists.txt');
11
+ const NAMES = '封面-1\n' + '封面-3\n' + '封面-2\n' + '封面-4';
12
+
13
+ const JSON_PATH = resolve('./tests/json/books.json');
14
+ const CHAPTERS = [
15
+ '神秘的龙珠出现!悟空变成了小孩',
16
+ null,
17
+ '我才是主角!小芳踏上宇宙飞行的旅程',
18
+ '超级抢钱!商人的行星伊美加',
19
+ '悟空成了通缉犯',
20
+ '',
21
+ '快看那个强者!保镖莱德奇',
22
+ '好痛啊!当牙医的悟空',
23
+ ];
24
+
25
+ const DRAGON_BOLL = {
26
+ name: '龙珠',
27
+ chapters: CHAPTERS,
28
+ };
29
+
30
+ const JS_PATH = resolve('./tests/strip-non-digit.spec.js');
31
+
32
+ describe('readList() 方法:', () => {
33
+ beforeEach(() => {
34
+ writeFile(TXT_PATH, NAMES);
35
+ });
36
+
37
+ afterEach(() => {
38
+ // 删除临时文件,确保单测代码干净
39
+ removeFile(dirname(TXT_PATH), () => {
40
+ console.log(`${TXT_PATH}已删除!`);
41
+ });
42
+ removeFile(dirname(JSON_PATH), {
43
+ maxRetries: 1,
44
+ });
45
+ });
46
+
47
+ it(`readList('${TXT_PATH}'),检测读取.txt格式文件${TXT_PATH}数据,第1条内容,返回:'封面-1'`, () => {
48
+ const names = readList(TXT_PATH);
49
+ expect(names[0]).toEqual('封面-1');
50
+ });
51
+
52
+ it(`readList('${JSON_PATH}'),检测读取.json格式文件${JSON_PATH}数据,第3条内容,返回:'悟空成了通缉犯'`, () => {
53
+ writeFile(JSON_PATH, JSON.stringify(CHAPTERS));
54
+ const names = readList(JSON_PATH);
55
+
56
+ expect(names.length).toEqual(6);
57
+ expect(names[3]).toEqual('悟空成了通缉犯');
58
+ });
59
+
60
+ it(`readList('${JSON_PATH}', 'chapters'),检测读取.json格式文件${JSON_PATH}数据中的 'chapters' 属性的数据,第3条内容,返回:'悟空成了通缉犯'`, () => {
61
+ writeFile(JSON_PATH, JSON.stringify(DRAGON_BOLL));
62
+ const names = readList(JSON_PATH, 'chapters');
63
+
64
+ expect(names.length).toEqual(6);
65
+ expect(names[3]).toEqual('悟空成了通缉犯');
66
+ });
67
+
68
+ it(`readList('${NOT_EXISTS_PATH}'),检测读取.txt格式文件${NOT_EXISTS_PATH}数据,因为文件不存在,返回:[]`, () => {
69
+ const names = readList(NOT_EXISTS_PATH);
70
+ expect(names.length).toEqual(0);
71
+ });
72
+
73
+ it(`readList('${JS_PATH}'),检测读取.js格式文件${NOT_EXISTS_PATH}数据,因为不支持该格式,返回:[]`, () => {
74
+ const names = readList(JS_PATH);
75
+ expect(names.length).toEqual(0);
76
+ });
77
+
78
+ it(`readList('${JSON_PATH}'),检测读取.json格式文件${JSON_PATH}数据,因为数据不是JSON数组格式,返回:[]`, () => {
79
+ writeFile(JSON_PATH, JSON.stringify(DRAGON_BOLL));
80
+ const names = readList(JSON_PATH);
81
+
82
+ expect(names.length).toEqual(0);
83
+ });
84
+
85
+ it(`readList('${JSON_PATH}', 'name'),检测读取.json格式文件${JSON_PATH}数据中的 'name' 属性的数据,因为数据不是数组格式,返回:[]`, () => {
86
+ writeFile(JSON_PATH, JSON.stringify(DRAGON_BOLL));
87
+ const names = readList(JSON_PATH, 'name');
88
+
89
+ expect(names.length).toEqual(0);
90
+ });
91
+ });
@@ -0,0 +1,50 @@
1
+ import path from 'node:path';
2
+
3
+ import writeFile from '@/lib/utils/write-file.js';
4
+ import removeFile from '@/lib/utils/remove-file.js';
5
+ import isFileExists from '@/lib/utils/is-file-exists.js';
6
+ import rename from '@/lib/utils/rename.js';
7
+
8
+ const { resolve } = path;
9
+
10
+ const TEMPLATE_DIR = './tests/rename';
11
+ const OLD_PATH = resolve(`${TEMPLATE_DIR}/readme.txt`);
12
+ const NEW_PATH = resolve(`${TEMPLATE_DIR}/new-readme.txt`);
13
+ const MD_PATH = resolve(`${TEMPLATE_DIR}/readme.md`);
14
+ const NOT_EXISTS_PATH = resolve('./music.mp3');
15
+
16
+ describe('rename() 方法:', () => {
17
+ beforeEach(() => {
18
+ writeFile(OLD_PATH, '# readme 标题');
19
+ });
20
+
21
+ afterEach(() => {
22
+ // 删除临时文件,确保单测代码干净
23
+ removeFile(resolve(TEMPLATE_DIR));
24
+ });
25
+
26
+ it(`rename('${OLD_PATH}', '${NEW_PATH}'),检测文件${NEW_PATH}是否存在,返回:true`, () => {
27
+ rename(OLD_PATH, NEW_PATH);
28
+ expect(isFileExists(NEW_PATH)).toBe(true);
29
+ });
30
+
31
+ it(`rename('${OLD_PATH}', '${MD_PATH}'),检测文件${MD_PATH}是否存在,返回:true`, () => {
32
+ rename(OLD_PATH, MD_PATH);
33
+ expect(isFileExists(MD_PATH)).toBe(true);
34
+ });
35
+
36
+ it(`rename('${OLD_PATH}', '${MD_PATH}', () => {console.log('重命名完成')}),检测文件${MD_PATH}是否存在,返回:true`, () => {
37
+ rename(OLD_PATH, MD_PATH, () => {
38
+ console.log('重命名完成');
39
+ });
40
+ expect(isFileExists(MD_PATH)).toBe(true);
41
+ });
42
+
43
+ it(`rename('${NOT_EXISTS_PATH}', '${NEW_PATH}'),检测文件${NEW_PATH}是否存在,返回:false`, () => {
44
+ expect(rename(NOT_EXISTS_PATH, NEW_PATH)).toBe(false);
45
+ });
46
+
47
+ it(`rename('${OLD_PATH}', '${OLD_PATH}'),检测文件名不变${NEW_PATH},返回:false`, () => {
48
+ expect(rename(OLD_PATH, OLD_PATH)).toBe(false);
49
+ });
50
+ });
@@ -0,0 +1,40 @@
1
+ import replaceIndexChapter from '@/lib/utils/replace-index-chapter.js';
2
+
3
+ const FILE_NAME = 'S1E1-火影忍者.mp4';
4
+ const chapter = (filename) => {
5
+ const name = filename.replace(/-(.*)/g, '');
6
+ const index = name.replace(/(.*)E/g, '');
7
+ const number = Number(index);
8
+
9
+ return {
10
+ name: `${name}-`,
11
+ index,
12
+ number,
13
+ };
14
+ };
15
+
16
+ describe('replaceIndexChapter() 方法:', () => {
17
+ it(`replaceIndexChapter('${FILE_NAME}'), 返回:'S1E1-火影忍者'`, () => {
18
+ expect(replaceIndexChapter(FILE_NAME)).toBe('S1E1-火影忍者');
19
+ });
20
+
21
+ it(`replaceIndexChapter('${FILE_NAME}', {name: 'S1E1-', index: 1, number: 1}), 返回:'第01集:火影忍者'`, () => {
22
+ expect(
23
+ replaceIndexChapter(FILE_NAME, { name: 'S1E1-', index: '1', number: 1 }),
24
+ ).toBe('第01集:火影忍者');
25
+ });
26
+
27
+ it(`replaceIndexChapter('${FILE_NAME}', {name: 'S1E1-', index: 1, number: 1}, false), 返回:'${FILE_NAME}'`, () => {
28
+ expect(
29
+ replaceIndexChapter(
30
+ FILE_NAME,
31
+ { name: 'S1E1-', index: '1', number: 1 },
32
+ false,
33
+ ),
34
+ ).toBe('第1集:火影忍者');
35
+ });
36
+
37
+ it(`replaceIndexChapter('${FILE_NAME}', ${chapter}), 返回:'第01集:火影忍者'`, () => {
38
+ expect(replaceIndexChapter(FILE_NAME, chapter)).toBe('第01集:火影忍者');
39
+ });
40
+ });
@@ -0,0 +1,221 @@
1
+ import path from 'node:path';
2
+
3
+ import sortFiles from '@/lib/utils/sort-files.js';
4
+ import readDir from '@/lib/utils/read-dir.js';
5
+ import getBasename from '@/lib/utils/get-basename.js';
6
+
7
+ const ORIGIN_FILES = [
8
+ '1.jpg',
9
+ '8.jpg',
10
+ '9.jpg',
11
+ '2.jpg',
12
+ '5.jpg',
13
+ '6.jpg',
14
+ '3.jpg',
15
+ '4.jpg',
16
+ '7.jpg',
17
+ '10.jpg',
18
+ ];
19
+
20
+ const ASC_FILES = [
21
+ '1.jpg',
22
+ '2.jpg',
23
+ '3.jpg',
24
+ '4.jpg',
25
+ '5.jpg',
26
+ '6.jpg',
27
+ '7.jpg',
28
+ '8.jpg',
29
+ '9.jpg',
30
+ '10.jpg',
31
+ ];
32
+
33
+ const DESC_FILES = [
34
+ '10.jpg',
35
+ '9.jpg',
36
+ '8.jpg',
37
+ '7.jpg',
38
+ '6.jpg',
39
+ '5.jpg',
40
+ '4.jpg',
41
+ '3.jpg',
42
+ '2.jpg',
43
+ '1.jpg',
44
+ ];
45
+
46
+ const ORIGIN_BOOKS = [
47
+ 'JavaScript Data Structures and Algorithms.pdf',
48
+ 'Express in Action.epub',
49
+ '凡人修仙传.txt',
50
+ '仙逆.md',
51
+ '菊与刀.docx',
52
+ ];
53
+
54
+ const SORT_BY_BOOKS = [
55
+ 'Express in Action.epub',
56
+ 'JavaScript Data Structures and Algorithms.pdf',
57
+ '仙逆.md',
58
+ '凡人修仙传.txt',
59
+ '菊与刀.docx',
60
+ ];
61
+
62
+ const ASC_BOOKS = [
63
+ '凡人修仙传.txt',
64
+ '菊与刀.docx',
65
+ '仙逆.md',
66
+ 'Express in Action.epub',
67
+ 'JavaScript Data Structures and Algorithms.pdf',
68
+ ];
69
+
70
+ const DESC_BOOKS = [
71
+ 'JavaScript Data Structures and Algorithms.pdf',
72
+ 'Express in Action.epub',
73
+ '仙逆.md',
74
+ '菊与刀.docx',
75
+ '凡人修仙传.txt',
76
+ ];
77
+
78
+ const { resolve } = path;
79
+ const { stringify } = JSON;
80
+ const sortBy = (files) => files.toSorted();
81
+ const TESTS_DIR_PATH = resolve(process.cwd(), './lib/utils');
82
+ const JS_FILES = readDir(TESTS_DIR_PATH);
83
+
84
+ describe('sortFiles() 方法:', () => {
85
+ const customizeSortByOptions = {
86
+ sortBy,
87
+ };
88
+
89
+ it(`sortFiles('${ORIGIN_BOOKS}', null), 返回:'${ASC_BOOKS}'`, () => {
90
+ const sorted = sortFiles(ORIGIN_BOOKS, null);
91
+ expect(sorted).toEqual(ASC_BOOKS);
92
+ });
93
+
94
+ it(`sortFiles('${ORIGIN_BOOKS}'), 返回:'${ASC_BOOKS}'`, () => {
95
+ const sorted = sortFiles(ORIGIN_BOOKS);
96
+ expect(sorted).toEqual(ASC_BOOKS);
97
+ });
98
+
99
+ it(`sortFiles('${ORIGIN_BOOKS}', ${stringify(customizeSortByOptions)}), 自定义排序,返回:'${SORT_BY_BOOKS}'`, () => {
100
+ const sorted = sortFiles(ORIGIN_BOOKS, customizeSortByOptions);
101
+ expect(sorted).toEqual(SORT_BY_BOOKS);
102
+ });
103
+
104
+ const sortByNameDescOptions = {
105
+ sortBy: 'name',
106
+ order: 'desc',
107
+ };
108
+
109
+ it(`sortFiles('${ORIGIN_FILES}', ${stringify(sortByNameDescOptions)}), 按文件名(desc排序),返回:'${stringify(DESC_FILES)}'`, () => {
110
+ const sorted = sortFiles(ORIGIN_FILES, sortByNameDescOptions);
111
+ expect(sorted).toEqual(DESC_FILES);
112
+ });
113
+
114
+ it(`sortFiles('${ORIGIN_BOOKS}', ${stringify(sortByNameDescOptions)}), 按文件名(desc排序),返回:'${stringify(DESC_BOOKS)}'`, () => {
115
+ const sorted = sortFiles(ORIGIN_BOOKS, sortByNameDescOptions);
116
+ expect(sorted).toEqual(DESC_BOOKS);
117
+ });
118
+
119
+ const sortByNameAscOptions = {
120
+ order: 'asc',
121
+ };
122
+
123
+ it(`sortFiles('${ORIGIN_FILES}', ${stringify(sortByNameAscOptions)}), 按文件名(asc排序),返回:'${stringify(ASC_FILES)}'`, () => {
124
+ const sorted = sortFiles(ORIGIN_FILES, sortByNameAscOptions);
125
+ expect(sorted).toEqual(ASC_FILES);
126
+ });
127
+
128
+ const sortBySizeDescOptions = {
129
+ sortBy: 'size',
130
+ order: 'desc',
131
+ dirPath: TESTS_DIR_PATH,
132
+ };
133
+
134
+ it(`sortFiles('${JS_FILES}', '${stringify(sortBySizeDescOptions)}'), 按文件大小(desc排序), 排序后的第1个文件名称,返回:'sort-files'`, () => {
135
+ const sorted = sortFiles(JS_FILES, sortBySizeDescOptions);
136
+
137
+ expect(getBasename(sorted[0])).toEqual('sort-files');
138
+ });
139
+
140
+ const sortBySizeAscOptions = {
141
+ sortBy: 'size',
142
+ order: 'asc',
143
+ dirPath: TESTS_DIR_PATH,
144
+ };
145
+
146
+ it(`sortFiles('${JS_FILES}', '${stringify(sortBySizeAscOptions)}'), 按文件大小(asc排序), 排序后的第1个文件名称,返回:'strip-non-digit'`, () => {
147
+ const sorted = sortFiles(JS_FILES, sortBySizeAscOptions);
148
+
149
+ expect(getBasename(sorted[0])).toEqual('strip-non-digit');
150
+ });
151
+
152
+ const sortByTypeDescOptions = {
153
+ sortBy: 'type',
154
+ order: 'desc',
155
+ };
156
+
157
+ it(`sortFiles('${ORIGIN_BOOKS}', ${stringify(sortByTypeDescOptions)}), 按文件类型(desc排序), 排序后的第1个文件名称,返回:'凡人修仙传.txt'`, () => {
158
+ const sorted = sortFiles(ORIGIN_BOOKS, sortByTypeDescOptions);
159
+
160
+ expect(sorted[0]).toEqual('凡人修仙传.txt');
161
+ });
162
+
163
+ const sortByTypeAscOptions = {
164
+ sortBy: 'type',
165
+ order: 'asc',
166
+ };
167
+
168
+ it(`sortFiles('${ORIGIN_BOOKS}', ${stringify(sortByTypeAscOptions)}), 按文件类型(desc排序), 排序后的第1个文件名称,返回:'菊与刀.docx'`, () => {
169
+ const sorted = sortFiles(ORIGIN_BOOKS, sortByTypeAscOptions);
170
+
171
+ expect(sorted[0]).toEqual('菊与刀.docx');
172
+ });
173
+
174
+ const sortByModifyTimeAscOptions = {
175
+ sortBy: 'modify-time',
176
+ order: 'asc',
177
+ dirPath: TESTS_DIR_PATH,
178
+ };
179
+
180
+ it(`sortFiles('${JS_FILES}', '${stringify(sortByModifyTimeAscOptions)}'), 按文件修改时间(asc排序), 排序后的第1个文件名称,返回:'get-basename'`, () => {
181
+ const sorted = sortFiles(JS_FILES, sortByModifyTimeAscOptions);
182
+
183
+ expect(getBasename(sorted[0])).toEqual('get-basename');
184
+ });
185
+
186
+ const sortByModifyTimeDescOptions = {
187
+ sortBy: 'modify-time',
188
+ order: 'desc',
189
+ dirPath: TESTS_DIR_PATH,
190
+ };
191
+
192
+ it(`sortFiles('${JS_FILES}', '${stringify(sortByModifyTimeDescOptions)}'), 按文件修改时间(asc排序), 排序后的第1个文件名称,返回:'terminal-link'`, () => {
193
+ const sorted = sortFiles(JS_FILES, sortByModifyTimeDescOptions);
194
+
195
+ expect(getBasename(sorted[0])).toEqual('terminal-link');
196
+ });
197
+
198
+ const sortByBirthtimeAscOptions = {
199
+ sortBy: 'birthtime',
200
+ order: 'asc',
201
+ dirPath: TESTS_DIR_PATH,
202
+ };
203
+
204
+ it(`sortFiles('${JS_FILES}', '${stringify(sortByBirthtimeAscOptions)}'), 按文件修改时间(asc排序), 排序后的第1个文件名称,返回:'get-basename'`, () => {
205
+ const sorted = sortFiles(JS_FILES, sortByBirthtimeAscOptions);
206
+
207
+ expect(getBasename(sorted[0])).toEqual('get-basename');
208
+ });
209
+
210
+ const sortByBirthtimeDescOptions = {
211
+ sortBy: 'birthtime',
212
+ order: 'desc',
213
+ dirPath: TESTS_DIR_PATH,
214
+ };
215
+
216
+ it(`sortFiles('${JS_FILES}', '${stringify(sortByBirthtimeDescOptions)}'), 按文件修改时间(asc排序), 排序后的第1个文件名称,返回:'terminal-link'`, () => {
217
+ const sorted = sortFiles(JS_FILES, sortByBirthtimeDescOptions);
218
+
219
+ expect(getBasename(sorted[0])).toEqual('terminal-link');
220
+ });
221
+ });
@@ -0,0 +1,15 @@
1
+ import stripNonDigit from '@/lib/utils/strip-non-digit.js';
2
+
3
+ describe('stripNonDigit() 方法:', () => {
4
+ it(`stripNonDigit(1),返回:''`, () => {
5
+ expect(stripNonDigit(1)).toEqual('');
6
+ });
7
+
8
+ it(`stripNonDigit('第1集:'),返回:'1'`, () => {
9
+ expect(stripNonDigit('第1集:')).toEqual('1');
10
+ });
11
+
12
+ it(`stripNonDigit('第1集:我的第1天'),返回:'11'`, () => {
13
+ expect(stripNonDigit('第1集:我的第1天')).toEqual('11');
14
+ });
15
+ });
@@ -0,0 +1,31 @@
1
+ import toIndexChapter from '@/lib/utils/to-index-chapter.js';
2
+
3
+ describe('toIndexChapter() 方法:', () => {
4
+ it(`toIndexChapter(1), 返回:'第1集:'`, () => {
5
+ expect(toIndexChapter(1)).toBe('第1集:');
6
+ });
7
+
8
+ it(`toIndexChapter('21'), 返回:'第21集:'`, () => {
9
+ expect(toIndexChapter('21')).toBe('第21集:');
10
+ });
11
+
12
+ it(`toIndexChapter(1, true), 返回:'1'`, () => {
13
+ expect(toIndexChapter(1, true)).toBe('1');
14
+ });
15
+
16
+ it(`toIndexChapter('21', true), 返回:'21'`, () => {
17
+ expect(toIndexChapter('21', true)).toBe('21');
18
+ });
19
+
20
+ it(`toIndexChapter('21', false, { prefix:'', suffix:'话' }), 返回:'21话:'`, () => {
21
+ expect(toIndexChapter('21', false, { prefix: '', suffix: '话' })).toBe(
22
+ '21话:',
23
+ );
24
+ });
25
+
26
+ it(`toIndexChapter('21', false, { suffix:'章', delimiter: '-' }), 返回:'第21章-'`, () => {
27
+ expect(toIndexChapter('21', false, { suffix: '章', delimiter: '-' })).toBe(
28
+ '第21章-',
29
+ );
30
+ });
31
+ });
@@ -0,0 +1,34 @@
1
+ import path from 'node:path';
2
+
3
+ import writeFile from '@/lib/utils/write-file.js';
4
+ import readFile from '@/lib/utils/read-file.js';
5
+ import removeFile from '@/lib/utils/remove-file.js';
6
+
7
+ const { resolve, dirname } = path;
8
+
9
+ const FILE_NAME = 'default.config.json';
10
+ const TEMPLATE_DIR = './tests/write';
11
+ const ABSOLUTE_PATH = resolve(process.cwd(), `${TEMPLATE_DIR}/${FILE_NAME}`);
12
+ const CONTENT_FOLDER = '{"folderPath": "./tests"}';
13
+ const CONTENT_PAD_START = '{"indexPadZero": true}';
14
+
15
+ describe(`writeFile() 方法:`, () => {
16
+ afterEach(() => {
17
+ // 删除临时文件,确保单测代码干净
18
+ removeFile(dirname(ABSOLUTE_PATH));
19
+ });
20
+
21
+ it(`writeFile('${ABSOLUTE_PATH}','${CONTENT_FOLDER}'),返回:"${CONTENT_FOLDER}"`, () => {
22
+ writeFile(ABSOLUTE_PATH, CONTENT_FOLDER);
23
+ const config = readFile(ABSOLUTE_PATH, 'utf8');
24
+ expect(config).toEqual(CONTENT_FOLDER);
25
+ });
26
+
27
+ it(`writeFile('${ABSOLUTE_PATH}','${CONTENT_PAD_START}'),返回:"${CONTENT_PAD_START}"`, () => {
28
+ writeFile(ABSOLUTE_PATH, CONTENT_PAD_START);
29
+ const config = readFile(ABSOLUTE_PATH, { encoding: 'utf8' }, () => {
30
+ console.log(`已成功读取"${ABSOLUTE_PATH}"的数据`);
31
+ });
32
+ expect(config).toEqual(CONTENT_PAD_START);
33
+ });
34
+ });