@akanjs/cli 2.1.0-rc.6 → 2.1.0-rc.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,7 +3,6 @@ var __require = import.meta.require;
3
3
 
4
4
  // pkgs/@akanjs/devkit/incrementalBuilder/incrementalBuilder.proc.ts
5
5
  import path36 from "path";
6
- import { Logger as Logger12 } from "akanjs/common";
7
6
 
8
7
  // pkgs/@akanjs/devkit/aiEditor.ts
9
8
  import { input, select } from "@inquirer/prompts";
@@ -5950,12 +5949,7 @@ class CssImportResolver {
5950
5949
  }
5951
5950
  }
5952
5951
  #resolutionBases(fromBase) {
5953
- return [
5954
- fromBase,
5955
- this.#workspaceRoot,
5956
- path22.dirname(Bun.main),
5957
- path22.resolve(path22.dirname(Bun.main), "../..")
5958
- ];
5952
+ return [fromBase, this.#workspaceRoot, path22.dirname(Bun.main), path22.resolve(path22.dirname(Bun.main), "../..")];
5959
5953
  }
5960
5954
  #packageJsonCandidates(pkgName) {
5961
5955
  return [
@@ -7177,22 +7171,6 @@ var SSR_RENDER_EXTERNALS = [
7177
7171
  "react-server-dom-webpack/client.node",
7178
7172
  "react-server-dom-webpack/client.browser"
7179
7173
  ];
7180
- var TYPECHECK_WORKER_CODE = `
7181
- import { TypeChecker } from "@akanjs/devkit";
7182
-
7183
- try {
7184
- const configPath = process.env.AKAN_TYPECHECK_TSCONFIG;
7185
- if (!configPath) throw new Error("AKAN_TYPECHECK_TSCONFIG is required");
7186
- const result = TypeChecker.checkProject(configPath);
7187
- if (result.errors.length > 0) {
7188
- console.error(result.message);
7189
- process.exit(1);
7190
- }
7191
- } catch (error) {
7192
- console.error(error instanceof Error ? error.message : String(error));
7193
- process.exit(1);
7194
- }
7195
- `;
7196
7174
 
7197
7175
  class ApplicationBuildRunner {
7198
7176
  #app;
@@ -7336,7 +7314,8 @@ class ApplicationBuildRunner {
7336
7314
  return { typecheckDir, tsconfigPath };
7337
7315
  }
7338
7316
  async#checkProjectInChildProcess(tsconfigPath) {
7339
- const proc = Bun.spawn([process.execPath, "--eval", TYPECHECK_WORKER_CODE], {
7317
+ const entry = await this.#resolveTypecheckWorkerEntry();
7318
+ const proc = Bun.spawn([process.execPath, entry], {
7340
7319
  cwd: this.#app.workspace.workspaceRoot,
7341
7320
  env: this.#app.getCommandEnv({
7342
7321
  AKAN_COMMAND_TYPE: "typecheck",
@@ -7353,6 +7332,18 @@ class ApplicationBuildRunner {
7353
7332
  if (exitCode !== 0)
7354
7333
  throw new Error((stderr || stdout).trim() || `Typecheck failed with exit code ${exitCode}`);
7355
7334
  }
7335
+ async#resolveTypecheckWorkerEntry() {
7336
+ const candidates = [
7337
+ path32.join(this.#app.workspace.workspaceRoot, "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
7338
+ path32.join(this.#app.workspace.workspaceRoot, "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
7339
+ path32.join(import.meta.dir, "typecheck.proc.js"),
7340
+ path32.join(import.meta.dir, "typecheck.proc.ts")
7341
+ ];
7342
+ for (const candidate of candidates)
7343
+ if (await Bun.file(candidate).exists())
7344
+ return candidate;
7345
+ throw new Error(`[cli] typecheck worker entry not found; looked in: ${candidates.join(", ")}`);
7346
+ }
7356
7347
  async#buildOrThrow(label, config) {
7357
7348
  const result = await Bun.build(config);
7358
7349
  if (!result.success)
@@ -8121,7 +8112,7 @@ class CapacitorApp {
8121
8112
  await mkdir10(this.targetRoot, { recursive: true });
8122
8113
  const appInfoPath = path34.relative(this.app.cwdPath, path34.join(this.app.cwdPath, "akan.app.json")).split(path34.sep).join("/");
8123
8114
  const content = `import type { AppScanResult } from "akanjs";
8124
- import { withBase } from "@akanjs/devkit/capacitor.base.config";
8115
+ import { withBase } from "akanjs/capacitor.base.config";
8125
8116
  import appInfo from "${appInfoPath.startsWith(".") ? appInfoPath : `./${appInfoPath}`}";
8126
8117
 
8127
8118
  export default withBase(
@@ -9364,6 +9355,8 @@ import { useEffect as useEffect3, useState as useState3 } from "react";
9364
9355
  import { jsxDEV as jsxDEV2, Fragment as Fragment2 } from "react/jsx-dev-runtime";
9365
9356
  "use client";
9366
9357
  // pkgs/@akanjs/devkit/incrementalBuilder/incrementalBuilder.proc.ts
9358
+ import { Logger as Logger12 } from "akanjs/common";
9359
+
9367
9360
  class IncrementalBuilder {
9368
9361
  #logger = new Logger12("IncrementalBuilder");
9369
9362
  #app;
package/index.js CHANGED
@@ -5947,12 +5947,7 @@ class CssImportResolver {
5947
5947
  }
5948
5948
  }
5949
5949
  #resolutionBases(fromBase) {
5950
- return [
5951
- fromBase,
5952
- this.#workspaceRoot,
5953
- path22.dirname(Bun.main),
5954
- path22.resolve(path22.dirname(Bun.main), "../..")
5955
- ];
5950
+ return [fromBase, this.#workspaceRoot, path22.dirname(Bun.main), path22.resolve(path22.dirname(Bun.main), "../..")];
5956
5951
  }
5957
5952
  #packageJsonCandidates(pkgName) {
5958
5953
  return [
@@ -7174,22 +7169,6 @@ var SSR_RENDER_EXTERNALS = [
7174
7169
  "react-server-dom-webpack/client.node",
7175
7170
  "react-server-dom-webpack/client.browser"
7176
7171
  ];
7177
- var TYPECHECK_WORKER_CODE = `
7178
- import { TypeChecker } from "@akanjs/devkit";
7179
-
7180
- try {
7181
- const configPath = process.env.AKAN_TYPECHECK_TSCONFIG;
7182
- if (!configPath) throw new Error("AKAN_TYPECHECK_TSCONFIG is required");
7183
- const result = TypeChecker.checkProject(configPath);
7184
- if (result.errors.length > 0) {
7185
- console.error(result.message);
7186
- process.exit(1);
7187
- }
7188
- } catch (error) {
7189
- console.error(error instanceof Error ? error.message : String(error));
7190
- process.exit(1);
7191
- }
7192
- `;
7193
7172
 
7194
7173
  class ApplicationBuildRunner {
7195
7174
  #app;
@@ -7333,7 +7312,8 @@ class ApplicationBuildRunner {
7333
7312
  return { typecheckDir, tsconfigPath };
7334
7313
  }
7335
7314
  async#checkProjectInChildProcess(tsconfigPath) {
7336
- const proc = Bun.spawn([process.execPath, "--eval", TYPECHECK_WORKER_CODE], {
7315
+ const entry = await this.#resolveTypecheckWorkerEntry();
7316
+ const proc = Bun.spawn([process.execPath, entry], {
7337
7317
  cwd: this.#app.workspace.workspaceRoot,
7338
7318
  env: this.#app.getCommandEnv({
7339
7319
  AKAN_COMMAND_TYPE: "typecheck",
@@ -7350,6 +7330,18 @@ class ApplicationBuildRunner {
7350
7330
  if (exitCode !== 0)
7351
7331
  throw new Error((stderr || stdout).trim() || `Typecheck failed with exit code ${exitCode}`);
7352
7332
  }
7333
+ async#resolveTypecheckWorkerEntry() {
7334
+ const candidates = [
7335
+ path32.join(this.#app.workspace.workspaceRoot, "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
7336
+ path32.join(this.#app.workspace.workspaceRoot, "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
7337
+ path32.join(import.meta.dir, "typecheck.proc.js"),
7338
+ path32.join(import.meta.dir, "typecheck.proc.ts")
7339
+ ];
7340
+ for (const candidate of candidates)
7341
+ if (await Bun.file(candidate).exists())
7342
+ return candidate;
7343
+ throw new Error(`[cli] typecheck worker entry not found; looked in: ${candidates.join(", ")}`);
7344
+ }
7353
7345
  async#buildOrThrow(label, config) {
7354
7346
  const result = await Bun.build(config);
7355
7347
  if (!result.success)
@@ -8118,7 +8110,7 @@ class CapacitorApp {
8118
8110
  await mkdir10(this.targetRoot, { recursive: true });
8119
8111
  const appInfoPath = path34.relative(this.app.cwdPath, path34.join(this.app.cwdPath, "akan.app.json")).split(path34.sep).join("/");
8120
8112
  const content = `import type { AppScanResult } from "akanjs";
8121
- import { withBase } from "@akanjs/devkit/capacitor.base.config";
8113
+ import { withBase } from "akanjs/capacitor.base.config";
8122
8114
  import appInfo from "${appInfoPath.startsWith(".") ? appInfoPath : `./${appInfoPath}`}";
8123
8115
 
8124
8116
  export default withBase(
@@ -10152,7 +10144,9 @@ class PackageRunner extends runner("package") {
10152
10144
  await pkg.dist.mkdir(pkg.dist.cwdPath);
10153
10145
  const scanner = await TypeScriptDependencyScanner.from(pkg);
10154
10146
  const { npmDeps, npmDevDeps, missingDeps } = await scanner.getPackageBuildDependencies(pkg.name);
10155
- const packageRuntimeDependencies = { "@akanjs/devkit": ["daisyui", "tailwind-scrollbar"] };
10147
+ const packageRuntimeDependencies = {
10148
+ "@akanjs/devkit": ["daisyui", "tailwind-scrollbar"]
10149
+ };
10156
10150
  const packageRuntimeDevDependencies = { akanjs: ["@biomejs/biome", "@types/bun"] };
10157
10151
  if (pkg.name === "@akanjs/cli") {
10158
10152
  const devkitPackageJson = await pkg.workspace.readJson("pkgs/@akanjs/devkit/package.json");
@@ -10467,6 +10461,7 @@ class CloudCommand extends command("cloud", [CloudScript], ({ public: target })
10467
10461
 
10468
10462
  // pkgs/@akanjs/cli/guideline/guideline.prompt.ts
10469
10463
  import { randomPicks } from "akanjs/common";
10464
+
10470
10465
  class GuidelinePrompt extends Prompter {
10471
10466
  workspace;
10472
10467
  name;
@@ -11568,7 +11563,7 @@ class ScalarScript extends script("scalar", [ScalarRunner]) {
11568
11563
 
11569
11564
  // pkgs/@akanjs/cli/scalar/scalar.command.ts
11570
11565
  class ScalarCommand extends command("scalar", [ScalarScript], ({ public: target }) => ({
11571
- createScalar: target({ desc: "Create a new scalar type (simple data model without DB)" }).arg("scalarName", String, { desc: "name of scalar" }).option("ai", Boolean, { default: false, desc: "use ai to create scalar" }).with(Sys).exec(async function(scalarName, ai, sys3) {
11566
+ createScalar: target({ desc: "Create a new scalar type (simple data model without DB)" }).arg("scalarName", String, { desc: "name of scalar" }).with(Sys).option("ai", Boolean, { default: false, desc: "use ai to create scalar" }).exec(async function(scalarName, sys3, ai) {
11572
11567
  const name = lowerlize2(scalarName.replace(/ /g, ""));
11573
11568
  if (ai)
11574
11569
  await this.scalarScript.createScalarWithAi(sys3, name);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akanjs/cli",
3
- "version": "2.1.0-rc.6",
3
+ "version": "2.1.0-rc.8",
4
4
  "sourceType": "module",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -34,7 +34,7 @@
34
34
  "@langchain/deepseek": "^1.0.26",
35
35
  "@langchain/openai": "^1.4.6",
36
36
  "@trapezedev/project": "^7.1.4",
37
- "akanjs": "2.1.0-rc.5",
37
+ "akanjs": "2.1.0-rc.8",
38
38
  "chalk": "^5.6.2",
39
39
  "commander": "^14.0.3",
40
40
  "daisyui": "^5.5.20",
@@ -1,5 +1,5 @@
1
- import type { AppInfo, LibInfo } from "akanjs";
2
1
  import type { SysExecutor } from "@akanjs/devkit";
2
+ import type { AppInfo, LibInfo } from "akanjs";
3
3
 
4
4
  interface Dict {
5
5
  [key: string]: string;
@@ -117,4 +117,5 @@ libs/*/common/index.ts
117
117
  libs/*/client.ts
118
118
  libs/*/server.ts
119
119
  libs/*/index.ts
120
- **/.akan
120
+ **/.akan
121
+ **/bun.lock
@@ -0,0 +1,208 @@
1
+ // @bun
2
+ var __require = import.meta.require;
3
+
4
+ // pkgs/@akanjs/devkit/typeChecker.ts
5
+ import { readFileSync } from "fs";
6
+ import * as path from "path";
7
+ import chalk from "chalk";
8
+ import * as ts from "typescript";
9
+
10
+ class TypeChecker {
11
+ configPath;
12
+ configFile;
13
+ config;
14
+ constructor(executor) {
15
+ const configPath = this.#findConfigFile(executor.cwdPath);
16
+ if (!configPath)
17
+ throw new Error("No tsconfig.json found in the project");
18
+ this.configPath = configPath;
19
+ this.configFile = ts.readConfigFile(this.configPath, (fileName) => ts.sys.readFile(fileName));
20
+ const parsedConfig = ts.parseJsonConfigFileContent(this.configFile.config, ts.sys, path.dirname(this.configPath), undefined, this.configPath);
21
+ if (parsedConfig.errors.length > 0) {
22
+ const errorMessages = parsedConfig.errors.map((error) => ts.flattenDiagnosticMessageText(error.messageText, `
23
+ `)).join(`
24
+ `);
25
+ throw new Error(`Error parsing tsconfig.json:
26
+ ${errorMessages}`);
27
+ }
28
+ this.config = parsedConfig;
29
+ }
30
+ #findConfigFile(searchPath) {
31
+ return ts.findConfigFile(searchPath, (fileName) => ts.sys.fileExists(fileName), "tsconfig.json");
32
+ }
33
+ check(filePath) {
34
+ const program = ts.createProgram([filePath], this.config.options);
35
+ const diagnostics = [
36
+ ...program.getSemanticDiagnostics(),
37
+ ...program.getSyntacticDiagnostics(),
38
+ ...this.config.options.declaration ? program.getDeclarationDiagnostics() : []
39
+ ];
40
+ const errors = diagnostics.filter((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error);
41
+ const warnings = diagnostics.filter((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Warning);
42
+ const fileDiagnostics = diagnostics.filter((diagnostic) => diagnostic.file?.fileName === filePath);
43
+ const fileErrors = fileDiagnostics.filter((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error);
44
+ const fileWarnings = fileDiagnostics.filter((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Warning);
45
+ return { diagnostics, errors, warnings, fileDiagnostics, fileErrors, fileWarnings };
46
+ }
47
+ formatDiagnostics(diagnostics) {
48
+ if (diagnostics.length === 0)
49
+ return chalk.bold("\u2705 No type errors found");
50
+ const output = [];
51
+ let errorCount = 0;
52
+ let warningCount = 0;
53
+ let suggestionCount = 0;
54
+ const diagnosticsByFile = new Map;
55
+ diagnostics.forEach((diagnostic) => {
56
+ if (diagnostic.category === ts.DiagnosticCategory.Error)
57
+ errorCount++;
58
+ else if (diagnostic.category === ts.DiagnosticCategory.Warning)
59
+ warningCount++;
60
+ else if (diagnostic.category === ts.DiagnosticCategory.Suggestion)
61
+ suggestionCount++;
62
+ if (diagnostic.file) {
63
+ const fileName = diagnostic.file.fileName;
64
+ if (!diagnosticsByFile.has(fileName))
65
+ diagnosticsByFile.set(fileName, []);
66
+ const fileDiagnostics = diagnosticsByFile.get(fileName);
67
+ if (fileDiagnostics)
68
+ fileDiagnostics.push(diagnostic);
69
+ } else {
70
+ if (!diagnosticsByFile.has(""))
71
+ diagnosticsByFile.set("", []);
72
+ const fileDiagnostics = diagnosticsByFile.get("");
73
+ if (fileDiagnostics)
74
+ fileDiagnostics.push(diagnostic);
75
+ }
76
+ });
77
+ diagnosticsByFile.forEach((fileDiagnostics, fileName) => {
78
+ if (fileName)
79
+ output.push(`
80
+ ${chalk.cyan(fileName)}`);
81
+ fileDiagnostics.forEach((diagnostic) => {
82
+ const categoryText = diagnostic.category === ts.DiagnosticCategory.Error ? "error" : diagnostic.category === ts.DiagnosticCategory.Warning ? "warning" : "suggestion";
83
+ const categoryColor = diagnostic.category === ts.DiagnosticCategory.Error ? chalk.red : diagnostic.category === ts.DiagnosticCategory.Warning ? chalk.yellow : chalk.blue;
84
+ const icon = diagnostic.category === ts.DiagnosticCategory.Error ? "\u274C" : diagnostic.category === ts.DiagnosticCategory.Warning ? "\u26A0\uFE0F" : "\uD83D\uDCA1";
85
+ const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, `
86
+ `);
87
+ const tsCode = chalk.dim(`(TS${diagnostic.code})`);
88
+ if (diagnostic.file && diagnostic.start !== undefined) {
89
+ const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
90
+ output.push(`
91
+ ${icon} ${categoryColor(categoryText)}: ${message} ${tsCode}`);
92
+ output.push(` ${chalk.gray("at")} ${fileName}:${chalk.bold(`${line + 1}:${character + 1}`)}`);
93
+ const sourceLines = diagnostic.file.text.split(`
94
+ `);
95
+ if (line < sourceLines.length) {
96
+ const sourceLine = sourceLines[line];
97
+ const lineNumber = (line + 1).toString().padStart(5, " ");
98
+ output.push(`
99
+ ${chalk.dim(`${lineNumber} |`)} ${sourceLine}`);
100
+ const underlinePrefix = " ".repeat(character);
101
+ const length = diagnostic.length ?? 1;
102
+ const underline = "~".repeat(Math.max(1, length));
103
+ output.push(`${chalk.dim(`${" ".repeat(lineNumber.length)} |`)} ${underlinePrefix}${categoryColor(underline)}`);
104
+ }
105
+ } else
106
+ output.push(`
107
+ ${icon} ${categoryColor(categoryText)}: ${message} ${tsCode}`);
108
+ });
109
+ });
110
+ const summary = [];
111
+ if (errorCount > 0)
112
+ summary.push(chalk.red(`${errorCount} error(s)`));
113
+ if (warningCount > 0)
114
+ summary.push(chalk.yellow(`${warningCount} warning(s)`));
115
+ if (suggestionCount > 0)
116
+ summary.push(chalk.blue(`${suggestionCount} suggestion(s)`));
117
+ return `
118
+ ${summary.join(", ")} found${output.join(`
119
+ `)}`;
120
+ }
121
+ getDetailedDiagnostics(filePath) {
122
+ const { diagnostics } = this.check(filePath);
123
+ const sourceFile = ts.createSourceFile(filePath, readFileSync(filePath, "utf8"), ts.ScriptTarget.Latest, true);
124
+ const details = diagnostics.map((diagnostic) => {
125
+ if (diagnostic.file && diagnostic.start !== undefined) {
126
+ const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
127
+ const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, `
128
+ `);
129
+ const lines = sourceFile.text.split(`
130
+ `);
131
+ const codeSnippet = line < lines.length ? lines[line] : undefined;
132
+ return { line: line + 1, column: character + 1, message, code: diagnostic.code, codeSnippet };
133
+ }
134
+ return {
135
+ line: 0,
136
+ column: 0,
137
+ message: ts.flattenDiagnosticMessageText(diagnostic.messageText, `
138
+ `),
139
+ code: diagnostic.code
140
+ };
141
+ });
142
+ return { diagnostics, details };
143
+ }
144
+ hasNoTypeErrors(filePath) {
145
+ try {
146
+ const { diagnostics } = this.check(filePath);
147
+ return diagnostics.length === 0;
148
+ } catch (error) {
149
+ return false;
150
+ }
151
+ }
152
+ static checkProject(configPath) {
153
+ const parsedConfig = TypeChecker.parseConfig(configPath);
154
+ const host = ts.createIncrementalCompilerHost(parsedConfig.options);
155
+ const builderProgram = ts.createIncrementalProgram({
156
+ rootNames: parsedConfig.fileNames,
157
+ options: parsedConfig.options,
158
+ projectReferences: parsedConfig.projectReferences,
159
+ configFileParsingDiagnostics: parsedConfig.errors,
160
+ host
161
+ });
162
+ const program = builderProgram.getProgram();
163
+ const diagnostics = [...ts.getPreEmitDiagnostics(program), ...builderProgram.emit().diagnostics];
164
+ const errors = diagnostics.filter((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Error);
165
+ const warnings = diagnostics.filter((diagnostic) => diagnostic.category === ts.DiagnosticCategory.Warning);
166
+ return {
167
+ configPath,
168
+ diagnostics,
169
+ errors,
170
+ warnings,
171
+ message: TypeChecker.formatDiagnosticMessages(diagnostics)
172
+ };
173
+ }
174
+ static parseConfig(configPath) {
175
+ const configFile = ts.readConfigFile(configPath, (fileName) => ts.sys.readFile(fileName));
176
+ const configDiagnostics = configFile.error ? [configFile.error] : [];
177
+ if (!configFile.config) {
178
+ const message = TypeChecker.formatDiagnosticMessages(configDiagnostics);
179
+ throw new Error(message || `Error reading tsconfig.json: ${configPath}`);
180
+ }
181
+ const parsedConfig = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path.dirname(configPath), undefined, configPath);
182
+ if (parsedConfig.errors.length > 0)
183
+ throw new Error(TypeChecker.formatDiagnosticMessages(parsedConfig.errors));
184
+ return parsedConfig;
185
+ }
186
+ static formatDiagnosticMessages(diagnostics) {
187
+ return ts.formatDiagnosticsWithColorAndContext(diagnostics, {
188
+ getCanonicalFileName: (fileName) => fileName,
189
+ getCurrentDirectory: () => process.cwd(),
190
+ getNewLine: () => ts.sys.newLine
191
+ });
192
+ }
193
+ }
194
+
195
+ // pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts
196
+ try {
197
+ const configPath = process.env.AKAN_TYPECHECK_TSCONFIG;
198
+ if (!configPath)
199
+ throw new Error("AKAN_TYPECHECK_TSCONFIG is required");
200
+ const result = TypeChecker.checkProject(configPath);
201
+ if (result.errors.length > 0) {
202
+ console.error(result.message);
203
+ process.exit(1);
204
+ }
205
+ } catch (error) {
206
+ console.error(error instanceof Error ? error.message : String(error));
207
+ process.exit(1);
208
+ }