@simplysm/core-node 14.0.6 → 14.0.8

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/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ export * as cpx from "./utils/cp";
1
2
  export * as fsx from "./utils/fs";
2
3
  export * as pathx from "./utils/path";
3
4
  export * from "./features/fs-watcher";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["..\\src\\index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,GAAG,MAAM,YAAY,CAAC;AAClC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAGtC,cAAc,uBAAuB,CAAC;AAGtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["..\\src\\index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,GAAG,MAAM,YAAY,CAAC;AAClC,OAAO,KAAK,GAAG,MAAM,YAAY,CAAC;AAClC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAGtC,cAAc,uBAAuB,CAAC;AAGtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  // 유틸리티
2
+ export * as cpx from "./utils/cp.js";
2
3
  export * as fsx from "./utils/fs.js";
3
4
  export * as pathx from "./utils/path.js";
4
5
  // 기능
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["..\\src\\index.ts"],"names":[],"mappings":"AAAA,OAAO;AACP,OAAO,KAAK,GAAG,MAAM,YAAY,CAAC;AAClC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAEtC,KAAK;AACL,cAAc,uBAAuB,CAAC;AAEtC,KAAK;AACL,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["..\\src\\index.ts"],"names":[],"mappings":"AAAA,OAAO;AACP,OAAO,KAAK,GAAG,MAAM,YAAY,CAAC;AAClC,OAAO,KAAK,GAAG,MAAM,YAAY,CAAC;AAClC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAEtC,KAAK;AACL,cAAc,uBAAuB,CAAC;AAEtC,KAAK;AACL,cAAc,gBAAgB,CAAC;AAC/B,cAAc,iBAAiB,CAAC;AAChC,cAAc,wBAAwB,CAAC"}
@@ -0,0 +1,30 @@
1
+ import type { ChildProcess } from "child_process";
2
+ export declare function codePageToEncoding(codePage: number): string;
3
+ export declare function resetEncodingCache(): void;
4
+ export declare function getSystemEncoding(): string;
5
+ export interface ExecOptions {
6
+ cwd?: string;
7
+ env?: Record<string, string>;
8
+ stdio?: "pipe" | "inherit";
9
+ shell?: boolean;
10
+ reject?: boolean;
11
+ }
12
+ export type ExecSyncOptions = Omit<ExecOptions, "reject">;
13
+ export interface ExecResult {
14
+ stdout: string;
15
+ stderr: string;
16
+ exitCode: number;
17
+ }
18
+ export declare function decodeBytes(raw: Uint8Array, systemEncoding?: string): string;
19
+ export declare class ExecProcess implements PromiseLike<ExecResult> {
20
+ private readonly _process;
21
+ private readonly _promise;
22
+ constructor(cp: ChildProcess, promise: Promise<ExecResult>);
23
+ get pid(): number | undefined;
24
+ then<TResult1 = ExecResult, TResult2 = never>(onfulfilled?: ((value: ExecResult) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
25
+ catch<TResult = never>(onrejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null): Promise<ExecResult | TResult>;
26
+ kill(signal?: NodeJS.Signals | number): boolean;
27
+ }
28
+ export declare function exec(cmd: string, args: string[], options?: ExecOptions): ExecProcess;
29
+ export declare function execSync(cmd: string, args: string[], options?: ExecSyncOptions): ExecResult;
30
+ //# sourceMappingURL=cp.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cp.d.ts","sourceRoot":"","sources":["..\\..\\src\\utils\\cp.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAkBlD,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE3D;AAED,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC;AAED,wBAAgB,iBAAiB,IAAI,MAAM,CA2B1C;AAID,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;AAE1D,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAMD,wBAAgB,WAAW,CAAC,GAAG,EAAE,UAAU,EAAE,cAAc,CAAC,EAAE,MAAM,GAAG,MAAM,CAY5E;AAMD,qBAAa,WAAY,YAAW,WAAW,CAAC,UAAU,CAAC;IACzD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAe;IACxC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAsB;gBAEnC,EAAE,EAAE,YAAY,EAAE,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC;IAK1D,IAAI,GAAG,IAAI,MAAM,GAAG,SAAS,CAE5B;IAED,IAAI,CAAC,QAAQ,GAAG,UAAU,EAAE,QAAQ,GAAG,KAAK,EAC1C,WAAW,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,UAAU,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,EAC9E,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,KAAK,QAAQ,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAC,GAAG,IAAI,GAC1E,OAAO,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAI/B,KAAK,CAAC,OAAO,GAAG,KAAK,EACnB,UAAU,CAAC,EAAE,CAAC,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,GACxE,OAAO,CAAC,UAAU,GAAG,OAAO,CAAC;IAIhC,IAAI,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,OAAO,GAAG,MAAM,GAAG,OAAO;CAGhD;AAMD,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,WAAW,CAiDpF;AAED,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,UAAU,CAkB3F"}
@@ -0,0 +1,149 @@
1
+ import { execSync as cpExecSync, spawn as cpSpawn, spawnSync as cpSpawnSync } from "child_process";
2
+ import { bytes } from "@simplysm/core-common";
3
+ const CODE_PAGE_MAP = {
4
+ 65001: "utf-8",
5
+ 949: "euc-kr",
6
+ 932: "shift-jis",
7
+ 936: "gbk",
8
+ 950: "big5",
9
+ 1252: "windows-1252",
10
+ 1251: "windows-1251",
11
+ 1250: "windows-1250",
12
+ 874: "windows-874",
13
+ };
14
+ let _cachedEncoding;
15
+ export function codePageToEncoding(codePage) {
16
+ return CODE_PAGE_MAP[codePage] ?? "utf-8";
17
+ }
18
+ export function resetEncodingCache() {
19
+ _cachedEncoding = undefined;
20
+ }
21
+ export function getSystemEncoding() {
22
+ if (_cachedEncoding != null)
23
+ return _cachedEncoding;
24
+ try {
25
+ if (process.platform === "win32") {
26
+ const output = cpExecSync("chcp", { encoding: "utf-8" });
27
+ const match = output.match(/\d+/);
28
+ if (match) {
29
+ _cachedEncoding = codePageToEncoding(Number(match[0]));
30
+ return _cachedEncoding;
31
+ }
32
+ }
33
+ else {
34
+ const lang = process.env["LANG"] ?? process.env["LC_ALL"] ?? "";
35
+ const dotIndex = lang.indexOf(".");
36
+ if (dotIndex >= 0) {
37
+ let encoding = lang.slice(dotIndex + 1).split("@")[0].toLowerCase();
38
+ if (encoding === "utf8")
39
+ encoding = "utf-8";
40
+ _cachedEncoding = encoding;
41
+ return _cachedEncoding;
42
+ }
43
+ }
44
+ }
45
+ catch {
46
+ // 감지 실패 시 fallback
47
+ }
48
+ _cachedEncoding = "utf-8";
49
+ return _cachedEncoding;
50
+ }
51
+ //#endregion
52
+ //#region decodeBytes
53
+ export function decodeBytes(raw, systemEncoding) {
54
+ const encoding = systemEncoding ?? getSystemEncoding();
55
+ if (encoding === "utf-8") {
56
+ return new TextDecoder("utf-8").decode(raw);
57
+ }
58
+ try {
59
+ return new TextDecoder("utf-8", { fatal: true }).decode(raw);
60
+ }
61
+ catch {
62
+ return new TextDecoder(encoding).decode(raw);
63
+ }
64
+ }
65
+ //#endregion
66
+ //#region ExecProcess
67
+ export class ExecProcess {
68
+ _process;
69
+ _promise;
70
+ constructor(cp, promise) {
71
+ this._process = cp;
72
+ this._promise = promise;
73
+ }
74
+ get pid() {
75
+ return this._process.pid;
76
+ }
77
+ then(onfulfilled, onrejected) {
78
+ return this._promise.then(onfulfilled, onrejected);
79
+ }
80
+ catch(onrejected) {
81
+ return this._promise.catch(onrejected);
82
+ }
83
+ kill(signal) {
84
+ return this._process.kill(signal);
85
+ }
86
+ }
87
+ //#endregion
88
+ //#region exec / execSync
89
+ export function exec(cmd, args, options) {
90
+ const isInherit = options?.stdio === "inherit";
91
+ const cp = cpSpawn(cmd, args, {
92
+ cwd: options?.cwd,
93
+ env: options?.env != null ? { ...process.env, ...options.env } : undefined,
94
+ stdio: isInherit ? "inherit" : "pipe",
95
+ shell: options?.shell ?? false,
96
+ });
97
+ const promise = new Promise((resolve, reject) => {
98
+ cp.on("error", (err) => {
99
+ reject(Object.assign(err, { stdout: "", stderr: "", exitCode: 1 }));
100
+ });
101
+ if (isInherit) {
102
+ cp.on("close", (code, signal) => {
103
+ const exitCode = code ?? (signal != null ? 1 : 0);
104
+ const result = { stdout: "", stderr: "", exitCode };
105
+ if (exitCode !== 0 && options.reject !== false) {
106
+ reject(Object.assign(new Error(`Command failed: ${cmd} ${args.join(" ")}`), result));
107
+ }
108
+ else {
109
+ resolve(result);
110
+ }
111
+ });
112
+ return;
113
+ }
114
+ const stdoutChunks = [];
115
+ const stderrChunks = [];
116
+ cp.stdout.on("data", (chunk) => stdoutChunks.push(chunk));
117
+ cp.stderr.on("data", (chunk) => stderrChunks.push(chunk));
118
+ cp.on("close", (code, signal) => {
119
+ const exitCode = code ?? (signal != null ? 1 : 0);
120
+ const stdout = decodeBytes(bytes.concat(stdoutChunks));
121
+ const stderr = decodeBytes(bytes.concat(stderrChunks));
122
+ const result = { stdout, stderr, exitCode };
123
+ if (exitCode !== 0 && options?.reject !== false) {
124
+ reject(Object.assign(new Error(`Command failed: ${cmd} ${args.join(" ")}`), result));
125
+ }
126
+ else {
127
+ resolve(result);
128
+ }
129
+ });
130
+ });
131
+ return new ExecProcess(cp, promise);
132
+ }
133
+ export function execSync(cmd, args, options) {
134
+ const isInherit = options?.stdio === "inherit";
135
+ const result = cpSpawnSync(cmd, args, {
136
+ cwd: options?.cwd,
137
+ env: options?.env != null ? { ...process.env, ...options.env } : undefined,
138
+ stdio: isInherit ? "inherit" : "pipe",
139
+ shell: options?.shell ?? false,
140
+ });
141
+ if (isInherit) {
142
+ return { stdout: "", stderr: "", exitCode: result.status ?? 0 };
143
+ }
144
+ const stdout = decodeBytes(result.stdout);
145
+ const stderr = decodeBytes(result.stderr);
146
+ return { stdout, stderr, exitCode: result.status ?? 0 };
147
+ }
148
+ //#endregion
149
+ //# sourceMappingURL=cp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cp.js","sourceRoot":"","sources":["..\\..\\src\\utils\\cp.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@simplysm/core-node",
3
- "version": "14.0.6",
3
+ "version": "14.0.8",
4
4
  "description": "심플리즘 패키지 - 코어 (node)",
5
5
  "author": "심플리즘",
6
6
  "license": "Apache-2.0",
@@ -25,7 +25,7 @@
25
25
  "glob": "^13.0.6",
26
26
  "minimatch": "^10.2.4",
27
27
  "tsx": "^4.21.0",
28
- "@simplysm/core-common": "14.0.6"
28
+ "@simplysm/core-common": "14.0.8"
29
29
  },
30
30
  "devDependencies": {
31
31
  "@types/node": "^20.19.37"
package/src/index.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  // 유틸리티
2
+ export * as cpx from "./utils/cp";
2
3
  export * as fsx from "./utils/fs";
3
4
  export * as pathx from "./utils/path";
4
5
 
@@ -0,0 +1,202 @@
1
+ import type { ChildProcess } from "child_process";
2
+ import { execSync as cpExecSync, spawn as cpSpawn, spawnSync as cpSpawnSync } from "child_process";
3
+ import { bytes } from "@simplysm/core-common";
4
+
5
+ const CODE_PAGE_MAP: Record<number, string> = {
6
+ 65001: "utf-8",
7
+ 949: "euc-kr",
8
+ 932: "shift-jis",
9
+ 936: "gbk",
10
+ 950: "big5",
11
+ 1252: "windows-1252",
12
+ 1251: "windows-1251",
13
+ 1250: "windows-1250",
14
+ 874: "windows-874",
15
+ };
16
+
17
+ let _cachedEncoding: string | undefined;
18
+
19
+ export function codePageToEncoding(codePage: number): string {
20
+ return CODE_PAGE_MAP[codePage] ?? "utf-8";
21
+ }
22
+
23
+ export function resetEncodingCache(): void {
24
+ _cachedEncoding = undefined;
25
+ }
26
+
27
+ export function getSystemEncoding(): string {
28
+ if (_cachedEncoding != null) return _cachedEncoding;
29
+
30
+ try {
31
+ if (process.platform === "win32") {
32
+ const output = cpExecSync("chcp", { encoding: "utf-8" });
33
+ const match = output.match(/\d+/);
34
+ if (match) {
35
+ _cachedEncoding = codePageToEncoding(Number(match[0]));
36
+ return _cachedEncoding;
37
+ }
38
+ } else {
39
+ const lang = process.env["LANG"] ?? process.env["LC_ALL"] ?? "";
40
+ const dotIndex = lang.indexOf(".");
41
+ if (dotIndex >= 0) {
42
+ let encoding = lang.slice(dotIndex + 1).split("@")[0].toLowerCase();
43
+ if (encoding === "utf8") encoding = "utf-8";
44
+ _cachedEncoding = encoding;
45
+ return _cachedEncoding;
46
+ }
47
+ }
48
+ } catch {
49
+ // 감지 실패 시 fallback
50
+ }
51
+
52
+ _cachedEncoding = "utf-8";
53
+ return _cachedEncoding;
54
+ }
55
+
56
+ //#region exec types
57
+
58
+ export interface ExecOptions {
59
+ cwd?: string;
60
+ env?: Record<string, string>;
61
+ stdio?: "pipe" | "inherit";
62
+ shell?: boolean;
63
+ reject?: boolean;
64
+ }
65
+
66
+ export type ExecSyncOptions = Omit<ExecOptions, "reject">;
67
+
68
+ export interface ExecResult {
69
+ stdout: string;
70
+ stderr: string;
71
+ exitCode: number;
72
+ }
73
+
74
+ //#endregion
75
+
76
+ //#region decodeBytes
77
+
78
+ export function decodeBytes(raw: Uint8Array, systemEncoding?: string): string {
79
+ const encoding = systemEncoding ?? getSystemEncoding();
80
+
81
+ if (encoding === "utf-8") {
82
+ return new TextDecoder("utf-8").decode(raw);
83
+ }
84
+
85
+ try {
86
+ return new TextDecoder("utf-8", { fatal: true }).decode(raw);
87
+ } catch {
88
+ return new TextDecoder(encoding).decode(raw);
89
+ }
90
+ }
91
+
92
+ //#endregion
93
+
94
+ //#region ExecProcess
95
+
96
+ export class ExecProcess implements PromiseLike<ExecResult> {
97
+ private readonly _process: ChildProcess;
98
+ private readonly _promise: Promise<ExecResult>;
99
+
100
+ constructor(cp: ChildProcess, promise: Promise<ExecResult>) {
101
+ this._process = cp;
102
+ this._promise = promise;
103
+ }
104
+
105
+ get pid(): number | undefined {
106
+ return this._process.pid;
107
+ }
108
+
109
+ then<TResult1 = ExecResult, TResult2 = never>(
110
+ onfulfilled?: ((value: ExecResult) => TResult1 | PromiseLike<TResult1>) | null,
111
+ onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,
112
+ ): Promise<TResult1 | TResult2> {
113
+ return this._promise.then(onfulfilled, onrejected);
114
+ }
115
+
116
+ catch<TResult = never>(
117
+ onrejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null,
118
+ ): Promise<ExecResult | TResult> {
119
+ return this._promise.catch(onrejected);
120
+ }
121
+
122
+ kill(signal?: NodeJS.Signals | number): boolean {
123
+ return this._process.kill(signal);
124
+ }
125
+ }
126
+
127
+ //#endregion
128
+
129
+ //#region exec / execSync
130
+
131
+ export function exec(cmd: string, args: string[], options?: ExecOptions): ExecProcess {
132
+ const isInherit = options?.stdio === "inherit";
133
+
134
+ const cp = cpSpawn(cmd, args, {
135
+ cwd: options?.cwd,
136
+ env: options?.env != null ? { ...process.env, ...options.env } : undefined,
137
+ stdio: isInherit ? "inherit" : "pipe",
138
+ shell: options?.shell ?? false,
139
+ });
140
+
141
+ const promise = new Promise<ExecResult>((resolve, reject) => {
142
+ cp.on("error", (err) => {
143
+ reject(Object.assign(err, { stdout: "", stderr: "", exitCode: 1 }));
144
+ });
145
+
146
+ if (isInherit) {
147
+ cp.on("close", (code, signal) => {
148
+ const exitCode = code ?? (signal != null ? 1 : 0);
149
+ const result: ExecResult = { stdout: "", stderr: "", exitCode };
150
+ if (exitCode !== 0 && options.reject !== false) {
151
+ reject(Object.assign(new Error(`Command failed: ${cmd} ${args.join(" ")}`), result));
152
+ } else {
153
+ resolve(result);
154
+ }
155
+ });
156
+ return;
157
+ }
158
+
159
+ const stdoutChunks: Uint8Array[] = [];
160
+ const stderrChunks: Uint8Array[] = [];
161
+
162
+ cp.stdout!.on("data", (chunk: Uint8Array) => stdoutChunks.push(chunk));
163
+ cp.stderr!.on("data", (chunk: Uint8Array) => stderrChunks.push(chunk));
164
+
165
+ cp.on("close", (code, signal) => {
166
+ const exitCode = code ?? (signal != null ? 1 : 0);
167
+ const stdout = decodeBytes(bytes.concat(stdoutChunks));
168
+ const stderr = decodeBytes(bytes.concat(stderrChunks));
169
+ const result: ExecResult = { stdout, stderr, exitCode };
170
+
171
+ if (exitCode !== 0 && options?.reject !== false) {
172
+ reject(Object.assign(new Error(`Command failed: ${cmd} ${args.join(" ")}`), result));
173
+ } else {
174
+ resolve(result);
175
+ }
176
+ });
177
+ });
178
+
179
+ return new ExecProcess(cp, promise);
180
+ }
181
+
182
+ export function execSync(cmd: string, args: string[], options?: ExecSyncOptions): ExecResult {
183
+ const isInherit = options?.stdio === "inherit";
184
+
185
+ const result = cpSpawnSync(cmd, args, {
186
+ cwd: options?.cwd,
187
+ env: options?.env != null ? { ...process.env, ...options.env } : undefined,
188
+ stdio: isInherit ? "inherit" : "pipe",
189
+ shell: options?.shell ?? false,
190
+ });
191
+
192
+ if (isInherit) {
193
+ return { stdout: "", stderr: "", exitCode: result.status ?? 0 };
194
+ }
195
+
196
+ const stdout = decodeBytes(result.stdout as Uint8Array);
197
+ const stderr = decodeBytes(result.stderr as Uint8Array);
198
+
199
+ return { stdout, stderr, exitCode: result.status ?? 0 };
200
+ }
201
+
202
+ //#endregion