@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.
@@ -1,18 +1,14 @@
1
1
  import { capitalize, Logger } from "@akanjs/common";
2
- import {
3
- getAppConfig,
4
- getDefaultFileScan,
5
- getLibConfig
6
- } from "@akanjs/config";
2
+ import { getAppConfig, getLibConfig } from "@akanjs/config";
7
3
  import chalk from "chalk";
8
4
  import { exec, fork, spawn } from "child_process";
9
5
  import dotenv from "dotenv";
10
6
  import fs from "fs";
11
7
  import fsPromise from "fs/promises";
12
8
  import path from "path";
13
- import { TypeScriptDependencyScanner } from "./dependencyScanner";
14
9
  import { getDirname } from "./getDirname";
15
10
  import { Linter } from "./linter";
11
+ import { AppInfo, LibInfo, PkgInfo, WorkspaceInfo } from "./scanInfo";
16
12
  import { Spinner } from "./spinner";
17
13
  import { TypeChecker } from "./typeChecker";
18
14
  const execEmoji = {
@@ -159,6 +155,22 @@ class Executor {
159
155
  return [];
160
156
  }
161
157
  }
158
+ async getFilesAndDirs(dirPath) {
159
+ const paths = await this.readdir(dirPath);
160
+ const files = [];
161
+ const dirs = [];
162
+ const fullDirPath = this.getPath(dirPath);
163
+ await Promise.all(
164
+ paths.map(async (p) => {
165
+ const stats = await fsPromise.stat(path.join(fullDirPath, p));
166
+ if (stats.isDirectory())
167
+ dirs.push(p);
168
+ else
169
+ files.push(p);
170
+ })
171
+ );
172
+ return { files, dirs };
173
+ }
162
174
  exists(filePath) {
163
175
  const readPath = this.getPath(filePath);
164
176
  return fs.existsSync(readPath);
@@ -190,11 +202,12 @@ class Executor {
190
202
  contentStr = fs.readFileSync(writePath, "utf-8");
191
203
  } else {
192
204
  fs.writeFileSync(writePath, contentStr, "utf8");
193
- this.logger.verbose(`File ${writePath} is changed`);
205
+ if (Logger.isVerbose())
206
+ this.logger.rawLog(chalk.yellow(`File Update: ${filePath}`));
194
207
  }
195
208
  } else {
196
209
  fs.writeFileSync(writePath, contentStr, "utf8");
197
- this.logger.verbose(`File ${writePath} is created`);
210
+ this.logger.rawLog(chalk.green(`File Create: ${filePath}`));
198
211
  }
199
212
  return { filePath: writePath, content: contentStr };
200
213
  }
@@ -231,7 +244,10 @@ class Executor {
231
244
  spinning(msg, { prefix = `${this.emoji}${this.name}`, indent = 0, enableSpin = !Executor.verbose } = {}) {
232
245
  return new Spinner(msg, { prefix, indent, enableSpin }).start();
233
246
  }
234
- getTsConfig(pathname = "tsconfig.json") {
247
+ #tsconfig = null;
248
+ getTsConfig(pathname = "tsconfig.json", { refresh } = {}) {
249
+ if (this.#tsconfig && !refresh)
250
+ return this.#tsconfig;
235
251
  const tsconfig = this.readJson(pathname);
236
252
  if (tsconfig.extends) {
237
253
  const extendsTsconfig = this.getTsConfig(tsconfig.extends);
@@ -241,17 +257,34 @@ class Executor {
241
257
  compilerOptions: { ...extendsTsconfig.compilerOptions, ...tsconfig.compilerOptions }
242
258
  };
243
259
  }
260
+ this.#tsconfig = tsconfig;
244
261
  return tsconfig;
245
262
  }
263
+ setTsConfig(tsconfig) {
264
+ this.writeJson("tsconfig.json", tsconfig);
265
+ this.#tsconfig = tsconfig;
266
+ }
267
+ #packageJson = null;
268
+ getPackageJson({ refresh } = {}) {
269
+ if (this.#packageJson && !refresh)
270
+ return this.#packageJson;
271
+ const packageJson = this.readJson("package.json");
272
+ this.#packageJson = packageJson;
273
+ return packageJson;
274
+ }
275
+ setPackageJson(packageJson) {
276
+ this.writeJson("package.json", packageJson);
277
+ this.#packageJson = packageJson;
278
+ }
246
279
  async #applyTemplateFile({
247
280
  templatePath,
248
281
  targetPath,
249
- scanResult,
282
+ scanInfo,
250
283
  overwrite = true
251
284
  }, dict = {}) {
252
285
  if (targetPath.endsWith(".js") || targetPath.endsWith(".jsx")) {
253
286
  const getContent = await import(templatePath);
254
- const result = getContent.default(scanResult ?? null, dict);
287
+ const result = getContent.default(scanInfo ?? null, dict);
255
288
  if (result === null)
256
289
  return null;
257
290
  const filename = typeof result === "object" ? result.filename : path.basename(targetPath).replace(".js", ".ts");
@@ -281,7 +314,7 @@ class Executor {
281
314
  async _applyTemplate({
282
315
  basePath,
283
316
  template,
284
- scanResult,
317
+ scanInfo,
285
318
  dict = {},
286
319
  overwrite = true
287
320
  }) {
@@ -290,7 +323,7 @@ class Executor {
290
323
  if (fs.statSync(prefixTemplatePath).isFile()) {
291
324
  const filename = path.basename(prefixTemplatePath);
292
325
  const fileContent = await this.#applyTemplateFile(
293
- { templatePath: prefixTemplatePath, targetPath: path.join(basePath, filename), scanResult, overwrite },
326
+ { templatePath: prefixTemplatePath, targetPath: path.join(basePath, filename), scanInfo, overwrite },
294
327
  dict
295
328
  );
296
329
  return fileContent ? [fileContent] : [];
@@ -301,7 +334,7 @@ class Executor {
301
334
  const subpath = path.join(templatePath, subdir);
302
335
  if (fs.statSync(subpath).isFile()) {
303
336
  const fileContent = await this.#applyTemplateFile(
304
- { templatePath: subpath, targetPath: path.join(basePath, subdir), scanResult, overwrite },
337
+ { templatePath: subpath, targetPath: path.join(basePath, subdir), scanInfo, overwrite },
305
338
  dict
306
339
  );
307
340
  return fileContent ? [fileContent] : [];
@@ -309,7 +342,7 @@ class Executor {
309
342
  return await this._applyTemplate({
310
343
  basePath: path.join(basePath, subdir),
311
344
  template: path.join(template, subdir),
312
- scanResult,
345
+ scanInfo,
313
346
  dict,
314
347
  overwrite
315
348
  });
@@ -359,9 +392,12 @@ class WorkspaceExecutor extends Executor {
359
392
  this.workspaceRoot = workspaceRoot;
360
393
  this.repoName = repoName;
361
394
  }
362
- static fromRoot() {
363
- const repoName = path.basename(process.cwd());
364
- return new WorkspaceExecutor({ workspaceRoot: process.cwd(), repoName });
395
+ static #execs = /* @__PURE__ */ new Map();
396
+ static fromRoot({
397
+ workspaceRoot = process.cwd(),
398
+ repoName = path.basename(process.cwd())
399
+ } = {}) {
400
+ return this.#execs.get(repoName) ?? new WorkspaceExecutor({ workspaceRoot, repoName });
365
401
  }
366
402
  getBaseDevEnv() {
367
403
  const envFile = dotenv.parse(this.readFile(".env"));
@@ -379,36 +415,7 @@ class WorkspaceExecutor extends Executor {
379
415
  return { ...appName ? { name: appName } : {}, repoName, serveDomain, env, portOffset };
380
416
  }
381
417
  async scan() {
382
- const [appNames, libNames, pkgNames] = await Promise.all([this.getApps(), this.getLibs(), this.getPkgs()]);
383
- const [appScanResults, libScanResults, pkgScanResults] = await Promise.all([
384
- Promise.all(
385
- appNames.map(async (appName) => {
386
- const app = AppExecutor.from(this, appName);
387
- const akanConfig = await app.getConfig("scan");
388
- return await app.scan({ akanConfig });
389
- })
390
- ),
391
- Promise.all(
392
- libNames.map(async (libName) => {
393
- const lib = LibExecutor.from(this, libName);
394
- const akanConfig = await lib.getConfig("scan");
395
- return await lib.scan({ akanConfig });
396
- })
397
- ),
398
- Promise.all(
399
- pkgNames.map(async (pkgName) => {
400
- return await PkgExecutor.from(this, pkgName).scan();
401
- })
402
- )
403
- ]);
404
- return {
405
- appNames,
406
- libNames,
407
- pkgNames,
408
- apps: Object.fromEntries(appScanResults.map((app) => [app.name, app])),
409
- libs: Object.fromEntries(libScanResults.map((lib) => [lib.name, lib])),
410
- pkgs: Object.fromEntries(pkgScanResults.map((pkg) => [pkg.name, pkg]))
411
- };
418
+ return await WorkspaceInfo.fromExecutor(this);
412
419
  }
413
420
  async getApps() {
414
421
  if (!fs.existsSync(`${this.workspaceRoot}/apps`))
@@ -556,160 +563,103 @@ class SysExecutor extends Executor {
556
563
  this.type = type;
557
564
  this.emoji = execEmoji[type];
558
565
  }
559
- async getConfig(command) {
560
- return this.type === "app" ? await getAppConfig(this.cwdPath, { ...this.workspace.getBaseDevEnv(), type: "app", name: this.name, command }) : await getLibConfig(this.cwdPath, { ...this.workspace.getBaseDevEnv(), type: "lib", name: this.name, command });
566
+ #akanConfig = null;
567
+ async getConfig({ refresh } = {}) {
568
+ if (this.#akanConfig && !refresh)
569
+ return this.#akanConfig;
570
+ this.#akanConfig = this.type === "app" ? await getAppConfig(this.cwdPath, { ...this.workspace.getBaseDevEnv(), type: "app", name: this.name }) : await getLibConfig(this.cwdPath, { ...this.workspace.getBaseDevEnv(), type: "lib", name: this.name });
571
+ return this.#akanConfig;
561
572
  }
562
573
  async getModules() {
563
574
  const path2 = this.type === "app" ? `apps/${this.name}/lib` : `libs/${this.name}/lib`;
564
575
  return await this.workspace.getDirInModule(path2, this.name);
565
576
  }
577
+ #scanInfo = null;
566
578
  async scan({
567
- tsconfig = this.getTsConfig(`${this.cwdPath}/tsconfig.json`),
568
- akanConfig
569
- }, libScanResults = {}) {
570
- if (libScanResults[this.name])
571
- return libScanResults[this.name];
572
- const rootPackageJson = this.readJson(`${this.workspace.workspaceRoot}/package.json`);
573
- const scanner = new TypeScriptDependencyScanner(this.cwdPath);
574
- const npmSet = new Set(Object.keys({ ...rootPackageJson.dependencies, ...rootPackageJson.devDependencies }));
575
- const pkgPathSet = new Set(
576
- Object.keys(tsconfig.compilerOptions.paths ?? {}).filter((path2) => tsconfig.compilerOptions.paths?.[path2]?.some((resolve) => resolve.startsWith("pkgs/"))).map((path2) => path2.replace("/*", ""))
577
- );
578
- const libPathSet = new Set(
579
- Object.keys(tsconfig.compilerOptions.paths ?? {}).filter((path2) => tsconfig.compilerOptions.paths?.[path2]?.some((resolve) => resolve.startsWith("libs/"))).map((path2) => path2.replace("/*", ""))
580
- );
581
- const [npmDepSet, pkgPathDepSet, libPathDepSet] = await scanner.getImportSets([npmSet, pkgPathSet, libPathSet]);
582
- const pkgDeps = [...pkgPathDepSet].map((path2) => {
583
- const pathSplitLength = path2.split("/").length;
584
- return (tsconfig.compilerOptions.paths?.[path2]?.[0] ?? "*").split("/").slice(1, 1 + pathSplitLength).join("/");
585
- });
586
- const libDeps = [...libPathDepSet].map((path2) => {
587
- const pathSplitLength = path2.split("/").length;
588
- return (tsconfig.compilerOptions.paths?.[path2]?.[0] ?? "*").split("/").slice(1, 1 + pathSplitLength).join("/");
589
- }).filter((libName) => libName !== this.name);
590
- if (!fs.existsSync(`${this.cwdPath}/lib/__scalar`))
591
- fs.mkdirSync(`${this.cwdPath}/lib/__scalar`, { recursive: true });
592
- const files = getDefaultFileScan();
593
- const dirnames = (await this.readdir("lib")).filter(
594
- (name) => fs.lstatSync(`${this.cwdPath}/lib/${name}`).isDirectory()
595
- );
596
- const databaseDirs = dirnames.filter((name) => !name.startsWith("_"));
597
- const serviceDirs = dirnames.filter((name) => name.startsWith("_") && !name.startsWith("__"));
598
- await Promise.all(
599
- databaseDirs.map(async (name) => {
600
- const filenames = await this.readdir(path.join("lib", name));
601
- filenames.forEach((filename) => {
602
- if (filename.endsWith(".constant.ts"))
603
- files.constants.databases.push(name);
604
- else if (filename.endsWith(".dictionary.ts"))
605
- files.dictionary.databases.push(name);
606
- else if (filename.endsWith(".document.ts"))
607
- files.documents.databases.push(name);
608
- else if (filename.endsWith(".service.ts"))
609
- files.services.databases.push(name);
610
- else if (filename.endsWith(".signal.ts"))
611
- files.signal.databases.push(name);
612
- else if (filename.endsWith(".store.ts"))
613
- files.store.databases.push(name);
614
- else if (filename === "index.tsx")
615
- files.components.databases.push(name);
616
- });
617
- })
618
- );
619
- await Promise.all(
620
- serviceDirs.map(async (dirname) => {
621
- const name = dirname.slice(1);
622
- const filenames = await this.readdir(path.join("lib", dirname));
623
- filenames.forEach((filename) => {
624
- if (filename.endsWith(".dictionary.ts"))
625
- files.dictionary.services.push(name);
626
- else if (filename.endsWith(".service.ts"))
627
- files.services.services.push(name);
628
- else if (filename.endsWith(".signal.ts"))
629
- files.signal.services.push(name);
630
- else if (filename.endsWith(".store.ts"))
631
- files.store.services.push(name);
632
- else if (filename === "index.tsx")
633
- files.components.services.push(name);
634
- });
635
- })
636
- );
637
- const scalarDirs = (await this.readdir("lib/__scalar")).filter((name) => !name.startsWith("_"));
638
- await Promise.all(
639
- scalarDirs.map(async (name) => {
640
- const filenames = await this.readdir(path.join("lib/__scalar", name));
641
- filenames.forEach((filename) => {
642
- if (filename.endsWith(".constant.ts"))
643
- files.constants.scalars.push(name);
644
- else if (filename.endsWith(".dictionary.ts"))
645
- files.dictionary.scalars.push(name);
646
- else if (filename.endsWith(".document.ts"))
647
- files.documents.scalars.push(name);
648
- else if (filename.endsWith(".service.ts"))
649
- files.services.scalars.push(name);
650
- else if (filename.endsWith(".signal.ts"))
651
- files.signal.scalars.push(name);
652
- else if (filename.endsWith(".store.ts"))
653
- files.store.scalars.push(name);
654
- else if (filename === "index.ts")
655
- files.components.scalars.push(name);
656
- });
657
- })
658
- );
659
- const missingLibDeps = [];
660
- libDeps.forEach((libName) => {
661
- if (!akanConfig.libs.includes(libName))
662
- missingLibDeps.push(libName);
663
- });
664
- if (missingLibDeps.length)
665
- throw new Error(
666
- `Missing libs: ${missingLibDeps.join(", ")}, add these dependencies in akan.config.ts as { libs: [...other deps, ${missingLibDeps.join(", ")}] }`
667
- );
668
- for (const libName of akanConfig.libs) {
669
- if (libScanResults[libName])
670
- continue;
671
- const lib = new LibExecutor({ workspace: this.workspace, name: libName });
672
- const akanConfig2 = await lib.getConfig();
673
- libScanResults[libName] = await lib.scan({ akanConfig: akanConfig2 }, libScanResults);
579
+ refresh,
580
+ write = true,
581
+ writeLib = true
582
+ } = {}) {
583
+ if (this.#scanInfo && !refresh)
584
+ return this.#scanInfo;
585
+ const scanInfo = this.type === "app" ? await AppInfo.fromExecutor(this, { refresh }) : await LibInfo.fromExecutor(this, { refresh });
586
+ if (write) {
587
+ await Promise.all([
588
+ this._applyTemplate({ basePath: "lib", template: "lib", scanInfo }),
589
+ this._applyTemplate({ basePath: ".", template: "server.ts", scanInfo }),
590
+ this._applyTemplate({ basePath: ".", template: "client.ts", scanInfo }),
591
+ this.type === "lib" ? this._applyTemplate({ basePath: ".", template: "index.ts", scanInfo }) : null,
592
+ ...scanInfo.getDatabaseModules().map(
593
+ (model) => this._applyTemplate({
594
+ basePath: `lib/${model}`,
595
+ template: "moduleRoot",
596
+ scanInfo,
597
+ dict: { model, Model: capitalize(model) }
598
+ })
599
+ ),
600
+ ...scanInfo.getServiceModules().map(
601
+ (model) => this._applyTemplate({
602
+ basePath: `lib/_${model}`,
603
+ template: "moduleRoot",
604
+ scanInfo,
605
+ dict: { model, Model: capitalize(model) }
606
+ })
607
+ )
608
+ ]);
609
+ this.writeJson(`akan.${this.type}.json`, scanInfo.getScanResult());
610
+ if (this.type === "lib")
611
+ this.#updateDependencies(scanInfo);
612
+ if (writeLib) {
613
+ const libInfos = [...scanInfo.getLibInfos().values()];
614
+ await Promise.all(
615
+ libInfos.map((libInfo) => [
616
+ libInfo.exec._applyTemplate({ basePath: "lib", template: "lib", scanInfo: libInfo }),
617
+ libInfo.exec._applyTemplate({ basePath: ".", template: "server.ts", scanInfo: libInfo }),
618
+ libInfo.exec._applyTemplate({ basePath: ".", template: "client.ts", scanInfo: libInfo }),
619
+ libInfo.exec._applyTemplate({ basePath: ".", template: "index.ts", scanInfo: libInfo }),
620
+ ...libInfo.getDatabaseModules().map(
621
+ (model) => libInfo.exec._applyTemplate({
622
+ basePath: `lib/${model}`,
623
+ template: "moduleRoot",
624
+ scanInfo: libInfo,
625
+ dict: { model, Model: capitalize(model) }
626
+ })
627
+ ),
628
+ ...libInfo.getServiceModules().map(
629
+ (model) => libInfo.exec._applyTemplate({
630
+ basePath: `lib/_${model}`,
631
+ template: "moduleRoot",
632
+ scanInfo: libInfo,
633
+ dict: { model, Model: capitalize(model) }
634
+ })
635
+ )
636
+ ]).flat()
637
+ );
638
+ }
674
639
  }
675
- const scanResult = {
676
- name: this.name,
677
- type: this.type,
678
- repoName: this.workspace.repoName,
679
- serveDomain: this.workspace.getBaseDevEnv().serveDomain,
680
- akanConfig,
681
- files,
682
- libDeps,
683
- pkgDeps,
684
- dependencies: [...npmDepSet].filter((dep) => !dep.startsWith("@akanjs")),
685
- libs: Object.fromEntries(akanConfig.libs.map((libName) => [libName, libScanResults[libName]]))
686
- };
687
- await this._applyTemplate({ basePath: "lib", template: "lib", scanResult });
688
- await this._applyTemplate({ basePath: ".", template: "server.ts", scanResult });
689
- await this._applyTemplate({ basePath: ".", template: "client.ts", scanResult });
690
- if (this.type === "lib")
691
- await this._applyTemplate({ basePath: ".", template: "index.ts", scanResult });
692
- this.writeJson(`akan.${this.type}.json`, scanResult);
693
- if (this.type === "app")
694
- return scanResult;
695
- const libPackageJson = this.readJson("package.json");
640
+ this.#scanInfo = scanInfo;
641
+ return scanInfo;
642
+ }
643
+ #updateDependencies(scanInfo) {
644
+ const rootPackageJson = this.workspace.getPackageJson();
645
+ const libPackageJson = this.getPackageJson();
646
+ const dependencies = scanInfo.getScanResult().dependencies;
696
647
  const libPkgJsonWithDeps = {
697
648
  ...libPackageJson,
698
649
  dependencies: {
699
650
  ...libPackageJson.dependencies,
700
651
  ...Object.fromEntries(
701
- scanResult.dependencies.filter((dep) => rootPackageJson.dependencies?.[dep]).sort().map((dep) => [dep, rootPackageJson.dependencies?.[dep]])
652
+ dependencies.filter((dep) => rootPackageJson.dependencies?.[dep]).sort().map((dep) => [dep, rootPackageJson.dependencies?.[dep]])
702
653
  )
703
654
  },
704
655
  devDependencies: {
705
656
  ...libPackageJson.devDependencies,
706
657
  ...Object.fromEntries(
707
- scanResult.dependencies.filter((dep) => rootPackageJson.devDependencies?.[dep]).sort().map((dep) => [dep, rootPackageJson.devDependencies?.[dep]])
658
+ dependencies.filter((dep) => rootPackageJson.devDependencies?.[dep]).sort().map((dep) => [dep, rootPackageJson.devDependencies?.[dep]])
708
659
  )
709
660
  }
710
661
  };
711
- this.writeJson("package.json", libPkgJsonWithDeps);
712
- return scanResult;
662
+ this.setPackageJson(libPkgJsonWithDeps);
713
663
  }
714
664
  getLocalFile(targetPath) {
715
665
  const filePath = path.isAbsolute(targetPath) ? targetPath : `${this.type}s/${this.name}/${targetPath}`;
@@ -792,9 +742,9 @@ class SysExecutor extends Executor {
792
742
  )
793
743
  };
794
744
  const akanConfig = await this.getConfig();
795
- const scanResult = await this.scan({ akanConfig });
796
- const fileContents = await this._applyTemplate({ ...options, scanResult, dict });
797
- await this.scan({ akanConfig });
745
+ const scanInfo = await this.scan();
746
+ const fileContents = await this._applyTemplate({ ...options, scanInfo, dict });
747
+ await this.scan();
798
748
  return fileContents;
799
749
  }
800
750
  setTsPaths() {
@@ -809,21 +759,29 @@ class AppExecutor extends SysExecutor {
809
759
  super({ workspace, name, type: "app" });
810
760
  this.dist = new Executor(`dist/${name}`, `${this.workspace.workspaceRoot}/dist/apps/${name}`);
811
761
  }
762
+ static #execs = /* @__PURE__ */ new Map();
812
763
  static from(executor, name) {
813
- if (executor instanceof WorkspaceExecutor)
764
+ const exec2 = this.#execs.get(name);
765
+ if (exec2)
766
+ return exec2;
767
+ else if (executor instanceof WorkspaceExecutor)
814
768
  return new AppExecutor({ workspace: executor, name });
815
- return new AppExecutor({ workspace: executor.workspace, name });
769
+ else
770
+ return new AppExecutor({ workspace: executor.workspace, name });
816
771
  }
817
772
  getEnv() {
818
773
  return this.workspace.getBaseDevEnv().env;
819
774
  }
820
- async getConfig(command) {
821
- return await getAppConfig(this.cwdPath, {
775
+ #akanConfig = null;
776
+ async getConfig({ refresh } = {}) {
777
+ if (this.#akanConfig && !refresh)
778
+ return this.#akanConfig;
779
+ this.#akanConfig = await getAppConfig(this.cwdPath, {
822
780
  ...this.workspace.getBaseDevEnv(),
823
781
  type: "app",
824
- name: this.name,
825
- command
782
+ name: this.name
826
783
  });
784
+ return this.#akanConfig;
827
785
  }
828
786
  async syncAssets(libDeps) {
829
787
  const projectPublicLibPath = `${this.cwdPath}/public/libs`;
@@ -860,18 +818,26 @@ class LibExecutor extends SysExecutor {
860
818
  super({ workspace, name, type: "lib" });
861
819
  this.dist = new Executor(`dist/${name}`, `${this.workspace.workspaceRoot}/dist/libs/${name}`);
862
820
  }
821
+ static #execs = /* @__PURE__ */ new Map();
863
822
  static from(executor, name) {
864
- if (executor instanceof WorkspaceExecutor)
823
+ const exec2 = this.#execs.get(name);
824
+ if (exec2)
825
+ return exec2;
826
+ else if (executor instanceof WorkspaceExecutor)
865
827
  return new LibExecutor({ workspace: executor, name });
866
- return new LibExecutor({ workspace: executor.workspace, name });
867
- }
868
- async getConfig(command) {
869
- return await getLibConfig(this.cwdPath, {
828
+ else
829
+ return new LibExecutor({ workspace: executor.workspace, name });
830
+ }
831
+ #akanConfig = null;
832
+ async getConfig({ refresh } = {}) {
833
+ if (this.#akanConfig && !refresh)
834
+ return this.#akanConfig;
835
+ this.#akanConfig = await getLibConfig(this.cwdPath, {
870
836
  ...this.workspace.getBaseDevEnv(),
871
837
  type: "lib",
872
- name: this.name,
873
- command
838
+ name: this.name
874
839
  });
840
+ return this.#akanConfig;
875
841
  }
876
842
  }
877
843
  class PkgExecutor extends Executor {
@@ -890,27 +856,13 @@ class PkgExecutor extends Executor {
890
856
  return new PkgExecutor({ workspace: executor, name });
891
857
  return new PkgExecutor({ workspace: executor.workspace, name });
892
858
  }
893
- async scan({
894
- packageJson = this.readJson(`${this.cwdPath}/package.json`),
895
- tsconfig = this.getTsConfig(`${this.cwdPath}/tsconfig.json`)
896
- } = {}) {
897
- const rootPackageJson = this.readJson(`${this.workspace.workspaceRoot}/package.json`);
898
- const scanner = new TypeScriptDependencyScanner(this.cwdPath);
899
- const npmSet = new Set(Object.keys({ ...rootPackageJson.dependencies, ...rootPackageJson.devDependencies }));
900
- const pkgPathSet = new Set(
901
- Object.keys(tsconfig.compilerOptions.paths ?? {}).filter((path2) => tsconfig.compilerOptions.paths?.[path2]?.some((resolve) => resolve.startsWith("pkgs/"))).map((path2) => path2.replace("/*", ""))
902
- );
903
- const [npmDepSet, pkgPathDepSet] = await scanner.getImportSets([npmSet, pkgPathSet]);
904
- const pkgDeps = [...pkgPathDepSet].map((path2) => {
905
- const pathSplitLength = path2.split("/").length;
906
- return (tsconfig.compilerOptions.paths?.[path2]?.[0] ?? "*").split("/").slice(1, 1 + pathSplitLength).join("/");
907
- }).filter((pkg) => pkg !== this.name);
908
- const pkgScanResult = {
909
- name: this.name,
910
- pkgDeps,
911
- dependencies: [...npmDepSet]
912
- };
913
- return pkgScanResult;
859
+ #scanInfo = null;
860
+ async scan({ refresh } = {}) {
861
+ if (this.#scanInfo && !refresh)
862
+ return this.#scanInfo;
863
+ const scanInfo = await PkgInfo.fromExecutor(this, { refresh });
864
+ this.#scanInfo = scanInfo;
865
+ return scanInfo;
914
866
  }
915
867
  }
916
868
  class ModuleExecutor extends Executor {
package/esm/src/index.js CHANGED
@@ -20,3 +20,4 @@ export * from "./prompter";
20
20
  export * from "./guideline";
21
21
  export * from "./getDirname";
22
22
  export * from "./useStdoutDimensions";
23
+ export * from "./scanInfo";