@akanjs/devkit 0.9.41 → 0.9.42

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.
@@ -104,8 +104,8 @@ class Builder {
104
104
  }
105
105
  };
106
106
  buildResult.outputFiles.map((file) => this.#distExecutor.writeFile(file.path, file.text));
107
- this.#distExecutor.writeJson("package.json", pkgPackageJson);
108
- this.#executor.writeJson("package.json", pkgPackageJson);
107
+ this.#distExecutor.setPackageJson(pkgPackageJson);
108
+ this.#executor.setPackageJson(pkgPackageJson);
109
109
  }
110
110
  }
111
111
  // Annotate the CommonJS export names for ESM import in node:
@@ -217,8 +217,18 @@ const runCommands = async (...commands) => {
217
217
  });
218
218
  const __dirname = (0, import__.getDirname)(import_meta.url);
219
219
  const hasPackageJson = import_fs.default.existsSync(`${__dirname}/../package.json`);
220
- const version = hasPackageJson ? JSON.parse(import_fs.default.readFileSync(`${__dirname}/../package.json`, "utf8")).version : "0.0.1";
221
- import_commander.program.version(version).description("Akan CLI");
220
+ process.env.AKAN_VERSION = hasPackageJson ? JSON.parse(import_fs.default.readFileSync(`${__dirname}/../package.json`, "utf8")).version : "0.0.1";
221
+ import_commander.program.version(process.env.AKAN_VERSION).description("Akan CLI");
222
+ const akanBasePackageJson = import_fs.default.existsSync("./node_modules/@akanjs/base/package.json") ? JSON.parse(import_fs.default.readFileSync("./node_modules/@akanjs/base/package.json", "utf8")) : null;
223
+ if (akanBasePackageJson && akanBasePackageJson.version !== process.env.AKAN_VERSION) {
224
+ import_common.Logger.rawLog(
225
+ import_chalk.default.yellow(
226
+ `
227
+ Akan CLI version is mismatch with installed package. ${process.env.AKAN_VERSION} (global) vs ${akanBasePackageJson.version} (base)
228
+ It may cause unexpected behavior. Run \`akan update\` to update latest akanjs.`
229
+ )
230
+ );
231
+ }
222
232
  for (const command of commands) {
223
233
  const targetMetas = (0, import_targetMeta.getTargetMetas)(command);
224
234
  for (const targetMeta of targetMetas) {
@@ -281,7 +291,8 @@ const runCommands = async (...commands) => {
281
291
  import_common.Logger.rawLog();
282
292
  } catch (e) {
283
293
  const errMsg = e instanceof Error ? e.message : typeof e === "string" ? e : JSON.stringify(e);
284
- import_common.Logger.error(`Command Error: ${import_chalk.default.red(errMsg)}`);
294
+ import_common.Logger.rawLog(`
295
+ ${import_chalk.default.red(errMsg)}`);
285
296
  throw e;
286
297
  }
287
298
  });
@@ -34,11 +34,37 @@ var fs = __toESM(require("fs"));
34
34
  var path = __toESM(require("path"));
35
35
  var ts = __toESM(require("typescript"));
36
36
  class TypeScriptDependencyScanner {
37
- constructor(directory) {
38
- this.directory = directory;
39
- }
40
37
  #fileDependencies = /* @__PURE__ */ new Map();
41
38
  #visitedFiles = /* @__PURE__ */ new Set();
39
+ directory;
40
+ tsconfig;
41
+ rootPackageJson;
42
+ constructor(directory, { tsconfig, rootPackageJson }) {
43
+ this.directory = directory;
44
+ this.tsconfig = tsconfig;
45
+ this.rootPackageJson = rootPackageJson;
46
+ }
47
+ async getMonorepoDependencies(projectName) {
48
+ const npmSet = new Set(
49
+ Object.keys({ ...this.rootPackageJson.dependencies, ...this.rootPackageJson.devDependencies })
50
+ );
51
+ const pkgPathSet = new Set(
52
+ Object.keys(this.tsconfig.compilerOptions.paths ?? {}).filter((path2) => this.tsconfig.compilerOptions.paths?.[path2]?.some((resolve) => resolve.startsWith("pkgs/"))).map((path2) => path2.replace("/*", ""))
53
+ );
54
+ const libPathSet = new Set(
55
+ Object.keys(this.tsconfig.compilerOptions.paths ?? {}).filter((path2) => this.tsconfig.compilerOptions.paths?.[path2]?.some((resolve) => resolve.startsWith("libs/"))).map((path2) => path2.replace("/*", ""))
56
+ );
57
+ const [npmDepSet, pkgPathDepSet, libPathDepSet] = await this.getImportSets([npmSet, pkgPathSet, libPathSet]);
58
+ const pkgDeps = [...pkgPathDepSet].map((path2) => {
59
+ const pathSplitLength = path2.split("/").length;
60
+ return (this.tsconfig.compilerOptions.paths?.[path2]?.[0] ?? "*").split("/").slice(1, 1 + pathSplitLength).join("/");
61
+ });
62
+ const libDeps = [...libPathDepSet].map((path2) => {
63
+ const pathSplitLength = path2.split("/").length;
64
+ return (this.tsconfig.compilerOptions.paths?.[path2]?.[0] ?? "*").split("/").slice(1, 1 + pathSplitLength).join("/");
65
+ }).filter((libName) => libName !== projectName);
66
+ return { pkgDeps, libDeps, npmDeps: [...npmDepSet] };
67
+ }
42
68
  async getImportSets(depSets) {
43
69
  const fileDependencies = await this.getDependencies();
44
70
  const importedDepSets = new Array(depSets.length);
@@ -45,9 +45,9 @@ var import_dotenv = __toESM(require("dotenv"));
45
45
  var import_fs = __toESM(require("fs"));
46
46
  var import_promises = __toESM(require("fs/promises"));
47
47
  var import_path = __toESM(require("path"));
48
- var import_dependencyScanner = require("./dependencyScanner");
49
48
  var import_getDirname = require("./getDirname");
50
49
  var import_linter = require("./linter");
50
+ var import_scanInfo = require("./scanInfo");
51
51
  var import_spinner = require("./spinner");
52
52
  var import_typeChecker = require("./typeChecker");
53
53
  const import_meta = {};
@@ -195,6 +195,22 @@ class Executor {
195
195
  return [];
196
196
  }
197
197
  }
198
+ async getFilesAndDirs(dirPath) {
199
+ const paths = await this.readdir(dirPath);
200
+ const files = [];
201
+ const dirs = [];
202
+ const fullDirPath = this.getPath(dirPath);
203
+ await Promise.all(
204
+ paths.map(async (p) => {
205
+ const stats = await import_promises.default.stat(import_path.default.join(fullDirPath, p));
206
+ if (stats.isDirectory())
207
+ dirs.push(p);
208
+ else
209
+ files.push(p);
210
+ })
211
+ );
212
+ return { files, dirs };
213
+ }
198
214
  exists(filePath) {
199
215
  const readPath = this.getPath(filePath);
200
216
  return import_fs.default.existsSync(readPath);
@@ -226,11 +242,12 @@ class Executor {
226
242
  contentStr = import_fs.default.readFileSync(writePath, "utf-8");
227
243
  } else {
228
244
  import_fs.default.writeFileSync(writePath, contentStr, "utf8");
229
- this.logger.verbose(`File ${writePath} is changed`);
245
+ if (import_common.Logger.isVerbose())
246
+ this.logger.rawLog(import_chalk.default.yellow(`File Update: ${filePath}`));
230
247
  }
231
248
  } else {
232
249
  import_fs.default.writeFileSync(writePath, contentStr, "utf8");
233
- this.logger.verbose(`File ${writePath} is created`);
250
+ this.logger.rawLog(import_chalk.default.green(`File Create: ${filePath}`));
234
251
  }
235
252
  return { filePath: writePath, content: contentStr };
236
253
  }
@@ -267,7 +284,10 @@ class Executor {
267
284
  spinning(msg, { prefix = `${this.emoji}${this.name}`, indent = 0, enableSpin = !Executor.verbose } = {}) {
268
285
  return new import_spinner.Spinner(msg, { prefix, indent, enableSpin }).start();
269
286
  }
270
- getTsConfig(pathname = "tsconfig.json") {
287
+ #tsconfig = null;
288
+ getTsConfig(pathname = "tsconfig.json", { refresh } = {}) {
289
+ if (this.#tsconfig && !refresh)
290
+ return this.#tsconfig;
271
291
  const tsconfig = this.readJson(pathname);
272
292
  if (tsconfig.extends) {
273
293
  const extendsTsconfig = this.getTsConfig(tsconfig.extends);
@@ -277,17 +297,34 @@ class Executor {
277
297
  compilerOptions: { ...extendsTsconfig.compilerOptions, ...tsconfig.compilerOptions }
278
298
  };
279
299
  }
300
+ this.#tsconfig = tsconfig;
280
301
  return tsconfig;
281
302
  }
303
+ setTsConfig(tsconfig) {
304
+ this.writeJson("tsconfig.json", tsconfig);
305
+ this.#tsconfig = tsconfig;
306
+ }
307
+ #packageJson = null;
308
+ getPackageJson({ refresh } = {}) {
309
+ if (this.#packageJson && !refresh)
310
+ return this.#packageJson;
311
+ const packageJson = this.readJson("package.json");
312
+ this.#packageJson = packageJson;
313
+ return packageJson;
314
+ }
315
+ setPackageJson(packageJson) {
316
+ this.writeJson("package.json", packageJson);
317
+ this.#packageJson = packageJson;
318
+ }
282
319
  async #applyTemplateFile({
283
320
  templatePath,
284
321
  targetPath,
285
- scanResult,
322
+ scanInfo,
286
323
  overwrite = true
287
324
  }, dict = {}) {
288
325
  if (targetPath.endsWith(".js") || targetPath.endsWith(".jsx")) {
289
326
  const getContent = await import(templatePath);
290
- const result = getContent.default(scanResult ?? null, dict);
327
+ const result = getContent.default(scanInfo ?? null, dict);
291
328
  if (result === null)
292
329
  return null;
293
330
  const filename = typeof result === "object" ? result.filename : import_path.default.basename(targetPath).replace(".js", ".ts");
@@ -317,7 +354,7 @@ class Executor {
317
354
  async _applyTemplate({
318
355
  basePath,
319
356
  template,
320
- scanResult,
357
+ scanInfo,
321
358
  dict = {},
322
359
  overwrite = true
323
360
  }) {
@@ -326,7 +363,7 @@ class Executor {
326
363
  if (import_fs.default.statSync(prefixTemplatePath).isFile()) {
327
364
  const filename = import_path.default.basename(prefixTemplatePath);
328
365
  const fileContent = await this.#applyTemplateFile(
329
- { templatePath: prefixTemplatePath, targetPath: import_path.default.join(basePath, filename), scanResult, overwrite },
366
+ { templatePath: prefixTemplatePath, targetPath: import_path.default.join(basePath, filename), scanInfo, overwrite },
330
367
  dict
331
368
  );
332
369
  return fileContent ? [fileContent] : [];
@@ -337,7 +374,7 @@ class Executor {
337
374
  const subpath = import_path.default.join(templatePath, subdir);
338
375
  if (import_fs.default.statSync(subpath).isFile()) {
339
376
  const fileContent = await this.#applyTemplateFile(
340
- { templatePath: subpath, targetPath: import_path.default.join(basePath, subdir), scanResult, overwrite },
377
+ { templatePath: subpath, targetPath: import_path.default.join(basePath, subdir), scanInfo, overwrite },
341
378
  dict
342
379
  );
343
380
  return fileContent ? [fileContent] : [];
@@ -345,7 +382,7 @@ class Executor {
345
382
  return await this._applyTemplate({
346
383
  basePath: import_path.default.join(basePath, subdir),
347
384
  template: import_path.default.join(template, subdir),
348
- scanResult,
385
+ scanInfo,
349
386
  dict,
350
387
  overwrite
351
388
  });
@@ -395,9 +432,12 @@ class WorkspaceExecutor extends Executor {
395
432
  this.workspaceRoot = workspaceRoot;
396
433
  this.repoName = repoName;
397
434
  }
398
- static fromRoot() {
399
- const repoName = import_path.default.basename(process.cwd());
400
- return new WorkspaceExecutor({ workspaceRoot: process.cwd(), repoName });
435
+ static #execs = /* @__PURE__ */ new Map();
436
+ static fromRoot({
437
+ workspaceRoot = process.cwd(),
438
+ repoName = import_path.default.basename(process.cwd())
439
+ } = {}) {
440
+ return this.#execs.get(repoName) ?? new WorkspaceExecutor({ workspaceRoot, repoName });
401
441
  }
402
442
  getBaseDevEnv() {
403
443
  const envFile = import_dotenv.default.parse(this.readFile(".env"));
@@ -415,36 +455,7 @@ class WorkspaceExecutor extends Executor {
415
455
  return { ...appName ? { name: appName } : {}, repoName, serveDomain, env, portOffset };
416
456
  }
417
457
  async scan() {
418
- const [appNames, libNames, pkgNames] = await Promise.all([this.getApps(), this.getLibs(), this.getPkgs()]);
419
- const [appScanResults, libScanResults, pkgScanResults] = await Promise.all([
420
- Promise.all(
421
- appNames.map(async (appName) => {
422
- const app = AppExecutor.from(this, appName);
423
- const akanConfig = await app.getConfig("scan");
424
- return await app.scan({ akanConfig });
425
- })
426
- ),
427
- Promise.all(
428
- libNames.map(async (libName) => {
429
- const lib = LibExecutor.from(this, libName);
430
- const akanConfig = await lib.getConfig("scan");
431
- return await lib.scan({ akanConfig });
432
- })
433
- ),
434
- Promise.all(
435
- pkgNames.map(async (pkgName) => {
436
- return await PkgExecutor.from(this, pkgName).scan();
437
- })
438
- )
439
- ]);
440
- return {
441
- appNames,
442
- libNames,
443
- pkgNames,
444
- apps: Object.fromEntries(appScanResults.map((app) => [app.name, app])),
445
- libs: Object.fromEntries(libScanResults.map((lib) => [lib.name, lib])),
446
- pkgs: Object.fromEntries(pkgScanResults.map((pkg) => [pkg.name, pkg]))
447
- };
458
+ return await import_scanInfo.WorkspaceInfo.fromExecutor(this);
448
459
  }
449
460
  async getApps() {
450
461
  if (!import_fs.default.existsSync(`${this.workspaceRoot}/apps`))
@@ -592,160 +603,103 @@ class SysExecutor extends Executor {
592
603
  this.type = type;
593
604
  this.emoji = execEmoji[type];
594
605
  }
595
- async getConfig(command) {
596
- return this.type === "app" ? await (0, import_config.getAppConfig)(this.cwdPath, { ...this.workspace.getBaseDevEnv(), type: "app", name: this.name, command }) : await (0, import_config.getLibConfig)(this.cwdPath, { ...this.workspace.getBaseDevEnv(), type: "lib", name: this.name, command });
606
+ #akanConfig = null;
607
+ async getConfig({ refresh } = {}) {
608
+ if (this.#akanConfig && !refresh)
609
+ return this.#akanConfig;
610
+ this.#akanConfig = this.type === "app" ? await (0, import_config.getAppConfig)(this.cwdPath, { ...this.workspace.getBaseDevEnv(), type: "app", name: this.name }) : await (0, import_config.getLibConfig)(this.cwdPath, { ...this.workspace.getBaseDevEnv(), type: "lib", name: this.name });
611
+ return this.#akanConfig;
597
612
  }
598
613
  async getModules() {
599
614
  const path2 = this.type === "app" ? `apps/${this.name}/lib` : `libs/${this.name}/lib`;
600
615
  return await this.workspace.getDirInModule(path2, this.name);
601
616
  }
617
+ #scanInfo = null;
602
618
  async scan({
603
- tsconfig = this.getTsConfig(`${this.cwdPath}/tsconfig.json`),
604
- akanConfig
605
- }, libScanResults = {}) {
606
- if (libScanResults[this.name])
607
- return libScanResults[this.name];
608
- const rootPackageJson = this.readJson(`${this.workspace.workspaceRoot}/package.json`);
609
- const scanner = new import_dependencyScanner.TypeScriptDependencyScanner(this.cwdPath);
610
- const npmSet = new Set(Object.keys({ ...rootPackageJson.dependencies, ...rootPackageJson.devDependencies }));
611
- const pkgPathSet = new Set(
612
- Object.keys(tsconfig.compilerOptions.paths ?? {}).filter((path2) => tsconfig.compilerOptions.paths?.[path2]?.some((resolve) => resolve.startsWith("pkgs/"))).map((path2) => path2.replace("/*", ""))
613
- );
614
- const libPathSet = new Set(
615
- Object.keys(tsconfig.compilerOptions.paths ?? {}).filter((path2) => tsconfig.compilerOptions.paths?.[path2]?.some((resolve) => resolve.startsWith("libs/"))).map((path2) => path2.replace("/*", ""))
616
- );
617
- const [npmDepSet, pkgPathDepSet, libPathDepSet] = await scanner.getImportSets([npmSet, pkgPathSet, libPathSet]);
618
- const pkgDeps = [...pkgPathDepSet].map((path2) => {
619
- const pathSplitLength = path2.split("/").length;
620
- return (tsconfig.compilerOptions.paths?.[path2]?.[0] ?? "*").split("/").slice(1, 1 + pathSplitLength).join("/");
621
- });
622
- const libDeps = [...libPathDepSet].map((path2) => {
623
- const pathSplitLength = path2.split("/").length;
624
- return (tsconfig.compilerOptions.paths?.[path2]?.[0] ?? "*").split("/").slice(1, 1 + pathSplitLength).join("/");
625
- }).filter((libName) => libName !== this.name);
626
- if (!import_fs.default.existsSync(`${this.cwdPath}/lib/__scalar`))
627
- import_fs.default.mkdirSync(`${this.cwdPath}/lib/__scalar`, { recursive: true });
628
- const files = (0, import_config.getDefaultFileScan)();
629
- const dirnames = (await this.readdir("lib")).filter(
630
- (name) => import_fs.default.lstatSync(`${this.cwdPath}/lib/${name}`).isDirectory()
631
- );
632
- const databaseDirs = dirnames.filter((name) => !name.startsWith("_"));
633
- const serviceDirs = dirnames.filter((name) => name.startsWith("_") && !name.startsWith("__"));
634
- await Promise.all(
635
- databaseDirs.map(async (name) => {
636
- const filenames = await this.readdir(import_path.default.join("lib", name));
637
- filenames.forEach((filename) => {
638
- if (filename.endsWith(".constant.ts"))
639
- files.constants.databases.push(name);
640
- else if (filename.endsWith(".dictionary.ts"))
641
- files.dictionary.databases.push(name);
642
- else if (filename.endsWith(".document.ts"))
643
- files.documents.databases.push(name);
644
- else if (filename.endsWith(".service.ts"))
645
- files.services.databases.push(name);
646
- else if (filename.endsWith(".signal.ts"))
647
- files.signal.databases.push(name);
648
- else if (filename.endsWith(".store.ts"))
649
- files.store.databases.push(name);
650
- else if (filename === "index.tsx")
651
- files.components.databases.push(name);
652
- });
653
- })
654
- );
655
- await Promise.all(
656
- serviceDirs.map(async (dirname) => {
657
- const name = dirname.slice(1);
658
- const filenames = await this.readdir(import_path.default.join("lib", dirname));
659
- filenames.forEach((filename) => {
660
- if (filename.endsWith(".dictionary.ts"))
661
- files.dictionary.services.push(name);
662
- else if (filename.endsWith(".service.ts"))
663
- files.services.services.push(name);
664
- else if (filename.endsWith(".signal.ts"))
665
- files.signal.services.push(name);
666
- else if (filename.endsWith(".store.ts"))
667
- files.store.services.push(name);
668
- else if (filename === "index.tsx")
669
- files.components.services.push(name);
670
- });
671
- })
672
- );
673
- const scalarDirs = (await this.readdir("lib/__scalar")).filter((name) => !name.startsWith("_"));
674
- await Promise.all(
675
- scalarDirs.map(async (name) => {
676
- const filenames = await this.readdir(import_path.default.join("lib/__scalar", name));
677
- filenames.forEach((filename) => {
678
- if (filename.endsWith(".constant.ts"))
679
- files.constants.scalars.push(name);
680
- else if (filename.endsWith(".dictionary.ts"))
681
- files.dictionary.scalars.push(name);
682
- else if (filename.endsWith(".document.ts"))
683
- files.documents.scalars.push(name);
684
- else if (filename.endsWith(".service.ts"))
685
- files.services.scalars.push(name);
686
- else if (filename.endsWith(".signal.ts"))
687
- files.signal.scalars.push(name);
688
- else if (filename.endsWith(".store.ts"))
689
- files.store.scalars.push(name);
690
- else if (filename === "index.ts")
691
- files.components.scalars.push(name);
692
- });
693
- })
694
- );
695
- const missingLibDeps = [];
696
- libDeps.forEach((libName) => {
697
- if (!akanConfig.libs.includes(libName))
698
- missingLibDeps.push(libName);
699
- });
700
- if (missingLibDeps.length)
701
- throw new Error(
702
- `Missing libs: ${missingLibDeps.join(", ")}, add these dependencies in akan.config.ts as { libs: [...other deps, ${missingLibDeps.join(", ")}] }`
703
- );
704
- for (const libName of akanConfig.libs) {
705
- if (libScanResults[libName])
706
- continue;
707
- const lib = new LibExecutor({ workspace: this.workspace, name: libName });
708
- const akanConfig2 = await lib.getConfig();
709
- libScanResults[libName] = await lib.scan({ akanConfig: akanConfig2 }, libScanResults);
619
+ refresh,
620
+ write = true,
621
+ writeLib = true
622
+ } = {}) {
623
+ if (this.#scanInfo && !refresh)
624
+ return this.#scanInfo;
625
+ const scanInfo = this.type === "app" ? await import_scanInfo.AppInfo.fromExecutor(this, { refresh }) : await import_scanInfo.LibInfo.fromExecutor(this, { refresh });
626
+ if (write) {
627
+ await Promise.all([
628
+ this._applyTemplate({ basePath: "lib", template: "lib", scanInfo }),
629
+ this._applyTemplate({ basePath: ".", template: "server.ts", scanInfo }),
630
+ this._applyTemplate({ basePath: ".", template: "client.ts", scanInfo }),
631
+ this.type === "lib" ? this._applyTemplate({ basePath: ".", template: "index.ts", scanInfo }) : null,
632
+ ...scanInfo.getDatabaseModules().map(
633
+ (model) => this._applyTemplate({
634
+ basePath: `lib/${model}`,
635
+ template: "moduleRoot",
636
+ scanInfo,
637
+ dict: { model, Model: (0, import_common.capitalize)(model) }
638
+ })
639
+ ),
640
+ ...scanInfo.getServiceModules().map(
641
+ (model) => this._applyTemplate({
642
+ basePath: `lib/_${model}`,
643
+ template: "moduleRoot",
644
+ scanInfo,
645
+ dict: { model, Model: (0, import_common.capitalize)(model) }
646
+ })
647
+ )
648
+ ]);
649
+ this.writeJson(`akan.${this.type}.json`, scanInfo.getScanResult());
650
+ if (this.type === "lib")
651
+ this.#updateDependencies(scanInfo);
652
+ if (writeLib) {
653
+ const libInfos = [...scanInfo.getLibInfos().values()];
654
+ await Promise.all(
655
+ libInfos.map((libInfo) => [
656
+ libInfo.exec._applyTemplate({ basePath: "lib", template: "lib", scanInfo: libInfo }),
657
+ libInfo.exec._applyTemplate({ basePath: ".", template: "server.ts", scanInfo: libInfo }),
658
+ libInfo.exec._applyTemplate({ basePath: ".", template: "client.ts", scanInfo: libInfo }),
659
+ libInfo.exec._applyTemplate({ basePath: ".", template: "index.ts", scanInfo: libInfo }),
660
+ ...libInfo.getDatabaseModules().map(
661
+ (model) => libInfo.exec._applyTemplate({
662
+ basePath: `lib/${model}`,
663
+ template: "moduleRoot",
664
+ scanInfo: libInfo,
665
+ dict: { model, Model: (0, import_common.capitalize)(model) }
666
+ })
667
+ ),
668
+ ...libInfo.getServiceModules().map(
669
+ (model) => libInfo.exec._applyTemplate({
670
+ basePath: `lib/_${model}`,
671
+ template: "moduleRoot",
672
+ scanInfo: libInfo,
673
+ dict: { model, Model: (0, import_common.capitalize)(model) }
674
+ })
675
+ )
676
+ ]).flat()
677
+ );
678
+ }
710
679
  }
711
- const scanResult = {
712
- name: this.name,
713
- type: this.type,
714
- repoName: this.workspace.repoName,
715
- serveDomain: this.workspace.getBaseDevEnv().serveDomain,
716
- akanConfig,
717
- files,
718
- libDeps,
719
- pkgDeps,
720
- dependencies: [...npmDepSet].filter((dep) => !dep.startsWith("@akanjs")),
721
- libs: Object.fromEntries(akanConfig.libs.map((libName) => [libName, libScanResults[libName]]))
722
- };
723
- await this._applyTemplate({ basePath: "lib", template: "lib", scanResult });
724
- await this._applyTemplate({ basePath: ".", template: "server.ts", scanResult });
725
- await this._applyTemplate({ basePath: ".", template: "client.ts", scanResult });
726
- if (this.type === "lib")
727
- await this._applyTemplate({ basePath: ".", template: "index.ts", scanResult });
728
- this.writeJson(`akan.${this.type}.json`, scanResult);
729
- if (this.type === "app")
730
- return scanResult;
731
- const libPackageJson = this.readJson("package.json");
680
+ this.#scanInfo = scanInfo;
681
+ return scanInfo;
682
+ }
683
+ #updateDependencies(scanInfo) {
684
+ const rootPackageJson = this.workspace.getPackageJson();
685
+ const libPackageJson = this.getPackageJson();
686
+ const dependencies = scanInfo.getScanResult().dependencies;
732
687
  const libPkgJsonWithDeps = {
733
688
  ...libPackageJson,
734
689
  dependencies: {
735
690
  ...libPackageJson.dependencies,
736
691
  ...Object.fromEntries(
737
- scanResult.dependencies.filter((dep) => rootPackageJson.dependencies?.[dep]).sort().map((dep) => [dep, rootPackageJson.dependencies?.[dep]])
692
+ dependencies.filter((dep) => rootPackageJson.dependencies?.[dep]).sort().map((dep) => [dep, rootPackageJson.dependencies?.[dep]])
738
693
  )
739
694
  },
740
695
  devDependencies: {
741
696
  ...libPackageJson.devDependencies,
742
697
  ...Object.fromEntries(
743
- scanResult.dependencies.filter((dep) => rootPackageJson.devDependencies?.[dep]).sort().map((dep) => [dep, rootPackageJson.devDependencies?.[dep]])
698
+ dependencies.filter((dep) => rootPackageJson.devDependencies?.[dep]).sort().map((dep) => [dep, rootPackageJson.devDependencies?.[dep]])
744
699
  )
745
700
  }
746
701
  };
747
- this.writeJson("package.json", libPkgJsonWithDeps);
748
- return scanResult;
702
+ this.setPackageJson(libPkgJsonWithDeps);
749
703
  }
750
704
  getLocalFile(targetPath) {
751
705
  const filePath = import_path.default.isAbsolute(targetPath) ? targetPath : `${this.type}s/${this.name}/${targetPath}`;
@@ -828,9 +782,9 @@ class SysExecutor extends Executor {
828
782
  )
829
783
  };
830
784
  const akanConfig = await this.getConfig();
831
- const scanResult = await this.scan({ akanConfig });
832
- const fileContents = await this._applyTemplate({ ...options, scanResult, dict });
833
- await this.scan({ akanConfig });
785
+ const scanInfo = await this.scan();
786
+ const fileContents = await this._applyTemplate({ ...options, scanInfo, dict });
787
+ await this.scan();
834
788
  return fileContents;
835
789
  }
836
790
  setTsPaths() {
@@ -845,21 +799,29 @@ class AppExecutor extends SysExecutor {
845
799
  super({ workspace, name, type: "app" });
846
800
  this.dist = new Executor(`dist/${name}`, `${this.workspace.workspaceRoot}/dist/apps/${name}`);
847
801
  }
802
+ static #execs = /* @__PURE__ */ new Map();
848
803
  static from(executor, name) {
849
- if (executor instanceof WorkspaceExecutor)
804
+ const exec2 = this.#execs.get(name);
805
+ if (exec2)
806
+ return exec2;
807
+ else if (executor instanceof WorkspaceExecutor)
850
808
  return new AppExecutor({ workspace: executor, name });
851
- return new AppExecutor({ workspace: executor.workspace, name });
809
+ else
810
+ return new AppExecutor({ workspace: executor.workspace, name });
852
811
  }
853
812
  getEnv() {
854
813
  return this.workspace.getBaseDevEnv().env;
855
814
  }
856
- async getConfig(command) {
857
- return await (0, import_config.getAppConfig)(this.cwdPath, {
815
+ #akanConfig = null;
816
+ async getConfig({ refresh } = {}) {
817
+ if (this.#akanConfig && !refresh)
818
+ return this.#akanConfig;
819
+ this.#akanConfig = await (0, import_config.getAppConfig)(this.cwdPath, {
858
820
  ...this.workspace.getBaseDevEnv(),
859
821
  type: "app",
860
- name: this.name,
861
- command
822
+ name: this.name
862
823
  });
824
+ return this.#akanConfig;
863
825
  }
864
826
  async syncAssets(libDeps) {
865
827
  const projectPublicLibPath = `${this.cwdPath}/public/libs`;
@@ -896,18 +858,26 @@ class LibExecutor extends SysExecutor {
896
858
  super({ workspace, name, type: "lib" });
897
859
  this.dist = new Executor(`dist/${name}`, `${this.workspace.workspaceRoot}/dist/libs/${name}`);
898
860
  }
861
+ static #execs = /* @__PURE__ */ new Map();
899
862
  static from(executor, name) {
900
- if (executor instanceof WorkspaceExecutor)
863
+ const exec2 = this.#execs.get(name);
864
+ if (exec2)
865
+ return exec2;
866
+ else if (executor instanceof WorkspaceExecutor)
901
867
  return new LibExecutor({ workspace: executor, name });
902
- return new LibExecutor({ workspace: executor.workspace, name });
903
- }
904
- async getConfig(command) {
905
- return await (0, import_config.getLibConfig)(this.cwdPath, {
868
+ else
869
+ return new LibExecutor({ workspace: executor.workspace, name });
870
+ }
871
+ #akanConfig = null;
872
+ async getConfig({ refresh } = {}) {
873
+ if (this.#akanConfig && !refresh)
874
+ return this.#akanConfig;
875
+ this.#akanConfig = await (0, import_config.getLibConfig)(this.cwdPath, {
906
876
  ...this.workspace.getBaseDevEnv(),
907
877
  type: "lib",
908
- name: this.name,
909
- command
878
+ name: this.name
910
879
  });
880
+ return this.#akanConfig;
911
881
  }
912
882
  }
913
883
  class PkgExecutor extends Executor {
@@ -926,27 +896,13 @@ class PkgExecutor extends Executor {
926
896
  return new PkgExecutor({ workspace: executor, name });
927
897
  return new PkgExecutor({ workspace: executor.workspace, name });
928
898
  }
929
- async scan({
930
- packageJson = this.readJson(`${this.cwdPath}/package.json`),
931
- tsconfig = this.getTsConfig(`${this.cwdPath}/tsconfig.json`)
932
- } = {}) {
933
- const rootPackageJson = this.readJson(`${this.workspace.workspaceRoot}/package.json`);
934
- const scanner = new import_dependencyScanner.TypeScriptDependencyScanner(this.cwdPath);
935
- const npmSet = new Set(Object.keys({ ...rootPackageJson.dependencies, ...rootPackageJson.devDependencies }));
936
- const pkgPathSet = new Set(
937
- Object.keys(tsconfig.compilerOptions.paths ?? {}).filter((path2) => tsconfig.compilerOptions.paths?.[path2]?.some((resolve) => resolve.startsWith("pkgs/"))).map((path2) => path2.replace("/*", ""))
938
- );
939
- const [npmDepSet, pkgPathDepSet] = await scanner.getImportSets([npmSet, pkgPathSet]);
940
- const pkgDeps = [...pkgPathDepSet].map((path2) => {
941
- const pathSplitLength = path2.split("/").length;
942
- return (tsconfig.compilerOptions.paths?.[path2]?.[0] ?? "*").split("/").slice(1, 1 + pathSplitLength).join("/");
943
- }).filter((pkg) => pkg !== this.name);
944
- const pkgScanResult = {
945
- name: this.name,
946
- pkgDeps,
947
- dependencies: [...npmDepSet]
948
- };
949
- return pkgScanResult;
899
+ #scanInfo = null;
900
+ async scan({ refresh } = {}) {
901
+ if (this.#scanInfo && !refresh)
902
+ return this.#scanInfo;
903
+ const scanInfo = await import_scanInfo.PkgInfo.fromExecutor(this, { refresh });
904
+ this.#scanInfo = scanInfo;
905
+ return scanInfo;
950
906
  }
951
907
  }
952
908
  class ModuleExecutor extends Executor {
package/cjs/src/index.js CHANGED
@@ -36,6 +36,7 @@ __reExport(src_exports, require("./prompter"), module.exports);
36
36
  __reExport(src_exports, require("./guideline"), module.exports);
37
37
  __reExport(src_exports, require("./getDirname"), module.exports);
38
38
  __reExport(src_exports, require("./useStdoutDimensions"), module.exports);
39
+ __reExport(src_exports, require("./scanInfo"), module.exports);
39
40
  // Annotate the CommonJS export names for ESM import in node:
40
41
  0 && (module.exports = {
41
42
  ...require("./createTunnel"),
@@ -59,5 +60,6 @@ __reExport(src_exports, require("./useStdoutDimensions"), module.exports);
59
60
  ...require("./prompter"),
60
61
  ...require("./guideline"),
61
62
  ...require("./getDirname"),
62
- ...require("./useStdoutDimensions")
63
+ ...require("./useStdoutDimensions"),
64
+ ...require("./scanInfo")
63
65
  });