@simplysm/sd-cli 7.0.23 → 7.0.24

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.
@@ -0,0 +1,287 @@
1
+ import { INpmConfig, ISdCliPackageBuildResult, ISdCliServerPackageConfig } from "../commons";
2
+ import { EventEmitter } from "events";
3
+ import { FsUtil, Logger, PathUtil } from "@simplysm/sd-core-node";
4
+ import webpack from "webpack";
5
+ import path from "path";
6
+ import ts from "typescript";
7
+ import { SdCliBuildResultUtil } from "../utils/SdCliBuildResultUtil";
8
+ import { ErrorInfo } from "ts-loader/dist/interfaces";
9
+ import os from "os";
10
+ import { ESLint } from "eslint";
11
+ import webpackMerge from "webpack-merge";
12
+ import TerserPlugin from "terser-webpack-plugin";
13
+ import { StringUtil } from "@simplysm/sd-core-common";
14
+ import { SdCliNpmConfigUtil } from "../utils/SdCliNpmConfigUtil";
15
+ import ESLintWebpackPlugin from "eslint-webpack-plugin";
16
+ import CopyWebpackPlugin from "copy-webpack-plugin";
17
+ import LintResult = ESLint.LintResult;
18
+
19
+ export class SdCliServerBuilder extends EventEmitter {
20
+ private readonly _logger = Logger.get(["simplysm", "sd-cli", this.constructor.name]);
21
+
22
+ private readonly _parsedTsconfig: ts.ParsedCommandLine;
23
+ private readonly _npmConfigMap = new Map<string, INpmConfig>();
24
+
25
+ public constructor(private readonly _rootPath: string,
26
+ private readonly _config: ISdCliServerPackageConfig,
27
+ private readonly _workspaceRootPath: string) {
28
+ super();
29
+
30
+ // tsconfig
31
+ const tsconfigFilePath = path.resolve(this._rootPath, "tsconfig-build.json");
32
+ const tsconfig = FsUtil.readJson(tsconfigFilePath);
33
+ this._parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, this._rootPath);
34
+ }
35
+
36
+ public override on(event: "change", listener: () => void): this;
37
+ public override on(event: "complete", listener: (results: ISdCliPackageBuildResult[]) => void): this;
38
+ public override on(event: string | symbol, listener: (...args: any[]) => void): this {
39
+ return super.on(event, listener);
40
+ }
41
+
42
+ public async watchAsync(): Promise<void> {
43
+ }
44
+
45
+ public async buildAsync(): Promise<ISdCliPackageBuildResult[]> {
46
+ // DIST 비우기
47
+ await FsUtil.removeAsync(this._parsedTsconfig.options.outDir!);
48
+
49
+ // 빌드 준비
50
+ const extModuleNames = this._findExternalModules(false).map((item) => item.name);
51
+
52
+ // 빌드
53
+ this._logger.debug("Webpack 빌드 수행...");
54
+ const webpackConfig = this._getWebpackBuildConfig(extModuleNames);
55
+ const compiler = webpack(webpackConfig);
56
+ const buildResults = await new Promise<ISdCliPackageBuildResult[]>((resolve, reject) => {
57
+ compiler.run((err, stats) => {
58
+ if (err != null || stats == null) {
59
+ reject(err);
60
+ return;
61
+ }
62
+
63
+ // 결과 리턴
64
+ const results = SdCliBuildResultUtil.convertFromWebpackStats(stats);
65
+ resolve(results);
66
+ });
67
+ });
68
+ this._logger.debug("Webpack 빌드 완료");
69
+
70
+ return buildResults;
71
+ }
72
+
73
+ private get _webpackCommonConfig(): webpack.Configuration {
74
+ return {
75
+ devtool: false,
76
+ target: ["node", "es2020"],
77
+ profile: false,
78
+ resolve: {
79
+ roots: [this._rootPath],
80
+ extensions: [".ts", ".js", ".mjs", ".cjs"],
81
+ symlinks: true,
82
+ mainFields: ["es2020", "default", "module", "main"]
83
+ },
84
+ context: this._workspaceRootPath,
85
+ entry: {
86
+ main: [
87
+ path.resolve(this._rootPath, "src/main.ts")
88
+ ]
89
+ },
90
+ output: {
91
+ clean: true,
92
+ path: this._parsedTsconfig.options.outDir,
93
+ filename: "[name].js",
94
+ chunkFilename: "[name].js",
95
+ assetModuleFilename: "resources/[name][ext][query]"
96
+ },
97
+ performance: { hints: false },
98
+ node: false,
99
+ stats: "errors-warnings",
100
+ module: {
101
+ strictExportPresence: true,
102
+ rules: [
103
+ {
104
+ test: /\.ts$/,
105
+ exclude: /node_modules/,
106
+ loader: "ts-loader",
107
+ options: {
108
+ compilerOptions: this._parsedTsconfig.options,
109
+ errorFormatter: (msg: ErrorInfo) => {
110
+ return SdCliBuildResultUtil.getMessage({
111
+ filePath: msg.file,
112
+ line: msg.line,
113
+ char: msg.character,
114
+ code: "TS" + msg.code.toString(),
115
+ severity: msg.severity,
116
+ message: msg.content
117
+ });
118
+ }
119
+ }
120
+ },
121
+ {
122
+ test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico|otf|xlsx?|pptx?|docx?|zip|pfx|pkl)$/,
123
+ type: "asset/resource"
124
+ }
125
+ ]
126
+ },
127
+ plugins: [
128
+ new CopyWebpackPlugin({
129
+ patterns: ["assets/"].map((item) => ({
130
+ context: this._rootPath,
131
+ to: item,
132
+ from: `src/${item}`,
133
+ noErrorOnMissing: true,
134
+ force: true,
135
+ globOptions: {
136
+ dot: true,
137
+ followSymbolicLinks: false,
138
+ ignore: [
139
+ ".gitkeep",
140
+ "**/.DS_Store",
141
+ "**/Thumbs.db"
142
+ ].map((i) => PathUtil.posix(this._rootPath, i))
143
+ },
144
+ priority: 0
145
+ }))
146
+ }),
147
+ new webpack.EnvironmentPlugin({
148
+ SD_VERSION: this._getNpmConfig(this._rootPath)!.version,
149
+ ...this._config.env
150
+ }),
151
+ new ESLintWebpackPlugin({
152
+ context: this._rootPath,
153
+ extensions: ["ts", "js", "mjs", "cjs"],
154
+ fix: false,
155
+ threads: false,
156
+ formatter: (results: LintResult[]) => {
157
+ const resultMessages: string[] = [];
158
+ for (const result of results) {
159
+ for (const msg of result.messages) {
160
+ const severity = msg.severity === 1 ? "warning" : msg.severity === 2 ? "error" : undefined;
161
+ if (severity === undefined) continue;
162
+
163
+ resultMessages.push(SdCliBuildResultUtil.getMessage({
164
+ filePath: result.filePath,
165
+ line: msg.line,
166
+ char: msg.column,
167
+ code: msg.ruleId?.toString(),
168
+ severity,
169
+ message: msg.message
170
+ }));
171
+ }
172
+ }
173
+ return resultMessages.join(os.EOL);
174
+ }
175
+ }),
176
+ new webpack.ProgressPlugin({
177
+ handler: (per: number, msg: string, ...args: string[]) => {
178
+ const phaseText = msg ? ` - phase: ${msg}` : "";
179
+ const argsText = args.length > 0 ? ` - args: [${args.join(", ")}]` : "";
180
+ this._logger.debug(`Webpack 빌드 수행중...(${Math.round(per * 100)}%)${phaseText}${argsText}`);
181
+ }
182
+ })
183
+ ]
184
+ };
185
+ }
186
+
187
+ private _getWebpackWatchConfig(extModuleNames: string[]): webpack.Configuration {
188
+ const internalModuleCachePaths = FsUtil.findAllParentChildDirPaths("node_modules/!(@simplysm)", this._rootPath, this._workspaceRootPath);
189
+
190
+ return webpackMerge(this._webpackCommonConfig, {
191
+ mode: "development",
192
+ output: {
193
+ libraryTarget: "umd"
194
+ },
195
+ module: {
196
+ rules: [
197
+ {
198
+ test: /\.m?js$/,
199
+ enforce: "pre",
200
+ loader: "source-map-loader",
201
+ options: {
202
+ filterSourceMappingUrl: (mapUri: string, resourcePath: string) => {
203
+ return !resourcePath.includes("node_modules") || (/@simplysm[\\/]sd/).test(resourcePath);
204
+ }
205
+ }
206
+ }
207
+ ]
208
+ },
209
+ cache: { type: "memory", maxGenerations: 1 },
210
+ snapshot: {
211
+ immutablePaths: internalModuleCachePaths,
212
+ managedPaths: internalModuleCachePaths
213
+ },
214
+ optimization: {
215
+ moduleIds: "deterministic",
216
+ chunkIds: "named",
217
+ emitOnErrors: true
218
+ },
219
+ externals: extModuleNames
220
+ });
221
+ }
222
+
223
+ private _getWebpackBuildConfig(extModuleNames: string[]): webpack.Configuration {
224
+ return webpackMerge(this._webpackCommonConfig, {
225
+ mode: "production",
226
+ output: {
227
+ libraryTarget: "module"
228
+ },
229
+ cache: false,
230
+ optimization: {
231
+ minimizer: [
232
+ new TerserPlugin({
233
+ terserOptions: {
234
+ ecma: 2020,
235
+ sourceMap: false,
236
+ keep_classnames: true,
237
+ keep_fnames: true,
238
+ ie8: false,
239
+ safari10: false,
240
+ module: true
241
+ }
242
+ })
243
+ ],
244
+ moduleIds: "deterministic",
245
+ chunkIds: "deterministic",
246
+ emitOnErrors: false
247
+ },
248
+ externals: extModuleNames
249
+ });
250
+ }
251
+
252
+ private _findExternalModules(all: boolean): { name: string; path: string }[] {
253
+ const loadedModuleNames: string[] = [];
254
+ const externalModules: { name: string; path: string }[] = [];
255
+
256
+ const fn = (currPath: string): void => {
257
+ const npmConfig = this._getNpmConfig(currPath);
258
+ if (!npmConfig) return;
259
+
260
+
261
+ for (const moduleName of SdCliNpmConfigUtil.getAllDependencies(npmConfig)) {
262
+ if (loadedModuleNames.includes(moduleName)) continue;
263
+ loadedModuleNames.push(moduleName);
264
+
265
+ const modulePath = FsUtil.findAllParentChildDirPaths("node_modules/" + moduleName, currPath, this._workspaceRootPath).first();
266
+ if (StringUtil.isNullOrEmpty(modulePath)) continue;
267
+
268
+ if (all || FsUtil.exists(path.resolve(modulePath, "binding.gyp"))) {
269
+ externalModules.push({ path: modulePath, name: moduleName });
270
+ }
271
+
272
+ fn(modulePath);
273
+ }
274
+ };
275
+
276
+ fn(this._rootPath);
277
+
278
+ return externalModules.distinct();
279
+ }
280
+
281
+ private _getNpmConfig(pkgPath: string): INpmConfig | undefined {
282
+ if (!this._npmConfigMap.has(pkgPath)) {
283
+ this._npmConfigMap.set(pkgPath, FsUtil.readJson(path.resolve(pkgPath, "package.json")));
284
+ }
285
+ return this._npmConfigMap.get(pkgPath);
286
+ }
287
+ }
@@ -165,7 +165,7 @@ export class SdCliTsLibBuilder extends EventEmitter {
165
165
  results.push(
166
166
  ...diagnostics
167
167
  .filter((item) => [ts.DiagnosticCategory.Error, ts.DiagnosticCategory.Warning].includes(item.category))
168
- .map((item) => SdCliBuildResultUtil.convertDiagsToResult(item))
168
+ .map((item) => SdCliBuildResultUtil.convertFromTsDiag(item))
169
169
  .filterExists()
170
170
  );
171
171
 
package/src/commons.ts CHANGED
@@ -39,17 +39,14 @@ export interface ISdCliConfig {
39
39
  localUpdates?: Record<string, string>;
40
40
  }
41
41
 
42
- export type TSdCliPackageConfig = ISdCliLibPackageConfig | ISdCliNgLibPackageConfig | ISdCliServerPackageConfig;
42
+ export type TSdCliPackageConfig = ISdCliLibPackageConfig | ISdCliServerPackageConfig;
43
43
 
44
44
  export interface ISdCliLibPackageConfig {
45
45
  type: "library";
46
46
  publish?: "npm";
47
47
  }
48
48
 
49
- export interface ISdCliNgLibPackageConfig {
50
- type: "angular";
51
- }
52
-
53
49
  export interface ISdCliServerPackageConfig {
54
50
  type: "server";
51
+ env?: Record<string, string>;
55
52
  }
@@ -0,0 +1,22 @@
1
+ import { Logger, SdProcess } from "@simplysm/sd-core-node";
2
+ import { SdCliPrepare } from "./SdCliPrepare";
3
+
4
+ export class SdCliNpm {
5
+ private readonly _logger = Logger.get(["simplysm", "sd-cli", this.constructor.name]);
6
+
7
+ public constructor(private readonly _rootPath: string) {
8
+ }
9
+
10
+ public async updateAsync(): Promise<void> {
11
+ this._logger.debug("업데이트할 패키지 확인...");
12
+ await SdProcess.execAsync("npm outdated", { cwd: this._rootPath });
13
+
14
+ this._logger.debug("업데이트 시작...");
15
+ await SdProcess.execAsync("npm update", { cwd: this._rootPath });
16
+
17
+ this._logger.debug("sd-cli 준비...");
18
+ await new SdCliPrepare().prepareAsync();
19
+
20
+ this._logger.info("노드 패키지 업데이트 완료");
21
+ }
22
+ }
@@ -0,0 +1,54 @@
1
+ import { FsUtil, Logger } from "@simplysm/sd-core-node";
2
+
3
+ export class SdCliPrepare {
4
+ private readonly _logger = Logger.get(["simplysm", "sd-cli", this.constructor.name]);
5
+
6
+ public async prepareAsync(): Promise<void> {
7
+ // 타입체크 속도 지연 메시지 추가
8
+ const r1 = await this._modifyTypescriptCodeForTypeCheckPerformanceWarning();
9
+ this._logger.log(`[모듈수정] 타입체크 속도 지연 메시지 추가 (${r1 ? "O" : "X"})`);
10
+ }
11
+
12
+ private async _modifyTypescriptCodeForTypeCheckPerformanceWarning(): Promise<boolean> {
13
+ const fileUrl = await import.meta.resolve!("typescript");
14
+ const filePath = fileUrl.replace(/^file:\/\/\//, "");
15
+ const fileContent = await FsUtil.readFileAsync(filePath);
16
+ const modifiedFileContent = fileContent.replace(`
17
+ function checkSourceElement(node) {
18
+ if (node) {
19
+ var saveCurrentNode = currentNode;
20
+ currentNode = node;
21
+ instantiationCount = 0;
22
+ checkSourceElementWorker(node);
23
+ currentNode = saveCurrentNode;
24
+ }
25
+ }`, `
26
+ function checkSourceElement(node) {
27
+ if (node) {
28
+ const prevUsage = process.cpuUsage();
29
+
30
+ var saveCurrentNode = currentNode;
31
+ currentNode = node;
32
+ instantiationCount = 0;
33
+ checkSourceElementWorker(node);
34
+ currentNode = saveCurrentNode;
35
+
36
+ const usage = process.cpuUsage(prevUsage);
37
+ if (node.hasChildPerformanceWarning) {
38
+ node.parent.hasChildPerformanceWarning = true;
39
+ }
40
+ else if (usage.user + usage.system > 2000 * 1000 && node.kind !== 253) {
41
+ error(node, {
42
+ code: 9000,
43
+ category: ts.DiagnosticCategory.Warning,
44
+ key: "simplysm_check_source_element_performance_slow",
45
+ message: "소스코드 타입분석에 너무 오랜 시간이 소요됩니다. [" + Math.round((usage.user + usage.system) / 1000) + "ms/cpu, KIND: " + node.kind + "]"
46
+ });
47
+ node.parent.hasChildPerformanceWarning = true;
48
+ }
49
+ }
50
+ }`);
51
+ await FsUtil.writeFileAsync(filePath, modifiedFileContent);
52
+ return fileContent !== modifiedFileContent;
53
+ }
54
+ }
@@ -2,13 +2,13 @@ import { FsUtil, Logger, 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";
5
- import { Wait } from "@simplysm/sd-core-common";
5
+ import { Uuid, Wait } from "@simplysm/sd-core-common";
6
6
  import os from "os";
7
7
  import { SdCliBuildResultUtil } from "../utils/SdCliBuildResultUtil";
8
8
  import semver from "semver/preload";
9
9
  import { SdCliConfigUtil } from "../utils/SdCliConfigUtil";
10
10
  import { SdServiceServer } from "@simplysm/sd-service/server";
11
- import decache from "decache";
11
+ import { SdCliNpm } from "./SdCliNpm";
12
12
 
13
13
  export class SdCliWorkspace {
14
14
  private readonly _logger = Logger.get(["simplysm", "sd-cli", this.constructor.name]);
@@ -40,7 +40,15 @@ export class SdCliWorkspace {
40
40
  changeCount++;
41
41
  this._logger.debug(`[${pkg.name}] 빌드를 시작합니다...`);
42
42
  })
43
- .on("complete", (results) => {
43
+ .on("complete", async (results) => {
44
+ if (pkg.type === "server") {
45
+ if (results.some((item) => item.severity === "error")) {
46
+ return;
47
+ }
48
+
49
+ await this._restartServerAsync(pkg);
50
+ }
51
+
44
52
  this._logger.debug(`[${pkg.name}] 빌드가 완료되었습니다.`);
45
53
  totalResultMap.set(pkg.name, results);
46
54
 
@@ -52,40 +60,6 @@ export class SdCliWorkspace {
52
60
  }
53
61
  }, 500);
54
62
  });
55
-
56
-
57
- if (pkg.type === "server") {
58
- pkg.on("complete", async (results) => {
59
- if (results.some((item) => item.severity === "error")) {
60
- return;
61
- }
62
-
63
- const entryFileRelPath = pkg.main;
64
- if (entryFileRelPath === undefined) {
65
- this._logger.error(`서버패키지(${pkg.name})의 'package.json'에서 'main'필드를 찾을 수 없습니다.`);
66
- return;
67
- }
68
- const entryFilePath = path.resolve(pkg.rootPath, entryFileRelPath);
69
-
70
- this._logger.log(`서버(${pkg.name}) 재시작...`);
71
- const serverInfo = this._serverInfoMap.getOrCreate(pkg.name, {});
72
- if (serverInfo.server) {
73
- await serverInfo.server.closeAsync();
74
- delete serverInfo.server;
75
- decache(entryFilePath);
76
- }
77
-
78
- serverInfo.server = (await import(entryFilePath)) as SdServiceServer | undefined;
79
- if (serverInfo.server === undefined) {
80
- this._logger.error(`${entryFilePath}(0, 0): 'SdServiceServer'를 'export'해야 합니다.`);
81
- return;
82
- }
83
-
84
- await Wait.until(() => serverInfo.server!.isOpen);
85
-
86
- this._logger.log(`서버(${pkg.name}) 재시작 완료`);
87
- });
88
- }
89
63
  }
90
64
 
91
65
  this._logger.debug("빌드를 시작합니다...");
@@ -98,6 +72,32 @@ export class SdCliWorkspace {
98
72
  });
99
73
  }
100
74
 
75
+ private async _restartServerAsync(pkg: SdCliPackage): Promise<void> {
76
+ const entryFileRelPath = pkg.main;
77
+ if (entryFileRelPath === undefined) {
78
+ this._logger.error(`서버패키지(${pkg.name})의 'package.json'에서 'main'필드를 찾을 수 없습니다.`);
79
+ return;
80
+ }
81
+ const entryFilePath = path.resolve(pkg.rootPath, entryFileRelPath);
82
+
83
+ this._logger.log(`서버(${pkg.name}) 재시작...`);
84
+ const serverInfo = this._serverInfoMap.getOrCreate(pkg.name, {});
85
+ if (serverInfo.server) {
86
+ await serverInfo.server.closeAsync();
87
+ delete serverInfo.server;
88
+ }
89
+
90
+ serverInfo.server = (await import("file:///" + entryFilePath + "?update=" + Uuid.new().toString())).default as SdServiceServer | undefined;
91
+ if (!(serverInfo.server instanceof SdServiceServer)) {
92
+ this._logger.error(`${entryFilePath}(0, 0): 'SdServiceServer'를 'export'해야 합니다.`);
93
+ return;
94
+ }
95
+
96
+ await Wait.until(() => serverInfo.server!.isOpen);
97
+
98
+ this._logger.log(`서버(${pkg.name}) 재시작 완료`);
99
+ }
100
+
101
101
  public async buildAsync(opt: { confFileRelPath: string; optNames: string[] }): Promise<void> {
102
102
  this._logger.debug("프로젝트 설정 가져오기...");
103
103
  const config = await SdCliConfigUtil.loadConfigAsync(path.resolve(this._rootPath, opt.confFileRelPath), false, opt.optNames);
@@ -160,6 +160,9 @@ export class SdCliWorkspace {
160
160
  this._logger.debug("프로젝트 및 패키지 버전 설정...");
161
161
  await this._upgradeVersionAsync(pkgs);
162
162
 
163
+ this._logger.debug("노드패키지 업데이트...");
164
+ await new SdCliNpm(this._rootPath).updateAsync();
165
+
163
166
  // 빌드
164
167
  if (!opt.noBuild) {
165
168
  this._logger.debug("빌드를 시작합니다...");
@@ -5,6 +5,8 @@ import { EventEmitter } from "events";
5
5
  import { ObjectUtil } from "@simplysm/sd-core-common";
6
6
  import { SdCliTsLibBuilder } from "../builder/SdCliTsLibBuilder";
7
7
  import { SdCliJsLibBuilder } from "../builder/SdCliJsLibBuilder";
8
+ import { SdCliNpmConfigUtil } from "../utils/SdCliNpmConfigUtil";
9
+ import { SdCliServerBuilder } from "../builder/SdCliServerBuilder";
8
10
 
9
11
  export class SdCliPackage extends EventEmitter {
10
12
  private readonly _npmConfig: INpmConfig;
@@ -26,12 +28,7 @@ export class SdCliPackage extends EventEmitter {
26
28
  }
27
29
 
28
30
  public get allDependencies(): string[] {
29
- return [
30
- ...Object.keys(this._npmConfig.dependencies ?? {}),
31
- ...Object.keys(this._npmConfig.optionalDependencies ?? {}),
32
- ...Object.keys(this._npmConfig.devDependencies ?? {}),
33
- ...Object.keys(this._npmConfig.peerDependencies ?? {})
34
- ].distinct();
31
+ return SdCliNpmConfigUtil.getAllDependencies(this._npmConfig);
35
32
  }
36
33
 
37
34
  public constructor(private readonly _workspaceRootPath: string,
@@ -76,8 +73,15 @@ export class SdCliPackage extends EventEmitter {
76
73
  await this._genBuildTsconfigAsync();
77
74
  }
78
75
 
79
- const isAngular = isTs && this.allDependencies.includes("@angular/core");
80
- const builder = !isTs ? new SdCliJsLibBuilder(this.rootPath) : new SdCliTsLibBuilder(this.rootPath, isAngular);
76
+ let builder: SdCliJsLibBuilder | SdCliTsLibBuilder | SdCliServerBuilder;
77
+
78
+ if (this._config.type === "library") {
79
+ const isAngular = isTs && this.allDependencies.includes("@angular/core");
80
+ builder = !isTs ? new SdCliJsLibBuilder(this.rootPath) : new SdCliTsLibBuilder(this.rootPath, isAngular);
81
+ }
82
+ else {
83
+ builder = new SdCliServerBuilder(this.rootPath, this._config, this._workspaceRootPath);
84
+ }
81
85
 
82
86
  await builder
83
87
  .on("change", () => {
@@ -2,9 +2,10 @@ import ts from "typescript";
2
2
  import * as os from "os";
3
3
  import * as path from "path";
4
4
  import { ISdCliPackageBuildResult } from "../commons";
5
+ import webpack from "webpack";
5
6
 
6
7
  export class SdCliBuildResultUtil {
7
- public static convertDiagsToResult(diag: ts.Diagnostic): ISdCliPackageBuildResult | undefined {
8
+ public static convertFromTsDiag(diag: ts.Diagnostic): ISdCliPackageBuildResult | undefined {
8
9
  const severity = diag.category === ts.DiagnosticCategory.Error ? "error"
9
10
  : diag.category === ts.DiagnosticCategory.Warning ? "warning"
10
11
  : undefined;
@@ -29,6 +30,35 @@ export class SdCliBuildResultUtil {
29
30
  };
30
31
  }
31
32
 
33
+ public static convertFromWebpackStats(stats: webpack.Stats): ISdCliPackageBuildResult[] {
34
+ const results: ISdCliPackageBuildResult[] = [];
35
+
36
+ for (const statWarn of stats.compilation.warnings) {
37
+ if (stats.compilation.options.ignoreWarnings?.some((ignoreWarning) => ignoreWarning(statWarn, stats.compilation))) continue;
38
+
39
+ results.push(this._convertFromWebpackError("warning", statWarn));
40
+ }
41
+
42
+ for (const statErr of stats.compilation.errors) {
43
+ results.push(this._convertFromWebpackError("error", statErr));
44
+ }
45
+
46
+ return results;
47
+ }
48
+
49
+ private static _convertFromWebpackError(severity: "warning" | "error", err: webpack.WebpackError): ISdCliPackageBuildResult {
50
+ console.log(err);
51
+ return {
52
+ filePath: err.file,
53
+ line: err.loc["start"].line,
54
+ char: err.loc["start"].column,
55
+ code: err.name,
56
+ severity,
57
+ message: err.message
58
+ };
59
+ }
60
+
61
+
32
62
  public static getMessage(result: ISdCliPackageBuildResult): string {
33
63
  let str = "";
34
64
  if (result.filePath !== undefined) {
@@ -0,0 +1,12 @@
1
+ import { INpmConfig } from "../commons";
2
+
3
+ export class SdCliNpmConfigUtil {
4
+ public static getAllDependencies(npmConfig: INpmConfig): string[] {
5
+ return [
6
+ ...Object.keys(npmConfig.dependencies ?? {}),
7
+ ...Object.keys(npmConfig.optionalDependencies ?? {}),
8
+ ...Object.keys(npmConfig.devDependencies ?? {}),
9
+ ...Object.keys(npmConfig.peerDependencies ?? {})
10
+ ].distinct();
11
+ }
12
+ }