@simplysm/sd-cli 12.8.18 → 12.8.21

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 (37) hide show
  1. package/dist/entry/sd-cli-cordova.d.ts +30 -0
  2. package/dist/entry/sd-cli-cordova.js +309 -249
  3. package/dist/entry/sd-cli-cordova.js.map +1 -1
  4. package/dist/entry/sd-cli-project.d.ts +1 -1
  5. package/dist/entry/sd-cli-project.js +8 -9
  6. package/dist/entry/sd-cli-project.js.map +1 -1
  7. package/dist/index.d.ts +1 -0
  8. package/dist/index.js +1 -0
  9. package/dist/index.js.map +1 -1
  10. package/dist/pkg-builders/client/sd-ng.bundler.d.ts +15 -1
  11. package/dist/pkg-builders/client/sd-ng.bundler.js +60 -70
  12. package/dist/pkg-builders/client/sd-ng.bundler.js.map +1 -1
  13. package/dist/pkg-builders/client/sd-ng.plugin-creator.js +49 -29
  14. package/dist/pkg-builders/client/sd-ng.plugin-creator.js.map +1 -1
  15. package/dist/pkg-builders/lib/sd-ts-lib.builder.js +7 -4
  16. package/dist/pkg-builders/lib/sd-ts-lib.builder.js.map +1 -1
  17. package/dist/ts-compiler/sd-ts-compiler.d.ts +24 -2
  18. package/dist/ts-compiler/sd-ts-compiler.js +267 -575
  19. package/dist/ts-compiler/sd-ts-compiler.js.map +1 -1
  20. package/dist/ts-compiler/sd-ts-dependency-analyzer.d.ts +10 -0
  21. package/dist/ts-compiler/sd-ts-dependency-analyzer.js +140 -0
  22. package/dist/ts-compiler/sd-ts-dependency-analyzer.js.map +1 -0
  23. package/dist/types/ts-compiler.types.d.ts +12 -7
  24. package/dist/types/worker.types.d.ts +13 -0
  25. package/dist/utils/sd-cli-performance-time.js +1 -1
  26. package/package.json +10 -12
  27. package/src/entry/sd-cli-cordova.ts +394 -281
  28. package/src/entry/sd-cli-project.ts +11 -23
  29. package/src/index.ts +1 -0
  30. package/src/pkg-builders/client/sd-ng.bundler.ts +70 -69
  31. package/src/pkg-builders/client/sd-ng.plugin-creator.ts +47 -27
  32. package/src/pkg-builders/lib/sd-ts-lib.builder.ts +14 -7
  33. package/src/ts-compiler/sd-ts-compiler.ts +334 -705
  34. package/src/ts-compiler/sd-ts-dependency-analyzer.ts +176 -0
  35. package/src/types/ts-compiler.types.ts +11 -6
  36. package/src/types/worker.types.ts +7 -6
  37. package/src/utils/sd-cli-performance-time.ts +1 -1
@@ -11,76 +11,30 @@ import { SdCliPerformanceTimer } from "../utils/sd-cli-performance-time";
11
11
  import { SdCliConvertMessageUtils } from "../utils/sd-cli-convert-message.utils";
12
12
  import { createWorkerTransformer, } from "@angular/build/src/tools/angular/transformers/web-worker-transformer";
13
13
  import { ESLint } from "eslint";
14
+ import { SdTsDependencyAnalyzer } from "./sd-ts-dependency-analyzer";
14
15
  export class SdTsCompiler {
15
- #logger = SdLogger.get(["simplysm", "sd-cli", "SdTsCompiler"]);
16
- #parsedTsconfig;
17
- #isForAngular;
18
- // readonly #workerRevDependencyCacheMap = new Map<TNormPath, Set<TNormPath>>();
19
- #revDependencyCacheMap = new Map();
20
- #resourceDependencyCacheMap = new Map();
21
- #sourceFileCacheMap = new Map();
22
- #emittedFilesCacheMap = new Map();
23
- #stylesheetBundler;
24
- #compilerHost;
25
- #ngProgram;
26
- #program;
27
- #modifiedFileSet = new Set();
28
- #affectedFileSet = new Set();
29
- #watchFileSet = new Set();
30
- #stylesheetBundlingResultMap = new Map();
31
- #pkgPath;
32
- #distPath;
33
- #globalStyleFilePath;
34
- #watchScopePaths;
35
- #isForBundle;
36
- // readonly #lintWorker = new SdWorker<TSdLintWorkerType>(import.meta.resolve("../workers/lint-worker"));
37
- #perf;
38
- // #processWebWorker?: (workerFile: string, containingFile: string) => string;
39
- constructor(opt) {
40
- this.#pkgPath = opt.pkgPath;
41
- this.#globalStyleFilePath = opt.globalStyleFilePath;
42
- this.#isForBundle = opt.isForBundle;
43
- this.#watchScopePaths = opt.watchScopePaths;
44
- // this.#processWebWorker = opt.processWebWorker;
45
- this.#debug("초기화...");
46
- //-- isForAngular / parsedTsConfig
47
- const tsconfigPath = path.resolve(opt.pkgPath, "tsconfig.json");
16
+ constructor(_opt) {
17
+ this._opt = _opt;
18
+ this._logger = SdLogger.get(["simplysm", "sd-cli", "SdTsCompiler"]);
19
+ this._revDepCacheMap = new Map();
20
+ this._sourceFileCacheMap = new Map();
21
+ this._emittedFilesCacheMap = new Map();
22
+ this._modifiedFileSet = new Set();
23
+ this._affectedFileSet = new Set();
24
+ this._watchFileSet = new Set();
25
+ this._stylesheetBundlingResultMap = new Map();
26
+ this._debug("초기화 중...");
27
+ const tsconfigPath = path.resolve(this._opt.pkgPath, "tsconfig.json");
48
28
  const tsconfig = FsUtils.readJson(tsconfigPath);
49
- this.#isForAngular = Boolean(tsconfig.angularCompilerOptions);
50
- this.#parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, opt.pkgPath, {
51
- ...tsconfig.angularCompilerOptions,
52
- ...opt.additionalOptions,
53
- });
54
- this.#distPath = PathUtils.norm(this.#parsedTsconfig.options.outDir ?? path.resolve(opt.pkgPath, "dist"));
55
- //-- compilerHost
56
- this.#compilerHost = ts.createCompilerHost(this.#parsedTsconfig.options);
57
- const baseGetSourceFile = this.#compilerHost.getSourceFile;
58
- this.#compilerHost.getSourceFile = (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile, ...args) => {
59
- if (!shouldCreateNewSourceFile && this.#sourceFileCacheMap.has(PathUtils.norm(fileName))) {
60
- return this.#sourceFileCacheMap.get(PathUtils.norm(fileName));
61
- }
62
- const sf = baseGetSourceFile.call(this.#compilerHost, fileName, languageVersionOrOptions, onError, true, ...args);
63
- if (sf) {
64
- this.#sourceFileCacheMap.set(PathUtils.norm(fileName), sf);
65
- }
66
- else {
67
- this.#sourceFileCacheMap.delete(PathUtils.norm(fileName));
68
- }
69
- return sf;
70
- };
71
- const baseReadFile = this.#compilerHost.readFile;
72
- this.#compilerHost.readFile = (fileName) => {
73
- this.#watchFileSet.add(PathUtils.norm(fileName));
74
- return baseReadFile.call(this.#compilerHost, fileName);
75
- };
76
- if (this.#isForAngular) {
29
+ this._isForAngular = Boolean(tsconfig.angularCompilerOptions);
30
+ if (this._isForAngular) {
77
31
  //-- stylesheetBundler
78
- this.#stylesheetBundler = new ComponentStylesheetBundler({
79
- workspaceRoot: opt.pkgPath,
80
- optimization: !opt.isDevMode,
32
+ this._stylesheetBundler = new ComponentStylesheetBundler({
33
+ workspaceRoot: this._opt.pkgPath,
34
+ optimization: !this._opt.isDevMode,
81
35
  inlineFonts: true,
82
36
  preserveSymlinks: false,
83
- sourcemap: opt.isDevMode ? "inline" : false,
37
+ sourcemap: this._opt.isDevMode ? "inline" : false,
84
38
  outputNames: { bundles: "[name]", media: "media/[name]" },
85
39
  includePaths: [],
86
40
  externalDependencies: [],
@@ -94,53 +48,116 @@ export class SdTsCompiler {
94
48
  path: ".cache/angular",
95
49
  basePath: ".cache",
96
50
  },
97
- }, "scss", opt.isDevMode);
98
- //-- compilerHost
99
- this.#compilerHost.readResource = (fileName) => {
100
- return this.#compilerHost.readFile(fileName) ?? "";
51
+ }, "scss", this._opt.isDevMode);
52
+ }
53
+ }
54
+ _parseTsConfig() {
55
+ const config = this._loadTsConfig();
56
+ const compilerHost = this._createCompilerHost(config.options);
57
+ return {
58
+ ...config,
59
+ compilerHost,
60
+ };
61
+ }
62
+ _loadTsConfig() {
63
+ const tsconfigPath = path.resolve(this._opt.pkgPath, "tsconfig.json");
64
+ const tsconfig = FsUtils.readJson(tsconfigPath);
65
+ const parsedTsconfig = ts.parseJsonConfigFileContent(tsconfig, ts.sys, this._opt.pkgPath, {
66
+ ...tsconfig.angularCompilerOptions,
67
+ ...this._opt.additionalOptions,
68
+ });
69
+ const distPath = PathUtils.norm(parsedTsconfig.options.outDir ?? path.resolve(this._opt.pkgPath, "dist"));
70
+ return {
71
+ fileNames: parsedTsconfig.fileNames,
72
+ options: parsedTsconfig.options,
73
+ distPath: distPath,
74
+ };
75
+ }
76
+ _createCompilerHost(compilerOptions) {
77
+ const compilerHost = ts.createCompilerHost(compilerOptions);
78
+ const baseGetSourceFile = compilerHost.getSourceFile;
79
+ compilerHost.getSourceFile = (fileName, languageVersionOrOptions, onError, shouldCreateNewSourceFile, ...args) => {
80
+ const fileNPath = PathUtils.norm(fileName);
81
+ if (!shouldCreateNewSourceFile && this._sourceFileCacheMap.has(fileNPath)) {
82
+ return this._sourceFileCacheMap.get(fileNPath);
83
+ }
84
+ const sf = baseGetSourceFile.call(compilerHost, fileName, languageVersionOrOptions, onError, true, ...args);
85
+ if (sf) {
86
+ this._sourceFileCacheMap.set(fileNPath, sf);
87
+ }
88
+ else {
89
+ this._sourceFileCacheMap.delete(fileNPath);
90
+ }
91
+ return sf;
92
+ };
93
+ const baseReadFile = compilerHost.readFile;
94
+ compilerHost.readFile = (fileName) => {
95
+ this._watchFileSet.add(PathUtils.norm(fileName));
96
+ return baseReadFile.call(compilerHost, fileName);
97
+ };
98
+ if (this._isForAngular) {
99
+ compilerHost.readResource = (fileName) => {
100
+ return compilerHost.readFile(fileName) ?? "";
101
101
  };
102
- this.#compilerHost.transformResource = async (data, context) => {
102
+ compilerHost.transformResource = async (data, context) => {
103
103
  if (context.type !== "style") {
104
104
  return null;
105
105
  }
106
- const contents = await this.#bundleStylesheetAsync(data, PathUtils.norm(context.containingFile), context.resourceFile != null ? PathUtils.norm(context.resourceFile) : undefined);
107
- return StringUtils.isNullOrEmpty(contents) ? null : { content: contents };
106
+ const stylesheetBundlingResult = await this._bundleStylesheetAsync(data, PathUtils.norm(context.containingFile), context.resourceFile != null ? PathUtils.norm(context.resourceFile) : undefined);
107
+ return StringUtils.isNullOrEmpty(stylesheetBundlingResult.contents)
108
+ ? null
109
+ : { content: stylesheetBundlingResult.contents };
108
110
  };
109
- this.#compilerHost.getModifiedResourceFiles = () => {
110
- return new Set(Array.from(this.#modifiedFileSet).map((item) => PathUtils.posix(item)));
111
+ compilerHost.getModifiedResourceFiles = () => {
112
+ return new Set(Array.from(this._modifiedFileSet).map((item) => PathUtils.posix(item)));
111
113
  };
112
114
  }
115
+ return compilerHost;
113
116
  }
114
- async #bundleStylesheetAsync(data, containingFile, resourceFile = null) {
117
+ async _bundleStylesheetAsync(data, containingFile, resourceFile = null) {
115
118
  // containingFile: 포함된 파일 (.ts)
116
119
  // resourceFile: 외부 리소스 파일 (styleUrls로 입력하지 않고 styles에 직접 입력한 경우 null)
117
120
  // referencedFiles: import한 외부 scss 파일 혹은 woff파일등 외부 파일
118
121
  // this.#debug(`bundle stylesheet...(${containingFile}, ${resourceFile})`);
119
- return await this.#perf.run("bundle style", async () => {
120
- const stylesheetResult = resourceFile != null
121
- ? await this.#stylesheetBundler.bundleFile(resourceFile)
122
- : await this.#stylesheetBundler.bundleInline(data, containingFile, "scss");
123
- if (stylesheetResult.referencedFiles) {
124
- for (const referencedFile of stylesheetResult.referencedFiles) {
125
- const depCacheSet = this.#resourceDependencyCacheMap.getOrCreate(PathUtils.norm(referencedFile), new Set());
126
- depCacheSet.add(resourceFile ?? containingFile);
122
+ return await this._perf.run("스타일 번들링", async () => {
123
+ const fileNPath = PathUtils.norm(resourceFile ?? containingFile);
124
+ if (this._stylesheetBundlingResultMap.has(fileNPath)) {
125
+ return this._stylesheetBundlingResultMap.get(fileNPath);
126
+ }
127
+ try {
128
+ const result = resourceFile != null
129
+ ? await this._stylesheetBundler.bundleFile(resourceFile)
130
+ : await this._stylesheetBundler.bundleInline(data, containingFile, "scss");
131
+ if (result.referencedFiles) {
132
+ for (const referencedFile of result.referencedFiles) {
133
+ const depCacheSet = this._revDepCacheMap.getOrCreate(PathUtils.norm(referencedFile), new Set());
134
+ depCacheSet.add(fileNPath);
135
+ }
136
+ this._watchFileSet.adds(...Array.from(result.referencedFiles.values())
137
+ .map((item) => PathUtils.norm(item)));
127
138
  }
128
- this.#watchFileSet.adds(...Array.from(stylesheetResult.referencedFiles.values())
129
- .map((item) => PathUtils.norm(item)));
139
+ this._stylesheetBundlingResultMap.set(fileNPath, result);
140
+ return result;
141
+ }
142
+ catch (err) {
143
+ const result = {
144
+ errors: [
145
+ {
146
+ text: `스타일 번들링 실패: ${err.message ?? "알 수 없는 오류"}`,
147
+ location: { file: containingFile },
148
+ },
149
+ ],
150
+ warnings: [],
151
+ };
152
+ this._stylesheetBundlingResultMap.set(fileNPath, result);
153
+ return result;
130
154
  }
131
- this.#stylesheetBundlingResultMap.set(PathUtils.norm(resourceFile ?? containingFile), {
132
- outputFiles: stylesheetResult.errors == null ? stylesheetResult.outputFiles : undefined,
133
- metafile: stylesheetResult.errors == null ? stylesheetResult.metafile : undefined,
134
- errors: stylesheetResult.errors,
135
- warnings: stylesheetResult.warnings,
136
- });
137
- return stylesheetResult.contents;
138
155
  });
139
156
  }
140
157
  async compileAsync(modifiedFileSet) {
141
- this.#perf = new SdCliPerformanceTimer("esbuild compile");
142
- this.#modifiedFileSet = new Set(modifiedFileSet);
143
- this.#affectedFileSet = new Set();
158
+ this._perf = new SdCliPerformanceTimer("esbuild compile");
159
+ this._modifiedFileSet = new Set(modifiedFileSet);
160
+ this._affectedFileSet = new Set();
144
161
  /*for (const mod of modifiedFileSet) {
145
162
  const workerImporters = this.#workerRevDependencyCacheMap.get(mod);
146
163
  if (workerImporters) {
@@ -149,146 +166,118 @@ export class SdTsCompiler {
149
166
  this.#modifiedFileSet.add(mod);
150
167
  }
151
168
  }*/
152
- const prepareResult = await this.#prepareAsync();
153
- const [buildResult, lintResults] = await Promise.all([this.#buildAsync(), this.#lintAsync()]);
154
- this.#debug(`build completed`, this.#perf.toString());
169
+ const tsconf = this._parseTsConfig();
170
+ const prepareResult = await this._prepareAsync(tsconf);
171
+ const [buildResult, lintResults] = await Promise.all([
172
+ this._buildAsync(tsconf),
173
+ this._lintAsync(),
174
+ ]);
175
+ this._debug(`빌드 완료됨`, this._perf.toString());
176
+ this._debug(`영향 받은 파일: ${this._affectedFileSet.size}개`);
177
+ this._debug(`감시 중인 파일: ${this._watchFileSet.size}개`);
155
178
  return {
156
179
  messages: [
157
180
  ...prepareResult.messages,
158
181
  ...SdCliConvertMessageUtils.convertToBuildMessagesFromTsDiag(buildResult.diagnostics),
159
182
  ...SdCliConvertMessageUtils.convertToBuildMessagesFromEslint(lintResults),
160
183
  ],
161
- watchFileSet: this.#watchFileSet,
162
- affectedFileSet: this.#affectedFileSet,
163
- stylesheetBundlingResultMap: this.#stylesheetBundlingResultMap,
164
- emittedFilesCacheMap: this.#emittedFilesCacheMap,
184
+ watchFileSet: this._watchFileSet,
185
+ affectedFileSet: this._affectedFileSet,
186
+ stylesheetBundlingResultMap: this._stylesheetBundlingResultMap,
187
+ emittedFilesCacheMap: this._emittedFilesCacheMap,
165
188
  emitFileSet: buildResult.emitFileSet,
166
189
  };
167
190
  }
168
- async #prepareAsync() {
169
- if (this.#modifiedFileSet.size !== 0) {
170
- this.#debug(`get affected (old deps & old res deps)...`);
171
- this.#perf.run("get affected", () => {
172
- for (const modifiedFile of this.#modifiedFileSet) {
173
- this.#affectedFileSet.add(modifiedFile);
174
- this.#affectedFileSet.adds(...(this.#revDependencyCacheMap.get(modifiedFile) ?? []));
175
- this.#affectedFileSet.adds(...(this.#resourceDependencyCacheMap.get(modifiedFile) ?? []));
191
+ async _prepareAsync(tsconf) {
192
+ if (this._modifiedFileSet.size !== 0) {
193
+ this._debug(`영향 받은 파일 추적 중... (구 의존성)`);
194
+ this._perf.run("영향 받은 파일 추적", () => {
195
+ for (const modifiedFile of this._modifiedFileSet) {
196
+ this._affectedFileSet.add(modifiedFile);
197
+ this._affectedFileSet.adds(...(this._revDepCacheMap.get(modifiedFile) ?? []));
198
+ // .d.ts .js 대응
199
+ if (modifiedFile.endsWith(".d.ts")) {
200
+ const jsEquivalent = PathUtils.norm(modifiedFile.replace(/\.d\.ts$/, ".js"));
201
+ this._affectedFileSet.add(jsEquivalent);
202
+ }
176
203
  }
177
204
  });
178
- this.#debug(`invalidate & clear cache...`);
179
- this.#perf.run("invalidate & clear cache", () => {
180
- this.#stylesheetBundler?.invalidate(this.#affectedFileSet);
181
- for (const affectedFile of this.#affectedFileSet) {
182
- this.#emittedFilesCacheMap.delete(affectedFile);
183
- this.#sourceFileCacheMap.delete(affectedFile);
184
- this.#stylesheetBundlingResultMap.delete(affectedFile);
185
- this.#watchFileSet.delete(affectedFile);
205
+ this._debug(`캐시 무효화 초기화 중...`);
206
+ this._perf.run("캐시 무효화 초기화", () => {
207
+ this._stylesheetBundler?.invalidate(this._affectedFileSet);
208
+ for (const affectedFile of this._affectedFileSet) {
209
+ this._emittedFilesCacheMap.delete(affectedFile);
210
+ this._sourceFileCacheMap.delete(affectedFile);
211
+ this._stylesheetBundlingResultMap.delete(affectedFile);
212
+ this._watchFileSet.delete(affectedFile);
213
+ for (const [key, deps] of this._revDepCacheMap.entries()) {
214
+ if (key === affectedFile) {
215
+ this._revDepCacheMap.delete(key);
216
+ continue;
217
+ }
218
+ if (deps.has(affectedFile)) {
219
+ deps.delete(affectedFile);
220
+ if (deps.size === 0) {
221
+ this._revDepCacheMap.delete(key);
222
+ }
223
+ }
224
+ }
186
225
  }
187
- this.#revDependencyCacheMap.clear();
188
- this.#resourceDependencyCacheMap.clear();
189
226
  });
190
227
  }
191
- this.#debug(`create program...`);
192
- this.#perf.run("create program", () => {
193
- if (this.#isForAngular) {
194
- this.#ngProgram = new NgtscProgram(this.#parsedTsconfig.fileNames, this.#parsedTsconfig.options, this.#compilerHost, this.#ngProgram);
195
- this.#program = this.#ngProgram.getTsProgram();
228
+ this._debug(`ts.Program 생성 중...`);
229
+ this._perf.run("ts.Program 생성", () => {
230
+ if (this._isForAngular) {
231
+ this._ngProgram = new NgtscProgram(tsconf.fileNames, tsconf.options, tsconf.compilerHost, this._ngProgram);
232
+ this._program = this._ngProgram.getTsProgram();
196
233
  }
197
234
  else {
198
- this.#program = ts.createProgram(this.#parsedTsconfig.fileNames, this.#parsedTsconfig.options, this.#compilerHost, this.#program);
235
+ this._program = ts.createProgram(tsconf.fileNames, tsconf.options, tsconf.compilerHost, this._program);
199
236
  }
200
237
  });
201
- if (this.#ngProgram) {
202
- await this.#perf.run("ng analyze", async () => {
203
- await this.#ngProgram.compiler.analyzeAsync();
238
+ if (this._ngProgram) {
239
+ await this._perf.run("Angular 템플릿 분석", async () => {
240
+ await this._ngProgram.compiler.analyzeAsync();
204
241
  });
205
242
  }
206
- const getOrgSourceFile = (sf) => {
207
- if (sf.fileName.endsWith(".ngtypecheck.ts")) {
208
- const orgFileName = sf.fileName.slice(0, -15) + ".ts";
209
- return this.#program.getSourceFile(orgFileName);
210
- }
211
- return sf;
212
- };
213
- const sourceFileSet = new Set(this.#program.getSourceFiles()
214
- .map((sf) => getOrgSourceFile(sf))
215
- .filterExists());
216
- this.#debug(`get new deps...`);
243
+ this._debug(`새 의존성 분석 중...`);
217
244
  const messages = [];
218
- this.#perf.run("get new deps", () => {
219
- const depMap = new Map();
220
- for (const sf of sourceFileSet) {
221
- if (!this.#watchScopePaths.some((scopePath) => PathUtils.isChildPath(sf.fileName, scopePath))) {
222
- continue;
223
- }
224
- const refs = this.#findDeps(sf);
225
- messages.push(...refs.filter((item) => "severity" in item));
226
- depMap.set(PathUtils.norm(sf.fileName), refs
227
- .filter((item) => "fileName" in item)
228
- .filter((item) => this.#watchScopePaths.some((scopePath) => PathUtils.isChildPath(item.fileName, scopePath))));
229
- }
230
- const allDepMap = new Map();
231
- const getAllDeps = (fileName, prevSet) => {
232
- if (allDepMap.has(fileName)) {
233
- return allDepMap.get(fileName);
234
- }
235
- const result = new Set();
236
- const deps = depMap.get(fileName) ?? [];
237
- result.adds(...deps.map((item) => item.fileName));
245
+ const analysed1 = this._perf.run(" 의존성 분석", () => {
246
+ const analysed = SdTsDependencyAnalyzer.analyze(this._program, tsconf.compilerHost, this._opt.watchScopePaths);
247
+ messages.push(...analysed.messages);
248
+ for (const sf of analysed.sourceFileSet) {
249
+ const filePath = PathUtils.norm(sf.fileName);
250
+ const deps = analysed.allDepMap.get(filePath) ?? new Set();
238
251
  for (const dep of deps) {
239
- const targetDeps = depMap.get(dep.fileName) ?? [];
240
- if (dep.importName === "*") {
241
- for (const targetRefItem of targetDeps.filter((item) => item.exportName != null)) {
242
- if (prevSet?.has(targetRefItem.fileName))
243
- continue;
244
- result.add(targetRefItem.fileName);
245
- result.adds(...getAllDeps(targetRefItem.fileName, new Set(prevSet).adds(...result)));
246
- }
247
- }
248
- else {
249
- for (const targetRefItem of targetDeps.filter((item) => item.exportName
250
- === dep.importName)) {
251
- if (prevSet?.has(targetRefItem.fileName))
252
- continue;
253
- result.add(targetRefItem.fileName);
254
- result.adds(...getAllDeps(targetRefItem.fileName, new Set(prevSet).adds(...result)));
255
- }
256
- }
252
+ const depCache = this._revDepCacheMap.getOrCreate(dep, new Set());
253
+ depCache.add(filePath);
257
254
  }
258
- return result;
259
- };
260
- for (const sf of sourceFileSet) {
261
- const deps = getAllDeps(PathUtils.norm(sf.fileName));
262
- allDepMap.set(PathUtils.norm(sf.fileName), deps);
263
- for (const dep of getAllDeps(PathUtils.norm(sf.fileName))) {
264
- const depCache = this.#revDependencyCacheMap.getOrCreate(dep, new Set());
265
- depCache.add(PathUtils.norm(sf.fileName));
266
- }
267
- if (this.#ngProgram) {
268
- if (this.#ngProgram.compiler.ignoreForEmit.has(sf)) {
255
+ if (this._ngProgram) {
256
+ if (this._ngProgram.compiler.ignoreForEmit.has(sf)) {
269
257
  continue;
270
258
  }
271
- for (const dep of this.#ngProgram.compiler.getResourceDependencies(sf)) {
272
- const ref = this.#resourceDependencyCacheMap.getOrCreate(PathUtils.norm(dep), new Set());
273
- ref.add(PathUtils.norm(sf.fileName));
259
+ for (const dep of this._ngProgram.compiler.getResourceDependencies(sf)) {
260
+ const ref = this._revDepCacheMap.getOrCreate(PathUtils.norm(dep), new Set());
261
+ ref.add(filePath);
274
262
  }
275
263
  }
276
264
  }
265
+ return analysed;
277
266
  });
278
- if (this.#modifiedFileSet.size === 0) {
279
- this.#debug(`get affected (init)...`);
280
- this.#perf.run("get affected (init)", () => {
281
- for (const sf of sourceFileSet) {
282
- if (!this.#watchScopePaths.some((scopePath) => PathUtils.isChildPath(sf.fileName, scopePath))) {
267
+ if (this._modifiedFileSet.size === 0) {
268
+ this._debug(`영향 받은 파일 추가 중... (새 의존성)`);
269
+ this._perf.run("영향 받은 파일 추가 중 (새 의존성)", () => {
270
+ for (const sf of analysed1.sourceFileSet) {
271
+ if (!this._opt.watchScopePaths.some((scopePath) => PathUtils.isChildPath(sf.fileName, scopePath))) {
283
272
  continue;
284
273
  }
285
- this.#affectedFileSet.add(PathUtils.norm(sf.fileName));
274
+ this._affectedFileSet.add(PathUtils.norm(sf.fileName));
286
275
  }
287
276
  });
288
277
  }
289
- for (const dep of this.#revDependencyCacheMap.keys()) {
290
- if (this.#modifiedFileSet.has(dep)) {
291
- this.#affectedFileSet.adds(...Array.from(this.#revDependencyCacheMap.get(dep)).mapMany((item) => [
278
+ for (const dep of this._revDepCacheMap.keys()) {
279
+ if (this._modifiedFileSet.has(dep)) {
280
+ this._affectedFileSet.adds(...Array.from(this._revDepCacheMap.get(dep)).mapMany((item) => [
292
281
  item,
293
282
  // .d.ts면 .js파일도 affected에 추가
294
283
  item.endsWith(".d.ts") ? PathUtils.norm(item.replace(/\.d\.ts$/, ".js")) : undefined,
@@ -296,29 +285,17 @@ export class SdTsCompiler {
296
285
  }
297
286
  // dep이 emit된적이 없으면 affected에 추가해야함.
298
287
  // dep파일이 추가된후 기존 파일에서 import하면 dep파일이 affected에 포함이 안되는 현상 때문
299
- if (!this.#emittedFilesCacheMap.has(dep)) {
300
- this.#affectedFileSet.add(dep);
301
- }
302
- }
303
- if (this.#ngProgram) {
304
- for (const dep of this.#resourceDependencyCacheMap.keys()) {
305
- if (this.#modifiedFileSet.has(dep)) {
306
- this.#affectedFileSet.adds(...this.#resourceDependencyCacheMap.get(dep));
307
- }
308
- // dep이 emit된적이 없으면 affected에 추가해야함.
309
- // dep파일이 추가된후 기존 파일에서 import하면 dep파일이 affected에 포함이 안되는 현상 때문
310
- if (!this.#emittedFilesCacheMap.has(dep)) {
311
- this.#affectedFileSet.add(dep);
312
- }
288
+ if (!this._emittedFilesCacheMap.has(dep)) {
289
+ this._affectedFileSet.add(dep);
313
290
  }
314
291
  }
315
292
  return {
316
293
  messages,
317
294
  };
318
295
  }
319
- async #lintAsync() {
320
- const lintFilePaths = Array.from(this.#affectedFileSet)
321
- .filter((item) => PathUtils.isChildPath(item, this.#pkgPath))
296
+ async _lintAsync() {
297
+ const lintFilePaths = Array.from(this._affectedFileSet)
298
+ .filter((item) => PathUtils.isChildPath(item, this._opt.pkgPath))
322
299
  .filter((item) => ((!item.endsWith(".d.ts") && item.endsWith(".ts")) ||
323
300
  item.endsWith(".js")))
324
301
  .filter((item) => FsUtils.exists(item));
@@ -326,14 +303,14 @@ export class SdTsCompiler {
326
303
  return [];
327
304
  }
328
305
  const linter = new ESLint({
329
- cwd: this.#pkgPath,
306
+ cwd: this._opt.pkgPath,
330
307
  cache: false,
331
308
  overrideConfig: {
332
309
  languageOptions: {
333
310
  parserOptions: {
334
311
  // parser: tseslint.parser,
335
312
  project: null,
336
- programs: [this.#program],
313
+ programs: [this._program],
337
314
  },
338
315
  },
339
316
  },
@@ -346,206 +323,88 @@ export class SdTsCompiler {
346
323
  // },
347
324
  // ]);
348
325
  }
349
- async #buildAsync() {
326
+ async _buildAsync(tsconf) {
350
327
  const emitFileSet = new Set();
351
328
  const diagnostics = [];
352
- this.#debug(`get diagnostics...`);
353
- this.#perf.run("get program diagnostics", () => {
354
- diagnostics.push(...this.#program.getConfigFileParsingDiagnostics(), ...this.#program.getOptionsDiagnostics(), ...this.#program.getGlobalDiagnostics());
355
- if (this.#ngProgram) {
356
- diagnostics.push(...this.#ngProgram.compiler.getOptionDiagnostics());
329
+ this._debug(`프로그램 진단 수집 중...`);
330
+ this._perf.run("프로그램 진단 수집", () => {
331
+ diagnostics.push(...this._program.getConfigFileParsingDiagnostics(), ...this._program.getOptionsDiagnostics(), ...this._program.getGlobalDiagnostics());
332
+ if (this._ngProgram) {
333
+ diagnostics.push(...this._ngProgram.compiler.getOptionDiagnostics());
357
334
  }
358
335
  });
359
- this.#debug(`get diagnostics of files...`);
360
- for (const affectedFile of this.#affectedFileSet) {
361
- if (!PathUtils.isChildPath(affectedFile, this.#pkgPath)) {
336
+ this._debug(`개별 파일 진단 수집 중...`);
337
+ for (const affectedFile of this._affectedFileSet) {
338
+ if (!PathUtils.isChildPath(affectedFile, this._opt.pkgPath))
362
339
  continue;
363
- }
364
- const affectedSourceFile = this.#program.getSourceFile(affectedFile);
340
+ const affectedSourceFile = this._program.getSourceFile(affectedFile);
365
341
  if (!affectedSourceFile ||
366
- (this.#ngProgram && this.#ngProgram.compiler.ignoreForDiagnostics.has(affectedSourceFile))) {
342
+ (this._ngProgram && this._ngProgram.compiler.ignoreForDiagnostics.has(affectedSourceFile))) {
367
343
  continue;
368
344
  }
369
345
  // this.#debug(`get diagnostics of file ${affectedFile}...`);
370
- this.#perf.run("get file diagnostics", () => {
371
- diagnostics.push(...this.#program.getSyntacticDiagnostics(affectedSourceFile), ...this.#program.getSemanticDiagnostics(affectedSourceFile));
346
+ this._perf.run("개별 파일 진단 수집", () => {
347
+ diagnostics.push(...this._program.getSyntacticDiagnostics(affectedSourceFile), ...this._program.getSemanticDiagnostics(affectedSourceFile));
372
348
  });
373
- if (this.#ngProgram) {
374
- this.#perf.run("get file diagnostics: ng", () => {
375
- if (affectedSourceFile.isDeclarationFile) {
349
+ if (this._ngProgram) {
350
+ this._perf.run("개별 파일 진단 수집(Angular)", () => {
351
+ if (affectedSourceFile.isDeclarationFile)
376
352
  return;
377
- }
378
- diagnostics.push(...this.#ngProgram.compiler.getDiagnosticsForFile(affectedSourceFile, OptimizeFor.WholeProgram));
353
+ diagnostics.push(...this._ngProgram.compiler.getDiagnosticsForFile(affectedSourceFile, OptimizeFor.WholeProgram));
379
354
  });
380
355
  }
381
356
  }
382
- this.#perf.run("emit", () => {
383
- this.#debug(`prepare emit...`);
357
+ this._perf.run("파일 출력 (emit)", () => {
358
+ this._debug(`파일 출력 준비 중...`);
384
359
  let transformers = {};
385
- if (this.#ngProgram) {
360
+ if (this._ngProgram) {
386
361
  transformers = {
387
362
  ...transformers,
388
- ...this.#ngProgram.compiler.prepareEmit().transformers,
363
+ ...this._ngProgram.compiler.prepareEmit().transformers,
389
364
  };
390
- (transformers.before ??= []).push(replaceBootstrap(() => this.#program.getTypeChecker()));
365
+ (transformers.before ??= []).push(replaceBootstrap(() => this._program.getTypeChecker()));
391
366
  (transformers.before ??= []).push(createWorkerTransformer((file, importer) => {
392
367
  const fullPath = path.resolve(path.dirname(importer), file);
393
- const relPath = path.relative(path.resolve(this.#pkgPath, "src"), fullPath);
368
+ const relPath = path.relative(path.resolve(this._opt.pkgPath, "src"), fullPath);
394
369
  return relPath.replace(/\.ts$/, "").replaceAll("\\", "/") + ".js";
395
370
  }));
396
371
  }
397
- // (transformers.before ??= []).push(transformKeys(this.#program));
398
- /*const fixImportTransformer: ts.TransformerFactory<ts.SourceFile> = (context) => {
399
- return (sf) => {
400
- const shouldAppendJs = (importText: string): string | undefined => {
401
- const resolved = ts.resolveModuleName(
402
- importText,
403
- sf.fileName,
404
- this.#program!.getCompilerOptions(),
405
- ts.sys,
406
- );
407
-
408
- const resolvedInfo = resolved.resolvedModule;
409
- if (!resolvedInfo) return undefined;
410
-
411
- const resolvedFileName = resolvedInfo.resolvedFileName;
412
-
413
- // ① .ts / .tsx / .js / .jsx 만 대상
414
- if (!/\.(d\.ts|ts|tsx|js|jsx)$/i.test(resolvedFileName)) return undefined;
415
-
416
- // ② 사용자가 .js, .mjs, .json 등 명시한 경우 무시
417
- if (/\.[mc]?js$|\.json$/i.test(importText)) return undefined;
418
-
419
- // 3. import 경로의 마지막 부분이 파일명(확장자 제외)과 같으면 → .js 붙여야 함
420
- const importLastName = importText.split("/").pop();
421
- const resolvedFileNameOnly = path.basename(resolvedFileName)
422
- .replace(/\.(d\.ts|ts|tsx|js|jsx)$/, "");
423
-
424
- if (importLastName === resolvedFileNameOnly) {
425
- return importText + ".js";
426
- }
427
-
428
- // 4. 그렇지 않으면 → index.ts 같은 루트 패키지 import → .js 붙이지 않음
429
- return undefined;
430
- };
431
-
432
- const visitor: ts.Visitor = (node): ts.Node => {
433
- // import { x } from "./foo"
434
- if (
435
- ts.isImportDeclaration(node) &&
436
- ts.isStringLiteral(node.moduleSpecifier)
437
- ) {
438
- const newPath = shouldAppendJs(node.moduleSpecifier.text);
439
- if (newPath != null) {
440
- return ts.factory.updateImportDeclaration(
441
- node,
442
- node.modifiers,
443
- node.importClause,
444
- ts.factory.createStringLiteral(newPath),
445
- undefined,
446
- );
447
- }
448
- }
449
-
450
- // export * from "./bar"
451
- if (
452
- ts.isExportDeclaration(node) &&
453
- node.moduleSpecifier &&
454
- ts.isStringLiteral(node.moduleSpecifier)
455
- ) {
456
- const newPath = shouldAppendJs(node.moduleSpecifier.text);
457
- if (newPath != null) {
458
- return ts.factory.updateExportDeclaration(
459
- node,
460
- node.modifiers,
461
- node.isTypeOnly,
462
- node.exportClause,
463
- ts.factory.createStringLiteral(newPath),
464
- undefined,
465
- );
466
- }
467
- }
468
-
469
- // dynamic import("./baz")
470
- if (
471
- ts.isCallExpression(node) &&
472
- node.expression.kind === ts.SyntaxKind.ImportKeyword &&
473
- node.arguments.length === 1 &&
474
- ts.isStringLiteral(node.arguments[0])
475
- ) {
476
- const newPath = shouldAppendJs(node.arguments[0].text);
477
- if (newPath != null) {
478
- return ts.factory.updateCallExpression(
479
- node,
480
- node.expression,
481
- undefined,
482
- [ts.factory.createStringLiteral(newPath)],
483
- );
484
- }
485
- }
486
-
487
- return ts.visitEachChild(node, visitor, context);
488
- };
489
-
490
- return ts.visitNode(sf, visitor) as ts.SourceFile;
491
- };
492
- };
493
- (transformers.before ??= []).push(fixImportTransformer);*/
494
- this.#debug(`emit for files...`);
372
+ this._debug(`파일 출력 중...`);
495
373
  // affected에 새로 추가된 파일은 포함되지 않는 현상이 있어 sourceFileSet으로 바꿈
496
374
  // 비교해보니, 딱히 getSourceFiles라서 더 느려지는것 같지는 않음
497
375
  // 그래도 affected로 다시 테스트 (조금이라도 더 빠르게)
498
- for (const affectedFile of this.#affectedFileSet) {
499
- if (this.#emittedFilesCacheMap.has(affectedFile)) {
376
+ for (const affectedFile of this._affectedFileSet) {
377
+ if (this._emittedFilesCacheMap.has(affectedFile))
500
378
  continue;
501
- }
502
- const sf = this.#program.getSourceFile(affectedFile);
503
- if (!sf) {
379
+ const sf = this._program.getSourceFile(affectedFile);
380
+ if (!sf || sf.isDeclarationFile)
504
381
  continue;
505
- }
506
- if (sf.isDeclarationFile) {
382
+ if (this._ngProgram?.compiler.ignoreForEmit.has(sf))
507
383
  continue;
508
- }
509
- if (this.#ngProgram?.compiler.ignoreForEmit.has(sf)) {
384
+ if (this._ngProgram?.compiler.incrementalCompilation.safeToSkipEmit(sf))
510
385
  continue;
511
- }
512
- if (this.#ngProgram?.compiler.incrementalCompilation.safeToSkipEmit(sf)) {
386
+ // 번들이 아닌 외부패키지는 보통 emit안해도 됨
387
+ // but esbuild를 통해 bundle로 묶어야 하는놈들은 모든 output이 있어야 함.
388
+ if (!this._opt.isForBundle && !PathUtils.isChildPath(sf.fileName, this._opt.pkgPath)) {
513
389
  continue;
514
390
  }
515
- // esbuild를 통해 bundle로 묶어야 하는놈들은 모든 output이 있어야 함.
516
- if (!this.#isForBundle) {
517
- if (!PathUtils.isChildPath(sf.fileName, this.#pkgPath)) {
518
- continue;
519
- }
520
- }
521
- this.#program.emit(sf, (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
391
+ this._program.emit(sf, (fileName, text, writeByteOrderMark, onError, sourceFiles, data) => {
522
392
  if (!sourceFiles || sourceFiles.length === 0) {
523
- this.#compilerHost.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
393
+ tsconf.compilerHost.writeFile(fileName, text, writeByteOrderMark, onError, sourceFiles, data);
524
394
  return;
525
395
  }
526
396
  const sourceFile = ts.getOriginalNode(sourceFiles[0], ts.isSourceFile);
527
- if (this.#ngProgram) {
528
- if (this.#ngProgram.compiler.ignoreForEmit.has(sourceFile)) {
397
+ if (this._ngProgram) {
398
+ if (this._ngProgram.compiler.ignoreForEmit.has(sourceFile))
529
399
  return;
530
- }
531
- this.#ngProgram.compiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
400
+ this._ngProgram.compiler.incrementalCompilation.recordSuccessfulEmit(sourceFile);
532
401
  }
533
- const emitFileInfoCaches = this.#emittedFilesCacheMap.getOrCreate(PathUtils.norm(sourceFile.fileName), []);
534
- if (PathUtils.isChildPath(sourceFile.fileName, this.#pkgPath)) {
535
- let realFilePath = PathUtils.norm(fileName);
536
- let realText = text;
537
- if (PathUtils.isChildPath(realFilePath, path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"))) {
538
- realFilePath = PathUtils.norm(this.#distPath, path.relative(path.resolve(this.#distPath, path.basename(this.#pkgPath), "src"), realFilePath));
539
- if (fileName.endsWith(".js.map")) {
540
- const sourceMapContents = JSON.parse(realText);
541
- // remove "../../"
542
- sourceMapContents.sources[0] = sourceMapContents.sources[0].slice(6);
543
- realText = JSON.stringify(sourceMapContents);
544
- }
545
- }
402
+ const emitFileInfoCaches = this._emittedFilesCacheMap.getOrCreate(PathUtils.norm(sourceFile.fileName), []);
403
+ if (PathUtils.isChildPath(sourceFile.fileName, this._opt.pkgPath)) {
404
+ const real = this._convertOutputToReal(fileName, tsconf.distPath, text);
546
405
  emitFileInfoCaches.push({
547
- outAbsPath: realFilePath,
548
- text: realText,
406
+ outAbsPath: real.filePath,
407
+ text: real.text,
549
408
  });
550
409
  }
551
410
  else {
@@ -556,20 +415,20 @@ export class SdTsCompiler {
556
415
  }
557
416
  });
558
417
  //-- global style
559
- if (this.#globalStyleFilePath != null &&
560
- FsUtils.exists(this.#globalStyleFilePath) &&
561
- !this.#emittedFilesCacheMap.has(this.#globalStyleFilePath)) {
562
- this.#debug(`bundle global style...`);
563
- await this.#perf.run("bundle global style", async () => {
564
- const data = FsUtils.readFile(this.#globalStyleFilePath);
565
- const contents = await this.#bundleStylesheetAsync(data, this.#globalStyleFilePath, this.#globalStyleFilePath);
566
- const emitFileInfos = this.#emittedFilesCacheMap.getOrCreate(this.#globalStyleFilePath, []);
418
+ if (this._opt.globalStyleFilePath != null &&
419
+ FsUtils.exists(this._opt.globalStyleFilePath) &&
420
+ !this._emittedFilesCacheMap.has(this._opt.globalStyleFilePath)) {
421
+ this._debug(`전역 스타일 번들링 중...`);
422
+ await this._perf.run("전역 스타일 번들링", async () => {
423
+ const data = FsUtils.readFile(this._opt.globalStyleFilePath);
424
+ const stylesheetBundlingResult = await this._bundleStylesheetAsync(data, this._opt.globalStyleFilePath, this._opt.globalStyleFilePath);
425
+ const emitFileInfos = this._emittedFilesCacheMap.getOrCreate(this._opt.globalStyleFilePath, []);
567
426
  emitFileInfos.push({
568
- outAbsPath: PathUtils.norm(this.#pkgPath, path.relative(path.resolve(this.#pkgPath, "src"), this.#globalStyleFilePath)
427
+ outAbsPath: PathUtils.norm(this._opt.pkgPath, path.relative(path.resolve(this._opt.pkgPath, "src"), this._opt.globalStyleFilePath)
569
428
  .replace(/\.scss$/, ".css")),
570
- text: contents,
429
+ text: stylesheetBundlingResult.contents ?? "",
571
430
  });
572
- emitFileSet.add(this.#globalStyleFilePath);
431
+ emitFileSet.add(this._opt.globalStyleFilePath);
573
432
  });
574
433
  }
575
434
  return {
@@ -577,190 +436,23 @@ export class SdTsCompiler {
577
436
  diagnostics,
578
437
  };
579
438
  }
580
- #debug(...msg) {
581
- this.#logger.debug(`[${path.basename(this.#pkgPath)}]`, ...msg);
582
- }
583
- #findDeps(sf) {
584
- const deps = [];
585
- const tc = this.#program.getTypeChecker();
586
- const visit = (node) => {
587
- if (ts.isExportDeclaration(node)) {
588
- if (node.moduleSpecifier) {
589
- const moduleSymbol = tc.getSymbolAtLocation(node.moduleSpecifier);
590
- if (!moduleSymbol) {
591
- const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
592
- deps.push({
593
- filePath: PathUtils.norm(sf.fileName),
594
- line: pos.line,
595
- char: pos.character,
596
- code: undefined,
597
- severity: "error",
598
- message: "export moduleSymbol not found",
599
- type: "deps",
600
- });
601
- return;
602
- }
603
- const decls = moduleSymbol.getDeclarations();
604
- if (!decls) {
605
- const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
606
- deps.push({
607
- filePath: PathUtils.norm(sf.fileName),
608
- line: pos.line,
609
- char: pos.character,
610
- code: undefined,
611
- severity: "error",
612
- message: "export decls not found",
613
- type: "deps",
614
- });
615
- return;
616
- }
617
- const namedBindings = node.exportClause;
618
- if (namedBindings && ts.isNamedExports(namedBindings)) {
619
- for (const el of namedBindings.elements) {
620
- for (const decl of decls) {
621
- deps.push({
622
- fileName: PathUtils.norm(decl.getSourceFile().fileName),
623
- importName: el.name.text,
624
- exportName: el.propertyName?.text ?? el.name.text,
625
- });
626
- }
627
- }
628
- }
629
- else {
630
- if (!moduleSymbol.exports) {
631
- const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
632
- deps.push({
633
- filePath: PathUtils.norm(sf.fileName),
634
- line: pos.line,
635
- char: pos.character,
636
- code: undefined,
637
- severity: "error",
638
- message: "moduleSymbol exports not found",
639
- type: "deps",
640
- });
641
- return;
642
- }
643
- for (const decl of decls) {
644
- for (const key of moduleSymbol.exports.keys()) {
645
- deps.push({
646
- fileName: PathUtils.norm(decl.getSourceFile().fileName),
647
- importName: key.toString(),
648
- exportName: key.toString(),
649
- });
650
- }
651
- }
652
- }
653
- }
654
- }
655
- else if (ts.isImportDeclaration(node)) {
656
- const moduleSymbol = tc.getSymbolAtLocation(node.moduleSpecifier);
657
- if (!moduleSymbol) {
658
- if (ts.isStringLiteral(node.moduleSpecifier)
659
- && node.moduleSpecifier.text.startsWith("./")) {
660
- deps.push({
661
- fileName: PathUtils.norm(path.resolve(path.dirname(sf.fileName), node.moduleSpecifier.text + ".ts")),
662
- importName: "*",
663
- });
664
- // const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
665
- // deps.push({
666
- // filePath: PathUtil.norm(sf.fileName),
667
- // line: pos.line,
668
- // char: pos.character,
669
- // code: undefined,
670
- // severity: "error",
671
- // message: `import moduleSymbol not found (${node.moduleSpecifier.text})`,
672
- // type: "deps",
673
- // });
674
- // return;
675
- }
676
- /*else {
677
- throw new NeverEntryError(`import moduleSymbol: ${sf.fileName} ${node.moduleSpecifier["text"]}`);
678
- }*/
679
- }
680
- else {
681
- const decls = moduleSymbol.getDeclarations();
682
- if (!decls) {
683
- const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
684
- deps.push({
685
- filePath: PathUtils.norm(sf.fileName),
686
- line: pos.line,
687
- char: pos.character,
688
- code: undefined,
689
- severity: "error",
690
- message: `import decls not found (${moduleSymbol.name})`,
691
- type: "deps",
692
- });
693
- return;
694
- }
695
- const namedBindings = node.importClause?.namedBindings;
696
- if (namedBindings && ts.isNamedImports(namedBindings)) {
697
- for (const el of namedBindings.elements) {
698
- for (const decl of decls) {
699
- deps.push({
700
- fileName: PathUtils.norm(decl.getSourceFile().fileName),
701
- importName: el.name.text,
702
- });
703
- }
704
- }
705
- }
706
- else {
707
- for (const decl of decls) {
708
- deps.push({
709
- fileName: PathUtils.norm(decl.getSourceFile().fileName),
710
- importName: "*",
711
- });
712
- }
713
- }
714
- }
439
+ _convertOutputToReal(filePath, distPath, text) {
440
+ let realFilePath = PathUtils.norm(filePath);
441
+ let realText = text;
442
+ const srcRelBasePath = path.resolve(distPath, path.basename(this._opt.pkgPath), "src");
443
+ if (PathUtils.isChildPath(realFilePath, srcRelBasePath)) {
444
+ realFilePath = PathUtils.norm(distPath, path.relative(srcRelBasePath, realFilePath));
445
+ // source map 위치 정확히 찾아가기
446
+ if (filePath.endsWith(".js.map")) {
447
+ const sourceMapContents = JSON.parse(realText);
448
+ sourceMapContents.sources[0] = sourceMapContents.sources[0].slice(6); // remove "../../"
449
+ realText = JSON.stringify(sourceMapContents);
715
450
  }
716
- if (ts.isCallExpression(node) && node.expression.kind === ts.SyntaxKind.ImportKeyword) {
717
- if (ts.isStringLiteral(node.arguments[0]) && node.arguments[0].text.startsWith("./")) {
718
- const moduleSymbol = tc.getSymbolAtLocation(node.arguments[0]);
719
- if (!moduleSymbol) {
720
- deps.push({
721
- fileName: PathUtils.norm(path.resolve(path.dirname(sf.fileName), node.arguments[0].text + ".ts")),
722
- importName: "*",
723
- });
724
- // const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
725
- // deps.push({
726
- // filePath: PathUtil.norm(sf.fileName),
727
- // line: pos.line,
728
- // char: pos.character,
729
- // code: undefined,
730
- // severity: "error",
731
- // message: `import() moduleSymbol not found (${node.arguments[0].text})`,
732
- // type: "deps",
733
- // });
734
- // return;
735
- }
736
- else {
737
- const decls = moduleSymbol.getDeclarations();
738
- if (!decls) {
739
- const pos = ts.getLineAndCharacterOfPosition(sf, node.getStart());
740
- deps.push({
741
- filePath: PathUtils.norm(sf.fileName),
742
- line: pos.line,
743
- char: pos.character,
744
- code: undefined,
745
- severity: "error",
746
- message: `import() decls not found (${node.arguments[0].text})`,
747
- type: "deps",
748
- });
749
- return;
750
- }
751
- for (const decl of decls) {
752
- deps.push({
753
- fileName: PathUtils.norm(decl.getSourceFile().fileName),
754
- importName: "*",
755
- });
756
- }
757
- }
758
- }
759
- }
760
- node.forEachChild(visit);
761
- };
762
- sf.forEachChild(visit);
763
- return deps;
451
+ }
452
+ return { filePath: realFilePath, text: realText };
453
+ }
454
+ _debug(...msg) {
455
+ this._logger.debug(`[${path.basename(this._opt.pkgPath)}]`, ...msg);
764
456
  }
765
457
  }
766
458
  //# sourceMappingURL=sd-ts-compiler.js.map