sonamu 0.9.4 → 0.9.6
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/ai/providers/rtzr/utils.js +2 -2
- package/dist/api/config.d.ts +13 -2
- package/dist/api/config.d.ts.map +1 -1
- package/dist/api/config.js +1 -1
- package/dist/api/context.d.ts +17 -7
- package/dist/api/context.d.ts.map +1 -1
- package/dist/api/context.js +1 -1
- package/dist/api/decorators.d.ts +18 -0
- package/dist/api/decorators.d.ts.map +1 -1
- package/dist/api/decorators.js +54 -3
- package/dist/api/index.js +8 -3
- package/dist/api/sonamu.d.ts +24 -9
- package/dist/api/sonamu.d.ts.map +1 -1
- package/dist/api/sonamu.js +365 -79
- package/dist/api/websocket-helpers.d.ts +24 -0
- package/dist/api/websocket-helpers.d.ts.map +1 -0
- package/dist/api/websocket-helpers.js +77 -0
- package/dist/bin/cli.js +12 -4
- package/dist/database/upsert-builder.js +4 -4
- package/dist/dict/sonamu-dictionary.js +6 -6
- package/dist/entity/entity-manager.js +1 -1
- package/dist/entity/entity.js +3 -3
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -4
- package/dist/migration/code-generation.d.ts.map +1 -1
- package/dist/migration/code-generation.js +8 -9
- package/dist/stream/index.d.ts +6 -0
- package/dist/stream/index.d.ts.map +1 -1
- package/dist/stream/index.js +13 -2
- package/dist/stream/ws-audience-resolver.d.ts +15 -0
- package/dist/stream/ws-audience-resolver.d.ts.map +1 -0
- package/dist/stream/ws-audience-resolver.js +31 -0
- package/dist/stream/ws-audience.d.ts +28 -0
- package/dist/stream/ws-audience.d.ts.map +1 -0
- package/dist/stream/ws-audience.js +46 -0
- package/dist/stream/ws-cluster-bus.d.ts +23 -0
- package/dist/stream/ws-cluster-bus.d.ts.map +1 -0
- package/dist/stream/ws-cluster-bus.js +18 -0
- package/dist/stream/ws-core.d.ts +15 -0
- package/dist/stream/ws-core.d.ts.map +1 -0
- package/dist/stream/ws-core.js +1 -0
- package/dist/stream/ws-delivery.d.ts +24 -0
- package/dist/stream/ws-delivery.d.ts.map +1 -0
- package/dist/stream/ws-delivery.js +103 -0
- package/dist/stream/ws-local-connection-store.d.ts +10 -0
- package/dist/stream/ws-local-connection-store.d.ts.map +1 -0
- package/dist/stream/ws-local-connection-store.js +44 -0
- package/dist/stream/ws-presence-store.d.ts +61 -0
- package/dist/stream/ws-presence-store.d.ts.map +1 -0
- package/dist/stream/ws-presence-store.js +236 -0
- package/dist/stream/ws-registry.d.ts +42 -0
- package/dist/stream/ws-registry.d.ts.map +1 -0
- package/dist/stream/ws-registry.js +108 -0
- package/dist/stream/ws.d.ts +52 -0
- package/dist/stream/ws.d.ts.map +1 -0
- package/dist/stream/ws.js +397 -0
- package/dist/syncer/api-parser.d.ts.map +1 -1
- package/dist/syncer/api-parser.js +72 -2
- package/dist/syncer/checksum.d.ts.map +1 -1
- package/dist/syncer/checksum.js +13 -12
- package/dist/syncer/code-generator.d.ts.map +1 -1
- package/dist/syncer/code-generator.js +7 -4
- package/dist/syncer/event-batcher.d.ts +27 -0
- package/dist/syncer/event-batcher.d.ts.map +1 -0
- package/dist/syncer/event-batcher.js +69 -0
- package/dist/syncer/file-patterns.d.ts +48 -26
- package/dist/syncer/file-patterns.d.ts.map +1 -1
- package/dist/syncer/file-patterns.js +71 -23
- package/dist/syncer/file-tracking.d.ts +13 -0
- package/dist/syncer/file-tracking.d.ts.map +1 -0
- package/dist/syncer/file-tracking.js +33 -0
- package/dist/syncer/index.js +2 -2
- package/dist/syncer/module-loader.d.ts +2 -11
- package/dist/syncer/module-loader.d.ts.map +1 -1
- package/dist/syncer/module-loader.js +3 -3
- package/dist/syncer/syncer-actions.d.ts +39 -6
- package/dist/syncer/syncer-actions.d.ts.map +1 -1
- package/dist/syncer/syncer-actions.js +125 -10
- package/dist/syncer/syncer.d.ts +33 -19
- package/dist/syncer/syncer.d.ts.map +1 -1
- package/dist/syncer/syncer.js +168 -168
- package/dist/syncer/watcher.d.ts +8 -0
- package/dist/syncer/watcher.d.ts.map +1 -0
- package/dist/syncer/watcher.js +105 -0
- package/dist/tasks/workflow-manager.d.ts.map +1 -1
- package/dist/tasks/workflow-manager.js +2 -1
- package/dist/template/implementations/services.template.d.ts.map +1 -1
- package/dist/template/implementations/services.template.js +36 -1
- package/dist/testing/bootstrap.d.ts.map +1 -1
- package/dist/testing/bootstrap.js +8 -1
- package/dist/testing/data-explorer.d.ts.map +1 -1
- package/dist/testing/data-explorer.js +5 -3
- package/dist/testing/fixture-manager.js +1 -1
- package/dist/types/types.d.ts +2 -1
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/types.js +2 -2
- package/dist/ui/api.d.ts.map +1 -1
- package/dist/ui/api.js +4 -3
- package/dist/ui/cdd-service.js +1 -1
- package/dist/ui-web/assets/{index-C5KUjXm0.js → index-BmThfg-s.js} +39 -39
- package/dist/ui-web/assets/index-D4rYm-Xz.css +1 -0
- package/dist/ui-web/index.html +2 -2
- package/dist/utils/async-utils.d.ts +27 -3
- package/dist/utils/async-utils.d.ts.map +1 -1
- package/dist/utils/async-utils.js +56 -6
- package/dist/utils/formatter.d.ts +7 -1
- package/dist/utils/formatter.d.ts.map +1 -1
- package/dist/utils/formatter.js +95 -60
- package/dist/utils/fs-utils.d.ts +2 -0
- package/dist/utils/fs-utils.d.ts.map +1 -1
- package/dist/utils/fs-utils.js +10 -2
- package/dist/utils/process-utils.d.ts +6 -0
- package/dist/utils/process-utils.d.ts.map +1 -1
- package/dist/utils/process-utils.js +16 -3
- package/dist/utils/utils.d.ts +1 -0
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +2 -2
- package/package.json +7 -5
- package/src/ai/providers/rtzr/utils.ts +1 -1
- package/src/api/__tests__/sonamu.websocket.test.ts +64 -0
- package/src/api/__tests__/websocket-context.types.test.ts +58 -0
- package/src/api/config.ts +28 -2
- package/src/api/context.ts +21 -7
- package/src/api/decorators.ts +101 -1
- package/src/api/sonamu.ts +529 -127
- package/src/api/websocket-helpers.ts +122 -0
- package/src/bin/cli.ts +10 -2
- package/src/database/upsert-builder.ts +3 -3
- package/src/dict/sonamu-dictionary.ts +3 -3
- package/src/entity/entity.ts +1 -1
- package/src/index.ts +6 -0
- package/src/migration/code-generation.ts +6 -11
- package/src/shared/app.shared.ts.txt +312 -4
- package/src/shared/web.shared.ts.txt +340 -4
- package/src/stream/__tests__/ws-contracts.test.ts +381 -0
- package/src/stream/__tests__/ws.test.ts +449 -0
- package/src/stream/index.ts +6 -0
- package/src/stream/ws-audience-resolver.ts +35 -0
- package/src/stream/ws-audience.ts +62 -0
- package/src/stream/ws-cluster-bus.ts +32 -0
- package/src/stream/ws-core.ts +16 -0
- package/src/stream/ws-delivery.ts +138 -0
- package/src/stream/ws-local-connection-store.ts +44 -0
- package/src/stream/ws-presence-store.ts +326 -0
- package/src/stream/ws-registry.ts +138 -0
- package/src/stream/ws.ts +591 -0
- package/src/syncer/__tests__/api-parser.websocket-type-ref.test.ts +78 -0
- package/src/syncer/api-parser.ts +112 -1
- package/src/syncer/checksum.ts +23 -29
- package/src/syncer/code-generator.ts +4 -1
- package/src/syncer/event-batcher.ts +72 -0
- package/src/syncer/file-patterns.ts +98 -30
- package/src/syncer/file-tracking.ts +27 -0
- package/src/syncer/module-loader.ts +5 -12
- package/src/syncer/syncer-actions.ts +179 -17
- package/src/syncer/syncer.ts +250 -287
- package/src/syncer/watcher.ts +128 -0
- package/src/tasks/workflow-manager.ts +1 -0
- package/src/template/__tests__/services.template.websocket.test.ts +79 -0
- package/src/template/implementations/services.template.ts +69 -0
- package/src/testing/bootstrap.ts +8 -1
- package/src/testing/data-explorer.ts +3 -2
- package/src/types/types.ts +20 -2
- package/src/ui/api.ts +10 -1
- package/src/utils/async-utils.ts +71 -4
- package/src/utils/formatter.ts +114 -75
- package/src/utils/fs-utils.ts +9 -0
- package/src/utils/process-utils.ts +17 -0
- package/src/utils/utils.ts +1 -1
- package/dist/ui-web/assets/index-Dr8pRJC_.css +0 -1
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import assert from "assert";
|
|
2
|
-
import { mkdir, writeFile } from "fs/promises";
|
|
2
|
+
import { mkdir, readFile, writeFile } from "fs/promises";
|
|
3
3
|
import path, { dirname } from "path";
|
|
4
4
|
|
|
5
5
|
import chalk from "chalk";
|
|
6
6
|
|
|
7
7
|
import { Sonamu } from "../api/sonamu";
|
|
8
8
|
import { type EntityNamesRecord } from "../entity/entity-manager";
|
|
9
|
+
import { AlreadyProcessedException } from "../exceptions/so-exceptions";
|
|
9
10
|
import { Naite } from "../naite/naite";
|
|
10
11
|
import { isTest } from "../utils/controller";
|
|
12
|
+
import { formatCode } from "../utils/formatter";
|
|
11
13
|
import { copyFileWithReplaceCoreToShared, exists } from "../utils/fs-utils";
|
|
12
14
|
import { type AbsolutePath } from "../utils/path-utils";
|
|
13
15
|
import { generateTemplate } from "./code-generator";
|
|
16
|
+
import { trackWritten } from "./file-tracking";
|
|
14
17
|
|
|
15
18
|
// web/.sonamu.env 에 현재 설정값 저장
|
|
16
19
|
export async function actionSyncConfig() {
|
|
@@ -35,7 +38,7 @@ export async function actionGenerateServices(
|
|
|
35
38
|
paramsArray: {
|
|
36
39
|
namesRecord: EntityNamesRecord;
|
|
37
40
|
}[],
|
|
38
|
-
): Promise<
|
|
41
|
+
): Promise<AbsolutePath[]> {
|
|
39
42
|
Naite.t("actionGenerateServices", paramsArray);
|
|
40
43
|
|
|
41
44
|
// services.generated.ts 통합 파일 생성
|
|
@@ -50,6 +53,14 @@ export async function actionGenerateServices(
|
|
|
50
53
|
return [...servicesFile];
|
|
51
54
|
}
|
|
52
55
|
|
|
56
|
+
/**
|
|
57
|
+
* Entity에 딸린 초기 types.ts를 만들어줍니다.
|
|
58
|
+
* @param entityId
|
|
59
|
+
*/
|
|
60
|
+
export async function actionGenerateInitialTypes(entityId: string): Promise<AbsolutePath[]> {
|
|
61
|
+
return generateTemplate("init_types", { entityId });
|
|
62
|
+
}
|
|
63
|
+
|
|
53
64
|
/**
|
|
54
65
|
* sonamu.generated.ts와 sonamu.generated.sso.ts를 생성합니다.
|
|
55
66
|
* @returns 생성된 파일 경로 배열.
|
|
@@ -78,22 +89,40 @@ export async function actionGenerateHttps(): Promise<AbsolutePath> {
|
|
|
78
89
|
}
|
|
79
90
|
|
|
80
91
|
/**
|
|
81
|
-
* queries.generated.ts
|
|
92
|
+
* queries.generated.ts 재생성합니다.
|
|
82
93
|
* @returns 생성된 파일 경로 배열.
|
|
83
94
|
*/
|
|
84
|
-
export async function
|
|
85
|
-
return (
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
95
|
+
export async function actionGenerateSsrQueries(): Promise<AbsolutePath[]> {
|
|
96
|
+
return generateTemplate("queries", {}, { overwrite: true });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* entry-server.generated.tsx를 생성합니다.
|
|
101
|
+
* 다른 액션들과 달리, 이미 파일이 있으면 그냥 놔둡니다. 그래서 함수 이름 끝에 써놨어요 ㅎ
|
|
102
|
+
* 입력 의존 없는 정적 코드라 매번 overwrite는 mtime만 갱신하는 의미 없는 동작.
|
|
103
|
+
* 템플릿 자체가 변경된 경우(Sonamu 업그레이드)에는 사용자가 파일을 삭제한 뒤 sync로 재생성.
|
|
104
|
+
* @returns 생성된 파일 경로 배열 (이미 있으면 빈 배열).
|
|
105
|
+
*/
|
|
106
|
+
export async function actionGenerateSsrEntryServerIfNotExists(): Promise<AbsolutePath[]> {
|
|
107
|
+
try {
|
|
108
|
+
return await generateTemplate("entry_server", {}, { overwrite: false });
|
|
109
|
+
} catch (e) {
|
|
110
|
+
// generateTemplate은 overwrite: false에서 파일이 이미 있으면 예외를 던집니다.
|
|
111
|
+
// IfNotExists 의미상 "그냥 놔둔다"가 정상이므로 빈 배열로 변환합니다.
|
|
112
|
+
if (e instanceof AlreadyProcessedException) {
|
|
113
|
+
return [];
|
|
114
|
+
}
|
|
115
|
+
throw e;
|
|
116
|
+
}
|
|
91
117
|
}
|
|
92
118
|
|
|
93
119
|
/**
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
*
|
|
120
|
+
* 주어진 .ts 파일들(api에 있다고 가정)을 모든 타겟 디렉토리의 services에 갖다 둡니다.
|
|
121
|
+
* 이때 내부의 sonamu import는 sonamu.shared.ts import로 치환되고,
|
|
122
|
+
* 경로의 /application/은 /services/로 치환됩니다.
|
|
123
|
+
*
|
|
124
|
+
* @param tsPaths 복사할 파일들의 절대 경로
|
|
125
|
+
* @returns 각 타겟에 복사된 파일들의 절대 경로 배열 (flat).
|
|
97
126
|
*/
|
|
98
127
|
export async function actionSyncFilesToTargets(tsPaths: AbsolutePath[]): Promise<string[]> {
|
|
99
128
|
const { targets } = Sonamu.config.sync;
|
|
@@ -111,10 +140,6 @@ export async function actionSyncFilesToTargets(tsPaths: AbsolutePath[]): Promise
|
|
|
111
140
|
if (!(await exists(dir))) {
|
|
112
141
|
await mkdir(dir, { recursive: true });
|
|
113
142
|
}
|
|
114
|
-
!isTest() &&
|
|
115
|
-
console.log(
|
|
116
|
-
chalk.bold("Copied: ") + chalk.blue(dst.replace(`${Sonamu.appRootPath}/`, "")),
|
|
117
|
-
);
|
|
118
143
|
const syncHeader = [
|
|
119
144
|
"/**",
|
|
120
145
|
" * @generated",
|
|
@@ -122,6 +147,11 @@ export async function actionSyncFilesToTargets(tsPaths: AbsolutePath[]): Promise
|
|
|
122
147
|
" */",
|
|
123
148
|
].join("\n");
|
|
124
149
|
await copyFileWithReplaceCoreToShared(realSrc, dst, syncHeader);
|
|
150
|
+
await trackWritten(dst as AbsolutePath);
|
|
151
|
+
!isTest() &&
|
|
152
|
+
console.log(
|
|
153
|
+
chalk.bold("Copied: ") + chalk.blue(dst.replace(`${Sonamu.appRootPath}/`, "")),
|
|
154
|
+
);
|
|
125
155
|
return dst;
|
|
126
156
|
}),
|
|
127
157
|
),
|
|
@@ -129,3 +159,135 @@ export async function actionSyncFilesToTargets(tsPaths: AbsolutePath[]): Promise
|
|
|
129
159
|
)
|
|
130
160
|
).flat();
|
|
131
161
|
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* shared 템플릿으로부터 sonamu.shared.ts 파일을 만들어서 모든 타겟 디렉토리에 갖다 둡니다.
|
|
165
|
+
* 파일을 만드는 과정에서 여러 치환 가공이 일어납니다.
|
|
166
|
+
*
|
|
167
|
+
* 다른 액션들과 달리, 이미 파일이 있으면 그냥 놔둡니다. 그래서 함수 이름 끝에 써놨어요 ㅎ
|
|
168
|
+
*/
|
|
169
|
+
export async function actionCopySharedToTargetsIfNotExists(): Promise<void> {
|
|
170
|
+
const { targets } = Sonamu.config.sync;
|
|
171
|
+
|
|
172
|
+
// plural.ts 내용을 읽어서 shared 파일에 삽입합니다.
|
|
173
|
+
const dictUtilsPath = path.join(
|
|
174
|
+
import.meta.dirname.replace("/dist/", "/src/"),
|
|
175
|
+
"../dict/utils.ts",
|
|
176
|
+
);
|
|
177
|
+
const dictUtilsCode = (await exists(dictUtilsPath)) ? await readFile(dictUtilsPath, "utf-8") : "";
|
|
178
|
+
|
|
179
|
+
// 특정 변수 치환을 위해서 사용합니다.
|
|
180
|
+
const convertMap = {
|
|
181
|
+
baseUrl:
|
|
182
|
+
Sonamu.config.server.baseUrl ??
|
|
183
|
+
`http://${Sonamu.config.server.listen?.host ?? "localhost"}:${Sonamu.config.server.listen?.port ?? 3000}`,
|
|
184
|
+
dictUtils: dictUtilsCode,
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
for (const target of targets) {
|
|
188
|
+
// 지금 가져가려는 이 파일은 Sonamu 코드베이스의 일부입니다.
|
|
189
|
+
// 그런데 dist 속 빌드된 소스 코드 파일이 필요한 것이 아니고, src에만 있는 텍스트 파일이 필요합니다.
|
|
190
|
+
// 따라서 /src/에서 찾습니다.
|
|
191
|
+
const srcPath = path.join(
|
|
192
|
+
import.meta.dirname.replace("/dist/", "/src/"),
|
|
193
|
+
`../shared/${target}.shared.ts.txt`,
|
|
194
|
+
);
|
|
195
|
+
if (!(await exists(srcPath))) {
|
|
196
|
+
continue;
|
|
197
|
+
}
|
|
198
|
+
if (!(await exists(path.join(Sonamu.appRootPath, target)))) {
|
|
199
|
+
throw new Error(
|
|
200
|
+
`Tried to copy sonamu.shared.ts to target '${target}' but the target directory does not exist. Please check your project directory structure.`,
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
const fullText = await readFile(srcPath, "utf-8");
|
|
205
|
+
const convertedText = Object.entries(convertMap).reduce(
|
|
206
|
+
(acc, [key, value]) => acc.replace(`$[[${key}]]`, value),
|
|
207
|
+
fullText,
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
// 이건 프로젝트에 .ts 소스 코드 파일을 생성하는 것이므로 src의 .ts 경로로 갑니다.
|
|
211
|
+
const destPath = path.join(Sonamu.appRootPath, target, "src/services/sonamu.shared.ts");
|
|
212
|
+
|
|
213
|
+
// 정말 혹시나지만 target 디렉토리는 있어도 src/services 디렉토리는 없을 수 있으므로 미리 생성해줍니다.
|
|
214
|
+
if (!(await exists(path.dirname(destPath)))) {
|
|
215
|
+
await mkdir(path.dirname(destPath), { recursive: true });
|
|
216
|
+
console.warn(`Created directory '${path.dirname(destPath)}' because it did not exist.`);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// 파일이 이미 존재하면 건너뜁니다.
|
|
220
|
+
// sonamu.shared.ts는 프로젝트에서 자유롭게 커스터마이징할 수 있어야 하므로,
|
|
221
|
+
// 최초 1회만 생성하고 이후에는 덮어쓰지 않습니다.
|
|
222
|
+
// 템플릿 내용($[[dictUtils]] 등)이 변경되었을 때 반영이 필요하면,
|
|
223
|
+
// 해당 파일을 삭제한 뒤 `pnpm sonamu sync`로 재생성하면 됩니다.
|
|
224
|
+
if (await exists(destPath)) {
|
|
225
|
+
continue;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
await writeFile(destPath, await formatCode(convertedText, destPath));
|
|
229
|
+
!isTest() &&
|
|
230
|
+
console.log(chalk.bold("Copied: ") + chalk.blue(path.relative(Sonamu.appRootPath, destPath)));
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Sonamu Dictionary(SD)를 모든 타겟(api + web/app 등)에 동기화합니다.
|
|
236
|
+
*
|
|
237
|
+
* 각 타겟에 대해:
|
|
238
|
+
* - target이 api가 아니면 사용자 작성 locale 파일(ko.ts/en.ts/...)을 api → target으로 복사
|
|
239
|
+
* - sd 템플릿을 렌더링해서 sd.generated.ts 생성 (overwrite)
|
|
240
|
+
*
|
|
241
|
+
* 한 타겟에서 실패해도 다른 타겟은 계속 진행합니다.
|
|
242
|
+
*/
|
|
243
|
+
export async function actionSyncSonamuDictionary(): Promise<void> {
|
|
244
|
+
const { targets } = Sonamu.config.sync;
|
|
245
|
+
const i18nConfig = Sonamu.config.i18n;
|
|
246
|
+
|
|
247
|
+
const targetList = ["api", ...targets] as ("api" | "web" | "app")[];
|
|
248
|
+
|
|
249
|
+
const apiI18nDir = path.join(Sonamu.appRootPath, Sonamu.config.api.dir, "src/i18n");
|
|
250
|
+
|
|
251
|
+
for (const target of targetList) {
|
|
252
|
+
try {
|
|
253
|
+
// web/app의 경우 locale 파일들을 api에서 복사
|
|
254
|
+
if (target !== "api") {
|
|
255
|
+
await syncLocaleFiles(target, apiI18nDir, i18nConfig.supportedLocales);
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
await generateTemplate("sd", { target }, { overwrite: true });
|
|
259
|
+
} catch (e) {
|
|
260
|
+
console.error(`Failed to generate SD template for ${target}:`, e);
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* api의 locale 파일을 web/app으로 복사합니다.
|
|
267
|
+
*/
|
|
268
|
+
async function syncLocaleFiles(
|
|
269
|
+
target: string,
|
|
270
|
+
apiI18nDir: string,
|
|
271
|
+
locales: string[],
|
|
272
|
+
): Promise<void> {
|
|
273
|
+
const targetI18nDir = path.join(Sonamu.appRootPath, target, "src/i18n");
|
|
274
|
+
|
|
275
|
+
// 디렉토리가 없으면 생성
|
|
276
|
+
await mkdir(targetI18nDir, { recursive: true });
|
|
277
|
+
|
|
278
|
+
for (const locale of locales) {
|
|
279
|
+
const sourceFile = path.join(apiI18nDir, `${locale}.ts`);
|
|
280
|
+
const targetFile = path.join(targetI18nDir, `${locale}.ts`);
|
|
281
|
+
|
|
282
|
+
const syncHeader = [
|
|
283
|
+
"/**",
|
|
284
|
+
" * @generated",
|
|
285
|
+
" * API에서 동기화된 파일입니다. 직접 수정하지 마세요.",
|
|
286
|
+
" */",
|
|
287
|
+
].join("\n");
|
|
288
|
+
await copyFileWithReplaceCoreToShared(sourceFile, targetFile, syncHeader);
|
|
289
|
+
await trackWritten(targetFile as AbsolutePath);
|
|
290
|
+
!isTest() &&
|
|
291
|
+
console.log(chalk.bold("Copied: ") + chalk.cyan(`${target}/src/i18n/${locale}.ts`));
|
|
292
|
+
}
|
|
293
|
+
}
|