@simplysm/sd-cli 13.0.1 → 13.0.3
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.map +1 -1
- package/dist/commands/lint.js +92 -0
- package/dist/commands/lint.js.map +1 -1
- package/dist/sd-cli.js +1 -1
- package/package.json +5 -4
- package/src/commands/lint.ts +111 -0
- package/src/sd-cli.ts +1 -1
- package/templates/add-client/__CLIENT__/package.json.hbs +1 -1
- package/templates/add-server/__SERVER__/package.json.hbs +2 -2
- package/templates/init/eslint.config.ts.hbs +2 -2
- package/templates/init/package.json.hbs +4 -3
- package/templates/init/stylelint.config.ts.hbs +1 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"AAKA,OAAO,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"AAKA,OAAO,uBAAuB,CAAC;AAO/B;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,0DAA0D;IAC1D,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,gBAAgB;IAChB,GAAG,EAAE,OAAO,CAAC;IACb,+CAA+C;IAC/C,MAAM,EAAE,OAAO,CAAC;CACjB;AAgDD;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CA+BvE;AAgBD;;;;;;;;;;GAUG;AACH,wBAAsB,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA+LjE"}
|
package/dist/commands/lint.js
CHANGED
|
@@ -6,7 +6,16 @@ import { fsExists, fsGlob, pathFilterByTargets } from "@simplysm/core-node";
|
|
|
6
6
|
import "@simplysm/core-common";
|
|
7
7
|
import { SdError } from "@simplysm/core-common";
|
|
8
8
|
import { consola, LogLevels } from "consola";
|
|
9
|
+
import stylelint from "stylelint";
|
|
9
10
|
const ESLINT_CONFIG_FILES = ["eslint.config.ts", "eslint.config.mts", "eslint.config.js", "eslint.config.mjs"];
|
|
11
|
+
const STYLELINT_CONFIG_FILES = [
|
|
12
|
+
"stylelint.config.ts",
|
|
13
|
+
"stylelint.config.mts",
|
|
14
|
+
"stylelint.config.js",
|
|
15
|
+
"stylelint.config.mjs",
|
|
16
|
+
".stylelintrc.json",
|
|
17
|
+
".stylelintrc.yml"
|
|
18
|
+
];
|
|
10
19
|
function isGlobalIgnoresConfig(item) {
|
|
11
20
|
if (item == null || typeof item !== "object") return false;
|
|
12
21
|
if (!("ignores" in item)) return false;
|
|
@@ -42,6 +51,12 @@ async function loadIgnorePatterns(cwd) {
|
|
|
42
51
|
}
|
|
43
52
|
return configs.filter(isGlobalIgnoresConfig).flatMap((item) => item.ignores);
|
|
44
53
|
}
|
|
54
|
+
async function hasStylelintConfig(cwd) {
|
|
55
|
+
for (const f of STYLELINT_CONFIG_FILES) {
|
|
56
|
+
if (await fsExists(path.join(cwd, f))) return true;
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
45
60
|
async function runLint(options) {
|
|
46
61
|
const { targets, fix, timing } = options;
|
|
47
62
|
const cwd = process.cwd();
|
|
@@ -102,6 +117,57 @@ async function runLint(options) {
|
|
|
102
117
|
await ESLint.outputFixes(ctx2.results);
|
|
103
118
|
logger.debug("\uC790\uB3D9 \uC218\uC815 \uC801\uC6A9 \uC644\uB8CC");
|
|
104
119
|
}
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
title: "Stylelint \uC124\uC815 \uD655\uC778",
|
|
123
|
+
task: async (ctx2, task) => {
|
|
124
|
+
ctx2.hasStylelintConfig = await hasStylelintConfig(cwd);
|
|
125
|
+
if (!ctx2.hasStylelintConfig) {
|
|
126
|
+
task.skip("stylelint.config \uD30C\uC77C \uC5C6\uC74C");
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
title: "CSS \uD30C\uC77C \uC218\uC9D1",
|
|
132
|
+
enabled: (ctx2) => ctx2.hasStylelintConfig === true,
|
|
133
|
+
task: async (ctx2, task) => {
|
|
134
|
+
let cssFiles = await fsGlob("**/*.css", {
|
|
135
|
+
cwd,
|
|
136
|
+
ignore: ctx2.ignorePatterns,
|
|
137
|
+
nodir: true,
|
|
138
|
+
absolute: true
|
|
139
|
+
});
|
|
140
|
+
cssFiles = pathFilterByTargets(cssFiles, targets, cwd);
|
|
141
|
+
ctx2.cssFiles = cssFiles;
|
|
142
|
+
task.title = `CSS \uD30C\uC77C \uC218\uC9D1 (${cssFiles.length}\uAC1C)`;
|
|
143
|
+
if (cssFiles.length === 0) {
|
|
144
|
+
task.skip("\uB9B0\uD2B8\uD560 CSS \uD30C\uC77C\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.");
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
title: "Stylelint \uC2E4\uD589",
|
|
150
|
+
enabled: (ctx2) => (ctx2.cssFiles?.length ?? 0) > 0,
|
|
151
|
+
task: async (ctx2, task) => {
|
|
152
|
+
const cssFiles = ctx2.cssFiles;
|
|
153
|
+
task.title = `Stylelint \uC2E4\uD589 \uC911... (${cssFiles.length}\uAC1C \uD30C\uC77C)`;
|
|
154
|
+
let configFile;
|
|
155
|
+
for (const f of STYLELINT_CONFIG_FILES) {
|
|
156
|
+
const configPath = path.join(cwd, f);
|
|
157
|
+
if (await fsExists(configPath)) {
|
|
158
|
+
configFile = configPath;
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
const result = await stylelint.lint({
|
|
163
|
+
files: cssFiles,
|
|
164
|
+
configFile,
|
|
165
|
+
fix,
|
|
166
|
+
cache: true,
|
|
167
|
+
cacheLocation: path.join(cwd, ".cache", "stylelint.cache")
|
|
168
|
+
});
|
|
169
|
+
ctx2.stylelintResult = result;
|
|
170
|
+
}
|
|
105
171
|
}
|
|
106
172
|
],
|
|
107
173
|
{
|
|
@@ -130,6 +196,32 @@ async function runLint(options) {
|
|
|
130
196
|
if (errorCount > 0) {
|
|
131
197
|
process.exitCode = 1;
|
|
132
198
|
}
|
|
199
|
+
if (ctx.stylelintResult != null && ctx.stylelintResult.results.length > 0) {
|
|
200
|
+
const stylelintErrorCount = ctx.stylelintResult.results.sum(
|
|
201
|
+
(r) => r.warnings.filter((w) => w.severity === "error").length
|
|
202
|
+
);
|
|
203
|
+
const stylelintWarningCount = ctx.stylelintResult.results.sum(
|
|
204
|
+
(r) => r.warnings.filter((w) => w.severity === "warning").length
|
|
205
|
+
);
|
|
206
|
+
if (stylelintErrorCount > 0) {
|
|
207
|
+
logger.error("Stylelint \uC5D0\uB7EC \uBC1C\uC0DD", { errorCount: stylelintErrorCount, warningCount: stylelintWarningCount });
|
|
208
|
+
} else if (stylelintWarningCount > 0) {
|
|
209
|
+
logger.info("Stylelint \uC644\uB8CC (\uACBD\uACE0 \uC788\uC74C)", {
|
|
210
|
+
errorCount: stylelintErrorCount,
|
|
211
|
+
warningCount: stylelintWarningCount
|
|
212
|
+
});
|
|
213
|
+
} else {
|
|
214
|
+
logger.info("Stylelint \uC644\uB8CC", { errorCount: stylelintErrorCount, warningCount: stylelintWarningCount });
|
|
215
|
+
}
|
|
216
|
+
const stylelintFormatter = await stylelint.formatters.string;
|
|
217
|
+
const stylelintOutput = stylelintFormatter(ctx.stylelintResult.results, ctx.stylelintResult);
|
|
218
|
+
if (stylelintOutput) {
|
|
219
|
+
process.stdout.write(stylelintOutput);
|
|
220
|
+
}
|
|
221
|
+
if (stylelintErrorCount > 0) {
|
|
222
|
+
process.exitCode = 1;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
133
225
|
}
|
|
134
226
|
export {
|
|
135
227
|
loadIgnorePatterns,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/commands/lint.ts"],
|
|
4
|
-
"mappings": "AAAA,SAAS,cAAc;AACvB,SAAS,kBAAkB;AAC3B,OAAO,UAAU;AACjB,SAAS,aAAa;AACtB,SAAS,UAAU,QAAQ,2BAA2B;AACtD,OAAO;AACP,SAAS,eAAe;AACxB,SAAS,SAAS,iBAAiB;
|
|
4
|
+
"mappings": "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",
|
|
5
5
|
"names": ["ctx"]
|
|
6
6
|
}
|
package/dist/sd-cli.js
CHANGED
|
@@ -27,7 +27,7 @@ function createCliParser(argv) {
|
|
|
27
27
|
if (args.debug) consola.level = LogLevels.debug;
|
|
28
28
|
}).command(
|
|
29
29
|
"lint [targets..]",
|
|
30
|
-
"ESLint\uB97C \uC2E4\uD589\uD55C\uB2E4.",
|
|
30
|
+
"ESLint + Stylelint\uB97C \uC2E4\uD589\uD55C\uB2E4.",
|
|
31
31
|
(cmd) => cmd.version(false).hide("help").positional("targets", {
|
|
32
32
|
type: "string",
|
|
33
33
|
array: true,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simplysm/sd-cli",
|
|
3
3
|
"sideEffects": false,
|
|
4
|
-
"version": "13.0.
|
|
4
|
+
"version": "13.0.3",
|
|
5
5
|
"description": "심플리즘 패키지 - CLI 도구",
|
|
6
6
|
"author": "김석래",
|
|
7
7
|
"repository": {
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"sharp": "^0.34.5",
|
|
37
37
|
"solid-js": "^1.9.11",
|
|
38
38
|
"ssh2": "^1.17.0",
|
|
39
|
+
"stylelint": "^16.26.1",
|
|
39
40
|
"tailwindcss": "^3.4.19",
|
|
40
41
|
"ts-morph": "^27.0.2",
|
|
41
42
|
"typescript": "^5.9.3",
|
|
@@ -44,9 +45,9 @@
|
|
|
44
45
|
"vite-plugin-solid": "^2.11.10",
|
|
45
46
|
"vite-tsconfig-paths": "^6.1.0",
|
|
46
47
|
"yargs": "^18.0.0",
|
|
47
|
-
"@simplysm/core-common": "13.0.
|
|
48
|
-
"@simplysm/core-node": "13.0.
|
|
49
|
-
"@simplysm/storage": "13.0.
|
|
48
|
+
"@simplysm/core-common": "13.0.3",
|
|
49
|
+
"@simplysm/core-node": "13.0.3",
|
|
50
|
+
"@simplysm/storage": "13.0.3"
|
|
50
51
|
},
|
|
51
52
|
"devDependencies": {
|
|
52
53
|
"@types/semver": "^7.7.1",
|
package/src/commands/lint.ts
CHANGED
|
@@ -6,6 +6,7 @@ import { fsExists, fsGlob, pathFilterByTargets } from "@simplysm/core-node";
|
|
|
6
6
|
import "@simplysm/core-common";
|
|
7
7
|
import { SdError } from "@simplysm/core-common";
|
|
8
8
|
import { consola, LogLevels } from "consola";
|
|
9
|
+
import stylelint from "stylelint";
|
|
9
10
|
|
|
10
11
|
//#region Types
|
|
11
12
|
|
|
@@ -32,6 +33,10 @@ interface LintContext {
|
|
|
32
33
|
eslint?: ESLint;
|
|
33
34
|
/** 린트 대상 파일이 있을 때만 초기화됨 */
|
|
34
35
|
results?: ESLint.LintResult[];
|
|
36
|
+
// Stylelint
|
|
37
|
+
hasStylelintConfig?: boolean;
|
|
38
|
+
cssFiles?: string[];
|
|
39
|
+
stylelintResult?: stylelint.LinterResult;
|
|
35
40
|
}
|
|
36
41
|
|
|
37
42
|
//#endregion
|
|
@@ -41,6 +46,16 @@ interface LintContext {
|
|
|
41
46
|
/** ESLint 설정 파일 탐색 순서 */
|
|
42
47
|
const ESLINT_CONFIG_FILES = ["eslint.config.ts", "eslint.config.mts", "eslint.config.js", "eslint.config.mjs"] as const;
|
|
43
48
|
|
|
49
|
+
/** Stylelint 설정 파일 탐색 순서 */
|
|
50
|
+
const STYLELINT_CONFIG_FILES = [
|
|
51
|
+
"stylelint.config.ts",
|
|
52
|
+
"stylelint.config.mts",
|
|
53
|
+
"stylelint.config.js",
|
|
54
|
+
"stylelint.config.mjs",
|
|
55
|
+
".stylelintrc.json",
|
|
56
|
+
".stylelintrc.yml",
|
|
57
|
+
] as const;
|
|
58
|
+
|
|
44
59
|
/**
|
|
45
60
|
* ignores 속성만 가진 ESLint 설정 객체인지 검사하는 타입 가드
|
|
46
61
|
*/
|
|
@@ -91,6 +106,16 @@ export async function loadIgnorePatterns(cwd: string): Promise<string[]> {
|
|
|
91
106
|
return configs.filter(isGlobalIgnoresConfig).flatMap((item) => item.ignores);
|
|
92
107
|
}
|
|
93
108
|
|
|
109
|
+
/**
|
|
110
|
+
* Stylelint 설정 파일이 존재하는지 확인한다.
|
|
111
|
+
*/
|
|
112
|
+
async function hasStylelintConfig(cwd: string): Promise<boolean> {
|
|
113
|
+
for (const f of STYLELINT_CONFIG_FILES) {
|
|
114
|
+
if (await fsExists(path.join(cwd, f))) return true;
|
|
115
|
+
}
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
94
119
|
//#endregion
|
|
95
120
|
|
|
96
121
|
//#region Main
|
|
@@ -174,6 +199,60 @@ export async function runLint(options: LintOptions): Promise<void> {
|
|
|
174
199
|
logger.debug("자동 수정 적용 완료");
|
|
175
200
|
},
|
|
176
201
|
},
|
|
202
|
+
{
|
|
203
|
+
title: "Stylelint 설정 확인",
|
|
204
|
+
task: async (ctx, task) => {
|
|
205
|
+
ctx.hasStylelintConfig = await hasStylelintConfig(cwd);
|
|
206
|
+
if (!ctx.hasStylelintConfig) {
|
|
207
|
+
task.skip("stylelint.config 파일 없음");
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
title: "CSS 파일 수집",
|
|
213
|
+
enabled: (ctx) => ctx.hasStylelintConfig === true,
|
|
214
|
+
task: async (ctx, task) => {
|
|
215
|
+
let cssFiles = await fsGlob("**/*.css", {
|
|
216
|
+
cwd,
|
|
217
|
+
ignore: ctx.ignorePatterns,
|
|
218
|
+
nodir: true,
|
|
219
|
+
absolute: true,
|
|
220
|
+
});
|
|
221
|
+
cssFiles = pathFilterByTargets(cssFiles, targets, cwd);
|
|
222
|
+
ctx.cssFiles = cssFiles;
|
|
223
|
+
task.title = `CSS 파일 수집 (${cssFiles.length}개)`;
|
|
224
|
+
if (cssFiles.length === 0) {
|
|
225
|
+
task.skip("린트할 CSS 파일이 없습니다.");
|
|
226
|
+
}
|
|
227
|
+
},
|
|
228
|
+
},
|
|
229
|
+
{
|
|
230
|
+
title: "Stylelint 실행",
|
|
231
|
+
enabled: (ctx) => (ctx.cssFiles?.length ?? 0) > 0,
|
|
232
|
+
task: async (ctx, task) => {
|
|
233
|
+
const cssFiles = ctx.cssFiles!;
|
|
234
|
+
task.title = `Stylelint 실행 중... (${cssFiles.length}개 파일)`;
|
|
235
|
+
|
|
236
|
+
// Stylelint 설정 파일 경로 찾기
|
|
237
|
+
let configFile: string | undefined;
|
|
238
|
+
for (const f of STYLELINT_CONFIG_FILES) {
|
|
239
|
+
const configPath = path.join(cwd, f);
|
|
240
|
+
if (await fsExists(configPath)) {
|
|
241
|
+
configFile = configPath;
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
const result = await stylelint.lint({
|
|
247
|
+
files: cssFiles,
|
|
248
|
+
configFile,
|
|
249
|
+
fix,
|
|
250
|
+
cache: true,
|
|
251
|
+
cacheLocation: path.join(cwd, ".cache", "stylelint.cache"),
|
|
252
|
+
});
|
|
253
|
+
ctx.stylelintResult = result;
|
|
254
|
+
},
|
|
255
|
+
},
|
|
177
256
|
],
|
|
178
257
|
{
|
|
179
258
|
renderer: consola.level >= LogLevels.debug ? "verbose" : "default",
|
|
@@ -211,6 +290,38 @@ export async function runLint(options: LintOptions): Promise<void> {
|
|
|
211
290
|
if (errorCount > 0) {
|
|
212
291
|
process.exitCode = 1;
|
|
213
292
|
}
|
|
293
|
+
|
|
294
|
+
// Stylelint 결과 출력
|
|
295
|
+
if (ctx.stylelintResult != null && ctx.stylelintResult.results.length > 0) {
|
|
296
|
+
const stylelintErrorCount = ctx.stylelintResult.results.sum(
|
|
297
|
+
(r) => r.warnings.filter((w) => w.severity === "error").length,
|
|
298
|
+
);
|
|
299
|
+
const stylelintWarningCount = ctx.stylelintResult.results.sum(
|
|
300
|
+
(r) => r.warnings.filter((w) => w.severity === "warning").length,
|
|
301
|
+
);
|
|
302
|
+
|
|
303
|
+
if (stylelintErrorCount > 0) {
|
|
304
|
+
logger.error("Stylelint 에러 발생", { errorCount: stylelintErrorCount, warningCount: stylelintWarningCount });
|
|
305
|
+
} else if (stylelintWarningCount > 0) {
|
|
306
|
+
logger.info("Stylelint 완료 (경고 있음)", {
|
|
307
|
+
errorCount: stylelintErrorCount,
|
|
308
|
+
warningCount: stylelintWarningCount,
|
|
309
|
+
});
|
|
310
|
+
} else {
|
|
311
|
+
logger.info("Stylelint 완료", { errorCount: stylelintErrorCount, warningCount: stylelintWarningCount });
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Stylelint formatter 출력
|
|
315
|
+
const stylelintFormatter = await stylelint.formatters.string;
|
|
316
|
+
const stylelintOutput = stylelintFormatter(ctx.stylelintResult.results, ctx.stylelintResult);
|
|
317
|
+
if (stylelintOutput) {
|
|
318
|
+
process.stdout.write(stylelintOutput);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
if (stylelintErrorCount > 0) {
|
|
322
|
+
process.exitCode = 1;
|
|
323
|
+
}
|
|
324
|
+
}
|
|
214
325
|
}
|
|
215
326
|
|
|
216
327
|
//#endregion
|
package/src/sd-cli.ts
CHANGED
|
@@ -15,12 +15,13 @@
|
|
|
15
15
|
"vitest": "vitest"
|
|
16
16
|
},
|
|
17
17
|
"devDependencies": {
|
|
18
|
-
"@simplysm/sd-cli": "~13.0.
|
|
19
|
-
"@simplysm/claude": "~13.0.
|
|
20
|
-
"@simplysm/
|
|
18
|
+
"@simplysm/sd-cli": "~13.0.3",
|
|
19
|
+
"@simplysm/claude": "~13.0.3",
|
|
20
|
+
"@simplysm/lint": "~13.0.3",
|
|
21
21
|
"@types/node": "^20.19.33",
|
|
22
22
|
"eslint": "^9.39.2",
|
|
23
23
|
"prettier": "^3.8.1",
|
|
24
|
+
"stylelint": "^16.13.0",
|
|
24
25
|
"typescript": "^5.9.3",
|
|
25
26
|
"vite-tsconfig-paths": "^6.1.0",
|
|
26
27
|
"vitest": "^4.0.18"
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default } from "@simplysm/lint/stylelint-recommended";
|