@simplysm/sd-cli 13.0.74 → 13.0.76
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/lint.d.ts +2 -2
- package/dist/commands/lint.d.ts.map +1 -1
- package/dist/commands/lint.js +0 -94
- package/dist/commands/lint.js.map +1 -1
- package/package.json +4 -5
- package/src/commands/lint.ts +2 -113
- package/templates/init/package.json.hbs +2 -3
- package/templates/init/packages/client-admin/package.json.hbs +5 -5
- package/templates/init/packages/client-admin/src/views/home/base/employee/EmployeeDetail.tsx.hbs +86 -105
- package/templates/init/packages/client-admin/src/views/home/base/role-permission/RoleDetail.tsx.hbs +4 -12
- package/templates/init/packages/client-admin/src/views/home/base/role-permission/RolePermissionDetail.tsx.hbs +0 -2
- package/templates/init/packages/client-admin/src/views/home/base/role-permission/RolePermissionView.tsx +1 -1
- package/templates/init/packages/client-admin/src/views/home/my-info/MyInfoDetail.tsx.hbs +36 -43
- package/templates/init/packages/db-main/package.json.hbs +2 -2
- package/templates/init/packages/server/package.json.hbs +4 -4
- package/templates/init/tests/e2e/package.json.hbs +1 -1
- package/tests/get-compiler-options-for-package.spec.ts +0 -45
- package/tests/get-package-source-files.spec.ts +0 -42
- package/tests/get-types-from-package-json.spec.ts +0 -19
- package/tests/infra/ResultCollector.spec.ts +0 -9
- package/tests/infra/WorkerManager.spec.ts +0 -34
- package/tests/load-ignore-patterns.spec.ts +0 -29
- package/tests/load-sd-config.spec.ts +0 -39
- package/tests/run-lint.spec.ts +0 -53
- package/tests/run-typecheck.spec.ts +0 -168
- package/tests/run-watch.spec.ts +0 -34
- package/tests/sd-cli.spec.ts +0 -88
- package/templates/init/stylelint.config.ts +0 -1
package/templates/init/packages/client-admin/src/views/home/base/role-permission/RoleDetail.tsx.hbs
CHANGED
|
@@ -33,7 +33,6 @@ export function RoleDetail(props: { itemId?: number }) {
|
|
|
33
33
|
return appService.orm.connectWithoutTransaction(async (db) => {
|
|
34
34
|
const role = await db
|
|
35
35
|
.role()
|
|
36
|
-
// eslint-disable-next-line solid/reactivity -- 비동기 콜백 내부
|
|
37
36
|
.where((c) => [expr.eq(c.id, props.itemId)])
|
|
38
37
|
.select((c) => ({
|
|
39
38
|
name: c.name,
|
|
@@ -61,7 +60,6 @@ export function RoleDetail(props: { itemId?: number }) {
|
|
|
61
60
|
await appService.orm.connect(async (db) => {
|
|
62
61
|
const count = await db
|
|
63
62
|
.role()
|
|
64
|
-
// eslint-disable-next-line solid/reactivity -- 비동기 콜백 내부
|
|
65
63
|
.where((c) => [
|
|
66
64
|
expr.eq(c.name, data.name ?? ""),
|
|
67
65
|
|
|
@@ -78,7 +76,6 @@ export function RoleDetail(props: { itemId?: number }) {
|
|
|
78
76
|
});
|
|
79
77
|
|
|
80
78
|
// 저장
|
|
81
|
-
// eslint-disable-next-line solid/reactivity -- 비동기 콜백 내부
|
|
82
79
|
const savedId = await appService.orm.connect(async (db) => {
|
|
83
80
|
if (props.itemId == null) {
|
|
84
81
|
const [inserted] = await db.role().insert(
|
|
@@ -95,7 +92,6 @@ export function RoleDetail(props: { itemId?: number }) {
|
|
|
95
92
|
} else {
|
|
96
93
|
await db
|
|
97
94
|
.role()
|
|
98
|
-
// eslint-disable-next-line solid/reactivity -- 비동기 콜백 내부
|
|
99
95
|
.where((_c) => [expr.eq(_c.id, props.itemId)])
|
|
100
96
|
.update((_c) => ({
|
|
101
97
|
name: data.name ?? "",
|
|
@@ -112,7 +108,6 @@ export function RoleDetail(props: { itemId?: number }) {
|
|
|
112
108
|
await appService.orm.connect(async (db) => {
|
|
113
109
|
await db
|
|
114
110
|
.role()
|
|
115
|
-
// eslint-disable-next-line solid/reactivity -- 비동기 콜백 내부
|
|
116
111
|
.where((_c) => [expr.eq(_c.id, props.itemId!)])
|
|
117
112
|
.update((_c) => ({
|
|
118
113
|
isDeleted: del,
|
|
@@ -133,19 +128,16 @@ export function RoleDetail(props: { itemId?: number }) {
|
|
|
133
128
|
{(ctx) => (
|
|
134
129
|
<div class="p-2">
|
|
135
130
|
<FormTable>
|
|
136
|
-
<
|
|
137
|
-
|
|
138
|
-
<th>이름</th>
|
|
139
|
-
<td>
|
|
131
|
+
<FormTable.Row>
|
|
132
|
+
<FormTable.Item label="이름">
|
|
140
133
|
<TextInput
|
|
141
134
|
required
|
|
142
135
|
disabled={!perms().edit}
|
|
143
136
|
value={ctx.data.name ?? ""}
|
|
144
137
|
onValueChange={(v) => ctx.setData("name", v)}
|
|
145
138
|
/>
|
|
146
|
-
</
|
|
147
|
-
</
|
|
148
|
-
</tbody>
|
|
139
|
+
</FormTable.Item>
|
|
140
|
+
</FormTable.Row>
|
|
149
141
|
</FormTable>
|
|
150
142
|
</div>
|
|
151
143
|
)}
|
|
@@ -57,11 +57,9 @@ export function RolePermissionDetail(props: { roleId: number }) {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
async function handleSubmit(data: Record<string, boolean>) {
|
|
60
|
-
// eslint-disable-next-line solid/reactivity -- 비동기 콜백 내부
|
|
61
60
|
await appService.orm.connect(async (db) => {
|
|
62
61
|
await db
|
|
63
62
|
.rolePermission()
|
|
64
|
-
// eslint-disable-next-line solid/reactivity -- 비동기 콜백 내부
|
|
65
63
|
.where((c) => [expr.eq(c.roleId, props.roleId)])
|
|
66
64
|
.delete();
|
|
67
65
|
|
|
@@ -24,7 +24,7 @@ export function RolePermissionView() {
|
|
|
24
24
|
variant={"ghost"}
|
|
25
25
|
theme={"primary"}
|
|
26
26
|
size={"xs"}
|
|
27
|
-
onClick={() => dialog.show(() => <RoleSheet />, { header: "권한그룹",
|
|
27
|
+
onClick={() => dialog.show(() => <RoleSheet />, { header: "권한그룹", closeOnInteractOutside: true })}
|
|
28
28
|
>
|
|
29
29
|
<Icon icon={IconExternalLink} />
|
|
30
30
|
</Button>
|
|
@@ -148,9 +148,8 @@ export function MyInfoDetail() {
|
|
|
148
148
|
<section>
|
|
149
149
|
<h3 class="mb-4 border-l-4 border-base-500 pl-3 font-bold text-base-500">인증정보</h3>
|
|
150
150
|
<FormTable>
|
|
151
|
-
<
|
|
152
|
-
<
|
|
153
|
-
<td>
|
|
151
|
+
<FormTable.Row>
|
|
152
|
+
<FormTable.Item label="이메일">
|
|
154
153
|
<TextInput
|
|
155
154
|
type="email"
|
|
156
155
|
required
|
|
@@ -158,11 +157,10 @@ export function MyInfoDetail() {
|
|
|
158
157
|
onValueChange={(v) => ctx.setData("email", v)}
|
|
159
158
|
autocomplete="off"
|
|
160
159
|
/>
|
|
161
|
-
</
|
|
162
|
-
</
|
|
163
|
-
<
|
|
164
|
-
<
|
|
165
|
-
<td>
|
|
160
|
+
</FormTable.Item>
|
|
161
|
+
</FormTable.Row>
|
|
162
|
+
<FormTable.Row>
|
|
163
|
+
<FormTable.Item label="현재 비밀번호">
|
|
166
164
|
<TextInput
|
|
167
165
|
required={Boolean(ctx.data.newPassword || ctx.data.confirmPassword)}
|
|
168
166
|
class="w-56"
|
|
@@ -172,11 +170,10 @@ export function MyInfoDetail() {
|
|
|
172
170
|
onValueChange={(v) => ctx.setData("currentPassword", v)}
|
|
173
171
|
placeholder="비밀번호 변경 시에만 입력"
|
|
174
172
|
/>
|
|
175
|
-
</
|
|
176
|
-
</
|
|
177
|
-
<
|
|
178
|
-
<
|
|
179
|
-
<td>
|
|
173
|
+
</FormTable.Item>
|
|
174
|
+
</FormTable.Row>
|
|
175
|
+
<FormTable.Row>
|
|
176
|
+
<FormTable.Item label="새 비밀번호">
|
|
180
177
|
<TextInput
|
|
181
178
|
required={Boolean(ctx.data.currentPassword || ctx.data.confirmPassword)}
|
|
182
179
|
minLength={8}
|
|
@@ -187,11 +184,10 @@ export function MyInfoDetail() {
|
|
|
187
184
|
onValueChange={(v) => ctx.setData("newPassword", v)}
|
|
188
185
|
placeholder="비밀번호 변경 시에만 입력"
|
|
189
186
|
/>
|
|
190
|
-
</
|
|
191
|
-
</
|
|
192
|
-
<
|
|
193
|
-
<
|
|
194
|
-
<td>
|
|
187
|
+
</FormTable.Item>
|
|
188
|
+
</FormTable.Row>
|
|
189
|
+
<FormTable.Row>
|
|
190
|
+
<FormTable.Item label="새 비밀번호 확인">
|
|
195
191
|
<TextInput
|
|
196
192
|
required={Boolean(ctx.data.currentPassword || ctx.data.newPassword)}
|
|
197
193
|
minLength={8}
|
|
@@ -207,38 +203,35 @@ export function MyInfoDetail() {
|
|
|
207
203
|
onValueChange={(v) => ctx.setData("confirmPassword", v)}
|
|
208
204
|
placeholder="비밀번호 변경 시에만 입력"
|
|
209
205
|
/>
|
|
210
|
-
</
|
|
211
|
-
</
|
|
206
|
+
</FormTable.Item>
|
|
207
|
+
</FormTable.Row>
|
|
212
208
|
</FormTable>
|
|
213
209
|
</section>
|
|
214
210
|
|
|
215
211
|
<section>
|
|
216
212
|
<h3 class="mb-4 border-l-4 border-base-500 pl-3 font-bold text-base-500">시스템설정</h3>
|
|
217
213
|
<FormTable>
|
|
218
|
-
<
|
|
219
|
-
<
|
|
220
|
-
<
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
214
|
+
<FormTable.Row>
|
|
215
|
+
<FormTable.Item label="로그인 시 화면">
|
|
216
|
+
<Select
|
|
217
|
+
class="w-full"
|
|
218
|
+
value={ctx.data.firstRouterLink}
|
|
219
|
+
onValueChange={(v) => ctx.setData("firstRouterLink", v)}
|
|
220
|
+
items={routeOptions()}
|
|
221
|
+
renderValue={(v) => <>{routeMap().get(v) ?? v}</>}
|
|
222
|
+
placeholder="선택 안함"
|
|
223
|
+
>
|
|
224
|
+
<Select.ItemTemplate>
|
|
225
|
+
{(href: string) => <>{routeMap().get(href) ?? href}</>}
|
|
226
|
+
</Select.ItemTemplate>
|
|
227
|
+
<Select.Action
|
|
228
|
+
onClick={() => ctx.setData("firstRouterLink", undefined as any)}
|
|
229
229
|
>
|
|
230
|
-
<
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
>
|
|
236
|
-
<Icon icon={IconX} class={"text-danger-500"} />
|
|
237
|
-
</Select.Action>
|
|
238
|
-
</Select>
|
|
239
|
-
</td>
|
|
240
|
-
</tr>
|
|
241
|
-
</tbody>
|
|
230
|
+
<Icon icon={IconX} class={"text-danger-500"} />
|
|
231
|
+
</Select.Action>
|
|
232
|
+
</Select>
|
|
233
|
+
</FormTable.Item>
|
|
234
|
+
</FormTable.Row>
|
|
242
235
|
</FormTable>
|
|
243
236
|
</section>
|
|
244
237
|
</div>
|
|
@@ -5,11 +5,11 @@
|
|
|
5
5
|
"private": true,
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@{{projectName}}/db-main": "workspace:*",
|
|
8
|
-
"@simplysm/core-common": "~13.0.
|
|
8
|
+
"@simplysm/core-common": "~13.0.76",
|
|
9
9
|
"@simplysm/excel": "^13.0.71",
|
|
10
|
-
"@simplysm/orm-common": "~13.0.
|
|
11
|
-
"@simplysm/orm-node": "~13.0.
|
|
12
|
-
"@simplysm/service-server": "~13.0.
|
|
10
|
+
"@simplysm/orm-common": "~13.0.76",
|
|
11
|
+
"@simplysm/orm-node": "~13.0.76",
|
|
12
|
+
"@simplysm/service-server": "~13.0.76",
|
|
13
13
|
"bcrypt": "^6.0.0",
|
|
14
14
|
"pg": "^8.19.0",
|
|
15
15
|
"pg-copy-streams": "^7.0.0"
|
|
@@ -81,21 +81,6 @@ describe("getCompilerOptionsForPackage", () => {
|
|
|
81
81
|
expect(result.types).toContain("lodash");
|
|
82
82
|
});
|
|
83
83
|
|
|
84
|
-
it("node target: removes duplicate node types", async () => {
|
|
85
|
-
const packageDir = "/project/packages/core-node";
|
|
86
|
-
vi.mocked(fsExists).mockResolvedValue(true);
|
|
87
|
-
vi.mocked(fsReadJson).mockResolvedValue({
|
|
88
|
-
devDependencies: {
|
|
89
|
-
"@types/node": "^20.0.0",
|
|
90
|
-
},
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
const result = await getCompilerOptionsForPackage(baseOptions, "node", packageDir);
|
|
94
|
-
|
|
95
|
-
// node type is included only once without duplicates
|
|
96
|
-
expect(result.types?.filter((t) => t === "node")).toHaveLength(1);
|
|
97
|
-
});
|
|
98
|
-
|
|
99
84
|
it("handles missing package.json with empty types", async () => {
|
|
100
85
|
const packageDir = "/project/packages/unknown";
|
|
101
86
|
vi.mocked(fsExists).mockResolvedValue(false);
|
|
@@ -106,34 +91,4 @@ describe("getCompilerOptionsForPackage", () => {
|
|
|
106
91
|
expect(result.types).toEqual(["node"]);
|
|
107
92
|
});
|
|
108
93
|
|
|
109
|
-
it("handles undefined lib correctly", async () => {
|
|
110
|
-
const optionsWithoutLib: ts.CompilerOptions = {
|
|
111
|
-
strict: true,
|
|
112
|
-
};
|
|
113
|
-
const packageDir = "/project/packages/core-node";
|
|
114
|
-
vi.mocked(fsExists).mockResolvedValue(false);
|
|
115
|
-
|
|
116
|
-
const result = await getCompilerOptionsForPackage(optionsWithoutLib, "node", packageDir);
|
|
117
|
-
|
|
118
|
-
// handles undefined lib without error
|
|
119
|
-
expect(result.lib).toBeUndefined();
|
|
120
|
-
expect(result.types).toEqual(["node"]);
|
|
121
|
-
});
|
|
122
|
-
|
|
123
|
-
it("does not mutate original baseOptions (immutability)", async () => {
|
|
124
|
-
const originalOptions: ts.CompilerOptions = {
|
|
125
|
-
lib: ["ES2024", "DOM"],
|
|
126
|
-
types: ["original"],
|
|
127
|
-
strict: true,
|
|
128
|
-
};
|
|
129
|
-
const packageDir = "/project/packages/core-node";
|
|
130
|
-
vi.mocked(fsExists).mockResolvedValue(false);
|
|
131
|
-
|
|
132
|
-
await getCompilerOptionsForPackage(originalOptions, "node", packageDir);
|
|
133
|
-
|
|
134
|
-
// original options are not changed
|
|
135
|
-
expect(originalOptions.lib).toEqual(["ES2024", "DOM"]);
|
|
136
|
-
expect(originalOptions.types).toEqual(["original"]);
|
|
137
|
-
expect(originalOptions.noEmit).toBeUndefined();
|
|
138
|
-
});
|
|
139
94
|
});
|
|
@@ -4,8 +4,6 @@ import type ts from "typescript";
|
|
|
4
4
|
import { getPackageSourceFiles, getPackageFiles } from "../src/utils/tsconfig";
|
|
5
5
|
|
|
6
6
|
describe("getPackageSourceFiles", () => {
|
|
7
|
-
const sep = path.sep;
|
|
8
|
-
|
|
9
7
|
it("filters files within package src directory only", () => {
|
|
10
8
|
const pkgDir = `/project/packages/core-common`;
|
|
11
9
|
const parsedConfig = {
|
|
@@ -60,35 +58,6 @@ describe("getPackageSourceFiles", () => {
|
|
|
60
58
|
]);
|
|
61
59
|
});
|
|
62
60
|
|
|
63
|
-
it("returns empty array if no files", () => {
|
|
64
|
-
const pkgDir = `/project/packages/empty`;
|
|
65
|
-
const parsedConfig = {
|
|
66
|
-
fileNames: [
|
|
67
|
-
`/project/packages/core/src/index.ts`,
|
|
68
|
-
`/project/packages/core-common/src/index.ts`,
|
|
69
|
-
],
|
|
70
|
-
} as ts.ParsedCommandLine;
|
|
71
|
-
|
|
72
|
-
const result = getPackageSourceFiles(pkgDir, parsedConfig);
|
|
73
|
-
|
|
74
|
-
expect(result).toEqual([]);
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it("handles path separators correctly", () => {
|
|
78
|
-
// use path.sep for platform-independent test
|
|
79
|
-
const pkgDir = `${sep}project${sep}packages${sep}core`;
|
|
80
|
-
const parsedConfig = {
|
|
81
|
-
fileNames: [
|
|
82
|
-
`${sep}project${sep}packages${sep}core${sep}src${sep}index.ts`,
|
|
83
|
-
`${sep}project${sep}packages${sep}core-common${sep}src${sep}index.ts`,
|
|
84
|
-
],
|
|
85
|
-
} as ts.ParsedCommandLine;
|
|
86
|
-
|
|
87
|
-
const result = getPackageSourceFiles(pkgDir, parsedConfig);
|
|
88
|
-
|
|
89
|
-
expect(result).toEqual([`${sep}project${sep}packages${sep}core${sep}src${sep}index.ts`]);
|
|
90
|
-
});
|
|
91
|
-
|
|
92
61
|
it("handles forward slash paths from TypeScript API correctly (Windows compatible)", () => {
|
|
93
62
|
// TypeScript API returns forward slash paths even on Windows
|
|
94
63
|
// pkgDir is created with path.join using OS-native separator
|
|
@@ -152,17 +121,6 @@ describe("getPackageFiles", () => {
|
|
|
152
121
|
]);
|
|
153
122
|
});
|
|
154
123
|
|
|
155
|
-
it("returns empty array if no files", () => {
|
|
156
|
-
const pkgDir = `/project/packages/empty`;
|
|
157
|
-
const parsedConfig = {
|
|
158
|
-
fileNames: [`/project/packages/core/src/index.ts`],
|
|
159
|
-
} as ts.ParsedCommandLine;
|
|
160
|
-
|
|
161
|
-
const result = getPackageFiles(pkgDir, parsedConfig);
|
|
162
|
-
|
|
163
|
-
expect(result).toEqual([]);
|
|
164
|
-
});
|
|
165
|
-
|
|
166
124
|
it("handles forward slash paths from TypeScript API correctly (Windows compatible)", () => {
|
|
167
125
|
const pkgDir = path.resolve("/project/packages/core-common");
|
|
168
126
|
const parsedConfig = {
|
|
@@ -68,25 +68,6 @@ describe("getTypesFromPackageJson", () => {
|
|
|
68
68
|
expect(result).toEqual([]);
|
|
69
69
|
});
|
|
70
70
|
|
|
71
|
-
it("filters out dependencies that are not @types/*", async () => {
|
|
72
|
-
const packageDir = "/project/packages/core-common";
|
|
73
|
-
const mockFsExists = vi.mocked(fsExists);
|
|
74
|
-
const mockFsReadJson = vi.mocked(fsReadJson);
|
|
75
|
-
|
|
76
|
-
mockFsExists.mockResolvedValue(true);
|
|
77
|
-
mockFsReadJson.mockResolvedValue({
|
|
78
|
-
devDependencies: {
|
|
79
|
-
typescript: "^5.0.0",
|
|
80
|
-
vitest: "^1.0.0",
|
|
81
|
-
eslint: "^9.0.0",
|
|
82
|
-
},
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
const result = await getTypesFromPackageJson(packageDir);
|
|
86
|
-
|
|
87
|
-
expect(result).toEqual([]);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
71
|
it("handles scoped @types packages correctly", async () => {
|
|
91
72
|
const packageDir = "/project/packages/core-common";
|
|
92
73
|
const mockFsExists = vi.mocked(fsExists);
|
|
@@ -27,13 +27,4 @@ describe("ResultCollector", () => {
|
|
|
27
27
|
expect(collector.toMap().size).toBe(1);
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
it("returns internal Map", () => {
|
|
31
|
-
const collector = new ResultCollector();
|
|
32
|
-
collector.add({ name: "pkg1", target: "node", type: "build", status: "success" });
|
|
33
|
-
|
|
34
|
-
const map = collector.toMap();
|
|
35
|
-
|
|
36
|
-
expect(map).toBeInstanceOf(Map);
|
|
37
|
-
expect(map.size).toBe(1);
|
|
38
|
-
});
|
|
39
30
|
});
|
|
@@ -26,12 +26,6 @@ describe("WorkerManager", () => {
|
|
|
26
26
|
expect(manager.get("test-worker")).toBe(worker);
|
|
27
27
|
});
|
|
28
28
|
|
|
29
|
-
it("returns undefined when retrieving a non-existent Worker", () => {
|
|
30
|
-
const manager = new WorkerManager();
|
|
31
|
-
|
|
32
|
-
expect(manager.get("nonexistent")).toBeUndefined();
|
|
33
|
-
});
|
|
34
|
-
|
|
35
29
|
it("terminates all Workers", async () => {
|
|
36
30
|
const manager = new WorkerManager();
|
|
37
31
|
const worker1 = manager.create("worker1", "/path/to/worker.ts");
|
|
@@ -57,34 +51,6 @@ describe("WorkerManager", () => {
|
|
|
57
51
|
expect(manager.get("worker2")).toBe(worker2);
|
|
58
52
|
});
|
|
59
53
|
|
|
60
|
-
it("handles terminating a non-existent Worker without error", async () => {
|
|
61
|
-
const manager = new WorkerManager();
|
|
62
|
-
|
|
63
|
-
await expect(manager.terminate("nonexistent")).resolves.toBeUndefined();
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
it("retrieves the count of managed Workers", () => {
|
|
67
|
-
const manager = new WorkerManager();
|
|
68
|
-
|
|
69
|
-
expect(manager.size).toBe(0);
|
|
70
|
-
|
|
71
|
-
manager.create("worker1", "/path/to/worker.ts");
|
|
72
|
-
expect(manager.size).toBe(1);
|
|
73
|
-
|
|
74
|
-
manager.create("worker2", "/path/to/worker.ts");
|
|
75
|
-
expect(manager.size).toBe(2);
|
|
76
|
-
});
|
|
77
|
-
|
|
78
|
-
it("retrieves list of all Worker IDs", () => {
|
|
79
|
-
const manager = new WorkerManager();
|
|
80
|
-
manager.create("worker1", "/path/to/worker.ts");
|
|
81
|
-
manager.create("worker2", "/path/to/worker.ts");
|
|
82
|
-
|
|
83
|
-
const ids = manager.ids;
|
|
84
|
-
|
|
85
|
-
expect(ids).toEqual(["worker1", "worker2"]);
|
|
86
|
-
});
|
|
87
|
-
|
|
88
54
|
it("overwrites existing Worker when creating with the same ID", () => {
|
|
89
55
|
const manager = new WorkerManager();
|
|
90
56
|
const worker1 = manager.create("same-id", "/path/to/worker1.ts");
|
|
@@ -156,33 +156,4 @@ describe("loadIgnorePatterns", () => {
|
|
|
156
156
|
expect(mockJitiImportFn).toHaveBeenCalledWith(expect.stringContaining("eslint.config.mts"));
|
|
157
157
|
});
|
|
158
158
|
|
|
159
|
-
it("returns empty pattern array if empty array exported", async () => {
|
|
160
|
-
const cwd = "/project";
|
|
161
|
-
const mockExists = vi.mocked(fsExists);
|
|
162
|
-
|
|
163
|
-
mockExists.mockImplementation((filePath: string) => {
|
|
164
|
-
return Promise.resolve(filePath === path.join(cwd, "eslint.config.ts"));
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
mockJitiImportFn.mockResolvedValue({
|
|
168
|
-
default: [],
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
const patterns = await loadIgnorePatterns(cwd);
|
|
172
|
-
|
|
173
|
-
expect(patterns).toEqual([]);
|
|
174
|
-
});
|
|
175
|
-
|
|
176
|
-
it("propagates error if jiti import fails", async () => {
|
|
177
|
-
const cwd = "/project";
|
|
178
|
-
const mockExists = vi.mocked(fsExists);
|
|
179
|
-
|
|
180
|
-
mockExists.mockImplementation((filePath: string) => {
|
|
181
|
-
return Promise.resolve(filePath === path.join(cwd, "eslint.config.ts"));
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
mockJitiImportFn.mockRejectedValue(new Error("Syntax error in config file"));
|
|
185
|
-
|
|
186
|
-
await expect(loadIgnorePatterns(cwd)).rejects.toThrow("Syntax error in config file");
|
|
187
|
-
});
|
|
188
159
|
});
|
|
@@ -65,28 +65,6 @@ describe("loadSdConfig", () => {
|
|
|
65
65
|
);
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
-
it("throws error if return value is wrong format (packages is array)", async () => {
|
|
69
|
-
vi.mocked(fsExists).mockResolvedValue(true);
|
|
70
|
-
mockJitiImport.mockResolvedValue({
|
|
71
|
-
default: () => ({ packages: [] }), // packages is array
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
await expect(loadSdConfig({ cwd: "/project", dev: false, opt: [] })).rejects.toThrow(
|
|
75
|
-
/sd\.config\.ts return value is not in .* correct format/,
|
|
76
|
-
);
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
it("throws error if return value is wrong format (packages is null)", async () => {
|
|
80
|
-
vi.mocked(fsExists).mockResolvedValue(true);
|
|
81
|
-
mockJitiImport.mockResolvedValue({
|
|
82
|
-
default: () => ({ packages: null }),
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
await expect(loadSdConfig({ cwd: "/project", dev: false, opt: [] })).rejects.toThrow(
|
|
86
|
-
/sd\.config\.ts return value is not in .* correct format/,
|
|
87
|
-
);
|
|
88
|
-
});
|
|
89
|
-
|
|
90
68
|
it("returns correct config", async () => {
|
|
91
69
|
vi.mocked(fsExists).mockResolvedValue(true);
|
|
92
70
|
mockJitiImport.mockResolvedValue({
|
|
@@ -117,21 +95,4 @@ describe("loadSdConfig", () => {
|
|
|
117
95
|
expect(config.packages).toEqual({});
|
|
118
96
|
});
|
|
119
97
|
|
|
120
|
-
it("handles async function default export correctly", async () => {
|
|
121
|
-
vi.mocked(fsExists).mockResolvedValue(true);
|
|
122
|
-
mockJitiImport.mockResolvedValue({
|
|
123
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
124
|
-
default: async () => ({
|
|
125
|
-
packages: {
|
|
126
|
-
"core-common": { target: "neutral" },
|
|
127
|
-
},
|
|
128
|
-
}),
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
const config = await loadSdConfig({ cwd: "/project", dev: false, opt: [] });
|
|
132
|
-
|
|
133
|
-
expect(config.packages).toEqual({
|
|
134
|
-
"core-common": { target: "neutral" },
|
|
135
|
-
});
|
|
136
|
-
});
|
|
137
98
|
});
|
package/tests/run-lint.spec.ts
CHANGED
|
@@ -255,25 +255,6 @@ describe("runLint", () => {
|
|
|
255
255
|
expect(mockState.lintedFiles).toHaveLength(0);
|
|
256
256
|
});
|
|
257
257
|
|
|
258
|
-
it("does not set exitCode when only warnings exist", async () => {
|
|
259
|
-
const cwd = "/project";
|
|
260
|
-
vi.mocked(fsExists).mockImplementation((filePath: string) => {
|
|
261
|
-
return Promise.resolve(filePath === path.join(cwd, "eslint.config.ts"));
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
mockJitiImportFn.mockResolvedValue({
|
|
265
|
-
default: [{ ignores: ["node_modules/**"] }],
|
|
266
|
-
});
|
|
267
|
-
|
|
268
|
-
vi.mocked(fsGlob).mockResolvedValue(["/project/src/index.ts"]);
|
|
269
|
-
|
|
270
|
-
mockState.lintResults = [{ errorCount: 0, warningCount: 3 }];
|
|
271
|
-
|
|
272
|
-
await runLint({ targets: [], fix: false, timing: false });
|
|
273
|
-
|
|
274
|
-
expect(process.exitCode).toBeUndefined();
|
|
275
|
-
});
|
|
276
|
-
|
|
277
258
|
it("sets TIMING environment variable when timing option is enabled", async () => {
|
|
278
259
|
const cwd = "/project";
|
|
279
260
|
vi.mocked(fsExists).mockImplementation((filePath: string) => {
|
|
@@ -326,20 +307,6 @@ describe("runLint", () => {
|
|
|
326
307
|
expect(process.exitCode).toBeUndefined();
|
|
327
308
|
});
|
|
328
309
|
|
|
329
|
-
it("propagates error when glob fails", async () => {
|
|
330
|
-
const cwd = "/project";
|
|
331
|
-
vi.mocked(fsExists).mockImplementation((filePath: string) => {
|
|
332
|
-
return Promise.resolve(filePath === path.join(cwd, "eslint.config.ts"));
|
|
333
|
-
});
|
|
334
|
-
|
|
335
|
-
mockJitiImportFn.mockResolvedValue({
|
|
336
|
-
default: [{ ignores: ["node_modules/**"] }],
|
|
337
|
-
});
|
|
338
|
-
|
|
339
|
-
vi.mocked(fsGlob).mockRejectedValue(new Error("Glob error"));
|
|
340
|
-
|
|
341
|
-
await expect(runLint({ targets: [], fix: false, timing: false })).rejects.toThrow("Glob error");
|
|
342
|
-
});
|
|
343
310
|
});
|
|
344
311
|
|
|
345
312
|
describe("executeLint", () => {
|
|
@@ -392,24 +359,4 @@ describe("executeLint", () => {
|
|
|
392
359
|
expect(result.warningCount).toBe(1);
|
|
393
360
|
});
|
|
394
361
|
|
|
395
|
-
it("includes formatter output in formattedOutput", async () => {
|
|
396
|
-
mockState.lintResults = [{ errorCount: 1, warningCount: 0 }];
|
|
397
|
-
vi.mocked(fsGlob).mockResolvedValue(["/project/packages/core-common/src/index.ts"]);
|
|
398
|
-
|
|
399
|
-
const result = await executeLint({ targets: [], fix: false, timing: false });
|
|
400
|
-
|
|
401
|
-
// MockESLint's formatter returns empty string, so formattedOutput is also empty string
|
|
402
|
-
expect(result.formattedOutput).toBeDefined();
|
|
403
|
-
expect(typeof result.formattedOutput).toBe("string");
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
it("returns success result when no files exist", async () => {
|
|
407
|
-
vi.mocked(fsGlob).mockResolvedValue([]);
|
|
408
|
-
|
|
409
|
-
const result = await executeLint({ targets: [], fix: false, timing: false });
|
|
410
|
-
|
|
411
|
-
expect(result.success).toBe(true);
|
|
412
|
-
expect(result.errorCount).toBe(0);
|
|
413
|
-
expect(result.warningCount).toBe(0);
|
|
414
|
-
});
|
|
415
362
|
});
|