@lark-apaas/fullstack-cli 1.1.6-alpha.8 → 1.1.7-alpha.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.
- package/dist/commands/sync.js +7 -0
- package/dist/config/sync.d.ts +10 -1
- package/dist/config/sync.js +6 -0
- package/dist/utils/file-ops.d.ts +17 -0
- package/dist/utils/file-ops.js +40 -0
- package/dist/utils/file-ops.test.d.ts +1 -0
- package/dist/utils/file-ops.test.js +104 -0
- package/package.json +5 -2
package/dist/commands/sync.js
CHANGED
|
@@ -2,6 +2,7 @@ import path from 'node:path';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
import { genSyncConfig } from '../config/sync.js';
|
|
5
|
+
import { removeLineFromFile } from '../utils/file-ops.js';
|
|
5
6
|
/**
|
|
6
7
|
* 同步模板文件到用户项目
|
|
7
8
|
*/
|
|
@@ -64,6 +65,12 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
|
|
|
64
65
|
}
|
|
65
66
|
return;
|
|
66
67
|
}
|
|
68
|
+
// 处理移除行操作
|
|
69
|
+
if (rule.type === 'remove-line') {
|
|
70
|
+
const destPath = path.join(userProjectRoot, rule.to);
|
|
71
|
+
removeLineFromFile(destPath, rule.pattern);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
67
74
|
// TypeScript 类型窄化:使用 'from' in rule 确保类型安全
|
|
68
75
|
if (!('from' in rule)) {
|
|
69
76
|
return;
|
package/dist/config/sync.d.ts
CHANGED
|
@@ -29,8 +29,17 @@ type DeleteRule = {
|
|
|
29
29
|
/** 同步类型 */
|
|
30
30
|
type: 'delete-file' | 'delete-directory';
|
|
31
31
|
};
|
|
32
|
+
/** 移除文件中指定行规则 */
|
|
33
|
+
type RemoveLineRule = {
|
|
34
|
+
/** 目标文件路径(相对于用户项目根目录) */
|
|
35
|
+
to: string;
|
|
36
|
+
/** 同步类型 */
|
|
37
|
+
type: 'remove-line';
|
|
38
|
+
/** 要移除的行内容(精确匹配,会自动 trim) */
|
|
39
|
+
pattern: string;
|
|
40
|
+
};
|
|
32
41
|
/** 同步规则联合类型 */
|
|
33
|
-
export type SyncRule = CopyRule | AppendRule | DeleteRule;
|
|
42
|
+
export type SyncRule = CopyRule | AppendRule | DeleteRule | RemoveLineRule;
|
|
34
43
|
export interface SyncConfig {
|
|
35
44
|
/** 派生规则 */
|
|
36
45
|
sync: SyncRule[];
|
package/dist/config/sync.js
CHANGED
|
@@ -28,6 +28,12 @@ const syncConfig = {
|
|
|
28
28
|
type: 'delete-directory',
|
|
29
29
|
to: '.swc', // 删除 .swc 目录(如果存在)
|
|
30
30
|
},
|
|
31
|
+
// 4. 从 .gitignore 中移除 package-lock.json
|
|
32
|
+
{
|
|
33
|
+
type: 'remove-line',
|
|
34
|
+
to: '.gitignore',
|
|
35
|
+
pattern: 'package-lock.json',
|
|
36
|
+
},
|
|
31
37
|
],
|
|
32
38
|
// 文件权限设置
|
|
33
39
|
permissions: {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 从文件中移除匹配的行
|
|
3
|
+
* @param filePath 文件路径
|
|
4
|
+
* @param pattern 要移除的行内容(精确匹配,会自动 trim)
|
|
5
|
+
* @returns 是否成功移除了内容
|
|
6
|
+
*/
|
|
7
|
+
export declare function removeLineFromFile(filePath: string, pattern: string): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* 纯函数版本:从内容中移除匹配的行(便于测试)
|
|
10
|
+
* @param content 文件内容
|
|
11
|
+
* @param pattern 要移除的行内容(精确匹配,会自动 trim)
|
|
12
|
+
* @returns 处理后的内容和是否有变化
|
|
13
|
+
*/
|
|
14
|
+
export declare function removeLineFromContent(content: string, pattern: string): {
|
|
15
|
+
result: string;
|
|
16
|
+
changed: boolean;
|
|
17
|
+
};
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* 从文件中移除匹配的行
|
|
5
|
+
* @param filePath 文件路径
|
|
6
|
+
* @param pattern 要移除的行内容(精确匹配,会自动 trim)
|
|
7
|
+
* @returns 是否成功移除了内容
|
|
8
|
+
*/
|
|
9
|
+
export function removeLineFromFile(filePath, pattern) {
|
|
10
|
+
if (!fs.existsSync(filePath)) {
|
|
11
|
+
console.log(`[fullstack-cli] ○ ${path.basename(filePath)} (not found)`);
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
const content = fs.readFileSync(filePath, 'utf-8');
|
|
15
|
+
const lines = content.split('\n');
|
|
16
|
+
const trimmedPattern = pattern.trim();
|
|
17
|
+
const filteredLines = lines.filter(line => line.trim() !== trimmedPattern);
|
|
18
|
+
if (filteredLines.length === lines.length) {
|
|
19
|
+
console.log(`[fullstack-cli] ○ ${path.basename(filePath)} (pattern not found: ${pattern})`);
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
fs.writeFileSync(filePath, filteredLines.join('\n'));
|
|
23
|
+
console.log(`[fullstack-cli] ✓ ${path.basename(filePath)} (removed: ${pattern})`);
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* 纯函数版本:从内容中移除匹配的行(便于测试)
|
|
28
|
+
* @param content 文件内容
|
|
29
|
+
* @param pattern 要移除的行内容(精确匹配,会自动 trim)
|
|
30
|
+
* @returns 处理后的内容和是否有变化
|
|
31
|
+
*/
|
|
32
|
+
export function removeLineFromContent(content, pattern) {
|
|
33
|
+
const lines = content.split('\n');
|
|
34
|
+
const trimmedPattern = pattern.trim();
|
|
35
|
+
const filteredLines = lines.filter(line => line.trim() !== trimmedPattern);
|
|
36
|
+
return {
|
|
37
|
+
result: filteredLines.join('\n'),
|
|
38
|
+
changed: filteredLines.length !== lines.length,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import { removeLineFromContent, removeLineFromFile } from './file-ops.js';
|
|
6
|
+
describe('removeLineFromContent', () => {
|
|
7
|
+
it('should remove a matching line', () => {
|
|
8
|
+
const content = `node_modules
|
|
9
|
+
package-lock.json
|
|
10
|
+
dist`;
|
|
11
|
+
const { result, changed } = removeLineFromContent(content, 'package-lock.json');
|
|
12
|
+
expect(changed).toBe(true);
|
|
13
|
+
expect(result).toBe(`node_modules
|
|
14
|
+
dist`);
|
|
15
|
+
});
|
|
16
|
+
it('should remove a line with leading/trailing spaces', () => {
|
|
17
|
+
const content = `node_modules
|
|
18
|
+
package-lock.json
|
|
19
|
+
dist`;
|
|
20
|
+
const { result, changed } = removeLineFromContent(content, 'package-lock.json');
|
|
21
|
+
expect(changed).toBe(true);
|
|
22
|
+
expect(result).toBe(`node_modules
|
|
23
|
+
dist`);
|
|
24
|
+
});
|
|
25
|
+
it('should match pattern with spaces in the pattern', () => {
|
|
26
|
+
const content = `node_modules
|
|
27
|
+
package-lock.json
|
|
28
|
+
dist`;
|
|
29
|
+
const { result, changed } = removeLineFromContent(content, ' package-lock.json ');
|
|
30
|
+
expect(changed).toBe(true);
|
|
31
|
+
expect(result).toBe(`node_modules
|
|
32
|
+
dist`);
|
|
33
|
+
});
|
|
34
|
+
it('should remove multiple matching lines', () => {
|
|
35
|
+
const content = `node_modules
|
|
36
|
+
package-lock.json
|
|
37
|
+
dist
|
|
38
|
+
package-lock.json`;
|
|
39
|
+
const { result, changed } = removeLineFromContent(content, 'package-lock.json');
|
|
40
|
+
expect(changed).toBe(true);
|
|
41
|
+
expect(result).toBe(`node_modules
|
|
42
|
+
dist`);
|
|
43
|
+
});
|
|
44
|
+
it('should return changed=false when pattern not found', () => {
|
|
45
|
+
const content = `node_modules
|
|
46
|
+
dist`;
|
|
47
|
+
const { result, changed } = removeLineFromContent(content, 'package-lock.json');
|
|
48
|
+
expect(changed).toBe(false);
|
|
49
|
+
expect(result).toBe(`node_modules
|
|
50
|
+
dist`);
|
|
51
|
+
});
|
|
52
|
+
it('should not remove partial matches', () => {
|
|
53
|
+
const content = `node_modules
|
|
54
|
+
package-lock.json.bak
|
|
55
|
+
dist`;
|
|
56
|
+
const { result, changed } = removeLineFromContent(content, 'package-lock.json');
|
|
57
|
+
expect(changed).toBe(false);
|
|
58
|
+
expect(result).toBe(`node_modules
|
|
59
|
+
package-lock.json.bak
|
|
60
|
+
dist`);
|
|
61
|
+
});
|
|
62
|
+
it('should handle empty content', () => {
|
|
63
|
+
const { result, changed } = removeLineFromContent('', 'package-lock.json');
|
|
64
|
+
expect(changed).toBe(false);
|
|
65
|
+
expect(result).toBe('');
|
|
66
|
+
});
|
|
67
|
+
it('should handle single line content', () => {
|
|
68
|
+
const { result, changed } = removeLineFromContent('package-lock.json', 'package-lock.json');
|
|
69
|
+
expect(changed).toBe(true);
|
|
70
|
+
expect(result).toBe('');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
describe('removeLineFromFile', () => {
|
|
74
|
+
let tempDir;
|
|
75
|
+
let testFilePath;
|
|
76
|
+
beforeEach(() => {
|
|
77
|
+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'fullstack-cli-test-'));
|
|
78
|
+
testFilePath = path.join(tempDir, '.gitignore');
|
|
79
|
+
});
|
|
80
|
+
afterEach(() => {
|
|
81
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
82
|
+
});
|
|
83
|
+
it('should remove matching line from file', () => {
|
|
84
|
+
fs.writeFileSync(testFilePath, `node_modules
|
|
85
|
+
package-lock.json
|
|
86
|
+
dist`);
|
|
87
|
+
const result = removeLineFromFile(testFilePath, 'package-lock.json');
|
|
88
|
+
expect(result).toBe(true);
|
|
89
|
+
expect(fs.readFileSync(testFilePath, 'utf-8')).toBe(`node_modules
|
|
90
|
+
dist`);
|
|
91
|
+
});
|
|
92
|
+
it('should return false when file does not exist', () => {
|
|
93
|
+
const result = removeLineFromFile(path.join(tempDir, 'nonexistent'), 'pattern');
|
|
94
|
+
expect(result).toBe(false);
|
|
95
|
+
});
|
|
96
|
+
it('should return false when pattern not found', () => {
|
|
97
|
+
fs.writeFileSync(testFilePath, `node_modules
|
|
98
|
+
dist`);
|
|
99
|
+
const result = removeLineFromFile(testFilePath, 'package-lock.json');
|
|
100
|
+
expect(result).toBe(false);
|
|
101
|
+
expect(fs.readFileSync(testFilePath, 'utf-8')).toBe(`node_modules
|
|
102
|
+
dist`);
|
|
103
|
+
});
|
|
104
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lark-apaas/fullstack-cli",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.7-alpha.1",
|
|
4
4
|
"description": "CLI tool for fullstack template management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
],
|
|
14
14
|
"scripts": {
|
|
15
15
|
"build": "tsc",
|
|
16
|
+
"test": "vitest run",
|
|
17
|
+
"test:watch": "vitest",
|
|
16
18
|
"prepublishOnly": "npm run build"
|
|
17
19
|
},
|
|
18
20
|
"keywords": [
|
|
@@ -37,6 +39,7 @@
|
|
|
37
39
|
},
|
|
38
40
|
"devDependencies": {
|
|
39
41
|
"@types/node": "^22.0.0",
|
|
40
|
-
"typescript": "^5.9.2"
|
|
42
|
+
"typescript": "^5.9.2",
|
|
43
|
+
"vitest": "^3.0.5"
|
|
41
44
|
}
|
|
42
45
|
}
|