@simplysm/sd-cli 7.0.66 → 7.0.77

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.
Files changed (53) hide show
  1. package/.eslintrc.cjs +3 -0
  2. package/dist/bin/sd-cli.mjs +62 -6
  3. package/dist/build-tool/SdCliCordova.d.ts +1 -1
  4. package/dist/build-tool/SdCliCordova.mjs +40 -27
  5. package/dist/build-tool/SdCliNgCacheCompilerHost.d.ts +1 -0
  6. package/dist/build-tool/SdCliNgCacheCompilerHost.mjs +11 -4
  7. package/dist/build-tool/SdCliPackageLinter.mjs +9 -5
  8. package/dist/builder/SdCliClientBuilder.d.ts +1 -0
  9. package/dist/builder/SdCliClientBuilder.mjs +45 -37
  10. package/dist/builder/SdCliJsLibBuilder.mjs +3 -3
  11. package/dist/builder/SdCliServerBuilder.d.ts +0 -1
  12. package/dist/builder/SdCliServerBuilder.mjs +39 -54
  13. package/dist/builder/SdCliTsLibBuilder.d.ts +1 -0
  14. package/dist/builder/SdCliTsLibBuilder.mjs +19 -7
  15. package/dist/commons.d.ts +18 -4
  16. package/dist/entry-points/SdCliFileCrypto.d.ts +7 -0
  17. package/dist/entry-points/SdCliFileCrypto.mjs +72 -0
  18. package/dist/entry-points/SdCliLocalUpdate.mjs +3 -3
  19. package/dist/entry-points/SdCliPrepare.mjs +3 -3
  20. package/dist/entry-points/SdCliWorkspace.d.ts +3 -0
  21. package/dist/entry-points/SdCliWorkspace.mjs +57 -37
  22. package/dist/index.d.ts +1 -0
  23. package/dist/index.mjs +2 -1
  24. package/dist/ng-tools/SdCliNgModuleGenerator.d.ts +2 -0
  25. package/dist/ng-tools/SdCliNgModuleGenerator.mjs +97 -18
  26. package/dist/ng-tools/babel/SdCliBbFileMetadata.d.ts +1 -1
  27. package/dist/ng-tools/babel/SdCliBbFileMetadata.mjs +4 -4
  28. package/dist/ng-tools/babel/TSdCliBbNgMetadata.mjs +6 -6
  29. package/dist/ng-tools/typescript/SdCliTsFileMetadata.mjs +2 -3
  30. package/dist/packages/SdCliPackage.mjs +52 -5
  31. package/dist/utils/SdCliBuildResultUtil.mjs +4 -1
  32. package/package.json +7 -9
  33. package/src/bin/sd-cli.ts +77 -6
  34. package/src/build-tool/SdCliCordova.ts +43 -26
  35. package/src/build-tool/SdCliNgCacheCompilerHost.ts +19 -11
  36. package/src/build-tool/SdCliPackageLinter.ts +8 -4
  37. package/src/builder/SdCliClientBuilder.ts +42 -32
  38. package/src/builder/SdCliJsLibBuilder.ts +2 -2
  39. package/src/builder/SdCliServerBuilder.ts +37 -51
  40. package/src/builder/SdCliTsLibBuilder.ts +22 -6
  41. package/src/commons.ts +21 -2
  42. package/src/entry-points/SdCliFileCrypto.ts +87 -0
  43. package/src/entry-points/SdCliLocalUpdate.ts +2 -2
  44. package/src/entry-points/SdCliPrepare.ts +2 -2
  45. package/src/entry-points/SdCliWorkspace.ts +59 -41
  46. package/src/index.ts +1 -0
  47. package/src/ng-tools/SdCliNgModuleGenerator.ts +119 -17
  48. package/src/ng-tools/babel/SdCliBbFileMetadata.ts +5 -5
  49. package/src/ng-tools/babel/TSdCliBbNgMetadata.ts +5 -5
  50. package/src/ng-tools/typescript/SdCliTsFileMetadata.ts +1 -2
  51. package/src/packages/SdCliPackage.ts +55 -4
  52. package/src/utils/SdCliBuildResultUtil.ts +4 -0
  53. package/tsconfig.json +3 -0
@@ -1,4 +1,4 @@
1
- import { FsUtil, Logger, SdProcess } from "@simplysm/sd-core-node";
1
+ import { FsUtil, Logger, PathUtil, SdProcess } from "@simplysm/sd-core-node";
2
2
  import path from "path";
3
3
  import { INpmConfig, ISdCliConfig, ISdCliPackageBuildResult } from "../commons";
4
4
  import { SdCliPackage } from "../packages/SdCliPackage";
@@ -23,7 +23,7 @@ export class SdCliWorkspace {
23
23
  this._npmConfig = FsUtil.readJson(npmConfigFilePath);
24
24
  }
25
25
 
26
- public async watchAsync(opt: { confFileRelPath: string; optNames: string[] }): Promise<void> {
26
+ public async watchAsync(opt: { confFileRelPath: string; optNames: string[]; pkgs: string[] }): Promise<void> {
27
27
  this._logger.debug("프로젝트 설정 가져오기...");
28
28
  const config = await SdCliConfigUtil.loadConfigAsync(path.resolve(this._rootPath, opt.confFileRelPath), true, opt.optNames);
29
29
 
@@ -33,7 +33,7 @@ export class SdCliWorkspace {
33
33
  }
34
34
 
35
35
  this._logger.debug("패키지 목록 구성...");
36
- const pkgs = await this._getPackagesAsync(config);
36
+ const pkgs = await this._getPackagesAsync(config, opt.pkgs);
37
37
 
38
38
  this._logger.debug("패키지 이벤트 설정...");
39
39
  let changeCount = 0;
@@ -72,22 +72,29 @@ export class SdCliWorkspace {
72
72
  }
73
73
  changeCount++;
74
74
 
75
- const pkgNames = pkgs.map((item) => item.name);
76
- const buildCompletedPackageNames: string[] = [];
77
- await pkgs.parallelAsync(async (pkg) => {
78
- await Wait.until(() => !pkg.allDependencies.some((dep) => pkgNames.includes(dep) && !buildCompletedPackageNames.includes(dep)));
79
- if (pkg.config.type === "client") {
80
- const middlewares = (await pkg.watchAsync()) as NextHandleFunction[];
81
-
82
- const serverInfo = this._serverInfoMap.getOrCreate(pkg.config.server, { middlewares: [], clientInfos: [] });
83
- serverInfo.middlewares.push(...middlewares);
84
- serverInfo.clientInfos.push({ pkgKey: pkg.name.split("/").last()! });
85
- }
86
- else {
87
- await pkg.watchAsync();
88
- }
89
- buildCompletedPackageNames.push(pkg.name);
90
- });
75
+ try {
76
+ const pkgNames = pkgs.map((item) => item.name);
77
+ const buildCompletedPackageNames: string[] = [];
78
+ await pkgs.parallelAsync(async (pkg) => {
79
+ await Wait.until(() => !pkg.allDependencies.some((dep) => pkgNames.includes(dep) && !buildCompletedPackageNames.includes(dep)));
80
+ if (pkg.config.type === "client") {
81
+ const middlewares = (await pkg.watchAsync()) as NextHandleFunction[];
82
+
83
+ const serverInfo = this._serverInfoMap.getOrCreate(pkg.config.server, { middlewares: [], clientInfos: [] });
84
+ serverInfo.middlewares.push(...middlewares);
85
+ serverInfo.clientInfos.push({ pkgKey: pkg.name.split("/").last()! });
86
+ }
87
+ else {
88
+ await pkg.watchAsync();
89
+ }
90
+ buildCompletedPackageNames.push(pkg.name);
91
+ });
92
+ }
93
+ catch (err) {
94
+ this._loggingResults(totalResultMap);
95
+ this._loggingOpenClientHrefs();
96
+ throw err;
97
+ }
91
98
 
92
99
  changeCount--;
93
100
  if (changeCount === 0) {
@@ -111,18 +118,22 @@ export class SdCliWorkspace {
111
118
  }
112
119
  const entryFilePath = path.resolve(pkg.rootPath, entryFileRelPath);
113
120
 
114
- this._logger.log(`서버(${pkg.name}) 재시작...`);
115
121
  try {
116
122
  const serverInfo = this._serverInfoMap.getOrCreate(path.basename(pkg.rootPath), {
117
123
  middlewares: [],
118
124
  clientInfos: []
119
125
  });
120
126
  if (serverInfo.server) {
127
+ this._logger.log(`[${pkg.name}] 기존 서버 중지...`);
121
128
  await serverInfo.server.closeAsync();
122
129
  delete serverInfo.server;
123
130
  }
124
131
 
125
- serverInfo.server = (await import("file:///" + entryFilePath + "?update=" + Uuid.new().toString())).default.default as SdServiceServer | undefined;
132
+ this._logger.log(`[${pkg.name}] 서버 시작중...`);
133
+
134
+ const serverMainPath = "file:///" + PathUtil.posix(entryFilePath) + "?update=" + Uuid.new().toString().replace(/-/g, "");
135
+ const serverModule = await import(serverMainPath);
136
+ serverInfo.server = serverModule.default as SdServiceServer | undefined;
126
137
  if (!serverInfo.server) {
127
138
  this._logger.error(`${entryFilePath}(0, 0): 'SdServiceServer'를 'export'해야 합니다.`);
128
139
  this._isServerRestarting = false;
@@ -131,7 +142,7 @@ export class SdCliWorkspace {
131
142
  serverInfo.server.devMiddlewares = serverInfo.middlewares;
132
143
  await Wait.until(() => serverInfo.server!.isOpen);
133
144
 
134
- this._logger.log(`서버(${pkg.name}) 재시작 완료`);
145
+ this._logger.log(`[${pkg.name}] 서버가 시작되었습니다.`);
135
146
  }
136
147
  catch (err) {
137
148
  this._logger.error(`서버(${pkg.name}) 재시작중 오류 발생`, err);
@@ -140,12 +151,12 @@ export class SdCliWorkspace {
140
151
  this._isServerRestarting = false;
141
152
  }
142
153
 
143
- public async buildAsync(opt: { confFileRelPath: string; optNames: string[] }): Promise<void> {
154
+ public async buildAsync(opt: { confFileRelPath: string; optNames: string[]; pkgs: string[] }): Promise<void> {
144
155
  this._logger.debug("프로젝트 설정 가져오기...");
145
156
  const config = await SdCliConfigUtil.loadConfigAsync(path.resolve(this._rootPath, opt.confFileRelPath), false, opt.optNames);
146
157
 
147
158
  this._logger.debug("패키지 목록 구성...");
148
- const pkgs = await this._getPackagesAsync(config);
159
+ const pkgs = await this._getPackagesAsync(config, opt.pkgs);
149
160
 
150
161
  this._logger.debug("프로젝트 및 패키지 버전 설정...");
151
162
  await this._upgradeVersionAsync(pkgs);
@@ -159,26 +170,32 @@ export class SdCliWorkspace {
159
170
  const pkgNames = pkgs.map((item) => item.name);
160
171
  const buildCompletedPackageNames: string[] = [];
161
172
  const totalResultMap = new Map<string, ISdCliPackageBuildResult[]>();
162
- await pkgs.parallelAsync(async (pkg) => {
163
- await Wait.until(() => !pkg.allDependencies.some((dep) => pkgNames.includes(dep) && !buildCompletedPackageNames.includes(dep)));
173
+ try {
174
+ await pkgs.parallelAsync(async (pkg) => {
175
+ await Wait.until(() => !pkg.allDependencies.some((dep) => pkgNames.includes(dep) && !buildCompletedPackageNames.includes(dep)));
164
176
 
165
- this._logger.debug(`[${pkg.name}] 빌드를 시작합니다...`);
166
- totalResultMap.set(pkg.name, await pkg.buildAsync());
167
- this._logger.debug(`[${pkg.name}] 빌드가 완료되었습니다.`);
177
+ this._logger.debug(`[${pkg.name}] 빌드를 시작합니다...`);
178
+ totalResultMap.set(pkg.name, await pkg.buildAsync());
179
+ this._logger.debug(`[${pkg.name}] 빌드가 완료되었습니다.`);
168
180
 
169
- buildCompletedPackageNames.push(pkg.name);
170
- });
181
+ buildCompletedPackageNames.push(pkg.name);
182
+ });
171
183
 
172
- this._loggingResults(totalResultMap);
173
- if (Array.from(totalResultMap.values()).mapMany().some((item) => item.severity === "error")) {
174
- throw new Error("빌드중 오류가 발생하였습니다.");
184
+ this._loggingResults(totalResultMap);
185
+ if (Array.from(totalResultMap.values()).mapMany().some((item) => item.severity === "error")) {
186
+ throw new Error("빌드중 오류가 발생하였습니다.");
187
+ }
188
+ else {
189
+ this._logger.info("모든 빌드가 완료되었습니다.");
190
+ }
175
191
  }
176
- else {
177
- this._logger.info("모든 빌드가 완료되었습니다.");
192
+ catch (err) {
193
+ this._loggingResults(totalResultMap);
194
+ throw err;
178
195
  }
179
196
  }
180
197
 
181
- public async publishAsync(opt: { noBuild: boolean; confFileRelPath: string; optNames: string[] }): Promise<void> {
198
+ public async publishAsync(opt: { noBuild: boolean; confFileRelPath: string; optNames: string[]; pkgs: string[] }): Promise<void> {
182
199
  this._logger.debug("프로젝트 설정 가져오기...");
183
200
  const config = await SdCliConfigUtil.loadConfigAsync(path.resolve(this._rootPath, opt.confFileRelPath), false, opt.optNames);
184
201
 
@@ -197,7 +214,7 @@ export class SdCliWorkspace {
197
214
  }
198
215
 
199
216
  this._logger.debug("패키지 목록 구성...");
200
- const pkgs = await this._getPackagesAsync(config);
217
+ const pkgs = await this._getPackagesAsync(config, opt.pkgs);
201
218
 
202
219
  this._logger.debug("프로젝트 및 패키지 버전 설정...");
203
220
  await this._upgradeVersionAsync(pkgs);
@@ -270,16 +287,17 @@ export class SdCliWorkspace {
270
287
  process.stdout.clearLine(0);
271
288
  }
272
289
 
273
- private async _getPackagesAsync(conf: ISdCliConfig): Promise<SdCliPackage[]> {
290
+ private async _getPackagesAsync(conf: ISdCliConfig, pkgs: string[]): Promise<SdCliPackage[]> {
274
291
  const pkgRootPaths = await this._npmConfig.workspaces?.mapManyAsync(async (item) => await FsUtil.globAsync(item));
275
292
  if (!pkgRootPaths) {
276
293
  throw new Error("최상위 'package.json'에서 'workspaces'를 찾을 수 없습니다.");
277
294
  }
278
295
 
279
-
280
296
  return pkgRootPaths.map((pkgRootPath) => {
297
+ if (pkgs.length > 0 && !pkgs.includes(path.basename(pkgRootPath))) return undefined;
281
298
  const pkgConfig = conf.packages[path.basename(pkgRootPath)];
282
- return pkgConfig ? new SdCliPackage(this._rootPath, pkgRootPath, pkgConfig) : undefined;
299
+ if (!pkgConfig) return undefined;
300
+ return new SdCliPackage(this._rootPath, pkgRootPath, pkgConfig);
283
301
  }).filterExists();
284
302
  }
285
303
 
package/src/index.ts CHANGED
@@ -8,6 +8,7 @@ export * from "./builder/SdCliJsLibBuilder";
8
8
  export * from "./builder/SdCliServerBuilder";
9
9
  export * from "./builder/SdCliTsLibBuilder";
10
10
  export * from "./commons";
11
+ export * from "./entry-points/SdCliFileCrypto";
11
12
  export * from "./entry-points/SdCliLocalUpdate";
12
13
  export * from "./entry-points/SdCliNpm";
13
14
  export * from "./entry-points/SdCliPrepare";
@@ -7,17 +7,18 @@ import {
7
7
  SdCliBbNgModuleMetadata,
8
8
  SdCliBbNgPipeMetadata
9
9
  } from "./babel/TSdCliBbNgMetadata";
10
- import { NeverEntryError, StringUtil } from "@simplysm/sd-core-common";
10
+ import { NeverEntryError, ObjectUtil, StringUtil } from "@simplysm/sd-core-common";
11
11
  import { TSdCliMetaRef } from "./commons";
12
12
  import { SdCliTsNgInjectableMetadata } from "./typescript/SdCliTsFileMetadata";
13
13
  import path from "path";
14
14
  import { JSDOM } from "jsdom";
15
- import { FsUtil, PathUtil } from "@simplysm/sd-core-node";
15
+ import { FsUtil, Logger, PathUtil } from "@simplysm/sd-core-node";
16
16
  import os from "os";
17
+ import { INpmConfig } from "../commons";
17
18
 
18
- // TODO: 에러 메시지 처리
19
- // TODO: forRoot에 있는 Provider 처리??
20
19
  export class SdCliNgModuleGenerator {
20
+ private readonly _logger: Logger;
21
+
21
22
  private readonly _bbMeta: SdCliBbRootMetadata;
22
23
  private readonly _tsMeta: SdCliTsRootMetadata;
23
24
 
@@ -44,6 +45,9 @@ export class SdCliNgModuleGenerator {
44
45
  const content = FsUtil.readFile(currFilePath);
45
46
  this._fileWriterCache.set(currFilePath, content);
46
47
  }
48
+
49
+ const npmConfig: INpmConfig = FsUtil.readJson(path.resolve(packagePath, "package.json"));
50
+ this._logger = Logger.get(["simplysm", "sd-cli", this.constructor.name, npmConfig.name]);
47
51
  }
48
52
 
49
53
  public removeCaches(changedFilePaths: string[]): void {
@@ -57,20 +61,118 @@ export class SdCliNgModuleGenerator {
57
61
  }
58
62
 
59
63
  public async runAsync(): Promise<void> {
64
+ this._logger.debug("Babel NgModule 정의 가져오기...");
60
65
  const bbNgModules = this._getBbNgModuleDefs();
66
+
67
+ this._logger.debug("NgModule Preset 구성...");
61
68
  const tsPreset = this._getTsGenNgModulePreset();
62
69
 
70
+ this._logger.debug("RoutingModule 정의 구성...");
63
71
  const genNgRoutingModules = await this._getGenNgRoutingModuleDefsAsync();
72
+
73
+ this._logger.debug("NgModule 정의 구성...");
64
74
  const genNgModules = this._getGenNgModuleDefs(bbNgModules, tsPreset.modules, tsPreset.sources);
65
75
 
76
+ this._logger.debug("NgModule 순환참조 병합...");
77
+ const mergedGenNgModules = this._mergeNgModuleCircularDependency(genNgModules);
78
+
79
+ this._logger.debug("생성할 파일 내용 구성...");
66
80
  const files = [
67
81
  ...this._getGenNgRoutingModuleFiles(genNgRoutingModules),
68
- ...this._getGenNgModuleFiles(genNgModules)
82
+ ...this._getGenNgModuleFiles(mergedGenNgModules)
69
83
  ];
70
84
 
85
+ this._logger.debug("파일 쓰기...");
71
86
  await this._writeFilesAsync(files);
72
87
  }
73
88
 
89
+ private _mergeNgModuleCircularDependency(mods: ITsGenNgModuleDef[]): ITsGenNgModuleDef[] {
90
+ // 중복 'check'목록 구성
91
+ const check = (mod: ITsGenNgModuleDef, ref: { filePath: string; name: string }, chain: ITsGenNgModuleDef[]): ITsGenNgModuleDef[][] => {
92
+ const result: ITsGenNgModuleDef[][] = [];
93
+ for (const imp of mod.imports) {
94
+ if ("filePath" in imp) {
95
+ if (imp.filePath === ref.filePath || imp.name === ref.name) {
96
+ result.push(chain.concat([mod]));
97
+ }
98
+ else {
99
+ const childMod = mods.single((item) => item.filePath === imp.filePath && item.name === imp.name);
100
+ if (childMod) {
101
+ if (chain.some((item) => item.filePath === childMod.filePath && item.name === childMod.name)) {
102
+ continue;
103
+ }
104
+
105
+ result.push(
106
+ ...check(childMod, ref, chain.concat([mod]))
107
+ );
108
+ }
109
+ }
110
+ }
111
+ }
112
+
113
+ return result;
114
+ };
115
+
116
+ const checkedList: ITsGenNgModuleDef[][] = [];
117
+ for (const mod of mods) {
118
+ const circularDepModules = check(mod, { filePath: mod.filePath, name: mod.name }, []);
119
+ if (circularDepModules.length > 0) {
120
+ checkedList.push(...circularDepModules);
121
+ }
122
+ }
123
+ const mergeModPacks = checkedList.map((item) => item.orderBy((item1) => item1.filePath)).distinct();
124
+
125
+ // 'merge'목록 구성
126
+ const currMergedList: ITsGenNgModuleDef[] = [];
127
+ for (const mergeModPack of mergeModPacks) {
128
+ let currMerged = mergeModPack[0];
129
+ for (const mergeMod of mergeModPack.slice(1)) {
130
+ currMerged = {
131
+ filePath: currMerged.filePath,
132
+ name: currMerged.name,
133
+ imports: currMerged.imports.concat(mergeMod.imports).distinct(),
134
+ exports: currMerged.exports.concat(mergeMod.exports).distinct(),
135
+ providers: currMerged.providers.concat(mergeMod.providers).distinct()
136
+ };
137
+ }
138
+ currMerged.imports.remove((imp) => (
139
+ "filePath" in imp &&
140
+ mergeModPack.some((mergeMod) => (
141
+ imp.filePath === mergeMod.filePath &&
142
+ imp.name === mergeMod.name
143
+ ))
144
+ ));
145
+
146
+ currMergedList.push(currMerged);
147
+ }
148
+
149
+ // 기존 'check'된 것들 모두 삭제
150
+ const result: ITsGenNgModuleDef[] = ObjectUtil.clone(mods);
151
+ for (const delMod of mergeModPacks.mapMany()) {
152
+ result.remove((item) => item.filePath === delMod.filePath && item.name === delMod.name);
153
+ }
154
+
155
+ // 'merge'된 것들 등록
156
+ result.push(...currMergedList);
157
+
158
+ // 모든 결과물에서 'import'에 'merge'된것들이 있으면 'merge'결과물 파일로 변경후, distinct
159
+ for (const resultItem of result) {
160
+ for (const imp of resultItem.imports) {
161
+ if (!("filePath" in imp)) continue;
162
+
163
+ for (const mergeModPack of mergeModPacks) {
164
+ if (mergeModPack.some((mergeModPackItem) => mergeModPackItem.filePath === imp.filePath && mergeModPackItem.name === imp.name)) {
165
+ imp.filePath = mergeModPack[0].filePath;
166
+ imp.name = mergeModPack[0].name;
167
+ }
168
+ }
169
+ }
170
+ resultItem.imports = resultItem.imports.distinct();
171
+ }
172
+
173
+ return result;
174
+ }
175
+
74
176
  private _findBbMetasFromMeta(srcMeta: TSdCliBbMetadata): TSdCliBbMetadata[] {
75
177
  const metaTmp = typeof srcMeta !== "string" && "__TSdCliMetaRef__" in srcMeta ? this._bbMeta.findMeta(srcMeta) : srcMeta;
76
178
  return metaTmp instanceof Array ? metaTmp : [metaTmp];
@@ -187,7 +289,7 @@ export class SdCliNgModuleGenerator {
187
289
  const moduleFilePath = path.resolve(this._modulesPath, path.relative(this._srcPath, path.dirname(fileMeta.filePath)), moduleClassName);
188
290
 
189
291
  result.sources.push({
190
- filePath: fileMeta.filePath,
292
+ filePath: fileMeta.filePath.replace(/\.[^.]*$/, ""),
191
293
  name: cls.exportedName,
192
294
  module: {
193
295
  filePath: moduleFilePath,
@@ -202,7 +304,7 @@ export class SdCliNgModuleGenerator {
202
304
  filePath: moduleFilePath,
203
305
  name: moduleClassName,
204
306
  source: {
205
- filePath: fileMeta.filePath,
307
+ filePath: fileMeta.filePath.replace(/\.[^.]*$/, ""),
206
308
  name: cls.exportedName
207
309
  },
208
310
  selector: "selector" in cls.target.ngDecl ? cls.target.ngDecl.selector : undefined,
@@ -218,9 +320,9 @@ export class SdCliNgModuleGenerator {
218
320
  private _getGenNgModuleDefs(bbModules: IBbNgModuleDef[], presetModules: ITsNgPresetModuleDef[], presetSources: ITsNgPresetSourceDef[]): ITsGenNgModuleDef[] {
219
321
  const result: ITsGenNgModuleDef[] = [];
220
322
 
221
- for (const el of presetSources) {
323
+ for (const presetSource of presetSources) {
222
324
  const imports: TSdCliMetaRef[] = [];
223
- for (const imp of el.imports) {
325
+ for (const imp of presetSource.imports) {
224
326
  if ("moduleName" in imp) {
225
327
  for (const mod of bbModules) {
226
328
  if (mod.exports.some((item) => item.moduleName === imp.moduleName && item.name === imp.name)) {
@@ -240,8 +342,8 @@ export class SdCliNgModuleGenerator {
240
342
  }
241
343
  }
242
344
 
243
- if (el.template !== undefined) {
244
- const templateDOM = new JSDOM(el.template);
345
+ if (presetSource.template !== undefined) {
346
+ const templateDOM = new JSDOM(presetSource.template);
245
347
 
246
348
  for (const mod of bbModules) {
247
349
  for (const selector of mod.selectors) {
@@ -257,7 +359,7 @@ export class SdCliNgModuleGenerator {
257
359
  }
258
360
 
259
361
  for (const pipeName of mod.pipeNames) {
260
- if (new RegExp("| *" + pipeName + "[^\\w]").test(el.template)) {
362
+ if (new RegExp("| *" + pipeName + "[^\\w]").test(presetSource.template)) {
261
363
  imports.push({ moduleName: mod.moduleName, name: mod.name, __TSdCliMetaRef__: "__TSdCliMetaRef__" });
262
364
  }
263
365
  }
@@ -277,7 +379,7 @@ export class SdCliNgModuleGenerator {
277
379
  }
278
380
 
279
381
  if (mod.pipeName !== undefined) {
280
- if (new RegExp("| *" + mod.pipeName + "[^\\w]").test(el.template)) {
382
+ if (new RegExp("| *" + mod.pipeName + "[^\\w]").test(presetSource.template)) {
281
383
  imports.push({ filePath: mod.filePath, name: mod.name, __TSdCliMetaRef__: "__TSdCliMetaRef__" });
282
384
  }
283
385
  }
@@ -285,11 +387,11 @@ export class SdCliNgModuleGenerator {
285
387
  }
286
388
 
287
389
  result.push({
288
- filePath: el.module.filePath,
289
- name: el.module.name,
390
+ filePath: presetSource.module.filePath,
391
+ name: presetSource.module.name,
290
392
  imports: imports.distinct(),
291
- exports: el.isProvider ? [] : [{ filePath: el.filePath, name: el.name }],
292
- providers: el.isProvider ? [{ filePath: el.filePath, name: el.name }] : []
393
+ exports: presetSource.isProvider ? [] : [{ filePath: presetSource.filePath, name: presetSource.name }],
394
+ providers: presetSource.isProvider ? [{ filePath: presetSource.filePath, name: presetSource.name }] : []
293
395
  });
294
396
  }
295
397
 
@@ -441,9 +441,9 @@ export class SdCliBbFileMetadata {
441
441
  throw SdCliBbUtil.error("예상치 못한 방식의 코드가 발견되었습니다.", this.filePath, rawMeta);
442
442
  }
443
443
 
444
- private readonly _getNgDecoArgCache = new Map<string, SdCliBbObjectMetadata>();
444
+ private readonly _getNgDecoArgCache = new Map<string, SdCliBbObjectMetadata | undefined>();
445
445
 
446
- public getNgDecoArg(className: string): SdCliBbObjectMetadata {
446
+ public getNgDecoArg(className: string): SdCliBbObjectMetadata | undefined {
447
447
  if (this._getNgDecoArgCache.has(className)) {
448
448
  return this._getNgDecoArgCache.get(className)!;
449
449
  }
@@ -529,9 +529,9 @@ export class SdCliBbFileMetadata {
529
529
  }
530
530
  });
531
531
 
532
- if (result === undefined) {
533
- throw new NeverEntryError(this.filePath + "," + className);
534
- }
532
+ // if (result === undefined) {
533
+ // throw new NeverEntryError(this.filePath + "," + className);
534
+ // }
535
535
 
536
536
  this._getNgDecoArgCache.set(className, result);
537
537
  return result;
@@ -27,13 +27,13 @@ export class SdCliBbNgModuleMetadata {
27
27
 
28
28
  const argObjMeta = this._fileMeta.getNgDecoArg(this._className);
29
29
 
30
- const expVal = argObjMeta.getPropValue("exports") ?? this._fileMeta.getNgDecoPropValue(this._className, "ɵmod", "exports");
30
+ const expVal = argObjMeta?.getPropValue("exports") ?? this._fileMeta.getNgDecoPropValue(this._className, "ɵmod", "exports");
31
31
  if (expVal !== undefined) {
32
32
  const expMetas = this._getExportAndProviderMetas(expVal);
33
33
  result.exports.push(...expMetas);
34
34
  }
35
35
 
36
- const provVal = argObjMeta.getPropValue("providers") ?? this._fileMeta.getNgDecoPropValue(this._className, "ɵmod", "providers");
36
+ const provVal = argObjMeta?.getPropValue("providers") ?? this._fileMeta.getNgDecoPropValue(this._className, "ɵmod", "providers");
37
37
  if (provVal !== undefined) {
38
38
  const provMetas = this._getExportAndProviderMetas(provVal);
39
39
  result.providers.push(...provMetas);
@@ -140,7 +140,7 @@ export class SdCliBbNgDirectiveMetadata {
140
140
  if (this._selectorCache !== undefined) return this._selectorCache;
141
141
 
142
142
  const argObjMeta = this._fileMeta.getNgDecoArg(this._className);
143
- const val = argObjMeta.getPropValue("selector") ?? this._fileMeta.getNgDecoPropValue(this._className, "ɵdir", "selector");
143
+ const val = argObjMeta?.getPropValue("selector") ?? this._fileMeta.getNgDecoPropValue(this._className, "ɵdir", "selector");
144
144
  if (typeof val === "string") {
145
145
  this._selectorCache = val;
146
146
  return this._selectorCache;
@@ -162,7 +162,7 @@ export class SdCliBbNgComponentMetadata {
162
162
  if (this._selectorCache !== undefined) return this._selectorCache;
163
163
 
164
164
  const argObjMeta = this._fileMeta.getNgDecoArg(this._className);
165
- const val = argObjMeta.getPropValue("selector") ?? this._fileMeta.getNgDecoPropValue(this._className, "ɵcmp", "selector");
165
+ const val = argObjMeta?.getPropValue("selector") ?? this._fileMeta.getNgDecoPropValue(this._className, "ɵcmp", "selector");
166
166
  if (typeof val === "string") {
167
167
  this._selectorCache = val;
168
168
  return this._selectorCache;
@@ -184,7 +184,7 @@ export class SdCliBbNgPipeMetadata {
184
184
  if (this._pipeNameCache !== undefined) return this._pipeNameCache;
185
185
 
186
186
  const argObjMeta = this._fileMeta.getNgDecoArg(this._className);
187
- const val = argObjMeta.getPropValue("name") ?? this._fileMeta.getNgDecoPropValue(this._className, "ɵpipe", "name");
187
+ const val = argObjMeta?.getPropValue("name") ?? this._fileMeta.getNgDecoPropValue(this._className, "ɵpipe", "name");
188
188
  if (typeof val === "string") {
189
189
  this._pipeNameCache = val;
190
190
  return val;
@@ -3,7 +3,6 @@ import ts from "typescript";
3
3
  import { NeverEntryError } from "@simplysm/sd-core-common";
4
4
  import { TSdCliMetaRef } from "../commons";
5
5
  import path from "path";
6
- import { SdCliTsUtil } from "./SdCliTsUtil";
7
6
 
8
7
  export class SdCliTsFileMetadata {
9
8
  public readonly sourceFile: ts.SourceFile;
@@ -53,7 +52,7 @@ export class SdCliTsFileMetadata {
53
52
  }
54
53
  }
55
54
  else {
56
- throw SdCliTsUtil.error("'import * as [name] from ...'을 'import [name] from ...'로 변경하세요.", this.sourceFile, node);
55
+ // throw SdCliTsUtil.error("'import * as [name] from ...'을 'import [name] from ...'로 변경하세요.", this.sourceFile, node);
57
56
  }
58
57
  }
59
58
  else {
@@ -1,14 +1,16 @@
1
1
  import { INpmConfig, ISdCliPackageBuildResult, ITsconfig, TSdCliPackageConfig } from "../commons";
2
2
  import path from "path";
3
- import { FsUtil, SdProcess } from "@simplysm/sd-core-node";
3
+ import { FsUtil, PathUtil, SdProcess } from "@simplysm/sd-core-node";
4
4
  import { EventEmitter } from "events";
5
- import { ObjectUtil } from "@simplysm/sd-core-common";
5
+ import { NeverEntryError, ObjectUtil, StringUtil } from "@simplysm/sd-core-common";
6
6
  import { SdCliTsLibBuilder } from "../builder/SdCliTsLibBuilder";
7
7
  import { SdCliJsLibBuilder } from "../builder/SdCliJsLibBuilder";
8
8
  import { SdCliServerBuilder } from "../builder/SdCliServerBuilder";
9
9
  import { SdCliNpmConfigUtil } from "../utils/SdCliNpmConfigUtil";
10
10
  import { SdCliClientBuilder } from "../builder/SdCliClientBuilder";
11
11
  import { NextHandleFunction } from "connect";
12
+ import { SdStorage } from "@simplysm/sd-storage";
13
+ import ts from "typescript";
12
14
 
13
15
  export class SdCliPackage extends EventEmitter {
14
16
  private readonly _npmConfig: INpmConfig;
@@ -83,8 +85,57 @@ export class SdCliPackage extends EventEmitter {
83
85
  }
84
86
 
85
87
  public async publishAsync(): Promise<void> {
86
- if (this.config.type === "library" && this.config.publish === "npm") {
87
- await SdProcess.spawnAsync("npm publish --quiet --access public", { cwd: this.rootPath });
88
+ if (this.config.publish !== undefined) {
89
+ if (this.config.type === "library") {
90
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
91
+ if (this.config.publish === "npm") {
92
+ await SdProcess.spawnAsync("npm publish --quiet --access public", { cwd: this.rootPath });
93
+ }
94
+ else {
95
+ throw new NeverEntryError();
96
+ }
97
+ }
98
+ else {
99
+ if (this.config.publish.type === "ftp" || this.config.publish.type === "ftps" || this.config.publish.type === "sftp") {
100
+ const tsconfigPath = path.resolve(this.rootPath, "tsconfig-build.json");
101
+ const tsconfig = FsUtil.readJson(tsconfigPath);
102
+ const parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, this.rootPath, tsconfig.angularCompilerOptions);
103
+
104
+ const ftp = await SdStorage.connectAsync(this.config.publish.type, {
105
+ host: this.config.publish.host,
106
+ port: this.config.publish.port,
107
+ user: this.config.publish.user,
108
+ pass: this.config.publish.pass
109
+ });
110
+ await ftp.uploadDirAsync(parsedTsconfig.options.outDir!, this.config.publish.path);
111
+ await ftp.closeAsync();
112
+ }
113
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
114
+ else if (this.config.publish.type === "local-directory") {
115
+ const tsconfigPath = path.resolve(this.rootPath, "tsconfig-build.json");
116
+ const tsconfig = FsUtil.readJson(tsconfigPath);
117
+ const parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, this.rootPath, tsconfig.angularCompilerOptions);
118
+
119
+ const targetRootPath = this.config.publish.path.replace(/%([^%]*)%/g, (item) => {
120
+ const envName = item.replace(/%/g, "");
121
+ if (!StringUtil.isNullOrEmpty(this._npmConfig.version) && envName === "SD_VERSION") {
122
+ return this._npmConfig.version;
123
+ }
124
+ return process.env[envName] ?? item;
125
+ });
126
+
127
+ const filePaths = await FsUtil.globAsync(path.resolve(this.rootPath, "**", "*"), {
128
+ dot: true,
129
+ nodir: true
130
+ });
131
+
132
+ await filePaths.parallelAsync(async (filePath) => {
133
+ const relativeFilePath = path.relative(parsedTsconfig.options.outDir!, filePath);
134
+ const targetPath = PathUtil.posix(targetRootPath, relativeFilePath);
135
+ await FsUtil.copyAsync(filePath, targetPath);
136
+ });
137
+ }
138
+ }
88
139
  }
89
140
  }
90
141
 
@@ -59,6 +59,10 @@ export class SdCliBuildResultUtil {
59
59
 
60
60
 
61
61
  public static getMessage(result: ISdCliPackageBuildResult): string {
62
+ if (result.code === "ESLintError") {
63
+ return result.message;
64
+ }
65
+
62
66
  let str = "";
63
67
  if (result.filePath !== undefined) {
64
68
  str += `${result.filePath}(${result.line ?? 0}, ${result.char ?? 0}): `;
package/tsconfig.json CHANGED
@@ -18,6 +18,9 @@
18
18
  ],
19
19
  "@simplysm/sd-service-server": [
20
20
  "../sd-service-server/src/index.ts"
21
+ ],
22
+ "@simplysm/sd-storage": [
23
+ "../sd-storage/src/index.ts"
21
24
  ]
22
25
  }
23
26
  },