byuckchon-frontend-cli 1.9.7 → 1.10.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/README.md +59 -5
- package/package.json +8 -2
- package/src/commands/adopt.js +12 -3
- package/src/constants/versions.js +12 -46
- package/src/generators/createApp.js +13 -29
- package/src/generators/createBaseFiles.js +79 -311
- package/src/generators/createFolders.js +17 -1
- package/src/generators/createMonorepo.js +49 -236
- package/src/generators/createPackageJson.js +10 -11
- package/src/generators/scaffoldReviewAutomation.js +51 -30
- package/src/utils/ensureRequiredDependencies.js +35 -9
- package/src/utils/settingsAssets.js +27 -0
- package/templates/review-automation/github/pull_request_template.md +30 -0
- package/templates/review-automation/github/workflows/eslint-convention-review.monorepo.yml +8 -6
- package/templates/review-automation/github/workflows/eslint-convention-review.single.yml +6 -6
- package/templates/review-automation/github/workflows/pr-check.monorepo.yml +51 -0
- package/templates/review-automation/github/workflows/pr-check.single.yml +47 -0
- package/templates/review-automation/github/workflows/pr-description.yml +58 -0
- package/templates/review-automation/tools/review.config.mjs +9 -0
- package/templates/review-automation/tools/eslint-rules/internal-blocking-conventions.js +0 -1242
- package/templates/review-automation/tools/eslint-rules/internal-plugin.cjs +0 -8
- package/templates/review-automation/tools/eslint-rules/internal-rdjson-formatter.js +0 -60
- package/templates/review-automation/tools/eslint-rules/internal-warning-conventions.js +0 -57
- package/templates/review-automation/tools/eslint-rules/package.json +0 -3
- package/templates/review-automation/tools/eslint-rules/review.config.mjs +0 -22
- package/templates/review-automation/tools/post-eslint-review-comments.cjs +0 -309
|
@@ -1,201 +1,77 @@
|
|
|
1
1
|
import fs from "fs/promises";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
2
3
|
import path from "path";
|
|
3
4
|
|
|
5
|
+
// JSON import attributes 는 Node 22+ 라서, Node 18 지원을 위해 createRequire 로 읽는다.
|
|
6
|
+
const require = createRequire(import.meta.url);
|
|
7
|
+
const vscodeSettings = require("@byuckchon-frontend/settings/vscode");
|
|
8
|
+
|
|
9
|
+
import { readSettingsAsset } from "../utils/settingsAssets.js";
|
|
10
|
+
|
|
4
11
|
async function write(filePath, content) {
|
|
5
12
|
await fs.writeFile(filePath, content, "utf-8");
|
|
6
13
|
}
|
|
7
14
|
|
|
8
|
-
const TOKEN_CONFIG_JS =
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
// color는 Tailwind 유틸리티로, typography는 .text-* 클래스로 생성
|
|
22
|
-
StyleDictionary.registerFormat({
|
|
23
|
-
name: "css/tailwind-theme",
|
|
24
|
-
format: ({ dictionary }) => {
|
|
25
|
-
let css = "";
|
|
26
|
-
const withPx = (value) =>
|
|
27
|
-
typeof value === "string" && /^\\d+(\\.\\d+)?$/.test(value)
|
|
28
|
-
? \`\${value}px\`
|
|
29
|
-
: value;
|
|
30
|
-
|
|
31
|
-
css += "@theme {\\n";
|
|
32
|
-
dictionary.allTokens.forEach((token) => {
|
|
33
|
-
if (token.$type === "color") {
|
|
34
|
-
css += \` --color-\${token.name}: \${token.$value};\\n\`;
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
css += "}\\n\\n";
|
|
38
|
-
|
|
39
|
-
css += "@layer components {\\n";
|
|
40
|
-
dictionary.allTokens.forEach((token) => {
|
|
41
|
-
if (token.$type === "typography" && token.$value) {
|
|
42
|
-
const typo = token.$value;
|
|
43
|
-
css += \` .text-\${token.name} {\\n\`;
|
|
44
|
-
if (typo.fontSize) {
|
|
45
|
-
css += \` font-size: \${withPx(typo.fontSize)};\\n\`;
|
|
46
|
-
}
|
|
47
|
-
if (typo.lineHeight) {
|
|
48
|
-
css += \` line-height: \${withPx(typo.lineHeight)};\\n\`;
|
|
49
|
-
}
|
|
50
|
-
if (typo.letterSpacing) {
|
|
51
|
-
css += \` letter-spacing: \${typo.letterSpacing};\\n\`;
|
|
52
|
-
}
|
|
53
|
-
if (typo.fontWeight) {
|
|
54
|
-
css += \` font-weight: \${typo.fontWeight};\\n\`;
|
|
55
|
-
}
|
|
56
|
-
if (typo.fontFamily) {
|
|
57
|
-
css += \` font-family: \${typo.fontFamily};\\n\`;
|
|
58
|
-
}
|
|
59
|
-
css += " }\\n";
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
css += "}\\n";
|
|
63
|
-
|
|
64
|
-
return css;
|
|
65
|
-
},
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
export default {
|
|
69
|
-
source: ["src/tokens.json"],
|
|
70
|
-
platforms: {
|
|
71
|
-
css: {
|
|
72
|
-
transforms: ["name/kebab"], // 일단 attribute/cti 제거
|
|
73
|
-
buildPath: "src/",
|
|
74
|
-
files: [
|
|
75
|
-
{
|
|
76
|
-
destination: "tokens.css",
|
|
77
|
-
format: "css/tailwind-theme",
|
|
78
|
-
},
|
|
79
|
-
],
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
};
|
|
15
|
+
const TOKEN_CONFIG_JS = `/**
|
|
16
|
+
* 디자이너가 넘긴 src/tokens.json 을 src/tokens.css 로 변환하는 설정.
|
|
17
|
+
*
|
|
18
|
+
* npm run tokens:build
|
|
19
|
+
*
|
|
20
|
+
* 변환 규칙(color / typography / motion)은 @byuckchon-frontend/settings 가
|
|
21
|
+
* 관리한다. 규칙이 바뀌면 settings 버전만 올리면 되고 이 파일은 그대로 둔다.
|
|
22
|
+
* 프로젝트별 예외가 필요하면 defineTokenConfig({ ... }) 에 인자를 넘긴다.
|
|
23
|
+
*/
|
|
24
|
+
import { defineTokenConfig } from "@byuckchon-frontend/settings/tokens";
|
|
25
|
+
|
|
26
|
+
export default defineTokenConfig();
|
|
83
27
|
`;
|
|
84
28
|
|
|
85
29
|
// ─── 공통 설정 파일 ────────────────────────────────────────────────────────────
|
|
86
30
|
|
|
87
31
|
async function createPrettierConfig(rootDir) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
trailingComma: "all",
|
|
91
|
-
singleQuote: true,
|
|
92
|
-
tabWidth: 2,
|
|
93
|
-
useTabs: false,
|
|
94
|
-
printWidth: 80,
|
|
95
|
-
plugins: [
|
|
96
|
-
"@trivago/prettier-plugin-sort-imports",
|
|
97
|
-
"prettier-plugin-tailwindcss",
|
|
98
|
-
],
|
|
99
|
-
importOrder: ["^@core/(.*)$", "^@server/(.*)$", "^@ui/(.*)$", "^[./]"],
|
|
100
|
-
importOrderSeparation: true,
|
|
101
|
-
importOrderSortSpecifiers: true,
|
|
102
|
-
};
|
|
32
|
+
// 규칙 본체는 @byuckchon-frontend/settings 가 관리한다.
|
|
33
|
+
// 프로젝트는 참조만 하므로, 팀 표준이 바뀌면 settings 버전만 올리면 된다.
|
|
103
34
|
await write(
|
|
104
|
-
path.join(rootDir, ".
|
|
105
|
-
|
|
35
|
+
path.join(rootDir, "prettier.config.js"),
|
|
36
|
+
`import byuckchon from '@byuckchon-frontend/settings/prettier';
|
|
37
|
+
|
|
38
|
+
/** 프로젝트 예외가 필요하면 펼쳐서 덮어쓰세요. (예: printWidth: 100) */
|
|
39
|
+
export default byuckchon;
|
|
40
|
+
`
|
|
106
41
|
);
|
|
107
42
|
}
|
|
108
43
|
|
|
109
44
|
async function createEslintConfig(rootDir) {
|
|
110
45
|
await write(
|
|
111
|
-
path.join(rootDir, ".
|
|
112
|
-
`
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
'unused-imports/no-unused-imports': 'error',
|
|
122
|
-
'unused-imports/no-unused-vars': [
|
|
123
|
-
'warn',
|
|
124
|
-
{
|
|
125
|
-
vars: 'all',
|
|
126
|
-
varsIgnorePattern: '^_',
|
|
127
|
-
args: 'after-used',
|
|
128
|
-
argsIgnorePattern: '^_',
|
|
129
|
-
},
|
|
130
|
-
],
|
|
131
|
-
'react/self-closing-comp': [
|
|
132
|
-
'warn',
|
|
133
|
-
{
|
|
134
|
-
component: true,
|
|
135
|
-
html: true,
|
|
136
|
-
},
|
|
137
|
-
],
|
|
138
|
-
},
|
|
139
|
-
settings: {
|
|
140
|
-
'import/resolver': {
|
|
141
|
-
typescript: {},
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
|
-
};
|
|
46
|
+
path.join(rootDir, "eslint.config.js"),
|
|
47
|
+
`import byuckchon from '@byuckchon-frontend/settings/eslint/react';
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 규칙 본체는 @byuckchon-frontend/settings 가 관리합니다.
|
|
51
|
+
* 프로젝트 예외는 뒤에 이어붙이세요.
|
|
52
|
+
*
|
|
53
|
+
* export default [...byuckchon, { rules: { 'import/order': 'off' } }];
|
|
54
|
+
*/
|
|
55
|
+
export default byuckchon;
|
|
145
56
|
`
|
|
146
57
|
);
|
|
147
58
|
}
|
|
148
59
|
|
|
149
60
|
async function createNextEslintConfig(rootDir) {
|
|
61
|
+
// next/core-web-vitals 는 설치된 next 버전과 짝을 이뤄야 해서 settings 가 들고 있지 않다.
|
|
62
|
+
// 프로젝트 쪽에서 합친다.
|
|
150
63
|
await write(
|
|
151
|
-
path.join(rootDir, ".
|
|
152
|
-
|
|
153
|
-
/** @type {import("eslint").Linter.Config} */
|
|
154
|
-
|
|
155
|
-
module.exports = {
|
|
156
|
-
root: true,
|
|
64
|
+
path.join(rootDir, "eslint.config.mjs"),
|
|
65
|
+
`import { FlatCompat } from '@eslint/eslintrc';
|
|
157
66
|
|
|
158
|
-
|
|
159
|
-
extends: ["next/core-web-vitals", "next/typescript"],
|
|
67
|
+
import byuckchon from '@byuckchon-frontend/settings/eslint/next';
|
|
160
68
|
|
|
161
|
-
|
|
162
|
-
plugins: ["import"],
|
|
163
|
-
|
|
164
|
-
rules: {
|
|
165
|
-
"@typescript-eslint/no-explicit-any": "off",
|
|
166
|
-
"import/order": [
|
|
167
|
-
"error",
|
|
168
|
-
{
|
|
169
|
-
// builtin: node 내장 모듈, external: npm 패키지, internal: 프로젝트 내 모듈, parent: 상위 경로, sibling: 형제 경로, index: 인덱스 파일
|
|
170
|
-
groups: ["builtin", "external", "internal", "parent", "sibling", "index"],
|
|
171
|
-
// 특정 패턴 그룹에 속하는 모듈 순서 지정
|
|
172
|
-
pathGroups: [
|
|
173
|
-
{
|
|
174
|
-
pattern: "react",
|
|
175
|
-
group: "external",
|
|
176
|
-
position: "before",
|
|
177
|
-
},
|
|
178
|
-
{
|
|
179
|
-
pattern: "next/**",
|
|
180
|
-
group: "external",
|
|
181
|
-
position: "before",
|
|
182
|
-
},
|
|
183
|
-
{
|
|
184
|
-
pattern: "@/**",
|
|
185
|
-
group: "internal",
|
|
186
|
-
},
|
|
187
|
-
],
|
|
188
|
-
// 중복 정렬 방지
|
|
189
|
-
pathGroupsExcludedImportTypes: ["react"],
|
|
190
|
-
// 알파벳 순서대로 오름차순 정렬
|
|
191
|
-
alphabetize: { order: "asc", caseInsensitive: true },
|
|
192
|
-
},
|
|
193
|
-
],
|
|
194
|
-
},
|
|
69
|
+
const compat = new FlatCompat({ baseDirectory: import.meta.dirname });
|
|
195
70
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
71
|
+
export default [
|
|
72
|
+
...compat.extends('next/core-web-vitals', 'next/typescript'),
|
|
73
|
+
...byuckchon,
|
|
74
|
+
];
|
|
199
75
|
`
|
|
200
76
|
);
|
|
201
77
|
}
|
|
@@ -228,17 +104,13 @@ Thumbs.db
|
|
|
228
104
|
npm-debug.log*
|
|
229
105
|
yarn-error.log*
|
|
230
106
|
|
|
231
|
-
#
|
|
232
|
-
node_modules
|
|
233
|
-
dist
|
|
234
|
-
dist-ssr
|
|
235
|
-
*.local
|
|
236
|
-
*.md
|
|
237
|
-
!README.md
|
|
107
|
+
# bc CLI
|
|
238
108
|
.bc/
|
|
239
|
-
.env
|
|
240
|
-
.env.production
|
|
241
109
|
.history
|
|
110
|
+
|
|
111
|
+
# Misc
|
|
112
|
+
dist-ssr/
|
|
113
|
+
*.local
|
|
242
114
|
`;
|
|
243
115
|
|
|
244
116
|
const nextExtra = `
|
|
@@ -254,27 +126,14 @@ out/
|
|
|
254
126
|
}
|
|
255
127
|
|
|
256
128
|
async function createVscodeSettings(rootDir) {
|
|
129
|
+
// settings.json 은 extends 가 없어서 참조가 불가능하다. 실제 파일이 있어야 한다.
|
|
130
|
+
// 그래서 settings 가 들고 있는 값을 "복사"하되, 나중에 팀 표준이 바뀌면
|
|
131
|
+
// npx byuckchon-settings-sync vscode
|
|
132
|
+
// 로 다시 맞출 수 있게 한다. 프로젝트가 값을 고치는 것은 자유.
|
|
257
133
|
await fs.mkdir(path.join(rootDir, ".vscode"), { recursive: true });
|
|
258
134
|
await write(
|
|
259
135
|
path.join(rootDir, ".vscode/settings.json"),
|
|
260
|
-
JSON.stringify(
|
|
261
|
-
{
|
|
262
|
-
"editor.defaultFormatter": "esbenp.prettier-vscode",
|
|
263
|
-
"editor.formatOnSave": true,
|
|
264
|
-
"eslint.validate": [
|
|
265
|
-
"javascript",
|
|
266
|
-
"typescript",
|
|
267
|
-
"javascriptreact",
|
|
268
|
-
"typescriptreact",
|
|
269
|
-
],
|
|
270
|
-
"editor.codeActionsOnSave": {
|
|
271
|
-
"source.organizeImports": "always",
|
|
272
|
-
"source.fixAll.eslint": "always",
|
|
273
|
-
},
|
|
274
|
-
},
|
|
275
|
-
null,
|
|
276
|
-
2
|
|
277
|
-
)
|
|
136
|
+
JSON.stringify(vscodeSettings, null, 2) + "\n"
|
|
278
137
|
);
|
|
279
138
|
}
|
|
280
139
|
|
|
@@ -333,45 +192,27 @@ export default defineConfig({
|
|
|
333
192
|
`
|
|
334
193
|
);
|
|
335
194
|
|
|
336
|
-
// tsconfig
|
|
195
|
+
// tsconfig — 공통 옵션은 @byuckchon-frontend/settings 가 관리한다.
|
|
196
|
+
// 프로젝트에는 경로 alias 처럼 이 프로젝트에만 해당하는 것만 남긴다.
|
|
337
197
|
await write(
|
|
338
198
|
path.join(rootDir, "tsconfig.json"),
|
|
339
199
|
JSON.stringify(
|
|
340
200
|
{
|
|
341
201
|
files: [],
|
|
342
|
-
references: [
|
|
343
|
-
{ path: "./tsconfig.app.json" },
|
|
344
|
-
{ path: "./tsconfig.node.json" },
|
|
345
|
-
],
|
|
202
|
+
references: [{ path: "./tsconfig.app.json" }, { path: "./tsconfig.node.json" }],
|
|
346
203
|
},
|
|
347
204
|
null,
|
|
348
205
|
2
|
|
349
|
-
)
|
|
206
|
+
) + "\n"
|
|
350
207
|
);
|
|
351
208
|
|
|
352
|
-
// tsconfig.app.json
|
|
353
209
|
await write(
|
|
354
210
|
path.join(rootDir, "tsconfig.app.json"),
|
|
355
211
|
JSON.stringify(
|
|
356
212
|
{
|
|
213
|
+
extends: "@byuckchon-frontend/settings/tsconfig/react.json",
|
|
357
214
|
compilerOptions: {
|
|
358
215
|
tsBuildInfoFile: "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
|
|
359
|
-
target: "ES2020",
|
|
360
|
-
useDefineForClassFields: true,
|
|
361
|
-
lib: ["ES2020", "DOM", "DOM.Iterable"],
|
|
362
|
-
module: "ESNext",
|
|
363
|
-
skipLibCheck: true,
|
|
364
|
-
moduleResolution: "bundler",
|
|
365
|
-
allowImportingTsExtensions: true,
|
|
366
|
-
isolatedModules: true,
|
|
367
|
-
moduleDetection: "force",
|
|
368
|
-
noEmit: true,
|
|
369
|
-
jsx: "react-jsx",
|
|
370
|
-
strict: true,
|
|
371
|
-
noUnusedLocals: true,
|
|
372
|
-
noUnusedParameters: true,
|
|
373
|
-
noFallthroughCasesInSwitch: true,
|
|
374
|
-
noUncheckedSideEffectImports: true,
|
|
375
216
|
baseUrl: ".",
|
|
376
217
|
paths: {
|
|
377
218
|
"@/*": ["src/*"],
|
|
@@ -379,42 +220,32 @@ export default defineConfig({
|
|
|
379
220
|
"@images/*": ["src/assets/images/*"],
|
|
380
221
|
},
|
|
381
222
|
},
|
|
382
|
-
include: ["src"
|
|
223
|
+
include: ["src"],
|
|
383
224
|
},
|
|
384
225
|
null,
|
|
385
226
|
2
|
|
386
|
-
)
|
|
227
|
+
) + "\n"
|
|
387
228
|
);
|
|
388
229
|
|
|
389
|
-
// tsconfig.node.json
|
|
390
230
|
await write(
|
|
391
231
|
path.join(rootDir, "tsconfig.node.json"),
|
|
392
232
|
JSON.stringify(
|
|
393
233
|
{
|
|
234
|
+
extends: "@byuckchon-frontend/settings/tsconfig/node.json",
|
|
394
235
|
compilerOptions: {
|
|
395
236
|
tsBuildInfoFile: "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
|
|
396
|
-
target: "ES2022",
|
|
397
|
-
lib: ["ES2023"],
|
|
398
237
|
module: "ESNext",
|
|
399
|
-
|
|
400
|
-
moduleResolution: "bundler",
|
|
401
|
-
allowImportingTsExtensions: true,
|
|
402
|
-
isolatedModules: true,
|
|
403
|
-
moduleDetection: "force",
|
|
404
|
-
noEmit: true,
|
|
405
|
-
strict: true,
|
|
406
|
-
noUnusedLocals: true,
|
|
407
|
-
noUnusedParameters: true,
|
|
408
|
-
noFallthroughCasesInSwitch: true,
|
|
409
|
-
noUncheckedSideEffectImports: true,
|
|
238
|
+
moduleResolution: "Bundler",
|
|
410
239
|
},
|
|
411
240
|
include: ["vite.config.ts"],
|
|
412
241
|
},
|
|
413
242
|
null,
|
|
414
243
|
2
|
|
415
|
-
)
|
|
244
|
+
) + "\n"
|
|
416
245
|
);
|
|
417
246
|
|
|
247
|
+
await write(path.join(rootDir, ".nvmrc"), await readSettingsAsset("project/nvmrc"));
|
|
248
|
+
|
|
418
249
|
await createPrettierConfig(rootDir);
|
|
419
250
|
await createEslintConfig(rootDir);
|
|
420
251
|
await createGitignore(rootDir, "react");
|
|
@@ -450,27 +281,7 @@ createRoot(document.getElementById('root')!).render(<App />);
|
|
|
450
281
|
|
|
451
282
|
await write(
|
|
452
283
|
path.join(rootDir, "src/global.d.ts"),
|
|
453
|
-
|
|
454
|
-
import React from 'react';
|
|
455
|
-
export const ReactComponent: React.FunctionComponent<
|
|
456
|
-
React.SVGProps<SVGSVGElement>
|
|
457
|
-
>;
|
|
458
|
-
const src: string;
|
|
459
|
-
|
|
460
|
-
export default src;
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
declare module '*.svg?react' {
|
|
464
|
-
import React from 'react';
|
|
465
|
-
const Component: React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
|
|
466
|
-
|
|
467
|
-
export default Component;
|
|
468
|
-
}
|
|
469
|
-
|
|
470
|
-
declare module '*.webp' {
|
|
471
|
-
const value: any;
|
|
472
|
-
export = value;
|
|
473
|
-
}
|
|
284
|
+
`/// <reference types="@byuckchon-frontend/settings/types/svg-vite" />
|
|
474
285
|
`
|
|
475
286
|
);
|
|
476
287
|
|
|
@@ -542,41 +353,26 @@ export default nextConfig;
|
|
|
542
353
|
`User-agent: *\nDisallow: /\n`
|
|
543
354
|
);
|
|
544
355
|
|
|
545
|
-
// tsconfig
|
|
356
|
+
// tsconfig (Next.js) — 공통 옵션은 settings 가 관리한다.
|
|
546
357
|
await write(
|
|
547
358
|
path.join(rootDir, "tsconfig.json"),
|
|
548
359
|
JSON.stringify(
|
|
549
360
|
{
|
|
361
|
+
extends: "@byuckchon-frontend/settings/tsconfig/next.json",
|
|
550
362
|
compilerOptions: {
|
|
551
|
-
|
|
552
|
-
lib: ["dom", "dom.iterable", "esnext"],
|
|
553
|
-
allowJs: true,
|
|
554
|
-
skipLibCheck: true,
|
|
555
|
-
strict: true,
|
|
556
|
-
noEmit: true,
|
|
557
|
-
esModuleInterop: true,
|
|
558
|
-
module: "esnext",
|
|
559
|
-
moduleResolution: "bundler",
|
|
560
|
-
resolveJsonModule: true,
|
|
561
|
-
isolatedModules: true,
|
|
562
|
-
jsx: "preserve",
|
|
563
|
-
incremental: true,
|
|
564
|
-
plugins: [{ name: "next" }],
|
|
363
|
+
baseUrl: ".",
|
|
565
364
|
paths: { "@/*": ["./src/*"] },
|
|
566
365
|
},
|
|
567
|
-
include: [
|
|
568
|
-
"next-env.d.ts",
|
|
569
|
-
"**/*.ts",
|
|
570
|
-
"**/*.tsx",
|
|
571
|
-
".next/types/**/*.ts",
|
|
572
|
-
],
|
|
366
|
+
include: ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
|
|
573
367
|
exclude: ["node_modules"],
|
|
574
368
|
},
|
|
575
369
|
null,
|
|
576
370
|
2
|
|
577
|
-
)
|
|
371
|
+
) + "\n"
|
|
578
372
|
);
|
|
579
373
|
|
|
374
|
+
await write(path.join(rootDir, ".nvmrc"), await readSettingsAsset("project/nvmrc"));
|
|
375
|
+
|
|
580
376
|
await createPrettierConfig(rootDir);
|
|
581
377
|
await createNextEslintConfig(rootDir);
|
|
582
378
|
await createGitignore(rootDir, "next");
|
|
@@ -671,39 +467,11 @@ export default function Error() {
|
|
|
671
467
|
|
|
672
468
|
await write(
|
|
673
469
|
path.join(rootDir, "src/global.d.ts"),
|
|
674
|
-
|
|
675
|
-
import React from 'react';
|
|
676
|
-
export const ReactComponent: React.FunctionComponent<
|
|
677
|
-
React.SVGProps<SVGSVGElement>
|
|
678
|
-
>;
|
|
679
|
-
const src: string;
|
|
680
|
-
|
|
681
|
-
export default src;
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
declare module '*.svg?react' {
|
|
685
|
-
import React from 'react';
|
|
686
|
-
const Component: React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
|
|
687
|
-
|
|
688
|
-
export default Component;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
declare module '*.webp' {
|
|
692
|
-
const value: any;
|
|
693
|
-
export = value;
|
|
694
|
-
}
|
|
470
|
+
`/// <reference types="@byuckchon-frontend/settings/types/svg-next" />
|
|
695
471
|
`
|
|
696
472
|
);
|
|
697
473
|
|
|
698
|
-
|
|
699
|
-
path.join(rootDir, "src/types.d.ts"),
|
|
700
|
-
`declare module "*.svg" {
|
|
701
|
-
import React from "react";
|
|
702
|
-
const ReactComponent: React.FC<React.SVGProps<SVGSVGElement>>;
|
|
703
|
-
export default ReactComponent;
|
|
704
|
-
}
|
|
705
|
-
`
|
|
706
|
-
);
|
|
474
|
+
// src/types.d.ts 는 global.d.ts 와 *.svg 선언이 충돌해서 제거했다.
|
|
707
475
|
}
|
|
708
476
|
|
|
709
477
|
// ─── 진입점 ───────────────────────────────────────────────────────────────────
|
|
@@ -12,6 +12,7 @@ const REACT_FOLDERS = [
|
|
|
12
12
|
'src/assets/icons',
|
|
13
13
|
'src/assets/images',
|
|
14
14
|
'src/lib',
|
|
15
|
+
'src/lib/utils',
|
|
15
16
|
'src/store',
|
|
16
17
|
'src/api',
|
|
17
18
|
'src/hooks',
|
|
@@ -34,6 +35,7 @@ const NEXT_FOLDERS = [
|
|
|
34
35
|
'src/constant',
|
|
35
36
|
'src/hooks',
|
|
36
37
|
'src/lib',
|
|
38
|
+
'src/lib/utils',
|
|
37
39
|
'src/providers',
|
|
38
40
|
];
|
|
39
41
|
|
|
@@ -50,7 +52,21 @@ export async function createFolders(rootDir, config) {
|
|
|
50
52
|
}
|
|
51
53
|
|
|
52
54
|
// 각 레이어에 placeholder 파일 생성
|
|
53
|
-
await writeFile(
|
|
55
|
+
await writeFile(
|
|
56
|
+
path.join(rootDir, 'src/lib/utils/cn.ts'),
|
|
57
|
+
`import { clsx, type ClassValue } from 'clsx';
|
|
58
|
+
import { twMerge } from 'tailwind-merge';
|
|
59
|
+
|
|
60
|
+
export function cn(...inputs: ClassValue[]) {
|
|
61
|
+
return twMerge(clsx(inputs));
|
|
62
|
+
}
|
|
63
|
+
`,
|
|
64
|
+
);
|
|
65
|
+
await writeFile(
|
|
66
|
+
path.join(rootDir, 'src/lib/utils/index.ts'),
|
|
67
|
+
"export { cn } from './cn';\n",
|
|
68
|
+
);
|
|
69
|
+
await writeFile(path.join(rootDir, 'src/lib/index.ts'), "export * from './utils';\n");
|
|
54
70
|
await writeFile(path.join(rootDir, 'src/hooks/index.ts'), '// 커스텀 훅\n');
|
|
55
71
|
await writeFile(path.join(rootDir, 'src/components/index.ts'), '// 재사용 가능한 UI 컴포넌트\n');
|
|
56
72
|
|