@akanjs/cli 2.1.0-rc.5 → 2.1.0-rc.7

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 [
@@ -7087,20 +7081,15 @@ class SsrBaseArtifactBuilder {
7087
7081
  return { rscClientUrl, vendorMap };
7088
7082
  }
7089
7083
  async#resolveAkanServerPath() {
7090
- const candidates = [
7091
- path30.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server"),
7092
- path30.join(this.#app.workspace.workspaceRoot, "node_modules/akanjs/server"),
7093
- path30.join(path30.dirname(Bun.main), "node_modules/akanjs/server"),
7094
- path30.join(path30.dirname(Bun.main), "../../akanjs/server"),
7095
- path30.resolve(import.meta.dir, "../../server"),
7096
- path30.resolve(import.meta.dir, "../server")
7097
- ];
7084
+ const candidates = [];
7098
7085
  try {
7099
- candidates.unshift(path30.dirname(Bun.resolveSync("akanjs/server", this.#app.workspace.workspaceRoot)));
7086
+ candidates.push(path30.dirname(Bun.resolveSync("akanjs/server", this.#app.workspace.workspaceRoot)));
7100
7087
  } catch {}
7088
+ candidates.push(path30.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server"), path30.join(this.#app.workspace.workspaceRoot, "node_modules/akanjs/server"));
7101
7089
  try {
7102
- candidates.unshift(path30.dirname(Bun.resolveSync("akanjs/server", path30.dirname(Bun.main))));
7090
+ candidates.push(path30.dirname(Bun.resolveSync("akanjs/server", path30.dirname(Bun.main))));
7103
7091
  } catch {}
7092
+ candidates.push(path30.join(path30.dirname(Bun.main), "node_modules/akanjs/server"), path30.join(path30.dirname(Bun.main), "../../akanjs/server"), path30.resolve(import.meta.dir, "../../server"), path30.resolve(import.meta.dir, "../server"));
7104
7093
  for (const candidate of candidates) {
7105
7094
  if (await Bun.file(path30.join(candidate, "rscClient.tsx")).exists())
7106
7095
  return candidate;
@@ -7182,22 +7171,6 @@ var SSR_RENDER_EXTERNALS = [
7182
7171
  "react-server-dom-webpack/client.node",
7183
7172
  "react-server-dom-webpack/client.browser"
7184
7173
  ];
7185
- var TYPECHECK_WORKER_CODE = `
7186
- import { TypeChecker } from "@akanjs/devkit";
7187
-
7188
- try {
7189
- const configPath = process.env.AKAN_TYPECHECK_TSCONFIG;
7190
- if (!configPath) throw new Error("AKAN_TYPECHECK_TSCONFIG is required");
7191
- const result = TypeChecker.checkProject(configPath);
7192
- if (result.errors.length > 0) {
7193
- console.error(result.message);
7194
- process.exit(1);
7195
- }
7196
- } catch (error) {
7197
- console.error(error instanceof Error ? error.message : String(error));
7198
- process.exit(1);
7199
- }
7200
- `;
7201
7174
 
7202
7175
  class ApplicationBuildRunner {
7203
7176
  #app;
@@ -7341,7 +7314,8 @@ class ApplicationBuildRunner {
7341
7314
  return { typecheckDir, tsconfigPath };
7342
7315
  }
7343
7316
  async#checkProjectInChildProcess(tsconfigPath) {
7344
- const proc = Bun.spawn([process.execPath, "--eval", TYPECHECK_WORKER_CODE], {
7317
+ const entry = await this.#resolveTypecheckWorkerEntry();
7318
+ const proc = Bun.spawn([process.execPath, entry], {
7345
7319
  cwd: this.#app.workspace.workspaceRoot,
7346
7320
  env: this.#app.getCommandEnv({
7347
7321
  AKAN_COMMAND_TYPE: "typecheck",
@@ -7358,6 +7332,18 @@ class ApplicationBuildRunner {
7358
7332
  if (exitCode !== 0)
7359
7333
  throw new Error((stderr || stdout).trim() || `Typecheck failed with exit code ${exitCode}`);
7360
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
+ }
7361
7347
  async#buildOrThrow(label, config) {
7362
7348
  const result = await Bun.build(config);
7363
7349
  if (!result.success)
@@ -8126,7 +8112,7 @@ class CapacitorApp {
8126
8112
  await mkdir10(this.targetRoot, { recursive: true });
8127
8113
  const appInfoPath = path34.relative(this.app.cwdPath, path34.join(this.app.cwdPath, "akan.app.json")).split(path34.sep).join("/");
8128
8114
  const content = `import type { AppScanResult } from "akanjs";
8129
- import { withBase } from "@akanjs/devkit/capacitor.base.config";
8115
+ import { withBase } from "akanjs/capacitor.base.config";
8130
8116
  import appInfo from "${appInfoPath.startsWith(".") ? appInfoPath : `./${appInfoPath}`}";
8131
8117
 
8132
8118
  export default withBase(
@@ -9369,6 +9355,8 @@ import { useEffect as useEffect3, useState as useState3 } from "react";
9369
9355
  import { jsxDEV as jsxDEV2, Fragment as Fragment2 } from "react/jsx-dev-runtime";
9370
9356
  "use client";
9371
9357
  // pkgs/@akanjs/devkit/incrementalBuilder/incrementalBuilder.proc.ts
9358
+ import { Logger as Logger12 } from "akanjs/common";
9359
+
9372
9360
  class IncrementalBuilder {
9373
9361
  #logger = new Logger12("IncrementalBuilder");
9374
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 [
@@ -7084,20 +7079,15 @@ class SsrBaseArtifactBuilder {
7084
7079
  return { rscClientUrl, vendorMap };
7085
7080
  }
7086
7081
  async#resolveAkanServerPath() {
7087
- const candidates = [
7088
- path30.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server"),
7089
- path30.join(this.#app.workspace.workspaceRoot, "node_modules/akanjs/server"),
7090
- path30.join(path30.dirname(Bun.main), "node_modules/akanjs/server"),
7091
- path30.join(path30.dirname(Bun.main), "../../akanjs/server"),
7092
- path30.resolve(import.meta.dir, "../../server"),
7093
- path30.resolve(import.meta.dir, "../server")
7094
- ];
7082
+ const candidates = [];
7095
7083
  try {
7096
- candidates.unshift(path30.dirname(Bun.resolveSync("akanjs/server", this.#app.workspace.workspaceRoot)));
7084
+ candidates.push(path30.dirname(Bun.resolveSync("akanjs/server", this.#app.workspace.workspaceRoot)));
7097
7085
  } catch {}
7086
+ candidates.push(path30.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server"), path30.join(this.#app.workspace.workspaceRoot, "node_modules/akanjs/server"));
7098
7087
  try {
7099
- candidates.unshift(path30.dirname(Bun.resolveSync("akanjs/server", path30.dirname(Bun.main))));
7088
+ candidates.push(path30.dirname(Bun.resolveSync("akanjs/server", path30.dirname(Bun.main))));
7100
7089
  } catch {}
7090
+ candidates.push(path30.join(path30.dirname(Bun.main), "node_modules/akanjs/server"), path30.join(path30.dirname(Bun.main), "../../akanjs/server"), path30.resolve(import.meta.dir, "../../server"), path30.resolve(import.meta.dir, "../server"));
7101
7091
  for (const candidate of candidates) {
7102
7092
  if (await Bun.file(path30.join(candidate, "rscClient.tsx")).exists())
7103
7093
  return candidate;
@@ -7179,22 +7169,6 @@ var SSR_RENDER_EXTERNALS = [
7179
7169
  "react-server-dom-webpack/client.node",
7180
7170
  "react-server-dom-webpack/client.browser"
7181
7171
  ];
7182
- var TYPECHECK_WORKER_CODE = `
7183
- import { TypeChecker } from "@akanjs/devkit";
7184
-
7185
- try {
7186
- const configPath = process.env.AKAN_TYPECHECK_TSCONFIG;
7187
- if (!configPath) throw new Error("AKAN_TYPECHECK_TSCONFIG is required");
7188
- const result = TypeChecker.checkProject(configPath);
7189
- if (result.errors.length > 0) {
7190
- console.error(result.message);
7191
- process.exit(1);
7192
- }
7193
- } catch (error) {
7194
- console.error(error instanceof Error ? error.message : String(error));
7195
- process.exit(1);
7196
- }
7197
- `;
7198
7172
 
7199
7173
  class ApplicationBuildRunner {
7200
7174
  #app;
@@ -7338,7 +7312,8 @@ class ApplicationBuildRunner {
7338
7312
  return { typecheckDir, tsconfigPath };
7339
7313
  }
7340
7314
  async#checkProjectInChildProcess(tsconfigPath) {
7341
- const proc = Bun.spawn([process.execPath, "--eval", TYPECHECK_WORKER_CODE], {
7315
+ const entry = await this.#resolveTypecheckWorkerEntry();
7316
+ const proc = Bun.spawn([process.execPath, entry], {
7342
7317
  cwd: this.#app.workspace.workspaceRoot,
7343
7318
  env: this.#app.getCommandEnv({
7344
7319
  AKAN_COMMAND_TYPE: "typecheck",
@@ -7355,6 +7330,18 @@ class ApplicationBuildRunner {
7355
7330
  if (exitCode !== 0)
7356
7331
  throw new Error((stderr || stdout).trim() || `Typecheck failed with exit code ${exitCode}`);
7357
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
+ }
7358
7345
  async#buildOrThrow(label, config) {
7359
7346
  const result = await Bun.build(config);
7360
7347
  if (!result.success)
@@ -8123,7 +8110,7 @@ class CapacitorApp {
8123
8110
  await mkdir10(this.targetRoot, { recursive: true });
8124
8111
  const appInfoPath = path34.relative(this.app.cwdPath, path34.join(this.app.cwdPath, "akan.app.json")).split(path34.sep).join("/");
8125
8112
  const content = `import type { AppScanResult } from "akanjs";
8126
- import { withBase } from "@akanjs/devkit/capacitor.base.config";
8113
+ import { withBase } from "akanjs/capacitor.base.config";
8127
8114
  import appInfo from "${appInfoPath.startsWith(".") ? appInfoPath : `./${appInfoPath}`}";
8128
8115
 
8129
8116
  export default withBase(
@@ -10157,7 +10144,9 @@ class PackageRunner extends runner("package") {
10157
10144
  await pkg.dist.mkdir(pkg.dist.cwdPath);
10158
10145
  const scanner = await TypeScriptDependencyScanner.from(pkg);
10159
10146
  const { npmDeps, npmDevDeps, missingDeps } = await scanner.getPackageBuildDependencies(pkg.name);
10160
- const packageRuntimeDependencies = { "@akanjs/devkit": ["daisyui", "tailwind-scrollbar"] };
10147
+ const packageRuntimeDependencies = {
10148
+ "@akanjs/devkit": ["daisyui", "tailwind-scrollbar"]
10149
+ };
10161
10150
  const packageRuntimeDevDependencies = { akanjs: ["@biomejs/biome", "@types/bun"] };
10162
10151
  if (pkg.name === "@akanjs/cli") {
10163
10152
  const devkitPackageJson = await pkg.workspace.readJson("pkgs/@akanjs/devkit/package.json");
@@ -10472,6 +10461,7 @@ class CloudCommand extends command("cloud", [CloudScript], ({ public: target })
10472
10461
 
10473
10462
  // pkgs/@akanjs/cli/guideline/guideline.prompt.ts
10474
10463
  import { randomPicks } from "akanjs/common";
10464
+
10475
10465
  class GuidelinePrompt extends Prompter {
10476
10466
  workspace;
10477
10467
  name;
@@ -11573,7 +11563,7 @@ class ScalarScript extends script("scalar", [ScalarRunner]) {
11573
11563
 
11574
11564
  // pkgs/@akanjs/cli/scalar/scalar.command.ts
11575
11565
  class ScalarCommand extends command("scalar", [ScalarScript], ({ public: target }) => ({
11576
- 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) {
11577
11567
  const name = lowerlize2(scalarName.replace(/ /g, ""));
11578
11568
  if (ai)
11579
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.5",
3
+ "version": "2.1.0-rc.7",
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.6",
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;
@@ -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
+ }