@simplysm/sd-cli 7.0.20 → 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.
- package/dist/bin/sd-cli.d.ts +1 -1
- package/dist/bin/sd-cli.mjs +54 -15
- package/dist/builder/SdCliServerBuilder.d.ts +21 -0
- package/dist/builder/SdCliServerBuilder.mjs +260 -0
- package/dist/builder/SdCliTsLibBuilder.mjs +2 -2
- package/dist/commons.d.ts +2 -4
- package/dist/entry-points/SdCliLocalUpdate.d.ts +7 -4
- package/dist/entry-points/SdCliLocalUpdate.mjs +6 -7
- package/dist/entry-points/SdCliNpm.d.ts +6 -0
- package/dist/entry-points/SdCliNpm.mjs +18 -0
- package/dist/entry-points/SdCliPrepare.d.ts +5 -0
- package/dist/entry-points/SdCliPrepare.mjs +54 -0
- package/dist/entry-points/SdCliWorkspace.d.ts +13 -5
- package/dist/entry-points/SdCliWorkspace.mjs +50 -13
- package/dist/packages/SdCliPackage.d.ts +5 -2
- package/dist/packages/SdCliPackage.mjs +31 -19
- package/dist/utils/SdCliBuildResultUtil.d.ts +4 -1
- package/dist/utils/SdCliBuildResultUtil.mjs +25 -2
- package/dist/utils/SdCliConfigUtil.d.ts +1 -1
- package/dist/utils/SdCliConfigUtil.mjs +5 -5
- package/dist/utils/SdCliNpmConfigUtil.d.ts +4 -0
- package/dist/utils/SdCliNpmConfigUtil.mjs +11 -0
- package/package.json +20 -11
- package/src/bin/sd-cli.ts +62 -14
- package/src/builder/SdCliServerBuilder.ts +287 -0
- package/src/builder/SdCliTsLibBuilder.ts +1 -1
- package/src/commons.ts +2 -5
- package/src/entry-points/SdCliLocalUpdate.ts +5 -6
- package/src/entry-points/SdCliNpm.ts +22 -0
- package/src/entry-points/SdCliPrepare.ts +54 -0
- package/src/entry-points/SdCliWorkspace.ts +65 -15
- package/src/packages/SdCliPackage.ts +33 -17
- package/src/utils/SdCliBuildResultUtil.ts +31 -1
- package/src/utils/SdCliConfigUtil.ts +4 -4
- package/src/utils/SdCliNpmConfigUtil.ts +12 -0
- package/tsconfig.json +4 -1
|
@@ -2,28 +2,31 @@ 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
|
+
import { SdCliConfigUtil } from "../utils/SdCliConfigUtil";
|
|
10
|
+
import { SdServiceServer } from "@simplysm/sd-service/server";
|
|
11
|
+
import { SdCliNpm } from "./SdCliNpm";
|
|
9
12
|
|
|
10
13
|
export class SdCliWorkspace {
|
|
11
14
|
private readonly _logger = Logger.get(["simplysm", "sd-cli", this.constructor.name]);
|
|
12
15
|
|
|
13
16
|
private readonly _npmConfig: INpmConfig;
|
|
14
|
-
private readonly
|
|
17
|
+
private readonly _serverInfoMap = new Map<string, IServerInfo>();
|
|
15
18
|
|
|
16
|
-
public constructor(private readonly _rootPath: string
|
|
17
|
-
private readonly _configFilePath?: string) {
|
|
19
|
+
public constructor(private readonly _rootPath: string) {
|
|
18
20
|
const npmConfigFilePath = path.resolve(this._rootPath, "package.json");
|
|
19
21
|
this._npmConfig = FsUtil.readJson(npmConfigFilePath);
|
|
20
|
-
|
|
21
|
-
this._config = FsUtil.readJson(path.resolve(this._rootPath, this._configFilePath ?? "simplysm.json"));
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
public async watchAsync(): Promise<void> {
|
|
24
|
+
public async watchAsync(opt: { confFileRelPath: string; optNames: string[] }): Promise<void> {
|
|
25
|
+
this._logger.debug("프로젝트 설정 가져오기...");
|
|
26
|
+
const config = await SdCliConfigUtil.loadConfigAsync(path.resolve(this._rootPath, opt.confFileRelPath), true, opt.optNames);
|
|
27
|
+
|
|
25
28
|
this._logger.debug("패키지 목록 구성...");
|
|
26
|
-
const pkgs = await this._getPackagesAsync();
|
|
29
|
+
const pkgs = await this._getPackagesAsync(config);
|
|
27
30
|
|
|
28
31
|
this._logger.debug("패키지 이벤트 설정...");
|
|
29
32
|
let changeCount = 0;
|
|
@@ -37,7 +40,15 @@ export class SdCliWorkspace {
|
|
|
37
40
|
changeCount++;
|
|
38
41
|
this._logger.debug(`[${pkg.name}] 빌드를 시작합니다...`);
|
|
39
42
|
})
|
|
40
|
-
.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
|
+
|
|
41
52
|
this._logger.debug(`[${pkg.name}] 빌드가 완료되었습니다.`);
|
|
42
53
|
totalResultMap.set(pkg.name, results);
|
|
43
54
|
|
|
@@ -61,9 +72,38 @@ export class SdCliWorkspace {
|
|
|
61
72
|
});
|
|
62
73
|
}
|
|
63
74
|
|
|
64
|
-
|
|
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
|
+
public async buildAsync(opt: { confFileRelPath: string; optNames: string[] }): Promise<void> {
|
|
102
|
+
this._logger.debug("프로젝트 설정 가져오기...");
|
|
103
|
+
const config = await SdCliConfigUtil.loadConfigAsync(path.resolve(this._rootPath, opt.confFileRelPath), false, opt.optNames);
|
|
104
|
+
|
|
65
105
|
this._logger.debug("패키지 목록 구성...");
|
|
66
|
-
const pkgs = await this._getPackagesAsync();
|
|
106
|
+
const pkgs = await this._getPackagesAsync(config);
|
|
67
107
|
|
|
68
108
|
this._logger.debug("프로젝트 및 패키지 버전 설정...");
|
|
69
109
|
await this._upgradeVersionAsync(pkgs);
|
|
@@ -96,7 +136,10 @@ export class SdCliWorkspace {
|
|
|
96
136
|
}
|
|
97
137
|
}
|
|
98
138
|
|
|
99
|
-
public async publishAsync(opt: { noBuild: boolean }): Promise<void> {
|
|
139
|
+
public async publishAsync(opt: { noBuild: boolean; confFileRelPath: string; optNames: string[] }): Promise<void> {
|
|
140
|
+
this._logger.debug("프로젝트 설정 가져오기...");
|
|
141
|
+
const config = await SdCliConfigUtil.loadConfigAsync(path.resolve(this._rootPath, opt.confFileRelPath), false, opt.optNames);
|
|
142
|
+
|
|
100
143
|
if (opt.noBuild) {
|
|
101
144
|
this._logger.warn("빌드하지 않고, 배포하는것은 상당히 위험합니다.");
|
|
102
145
|
await this._waitSecMessageAsync("프로세스를 중지하려면, 'CTRL+C'를 누르세요.", 5);
|
|
@@ -112,11 +155,14 @@ export class SdCliWorkspace {
|
|
|
112
155
|
}
|
|
113
156
|
|
|
114
157
|
this._logger.debug("패키지 목록 구성...");
|
|
115
|
-
const pkgs = await this._getPackagesAsync();
|
|
158
|
+
const pkgs = await this._getPackagesAsync(config);
|
|
116
159
|
|
|
117
160
|
this._logger.debug("프로젝트 및 패키지 버전 설정...");
|
|
118
161
|
await this._upgradeVersionAsync(pkgs);
|
|
119
162
|
|
|
163
|
+
this._logger.debug("노드패키지 업데이트...");
|
|
164
|
+
await new SdCliNpm(this._rootPath).updateAsync();
|
|
165
|
+
|
|
120
166
|
// 빌드
|
|
121
167
|
if (!opt.noBuild) {
|
|
122
168
|
this._logger.debug("빌드를 시작합니다...");
|
|
@@ -182,14 +228,14 @@ export class SdCliWorkspace {
|
|
|
182
228
|
process.stdout.clearLine(0);
|
|
183
229
|
}
|
|
184
230
|
|
|
185
|
-
private async _getPackagesAsync(): Promise<SdCliPackage[]> {
|
|
231
|
+
private async _getPackagesAsync(conf: ISdCliConfig): Promise<SdCliPackage[]> {
|
|
186
232
|
const pkgRootPaths = await this._npmConfig.workspaces?.mapManyAsync(async (item) => await FsUtil.globAsync(item));
|
|
187
233
|
if (!pkgRootPaths) {
|
|
188
234
|
throw new Error("최상위 'package.json'에서 'workspaces'를 찾을 수 없습니다.");
|
|
189
235
|
}
|
|
190
236
|
|
|
191
237
|
return pkgRootPaths.map((pkgRootPath) => {
|
|
192
|
-
const pkgConfig =
|
|
238
|
+
const pkgConfig = conf.packages[path.basename(pkgRootPath)];
|
|
193
239
|
return pkgConfig ? new SdCliPackage(this._rootPath, pkgRootPath, pkgConfig) : undefined;
|
|
194
240
|
}).filterExists();
|
|
195
241
|
}
|
|
@@ -227,3 +273,7 @@ export class SdCliWorkspace {
|
|
|
227
273
|
}
|
|
228
274
|
}
|
|
229
275
|
}
|
|
276
|
+
|
|
277
|
+
interface IServerInfo {
|
|
278
|
+
server?: SdServiceServer;
|
|
279
|
+
}
|
|
@@ -5,29 +5,38 @@ 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;
|
|
11
13
|
|
|
14
|
+
public get basename(): string {
|
|
15
|
+
return path.basename(this._workspaceRootPath);
|
|
16
|
+
}
|
|
17
|
+
|
|
12
18
|
public get name(): string {
|
|
13
19
|
return this._npmConfig.name;
|
|
14
20
|
}
|
|
15
21
|
|
|
22
|
+
public get main(): string | undefined {
|
|
23
|
+
return this._npmConfig.main;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
public get type(): TSdCliPackageConfig["type"] {
|
|
27
|
+
return this._config.type;
|
|
28
|
+
}
|
|
29
|
+
|
|
16
30
|
public get allDependencies(): string[] {
|
|
17
|
-
return
|
|
18
|
-
...Object.keys(this._npmConfig.dependencies ?? {}),
|
|
19
|
-
...Object.keys(this._npmConfig.optionalDependencies ?? {}),
|
|
20
|
-
...Object.keys(this._npmConfig.devDependencies ?? {}),
|
|
21
|
-
...Object.keys(this._npmConfig.peerDependencies ?? {})
|
|
22
|
-
].distinct();
|
|
31
|
+
return SdCliNpmConfigUtil.getAllDependencies(this._npmConfig);
|
|
23
32
|
}
|
|
24
33
|
|
|
25
34
|
public constructor(private readonly _workspaceRootPath: string,
|
|
26
|
-
|
|
35
|
+
public readonly rootPath: string,
|
|
27
36
|
private readonly _config: TSdCliPackageConfig) {
|
|
28
37
|
super();
|
|
29
38
|
|
|
30
|
-
const npmConfigFilePath = path.resolve(this.
|
|
39
|
+
const npmConfigFilePath = path.resolve(this.rootPath, "package.json");
|
|
31
40
|
this._npmConfig = FsUtil.readJson(npmConfigFilePath);
|
|
32
41
|
}
|
|
33
42
|
|
|
@@ -53,19 +62,26 @@ export class SdCliPackage extends EventEmitter {
|
|
|
53
62
|
updateDepVersion(this._npmConfig.devDependencies);
|
|
54
63
|
updateDepVersion(this._npmConfig.peerDependencies);
|
|
55
64
|
|
|
56
|
-
const npmConfigFilePath = path.resolve(this.
|
|
65
|
+
const npmConfigFilePath = path.resolve(this.rootPath, "package.json");
|
|
57
66
|
await FsUtil.writeJsonAsync(npmConfigFilePath, this._npmConfig, { space: 2 });
|
|
58
67
|
}
|
|
59
68
|
|
|
60
69
|
public async watchAsync(): Promise<void> {
|
|
61
|
-
const isTs = FsUtil.exists(path.resolve(this.
|
|
70
|
+
const isTs = FsUtil.exists(path.resolve(this.rootPath, "tsconfig.json"));
|
|
62
71
|
|
|
63
72
|
if (isTs) {
|
|
64
73
|
await this._genBuildTsconfigAsync();
|
|
65
74
|
}
|
|
66
75
|
|
|
67
|
-
|
|
68
|
-
|
|
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
|
+
}
|
|
69
85
|
|
|
70
86
|
await builder
|
|
71
87
|
.on("change", () => {
|
|
@@ -78,26 +94,26 @@ export class SdCliPackage extends EventEmitter {
|
|
|
78
94
|
}
|
|
79
95
|
|
|
80
96
|
public async buildAsync(): Promise<ISdCliPackageBuildResult[]> {
|
|
81
|
-
const isTs = FsUtil.exists(path.resolve(this.
|
|
97
|
+
const isTs = FsUtil.exists(path.resolve(this.rootPath, "tsconfig.json"));
|
|
82
98
|
|
|
83
99
|
if (isTs) {
|
|
84
100
|
await this._genBuildTsconfigAsync();
|
|
85
101
|
}
|
|
86
102
|
|
|
87
103
|
const isAngular = isTs && this.allDependencies.includes("@angular/core");
|
|
88
|
-
const builder = isTs ? new SdCliTsLibBuilder(this.
|
|
104
|
+
const builder = isTs ? new SdCliTsLibBuilder(this.rootPath, isAngular) : new SdCliJsLibBuilder(this.rootPath);
|
|
89
105
|
|
|
90
106
|
return await builder.buildAsync();
|
|
91
107
|
}
|
|
92
108
|
|
|
93
109
|
public async publishAsync(): Promise<void> {
|
|
94
110
|
if (this._config.type === "library" && this._config.publish === "npm") {
|
|
95
|
-
await SdProcess.execAsync("npm publish --quiet --access public", { cwd: this.
|
|
111
|
+
await SdProcess.execAsync("npm publish --quiet --access public", { cwd: this.rootPath });
|
|
96
112
|
}
|
|
97
113
|
}
|
|
98
114
|
|
|
99
115
|
private async _genBuildTsconfigAsync(): Promise<void> {
|
|
100
|
-
const baseTsconfigFilePath = path.resolve(this.
|
|
116
|
+
const baseTsconfigFilePath = path.resolve(this.rootPath, "tsconfig.json");
|
|
101
117
|
const baseTsconfig: ITsconfig = await FsUtil.readJsonAsync(baseTsconfigFilePath);
|
|
102
118
|
|
|
103
119
|
const buildTsconfig: ITsconfig = ObjectUtil.clone(baseTsconfig);
|
|
@@ -105,7 +121,7 @@ export class SdCliPackage extends EventEmitter {
|
|
|
105
121
|
delete buildTsconfig.compilerOptions.baseUrl;
|
|
106
122
|
delete buildTsconfig.compilerOptions.paths;
|
|
107
123
|
|
|
108
|
-
const buildTsconfigFilePath = path.resolve(this.
|
|
124
|
+
const buildTsconfigFilePath = path.resolve(this.rootPath, "tsconfig-build.json");
|
|
109
125
|
await FsUtil.writeJsonAsync(buildTsconfigFilePath, buildTsconfig, { space: 2 });
|
|
110
126
|
}
|
|
111
127
|
}
|
|
@@ -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
|
|
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) {
|
|
@@ -4,15 +4,15 @@ import { ObjectUtil } from "@simplysm/sd-core-common";
|
|
|
4
4
|
import path from "path";
|
|
5
5
|
|
|
6
6
|
export class SdCliConfigUtil {
|
|
7
|
-
public static
|
|
8
|
-
const confFileCont = FsUtil.
|
|
7
|
+
public static async loadConfigAsync(confFilePath: string, isDev: boolean, opts?: string[]): Promise<ISdCliConfig> {
|
|
8
|
+
const confFileCont = await FsUtil.readJsonAsync(confFilePath);
|
|
9
9
|
let conf = this._getConfigFromFileContent(confFileCont, isDev, opts);
|
|
10
10
|
|
|
11
11
|
// extends
|
|
12
12
|
if (conf.extends) {
|
|
13
13
|
for (const extConfFilePath of conf.extends) {
|
|
14
|
-
const extConf = this.
|
|
15
|
-
conf = this._mergeObj(
|
|
14
|
+
const extConf = await this.loadConfigAsync(path.resolve(path.dirname(confFilePath), extConfFilePath), isDev, opts);
|
|
15
|
+
conf = this._mergeObj(extConf, conf);
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
delete conf["extends"];
|
|
@@ -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
|
+
}
|