@lark-apaas/fullstack-cli 1.1.9 → 1.1.10
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 +158 -2
- package/dist/config/drizzle.config.d.ts +3 -1
- package/dist/config/drizzle.config.js +20 -16
- package/dist/index.d.ts +2 -1
- package/dist/index.js +3876 -49
- package/package.json +15 -7
- package/templates/nest-cli.json +25 -0
- package/templates/scripts/build.sh +16 -9
- package/templates/scripts/prune-smart.js +41 -7
- package/dist/commands/gen-db-schema.d.ts +0 -20
- package/dist/commands/gen-db-schema.js +0 -115
- package/dist/commands/read-logs/client-std.d.ts +0 -2
- package/dist/commands/read-logs/client-std.js +0 -98
- package/dist/commands/read-logs/json-lines.d.ts +0 -3
- package/dist/commands/read-logs/json-lines.js +0 -217
- package/dist/commands/read-logs/server-std.d.ts +0 -1
- package/dist/commands/read-logs/server-std.js +0 -25
- package/dist/commands/read-logs/std-utils.d.ts +0 -5
- package/dist/commands/read-logs/std-utils.js +0 -61
- package/dist/commands/read-logs/tail.d.ts +0 -2
- package/dist/commands/read-logs/tail.js +0 -47
- package/dist/commands/read-logs.d.ts +0 -16
- package/dist/commands/read-logs.js +0 -153
- package/dist/commands/read-logs.test.d.ts +0 -1
- package/dist/commands/read-logs.test.js +0 -199
- package/dist/commands/sync.d.ts +0 -6
- package/dist/commands/sync.js +0 -211
- package/dist/config/sync.d.ts +0 -52
- package/dist/config/sync.js +0 -54
- package/dist/utils/file-ops.d.ts +0 -17
- package/dist/utils/file-ops.js +0 -40
- package/dist/utils/file-ops.test.d.ts +0 -1
- package/dist/utils/file-ops.test.js +0 -104
package/dist/commands/sync.js
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import fs from 'node:fs';
|
|
3
|
-
import { fileURLToPath } from 'node:url';
|
|
4
|
-
import { genSyncConfig } from '../config/sync.js';
|
|
5
|
-
import { removeLineFromFile } from '../utils/file-ops.js';
|
|
6
|
-
/**
|
|
7
|
-
* 同步模板文件到用户项目
|
|
8
|
-
*/
|
|
9
|
-
export async function run(options) {
|
|
10
|
-
// 检测是否在用户项目中(通过 INIT_CWD 判断)
|
|
11
|
-
const userProjectRoot = process.env.INIT_CWD || process.cwd();
|
|
12
|
-
// 获取插件根目录
|
|
13
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
14
|
-
const __dirname = path.dirname(__filename);
|
|
15
|
-
const pluginRoot = path.resolve(__dirname, '../..');
|
|
16
|
-
// 只有在插件自己的开发目录中才跳过(避免在开发插件时触发 sync)
|
|
17
|
-
if (userProjectRoot === pluginRoot) {
|
|
18
|
-
console.log('[fullstack-cli] Skip syncing (installing plugin itself)');
|
|
19
|
-
process.exit(0);
|
|
20
|
-
}
|
|
21
|
-
// 检查是否存在 package.json,确保是有效的项目
|
|
22
|
-
const userPackageJson = path.join(userProjectRoot, 'package.json');
|
|
23
|
-
if (!fs.existsSync(userPackageJson)) {
|
|
24
|
-
console.log('[fullstack-cli] Skip syncing (not a valid npm project)');
|
|
25
|
-
process.exit(0);
|
|
26
|
-
}
|
|
27
|
-
try {
|
|
28
|
-
console.log('[fullstack-cli] Starting sync...');
|
|
29
|
-
// 使用配置
|
|
30
|
-
const config = genSyncConfig({
|
|
31
|
-
disableGenOpenapi: options.disableGenOpenapi ?? false,
|
|
32
|
-
});
|
|
33
|
-
if (!config || !config.sync) {
|
|
34
|
-
console.warn('[fullstack-cli] No sync configuration found');
|
|
35
|
-
process.exit(0);
|
|
36
|
-
}
|
|
37
|
-
// 执行同步规则
|
|
38
|
-
for (const rule of config.sync) {
|
|
39
|
-
await syncRule(rule, pluginRoot, userProjectRoot);
|
|
40
|
-
}
|
|
41
|
-
// 设置权限
|
|
42
|
-
if (config.permissions) {
|
|
43
|
-
setPermissions(config.permissions, userProjectRoot);
|
|
44
|
-
}
|
|
45
|
-
console.log('[fullstack-cli] Sync completed successfully ✅');
|
|
46
|
-
}
|
|
47
|
-
catch (error) {
|
|
48
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
49
|
-
console.error('[fullstack-cli] Failed to sync:', message);
|
|
50
|
-
process.exit(1);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* 执行单个同步规则
|
|
55
|
-
*/
|
|
56
|
-
async function syncRule(rule, pluginRoot, userProjectRoot) {
|
|
57
|
-
// 处理删除操作(只需要 to 路径)
|
|
58
|
-
if (rule.type === 'delete-file' || rule.type === 'delete-directory') {
|
|
59
|
-
const destPath = path.join(userProjectRoot, rule.to);
|
|
60
|
-
if (rule.type === 'delete-file') {
|
|
61
|
-
deleteFile(destPath);
|
|
62
|
-
}
|
|
63
|
-
else {
|
|
64
|
-
deleteDirectory(destPath);
|
|
65
|
-
}
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
|
-
// 处理移除行操作
|
|
69
|
-
if (rule.type === 'remove-line') {
|
|
70
|
-
const destPath = path.join(userProjectRoot, rule.to);
|
|
71
|
-
removeLineFromFile(destPath, rule.pattern);
|
|
72
|
-
return;
|
|
73
|
-
}
|
|
74
|
-
// TypeScript 类型窄化:使用 'from' in rule 确保类型安全
|
|
75
|
-
if (!('from' in rule)) {
|
|
76
|
-
return;
|
|
77
|
-
}
|
|
78
|
-
// 处理需要源文件的操作(CopyRule 和 AppendRule)
|
|
79
|
-
const srcPath = path.join(pluginRoot, rule.from);
|
|
80
|
-
const destPath = path.join(userProjectRoot, rule.to);
|
|
81
|
-
if (!fs.existsSync(srcPath)) {
|
|
82
|
-
console.warn(`[fullstack-cli] Source not found: ${rule.from}`);
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
switch (rule.type) {
|
|
86
|
-
case 'directory':
|
|
87
|
-
syncDirectory(srcPath, destPath, rule.overwrite ?? true);
|
|
88
|
-
break;
|
|
89
|
-
case 'file':
|
|
90
|
-
syncFile(srcPath, destPath, rule.overwrite ?? true);
|
|
91
|
-
break;
|
|
92
|
-
case 'append':
|
|
93
|
-
appendToFile(srcPath, destPath);
|
|
94
|
-
break;
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
/**
|
|
98
|
-
* 同步单个文件
|
|
99
|
-
*/
|
|
100
|
-
function syncFile(src, dest, overwrite = true) {
|
|
101
|
-
// 确保目标目录存在
|
|
102
|
-
const destDir = path.dirname(dest);
|
|
103
|
-
if (!fs.existsSync(destDir)) {
|
|
104
|
-
fs.mkdirSync(destDir, { recursive: true });
|
|
105
|
-
}
|
|
106
|
-
// 检查目标文件是否存在
|
|
107
|
-
if (fs.existsSync(dest) && !overwrite) {
|
|
108
|
-
console.log(`[fullstack-cli] ○ ${path.basename(dest)} (skipped, already exists)`);
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
// 复制文件
|
|
112
|
-
fs.copyFileSync(src, dest);
|
|
113
|
-
console.log(`[fullstack-cli] ✓ ${path.basename(dest)}`);
|
|
114
|
-
}
|
|
115
|
-
/**
|
|
116
|
-
* 同步整个目录
|
|
117
|
-
*/
|
|
118
|
-
function syncDirectory(src, dest, overwrite = true) {
|
|
119
|
-
// 确保目标目录存在
|
|
120
|
-
if (!fs.existsSync(dest)) {
|
|
121
|
-
fs.mkdirSync(dest, { recursive: true });
|
|
122
|
-
}
|
|
123
|
-
// 读取源目录所有文件
|
|
124
|
-
const files = fs.readdirSync(src);
|
|
125
|
-
let count = 0;
|
|
126
|
-
files.forEach(file => {
|
|
127
|
-
const srcFile = path.join(src, file);
|
|
128
|
-
const destFile = path.join(dest, file);
|
|
129
|
-
const stats = fs.statSync(srcFile);
|
|
130
|
-
if (stats.isDirectory()) {
|
|
131
|
-
// 递归处理子目录
|
|
132
|
-
syncDirectory(srcFile, destFile, overwrite);
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
// 复制文件
|
|
136
|
-
if (overwrite || !fs.existsSync(destFile)) {
|
|
137
|
-
fs.copyFileSync(srcFile, destFile);
|
|
138
|
-
console.log(`[fullstack-cli] ✓ ${path.relative(dest, destFile)}`);
|
|
139
|
-
count++;
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
if (count > 0) {
|
|
144
|
-
console.log(`[fullstack-cli] Synced ${count} files to ${path.basename(dest)}/`);
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
/**
|
|
148
|
-
* 追加内容到文件
|
|
149
|
-
*/
|
|
150
|
-
function appendToFile(src, dest) {
|
|
151
|
-
const content = fs.readFileSync(src, 'utf-8');
|
|
152
|
-
// 读取目标文件内容(如果存在)
|
|
153
|
-
let existingContent = '';
|
|
154
|
-
if (fs.existsSync(dest)) {
|
|
155
|
-
existingContent = fs.readFileSync(dest, 'utf-8');
|
|
156
|
-
}
|
|
157
|
-
// 检查是否已包含相同内容(避免重复追加)
|
|
158
|
-
if (existingContent.includes(content.trim())) {
|
|
159
|
-
console.log(`[fullstack-cli] ○ ${path.basename(dest)} (already contains content)`);
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
// 追加内容
|
|
163
|
-
fs.appendFileSync(dest, content);
|
|
164
|
-
console.log(`[fullstack-cli] ✓ ${path.basename(dest)} (appended)`);
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* 设置文件权限
|
|
168
|
-
*/
|
|
169
|
-
function setPermissions(permissions, projectRoot) {
|
|
170
|
-
for (const [pattern, mode] of Object.entries(permissions)) {
|
|
171
|
-
// 简单实现:只支持 **/*.sh 这种模式
|
|
172
|
-
if (pattern === '**/*.sh') {
|
|
173
|
-
const scriptsDir = path.join(projectRoot, 'scripts');
|
|
174
|
-
if (fs.existsSync(scriptsDir)) {
|
|
175
|
-
const files = fs.readdirSync(scriptsDir);
|
|
176
|
-
files.forEach(file => {
|
|
177
|
-
if (file.endsWith('.sh')) {
|
|
178
|
-
const filePath = path.join(scriptsDir, file);
|
|
179
|
-
fs.chmodSync(filePath, mode);
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
/**
|
|
187
|
-
* 删除单个文件
|
|
188
|
-
* @param filePath 要删除的文件路径
|
|
189
|
-
*/
|
|
190
|
-
function deleteFile(filePath) {
|
|
191
|
-
if (fs.existsSync(filePath)) {
|
|
192
|
-
fs.unlinkSync(filePath);
|
|
193
|
-
console.log(`[fullstack-cli] ✓ ${path.basename(filePath)} (deleted)`);
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
console.log(`[fullstack-cli] ○ ${path.basename(filePath)} (not found)`);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
/**
|
|
200
|
-
* 删除整个目录
|
|
201
|
-
* @param dirPath 要删除的目录路径
|
|
202
|
-
*/
|
|
203
|
-
function deleteDirectory(dirPath) {
|
|
204
|
-
if (fs.existsSync(dirPath)) {
|
|
205
|
-
fs.rmSync(dirPath, { recursive: true });
|
|
206
|
-
console.log(`[fullstack-cli] ✓ ${path.basename(dirPath)} (deleted)`);
|
|
207
|
-
}
|
|
208
|
-
else {
|
|
209
|
-
console.log(`[fullstack-cli] ○ ${path.basename(dirPath)} (not found)`);
|
|
210
|
-
}
|
|
211
|
-
}
|
package/dist/config/sync.d.ts
DELETED
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* fullstack-cli 派生配置
|
|
3
|
-
* 定义哪些文件/目录需要同步到用户项目
|
|
4
|
-
*/
|
|
5
|
-
/** 复制目录或文件规则 */
|
|
6
|
-
type CopyRule = {
|
|
7
|
-
/** 源文件/目录路径(相对于插件根目录) */
|
|
8
|
-
from: string;
|
|
9
|
-
/** 目标文件/目录路径(相对于用户项目根目录) */
|
|
10
|
-
to: string;
|
|
11
|
-
/** 同步类型 */
|
|
12
|
-
type: 'directory' | 'file';
|
|
13
|
-
/** 是否覆盖已存在的文件 */
|
|
14
|
-
overwrite?: boolean;
|
|
15
|
-
};
|
|
16
|
-
/** 追加内容规则 */
|
|
17
|
-
type AppendRule = {
|
|
18
|
-
/** 源文件路径(相对于插件根目录) */
|
|
19
|
-
from: string;
|
|
20
|
-
/** 目标文件路径(相对于用户项目根目录) */
|
|
21
|
-
to: string;
|
|
22
|
-
/** 同步类型 */
|
|
23
|
-
type: 'append';
|
|
24
|
-
};
|
|
25
|
-
/** 删除文件或目录规则 */
|
|
26
|
-
type DeleteRule = {
|
|
27
|
-
/** 目标文件/目录路径(相对于用户项目根目录) */
|
|
28
|
-
to: string;
|
|
29
|
-
/** 同步类型 */
|
|
30
|
-
type: 'delete-file' | 'delete-directory';
|
|
31
|
-
};
|
|
32
|
-
/** 移除文件中指定行规则 */
|
|
33
|
-
type RemoveLineRule = {
|
|
34
|
-
/** 目标文件路径(相对于用户项目根目录) */
|
|
35
|
-
to: string;
|
|
36
|
-
/** 同步类型 */
|
|
37
|
-
type: 'remove-line';
|
|
38
|
-
/** 要移除的行内容(精确匹配,会自动 trim) */
|
|
39
|
-
pattern: string;
|
|
40
|
-
};
|
|
41
|
-
/** 同步规则联合类型 */
|
|
42
|
-
export type SyncRule = CopyRule | AppendRule | DeleteRule | RemoveLineRule;
|
|
43
|
-
export interface SyncConfig {
|
|
44
|
-
/** 派生规则 */
|
|
45
|
-
sync: SyncRule[];
|
|
46
|
-
/** 文件权限设置 */
|
|
47
|
-
permissions?: Record<string, number>;
|
|
48
|
-
}
|
|
49
|
-
export declare function genSyncConfig(perms?: {
|
|
50
|
-
disableGenOpenapi?: boolean;
|
|
51
|
-
}): SyncConfig;
|
|
52
|
-
export {};
|
package/dist/config/sync.js
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* fullstack-cli 派生配置
|
|
3
|
-
* 定义哪些文件/目录需要同步到用户项目
|
|
4
|
-
*/
|
|
5
|
-
const syncConfig = {
|
|
6
|
-
// 派生规则
|
|
7
|
-
sync: [
|
|
8
|
-
// 1. 派生 scripts 目录(总是覆盖)
|
|
9
|
-
{
|
|
10
|
-
from: 'templates/scripts',
|
|
11
|
-
to: 'scripts',
|
|
12
|
-
type: 'directory',
|
|
13
|
-
overwrite: true,
|
|
14
|
-
},
|
|
15
|
-
// // 2. 追加内容到 .gitignore
|
|
16
|
-
// {
|
|
17
|
-
// from: 'templates/.gitignore.append',
|
|
18
|
-
// to: '.gitignore',
|
|
19
|
-
// type: 'append',
|
|
20
|
-
// },
|
|
21
|
-
// 3. 派生 server/type.ts 文件(总是覆盖)
|
|
22
|
-
// {
|
|
23
|
-
// from: 'templates/server/global.d.ts',
|
|
24
|
-
// to: 'server/types/global.d.ts',
|
|
25
|
-
// type: 'file',
|
|
26
|
-
// },
|
|
27
|
-
{
|
|
28
|
-
type: 'delete-directory',
|
|
29
|
-
to: '.swc', // 删除 .swc 目录(如果存在)
|
|
30
|
-
},
|
|
31
|
-
// 4. 从 .gitignore 中移除 package-lock.json
|
|
32
|
-
{
|
|
33
|
-
type: 'remove-line',
|
|
34
|
-
to: '.gitignore',
|
|
35
|
-
pattern: 'package-lock.json',
|
|
36
|
-
},
|
|
37
|
-
],
|
|
38
|
-
// 文件权限设置
|
|
39
|
-
permissions: {
|
|
40
|
-
// 所有 .sh 文件设置为可执行
|
|
41
|
-
// '**/*.sh': 0o755,
|
|
42
|
-
},
|
|
43
|
-
};
|
|
44
|
-
export function genSyncConfig(perms = {}) {
|
|
45
|
-
if (!perms.disableGenOpenapi) {
|
|
46
|
-
syncConfig.sync.push({
|
|
47
|
-
from: 'templates/helper/gen-openapi.ts',
|
|
48
|
-
to: 'scripts/gen-openapi.ts',
|
|
49
|
-
type: 'file',
|
|
50
|
-
overwrite: true,
|
|
51
|
-
});
|
|
52
|
-
}
|
|
53
|
-
return syncConfig;
|
|
54
|
-
}
|
package/dist/utils/file-ops.d.ts
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
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
|
-
};
|
package/dist/utils/file-ops.js
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
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
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,104 +0,0 @@
|
|
|
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
|
-
});
|