@akanjs/cli 2.3.9-rc.7 → 2.3.9-rc.9
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.
- package/incrementalBuilder.proc.js +2104 -548
- package/index.js +4424 -2983
- package/package.json +2 -2
- package/templates/workspaceRoot/biome.json.template +6 -6
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
var __require = import.meta.require;
|
|
3
3
|
|
|
4
4
|
// pkgs/@akanjs/devkit/incrementalBuilder/incrementalBuilder.proc.ts
|
|
5
|
-
import
|
|
5
|
+
import path42 from "path";
|
|
6
6
|
|
|
7
7
|
// pkgs/@akanjs/devkit/aiEditor.ts
|
|
8
8
|
import { input, select } from "@inquirer/prompts";
|
|
@@ -4777,8 +4777,8 @@ class AkanAppHost {
|
|
|
4777
4777
|
}
|
|
4778
4778
|
// pkgs/@akanjs/devkit/akanContext.ts
|
|
4779
4779
|
import { readdir } from "fs/promises";
|
|
4780
|
-
import
|
|
4781
|
-
import { capitalize as
|
|
4780
|
+
import path11 from "path";
|
|
4781
|
+
import { capitalize as capitalize3 } from "akanjs/common";
|
|
4782
4782
|
|
|
4783
4783
|
// pkgs/@akanjs/devkit/workflow/utils.ts
|
|
4784
4784
|
var jsonText = (value, { trailingNewline = true } = {}) => `${JSON.stringify(value, null, 2)}${trailingNewline ? `
|
|
@@ -4798,6 +4798,29 @@ var uniqueBy = (values, key) => {
|
|
|
4798
4798
|
var compactDiagnostics = (diagnostics) => diagnostics.filter((diagnostic) => !!diagnostic);
|
|
4799
4799
|
|
|
4800
4800
|
// pkgs/@akanjs/devkit/workflow/artifacts.ts
|
|
4801
|
+
var sourceChangeBlocked = (diagnostics) => diagnostics.some((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown"));
|
|
4802
|
+
var workflowPlanApproval = {
|
|
4803
|
+
required: true,
|
|
4804
|
+
meaning: "Review this read-only plan before apply_workflow mutates files.",
|
|
4805
|
+
applyTool: "apply_workflow"
|
|
4806
|
+
};
|
|
4807
|
+
var inferNextActionCode = (action, diagnostics) => {
|
|
4808
|
+
if (action.action)
|
|
4809
|
+
return action.action;
|
|
4810
|
+
if (sourceChangeBlocked(diagnostics) && action.command.startsWith("akan workflow explain"))
|
|
4811
|
+
return "blocked";
|
|
4812
|
+
if (action.command.startsWith("akan workflow repair"))
|
|
4813
|
+
return "repair";
|
|
4814
|
+
if (action.command.startsWith("akan workflow explain"))
|
|
4815
|
+
return "manual-review";
|
|
4816
|
+
if (action.command.startsWith("akan "))
|
|
4817
|
+
return "validate";
|
|
4818
|
+
return "answer";
|
|
4819
|
+
};
|
|
4820
|
+
var nextActionPriority = (action, diagnostics) => {
|
|
4821
|
+
const priority = sourceChangeBlocked(diagnostics) ? { blocked: 0, repair: 1, "manual-review": 2, validate: 3, answer: 4 } : { "manual-review": 0, validate: 1, repair: 2, blocked: 3, answer: 4 };
|
|
4822
|
+
return priority[action.action ?? "answer"];
|
|
4823
|
+
};
|
|
4801
4824
|
var createWorkflowApplyReport = ({
|
|
4802
4825
|
workflow,
|
|
4803
4826
|
mode,
|
|
@@ -4813,18 +4836,31 @@ var createWorkflowApplyReport = ({
|
|
|
4813
4836
|
plan
|
|
4814
4837
|
}) => {
|
|
4815
4838
|
const validationCommands = recommendedValidationCommands ?? commands;
|
|
4816
|
-
const
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4839
|
+
const nextActionsWithIntent = nextActions.map((action) => ({
|
|
4840
|
+
...action,
|
|
4841
|
+
action: inferNextActionCode(action, diagnostics)
|
|
4842
|
+
}));
|
|
4843
|
+
if (sourceChangeBlocked(diagnostics) && !nextActionsWithIntent.some((action) => action.action === "blocked")) {
|
|
4844
|
+
nextActionsWithIntent.unshift({
|
|
4845
|
+
command: `akan workflow explain ${workflow}`,
|
|
4846
|
+
reason: "Review source-change blockers before running validation.",
|
|
4847
|
+
action: "blocked"
|
|
4848
|
+
});
|
|
4849
|
+
}
|
|
4850
|
+
const orderedNextActions = uniqueBy(nextActionsWithIntent, (action) => action.command).sort((left, right) => nextActionPriority(left, diagnostics) - nextActionPriority(right, diagnostics));
|
|
4851
|
+
const sourceFilesChanged = uniqueBy(changedFiles, (file) => `${file.action}:${file.path}:${file.reason}`);
|
|
4852
|
+
const generatedFilesSynced = uniqueBy(generatedFiles, (file) => `${file.action}:${file.path}:${file.reason}`);
|
|
4821
4853
|
return {
|
|
4822
4854
|
schemaVersion: 1,
|
|
4823
4855
|
workflow,
|
|
4824
4856
|
mode,
|
|
4825
4857
|
status: workflowStatus(diagnostics),
|
|
4826
|
-
|
|
4827
|
-
|
|
4858
|
+
summary: {
|
|
4859
|
+
sourceFilesChanged,
|
|
4860
|
+
generatedFilesSynced
|
|
4861
|
+
},
|
|
4862
|
+
changedFiles: sourceFilesChanged,
|
|
4863
|
+
generatedFiles: generatedFilesSynced,
|
|
4828
4864
|
appliedCommands: uniqueBy(appliedCommands, (command) => command.command),
|
|
4829
4865
|
recommendedValidationCommands: uniqueBy(validationCommands, (command) => command.command),
|
|
4830
4866
|
commands: uniqueBy(validationCommands, (command) => command.command),
|
|
@@ -4902,6 +4938,52 @@ var statusForValidationKind = (commands, kind) => {
|
|
|
4902
4938
|
return "unknown";
|
|
4903
4939
|
return matching.some((command) => command.status === "failed") ? "failed" : "passed";
|
|
4904
4940
|
};
|
|
4941
|
+
var statusForCommands = (commands) => {
|
|
4942
|
+
if (commands.length === 0)
|
|
4943
|
+
return "unknown";
|
|
4944
|
+
return commandStatus(commands) === "failed" ? "failed" : "passed";
|
|
4945
|
+
};
|
|
4946
|
+
var statusForDiagnostics = (diagnostics) => {
|
|
4947
|
+
if (diagnostics.length === 0)
|
|
4948
|
+
return "unknown";
|
|
4949
|
+
return workflowStatus(diagnostics) === "failed" ? "failed" : "passed";
|
|
4950
|
+
};
|
|
4951
|
+
var workflowDiagnosticContextPaths = (diagnostics) => uniqueBy(diagnostics.flatMap((diagnostic) => diagnostic.context?.paths ?? []), (filePath) => filePath);
|
|
4952
|
+
var createWorkflowBaselineSummary = (diagnostics, { detailsIncluded = true, knownBlockerCount = 0 } = {}) => {
|
|
4953
|
+
const grouped = new Map;
|
|
4954
|
+
let totalErrors = 0;
|
|
4955
|
+
let totalWarnings = 0;
|
|
4956
|
+
for (const diagnostic of diagnostics) {
|
|
4957
|
+
if (diagnostic.severity === "error")
|
|
4958
|
+
totalErrors += 1;
|
|
4959
|
+
else
|
|
4960
|
+
totalWarnings += 1;
|
|
4961
|
+
const existing = grouped.get(diagnostic.code);
|
|
4962
|
+
if (existing) {
|
|
4963
|
+
existing.count += 1;
|
|
4964
|
+
if (existing.severity !== diagnostic.severity)
|
|
4965
|
+
existing.severity = "mixed";
|
|
4966
|
+
} else {
|
|
4967
|
+
grouped.set(diagnostic.code, {
|
|
4968
|
+
code: diagnostic.code,
|
|
4969
|
+
severity: diagnostic.severity,
|
|
4970
|
+
count: 1,
|
|
4971
|
+
sampleMessage: diagnostic.message
|
|
4972
|
+
});
|
|
4973
|
+
}
|
|
4974
|
+
}
|
|
4975
|
+
const contextPaths = workflowDiagnosticContextPaths(diagnostics);
|
|
4976
|
+
return {
|
|
4977
|
+
status: totalErrors > 0 ? "failed" : diagnostics.length > 0 ? "passed" : "unknown",
|
|
4978
|
+
total: diagnostics.length,
|
|
4979
|
+
totalErrors,
|
|
4980
|
+
totalWarnings,
|
|
4981
|
+
detailsIncluded,
|
|
4982
|
+
knownBlockerCount,
|
|
4983
|
+
byCode: [...grouped.values()],
|
|
4984
|
+
...contextPaths.length ? { contextPaths } : {}
|
|
4985
|
+
};
|
|
4986
|
+
};
|
|
4905
4987
|
var createKnownBlockers = (commands, diagnostics) => {
|
|
4906
4988
|
const commandBlockers = commands.filter((command) => command.status === "failed" && (command.failureScope === "workspace-config" || command.failureScope === "environment")).map((command) => ({
|
|
4907
4989
|
code: `workflow-validation-${command.failureScope}`,
|
|
@@ -4930,18 +5012,28 @@ var createKnownBlockers = (commands, diagnostics) => {
|
|
|
4930
5012
|
}
|
|
4931
5013
|
return [...grouped.values()];
|
|
4932
5014
|
};
|
|
4933
|
-
var createValidationStatuses = (commands,
|
|
5015
|
+
var createValidationStatuses = (commands, reportDiagnostics, baselineDiagnostics, workflowDiagnostics) => {
|
|
5016
|
+
const diagnostics = [...reportDiagnostics, ...baselineDiagnostics, ...workflowDiagnostics];
|
|
4934
5017
|
const scopes = [...failedCommandScopes(commands), ...errorDiagnosticScopes(diagnostics)];
|
|
4935
|
-
const
|
|
5018
|
+
const sourceDiagnostics = [...reportDiagnostics, ...workflowDiagnostics].filter((diagnostic) => diagnostic.failureScope === "source-change" || diagnostic.scope === "workflow" || !diagnostic.failureScope && diagnostic.scope !== "baseline");
|
|
5019
|
+
const sourceScopes = [...failedCommandScopes(commands), ...errorDiagnosticScopes(sourceDiagnostics)];
|
|
5020
|
+
const sourceStatus = statusForScope(commands, sourceDiagnostics, sourceScopes, "source-change");
|
|
5021
|
+
const validationCommandsStatus = statusForCommands(commands);
|
|
5022
|
+
const baselineStatus = statusForDiagnostics(baselineDiagnostics);
|
|
5023
|
+
const nonBaselineDiagnostics = [...reportDiagnostics, ...workflowDiagnostics];
|
|
4936
5024
|
const workspaceStatus = hasScopeFailure(scopes, "workspace-config", diagnostics) || hasScopeFailure(scopes, "environment", diagnostics) ? "failed" : commands.length || diagnostics.length ? "passed" : "unknown";
|
|
4937
|
-
const overallStatus = hasScopeFailure(scopes, "source-change", diagnostics) ? "failed" : hasScopeFailure(scopes, "workspace-config", diagnostics) ? "blocked-by-workspace-config" : hasScopeFailure(scopes, "environment", diagnostics) ? "blocked-by-environment" : workflowStatus(diagnostics) === "failed" || commandStatus(commands) === "failed" ? "failed" : "passed";
|
|
5025
|
+
const overallStatus = hasScopeFailure(scopes, "source-change", diagnostics) ? "failed" : validationCommandsStatus === "passed" && baselineStatus === "failed" && workflowStatus(nonBaselineDiagnostics) !== "failed" ? "passed-with-baseline-blockers" : hasScopeFailure(scopes, "workspace-config", diagnostics) ? "blocked-by-workspace-config" : hasScopeFailure(scopes, "environment", diagnostics) ? "blocked-by-environment" : workflowStatus(diagnostics) === "failed" || commandStatus(commands) === "failed" ? "failed" : "passed";
|
|
4938
5026
|
return {
|
|
4939
5027
|
sourceStatus,
|
|
4940
5028
|
workspaceStatus,
|
|
5029
|
+
validationCommandsStatus,
|
|
5030
|
+
baselineStatus,
|
|
4941
5031
|
overallStatus,
|
|
4942
5032
|
summary: {
|
|
4943
5033
|
sourceChange: sourceStatus,
|
|
4944
5034
|
generatedSync: statusForValidationKind(commands, "sync"),
|
|
5035
|
+
validationCommands: validationCommandsStatus,
|
|
5036
|
+
baseline: baselineStatus,
|
|
4945
5037
|
workspaceConfig: statusForScope(commands, diagnostics, scopes, "workspace-config"),
|
|
4946
5038
|
environment: statusForScope(commands, diagnostics, scopes, "environment")
|
|
4947
5039
|
}
|
|
@@ -4975,7 +5067,8 @@ var createWorkflowValidationRunReport = async ({
|
|
|
4975
5067
|
] : []);
|
|
4976
5068
|
const reportDiagnostics = [...diagnostics, ...commandDiagnostics];
|
|
4977
5069
|
const scopedDiagnostics = [...reportDiagnostics, ...baselineDiagnostics, ...workflowDiagnostics];
|
|
4978
|
-
const
|
|
5070
|
+
const knownBlockers = createKnownBlockers(results, scopedDiagnostics);
|
|
5071
|
+
const statuses = createValidationStatuses(results, reportDiagnostics, baselineDiagnostics, workflowDiagnostics);
|
|
4979
5072
|
return {
|
|
4980
5073
|
schemaVersion: 1,
|
|
4981
5074
|
runId,
|
|
@@ -4984,9 +5077,12 @@ var createWorkflowValidationRunReport = async ({
|
|
|
4984
5077
|
source,
|
|
4985
5078
|
status: statuses.overallStatus === "passed" ? "passed" : "failed",
|
|
4986
5079
|
...statuses,
|
|
4987
|
-
knownBlockers
|
|
5080
|
+
knownBlockers,
|
|
4988
5081
|
commands: results,
|
|
4989
5082
|
diagnostics: reportDiagnostics,
|
|
5083
|
+
baselineSummary: createWorkflowBaselineSummary(baselineDiagnostics, {
|
|
5084
|
+
knownBlockerCount: knownBlockers.filter((blocker) => blocker.failureScope === "workspace-config").length
|
|
5085
|
+
}),
|
|
4990
5086
|
baselineDiagnostics,
|
|
4991
5087
|
workflowDiagnostics,
|
|
4992
5088
|
repairActions: uniqueBy(repairActions, (action) => action.command),
|
|
@@ -5054,7 +5150,14 @@ var createRepairReport = ({
|
|
|
5054
5150
|
...syncedAt ? { syncedAt } : {}
|
|
5055
5151
|
});
|
|
5056
5152
|
// pkgs/@akanjs/devkit/workflow/executor.ts
|
|
5057
|
-
import
|
|
5153
|
+
import ts6 from "typescript";
|
|
5154
|
+
|
|
5155
|
+
// pkgs/@akanjs/devkit/workflow/moduleIndex.ts
|
|
5156
|
+
import { access } from "fs/promises";
|
|
5157
|
+
import path10 from "path";
|
|
5158
|
+
import ts5 from "typescript";
|
|
5159
|
+
|
|
5160
|
+
// pkgs/@akanjs/devkit/workflow/source.ts
|
|
5058
5161
|
import ts4 from "typescript";
|
|
5059
5162
|
|
|
5060
5163
|
// pkgs/@akanjs/devkit/workflow/primitive.ts
|
|
@@ -5107,7 +5210,7 @@ var sourceFile = (sys2, path10, action, reason) => ({
|
|
|
5107
5210
|
action,
|
|
5108
5211
|
reason
|
|
5109
5212
|
});
|
|
5110
|
-
var moduleComponentName = (moduleName) =>
|
|
5213
|
+
var moduleComponentName = (moduleName) => moduleName.replace(/[-_]+/g, " ").replace(/(?:^|\s+)([a-zA-Z0-9])/g, (_, char) => char.toUpperCase()).replace(/\s+/g, "");
|
|
5111
5214
|
var moduleSourcePaths = (moduleName) => {
|
|
5112
5215
|
const componentName = moduleComponentName(moduleName);
|
|
5113
5216
|
return {
|
|
@@ -5210,12 +5313,13 @@ var normalizeFieldType = (typeName) => {
|
|
|
5210
5313
|
var ensureBaseTypeImport = (content, typeName) => {
|
|
5211
5314
|
if (typeName !== "Int" && typeName !== "Float")
|
|
5212
5315
|
return content;
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
const baseImport = /import \{ ([^}]+) \} from "akanjs\/base";/.exec(content);
|
|
5316
|
+
const source = sourceFileFor("constant.ts", content);
|
|
5317
|
+
const baseImport = findNamedImport(source, "akanjs/base");
|
|
5216
5318
|
if (baseImport) {
|
|
5217
|
-
|
|
5218
|
-
|
|
5319
|
+
if (baseImport.names.includes(typeName))
|
|
5320
|
+
return content;
|
|
5321
|
+
const nextNames = [...baseImport.names, typeName].sort();
|
|
5322
|
+
return spliceText(content, baseImport.namedBindingsStart, baseImport.namedBindingsEnd, `{ ${nextNames.join(", ")} }`);
|
|
5219
5323
|
}
|
|
5220
5324
|
return `import { ${typeName} } from "akanjs/base";
|
|
5221
5325
|
${content}`;
|
|
@@ -5344,47 +5448,350 @@ var fieldExpression = (typeName, defaultValue, options = {}) => {
|
|
|
5344
5448
|
const defaultOption = defaultExpression ? `, { default: ${defaultExpression} }` : "";
|
|
5345
5449
|
return `${options.builderName ?? "field"}(${typeExpression}${defaultOption})`;
|
|
5346
5450
|
};
|
|
5347
|
-
var
|
|
5348
|
-
|
|
5349
|
-
|
|
5451
|
+
var fieldOrderingPriority = [
|
|
5452
|
+
"id",
|
|
5453
|
+
"name",
|
|
5454
|
+
"title",
|
|
5455
|
+
"status",
|
|
5456
|
+
"category",
|
|
5457
|
+
"description",
|
|
5458
|
+
"content",
|
|
5459
|
+
"startAt",
|
|
5460
|
+
"dueAt",
|
|
5461
|
+
"endAt",
|
|
5462
|
+
"createdAt",
|
|
5463
|
+
"updatedAt"
|
|
5464
|
+
];
|
|
5465
|
+
var sourceFileFor = (fileName, content, scriptKind = ts4.ScriptKind.TS) => ts4.createSourceFile(fileName, content, ts4.ScriptTarget.Latest, true, scriptKind);
|
|
5466
|
+
var hasParseDiagnostics = (source) => (source.parseDiagnostics ?? []).length > 0;
|
|
5467
|
+
var spliceText = (content, start, end, replacement) => `${content.slice(0, start)}${replacement}${content.slice(end)}`;
|
|
5468
|
+
var lineStartAt = (content, position) => content.lastIndexOf(`
|
|
5469
|
+
`, Math.max(0, position - 1)) + 1;
|
|
5470
|
+
var lineEndAt = (content, position) => {
|
|
5471
|
+
const end = content.indexOf(`
|
|
5472
|
+
`, position);
|
|
5473
|
+
return end < 0 ? content.length : end + 1;
|
|
5474
|
+
};
|
|
5475
|
+
var lineIndentAt = (content, position) => /^[ \t]*/.exec(content.slice(lineStartAt(content, position)))?.[0] ?? "";
|
|
5476
|
+
var nodeName = (node) => {
|
|
5477
|
+
if (!node)
|
|
5478
|
+
return null;
|
|
5479
|
+
if (ts4.isIdentifier(node) || ts4.isStringLiteral(node) || ts4.isNumericLiteral(node))
|
|
5480
|
+
return node.text;
|
|
5481
|
+
return null;
|
|
5482
|
+
};
|
|
5483
|
+
var propertyName = (node) => ts4.isPropertyAssignment(node) || ts4.isShorthandPropertyAssignment(node) || ts4.isMethodDeclaration(node) ? nodeName(node.name) : null;
|
|
5484
|
+
var expressionName = (expression) => {
|
|
5485
|
+
if (ts4.isIdentifier(expression))
|
|
5486
|
+
return expression.text;
|
|
5487
|
+
if (ts4.isPropertyAccessExpression(expression))
|
|
5488
|
+
return expression.name.text;
|
|
5489
|
+
if (ts4.isCallExpression(expression))
|
|
5490
|
+
return expressionName(expression.expression);
|
|
5491
|
+
if (ts4.isAsExpression(expression))
|
|
5492
|
+
return expressionName(expression.expression);
|
|
5493
|
+
return null;
|
|
5494
|
+
};
|
|
5495
|
+
var firstObjectReturnedByArrow = (node) => {
|
|
5496
|
+
if (!ts4.isArrowFunction(node) && !ts4.isFunctionExpression(node))
|
|
5497
|
+
return null;
|
|
5498
|
+
if (ts4.isObjectLiteralExpression(node.body))
|
|
5499
|
+
return node.body;
|
|
5500
|
+
if (ts4.isParenthesizedExpression(node.body) && ts4.isObjectLiteralExpression(node.body.expression)) {
|
|
5501
|
+
return node.body.expression;
|
|
5502
|
+
}
|
|
5503
|
+
if (!ts4.isBlock(node.body))
|
|
5504
|
+
return null;
|
|
5505
|
+
for (const statement of node.body.statements) {
|
|
5506
|
+
if (ts4.isReturnStatement(statement) && statement.expression && ts4.isObjectLiteralExpression(statement.expression)) {
|
|
5507
|
+
return statement.expression;
|
|
5508
|
+
}
|
|
5509
|
+
}
|
|
5510
|
+
return null;
|
|
5511
|
+
};
|
|
5512
|
+
var isViaCall = (expression) => ts4.isCallExpression(expression) && expressionName(expression.expression) === "via";
|
|
5513
|
+
var heritageCall = (node) => {
|
|
5514
|
+
const heritage = node.heritageClauses?.flatMap((clause) => [...clause.types]) ?? [];
|
|
5515
|
+
const expression = heritage.find((clause) => isViaCall(clause.expression))?.expression;
|
|
5516
|
+
return expression && ts4.isCallExpression(expression) ? expression : null;
|
|
5517
|
+
};
|
|
5518
|
+
var callExpressionName = (node) => ts4.isPropertyAccessExpression(node.expression) ? node.expression.name.text : expressionName(node.expression);
|
|
5519
|
+
var locatedObject = (source, objectLiteral) => ({
|
|
5520
|
+
objectStart: objectLiteral.getStart(source),
|
|
5521
|
+
objectEnd: objectLiteral.getEnd(),
|
|
5522
|
+
fields: objectLiteral.properties.map((property) => {
|
|
5523
|
+
const name = propertyName(property);
|
|
5524
|
+
if (!name)
|
|
5525
|
+
return null;
|
|
5526
|
+
return {
|
|
5527
|
+
name,
|
|
5528
|
+
start: property.getStart(source),
|
|
5529
|
+
fullStart: property.getFullStart(),
|
|
5530
|
+
end: property.getEnd()
|
|
5531
|
+
};
|
|
5532
|
+
}).filter((field) => field !== null)
|
|
5533
|
+
});
|
|
5534
|
+
var findConstantInputObject = (source, className) => {
|
|
5535
|
+
let locator = null;
|
|
5536
|
+
const visit = (node) => {
|
|
5537
|
+
if (locator)
|
|
5538
|
+
return;
|
|
5539
|
+
if (!ts4.isClassDeclaration(node) || node.name?.text !== className) {
|
|
5540
|
+
ts4.forEachChild(node, visit);
|
|
5541
|
+
return;
|
|
5542
|
+
}
|
|
5543
|
+
const viaCall = heritageCall(node);
|
|
5544
|
+
const callback = viaCall?.arguments.find((arg) => ts4.isArrowFunction(arg) || ts4.isFunctionExpression(arg));
|
|
5545
|
+
const objectLiteral = callback ? firstObjectReturnedByArrow(callback) : null;
|
|
5546
|
+
if (objectLiteral)
|
|
5547
|
+
locator = locatedObject(source, objectLiteral);
|
|
5548
|
+
};
|
|
5549
|
+
ts4.forEachChild(source, visit);
|
|
5550
|
+
return locator;
|
|
5551
|
+
};
|
|
5552
|
+
var chainMethodsForCall = (node) => {
|
|
5553
|
+
if (ts4.isAsExpression(node) || ts4.isParenthesizedExpression(node))
|
|
5554
|
+
return chainMethodsForCall(node.expression);
|
|
5555
|
+
if (!ts4.isCallExpression(node))
|
|
5556
|
+
return [];
|
|
5557
|
+
if (ts4.isPropertyAccessExpression(node.expression)) {
|
|
5558
|
+
return [...chainMethodsForCall(node.expression.expression), node.expression.name.text];
|
|
5559
|
+
}
|
|
5560
|
+
const name = expressionName(node.expression);
|
|
5561
|
+
return name ? [name] : [];
|
|
5562
|
+
};
|
|
5563
|
+
var outermostFluentCall = (node) => {
|
|
5564
|
+
let current = node;
|
|
5565
|
+
while (ts4.isPropertyAccessExpression(current.parent) && current.parent.expression === current && ts4.isCallExpression(current.parent.parent) && current.parent.parent.expression === current.parent) {
|
|
5566
|
+
current = current.parent.parent;
|
|
5567
|
+
}
|
|
5568
|
+
return current;
|
|
5569
|
+
};
|
|
5570
|
+
var protectedDictionaryChainOrder = ["model", "slice", "enum", "error", "translate"];
|
|
5571
|
+
var dictionaryChainOrderValid = (chainMethods) => {
|
|
5572
|
+
const protectedOrder = new Map(protectedDictionaryChainOrder.map((method, index) => [method, index]));
|
|
5573
|
+
let lastOrder = -1;
|
|
5574
|
+
for (const method of chainMethods) {
|
|
5575
|
+
const order = protectedOrder.get(method);
|
|
5576
|
+
if (order === undefined)
|
|
5577
|
+
continue;
|
|
5578
|
+
if (order < lastOrder)
|
|
5579
|
+
return false;
|
|
5580
|
+
lastOrder = order;
|
|
5581
|
+
}
|
|
5582
|
+
return true;
|
|
5583
|
+
};
|
|
5584
|
+
var findDictionaryModelObject = (source, moduleClassName) => {
|
|
5585
|
+
let locator = null;
|
|
5586
|
+
const visit = (node) => {
|
|
5587
|
+
if (locator)
|
|
5588
|
+
return;
|
|
5589
|
+
if (!ts4.isCallExpression(node) || callExpressionName(node) !== "model") {
|
|
5590
|
+
ts4.forEachChild(node, visit);
|
|
5591
|
+
return;
|
|
5592
|
+
}
|
|
5593
|
+
const typeArgument = node.typeArguments?.[0];
|
|
5594
|
+
if (!typeArgument || typeArgument.getText(source) !== moduleClassName) {
|
|
5595
|
+
ts4.forEachChild(node, visit);
|
|
5596
|
+
return;
|
|
5597
|
+
}
|
|
5598
|
+
const callback = node.arguments.find((arg) => ts4.isArrowFunction(arg) || ts4.isFunctionExpression(arg));
|
|
5599
|
+
const objectLiteral = callback ? firstObjectReturnedByArrow(callback) : null;
|
|
5600
|
+
if (objectLiteral) {
|
|
5601
|
+
locator = {
|
|
5602
|
+
...locatedObject(source, objectLiteral),
|
|
5603
|
+
chainMethods: chainMethodsForCall(outermostFluentCall(node))
|
|
5604
|
+
};
|
|
5605
|
+
}
|
|
5606
|
+
};
|
|
5607
|
+
ts4.forEachChild(source, visit);
|
|
5608
|
+
return locator;
|
|
5609
|
+
};
|
|
5610
|
+
var findLightProjectionArray = (source, moduleClassName) => {
|
|
5611
|
+
let locator = null;
|
|
5612
|
+
const visit = (node) => {
|
|
5613
|
+
if (locator)
|
|
5614
|
+
return;
|
|
5615
|
+
if (!ts4.isClassDeclaration(node) || node.name?.text !== `Light${moduleClassName}`) {
|
|
5616
|
+
ts4.forEachChild(node, visit);
|
|
5617
|
+
return;
|
|
5618
|
+
}
|
|
5619
|
+
const viaCall = heritageCall(node);
|
|
5620
|
+
const projectionArg = viaCall?.arguments.find((arg) => {
|
|
5621
|
+
const expression = ts4.isAsExpression(arg) ? arg.expression : arg;
|
|
5622
|
+
return ts4.isArrayLiteralExpression(expression);
|
|
5623
|
+
});
|
|
5624
|
+
const arrayLiteral = projectionArg ? ts4.isAsExpression(projectionArg) ? projectionArg.expression : projectionArg : null;
|
|
5625
|
+
if (!projectionArg || !arrayLiteral || !ts4.isArrayLiteralExpression(arrayLiteral))
|
|
5626
|
+
return;
|
|
5627
|
+
locator = {
|
|
5628
|
+
projectionStart: projectionArg.getStart(source),
|
|
5629
|
+
projectionEnd: projectionArg.getEnd(),
|
|
5630
|
+
fields: arrayLiteral.elements.map((element) => ts4.isStringLiteralLike(element) ? element.text : null).filter((field) => field !== null)
|
|
5631
|
+
};
|
|
5632
|
+
};
|
|
5633
|
+
ts4.forEachChild(source, visit);
|
|
5634
|
+
return locator;
|
|
5635
|
+
};
|
|
5636
|
+
var findNamedImport = (source, moduleSpecifier) => {
|
|
5637
|
+
for (const statement of source.statements) {
|
|
5638
|
+
if (!ts4.isImportDeclaration(statement) || !ts4.isStringLiteral(statement.moduleSpecifier))
|
|
5639
|
+
continue;
|
|
5640
|
+
if (statement.moduleSpecifier.text !== moduleSpecifier)
|
|
5641
|
+
continue;
|
|
5642
|
+
const namedBindings = statement.importClause?.namedBindings;
|
|
5643
|
+
if (!namedBindings || !ts4.isNamedImports(namedBindings))
|
|
5644
|
+
continue;
|
|
5645
|
+
return {
|
|
5646
|
+
names: namedBindings.elements.map((element) => element.name.text),
|
|
5647
|
+
namedBindingsStart: namedBindings.getStart(source),
|
|
5648
|
+
namedBindingsEnd: namedBindings.getEnd()
|
|
5649
|
+
};
|
|
5650
|
+
}
|
|
5651
|
+
return null;
|
|
5652
|
+
};
|
|
5653
|
+
var fieldExpressionBuilder = (property) => {
|
|
5654
|
+
if (!ts4.isPropertyAssignment(property))
|
|
5350
5655
|
return null;
|
|
5351
|
-
const
|
|
5352
|
-
|
|
5656
|
+
const initializer = ts4.isAsExpression(property.initializer) ? property.initializer.expression : property.initializer;
|
|
5657
|
+
if (!ts4.isCallExpression(initializer))
|
|
5658
|
+
return null;
|
|
5659
|
+
return expressionName(initializer.expression);
|
|
5660
|
+
};
|
|
5661
|
+
var priorityOf = (fieldName) => {
|
|
5662
|
+
const priority = fieldOrderingPriority.indexOf(fieldName);
|
|
5663
|
+
return priority < 0 ? null : priority;
|
|
5664
|
+
};
|
|
5665
|
+
var insertionIndexForFieldOrder = (fieldNames, newFieldName) => {
|
|
5666
|
+
const newPriority = priorityOf(newFieldName);
|
|
5667
|
+
if (newPriority !== null) {
|
|
5668
|
+
const greaterPriorityIndex = fieldNames.findIndex((name) => {
|
|
5669
|
+
const existingPriority = priorityOf(name);
|
|
5670
|
+
return existingPriority !== null && existingPriority > newPriority;
|
|
5671
|
+
});
|
|
5672
|
+
if (greaterPriorityIndex >= 0)
|
|
5673
|
+
return greaterPriorityIndex;
|
|
5674
|
+
const lastPriorityIndex = fieldNames.reduce((lastIndex, name, index) => {
|
|
5675
|
+
const existingPriority = priorityOf(name);
|
|
5676
|
+
return existingPriority !== null ? index : lastIndex;
|
|
5677
|
+
}, -1);
|
|
5678
|
+
return lastPriorityIndex + 1;
|
|
5679
|
+
}
|
|
5680
|
+
const lastNonPriorityIndex = fieldNames.reduce((lastIndex, name, index) => priorityOf(name) === null ? index : lastIndex, -1);
|
|
5681
|
+
return lastNonPriorityIndex >= 0 ? lastNonPriorityIndex + 1 : fieldNames.length;
|
|
5682
|
+
};
|
|
5683
|
+
var insertOrderedFieldLine = (content, locator, fieldName, line, options) => {
|
|
5684
|
+
if (locator.fields.some((field) => field.name === fieldName))
|
|
5685
|
+
return content;
|
|
5686
|
+
const insertIndex = insertionIndexForFieldOrder(locator.fields.map((field) => field.name), fieldName);
|
|
5687
|
+
const formattedLine = line.trim();
|
|
5688
|
+
if (locator.fields.length === 0) {
|
|
5689
|
+
return spliceText(content, locator.objectStart, locator.objectEnd, `{
|
|
5690
|
+
${options.fieldIndent}${formattedLine}
|
|
5691
|
+
${options.closingIndent}}`);
|
|
5692
|
+
}
|
|
5693
|
+
const beforeField = locator.fields[insertIndex];
|
|
5694
|
+
if (beforeField) {
|
|
5695
|
+
const leadingComments = ts4.getLeadingCommentRanges(content, beforeField.fullStart) ?? [];
|
|
5696
|
+
const insertAt2 = lineStartAt(content, leadingComments[0]?.pos ?? beforeField.start);
|
|
5697
|
+
const indent2 = lineIndentAt(content, beforeField.start) || options.fieldIndent;
|
|
5698
|
+
return spliceText(content, insertAt2, insertAt2, `${indent2}${formattedLine}
|
|
5699
|
+
`);
|
|
5700
|
+
}
|
|
5701
|
+
const afterField = locator.fields[locator.fields.length - 1];
|
|
5702
|
+
const insertAt = lineEndAt(content, afterField.end);
|
|
5703
|
+
const indent = lineIndentAt(content, afterField.start) || options.fieldIndent;
|
|
5704
|
+
return spliceText(content, insertAt, insertAt, `${indent}${formattedLine}
|
|
5705
|
+
`);
|
|
5706
|
+
};
|
|
5707
|
+
var viaBuilderParameterName = (content, className) => {
|
|
5708
|
+
const source = sourceFileFor("constant.ts", content);
|
|
5709
|
+
let builderName = null;
|
|
5710
|
+
const visit = (node) => {
|
|
5711
|
+
if (builderName !== null)
|
|
5712
|
+
return;
|
|
5713
|
+
if (!ts4.isClassDeclaration(node) || node.name?.text !== className) {
|
|
5714
|
+
ts4.forEachChild(node, visit);
|
|
5715
|
+
return;
|
|
5716
|
+
}
|
|
5717
|
+
const viaCall = heritageCall(node);
|
|
5718
|
+
const callback = viaCall?.arguments.find((arg) => ts4.isArrowFunction(arg) || ts4.isFunctionExpression(arg));
|
|
5719
|
+
if (callback && (ts4.isArrowFunction(callback) || ts4.isFunctionExpression(callback))) {
|
|
5720
|
+
builderName = nodeName(callback.parameters[0]?.name);
|
|
5721
|
+
}
|
|
5722
|
+
};
|
|
5723
|
+
ts4.forEachChild(source, visit);
|
|
5724
|
+
return builderName;
|
|
5725
|
+
};
|
|
5726
|
+
var inspectConstantStructure = (content, className, moduleClassName) => {
|
|
5727
|
+
const source = sourceFileFor("constant.ts", content);
|
|
5728
|
+
const inputObject = findConstantInputObject(source, className);
|
|
5729
|
+
const lightProjection = findLightProjectionArray(source, moduleClassName);
|
|
5730
|
+
const baseImport = findNamedImport(source, "akanjs/base");
|
|
5731
|
+
const fields = [];
|
|
5732
|
+
if (inputObject) {
|
|
5733
|
+
const visit = (node) => {
|
|
5734
|
+
if (!ts4.isClassDeclaration(node) || node.name?.text !== className) {
|
|
5735
|
+
ts4.forEachChild(node, visit);
|
|
5736
|
+
return;
|
|
5737
|
+
}
|
|
5738
|
+
const viaCall = heritageCall(node);
|
|
5739
|
+
const callback = viaCall?.arguments.find((arg) => ts4.isArrowFunction(arg) || ts4.isFunctionExpression(arg));
|
|
5740
|
+
const objectLiteral = callback ? firstObjectReturnedByArrow(callback) : null;
|
|
5741
|
+
if (!objectLiteral)
|
|
5742
|
+
return;
|
|
5743
|
+
fields.push(...objectLiteral.properties.map((property) => {
|
|
5744
|
+
const name = propertyName(property);
|
|
5745
|
+
if (!name)
|
|
5746
|
+
return null;
|
|
5747
|
+
return { name, expressionBuilder: fieldExpressionBuilder(property) };
|
|
5748
|
+
}).filter((field) => field !== null));
|
|
5749
|
+
};
|
|
5750
|
+
ts4.forEachChild(source, visit);
|
|
5751
|
+
}
|
|
5752
|
+
return {
|
|
5753
|
+
parseValid: !hasParseDiagnostics(source),
|
|
5754
|
+
inputObjectFound: inputObject !== null,
|
|
5755
|
+
builderName: viaBuilderParameterName(content, className),
|
|
5756
|
+
fields,
|
|
5757
|
+
lightProjectionFields: lightProjection?.fields ?? [],
|
|
5758
|
+
baseImports: baseImport?.names ?? []
|
|
5759
|
+
};
|
|
5760
|
+
};
|
|
5761
|
+
var inspectDictionaryStructure = (content, moduleClassName) => {
|
|
5762
|
+
const source = sourceFileFor("dictionary.ts", content);
|
|
5763
|
+
const modelObject = findDictionaryModelObject(source, moduleClassName);
|
|
5764
|
+
return {
|
|
5765
|
+
parseValid: !hasParseDiagnostics(source),
|
|
5766
|
+
modelObjectFound: modelObject !== null,
|
|
5767
|
+
chainOrderValid: modelObject ? dictionaryChainOrderValid(modelObject.chainMethods) : false,
|
|
5768
|
+
chainMethods: modelObject?.chainMethods ?? [],
|
|
5769
|
+
fields: modelObject?.fields.map((field) => field.name) ?? []
|
|
5770
|
+
};
|
|
5353
5771
|
};
|
|
5354
5772
|
var insertIntoObject = (content, className, line) => {
|
|
5355
|
-
const
|
|
5356
|
-
if (
|
|
5773
|
+
const fieldName = /^([A-Za-z_$][\w$]*)\s*:/.exec(line.trim())?.[1];
|
|
5774
|
+
if (!fieldName)
|
|
5357
5775
|
return null;
|
|
5358
|
-
const
|
|
5359
|
-
|
|
5776
|
+
const source = sourceFileFor("constant.ts", content);
|
|
5777
|
+
const locator = findConstantInputObject(source, className);
|
|
5778
|
+
if (!locator)
|
|
5360
5779
|
return null;
|
|
5361
|
-
|
|
5362
|
-
const suffix = content.slice(objectEndIndex);
|
|
5363
|
-
const insertion = prefix.endsWith(`
|
|
5364
|
-
`) ? ` ${line}
|
|
5365
|
-
` : `
|
|
5366
|
-
${line}
|
|
5367
|
-
`;
|
|
5368
|
-
return `${prefix}${insertion}${suffix}`;
|
|
5780
|
+
return insertOrderedFieldLine(content, locator, fieldName, line, { fieldIndent: " ", closingIndent: "" });
|
|
5369
5781
|
};
|
|
5370
5782
|
var insertLightProjectionField = (content, moduleClassName, fieldName) => {
|
|
5371
|
-
const
|
|
5372
|
-
|
|
5783
|
+
const source = sourceFileFor("constant.ts", content);
|
|
5784
|
+
const locator = findLightProjectionArray(source, moduleClassName);
|
|
5785
|
+
if (!locator)
|
|
5373
5786
|
return null;
|
|
5374
|
-
|
|
5375
|
-
if (!arrayMatch || arrayMatch.index === undefined)
|
|
5376
|
-
return null;
|
|
5377
|
-
const arrayStart = classIndex + arrayMatch.index;
|
|
5378
|
-
const arrayEnd = arrayStart + arrayMatch[0].length;
|
|
5379
|
-
const fields = [...arrayMatch[1].matchAll(/"([^"]+)"/g)].map((match) => match[1]).filter(Boolean);
|
|
5380
|
-
if (fields.includes(fieldName))
|
|
5787
|
+
if (locator.fields.includes(fieldName))
|
|
5381
5788
|
return content;
|
|
5382
|
-
const nextFields = [...fields, fieldName];
|
|
5789
|
+
const nextFields = [...locator.fields, fieldName];
|
|
5383
5790
|
const nextArray = nextFields.length === 0 ? "[] as const" : `[
|
|
5384
5791
|
${nextFields.map((field) => ` ${JSON.stringify(field)},`).join(`
|
|
5385
5792
|
`)}
|
|
5386
5793
|
] as const`;
|
|
5387
|
-
return
|
|
5794
|
+
return spliceText(content, locator.projectionStart, locator.projectionEnd, nextArray);
|
|
5388
5795
|
};
|
|
5389
5796
|
var insertTemplateField = ({
|
|
5390
5797
|
content,
|
|
@@ -5437,69 +5844,32 @@ ${values.map((value) => ` ${JSON.stringify(value)},`).join(`
|
|
|
5437
5844
|
${enumClass}`;
|
|
5438
5845
|
return `${content.slice(0, firstClassIndex)}${enumClass}${content.slice(firstClassIndex)}`;
|
|
5439
5846
|
};
|
|
5440
|
-
var findMatchingBrace = (content, openIndex) => {
|
|
5441
|
-
let depth = 0;
|
|
5442
|
-
let quote = null;
|
|
5443
|
-
let escaped = false;
|
|
5444
|
-
for (let index = openIndex;index < content.length; index++) {
|
|
5445
|
-
const char = content[index];
|
|
5446
|
-
if (quote) {
|
|
5447
|
-
if (escaped) {
|
|
5448
|
-
escaped = false;
|
|
5449
|
-
continue;
|
|
5450
|
-
}
|
|
5451
|
-
if (char === "\\") {
|
|
5452
|
-
escaped = true;
|
|
5453
|
-
continue;
|
|
5454
|
-
}
|
|
5455
|
-
if (char === quote)
|
|
5456
|
-
quote = null;
|
|
5457
|
-
continue;
|
|
5458
|
-
}
|
|
5459
|
-
if (char === '"' || char === "'" || char === "`") {
|
|
5460
|
-
quote = char;
|
|
5461
|
-
continue;
|
|
5462
|
-
}
|
|
5463
|
-
if (char === "{")
|
|
5464
|
-
depth += 1;
|
|
5465
|
-
if (char === "}") {
|
|
5466
|
-
depth -= 1;
|
|
5467
|
-
if (depth === 0)
|
|
5468
|
-
return index;
|
|
5469
|
-
}
|
|
5470
|
-
}
|
|
5471
|
-
return -1;
|
|
5472
|
-
};
|
|
5473
5847
|
var dictionaryModelFieldLine = (fieldName) => {
|
|
5474
5848
|
const label = bilingualLabelForField(fieldName);
|
|
5475
5849
|
const desc = bilingualDescriptionForField(fieldName);
|
|
5476
5850
|
return `${fieldName}: t([${JSON.stringify(label.en)}, ${JSON.stringify(label.ko)}]).desc([${JSON.stringify(desc.en)}, ${JSON.stringify(desc.ko)}]),`;
|
|
5477
5851
|
};
|
|
5478
5852
|
var insertDictionaryModelField = (content, moduleClassName, fieldName) => {
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
if (modelIndex < 0)
|
|
5853
|
+
const source = sourceFileFor("dictionary.ts", content);
|
|
5854
|
+
const locator = findDictionaryModelObject(source, moduleClassName);
|
|
5855
|
+
if (!locator)
|
|
5483
5856
|
return null;
|
|
5484
|
-
|
|
5485
|
-
|
|
5486
|
-
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
const
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
${fieldLine}
|
|
5501
|
-
`;
|
|
5502
|
-
return `${content.slice(0, objectEndIndex)}${insertion}${content.slice(objectEndIndex)}`;
|
|
5857
|
+
return insertOrderedFieldLine(content, locator, fieldName, dictionaryModelFieldLine(fieldName), {
|
|
5858
|
+
fieldIndent: " ",
|
|
5859
|
+
closingIndent: " "
|
|
5860
|
+
});
|
|
5861
|
+
};
|
|
5862
|
+
var hasConstantInputField = (content, className, fieldName) => {
|
|
5863
|
+
const source = sourceFileFor("constant.ts", content);
|
|
5864
|
+
if (hasParseDiagnostics(source))
|
|
5865
|
+
return false;
|
|
5866
|
+
return findConstantInputObject(source, className)?.fields.some((field) => field.name === fieldName) ?? false;
|
|
5867
|
+
};
|
|
5868
|
+
var hasDictionaryModelField = (content, moduleClassName, fieldName) => {
|
|
5869
|
+
const source = sourceFileFor("dictionary.ts", content);
|
|
5870
|
+
if (hasParseDiagnostics(source))
|
|
5871
|
+
return false;
|
|
5872
|
+
return findDictionaryModelObject(source, moduleClassName)?.fields.some((field) => field.name === fieldName) ?? false;
|
|
5503
5873
|
};
|
|
5504
5874
|
var ensureConstantTypeImport = (content, constantPath, typeName) => {
|
|
5505
5875
|
if (new RegExp(`import type \\{[^}]*\\b${typeName}\\b[^}]*\\} from "${constantPath}";`).test(content))
|
|
@@ -5529,6 +5899,401 @@ ${values.map((value) => ` ${value}: t([${JSON.stringify(titleize(value))}, ${
|
|
|
5529
5899
|
};
|
|
5530
5900
|
var parseValues = (value) => value?.split(",").map((item) => item.trim()).filter(Boolean) ?? [];
|
|
5531
5901
|
|
|
5902
|
+
// pkgs/@akanjs/devkit/workflow/moduleIndex.ts
|
|
5903
|
+
var indexFileKinds = [
|
|
5904
|
+
"abstract",
|
|
5905
|
+
"constant",
|
|
5906
|
+
"dictionary",
|
|
5907
|
+
"service",
|
|
5908
|
+
"signal",
|
|
5909
|
+
"store",
|
|
5910
|
+
"template",
|
|
5911
|
+
"unit",
|
|
5912
|
+
"util",
|
|
5913
|
+
"view",
|
|
5914
|
+
"zone"
|
|
5915
|
+
];
|
|
5916
|
+
var sourceText = async (filePath) => {
|
|
5917
|
+
try {
|
|
5918
|
+
return await Bun.file(filePath).text();
|
|
5919
|
+
} catch {
|
|
5920
|
+
return null;
|
|
5921
|
+
}
|
|
5922
|
+
};
|
|
5923
|
+
var fileExists = async (filePath) => {
|
|
5924
|
+
try {
|
|
5925
|
+
await access(filePath);
|
|
5926
|
+
return true;
|
|
5927
|
+
} catch {
|
|
5928
|
+
return false;
|
|
5929
|
+
}
|
|
5930
|
+
};
|
|
5931
|
+
var sourceFileFor2 = (filePath, content) => ts5.createSourceFile(filePath, content, ts5.ScriptTarget.Latest, true, ts5.ScriptKind.TS);
|
|
5932
|
+
var parseDiagnosticsFor = (source, filePath) => {
|
|
5933
|
+
const parseDiagnostics = source.parseDiagnostics ?? [];
|
|
5934
|
+
return parseDiagnostics.map((diagnostic) => ({
|
|
5935
|
+
severity: "error",
|
|
5936
|
+
code: "module-index-typescript-parse-error",
|
|
5937
|
+
message: `TypeScript parse diagnostic TS${diagnostic.code} in ${filePath}: ${ts5.flattenDiagnosticMessageText(diagnostic.messageText, `
|
|
5938
|
+
`)}`,
|
|
5939
|
+
context: { target: filePath, paths: [filePath] }
|
|
5940
|
+
}));
|
|
5941
|
+
};
|
|
5942
|
+
var spanFor = (source, file, node) => {
|
|
5943
|
+
const startOffset = node.getStart(source);
|
|
5944
|
+
const endOffset = node.getEnd();
|
|
5945
|
+
const start = source.getLineAndCharacterOfPosition(startOffset);
|
|
5946
|
+
const end = source.getLineAndCharacterOfPosition(endOffset);
|
|
5947
|
+
return {
|
|
5948
|
+
file,
|
|
5949
|
+
startLine: start.line + 1,
|
|
5950
|
+
endLine: end.line + 1,
|
|
5951
|
+
startOffset,
|
|
5952
|
+
endOffset
|
|
5953
|
+
};
|
|
5954
|
+
};
|
|
5955
|
+
var nodeName2 = (node) => {
|
|
5956
|
+
if (!node)
|
|
5957
|
+
return null;
|
|
5958
|
+
if (ts5.isIdentifier(node) || ts5.isStringLiteral(node) || ts5.isNumericLiteral(node))
|
|
5959
|
+
return node.text;
|
|
5960
|
+
return null;
|
|
5961
|
+
};
|
|
5962
|
+
var propertyName2 = (node) => ts5.isPropertyAssignment(node) || ts5.isShorthandPropertyAssignment(node) || ts5.isMethodDeclaration(node) ? nodeName2(node.name) : null;
|
|
5963
|
+
var expressionName2 = (expression) => {
|
|
5964
|
+
if (ts5.isIdentifier(expression))
|
|
5965
|
+
return expression.text;
|
|
5966
|
+
if (ts5.isPropertyAccessExpression(expression))
|
|
5967
|
+
return expression.name.text;
|
|
5968
|
+
if (ts5.isCallExpression(expression))
|
|
5969
|
+
return expressionName2(expression.expression);
|
|
5970
|
+
if (ts5.isAsExpression(expression))
|
|
5971
|
+
return expressionName2(expression.expression);
|
|
5972
|
+
return null;
|
|
5973
|
+
};
|
|
5974
|
+
var expressionSummary = (expression) => {
|
|
5975
|
+
if (ts5.isAsExpression(expression))
|
|
5976
|
+
return expressionSummary(expression.expression);
|
|
5977
|
+
if (ts5.isIdentifier(expression) || ts5.isPropertyAccessExpression(expression))
|
|
5978
|
+
return expressionName2(expression) ?? "expression";
|
|
5979
|
+
if (ts5.isArrayLiteralExpression(expression))
|
|
5980
|
+
return "array-literal";
|
|
5981
|
+
if (ts5.isObjectLiteralExpression(expression))
|
|
5982
|
+
return "object-literal";
|
|
5983
|
+
if (ts5.isStringLiteralLike(expression))
|
|
5984
|
+
return "string-literal";
|
|
5985
|
+
if (ts5.isNumericLiteral(expression))
|
|
5986
|
+
return "numeric-literal";
|
|
5987
|
+
if (expression.kind === ts5.SyntaxKind.TrueKeyword || expression.kind === ts5.SyntaxKind.FalseKeyword) {
|
|
5988
|
+
return "boolean-literal";
|
|
5989
|
+
}
|
|
5990
|
+
if (ts5.isCallExpression(expression)) {
|
|
5991
|
+
const callee = expressionName2(expression.expression);
|
|
5992
|
+
return callee ? `${callee}(...)` : "call-expression";
|
|
5993
|
+
}
|
|
5994
|
+
return ts5.SyntaxKind[expression.kind] ?? "expression";
|
|
5995
|
+
};
|
|
5996
|
+
var typeSummaryForInitializer = (initializer) => {
|
|
5997
|
+
if (!initializer)
|
|
5998
|
+
return;
|
|
5999
|
+
const expression = ts5.isAsExpression(initializer) ? initializer.expression : initializer;
|
|
6000
|
+
if (!ts5.isCallExpression(expression))
|
|
6001
|
+
return expressionSummary(expression);
|
|
6002
|
+
const callee = expressionName2(expression.expression);
|
|
6003
|
+
const firstArg = expression.arguments[0];
|
|
6004
|
+
const argSummary = firstArg ? expressionSummary(firstArg) : "";
|
|
6005
|
+
return [callee, argSummary ? `(${argSummary})` : ""].filter(Boolean).join("");
|
|
6006
|
+
};
|
|
6007
|
+
var fieldsFromObject = (source, file, objectLiteral, kind) => objectLiteral.properties.map((property, index) => {
|
|
6008
|
+
const name = propertyName2(property);
|
|
6009
|
+
if (!name)
|
|
6010
|
+
return null;
|
|
6011
|
+
const initializer = ts5.isPropertyAssignment(property) ? property.initializer : undefined;
|
|
6012
|
+
return {
|
|
6013
|
+
name,
|
|
6014
|
+
kind,
|
|
6015
|
+
order: index,
|
|
6016
|
+
...initializer ? { typeSummary: typeSummaryForInitializer(initializer) } : {},
|
|
6017
|
+
sourceSpan: spanFor(source, file, property)
|
|
6018
|
+
};
|
|
6019
|
+
}).filter((field) => field !== null);
|
|
6020
|
+
var firstObjectReturnedByArrow2 = (node) => {
|
|
6021
|
+
if (!ts5.isArrowFunction(node) && !ts5.isFunctionExpression(node))
|
|
6022
|
+
return null;
|
|
6023
|
+
if (ts5.isObjectLiteralExpression(node.body))
|
|
6024
|
+
return node.body;
|
|
6025
|
+
if (ts5.isParenthesizedExpression(node.body) && ts5.isObjectLiteralExpression(node.body.expression)) {
|
|
6026
|
+
return node.body.expression;
|
|
6027
|
+
}
|
|
6028
|
+
if (!ts5.isBlock(node.body))
|
|
6029
|
+
return null;
|
|
6030
|
+
for (const statement of node.body.statements) {
|
|
6031
|
+
if (ts5.isReturnStatement(statement) && statement.expression && ts5.isObjectLiteralExpression(statement.expression)) {
|
|
6032
|
+
return statement.expression;
|
|
6033
|
+
}
|
|
6034
|
+
}
|
|
6035
|
+
return null;
|
|
6036
|
+
};
|
|
6037
|
+
var isViaCall2 = (expression) => ts5.isCallExpression(expression) && expressionName2(expression.expression) === "via";
|
|
6038
|
+
var heritageCall2 = (node) => {
|
|
6039
|
+
const heritage = node.heritageClauses?.flatMap((clause) => [...clause.types]) ?? [];
|
|
6040
|
+
const expression = heritage.find((clause) => isViaCall2(clause.expression))?.expression;
|
|
6041
|
+
return expression && ts5.isCallExpression(expression) ? expression : null;
|
|
6042
|
+
};
|
|
6043
|
+
var parseConstantIndex = (filePath, content, moduleClassName) => {
|
|
6044
|
+
const source = sourceFileFor2(filePath, content);
|
|
6045
|
+
const diagnostics = parseDiagnosticsFor(source, filePath);
|
|
6046
|
+
const inputClassName = `${moduleClassName}Input`;
|
|
6047
|
+
let inputClass = null;
|
|
6048
|
+
let inputViaFound = false;
|
|
6049
|
+
let inputBuilderFound = false;
|
|
6050
|
+
let inputBuilderObjectFound = false;
|
|
6051
|
+
let builderName = null;
|
|
6052
|
+
let fields = [];
|
|
6053
|
+
let lightProjection;
|
|
6054
|
+
const visit = (node) => {
|
|
6055
|
+
if (!ts5.isClassDeclaration(node) || !node.name) {
|
|
6056
|
+
ts5.forEachChild(node, visit);
|
|
6057
|
+
return;
|
|
6058
|
+
}
|
|
6059
|
+
const className = node.name.text;
|
|
6060
|
+
const viaCall = heritageCall2(node);
|
|
6061
|
+
if (className === inputClassName) {
|
|
6062
|
+
inputClass = node;
|
|
6063
|
+
if (!viaCall)
|
|
6064
|
+
return;
|
|
6065
|
+
inputViaFound = true;
|
|
6066
|
+
const callback = viaCall.arguments.find((arg) => ts5.isArrowFunction(arg) || ts5.isFunctionExpression(arg));
|
|
6067
|
+
if (callback && (ts5.isArrowFunction(callback) || ts5.isFunctionExpression(callback))) {
|
|
6068
|
+
inputBuilderFound = true;
|
|
6069
|
+
builderName = nodeName2(callback.parameters[0]?.name) ?? null;
|
|
6070
|
+
const objectLiteral = firstObjectReturnedByArrow2(callback);
|
|
6071
|
+
if (objectLiteral) {
|
|
6072
|
+
inputBuilderObjectFound = true;
|
|
6073
|
+
fields = fieldsFromObject(source, filePath, objectLiteral, "constant");
|
|
6074
|
+
}
|
|
6075
|
+
}
|
|
6076
|
+
}
|
|
6077
|
+
if (!viaCall)
|
|
6078
|
+
return;
|
|
6079
|
+
if (className === `Light${moduleClassName}`) {
|
|
6080
|
+
const projectionArg = viaCall.arguments.find((arg) => {
|
|
6081
|
+
const expression = ts5.isAsExpression(arg) ? arg.expression : arg;
|
|
6082
|
+
return ts5.isArrayLiteralExpression(expression);
|
|
6083
|
+
});
|
|
6084
|
+
const arrayLiteral = projectionArg ? ts5.isAsExpression(projectionArg) ? projectionArg.expression : projectionArg : null;
|
|
6085
|
+
if (arrayLiteral && ts5.isArrayLiteralExpression(arrayLiteral)) {
|
|
6086
|
+
lightProjection = {
|
|
6087
|
+
className,
|
|
6088
|
+
sourceSpan: spanFor(source, filePath, arrayLiteral),
|
|
6089
|
+
fields: arrayLiteral.elements.map((element, order) => ts5.isStringLiteralLike(element) ? {
|
|
6090
|
+
name: element.text,
|
|
6091
|
+
kind: "lightProjection",
|
|
6092
|
+
order,
|
|
6093
|
+
typeSummary: "string-literal",
|
|
6094
|
+
sourceSpan: spanFor(source, filePath, element)
|
|
6095
|
+
} : null).filter((field) => field !== null)
|
|
6096
|
+
};
|
|
6097
|
+
}
|
|
6098
|
+
}
|
|
6099
|
+
};
|
|
6100
|
+
ts5.forEachChild(source, visit);
|
|
6101
|
+
if (!inputClass) {
|
|
6102
|
+
diagnostics.push({
|
|
6103
|
+
severity: "error",
|
|
6104
|
+
code: "module-index-constant-input-missing",
|
|
6105
|
+
message: `Constant input class ${inputClassName} was not found in ${filePath}.`,
|
|
6106
|
+
context: { target: inputClassName, paths: [filePath] }
|
|
6107
|
+
});
|
|
6108
|
+
} else if (!inputViaFound) {
|
|
6109
|
+
diagnostics.push({
|
|
6110
|
+
severity: "error",
|
|
6111
|
+
code: "module-index-constant-via-missing",
|
|
6112
|
+
message: `Constant input class ${inputClassName} does not extend via(...) in ${filePath}.`,
|
|
6113
|
+
context: { target: inputClassName, paths: [filePath] }
|
|
6114
|
+
});
|
|
6115
|
+
} else if (!inputBuilderFound) {
|
|
6116
|
+
diagnostics.push({
|
|
6117
|
+
severity: "error",
|
|
6118
|
+
code: "module-index-constant-builder-missing",
|
|
6119
|
+
message: `Constant input class ${inputClassName} does not provide a via(...) builder callback in ${filePath}.`,
|
|
6120
|
+
context: { target: inputClassName, paths: [filePath] }
|
|
6121
|
+
});
|
|
6122
|
+
} else if (!inputBuilderObjectFound) {
|
|
6123
|
+
diagnostics.push({
|
|
6124
|
+
severity: "error",
|
|
6125
|
+
code: "module-index-constant-builder-object-missing",
|
|
6126
|
+
message: `Constant input class ${inputClassName} builder does not return an object literal in ${filePath}.`,
|
|
6127
|
+
context: { target: inputClassName, paths: [filePath] }
|
|
6128
|
+
});
|
|
6129
|
+
}
|
|
6130
|
+
return {
|
|
6131
|
+
index: {
|
|
6132
|
+
path: filePath,
|
|
6133
|
+
inputClassName,
|
|
6134
|
+
builderName,
|
|
6135
|
+
fields,
|
|
6136
|
+
...lightProjection ? { lightProjection } : {},
|
|
6137
|
+
...inputClass ? { sourceSpan: spanFor(source, filePath, inputClass) } : {}
|
|
6138
|
+
},
|
|
6139
|
+
diagnostics
|
|
6140
|
+
};
|
|
6141
|
+
};
|
|
6142
|
+
var callExpressionName2 = (node) => ts5.isPropertyAccessExpression(node.expression) ? node.expression.name.text : expressionName2(node.expression);
|
|
6143
|
+
var parseDictionaryIndex = (filePath, content, moduleClassName) => {
|
|
6144
|
+
const source = sourceFileFor2(filePath, content);
|
|
6145
|
+
const diagnostics = parseDiagnosticsFor(source, filePath);
|
|
6146
|
+
let index;
|
|
6147
|
+
let modelFound = false;
|
|
6148
|
+
const visit = (node) => {
|
|
6149
|
+
if (modelFound || !ts5.isCallExpression(node)) {
|
|
6150
|
+
ts5.forEachChild(node, visit);
|
|
6151
|
+
return;
|
|
6152
|
+
}
|
|
6153
|
+
if (callExpressionName2(node) !== "model") {
|
|
6154
|
+
ts5.forEachChild(node, visit);
|
|
6155
|
+
return;
|
|
6156
|
+
}
|
|
6157
|
+
const typeArgument = node.typeArguments?.[0];
|
|
6158
|
+
if (!typeArgument || typeArgument.getText(source) !== moduleClassName) {
|
|
6159
|
+
ts5.forEachChild(node, visit);
|
|
6160
|
+
return;
|
|
6161
|
+
}
|
|
6162
|
+
modelFound = true;
|
|
6163
|
+
const callback = node.arguments.find((arg) => ts5.isArrowFunction(arg) || ts5.isFunctionExpression(arg));
|
|
6164
|
+
if (!callback || !ts5.isArrowFunction(callback) && !ts5.isFunctionExpression(callback)) {
|
|
6165
|
+
diagnostics.push({
|
|
6166
|
+
severity: "error",
|
|
6167
|
+
code: "module-index-dictionary-builder-missing",
|
|
6168
|
+
message: `Dictionary .model<${moduleClassName}> branch does not provide a builder callback in ${filePath}.`,
|
|
6169
|
+
context: { target: moduleClassName, paths: [filePath] }
|
|
6170
|
+
});
|
|
6171
|
+
return;
|
|
6172
|
+
}
|
|
6173
|
+
const objectLiteral = firstObjectReturnedByArrow2(callback);
|
|
6174
|
+
if (!objectLiteral) {
|
|
6175
|
+
diagnostics.push({
|
|
6176
|
+
severity: "error",
|
|
6177
|
+
code: "module-index-dictionary-builder-object-missing",
|
|
6178
|
+
message: `Dictionary .model<${moduleClassName}> builder does not return an object literal in ${filePath}.`,
|
|
6179
|
+
context: { target: moduleClassName, paths: [filePath] }
|
|
6180
|
+
});
|
|
6181
|
+
}
|
|
6182
|
+
index = {
|
|
6183
|
+
path: filePath,
|
|
6184
|
+
modelClassName: moduleClassName,
|
|
6185
|
+
translatorName: nodeName2(callback.parameters[0]?.name),
|
|
6186
|
+
fields: objectLiteral ? fieldsFromObject(source, filePath, objectLiteral, "dictionary") : [],
|
|
6187
|
+
sourceSpan: spanFor(source, filePath, node)
|
|
6188
|
+
};
|
|
6189
|
+
};
|
|
6190
|
+
ts5.forEachChild(source, visit);
|
|
6191
|
+
return { index, diagnostics, modelFound };
|
|
6192
|
+
};
|
|
6193
|
+
var expectedFilesFor = (module) => {
|
|
6194
|
+
const paths = moduleSourcePaths(module.name);
|
|
6195
|
+
return indexFileKinds.map((kind) => {
|
|
6196
|
+
const expectedModulePath = paths[kind];
|
|
6197
|
+
const expectedFilename = path10.basename(expectedModulePath);
|
|
6198
|
+
const actualFilename = module.files.find((file) => file === expectedFilename) ?? module.files.find((file) => file.toLowerCase() === expectedFilename.toLowerCase());
|
|
6199
|
+
const present = actualFilename !== undefined;
|
|
6200
|
+
const casing = !present ? "missing" : actualFilename === expectedFilename ? "match" : "mismatch";
|
|
6201
|
+
return {
|
|
6202
|
+
kind,
|
|
6203
|
+
path: `${module.path}/${actualFilename ?? expectedFilename}`,
|
|
6204
|
+
expectedPath: `${module.path}/${expectedFilename}`,
|
|
6205
|
+
filename: actualFilename ?? expectedFilename,
|
|
6206
|
+
expectedFilename,
|
|
6207
|
+
present,
|
|
6208
|
+
casing
|
|
6209
|
+
};
|
|
6210
|
+
});
|
|
6211
|
+
};
|
|
6212
|
+
var diagnosticsForFiles = (files) => files.flatMap((file) => {
|
|
6213
|
+
if (file.kind !== "constant" && file.kind !== "dictionary")
|
|
6214
|
+
return [];
|
|
6215
|
+
if (file.casing === "match")
|
|
6216
|
+
return [];
|
|
6217
|
+
return [
|
|
6218
|
+
{
|
|
6219
|
+
severity: "error",
|
|
6220
|
+
code: file.casing === "missing" ? "module-index-file-missing" : "module-index-file-casing-mismatch",
|
|
6221
|
+
message: file.casing === "missing" ? `Expected ${file.kind} file is missing: ${file.expectedPath}.` : `Expected ${file.expectedPath}, but found ${file.path}.`,
|
|
6222
|
+
context: { target: file.expectedPath, paths: [file.path, file.expectedPath] }
|
|
6223
|
+
}
|
|
6224
|
+
];
|
|
6225
|
+
});
|
|
6226
|
+
var fieldPresence = (requestedField, constantFields, dictionaryFields, lightFields) => {
|
|
6227
|
+
const names = new Set([
|
|
6228
|
+
...constantFields.map((field) => field.name),
|
|
6229
|
+
...dictionaryFields.map((field) => field.name),
|
|
6230
|
+
...lightFields.map((field) => field.name),
|
|
6231
|
+
...requestedField ? [requestedField] : []
|
|
6232
|
+
]);
|
|
6233
|
+
return [...names].sort().map((name) => ({
|
|
6234
|
+
name,
|
|
6235
|
+
requested: requestedField === name,
|
|
6236
|
+
constant: constantFields.some((field) => field.name === name),
|
|
6237
|
+
dictionary: dictionaryFields.some((field) => field.name === name),
|
|
6238
|
+
lightProjection: lightFields.some((field) => field.name === name)
|
|
6239
|
+
}));
|
|
6240
|
+
};
|
|
6241
|
+
var partialPresenceDiagnostics = (presence, module) => presence.filter((field) => field.constant !== field.dictionary || field.lightProjection && (!field.constant || !field.dictionary)).map((field) => ({
|
|
6242
|
+
severity: "warning",
|
|
6243
|
+
code: "module-index-field-presence-partial",
|
|
6244
|
+
message: `${module.sysName}:${module.name}.${field.name} presence differs across constant, dictionary, and lightProjection.`,
|
|
6245
|
+
context: {
|
|
6246
|
+
target: `${module.sysName}:${module.name}.${field.name}`,
|
|
6247
|
+
paths: [`${module.path}/${module.name}.constant.ts`, `${module.path}/${module.name}.dictionary.ts`]
|
|
6248
|
+
}
|
|
6249
|
+
}));
|
|
6250
|
+
var buildAkanModuleContextIndex = async (workspace, module, options = {}) => {
|
|
6251
|
+
const files = expectedFilesFor(module);
|
|
6252
|
+
const diagnostics = diagnosticsForFiles(files);
|
|
6253
|
+
const moduleClassName = moduleComponentName(module.name);
|
|
6254
|
+
const constantFile = files.find((file) => file.kind === "constant");
|
|
6255
|
+
const dictionaryFile = files.find((file) => file.kind === "dictionary");
|
|
6256
|
+
const constantContent = constantFile?.present && constantFile.casing === "match" ? await sourceText(path10.join(workspace.workspaceRoot, constantFile.path)) : null;
|
|
6257
|
+
const dictionaryContent = dictionaryFile?.present && dictionaryFile.casing === "match" ? await sourceText(path10.join(workspace.workspaceRoot, dictionaryFile.path)) : null;
|
|
6258
|
+
const parsedConstant = constantFile && constantContent ? parseConstantIndex(constantFile.path, constantContent, moduleClassName) : undefined;
|
|
6259
|
+
const constant = parsedConstant?.index;
|
|
6260
|
+
const parsedDictionary = dictionaryFile && dictionaryContent ? parseDictionaryIndex(dictionaryFile.path, dictionaryContent, moduleClassName) : undefined;
|
|
6261
|
+
const dictionary = parsedDictionary?.index;
|
|
6262
|
+
const presence = fieldPresence(options.field, constant?.fields ?? [], dictionary?.fields ?? [], constant?.lightProjection?.fields ?? []);
|
|
6263
|
+
if (constantFile?.present && constantFile.casing === "match" && !await fileExists(path10.join(workspace.workspaceRoot, constantFile.path))) {
|
|
6264
|
+
diagnostics.push({
|
|
6265
|
+
severity: "error",
|
|
6266
|
+
code: "module-index-file-unreadable",
|
|
6267
|
+
message: `Expected constant file could not be read: ${constantFile.path}.`,
|
|
6268
|
+
context: { paths: [constantFile.path] }
|
|
6269
|
+
});
|
|
6270
|
+
}
|
|
6271
|
+
if (parsedConstant)
|
|
6272
|
+
diagnostics.push(...parsedConstant.diagnostics);
|
|
6273
|
+
if (parsedDictionary)
|
|
6274
|
+
diagnostics.push(...parsedDictionary.diagnostics);
|
|
6275
|
+
if (dictionaryFile?.present && dictionaryFile.casing === "match" && !parsedDictionary?.modelFound) {
|
|
6276
|
+
diagnostics.push({
|
|
6277
|
+
severity: "error",
|
|
6278
|
+
code: "module-index-dictionary-model-missing",
|
|
6279
|
+
message: `Dictionary .model<${moduleClassName}> branch was not found in ${dictionaryFile.path}.`,
|
|
6280
|
+
context: { paths: [dictionaryFile.path] }
|
|
6281
|
+
});
|
|
6282
|
+
}
|
|
6283
|
+
diagnostics.push(...partialPresenceDiagnostics(presence, module));
|
|
6284
|
+
return {
|
|
6285
|
+
schemaVersion: 1,
|
|
6286
|
+
app: module.sysName,
|
|
6287
|
+
module: module.name,
|
|
6288
|
+
moduleClassName,
|
|
6289
|
+
files,
|
|
6290
|
+
fieldPresence: presence,
|
|
6291
|
+
...constant ? { constant } : {},
|
|
6292
|
+
...dictionary ? { dictionary } : {},
|
|
6293
|
+
diagnostics
|
|
6294
|
+
};
|
|
6295
|
+
};
|
|
6296
|
+
|
|
5532
6297
|
// pkgs/@akanjs/devkit/workflow/uiPolicy.ts
|
|
5533
6298
|
var addFieldUiPolicyForType = (typeName) => {
|
|
5534
6299
|
const normalizedType = typeName.toLowerCase() === "enum" ? "enum" : normalizeFieldType(typeName);
|
|
@@ -5593,11 +6358,18 @@ var postApplyDiagnostic = (code, message, target) => ({
|
|
|
5593
6358
|
failureScope: "source-change",
|
|
5594
6359
|
context: { target }
|
|
5595
6360
|
});
|
|
6361
|
+
var postApplyWarning = (code, message, target) => ({
|
|
6362
|
+
severity: "warning",
|
|
6363
|
+
code,
|
|
6364
|
+
message,
|
|
6365
|
+
failureScope: "source-change",
|
|
6366
|
+
context: { target }
|
|
6367
|
+
});
|
|
5596
6368
|
var sourceKindForPath = (filePath) => {
|
|
5597
6369
|
if (filePath.endsWith(".tsx"))
|
|
5598
|
-
return
|
|
6370
|
+
return ts6.ScriptKind.TSX;
|
|
5599
6371
|
if (filePath.endsWith(".ts"))
|
|
5600
|
-
return
|
|
6372
|
+
return ts6.ScriptKind.TS;
|
|
5601
6373
|
return null;
|
|
5602
6374
|
};
|
|
5603
6375
|
var checkPathCasing = async (workspace, filePath) => {
|
|
@@ -5625,15 +6397,15 @@ var checkTypeScriptSyntax = async (workspace, filePath) => {
|
|
|
5625
6397
|
if (!scriptKind)
|
|
5626
6398
|
return null;
|
|
5627
6399
|
const content = await workspace.readFile(filePath);
|
|
5628
|
-
const source =
|
|
5629
|
-
const diagnostic = source.parseDiagnostics[0];
|
|
6400
|
+
const source = ts6.createSourceFile(filePath, content, ts6.ScriptTarget.Latest, true, scriptKind);
|
|
6401
|
+
const diagnostic = (source.parseDiagnostics ?? [])[0];
|
|
5630
6402
|
if (!diagnostic)
|
|
5631
6403
|
return null;
|
|
5632
6404
|
const position = diagnostic.file?.getLineAndCharacterOfPosition(diagnostic.start ?? 0);
|
|
5633
6405
|
const location = position ? `:${position.line + 1}:${position.character + 1}` : "";
|
|
5634
6406
|
return {
|
|
5635
6407
|
code: "workflow-post-apply-syntax-error",
|
|
5636
|
-
message: `Generated source has a TypeScript syntax error at ${filePath}${location}: ${
|
|
6408
|
+
message: `Generated source has a TypeScript syntax error at ${filePath}${location}: ${ts6.flattenDiagnosticMessageText(diagnostic.messageText, " ")}`
|
|
5637
6409
|
};
|
|
5638
6410
|
};
|
|
5639
6411
|
var checkChangedFile = async (workspace, file) => {
|
|
@@ -5675,6 +6447,111 @@ var checkRecommendationPath = async (workspace, recommendation) => {
|
|
|
5675
6447
|
context: { target: recommendation.target }
|
|
5676
6448
|
};
|
|
5677
6449
|
};
|
|
6450
|
+
var sourceChangeError = (diagnostics) => diagnostics.some((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown"));
|
|
6451
|
+
var fieldCount = (fields, fieldName) => fields.filter((field) => field === fieldName).length;
|
|
6452
|
+
var fieldOrderValid = (fields, fieldName) => {
|
|
6453
|
+
const actualIndex = fields.indexOf(fieldName);
|
|
6454
|
+
if (actualIndex < 0 || fields.lastIndexOf(fieldName) !== actualIndex)
|
|
6455
|
+
return false;
|
|
6456
|
+
const fieldsWithoutRequested = fields.filter((_, index) => index !== actualIndex);
|
|
6457
|
+
return insertionIndexForFieldOrder(fieldsWithoutRequested, fieldName) === actualIndex;
|
|
6458
|
+
};
|
|
6459
|
+
var workflowModuleContext = async (workspace, plan) => {
|
|
6460
|
+
const app = workflowStringInput(plan.inputs.app);
|
|
6461
|
+
const moduleName = workflowStringInput(plan.inputs.module);
|
|
6462
|
+
if (!app || !moduleName)
|
|
6463
|
+
return null;
|
|
6464
|
+
const [apps, libs] = await workspace.getSyss();
|
|
6465
|
+
const sysType = apps.includes(app) ? "app" : libs.includes(app) ? "lib" : null;
|
|
6466
|
+
if (!sysType)
|
|
6467
|
+
return null;
|
|
6468
|
+
const modulePath = `${sysType}s/${app}/lib/${moduleName}`;
|
|
6469
|
+
const files = await workspace.readdir(modulePath);
|
|
6470
|
+
const abstractPath = `${modulePath}/${moduleName}.abstract.md`;
|
|
6471
|
+
return {
|
|
6472
|
+
kind: "domain",
|
|
6473
|
+
name: moduleName,
|
|
6474
|
+
folderName: moduleName,
|
|
6475
|
+
sysName: app,
|
|
6476
|
+
sysType,
|
|
6477
|
+
path: modulePath,
|
|
6478
|
+
abstract: {
|
|
6479
|
+
path: abstractPath,
|
|
6480
|
+
exists: files.includes(`${moduleName}.abstract.md`),
|
|
6481
|
+
headings: []
|
|
6482
|
+
},
|
|
6483
|
+
files
|
|
6484
|
+
};
|
|
6485
|
+
};
|
|
6486
|
+
var structureCheck = (code, target, status, message) => ({
|
|
6487
|
+
code,
|
|
6488
|
+
target,
|
|
6489
|
+
status,
|
|
6490
|
+
message
|
|
6491
|
+
});
|
|
6492
|
+
var checkAddFieldStructure = async (workspace, plan) => {
|
|
6493
|
+
if (plan.workflow !== "add-field" && plan.workflow !== "add-enum-field")
|
|
6494
|
+
return {};
|
|
6495
|
+
const app = workflowStringInput(plan.inputs.app);
|
|
6496
|
+
const moduleName = workflowStringInput(plan.inputs.module);
|
|
6497
|
+
const fieldName = workflowStringInput(plan.inputs.field);
|
|
6498
|
+
const typeName = workflowStringInput(plan.inputs.type);
|
|
6499
|
+
if (!app || !moduleName || !fieldName || !typeName)
|
|
6500
|
+
return {};
|
|
6501
|
+
const moduleContext = await workflowModuleContext(workspace, plan);
|
|
6502
|
+
if (!moduleContext)
|
|
6503
|
+
return {};
|
|
6504
|
+
const paths = moduleSourcePaths(moduleName);
|
|
6505
|
+
const constantPath = `${moduleContext.path}/${paths.constant.replace(`lib/${moduleName}/`, "")}`;
|
|
6506
|
+
const dictionaryPath = `${moduleContext.path}/${paths.dictionary.replace(`lib/${moduleName}/`, "")}`;
|
|
6507
|
+
const moduleClassName = moduleComponentName(moduleName);
|
|
6508
|
+
const inputClassName = `${moduleClassName}Input`;
|
|
6509
|
+
const index = await buildAkanModuleContextIndex(workspace, moduleContext, { field: fieldName });
|
|
6510
|
+
const diagnostics = [];
|
|
6511
|
+
const postApplyChecks = [];
|
|
6512
|
+
const constantContent = await workspace.readFile(constantPath);
|
|
6513
|
+
const constantStructure = inspectConstantStructure(constantContent, inputClassName, moduleClassName);
|
|
6514
|
+
const constantNames = constantStructure.fields.map((field) => field.name);
|
|
6515
|
+
const requestedConstantFields = constantStructure.fields.filter((field) => field.name === fieldName);
|
|
6516
|
+
const normalizedType = typeName.toLowerCase() === "enum" ? typeName : normalizeFieldType(typeName);
|
|
6517
|
+
const constantFailures = [
|
|
6518
|
+
!constantStructure.parseValid ? "constant file does not parse" : null,
|
|
6519
|
+
!constantStructure.inputObjectFound ? `${inputClassName} via builder object was not found` : null,
|
|
6520
|
+
requestedConstantFields.length !== 1 ? `field "${fieldName}" appears ${requestedConstantFields.length} time(s) in ${inputClassName}` : null,
|
|
6521
|
+
constantStructure.builderName && requestedConstantFields[0]?.expressionBuilder && requestedConstantFields[0].expressionBuilder !== constantStructure.builderName ? `field "${fieldName}" uses builder "${requestedConstantFields[0].expressionBuilder}" instead of "${constantStructure.builderName}"` : null,
|
|
6522
|
+
!constantStructure.builderName ? `${inputClassName} via builder parameter was not found` : null,
|
|
6523
|
+
(normalizedType === "Int" || normalizedType === "Float") && !constantStructure.baseImports.includes(normalizedType) ? `missing ${normalizedType} import from "akanjs/base"` : null,
|
|
6524
|
+
workflowBooleanInput(plan.inputs.includeInLight) === true && fieldCount(constantStructure.lightProjectionFields, fieldName) !== 1 ? `field "${fieldName}" is not present exactly once in Light${moduleClassName}` : null,
|
|
6525
|
+
...index.diagnostics.filter((diagnostic) => diagnostic.severity === "error" && diagnostic.context?.paths?.includes(constantPath)).map((diagnostic) => diagnostic.message)
|
|
6526
|
+
].filter((failure) => failure !== null);
|
|
6527
|
+
const constantValid = constantFailures.length === 0;
|
|
6528
|
+
postApplyChecks.push(structureCheck(constantValid ? "workflow-post-apply-constant-shape-valid" : "workflow-post-apply-structure-invalid", constantPath, constantValid ? "passed" : "failed", constantValid ? `${inputClassName} keeps via structure, builder usage, imports, and requested field presence.` : constantFailures.join(" ")));
|
|
6529
|
+
if (!constantValid) {
|
|
6530
|
+
diagnostics.push(postApplyDiagnostic("workflow-post-apply-structure-invalid", constantFailures.join(" "), constantPath));
|
|
6531
|
+
}
|
|
6532
|
+
const dictionaryContent = await workspace.readFile(dictionaryPath);
|
|
6533
|
+
const dictionaryStructure = inspectDictionaryStructure(dictionaryContent, moduleClassName);
|
|
6534
|
+
const dictionaryFailures = [
|
|
6535
|
+
!dictionaryStructure.parseValid ? "dictionary file does not parse" : null,
|
|
6536
|
+
!dictionaryStructure.modelObjectFound ? `.model<${moduleClassName}> object was not found` : null,
|
|
6537
|
+
dictionaryStructure.modelObjectFound && !dictionaryStructure.chainOrderValid ? `.model(), .slice(), .enum(), .error(), and .translate() chain order is broken: ${dictionaryStructure.chainMethods.join(" -> ")}` : null,
|
|
6538
|
+
fieldCount(dictionaryStructure.fields, fieldName) !== 1 ? `field "${fieldName}" appears ${fieldCount(dictionaryStructure.fields, fieldName)} time(s) in .model<${moduleClassName}>` : null,
|
|
6539
|
+
...index.diagnostics.filter((diagnostic) => diagnostic.severity === "error" && diagnostic.context?.paths?.includes(dictionaryPath)).map((diagnostic) => diagnostic.message)
|
|
6540
|
+
].filter((failure) => failure !== null);
|
|
6541
|
+
const dictionaryValid = dictionaryFailures.length === 0;
|
|
6542
|
+
postApplyChecks.push(structureCheck(dictionaryValid ? "workflow-post-apply-dictionary-shape-valid" : "workflow-post-apply-structure-invalid", dictionaryPath, dictionaryValid ? "passed" : "failed", dictionaryValid ? `.model<${moduleClassName}> keeps the requested field inside the model object and preserves dictionary chain order.` : dictionaryFailures.join(" ")));
|
|
6543
|
+
if (!dictionaryValid) {
|
|
6544
|
+
diagnostics.push(postApplyDiagnostic("workflow-post-apply-structure-invalid", dictionaryFailures.join(" "), dictionaryPath));
|
|
6545
|
+
}
|
|
6546
|
+
const constantOrderValid = fieldOrderValid(constantNames, fieldName);
|
|
6547
|
+
const dictionaryOrderValid = fieldOrderValid(dictionaryStructure.fields, fieldName);
|
|
6548
|
+
const orderValid = constantOrderValid && dictionaryOrderValid;
|
|
6549
|
+
postApplyChecks.push(structureCheck("workflow-post-apply-field-order-valid", `${constantPath}, ${dictionaryPath}`, orderValid ? "passed" : "failed", orderValid ? `Field "${fieldName}" follows the shared priority ordering policy.` : `Field "${fieldName}" is present but does not match the shared priority ordering policy.`));
|
|
6550
|
+
if (!orderValid) {
|
|
6551
|
+
diagnostics.push(postApplyWarning("workflow-post-apply-field-order-mismatch", `Field "${fieldName}" is present but does not match the shared priority ordering policy.`, `${constantPath}, ${dictionaryPath}`));
|
|
6552
|
+
}
|
|
6553
|
+
return { diagnostics, postApplyChecks };
|
|
6554
|
+
};
|
|
5678
6555
|
var resolveWorkflowSys = async (workspace, target) => {
|
|
5679
6556
|
if (!target)
|
|
5680
6557
|
return null;
|
|
@@ -5711,7 +6588,7 @@ var addFieldUiSurfaceInspection = (plan) => {
|
|
|
5711
6588
|
const policy = addFieldUiPolicyForType(typeName ?? "String");
|
|
5712
6589
|
const surfaces = workflowStringArrayInput(plan.inputs.surfaces);
|
|
5713
6590
|
const templateRequested = surfaces?.includes("template") ?? false;
|
|
5714
|
-
const moduleClassName =
|
|
6591
|
+
const moduleClassName = moduleComponentName(module);
|
|
5715
6592
|
const target = `${app ? `apps/${app}` : "*"}/${moduleSourcePaths(module).template}`;
|
|
5716
6593
|
return {
|
|
5717
6594
|
recommendations: [
|
|
@@ -5719,9 +6596,9 @@ var addFieldUiSurfaceInspection = (plan) => {
|
|
|
5719
6596
|
code: "add-field-ui-surface-review",
|
|
5720
6597
|
kind: "manual-action",
|
|
5721
6598
|
target,
|
|
5722
|
-
action: templateRequested ? `Template was requested for ${field}. If no Template file changed,
|
|
6599
|
+
action: templateRequested ? `Template was requested for ${field}. If no Template file changed, users will not see the field in the form yet because the file was missing, the generated ${module}Form/Layout.Template pattern was not found, or ${policy.component} needs option binding. Add it inside Layout.Template near existing Field components.` : `Template was not selected, so users will not see ${field} in the form from this apply. If list/card display is needed, include ${field} in Light${moduleClassName} projection data and place it in the local Unit/View card layout.`,
|
|
5723
6600
|
confidence: "medium",
|
|
5724
|
-
message: `Review UI
|
|
6601
|
+
message: `Review user-visible UI for ${module}.${field}; recommended component is ${policy.component}.`
|
|
5725
6602
|
}
|
|
5726
6603
|
],
|
|
5727
6604
|
nextActions: [
|
|
@@ -5880,6 +6757,11 @@ class WorkflowExecutor {
|
|
|
5880
6757
|
postApplyChecks.push(...result.postApplyChecks ?? []);
|
|
5881
6758
|
diagnostics.push(...result.diagnostics ?? []);
|
|
5882
6759
|
}
|
|
6760
|
+
if (!sourceChangeError(diagnostics)) {
|
|
6761
|
+
const result = await checkAddFieldStructure(this.workspace, plan);
|
|
6762
|
+
postApplyChecks.push(...result.postApplyChecks ?? []);
|
|
6763
|
+
diagnostics.push(...result.diagnostics ?? []);
|
|
6764
|
+
}
|
|
5883
6765
|
const recommendationDiagnostics = await Promise.all(recommendations.map((recommendation) => checkRecommendationPath(this.workspace, recommendation)));
|
|
5884
6766
|
diagnostics.push(...recommendationDiagnostics.filter((diagnostic) => !!diagnostic));
|
|
5885
6767
|
}
|
|
@@ -5898,7 +6780,7 @@ class WorkflowExecutor {
|
|
|
5898
6780
|
}
|
|
5899
6781
|
}
|
|
5900
6782
|
// pkgs/@akanjs/devkit/workflow/plan.ts
|
|
5901
|
-
import { capitalize as
|
|
6783
|
+
import { capitalize as capitalize2 } from "akanjs/common";
|
|
5902
6784
|
var surfaceModes = new Set(["infer", "include", "skip"]);
|
|
5903
6785
|
var parseStringList = (value) => {
|
|
5904
6786
|
if (Array.isArray(value)) {
|
|
@@ -5971,10 +6853,48 @@ var createAddFieldDefaultRecommendations = (inputs) => {
|
|
|
5971
6853
|
kind: "manual-action",
|
|
5972
6854
|
confidence: "high",
|
|
5973
6855
|
message: `Default for ${field} will be normalized to ${coercion.normalizedType} literal ${coercion.expression}.`,
|
|
5974
|
-
action: "Review the normalized default in the apply report
|
|
6856
|
+
action: "Review the normalized default in the apply report. To leave the field without a default, omit the default input."
|
|
5975
6857
|
}
|
|
5976
6858
|
];
|
|
5977
6859
|
};
|
|
6860
|
+
var moneyLikeFieldPattern = /(budget|price|amount|cost|rate|fee|salary|balance)/i;
|
|
6861
|
+
var wholeNumberFieldPattern = /(count|quantity|total|number|index|rank|order|age)/i;
|
|
6862
|
+
var createAddFieldInputRecommendations = (inputs) => {
|
|
6863
|
+
const field = typeof inputs.field === "string" ? inputs.field : "<field>";
|
|
6864
|
+
const typeName = typeof inputs.type === "string" ? inputs.type : null;
|
|
6865
|
+
const recommendations = [];
|
|
6866
|
+
if (!typeName)
|
|
6867
|
+
return recommendations;
|
|
6868
|
+
if (typeName.toLowerCase() === "number" || typeName.toLowerCase() === "numeric") {
|
|
6869
|
+
const recommendedType = moneyLikeFieldPattern.test(field) ? "Float" : wholeNumberFieldPattern.test(field) ? "Int" : null;
|
|
6870
|
+
recommendations.push({
|
|
6871
|
+
code: "add-field-type-choice",
|
|
6872
|
+
kind: "input-guidance",
|
|
6873
|
+
confidence: recommendedType ? "high" : "medium",
|
|
6874
|
+
message: recommendedType ? `Use ${recommendedType} for ${field}; Float is recommended for money-like decimal values and Int for whole-number values.` : `Choose Int for whole-number ${field} values or Float for decimal ${field} values.`,
|
|
6875
|
+
action: recommendedType ? `Re-run plan_workflow with type="${recommendedType}".` : 'Re-run plan_workflow with type="Int" or type="Float".'
|
|
6876
|
+
});
|
|
6877
|
+
}
|
|
6878
|
+
if (typeName.toLowerCase() === "enum" && !Array.isArray(inputs.values)) {
|
|
6879
|
+
recommendations.push({
|
|
6880
|
+
code: "add-field-enum-values",
|
|
6881
|
+
kind: "input-guidance",
|
|
6882
|
+
confidence: "high",
|
|
6883
|
+
message: `Enum field ${field} needs values before apply can choose valid dictionary and default behavior.`,
|
|
6884
|
+
action: 'Pass values as an array or comma-separated string, for example values=["draft","done"].'
|
|
6885
|
+
});
|
|
6886
|
+
}
|
|
6887
|
+
if (inputs.default === undefined) {
|
|
6888
|
+
recommendations.push({
|
|
6889
|
+
code: "add-field-default-optional",
|
|
6890
|
+
kind: "input-guidance",
|
|
6891
|
+
confidence: "medium",
|
|
6892
|
+
message: `No default will be written for ${field} because default is omitted.`,
|
|
6893
|
+
action: "Keep default omitted when the field should have no default value."
|
|
6894
|
+
});
|
|
6895
|
+
}
|
|
6896
|
+
return recommendations;
|
|
6897
|
+
};
|
|
5978
6898
|
var createAddFieldRecommendations = (inputs) => {
|
|
5979
6899
|
const app = typeof inputs.app === "string" ? inputs.app : "<app-or-lib>";
|
|
5980
6900
|
const module = typeof inputs.module === "string" ? inputs.module : "<module>";
|
|
@@ -6003,7 +6923,7 @@ var createAddFieldRecommendations = (inputs) => {
|
|
|
6003
6923
|
kind: "placement",
|
|
6004
6924
|
target: paths.constant,
|
|
6005
6925
|
confidence: "high",
|
|
6006
|
-
message: `Insert ${field}: field(${normalizedType}) in ${
|
|
6926
|
+
message: `Insert ${field}: field(${normalizedType}) in ${capitalize2(module)}Input.`
|
|
6007
6927
|
},
|
|
6008
6928
|
{
|
|
6009
6929
|
code: "add-field-placement-dictionary",
|
|
@@ -6035,9 +6955,9 @@ var createAddFieldRecommendations = (inputs) => {
|
|
|
6035
6955
|
code: "add-field-light-projection-choice",
|
|
6036
6956
|
kind: "manual-action",
|
|
6037
6957
|
target: paths.constant,
|
|
6038
|
-
action: `Pass includeInLight=true when ${field}
|
|
6958
|
+
action: `Pass includeInLight=true when users should see ${field} in list/card data. Without it, the field can exist on ${capitalize2(module)}Input but stay absent from Light${capitalize2(module)} projections.`,
|
|
6039
6959
|
confidence: "medium",
|
|
6040
|
-
message:
|
|
6960
|
+
message: `${module}.${field} is not selected for list/card projection data.`
|
|
6041
6961
|
}
|
|
6042
6962
|
] : [],
|
|
6043
6963
|
...includeInLight ? [
|
|
@@ -6046,7 +6966,7 @@ var createAddFieldRecommendations = (inputs) => {
|
|
|
6046
6966
|
kind: "placement",
|
|
6047
6967
|
target: paths.constant,
|
|
6048
6968
|
confidence: "high",
|
|
6049
|
-
message: `Add ${field} to Light${
|
|
6969
|
+
message: `Add ${field} to Light${capitalize2(module)} projection fields.`
|
|
6050
6970
|
}
|
|
6051
6971
|
] : [],
|
|
6052
6972
|
...surfaces && !templateRequested ? [
|
|
@@ -6055,18 +6975,20 @@ var createAddFieldRecommendations = (inputs) => {
|
|
|
6055
6975
|
kind: "manual-action",
|
|
6056
6976
|
target: paths.template,
|
|
6057
6977
|
confidence: "medium",
|
|
6058
|
-
message: `Template
|
|
6978
|
+
message: `Template form auto-edit is skipped for ${module}.${field} because surfaces does not include "template".`,
|
|
6979
|
+
action: `Pass surfaces=["template"] when users should enter ${field} in the Template form.`
|
|
6059
6980
|
}
|
|
6060
6981
|
] : [],
|
|
6061
6982
|
{
|
|
6062
6983
|
code: "add-field-ui-manual-review",
|
|
6063
6984
|
kind: "manual-action",
|
|
6064
6985
|
target: paths.template,
|
|
6065
|
-
action: `
|
|
6986
|
+
action: `After apply, verify what users can see: Template form auto-edit only runs when a generated ${module}Form hook and Layout.Template field list are present. Unit/View cards are not auto-edited, so ${field} may be stored on ${capitalize2(module)} but not shown in list/card UI until you place it in the local card layout.`,
|
|
6066
6987
|
confidence: "medium",
|
|
6067
|
-
message:
|
|
6988
|
+
message: `${app}:${module}.${field} may need UI review for user-visible Template, Unit, and View behavior.`
|
|
6068
6989
|
},
|
|
6069
|
-
...createAddFieldDefaultRecommendations(inputs)
|
|
6990
|
+
...createAddFieldDefaultRecommendations(inputs),
|
|
6991
|
+
...createAddFieldInputRecommendations(inputs)
|
|
6070
6992
|
];
|
|
6071
6993
|
};
|
|
6072
6994
|
var createWorkflowPlanPredictedChanges = (spec, inputs) => {
|
|
@@ -6209,7 +7131,8 @@ var createWorkflowPlan = (spec, rawInputs) => {
|
|
|
6209
7131
|
validation: spec.validation,
|
|
6210
7132
|
diagnostics,
|
|
6211
7133
|
recommendations: createWorkflowPlanRecommendations(spec, inputs),
|
|
6212
|
-
requiresApproval: true
|
|
7134
|
+
requiresApproval: true,
|
|
7135
|
+
approval: workflowPlanApproval
|
|
6213
7136
|
};
|
|
6214
7137
|
};
|
|
6215
7138
|
// pkgs/@akanjs/devkit/workflow/render.ts
|
|
@@ -6247,6 +7170,7 @@ var renderWorkflowPlan = (plan) => [
|
|
|
6247
7170
|
"",
|
|
6248
7171
|
`- Mode: ${plan.mode}`,
|
|
6249
7172
|
`- Requires approval: ${plan.requiresApproval}`,
|
|
7173
|
+
`- Approval: ${plan.approval?.meaning ?? "Review this read-only plan before applying workflow mutations."}`,
|
|
6250
7174
|
"",
|
|
6251
7175
|
"## Inputs",
|
|
6252
7176
|
...Object.entries(plan.inputs).map(([name, value]) => `- \`${name}\`: ${Array.isArray(value) ? value.join(", ") : value}`),
|
|
@@ -6280,8 +7204,13 @@ var renderRecommendation = (recommendation) => {
|
|
|
6280
7204
|
return `- [${recommendation.kind}]${target} ${recommendation.message}${action}`;
|
|
6281
7205
|
};
|
|
6282
7206
|
var renderDiagnostic = (diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`;
|
|
7207
|
+
var renderNextAction = (action) => `- \`${action.command}\`: ${action.reason}`;
|
|
6283
7208
|
var applySourceStatus = (report) => report.diagnostics.some((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown")) ? "failed" : "passed";
|
|
6284
7209
|
var renderWorkflowApplyReport = (report) => {
|
|
7210
|
+
const applySummary = {
|
|
7211
|
+
sourceFilesChanged: report.summary?.sourceFilesChanged ?? report.changedFiles,
|
|
7212
|
+
generatedFilesSynced: report.summary?.generatedFilesSynced ?? report.generatedFiles
|
|
7213
|
+
};
|
|
6285
7214
|
const manualReviewItems = [
|
|
6286
7215
|
...report.diagnostics.filter((diagnostic) => diagnostic.severity === "warning").map(renderDiagnostic),
|
|
6287
7216
|
...report.recommendations.filter((recommendation) => recommendation.kind === "manual-action").map(renderRecommendation)
|
|
@@ -6295,6 +7224,8 @@ var renderWorkflowApplyReport = (report) => {
|
|
|
6295
7224
|
`- Status: ${report.status}`,
|
|
6296
7225
|
`- Source-change status: ${applySourceStatus(report)}`,
|
|
6297
7226
|
`- Workspace status: ${validationBlockers.length ? "blocked" : "not blocked during apply"}`,
|
|
7227
|
+
`- Source files changed: ${applySummary.sourceFilesChanged.length}`,
|
|
7228
|
+
`- Generated files queued for sync: ${applySummary.generatedFilesSynced.length}`,
|
|
6298
7229
|
...report.validationTarget ? [`- Validation target: ${report.validationTarget}`] : [],
|
|
6299
7230
|
"",
|
|
6300
7231
|
"## Apply Checks",
|
|
@@ -6304,10 +7235,10 @@ var renderWorkflowApplyReport = (report) => {
|
|
|
6304
7235
|
...sourceBlockers.length ? sourceBlockers : ["- none"],
|
|
6305
7236
|
"",
|
|
6306
7237
|
"## Automatically Modified",
|
|
6307
|
-
...
|
|
7238
|
+
...applySummary.sourceFilesChanged.length ? applySummary.sourceFilesChanged.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
|
|
6308
7239
|
"",
|
|
6309
7240
|
"## Generated Sync",
|
|
6310
|
-
...
|
|
7241
|
+
...applySummary.generatedFilesSynced.length ? applySummary.generatedFilesSynced.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
|
|
6311
7242
|
"",
|
|
6312
7243
|
"## Applied Commands",
|
|
6313
7244
|
...report.appliedCommands.length ? report.appliedCommands.map((command) => `- \`${command.command}\`: ${command.reason}`) : ["- none"],
|
|
@@ -6328,58 +7259,82 @@ var renderWorkflowApplyReport = (report) => {
|
|
|
6328
7259
|
...report.recommendations.length ? report.recommendations.slice(0, 3).map(renderRecommendation) : ["- none"],
|
|
6329
7260
|
"",
|
|
6330
7261
|
"## Next Actions",
|
|
6331
|
-
...report.nextActions.length ? report.nextActions.
|
|
7262
|
+
...report.nextActions.length ? report.nextActions.slice(0, 3).map(renderNextAction) : ["- none"],
|
|
6332
7263
|
""
|
|
6333
7264
|
].join(`
|
|
6334
7265
|
`);
|
|
6335
7266
|
};
|
|
6336
7267
|
var renderWorkflowApply = (report, format = "markdown") => format === "json" ? jsonText(report) : renderWorkflowApplyReport(report);
|
|
6337
|
-
var renderWorkflowValidationRunReport = (report) =>
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
|
|
6351
|
-
|
|
6352
|
-
|
|
6353
|
-
|
|
6354
|
-
|
|
6355
|
-
|
|
6356
|
-
|
|
6357
|
-
|
|
6358
|
-
|
|
6359
|
-
|
|
6360
|
-
|
|
6361
|
-
|
|
6362
|
-
|
|
6363
|
-
|
|
6364
|
-
|
|
6365
|
-
|
|
6366
|
-
|
|
6367
|
-
|
|
6368
|
-
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
6372
|
-
|
|
6373
|
-
|
|
6374
|
-
|
|
6375
|
-
|
|
6376
|
-
|
|
6377
|
-
|
|
6378
|
-
|
|
6379
|
-
|
|
6380
|
-
|
|
6381
|
-
|
|
7268
|
+
var renderWorkflowValidationRunReport = (report) => {
|
|
7269
|
+
const baselineSummary = report.baselineSummary ?? {
|
|
7270
|
+
status: report.baselineDiagnostics?.some((diagnostic) => diagnostic.severity === "error") ? "failed" : "unknown",
|
|
7271
|
+
total: report.baselineDiagnostics?.length ?? 0,
|
|
7272
|
+
totalErrors: report.baselineDiagnostics?.filter((diagnostic) => diagnostic.severity === "error").length ?? 0,
|
|
7273
|
+
totalWarnings: report.baselineDiagnostics?.filter((diagnostic) => diagnostic.severity === "warning").length ?? 0,
|
|
7274
|
+
detailsIncluded: true,
|
|
7275
|
+
knownBlockerCount: report.knownBlockers.filter((blocker) => blocker.known).length,
|
|
7276
|
+
byCode: []
|
|
7277
|
+
};
|
|
7278
|
+
return [
|
|
7279
|
+
`# Workflow Validation: ${report.workflow}`,
|
|
7280
|
+
"",
|
|
7281
|
+
`- Run: ${report.runId}`,
|
|
7282
|
+
`- Status: ${report.status}`,
|
|
7283
|
+
`- Source status: ${report.sourceStatus}`,
|
|
7284
|
+
`- Workspace status: ${report.workspaceStatus}`,
|
|
7285
|
+
`- Validation commands status: ${report.validationCommandsStatus ?? "unknown"}`,
|
|
7286
|
+
`- Baseline status: ${report.baselineStatus ?? baselineSummary.status}`,
|
|
7287
|
+
`- Overall status: ${report.overallStatus}`,
|
|
7288
|
+
"",
|
|
7289
|
+
"## Status Summary",
|
|
7290
|
+
`- Source-change: ${report.summary.sourceChange}`,
|
|
7291
|
+
`- Generated sync: ${report.summary.generatedSync}`,
|
|
7292
|
+
`- Validation commands: ${report.summary.validationCommands ?? "unknown"}`,
|
|
7293
|
+
`- Baseline: ${report.summary.baseline ?? baselineSummary.status}`,
|
|
7294
|
+
`- Workspace config: ${report.summary.workspaceConfig}`,
|
|
7295
|
+
`- Environment: ${report.summary.environment}`,
|
|
7296
|
+
"",
|
|
7297
|
+
"## Source Change Diagnostics",
|
|
7298
|
+
...report.workflowDiagnostics?.length ? report.workflowDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
|
|
7299
|
+
"",
|
|
7300
|
+
"## Existing Workspace Blockers",
|
|
7301
|
+
`- Status: ${baselineSummary.status}`,
|
|
7302
|
+
`- Errors: ${baselineSummary.totalErrors}`,
|
|
7303
|
+
`- Warnings: ${baselineSummary.totalWarnings}`,
|
|
7304
|
+
...baselineSummary.byCode.length ? baselineSummary.byCode.map((item) => `- [${item.severity}] ${item.code} (${item.count}x): ${item.sampleMessage}`) : ["- none"],
|
|
7305
|
+
...baselineSummary.detailsIncluded ? [] : [
|
|
7306
|
+
"- Baseline details are summarized by default. Re-run validation with includeBaselineDetails=true for full baselineDiagnostics."
|
|
7307
|
+
],
|
|
7308
|
+
"",
|
|
7309
|
+
"## Existing Workspace Blocker Details",
|
|
7310
|
+
...report.baselineDiagnostics?.length ? report.baselineDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : baselineSummary.detailsIncluded ? ["- none"] : ["- omitted"],
|
|
7311
|
+
"",
|
|
7312
|
+
"## Known Blockers",
|
|
7313
|
+
...report.knownBlockers.length ? report.knownBlockers.map((blocker) => {
|
|
7314
|
+
const command = blocker.command ? ` \`${blocker.command}\`` : "";
|
|
7315
|
+
const count = blocker.count > 1 ? ` (${blocker.count}x)` : "";
|
|
7316
|
+
const known = blocker.known ? " known" : "";
|
|
7317
|
+
return `- [${blocker.failureScope}${known}]${command}${count}: ${blocker.message}`;
|
|
7318
|
+
}) : ["- none"],
|
|
7319
|
+
"",
|
|
7320
|
+
"## Commands",
|
|
7321
|
+
...report.commands.length ? report.commands.map((command) => {
|
|
7322
|
+
const scope = command.failureScope ? ` (${command.failureScope})` : "";
|
|
7323
|
+
return `- [${command.status}] \`${command.command}\`${scope}: ${command.reason}`;
|
|
7324
|
+
}) : ["- none"],
|
|
7325
|
+
"",
|
|
7326
|
+
"## Diagnostics",
|
|
7327
|
+
...report.diagnostics.length ? report.diagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
|
|
7328
|
+
"",
|
|
7329
|
+
"## Repair Actions",
|
|
7330
|
+
...report.repairActions.length ? report.repairActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
|
|
7331
|
+
"",
|
|
7332
|
+
"## Next Actions",
|
|
7333
|
+
...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
|
|
7334
|
+
""
|
|
7335
|
+
].join(`
|
|
6382
7336
|
`);
|
|
7337
|
+
};
|
|
6383
7338
|
var renderWorkflowValidation = (report, format = "markdown") => format === "json" ? jsonText(report) : renderWorkflowValidationRunReport(report);
|
|
6384
7339
|
var renderRepairReportMarkdown = (report) => [
|
|
6385
7340
|
`# Akan Repair: ${report.kind}`,
|
|
@@ -6409,6 +7364,70 @@ var renderWorkflowRunArtifact = (artifact, format = "markdown") => {
|
|
|
6409
7364
|
}
|
|
6410
7365
|
return jsonText(artifact);
|
|
6411
7366
|
};
|
|
7367
|
+
// pkgs/@akanjs/devkit/workflow/rolloutGate.ts
|
|
7368
|
+
var toolingRolloutCandidates = [
|
|
7369
|
+
{
|
|
7370
|
+
packageName: "typescript",
|
|
7371
|
+
status: "allowed",
|
|
7372
|
+
role: "Primary TypeScript Compiler API baseline for AST locator, text splice, and reparse checks.",
|
|
7373
|
+
adoptionGate: "Already present; keep using stable Bun-compatible package builds."
|
|
7374
|
+
},
|
|
7375
|
+
{
|
|
7376
|
+
packageName: "@ttsc/graph",
|
|
7377
|
+
status: "reference-only",
|
|
7378
|
+
role: "Source-free graph shape and lazy resident model reference.",
|
|
7379
|
+
adoptionGate: "Do not add as an Akan runtime dependency without a separate proposal or milestone update."
|
|
7380
|
+
},
|
|
7381
|
+
{
|
|
7382
|
+
packageName: "ts-morph",
|
|
7383
|
+
status: "experiment-only",
|
|
7384
|
+
role: "Prototype candidate for complex object literal insertion, import update, and class traversal.",
|
|
7385
|
+
adoptionGate: "Use only in isolated prototypes until package size and formatting churn are measured."
|
|
7386
|
+
},
|
|
7387
|
+
{
|
|
7388
|
+
packageName: "ast-grep",
|
|
7389
|
+
status: "experiment-only",
|
|
7390
|
+
role: "Prototype candidate for shape detection, CI rules, and migration rules.",
|
|
7391
|
+
adoptionGate: "Use as a local rule/check experiment, not as the edit engine."
|
|
7392
|
+
},
|
|
7393
|
+
{
|
|
7394
|
+
packageName: "recast",
|
|
7395
|
+
status: "experiment-only",
|
|
7396
|
+
role: "Prototype candidate for formatting preservation.",
|
|
7397
|
+
adoptionGate: "Low priority; require proof that formatting churn is lower than the baseline."
|
|
7398
|
+
},
|
|
7399
|
+
{
|
|
7400
|
+
packageName: "typescript-go",
|
|
7401
|
+
status: "blocked",
|
|
7402
|
+
role: "TypeScript-Go toolchain transition placeholder.",
|
|
7403
|
+
adoptionGate: "Out of scope for Season 2 rollout."
|
|
7404
|
+
},
|
|
7405
|
+
{
|
|
7406
|
+
packageName: "@typescript/native-preview",
|
|
7407
|
+
status: "blocked",
|
|
7408
|
+
role: "TypeScript-Go native preview package placeholder.",
|
|
7409
|
+
adoptionGate: "Out of scope for Season 2 rollout."
|
|
7410
|
+
}
|
|
7411
|
+
];
|
|
7412
|
+
var toolingRolloutGate = {
|
|
7413
|
+
schemaVersion: 1,
|
|
7414
|
+
strategy: "reference-first-dependency-later",
|
|
7415
|
+
dependencyPolicy: "Season 2 keeps new AST and graph tooling as references or isolated experiments until a separate proposal or milestone update approves adoption.",
|
|
7416
|
+
gateConditions: [
|
|
7417
|
+
"Works in Bun runtime and published package artifacts.",
|
|
7418
|
+
"Does not break dist/pkgs package verification.",
|
|
7419
|
+
"Keeps generated source formatting churn limited.",
|
|
7420
|
+
"Reduces add-field regression fixture failures compared with the current TypeScript API baseline.",
|
|
7421
|
+
"Does not move MCP responses toward returning source bodies."
|
|
7422
|
+
],
|
|
7423
|
+
candidates: toolingRolloutCandidates
|
|
7424
|
+
};
|
|
7425
|
+
var isRestrictedCandidate = (candidate) => candidate.status !== "allowed";
|
|
7426
|
+
var restrictedCandidates = new Map;
|
|
7427
|
+
for (const candidate of toolingRolloutCandidates) {
|
|
7428
|
+
if (isRestrictedCandidate(candidate))
|
|
7429
|
+
restrictedCandidates.set(candidate.packageName, candidate);
|
|
7430
|
+
}
|
|
6412
7431
|
// pkgs/@akanjs/devkit/akanContext.ts
|
|
6413
7432
|
var resourceList = [
|
|
6414
7433
|
{ uri: "akan://docs/framework", name: "Akan framework guide", mimeType: "text/markdown" },
|
|
@@ -6551,7 +7570,7 @@ var planInputString = (plan2, key) => {
|
|
|
6551
7570
|
var expandWorkflowTarget = (target, plan2) => {
|
|
6552
7571
|
const app = planInputString(plan2, "app");
|
|
6553
7572
|
const module = planInputString(plan2, "module");
|
|
6554
|
-
const moduleClass = module ?
|
|
7573
|
+
const moduleClass = module ? capitalize3(module) : "<Module>";
|
|
6555
7574
|
return target.replace(/^\*\//, app ? `apps/${app}/` : "").replaceAll("<module>", module || "<module>").replaceAll("<Module>", moduleClass);
|
|
6556
7575
|
};
|
|
6557
7576
|
var workflowPathsForPlan = (plan2) => plan2.predictedChanges.map((change) => expandWorkflowTarget(change.target, plan2));
|
|
@@ -6573,8 +7592,8 @@ var loadWorkflowContextPaths = async (workspace, runIdOrPlan, changedFiles) => {
|
|
|
6573
7592
|
const paths = [...changedFiles];
|
|
6574
7593
|
if (!runIdOrPlan)
|
|
6575
7594
|
return paths;
|
|
6576
|
-
const inputPath =
|
|
6577
|
-
const artifact = await safeReadJson(inputPath) ?? await safeReadJson(
|
|
7595
|
+
const inputPath = path11.isAbsolute(runIdOrPlan) ? runIdOrPlan : path11.join(workspace.workspaceRoot, runIdOrPlan);
|
|
7596
|
+
const artifact = await safeReadJson(inputPath) ?? await safeReadJson(path11.join(workspace.workspaceRoot, workflowRunArtifactPath(runIdOrPlan)));
|
|
6578
7597
|
if (artifact && isWorkflowRunArtifact(artifact))
|
|
6579
7598
|
paths.push(...workflowPathsForArtifact(artifact));
|
|
6580
7599
|
return [...new Set(paths.filter(Boolean))];
|
|
@@ -6592,9 +7611,9 @@ var isWorkflowRelatedDiagnostic = (diagnostic, workflowPaths) => {
|
|
|
6592
7611
|
});
|
|
6593
7612
|
};
|
|
6594
7613
|
var readGeneratedSyncStates = async (workspace) => {
|
|
6595
|
-
const syncDir =
|
|
7614
|
+
const syncDir = path11.join(workspace.workspaceRoot, workflowSyncDir);
|
|
6596
7615
|
const entries = await safeReadDir(syncDir);
|
|
6597
|
-
const states = await Promise.all(entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => safeReadJson(
|
|
7616
|
+
const states = await Promise.all(entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => safeReadJson(path11.join(syncDir, entry.name))));
|
|
6598
7617
|
return states.filter((state) => !!state && state.schemaVersion === 1 && typeof state.target === "string" && typeof state.syncedAt === "string");
|
|
6599
7618
|
};
|
|
6600
7619
|
var generatedFreshnessFromStates = async (workspace) => {
|
|
@@ -6631,12 +7650,12 @@ var parseAbstractSummary = (relativePath, content, includeContent) => {
|
|
|
6631
7650
|
};
|
|
6632
7651
|
};
|
|
6633
7652
|
var readFiles = async (dirPath) => (await safeReadDir(dirPath)).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
|
|
6634
|
-
var getRelative = (workspace, absolutePath) =>
|
|
7653
|
+
var getRelative = (workspace, absolutePath) => path11.relative(workspace.workspaceRoot, absolutePath).replaceAll(path11.sep, "/");
|
|
6635
7654
|
var createModuleContext = async (workspace, sys2, kind, folderName, moduleName, includeAbstractContent) => {
|
|
6636
|
-
const modulePath = kind === "scalar" ?
|
|
7655
|
+
const modulePath = kind === "scalar" ? path11.join(sys2.cwdPath, "lib", "__scalar", moduleName) : path11.join(sys2.cwdPath, "lib", folderName);
|
|
6637
7656
|
const relativePath = getRelative(workspace, modulePath);
|
|
6638
7657
|
const abstractPath = `${relativePath}/${moduleName}.abstract.md`;
|
|
6639
|
-
const abstractContent = await safeReadText(
|
|
7658
|
+
const abstractContent = await safeReadText(path11.join(workspace.workspaceRoot, abstractPath));
|
|
6640
7659
|
return {
|
|
6641
7660
|
kind,
|
|
6642
7661
|
name: moduleName,
|
|
@@ -6652,7 +7671,7 @@ var getSysModules = async (workspace, sys2, {
|
|
|
6652
7671
|
includeAbstractContent = false,
|
|
6653
7672
|
module: moduleFilter
|
|
6654
7673
|
} = {}) => {
|
|
6655
|
-
const libPath =
|
|
7674
|
+
const libPath = path11.join(sys2.cwdPath, "lib");
|
|
6656
7675
|
const entries = await safeReadDir(libPath);
|
|
6657
7676
|
const modules = [];
|
|
6658
7677
|
for (const entry of entries) {
|
|
@@ -6666,24 +7685,24 @@ var getSysModules = async (workspace, sys2, {
|
|
|
6666
7685
|
const serviceName = entry.name.replace(/^_+/, "");
|
|
6667
7686
|
if (moduleFilter && moduleFilter !== serviceName && moduleFilter !== entry.name)
|
|
6668
7687
|
continue;
|
|
6669
|
-
if (!await FileSys.fileExists(
|
|
7688
|
+
if (!await FileSys.fileExists(path11.join(libPath, entry.name, `${serviceName}.service.ts`)))
|
|
6670
7689
|
continue;
|
|
6671
7690
|
modules.push(await createModuleContext(workspace, sys2, "service", entry.name, serviceName, includeAbstractContent));
|
|
6672
7691
|
} else {
|
|
6673
7692
|
if (moduleFilter && moduleFilter !== entry.name)
|
|
6674
7693
|
continue;
|
|
6675
|
-
if (!await FileSys.fileExists(
|
|
7694
|
+
if (!await FileSys.fileExists(path11.join(libPath, entry.name, `${entry.name}.constant.ts`)))
|
|
6676
7695
|
continue;
|
|
6677
7696
|
modules.push(await createModuleContext(workspace, sys2, "domain", entry.name, entry.name, includeAbstractContent));
|
|
6678
7697
|
}
|
|
6679
7698
|
}
|
|
6680
|
-
const scalarRoot =
|
|
7699
|
+
const scalarRoot = path11.join(libPath, "__scalar");
|
|
6681
7700
|
for (const entry of await safeReadDir(scalarRoot)) {
|
|
6682
7701
|
if (!entry.isDirectory() || entry.name.startsWith("_"))
|
|
6683
7702
|
continue;
|
|
6684
7703
|
if (moduleFilter && moduleFilter !== entry.name)
|
|
6685
7704
|
continue;
|
|
6686
|
-
if (!await FileSys.fileExists(
|
|
7705
|
+
if (!await FileSys.fileExists(path11.join(scalarRoot, entry.name, `${entry.name}.constant.ts`)))
|
|
6687
7706
|
continue;
|
|
6688
7707
|
modules.push(await createModuleContext(workspace, sys2, "scalar", entry.name, entry.name, includeAbstractContent));
|
|
6689
7708
|
}
|
|
@@ -6695,7 +7714,7 @@ var getSysContext = async (workspace, type, name, options) => {
|
|
|
6695
7714
|
type,
|
|
6696
7715
|
name,
|
|
6697
7716
|
path: `${type}s/${name}`,
|
|
6698
|
-
hasConfig: await FileSys.fileExists(
|
|
7717
|
+
hasConfig: await FileSys.fileExists(path11.join(sys2.cwdPath, "akan.config.ts")),
|
|
6699
7718
|
modules: await getSysModules(workspace, sys2, {
|
|
6700
7719
|
includeAbstractContent: options.includeAbstractContent,
|
|
6701
7720
|
module: options.module
|
|
@@ -6706,13 +7725,13 @@ var getSysContext = async (workspace, type, name, options) => {
|
|
|
6706
7725
|
class AkanContextAnalyzer {
|
|
6707
7726
|
static async analyze(workspace, options = {}) {
|
|
6708
7727
|
const [appNames, libNames, pkgNames] = await workspace.getExecs();
|
|
6709
|
-
const rootPackageJson = await safeReadJson(
|
|
7728
|
+
const rootPackageJson = await safeReadJson(path11.join(workspace.workspaceRoot, "package.json"));
|
|
6710
7729
|
const filteredApps = options.app ? appNames.filter((name) => name === options.app) : appNames;
|
|
6711
7730
|
const [apps, libs, pkgs] = await Promise.all([
|
|
6712
7731
|
Promise.all(filteredApps.map((name) => getSysContext(workspace, "app", name, options))),
|
|
6713
7732
|
Promise.all(libNames.map((name) => getSysContext(workspace, "lib", name, options))),
|
|
6714
7733
|
Promise.all(pkgNames.map(async (name) => {
|
|
6715
|
-
const packageJson = await safeReadJson(
|
|
7734
|
+
const packageJson = await safeReadJson(path11.join(workspace.workspaceRoot, "pkgs", name, "package.json"));
|
|
6716
7735
|
return {
|
|
6717
7736
|
name,
|
|
6718
7737
|
path: `pkgs/${name}`,
|
|
@@ -6745,7 +7764,7 @@ class AkanContextAnalyzer {
|
|
|
6745
7764
|
repairAction("format", "akan repair format --target <app-or-lib-or-pkg>", "Run the formatter/linter repair path.", true)
|
|
6746
7765
|
];
|
|
6747
7766
|
for (const app of context.apps) {
|
|
6748
|
-
const appPath =
|
|
7767
|
+
const appPath = path11.join(workspace.workspaceRoot, app.path);
|
|
6749
7768
|
for (const entry of await safeReadDir(appPath)) {
|
|
6750
7769
|
const allowed = entry.isDirectory() ? appRootAllowDirs.has(entry.name) : appRootAllowFiles.has(entry.name);
|
|
6751
7770
|
if (!allowed) {
|
|
@@ -6769,7 +7788,7 @@ class AkanContextAnalyzer {
|
|
|
6769
7788
|
severity: strict ? "error" : "warning",
|
|
6770
7789
|
code: "module-abstract-missing",
|
|
6771
7790
|
path: module.abstract.path,
|
|
6772
|
-
message: `${
|
|
7791
|
+
message: `${capitalize3(module.kind)} module ${sys2.name}:${module.name} should include ${module.abstract.path}`,
|
|
6773
7792
|
repairActions: [action]
|
|
6774
7793
|
});
|
|
6775
7794
|
repairActions.push(action);
|
|
@@ -6781,14 +7800,14 @@ class AkanContextAnalyzer {
|
|
|
6781
7800
|
severity: "error",
|
|
6782
7801
|
code: "module-shape-invalid",
|
|
6783
7802
|
path: module.path,
|
|
6784
|
-
message: `${
|
|
7803
|
+
message: `${capitalize3(module.kind)} module ${sys2.name}:${module.name} is missing required files: ${missingFiles.join(", ")}`,
|
|
6785
7804
|
repairActions: [action]
|
|
6786
7805
|
});
|
|
6787
7806
|
repairActions.push(action);
|
|
6788
7807
|
}
|
|
6789
7808
|
if (module.kind !== "service" && module.files.includes(`${module.name}.dictionary.ts`)) {
|
|
6790
|
-
const constantPath =
|
|
6791
|
-
const dictionaryPath =
|
|
7809
|
+
const constantPath = path11.join(workspace.workspaceRoot, module.path, `${module.name}.constant.ts`);
|
|
7810
|
+
const dictionaryPath = path11.join(workspace.workspaceRoot, module.path, `${module.name}.dictionary.ts`);
|
|
6792
7811
|
const [constantContent, dictionaryContent] = await Promise.all([
|
|
6793
7812
|
safeReadText(constantPath),
|
|
6794
7813
|
safeReadText(dictionaryPath)
|
|
@@ -6860,6 +7879,543 @@ class AkanContextAnalyzer {
|
|
|
6860
7879
|
`;
|
|
6861
7880
|
}
|
|
6862
7881
|
}
|
|
7882
|
+
// pkgs/@akanjs/devkit/akanMcpContract.ts
|
|
7883
|
+
import path12 from "path";
|
|
7884
|
+
var emptySchema = { type: "object", properties: {} };
|
|
7885
|
+
var stringProperty = { type: "string" };
|
|
7886
|
+
var booleanProperty = { type: "boolean" };
|
|
7887
|
+
var objectProperty = { type: "object", additionalProperties: true };
|
|
7888
|
+
var stringArrayProperty = { type: "array", items: stringProperty };
|
|
7889
|
+
var inspectAkanContextRequestTypes = [
|
|
7890
|
+
"workspaceOverview",
|
|
7891
|
+
"moduleContext",
|
|
7892
|
+
"fieldInsertionContext",
|
|
7893
|
+
"workflowDiagnostics",
|
|
7894
|
+
"escape"
|
|
7895
|
+
];
|
|
7896
|
+
var inspectAkanContextRequestTypeProperty = { type: "string", enum: inspectAkanContextRequestTypes };
|
|
7897
|
+
var inspectAkanContextRequestBranches = [
|
|
7898
|
+
{
|
|
7899
|
+
type: "object",
|
|
7900
|
+
properties: { type: { const: "workspaceOverview" } },
|
|
7901
|
+
required: ["type"]
|
|
7902
|
+
},
|
|
7903
|
+
{
|
|
7904
|
+
type: "object",
|
|
7905
|
+
properties: { type: { const: "moduleContext" }, app: stringProperty, module: stringProperty },
|
|
7906
|
+
required: ["type", "app", "module"]
|
|
7907
|
+
},
|
|
7908
|
+
{
|
|
7909
|
+
type: "object",
|
|
7910
|
+
properties: {
|
|
7911
|
+
type: { const: "fieldInsertionContext" },
|
|
7912
|
+
app: stringProperty,
|
|
7913
|
+
module: stringProperty,
|
|
7914
|
+
field: stringProperty,
|
|
7915
|
+
fieldType: stringProperty
|
|
7916
|
+
},
|
|
7917
|
+
required: ["type", "app", "module", "field", "fieldType"]
|
|
7918
|
+
},
|
|
7919
|
+
{
|
|
7920
|
+
type: "object",
|
|
7921
|
+
properties: { type: { const: "workflowDiagnostics" }, runIdOrPlan: stringProperty },
|
|
7922
|
+
required: ["type", "runIdOrPlan"]
|
|
7923
|
+
},
|
|
7924
|
+
{
|
|
7925
|
+
type: "object",
|
|
7926
|
+
properties: { type: { const: "escape" }, reason: stringProperty, nextStep: stringProperty },
|
|
7927
|
+
required: ["type", "reason"]
|
|
7928
|
+
}
|
|
7929
|
+
];
|
|
7930
|
+
var inspectAkanContextInputSchema = {
|
|
7931
|
+
type: "object",
|
|
7932
|
+
properties: {
|
|
7933
|
+
question: {
|
|
7934
|
+
...stringProperty,
|
|
7935
|
+
description: "The user-facing question the agent is trying to answer before reading source bodies."
|
|
7936
|
+
},
|
|
7937
|
+
draft: {
|
|
7938
|
+
type: "object",
|
|
7939
|
+
properties: {
|
|
7940
|
+
reason: stringProperty,
|
|
7941
|
+
type: inspectAkanContextRequestTypeProperty
|
|
7942
|
+
},
|
|
7943
|
+
required: ["reason", "type"]
|
|
7944
|
+
},
|
|
7945
|
+
review: {
|
|
7946
|
+
...stringProperty,
|
|
7947
|
+
description: "A short self-review explaining why this minimal request is sufficient."
|
|
7948
|
+
},
|
|
7949
|
+
request: {
|
|
7950
|
+
type: "object",
|
|
7951
|
+
properties: {
|
|
7952
|
+
type: inspectAkanContextRequestTypeProperty,
|
|
7953
|
+
app: stringProperty,
|
|
7954
|
+
module: stringProperty,
|
|
7955
|
+
field: stringProperty,
|
|
7956
|
+
fieldType: stringProperty,
|
|
7957
|
+
runIdOrPlan: stringProperty,
|
|
7958
|
+
reason: stringProperty,
|
|
7959
|
+
nextStep: stringProperty
|
|
7960
|
+
},
|
|
7961
|
+
required: ["type"],
|
|
7962
|
+
oneOf: inspectAkanContextRequestBranches
|
|
7963
|
+
}
|
|
7964
|
+
},
|
|
7965
|
+
required: ["question", "draft", "review", "request"]
|
|
7966
|
+
};
|
|
7967
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7968
|
+
var slugPart = (value) => typeof value === "string" ? value.trim().replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() : "";
|
|
7969
|
+
var optionalString = (args, key) => {
|
|
7970
|
+
const value = args[key];
|
|
7971
|
+
return typeof value === "string" && value ? value : undefined;
|
|
7972
|
+
};
|
|
7973
|
+
var nestedStringArg = (args, key) => {
|
|
7974
|
+
const value = args[key];
|
|
7975
|
+
if (typeof value !== "string" || !value)
|
|
7976
|
+
throw new Error(`MCP tool argument "${key}" is required.`);
|
|
7977
|
+
return value;
|
|
7978
|
+
};
|
|
7979
|
+
var isInspectAkanContextRequestType = (value) => typeof value === "string" && inspectAkanContextRequestTypes.includes(value);
|
|
7980
|
+
var parseJsonOutput = (output) => JSON.parse(output);
|
|
7981
|
+
var workspacePath = (workspace, filePath) => path12.isAbsolute(filePath) ? filePath : path12.join(workspace.workspaceRoot, filePath);
|
|
7982
|
+
var defaultWorkflowPlanPath = (workflow, inputs) => {
|
|
7983
|
+
const slug = [
|
|
7984
|
+
slugPart(workflow),
|
|
7985
|
+
slugPart(inputs.app),
|
|
7986
|
+
slugPart(inputs.module),
|
|
7987
|
+
slugPart(inputs.field),
|
|
7988
|
+
slugPart(inputs.scalar),
|
|
7989
|
+
slugPart(inputs.surface),
|
|
7990
|
+
slugPart(inputs.mutation),
|
|
7991
|
+
slugPart(inputs.slice)
|
|
7992
|
+
].filter(Boolean).join("-");
|
|
7993
|
+
return `.akan/workflows/plans/${slug || "workflow-plan"}.json`;
|
|
7994
|
+
};
|
|
7995
|
+
var applyFirstPolicy = {
|
|
7996
|
+
mode: "apply-first",
|
|
7997
|
+
directSourceEdits: "fallback-only",
|
|
7998
|
+
applyRequiredWhen: ["plan_workflow returns planPath", "plan_workflow returns next.tool=apply_workflow"],
|
|
7999
|
+
approvalMeaning: "requiresApproval is an agent/user review signal before apply_workflow mutates files; it is not a separate MCP permission gate.",
|
|
8000
|
+
validationRequiredAfterApply: ["validationTarget", "applyReportPath"],
|
|
8001
|
+
fallbackAllowedWhen: [
|
|
8002
|
+
"list_workflows and explain_workflow show no matching workflow",
|
|
8003
|
+
"apply_workflow reports unsupported/no-op/failed diagnostics that require manual action",
|
|
8004
|
+
"recommendations include manual-action follow-up after workflow apply and repairs"
|
|
8005
|
+
],
|
|
8006
|
+
baselineDiagnosticsPolicy: "Do not fix unrelated baselineDiagnostics unless the user asks."
|
|
8007
|
+
};
|
|
8008
|
+
var stringArg = (args, key) => {
|
|
8009
|
+
const value = args[key];
|
|
8010
|
+
if (typeof value !== "string" || !value)
|
|
8011
|
+
throw new Error(`MCP tool argument "${key}" is required.`);
|
|
8012
|
+
return value;
|
|
8013
|
+
};
|
|
8014
|
+
var workflowInputsArg = (args) => {
|
|
8015
|
+
const value = args.inputs;
|
|
8016
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
8017
|
+
return {};
|
|
8018
|
+
return value;
|
|
8019
|
+
};
|
|
8020
|
+
var inspectAkanContextPropsArg = (args) => {
|
|
8021
|
+
const question = stringArg(args, "question");
|
|
8022
|
+
const review = stringArg(args, "review");
|
|
8023
|
+
if (!isRecord(args.draft))
|
|
8024
|
+
throw new Error('MCP tool argument "draft" is required.');
|
|
8025
|
+
if (!isRecord(args.request))
|
|
8026
|
+
throw new Error('MCP tool argument "request" is required.');
|
|
8027
|
+
if (!isInspectAkanContextRequestType(args.draft.type)) {
|
|
8028
|
+
throw new Error('MCP tool argument "draft.type" must be a supported inspect_akan_context request type.');
|
|
8029
|
+
}
|
|
8030
|
+
if (!isInspectAkanContextRequestType(args.request.type)) {
|
|
8031
|
+
throw new Error('MCP tool argument "request.type" must be a supported inspect_akan_context request type.');
|
|
8032
|
+
}
|
|
8033
|
+
const draft = { reason: nestedStringArg(args.draft, "reason"), type: args.draft.type };
|
|
8034
|
+
const request = args.request;
|
|
8035
|
+
if (request.type === "workspaceOverview")
|
|
8036
|
+
return { question, draft, review, request: { type: request.type } };
|
|
8037
|
+
if (request.type === "moduleContext")
|
|
8038
|
+
return {
|
|
8039
|
+
question,
|
|
8040
|
+
draft,
|
|
8041
|
+
review,
|
|
8042
|
+
request: {
|
|
8043
|
+
type: request.type,
|
|
8044
|
+
app: nestedStringArg(request, "app"),
|
|
8045
|
+
module: nestedStringArg(request, "module")
|
|
8046
|
+
}
|
|
8047
|
+
};
|
|
8048
|
+
if (request.type === "fieldInsertionContext")
|
|
8049
|
+
return {
|
|
8050
|
+
question,
|
|
8051
|
+
draft,
|
|
8052
|
+
review,
|
|
8053
|
+
request: {
|
|
8054
|
+
type: request.type,
|
|
8055
|
+
app: nestedStringArg(request, "app"),
|
|
8056
|
+
module: nestedStringArg(request, "module"),
|
|
8057
|
+
field: nestedStringArg(request, "field"),
|
|
8058
|
+
fieldType: nestedStringArg(request, "fieldType")
|
|
8059
|
+
}
|
|
8060
|
+
};
|
|
8061
|
+
if (request.type === "workflowDiagnostics")
|
|
8062
|
+
return {
|
|
8063
|
+
question,
|
|
8064
|
+
draft,
|
|
8065
|
+
review,
|
|
8066
|
+
request: { type: request.type, runIdOrPlan: nestedStringArg(request, "runIdOrPlan") }
|
|
8067
|
+
};
|
|
8068
|
+
return {
|
|
8069
|
+
question,
|
|
8070
|
+
draft,
|
|
8071
|
+
review,
|
|
8072
|
+
request: {
|
|
8073
|
+
type: "escape",
|
|
8074
|
+
reason: nestedStringArg(request, "reason"),
|
|
8075
|
+
nextStep: optionalString(request, "nextStep")
|
|
8076
|
+
}
|
|
8077
|
+
};
|
|
8078
|
+
};
|
|
8079
|
+
var inspectDiagnostic = (severity, code, message) => ({ severity, code, message });
|
|
8080
|
+
var moduleEvidence = (module) => ({
|
|
8081
|
+
kind: "module",
|
|
8082
|
+
target: `${module.sysName}:${module.name}`,
|
|
8083
|
+
path: module.path,
|
|
8084
|
+
summary: `${module.kind} module at ${module.path} with ${module.files.length} source file(s).`
|
|
8085
|
+
});
|
|
8086
|
+
var moduleCandidate = (module) => ({
|
|
8087
|
+
app: module.sysName,
|
|
8088
|
+
sysType: module.sysType,
|
|
8089
|
+
module: module.name,
|
|
8090
|
+
kind: module.kind,
|
|
8091
|
+
path: module.path,
|
|
8092
|
+
files: module.files
|
|
8093
|
+
});
|
|
8094
|
+
var readonlyMcpTools = [
|
|
8095
|
+
{
|
|
8096
|
+
name: "inspect_akan_context",
|
|
8097
|
+
description: "Read-only typed context inspection. Use question -> draft -> review -> request before source body reads; choose fieldInsertionContext for add-field evidence and escape when source body or outside evidence is required.",
|
|
8098
|
+
inputSchema: inspectAkanContextInputSchema
|
|
8099
|
+
},
|
|
8100
|
+
{
|
|
8101
|
+
name: "get_workspace_summary",
|
|
8102
|
+
description: "Legacy broad workspace summary. Prefer inspect_akan_context.workspaceOverview for typed source-body-free evidence.",
|
|
8103
|
+
inputSchema: emptySchema
|
|
8104
|
+
},
|
|
8105
|
+
{
|
|
8106
|
+
name: "list_apps",
|
|
8107
|
+
description: "List Akan apps from the workspace context without reading source bodies.",
|
|
8108
|
+
inputSchema: emptySchema
|
|
8109
|
+
},
|
|
8110
|
+
{
|
|
8111
|
+
name: "list_modules",
|
|
8112
|
+
description: "List Akan modules across apps and libs; use inspect_akan_context.moduleContext for typed evidence.",
|
|
8113
|
+
inputSchema: emptySchema
|
|
8114
|
+
},
|
|
8115
|
+
{
|
|
8116
|
+
name: "get_module_context",
|
|
8117
|
+
description: "Legacy broad module context. Pass app in monorepos; prefer inspect_akan_context.moduleContext or fieldInsertionContext for typed add-field evidence.",
|
|
8118
|
+
inputSchema: { type: "object", properties: { app: stringProperty, module: stringProperty }, required: ["module"] }
|
|
8119
|
+
},
|
|
8120
|
+
{
|
|
8121
|
+
name: "get_guideline",
|
|
8122
|
+
description: "Return an Akan agent guideline resource by name.",
|
|
8123
|
+
inputSchema: { type: "object", properties: { name: stringProperty }, required: ["name"] }
|
|
8124
|
+
},
|
|
8125
|
+
{
|
|
8126
|
+
name: "explain_command",
|
|
8127
|
+
description: "Explain one Akan CLI command and its agent-facing workflow policy.",
|
|
8128
|
+
inputSchema: { type: "object", properties: { command: stringProperty }, required: ["command"] }
|
|
8129
|
+
},
|
|
8130
|
+
{
|
|
8131
|
+
name: "doctor_workspace",
|
|
8132
|
+
description: "Report workspace diagnostics, optionally split into baseline and workflow scopes.",
|
|
8133
|
+
inputSchema: {
|
|
8134
|
+
type: "object",
|
|
8135
|
+
properties: {
|
|
8136
|
+
strict: booleanProperty,
|
|
8137
|
+
runIdOrPlan: stringProperty,
|
|
8138
|
+
changedFiles: stringArrayProperty,
|
|
8139
|
+
includeBaselineDetails: booleanProperty
|
|
8140
|
+
}
|
|
8141
|
+
}
|
|
8142
|
+
},
|
|
8143
|
+
{
|
|
8144
|
+
name: "get_validation_contract",
|
|
8145
|
+
description: "Return validation, artifact chain, and apply-first fallback policy.",
|
|
8146
|
+
inputSchema: emptySchema
|
|
8147
|
+
}
|
|
8148
|
+
];
|
|
8149
|
+
var planMcpTools = [
|
|
8150
|
+
{
|
|
8151
|
+
name: "list_workflows",
|
|
8152
|
+
description: "List available read-only workflow specs before creating a plan.",
|
|
8153
|
+
inputSchema: emptySchema
|
|
8154
|
+
},
|
|
8155
|
+
{
|
|
8156
|
+
name: "explain_workflow",
|
|
8157
|
+
description: "Explain one workflow's inputs, predicted changes, validation, and completion criteria.",
|
|
8158
|
+
inputSchema: { type: "object", properties: { workflow: stringProperty }, required: ["workflow"] }
|
|
8159
|
+
},
|
|
8160
|
+
{
|
|
8161
|
+
name: "plan_workflow",
|
|
8162
|
+
description: "Create a read-only workflow plan after context inspection and return planPath plus next.tool=apply_workflow.",
|
|
8163
|
+
inputSchema: {
|
|
8164
|
+
type: "object",
|
|
8165
|
+
properties: { workflow: stringProperty, inputs: objectProperty, out: stringProperty },
|
|
8166
|
+
required: ["workflow"]
|
|
8167
|
+
}
|
|
8168
|
+
}
|
|
8169
|
+
];
|
|
8170
|
+
var applyMcpTools = [
|
|
8171
|
+
{
|
|
8172
|
+
name: "apply_workflow",
|
|
8173
|
+
description: "Apply a stored workflow plan before direct edits and return validationTarget for run_validation.",
|
|
8174
|
+
inputSchema: {
|
|
8175
|
+
type: "object",
|
|
8176
|
+
properties: { planPath: stringProperty, dryRun: booleanProperty },
|
|
8177
|
+
required: ["planPath"]
|
|
8178
|
+
}
|
|
8179
|
+
},
|
|
8180
|
+
{
|
|
8181
|
+
name: "run_validation",
|
|
8182
|
+
description: "Validate a plan, apply report, validationTarget, or run artifact.",
|
|
8183
|
+
inputSchema: {
|
|
8184
|
+
type: "object",
|
|
8185
|
+
properties: { runIdOrPlan: stringProperty, includeBaselineDetails: booleanProperty },
|
|
8186
|
+
required: ["runIdOrPlan"]
|
|
8187
|
+
}
|
|
8188
|
+
},
|
|
8189
|
+
{
|
|
8190
|
+
name: "repair_generated",
|
|
8191
|
+
description: "Refresh generated Akan files before direct generated-file edits.",
|
|
8192
|
+
inputSchema: { type: "object", properties: { app: stringProperty }, required: ["app"] }
|
|
8193
|
+
},
|
|
8194
|
+
{
|
|
8195
|
+
name: "repair_imports",
|
|
8196
|
+
description: "Run the import repair path before manual import edits.",
|
|
8197
|
+
inputSchema: { type: "object", properties: { target: stringProperty }, required: ["target"] }
|
|
8198
|
+
},
|
|
8199
|
+
{
|
|
8200
|
+
name: "repair_module_shape",
|
|
8201
|
+
description: "Report module-shape repair actions before direct module file fixes.",
|
|
8202
|
+
inputSchema: {
|
|
8203
|
+
type: "object",
|
|
8204
|
+
properties: { app: stringProperty, module: stringProperty },
|
|
8205
|
+
required: ["app", "module"]
|
|
8206
|
+
}
|
|
8207
|
+
}
|
|
8208
|
+
];
|
|
8209
|
+
var listAkanMcpTools = (mode = "readonly") => {
|
|
8210
|
+
if (mode === "readonly")
|
|
8211
|
+
return readonlyMcpTools;
|
|
8212
|
+
if (mode === "plan")
|
|
8213
|
+
return [...readonlyMcpTools, ...planMcpTools];
|
|
8214
|
+
return [...readonlyMcpTools, ...planMcpTools, ...applyMcpTools];
|
|
8215
|
+
};
|
|
8216
|
+
var createAkanValidationContract = (listTools = listAkanMcpTools) => ({
|
|
8217
|
+
schemaVersion: 1,
|
|
8218
|
+
reports: ["WorkflowPlan", "WorkflowApplyReport", "WorkflowValidationRunReport", "RepairReport"],
|
|
8219
|
+
modes: {
|
|
8220
|
+
readonly: listTools("readonly").map((tool) => tool.name),
|
|
8221
|
+
plan: listTools("plan").map((tool) => tool.name),
|
|
8222
|
+
apply: listTools("apply").map((tool) => tool.name)
|
|
8223
|
+
},
|
|
8224
|
+
validationCommands: [
|
|
8225
|
+
"akan workflow validate <run-id-or-plan> --format json",
|
|
8226
|
+
"akan workflow report <run-id> --format json",
|
|
8227
|
+
"akan doctor --strict --format json"
|
|
8228
|
+
],
|
|
8229
|
+
validationFailureScopes: ["workspace-config", "environment", "source-change", "unknown"],
|
|
8230
|
+
artifactChainFields: ["planPath", "applyReportPath", "repairReportPath", "runId", "validationTarget", "next"],
|
|
8231
|
+
diagnosticScopes: ["baseline", "workflow", "unknown"],
|
|
8232
|
+
validationStatuses: {
|
|
8233
|
+
sourceStatus: ["passed", "failed", "unknown"],
|
|
8234
|
+
workspaceStatus: ["passed", "failed", "unknown"],
|
|
8235
|
+
validationCommandsStatus: ["passed", "failed", "unknown"],
|
|
8236
|
+
baselineStatus: ["passed", "failed", "unknown"],
|
|
8237
|
+
overallStatus: [
|
|
8238
|
+
"passed",
|
|
8239
|
+
"failed",
|
|
8240
|
+
"passed-with-baseline-blockers",
|
|
8241
|
+
"blocked-by-workspace-config",
|
|
8242
|
+
"blocked-by-environment"
|
|
8243
|
+
],
|
|
8244
|
+
baselineSummary: "Default MCP validation output summarizes baseline diagnostics; pass includeBaselineDetails=true for full baselineDiagnostics.",
|
|
8245
|
+
knownBlockers: "Repeated workspace-config/environment failures are summarized before command output."
|
|
8246
|
+
},
|
|
8247
|
+
moduleContextInputs: {
|
|
8248
|
+
module: "required",
|
|
8249
|
+
app: "required"
|
|
8250
|
+
},
|
|
8251
|
+
generatedFreshnessStatuses: ["fresh", "stale", "missing", "unknown"],
|
|
8252
|
+
toolingRolloutGate,
|
|
8253
|
+
directEditFallbackPolicy: applyFirstPolicy,
|
|
8254
|
+
applyReportFields: [
|
|
8255
|
+
"summary",
|
|
8256
|
+
"appliedCommands",
|
|
8257
|
+
"recommendedValidationCommands",
|
|
8258
|
+
"commands",
|
|
8259
|
+
"recommendations",
|
|
8260
|
+
"validationTarget"
|
|
8261
|
+
],
|
|
8262
|
+
repairCommands: [
|
|
8263
|
+
"akan repair generated --app <app-or-lib> --format json",
|
|
8264
|
+
"akan repair format --target <app-or-lib-or-pkg> --format json",
|
|
8265
|
+
"akan repair imports --target <app-or-lib-or-pkg> --format json",
|
|
8266
|
+
"akan repair dictionary --app <app-or-lib> --module <module> --format json",
|
|
8267
|
+
"akan repair module-shape --app <app-or-lib> --module <module> --format json"
|
|
8268
|
+
]
|
|
8269
|
+
});
|
|
8270
|
+
var inspectAkanContext = async (workspace, args) => {
|
|
8271
|
+
const props = inspectAkanContextPropsArg(args);
|
|
8272
|
+
const diagnostics = [];
|
|
8273
|
+
if (props.draft.type !== props.request.type) {
|
|
8274
|
+
diagnostics.push(inspectDiagnostic("warning", "inspect-draft-request-mismatch", `Draft chose ${props.draft.type}, but request uses ${props.request.type}.`));
|
|
8275
|
+
}
|
|
8276
|
+
const baseResult = (type, evidence, next, data) => ({
|
|
8277
|
+
schemaVersion: 1,
|
|
8278
|
+
type,
|
|
8279
|
+
question: props.question,
|
|
8280
|
+
diagnostics,
|
|
8281
|
+
evidence,
|
|
8282
|
+
next,
|
|
8283
|
+
...data ? { data } : {}
|
|
8284
|
+
});
|
|
8285
|
+
if (props.request.type === "escape") {
|
|
8286
|
+
return baseResult("escape", [{ kind: "escape", summary: props.request.reason }], {
|
|
8287
|
+
action: "escape",
|
|
8288
|
+
reason: props.request.reason,
|
|
8289
|
+
...props.request.nextStep ? { args: { nextStep: props.request.nextStep } } : {}
|
|
8290
|
+
}, { reason: props.request.reason, nextStep: props.request.nextStep ?? null });
|
|
8291
|
+
}
|
|
8292
|
+
if (props.request.type === "workflowDiagnostics") {
|
|
8293
|
+
const doctor = await AkanContextAnalyzer.doctor(workspace, {
|
|
8294
|
+
strict: true,
|
|
8295
|
+
runIdOrPlan: workspacePath(workspace, props.request.runIdOrPlan)
|
|
8296
|
+
});
|
|
8297
|
+
const baselineSummary = createWorkflowBaselineSummary((doctor.baselineDiagnostics ?? []).map((diagnostic) => ({
|
|
8298
|
+
severity: diagnostic.severity,
|
|
8299
|
+
code: diagnostic.code,
|
|
8300
|
+
message: diagnostic.message,
|
|
8301
|
+
scope: diagnostic.scope,
|
|
8302
|
+
context: diagnostic.context
|
|
8303
|
+
})), { detailsIncluded: false });
|
|
8304
|
+
diagnostics.push(...(doctor.workflowDiagnostics ?? doctor.diagnostics).map((diagnostic) => ({
|
|
8305
|
+
severity: diagnostic.severity,
|
|
8306
|
+
code: diagnostic.code,
|
|
8307
|
+
message: diagnostic.message,
|
|
8308
|
+
scope: diagnostic.scope,
|
|
8309
|
+
context: {
|
|
8310
|
+
...diagnostic.context,
|
|
8311
|
+
...diagnostic.path ? { paths: [diagnostic.path] } : {}
|
|
8312
|
+
}
|
|
8313
|
+
})));
|
|
8314
|
+
return baseResult("workflowDiagnostics", [
|
|
8315
|
+
{
|
|
8316
|
+
kind: "workflow",
|
|
8317
|
+
target: props.request.runIdOrPlan,
|
|
8318
|
+
summary: `Workflow diagnostics status is ${doctor.status}.`
|
|
8319
|
+
}
|
|
8320
|
+
], {
|
|
8321
|
+
action: doctor.status === "passed" ? "answer" : "validate",
|
|
8322
|
+
reason: doctor.status === "passed" ? "No strict workspace diagnostics were found for the workflow context." : "Review diagnostics before applying or manually editing source files."
|
|
8323
|
+
}, {
|
|
8324
|
+
status: doctor.status,
|
|
8325
|
+
baselineSummary,
|
|
8326
|
+
baselineDiagnostics: 0,
|
|
8327
|
+
workflowDiagnostics: doctor.workflowDiagnostics?.length ?? 0
|
|
8328
|
+
});
|
|
8329
|
+
}
|
|
8330
|
+
const context = await AkanContextAnalyzer.analyze(workspace, {
|
|
8331
|
+
app: props.request.type === "moduleContext" || props.request.type === "fieldInsertionContext" ? props.request.app : null,
|
|
8332
|
+
module: props.request.type === "moduleContext" || props.request.type === "fieldInsertionContext" ? props.request.module : null,
|
|
8333
|
+
includeAbstractContent: false
|
|
8334
|
+
});
|
|
8335
|
+
if (props.request.type === "workspaceOverview") {
|
|
8336
|
+
return baseResult("workspaceOverview", [
|
|
8337
|
+
{
|
|
8338
|
+
kind: "workspace",
|
|
8339
|
+
summary: `${context.repoName} has ${context.apps.length} app(s), ${context.libs.length} lib(s), and ${context.pkgs.length} package(s).`
|
|
8340
|
+
}
|
|
8341
|
+
], {
|
|
8342
|
+
action: "inspect",
|
|
8343
|
+
reason: "Choose moduleContext or fieldInsertionContext for module-scoped evidence before planning a workflow.",
|
|
8344
|
+
tool: "inspect_akan_context"
|
|
8345
|
+
}, {
|
|
8346
|
+
repoName: context.repoName,
|
|
8347
|
+
apps: context.apps.map((app) => ({ name: app.name, path: app.path, modules: app.modules.length })),
|
|
8348
|
+
libs: context.libs.map((lib) => ({ name: lib.name, path: lib.path, modules: lib.modules.length })),
|
|
8349
|
+
pkgs: context.pkgs.map((pkg) => ({ name: pkg.name, path: pkg.path, version: pkg.version ?? null })),
|
|
8350
|
+
generatedFiles: context.generatedFiles,
|
|
8351
|
+
validationCommands: context.validationCommands
|
|
8352
|
+
});
|
|
8353
|
+
}
|
|
8354
|
+
const modules = AkanContextAnalyzer.findModules(context, props.request.module, {
|
|
8355
|
+
app: props.request.app ?? null
|
|
8356
|
+
});
|
|
8357
|
+
if (modules.length === 0) {
|
|
8358
|
+
diagnostics.push(inspectDiagnostic("error", "inspect-module-not-found", `No module matched ${props.request.app ? `${props.request.app}:` : ""}${props.request.module}.`));
|
|
8359
|
+
return baseResult(props.request.type, [], {
|
|
8360
|
+
action: "escape",
|
|
8361
|
+
reason: "The requested module was not found in the workspace index; inspect workspace files or clarify the target."
|
|
8362
|
+
}, { candidates: [] });
|
|
8363
|
+
}
|
|
8364
|
+
if (!props.request.app && modules.length > 1) {
|
|
8365
|
+
diagnostics.push(inspectDiagnostic("error", "inspect-module-ambiguous", `Multiple modules match "${props.request.module}". Re-run with app to disambiguate.`));
|
|
8366
|
+
return baseResult(props.request.type, modules.map(moduleEvidence), {
|
|
8367
|
+
action: "clarify",
|
|
8368
|
+
reason: "Multiple modules have the same name; choose an app before planning a workflow."
|
|
8369
|
+
}, { candidates: modules.map(moduleCandidate) });
|
|
8370
|
+
}
|
|
8371
|
+
const module = modules[0];
|
|
8372
|
+
if (props.request.type === "moduleContext") {
|
|
8373
|
+
return baseResult("moduleContext", [moduleEvidence(module)], {
|
|
8374
|
+
action: "inspect",
|
|
8375
|
+
reason: "Use fieldInsertionContext when preparing add-field or escape when source body details are required.",
|
|
8376
|
+
tool: "inspect_akan_context"
|
|
8377
|
+
}, { module: moduleCandidate(module) });
|
|
8378
|
+
}
|
|
8379
|
+
if (module.kind !== "domain") {
|
|
8380
|
+
diagnostics.push(inspectDiagnostic("error", "field-insertion-unsupported-module-kind", `fieldInsertionContext currently targets domain modules; ${module.sysName}:${module.name} is ${module.kind}.`));
|
|
8381
|
+
}
|
|
8382
|
+
const moduleIndex2 = await buildAkanModuleContextIndex(workspace, module, { field: props.request.field });
|
|
8383
|
+
diagnostics.push(...moduleIndex2.diagnostics);
|
|
8384
|
+
return baseResult("fieldInsertionContext", [
|
|
8385
|
+
moduleEvidence(module),
|
|
8386
|
+
{
|
|
8387
|
+
kind: "field-insertion",
|
|
8388
|
+
target: `${module.sysName}:${module.name}.${props.request.field}`,
|
|
8389
|
+
path: module.path,
|
|
8390
|
+
summary: "M2 returns source-body-free AST index evidence for constant fields, dictionary model labels, and light projection fields."
|
|
8391
|
+
}
|
|
8392
|
+
], module.kind === "domain" ? {
|
|
8393
|
+
action: "plan_workflow",
|
|
8394
|
+
reason: "The module target is unambiguous; create an add-field workflow plan before source edits.",
|
|
8395
|
+
tool: "plan_workflow",
|
|
8396
|
+
args: {
|
|
8397
|
+
workflow: "add-field",
|
|
8398
|
+
inputs: {
|
|
8399
|
+
app: module.sysName,
|
|
8400
|
+
module: module.name,
|
|
8401
|
+
field: props.request.field,
|
|
8402
|
+
type: props.request.fieldType
|
|
8403
|
+
}
|
|
8404
|
+
}
|
|
8405
|
+
} : {
|
|
8406
|
+
action: "escape",
|
|
8407
|
+
reason: "This module kind is not a supported add-field target in the P1 context contract."
|
|
8408
|
+
}, {
|
|
8409
|
+
target: {
|
|
8410
|
+
app: module.sysName,
|
|
8411
|
+
module: module.name,
|
|
8412
|
+
field: props.request.field,
|
|
8413
|
+
fieldType: props.request.fieldType
|
|
8414
|
+
},
|
|
8415
|
+
files: moduleIndex2.files,
|
|
8416
|
+
moduleIndex: moduleIndex2
|
|
8417
|
+
});
|
|
8418
|
+
};
|
|
6863
8419
|
// pkgs/@akanjs/devkit/applicationBuildReporter.ts
|
|
6864
8420
|
import { Logger as Logger6 } from "akanjs/common";
|
|
6865
8421
|
|
|
@@ -6906,20 +8462,20 @@ Caused by: ${ApplicationBuildReporter.formatError(error.cause)}` : "";
|
|
|
6906
8462
|
}
|
|
6907
8463
|
// pkgs/@akanjs/devkit/applicationBuildRunner.ts
|
|
6908
8464
|
import { mkdir as mkdir8, rm as rm3 } from "fs/promises";
|
|
6909
|
-
import
|
|
8465
|
+
import path37 from "path";
|
|
6910
8466
|
|
|
6911
8467
|
// pkgs/@akanjs/devkit/frontendBuild/allRoutesBuilder.ts
|
|
6912
|
-
import
|
|
8468
|
+
import path22 from "path";
|
|
6913
8469
|
|
|
6914
8470
|
// pkgs/@akanjs/devkit/artifact/implicitRootLayout.ts
|
|
6915
8471
|
import { mkdir as mkdir3 } from "fs/promises";
|
|
6916
|
-
import
|
|
8472
|
+
import path13 from "path";
|
|
6917
8473
|
var LAYOUT_KEY_RE = /^\.\/(.+\/)?_layout\.(tsx|ts|jsx|js)$/;
|
|
6918
8474
|
async function appHasStModule(appCwdPath) {
|
|
6919
|
-
return Bun.file(
|
|
8475
|
+
return Bun.file(path13.join(appCwdPath, "lib", "st.ts")).exists();
|
|
6920
8476
|
}
|
|
6921
|
-
var IMPLICIT_LAYOUT_DIR =
|
|
6922
|
-
var IMPLICIT_DICT_DIR =
|
|
8477
|
+
var IMPLICIT_LAYOUT_DIR = path13.join(".akan", "generated", "root-layouts");
|
|
8478
|
+
var IMPLICIT_DICT_DIR = path13.join(".akan", "generated", "dict");
|
|
6923
8479
|
function getRootBoundarySegments(key) {
|
|
6924
8480
|
const match = LAYOUT_KEY_RE.exec(key);
|
|
6925
8481
|
if (!match)
|
|
@@ -6934,10 +8490,10 @@ function implicitRootLayoutKey(segments) {
|
|
|
6934
8490
|
}
|
|
6935
8491
|
function implicitRootLayoutAbsPath(appCwdPath, segments) {
|
|
6936
8492
|
const filename = segments.length ? `${segments.join("__")}__root_layout.tsx` : "__root_layout.tsx";
|
|
6937
|
-
return
|
|
8493
|
+
return path13.join(path13.resolve(appCwdPath), IMPLICIT_LAYOUT_DIR, filename);
|
|
6938
8494
|
}
|
|
6939
8495
|
function implicitDictionaryMacroAbsPath(appCwdPath) {
|
|
6940
|
-
return
|
|
8496
|
+
return path13.join(path13.resolve(appCwdPath), IMPLICIT_DICT_DIR, "useDict.ts");
|
|
6941
8497
|
}
|
|
6942
8498
|
function isRootBoundarySegments(segments, basePaths) {
|
|
6943
8499
|
const firstVisibleIndex = segments.findIndex((segment) => !/^\(.+\)$/.test(segment));
|
|
@@ -6960,7 +8516,7 @@ function findRootBoundaries(pageKeys, appCwdPath, basePaths) {
|
|
|
6960
8516
|
const id = segments.join("/");
|
|
6961
8517
|
boundaries.set(id, {
|
|
6962
8518
|
sourceKey: key,
|
|
6963
|
-
sourceAbsPath:
|
|
8519
|
+
sourceAbsPath: path13.resolve(appCwdPath, "page", key.replace(/^\.\//, "")),
|
|
6964
8520
|
segments
|
|
6965
8521
|
});
|
|
6966
8522
|
}
|
|
@@ -6978,21 +8534,21 @@ function findExplicitRootLayoutAbsPath(pageKeys, appCwdPath) {
|
|
|
6978
8534
|
const segments = getRootBoundarySegments(key);
|
|
6979
8535
|
return segments !== null && segments.length === 0;
|
|
6980
8536
|
});
|
|
6981
|
-
return rootLayoutKey ?
|
|
8537
|
+
return rootLayoutKey ? path13.resolve(appCwdPath, "page", rootLayoutKey.replace(/^\.\//, "")) : null;
|
|
6982
8538
|
}
|
|
6983
8539
|
function routePrefixForSegments(segments) {
|
|
6984
8540
|
const visible = segments.filter((segment) => !/^\(.+\)$/.test(segment));
|
|
6985
8541
|
return visible[0] ?? null;
|
|
6986
8542
|
}
|
|
6987
8543
|
async function assertEnvClientConvention(appCwdPath, appName) {
|
|
6988
|
-
const envPath =
|
|
8544
|
+
const envPath = path13.join(appCwdPath, "env", "env.client.ts");
|
|
6989
8545
|
if (!await Bun.file(envPath).exists()) {
|
|
6990
8546
|
throw new Error(`[route-convention] app "${appName}" must provide env/env.client.ts exporting "env" for generated System.Provider`);
|
|
6991
8547
|
}
|
|
6992
8548
|
}
|
|
6993
8549
|
async function writeGeneratedDictionaryMacroFile(appCwdPath, appName) {
|
|
6994
8550
|
const absPath = implicitDictionaryMacroAbsPath(appCwdPath);
|
|
6995
|
-
await mkdir3(
|
|
8551
|
+
await mkdir3(path13.dirname(absPath), { recursive: true });
|
|
6996
8552
|
await Bun.write(absPath, `import { getAllDictionary } from "@apps/${appName}/lib/dict" with { type: "macro" };
|
|
6997
8553
|
|
|
6998
8554
|
export const allDictionary = getAllDictionary();
|
|
@@ -7003,13 +8559,13 @@ async function writeGeneratedRootLayoutFile(opts) {
|
|
|
7003
8559
|
await assertEnvClientConvention(opts.appCwdPath, opts.appName);
|
|
7004
8560
|
const dictMacroAbsPath = opts.includeSystemProvider ? await writeGeneratedDictionaryMacroFile(opts.appCwdPath, opts.appName) : null;
|
|
7005
8561
|
const absPath = implicitRootLayoutAbsPath(opts.appCwdPath, opts.boundary.segments);
|
|
7006
|
-
await mkdir3(
|
|
7007
|
-
const dictMacroRel = dictMacroAbsPath ?
|
|
8562
|
+
await mkdir3(path13.dirname(absPath), { recursive: true });
|
|
8563
|
+
const dictMacroRel = dictMacroAbsPath ? path13.relative(path13.dirname(absPath), dictMacroAbsPath).split(path13.sep).join("/") : null;
|
|
7008
8564
|
const dictMacroSpecifier = dictMacroRel ? dictMacroRel.startsWith(".") ? dictMacroRel : `./${dictMacroRel}` : null;
|
|
7009
|
-
const sourceRel = opts.boundary.sourceAbsPath ?
|
|
8565
|
+
const sourceRel = opts.boundary.sourceAbsPath ? path13.relative(path13.dirname(absPath), opts.boundary.sourceAbsPath).split(path13.sep).join("/") : null;
|
|
7010
8566
|
const sourceSpecifier = sourceRel ? sourceRel.startsWith(".") ? sourceRel : `./${sourceRel}` : null;
|
|
7011
8567
|
const inheritedSourceAbsPath = opts.rootSourceAbsPath && opts.rootSourceAbsPath !== opts.boundary.sourceAbsPath ? opts.rootSourceAbsPath : null;
|
|
7012
|
-
const inheritedSourceRel = inheritedSourceAbsPath ?
|
|
8568
|
+
const inheritedSourceRel = inheritedSourceAbsPath ? path13.relative(path13.dirname(absPath), inheritedSourceAbsPath).split(path13.sep).join("/") : null;
|
|
7013
8569
|
const inheritedSourceSpecifier = inheritedSourceRel ? inheritedSourceRel.startsWith(".") ? inheritedSourceRel : `./${inheritedSourceRel}` : null;
|
|
7014
8570
|
const clientImport = opts.includeStInit ? `import { st } from "@apps/${opts.appName}/client";
|
|
7015
8571
|
void st;
|
|
@@ -7103,7 +8659,7 @@ export default function GeneratedLayout({ children, params, searchParams }: Layo
|
|
|
7103
8659
|
return absPath;
|
|
7104
8660
|
}
|
|
7105
8661
|
async function resolveSsrPageEntries(opts) {
|
|
7106
|
-
const absPageDir =
|
|
8662
|
+
const absPageDir = path13.resolve(opts.appCwdPath, "page");
|
|
7107
8663
|
const hasSt = await appHasStModule(opts.appCwdPath);
|
|
7108
8664
|
const basePaths = opts.basePaths ?? [];
|
|
7109
8665
|
const rootSourceAbsPath = findExplicitRootLayoutAbsPath(opts.pageKeys, opts.appCwdPath);
|
|
@@ -7114,7 +8670,7 @@ async function resolveSsrPageEntries(opts) {
|
|
|
7114
8670
|
}));
|
|
7115
8671
|
const base = opts.pageKeys.filter((key) => !rootLayoutKeys.has(key)).map((key) => ({
|
|
7116
8672
|
key,
|
|
7117
|
-
moduleAbsPath:
|
|
8673
|
+
moduleAbsPath: path13.resolve(absPageDir, key)
|
|
7118
8674
|
}));
|
|
7119
8675
|
const generated = await Promise.all(rootBoundaries.map(async (boundary) => ({
|
|
7120
8676
|
key: implicitRootLayoutKey(boundary.segments),
|
|
@@ -7138,14 +8694,14 @@ async function resolveSsrPageEntriesForApp(app, pageKeys) {
|
|
|
7138
8694
|
}
|
|
7139
8695
|
|
|
7140
8696
|
// pkgs/@akanjs/devkit/artifact/routeSeedIndex.ts
|
|
7141
|
-
import
|
|
8697
|
+
import path14 from "path";
|
|
7142
8698
|
import { assertUniqueRoutePatterns, compareRouteSpecificity, parseRouteModuleKey as parseRouteModuleKey2 } from "akanjs/common";
|
|
7143
8699
|
function computeRouteSeedIndex(pageEntries) {
|
|
7144
8700
|
const layoutsByPrefix = new Map;
|
|
7145
8701
|
const pagesBySegments = [];
|
|
7146
8702
|
for (const { key, moduleAbsPath, seedAbsPaths } of pageEntries) {
|
|
7147
8703
|
const parsed = parseRouteModuleKey2(key);
|
|
7148
|
-
const files = [
|
|
8704
|
+
const files = [path14.resolve(moduleAbsPath), ...(seedAbsPaths ?? []).map((seed) => path14.resolve(seed))];
|
|
7149
8705
|
if (parsed.kind === "layout") {
|
|
7150
8706
|
const prefix = parsed.routeSegments.join("/");
|
|
7151
8707
|
const prev = layoutsByPrefix.get(prefix) ?? [];
|
|
@@ -7182,7 +8738,7 @@ function computeRouteSeedIndex(pageEntries) {
|
|
|
7182
8738
|
}
|
|
7183
8739
|
var ROUTE_SEED_INDEX_JSON = "route-seed-index.json";
|
|
7184
8740
|
function serializeRouteSeedIndexForArtifact(index, artifactDir, options = {}) {
|
|
7185
|
-
const normalizedArtifactDir =
|
|
8741
|
+
const normalizedArtifactDir = path14.resolve(artifactDir);
|
|
7186
8742
|
if (options.production) {
|
|
7187
8743
|
return {
|
|
7188
8744
|
entries: index.entries.map((entry) => ({ routeId: entry.routeId }))
|
|
@@ -7197,22 +8753,22 @@ function serializeRouteSeedIndexForArtifact(index, artifactDir, options = {}) {
|
|
|
7197
8753
|
};
|
|
7198
8754
|
}
|
|
7199
8755
|
async function saveRouteSeedIndex(artifactDir, index, options = {}) {
|
|
7200
|
-
const absPath =
|
|
8756
|
+
const absPath = path14.join(path14.resolve(artifactDir), ROUTE_SEED_INDEX_JSON);
|
|
7201
8757
|
await Bun.write(absPath, `${JSON.stringify(serializeRouteSeedIndexForArtifact(index, artifactDir, options), null, 2)}
|
|
7202
8758
|
`);
|
|
7203
8759
|
return absPath;
|
|
7204
8760
|
}
|
|
7205
8761
|
function serializeArtifactPath(artifactPath, artifactDir) {
|
|
7206
|
-
if (!
|
|
8762
|
+
if (!path14.isAbsolute(artifactPath))
|
|
7207
8763
|
return artifactPath;
|
|
7208
|
-
return
|
|
8764
|
+
return path14.relative(artifactDir, artifactPath).split(path14.sep).join("/");
|
|
7209
8765
|
}
|
|
7210
8766
|
|
|
7211
8767
|
// pkgs/@akanjs/devkit/frontendBuild/clientEntryDiscovery.ts
|
|
7212
|
-
import
|
|
8768
|
+
import path17 from "path";
|
|
7213
8769
|
|
|
7214
8770
|
// pkgs/@akanjs/devkit/transforms/barrelAnalyzer.ts
|
|
7215
|
-
import
|
|
8771
|
+
import path15 from "path";
|
|
7216
8772
|
import { Logger as Logger7 } from "akanjs/common";
|
|
7217
8773
|
var REEXPORT_RE = /(?:^|\n)\s*export\s+(?:type\s+)?(?:(\*)(?:\s+as\s+(\w+))?|\{\s*([^}]*?)\s*\})\s+from\s+(["'])([^"']+)\4;?/g;
|
|
7218
8774
|
var LOCAL_NAMED_RE = /(?:^|\n)\s*export\s+\{\s*([^}]*?)\s*\}(?!\s*from)/g;
|
|
@@ -7335,7 +8891,7 @@ class BarrelAnalyzer {
|
|
|
7335
8891
|
}
|
|
7336
8892
|
#scanExports(source2, absFile) {
|
|
7337
8893
|
try {
|
|
7338
|
-
const transpiler = [".tsx", ".jsx"].includes(
|
|
8894
|
+
const transpiler = [".tsx", ".jsx"].includes(path15.extname(absFile)) ? this.#tsxTranspiler : this.#tsTranspiler;
|
|
7339
8895
|
const { exports } = transpiler.scan(source2);
|
|
7340
8896
|
return new Set(exports);
|
|
7341
8897
|
} catch (err) {
|
|
@@ -7344,16 +8900,16 @@ class BarrelAnalyzer {
|
|
|
7344
8900
|
}
|
|
7345
8901
|
}
|
|
7346
8902
|
#subpathFor(pkg, absFile) {
|
|
7347
|
-
const rel =
|
|
7348
|
-
if (!rel || rel.startsWith("..") ||
|
|
8903
|
+
const rel = path15.relative(pkg.pkgDir, absFile);
|
|
8904
|
+
if (!rel || rel.startsWith("..") || path15.isAbsolute(rel))
|
|
7349
8905
|
return null;
|
|
7350
8906
|
if (pkg.preserveFilePath)
|
|
7351
|
-
return `${pkg.pkgName}/${rel.split(
|
|
8907
|
+
return `${pkg.pkgName}/${rel.split(path15.sep).join("/")}`;
|
|
7352
8908
|
const noExt = stripKnownExt(rel);
|
|
7353
8909
|
const tail = collapseIndex(noExt);
|
|
7354
8910
|
if (tail === "")
|
|
7355
8911
|
return pkg.pkgName;
|
|
7356
|
-
return `${pkg.pkgName}/${tail.split(
|
|
8912
|
+
return `${pkg.pkgName}/${tail.split(path15.sep).join("/")}`;
|
|
7357
8913
|
}
|
|
7358
8914
|
async#resolveRel(fromFile, relSpec) {
|
|
7359
8915
|
if (this.#opts.resolveRelative)
|
|
@@ -7394,9 +8950,9 @@ var readIfExists = async (absFile) => {
|
|
|
7394
8950
|
return file.text();
|
|
7395
8951
|
};
|
|
7396
8952
|
var defaultResolveRelative = async (fromFile, relSpec) => {
|
|
7397
|
-
const baseDir =
|
|
7398
|
-
const joined =
|
|
7399
|
-
if (
|
|
8953
|
+
const baseDir = path15.dirname(fromFile);
|
|
8954
|
+
const joined = path15.resolve(baseDir, relSpec);
|
|
8955
|
+
if (path15.extname(joined)) {
|
|
7400
8956
|
if (await Bun.file(joined).exists())
|
|
7401
8957
|
return joined;
|
|
7402
8958
|
return null;
|
|
@@ -7407,7 +8963,7 @@ var defaultResolveRelative = async (fromFile, relSpec) => {
|
|
|
7407
8963
|
return cand;
|
|
7408
8964
|
}
|
|
7409
8965
|
for (const ext of CANDIDATE_EXTS) {
|
|
7410
|
-
const cand =
|
|
8966
|
+
const cand = path15.join(joined, `index${ext}`);
|
|
7411
8967
|
if (await Bun.file(cand).exists())
|
|
7412
8968
|
return cand;
|
|
7413
8969
|
}
|
|
@@ -7421,15 +8977,15 @@ var stripKnownExt = (relPath) => {
|
|
|
7421
8977
|
return relPath;
|
|
7422
8978
|
};
|
|
7423
8979
|
var collapseIndex = (relPathNoExt) => {
|
|
7424
|
-
const parts = relPathNoExt.split(
|
|
8980
|
+
const parts = relPathNoExt.split(path15.sep);
|
|
7425
8981
|
if (parts[parts.length - 1] === "index")
|
|
7426
8982
|
parts.pop();
|
|
7427
|
-
return parts.join(
|
|
8983
|
+
return parts.join(path15.sep);
|
|
7428
8984
|
};
|
|
7429
8985
|
|
|
7430
8986
|
// pkgs/@akanjs/devkit/transforms/barrelImportsPlugin.ts
|
|
7431
|
-
import
|
|
7432
|
-
import
|
|
8987
|
+
import path16 from "path";
|
|
8988
|
+
import ts7 from "typescript";
|
|
7433
8989
|
var createBarrelImportsPlugin = async (app, { skipPath = defaultSkipPath, pipeAfter } = {}) => {
|
|
7434
8990
|
const akanConfig2 = await app.getConfig();
|
|
7435
8991
|
const barrels = [...new Set(akanConfig2.barrelImports)].filter(Boolean);
|
|
@@ -7487,10 +9043,10 @@ var createTsconfigPackageResolver = async (app) => {
|
|
|
7487
9043
|
const raw = exact[0];
|
|
7488
9044
|
if (!raw)
|
|
7489
9045
|
return null;
|
|
7490
|
-
const entryFile =
|
|
9046
|
+
const entryFile = path16.resolve(app.workspace.workspaceRoot, raw);
|
|
7491
9047
|
if (!await Bun.file(entryFile).exists())
|
|
7492
9048
|
return null;
|
|
7493
|
-
const parsed =
|
|
9049
|
+
const parsed = path16.parse(entryFile);
|
|
7494
9050
|
const lastSlash = pkgName.lastIndexOf("/");
|
|
7495
9051
|
if (parsed.name !== "index" && lastSlash !== -1) {
|
|
7496
9052
|
const facet = pkgName.slice(lastSlash + 1);
|
|
@@ -7499,7 +9055,7 @@ var createTsconfigPackageResolver = async (app) => {
|
|
|
7499
9055
|
return { pkgName: parentSpec, entryFile, pkgDir: parsed.dir };
|
|
7500
9056
|
}
|
|
7501
9057
|
}
|
|
7502
|
-
return { pkgName, entryFile, pkgDir:
|
|
9058
|
+
return { pkgName, entryFile, pkgDir: path16.dirname(entryFile) };
|
|
7503
9059
|
}
|
|
7504
9060
|
for (const { prefix, replacements } of wildcardEntries) {
|
|
7505
9061
|
if (!pkgName.startsWith(prefix))
|
|
@@ -7509,7 +9065,7 @@ var createTsconfigPackageResolver = async (app) => {
|
|
|
7509
9065
|
if (!repl)
|
|
7510
9066
|
continue;
|
|
7511
9067
|
const replPath = repl.endsWith("/*") ? repl.slice(0, -1) : repl;
|
|
7512
|
-
const candidate =
|
|
9068
|
+
const candidate = path16.resolve(app.workspace.workspaceRoot, replPath + suffix);
|
|
7513
9069
|
for (const ext of CANDIDATE_EXTS2) {
|
|
7514
9070
|
const file = `${candidate}${ext}`;
|
|
7515
9071
|
if (await Bun.file(file).exists()) {
|
|
@@ -7517,14 +9073,14 @@ var createTsconfigPackageResolver = async (app) => {
|
|
|
7517
9073
|
if (lastSlash !== -1) {
|
|
7518
9074
|
const parentSpec = pkgName.slice(0, lastSlash);
|
|
7519
9075
|
if (parentSpec.length > 0) {
|
|
7520
|
-
return { pkgName: parentSpec, entryFile: file, pkgDir:
|
|
9076
|
+
return { pkgName: parentSpec, entryFile: file, pkgDir: path16.dirname(file) };
|
|
7521
9077
|
}
|
|
7522
9078
|
}
|
|
7523
|
-
return { pkgName, entryFile: file, pkgDir:
|
|
9079
|
+
return { pkgName, entryFile: file, pkgDir: path16.dirname(file) };
|
|
7524
9080
|
}
|
|
7525
9081
|
}
|
|
7526
9082
|
for (const ext of CANDIDATE_EXTS2) {
|
|
7527
|
-
const file =
|
|
9083
|
+
const file = path16.join(candidate, `index${ext}`);
|
|
7528
9084
|
if (await Bun.file(file).exists()) {
|
|
7529
9085
|
return { pkgName, entryFile: file, pkgDir: candidate };
|
|
7530
9086
|
}
|
|
@@ -7535,16 +9091,16 @@ var createTsconfigPackageResolver = async (app) => {
|
|
|
7535
9091
|
const exported = await resolveNodePackageExport(app.workspace.workspaceRoot, pkgName);
|
|
7536
9092
|
if (exported)
|
|
7537
9093
|
return exported;
|
|
7538
|
-
const pkgJsonPath =
|
|
9094
|
+
const pkgJsonPath = path16.join(app.workspace.workspaceRoot, "node_modules", pkgName, "package.json");
|
|
7539
9095
|
if (!await Bun.file(pkgJsonPath).exists())
|
|
7540
9096
|
return null;
|
|
7541
9097
|
try {
|
|
7542
9098
|
const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
|
|
7543
9099
|
const rel = pkgJson.module ?? pkgJson.main ?? "index.js";
|
|
7544
|
-
const entryFile =
|
|
9100
|
+
const entryFile = path16.resolve(path16.dirname(pkgJsonPath), rel);
|
|
7545
9101
|
if (!await Bun.file(entryFile).exists())
|
|
7546
9102
|
return null;
|
|
7547
|
-
return { pkgName, entryFile, pkgDir:
|
|
9103
|
+
return { pkgName, entryFile, pkgDir: path16.dirname(pkgJsonPath) };
|
|
7548
9104
|
} catch {
|
|
7549
9105
|
return null;
|
|
7550
9106
|
}
|
|
@@ -7558,22 +9114,22 @@ var resolveNodePackageExport = async (workspaceRoot, specifier) => {
|
|
|
7558
9114
|
const packageName = getPackageName(specifier);
|
|
7559
9115
|
if (!packageName)
|
|
7560
9116
|
return null;
|
|
7561
|
-
const pkgJsonPath =
|
|
9117
|
+
const pkgJsonPath = path16.join(workspaceRoot, "node_modules", packageName, "package.json");
|
|
7562
9118
|
if (!await Bun.file(pkgJsonPath).exists())
|
|
7563
9119
|
return null;
|
|
7564
9120
|
try {
|
|
7565
|
-
const pkgDir =
|
|
9121
|
+
const pkgDir = path16.dirname(pkgJsonPath);
|
|
7566
9122
|
const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
|
|
7567
9123
|
const subpath = specifier === packageName ? "." : `.${specifier.slice(packageName.length)}`;
|
|
7568
9124
|
const exported = resolvePackageExport(pkgJson.exports, subpath);
|
|
7569
9125
|
const rel = exported ?? (subpath === "." ? pkgJson.module ?? pkgJson.main ?? "index.js" : null);
|
|
7570
9126
|
if (!rel || !rel.startsWith("."))
|
|
7571
9127
|
return null;
|
|
7572
|
-
const entryFile = await resolveFileCandidate(
|
|
9128
|
+
const entryFile = await resolveFileCandidate(path16.resolve(pkgDir, rel));
|
|
7573
9129
|
if (!entryFile)
|
|
7574
9130
|
return null;
|
|
7575
9131
|
const pkgEntryName = specifier;
|
|
7576
|
-
return { pkgName: pkgEntryName, entryFile, pkgDir:
|
|
9132
|
+
return { pkgName: pkgEntryName, entryFile, pkgDir: path16.dirname(entryFile), preserveFilePath: true };
|
|
7577
9133
|
} catch {
|
|
7578
9134
|
return null;
|
|
7579
9135
|
}
|
|
@@ -7630,7 +9186,7 @@ var getPackageName = (specifier) => {
|
|
|
7630
9186
|
var resolveFileCandidate = async (candidate) => {
|
|
7631
9187
|
if (await Bun.file(candidate).exists())
|
|
7632
9188
|
return candidate;
|
|
7633
|
-
if (
|
|
9189
|
+
if (path16.extname(candidate))
|
|
7634
9190
|
return null;
|
|
7635
9191
|
for (const ext of CANDIDATE_EXTS2) {
|
|
7636
9192
|
const file = `${candidate}${ext}`;
|
|
@@ -7638,7 +9194,7 @@ var resolveFileCandidate = async (candidate) => {
|
|
|
7638
9194
|
return file;
|
|
7639
9195
|
}
|
|
7640
9196
|
for (const ext of CANDIDATE_EXTS2) {
|
|
7641
|
-
const file =
|
|
9197
|
+
const file = path16.join(candidate, `index${ext}`);
|
|
7642
9198
|
if (await Bun.file(file).exists())
|
|
7643
9199
|
return file;
|
|
7644
9200
|
}
|
|
@@ -7670,11 +9226,11 @@ var rewriteBarrelImports = async (source2, barrels, analyzer) => {
|
|
|
7670
9226
|
};
|
|
7671
9227
|
var findImportStatements = (source2) => {
|
|
7672
9228
|
const statements = [];
|
|
7673
|
-
const sourceFile2 =
|
|
9229
|
+
const sourceFile2 = ts7.createSourceFile("barrel-imports.tsx", source2, ts7.ScriptTarget.Latest, true, ts7.ScriptKind.TSX);
|
|
7674
9230
|
for (const statement of sourceFile2.statements) {
|
|
7675
|
-
if (!
|
|
9231
|
+
if (!ts7.isImportDeclaration(statement))
|
|
7676
9232
|
continue;
|
|
7677
|
-
if (!
|
|
9233
|
+
if (!ts7.isStringLiteral(statement.moduleSpecifier))
|
|
7678
9234
|
continue;
|
|
7679
9235
|
const importClause = statement.importClause;
|
|
7680
9236
|
if (!importClause)
|
|
@@ -7852,7 +9408,7 @@ class GraphClientEntryDiscovery {
|
|
|
7852
9408
|
}
|
|
7853
9409
|
invalidate(files) {
|
|
7854
9410
|
for (const file of files) {
|
|
7855
|
-
const absPath =
|
|
9411
|
+
const absPath = path17.resolve(file);
|
|
7856
9412
|
this.#readCache.delete(absPath);
|
|
7857
9413
|
this.#rewriteCache.delete(absPath);
|
|
7858
9414
|
this.#importCache.delete(absPath);
|
|
@@ -7862,7 +9418,7 @@ class GraphClientEntryDiscovery {
|
|
|
7862
9418
|
this.#reachableEntriesCache.clear();
|
|
7863
9419
|
}
|
|
7864
9420
|
async#fileExists(p) {
|
|
7865
|
-
const absPath =
|
|
9421
|
+
const absPath = path17.resolve(p);
|
|
7866
9422
|
let cached = this.#fileExistsCache.get(absPath);
|
|
7867
9423
|
if (!cached) {
|
|
7868
9424
|
cached = Bun.file(absPath).exists();
|
|
@@ -7871,7 +9427,7 @@ class GraphClientEntryDiscovery {
|
|
|
7871
9427
|
return cached;
|
|
7872
9428
|
}
|
|
7873
9429
|
#readFile(file) {
|
|
7874
|
-
const absPath =
|
|
9430
|
+
const absPath = path17.resolve(file);
|
|
7875
9431
|
let cached = this.#readCache.get(absPath);
|
|
7876
9432
|
if (!cached) {
|
|
7877
9433
|
cached = Bun.file(absPath).text().catch(() => null);
|
|
@@ -7880,7 +9436,7 @@ class GraphClientEntryDiscovery {
|
|
|
7880
9436
|
return cached;
|
|
7881
9437
|
}
|
|
7882
9438
|
async#resolveFileCandidate(absPathNoExt) {
|
|
7883
|
-
const cacheKey =
|
|
9439
|
+
const cacheKey = path17.resolve(absPathNoExt);
|
|
7884
9440
|
let cached = this.#resolvedFileCache.get(cacheKey);
|
|
7885
9441
|
if (cached)
|
|
7886
9442
|
return cached;
|
|
@@ -7893,7 +9449,7 @@ class GraphClientEntryDiscovery {
|
|
|
7893
9449
|
return f;
|
|
7894
9450
|
}
|
|
7895
9451
|
for (const ext of SOURCE_EXTS2) {
|
|
7896
|
-
const f =
|
|
9452
|
+
const f = path17.join(cacheKey, `index${ext}`);
|
|
7897
9453
|
if (await this.#fileExists(f))
|
|
7898
9454
|
return f;
|
|
7899
9455
|
}
|
|
@@ -7909,7 +9465,7 @@ class GraphClientEntryDiscovery {
|
|
|
7909
9465
|
return cached;
|
|
7910
9466
|
cached = (async () => {
|
|
7911
9467
|
if (spec.startsWith(".") || spec.startsWith("/")) {
|
|
7912
|
-
const abs = spec.startsWith("/") ? spec :
|
|
9468
|
+
const abs = spec.startsWith("/") ? spec : path17.resolve(importerDir, spec);
|
|
7913
9469
|
return this.#resolveFileCandidate(abs);
|
|
7914
9470
|
}
|
|
7915
9471
|
const pkg = await this.#resolvePackage(spec);
|
|
@@ -7921,7 +9477,7 @@ class GraphClientEntryDiscovery {
|
|
|
7921
9477
|
return cached;
|
|
7922
9478
|
}
|
|
7923
9479
|
async#getRewrittenSource(file, content) {
|
|
7924
|
-
const absPath =
|
|
9480
|
+
const absPath = path17.resolve(file);
|
|
7925
9481
|
let cached = this.#rewriteCache.get(absPath);
|
|
7926
9482
|
if (!cached) {
|
|
7927
9483
|
cached = (async () => {
|
|
@@ -7938,7 +9494,7 @@ class GraphClientEntryDiscovery {
|
|
|
7938
9494
|
return cached;
|
|
7939
9495
|
}
|
|
7940
9496
|
async#getImports(file, source2) {
|
|
7941
|
-
const absPath =
|
|
9497
|
+
const absPath = path17.resolve(file);
|
|
7942
9498
|
let cached = this.#importCache.get(absPath);
|
|
7943
9499
|
if (!cached) {
|
|
7944
9500
|
cached = Promise.resolve().then(() => {
|
|
@@ -7953,7 +9509,7 @@ class GraphClientEntryDiscovery {
|
|
|
7953
9509
|
return cached;
|
|
7954
9510
|
}
|
|
7955
9511
|
async#discoverFromFile(file, visiting) {
|
|
7956
|
-
const absPath =
|
|
9512
|
+
const absPath = path17.resolve(file);
|
|
7957
9513
|
const cached = this.#reachableEntriesCache.get(absPath);
|
|
7958
9514
|
if (cached)
|
|
7959
9515
|
return new Set(cached);
|
|
@@ -7970,7 +9526,7 @@ class GraphClientEntryDiscovery {
|
|
|
7970
9526
|
}
|
|
7971
9527
|
const source2 = await this.#getRewrittenSource(absPath, content);
|
|
7972
9528
|
const imports = await this.#getImports(absPath, source2);
|
|
7973
|
-
const importerDir =
|
|
9529
|
+
const importerDir = path17.dirname(absPath);
|
|
7974
9530
|
for (const imp of imports) {
|
|
7975
9531
|
const spec = imp.path;
|
|
7976
9532
|
if (!spec)
|
|
@@ -7996,14 +9552,14 @@ class GraphClientEntryDiscovery {
|
|
|
7996
9552
|
|
|
7997
9553
|
// pkgs/@akanjs/devkit/frontendBuild/routeClientBuilder.ts
|
|
7998
9554
|
import { mkdir as mkdir4 } from "fs/promises";
|
|
7999
|
-
import
|
|
9555
|
+
import path20 from "path";
|
|
8000
9556
|
|
|
8001
9557
|
// pkgs/@akanjs/devkit/transforms/rscUseClientTransform.ts
|
|
8002
|
-
import
|
|
9558
|
+
import path18 from "path";
|
|
8003
9559
|
var USE_CLIENT_RE2 = /^\s*(?:\/\*[\s\S]*?\*\/\s*|\/\/[^\n]*\n\s*)*["']use client["']/;
|
|
8004
9560
|
var IMPLICIT_ROOT_LAYOUT_RE = /[/\\]\.akan[/\\]generated[/\\](?:implicit-root-layout|root-layouts[/\\].*__root_layout)\.(tsx|ts|jsx|js)$/;
|
|
8005
9561
|
function toClientReferencePath(absPath, workspaceRoot) {
|
|
8006
|
-
return
|
|
9562
|
+
return path18.relative(path18.resolve(workspaceRoot), path18.resolve(absPath)).split(path18.sep).join("/");
|
|
8007
9563
|
}
|
|
8008
9564
|
function transformUseClient(source2, args) {
|
|
8009
9565
|
if (!USE_CLIENT_RE2.test(source2))
|
|
@@ -8039,7 +9595,7 @@ function loaderFor2(absPath) {
|
|
|
8039
9595
|
|
|
8040
9596
|
// pkgs/@akanjs/devkit/frontendBuild/clientEntriesBundler.ts
|
|
8041
9597
|
import fs2 from "fs";
|
|
8042
|
-
import
|
|
9598
|
+
import path19 from "path";
|
|
8043
9599
|
|
|
8044
9600
|
// pkgs/@akanjs/devkit/frontendBuild/clientBuildTypes.ts
|
|
8045
9601
|
var CLIENT_BUNDLE_NAMING = {
|
|
@@ -8128,23 +9684,23 @@ class ClientEntriesBundler {
|
|
|
8128
9684
|
};
|
|
8129
9685
|
}
|
|
8130
9686
|
async#createOpaqueEntryAliases() {
|
|
8131
|
-
const aliasDir =
|
|
9687
|
+
const aliasDir = path19.join(this.#app.cwdPath, ".akan", "generated", "client-entry-alias", this.#outputSubdir);
|
|
8132
9688
|
fs2.mkdirSync(aliasDir, { recursive: true });
|
|
8133
9689
|
const originalByAlias = new Map;
|
|
8134
9690
|
const aliasedEntries = await Promise.all(this.#entries.map(async (entry) => {
|
|
8135
|
-
const absEntry =
|
|
9691
|
+
const absEntry = path19.resolve(entry);
|
|
8136
9692
|
const hash = Bun.hash(`${this.#app.name}
|
|
8137
9693
|
${this.#outputSubdir}
|
|
8138
9694
|
${absEntry}`).toString(36);
|
|
8139
|
-
const aliasPath =
|
|
9695
|
+
const aliasPath = path19.join(aliasDir, `${hash}.tsx`);
|
|
8140
9696
|
await Bun.write(aliasPath, this.#createOpaqueEntryAliasSource(absEntry, await this.#scanEntryExportNames(absEntry)));
|
|
8141
|
-
originalByAlias.set(
|
|
9697
|
+
originalByAlias.set(path19.resolve(aliasPath), absEntry);
|
|
8142
9698
|
return aliasPath;
|
|
8143
9699
|
}));
|
|
8144
9700
|
return { entries: aliasedEntries, originalByAlias, aliasDir };
|
|
8145
9701
|
}
|
|
8146
9702
|
#createOpaqueEntryAliasSource(absEntry, exportNames) {
|
|
8147
|
-
const entryLit = JSON.stringify(
|
|
9703
|
+
const entryLit = JSON.stringify(path19.resolve(absEntry));
|
|
8148
9704
|
if (exportNames.length === 0)
|
|
8149
9705
|
return `export * from ${entryLit};
|
|
8150
9706
|
`;
|
|
@@ -8227,16 +9783,16 @@ ${absEntry}`).toString(36);
|
|
|
8227
9783
|
return rewritten;
|
|
8228
9784
|
}
|
|
8229
9785
|
#toServeUrl(absOutPath) {
|
|
8230
|
-
const rel =
|
|
9786
|
+
const rel = path19.relative(this.#outdir, absOutPath).split(path19.sep).join("/");
|
|
8231
9787
|
return `${this.#servePrefix}/${rel}`;
|
|
8232
9788
|
}
|
|
8233
9789
|
#absFromOutdir(p) {
|
|
8234
|
-
return
|
|
9790
|
+
return path19.isAbsolute(p) ? p : path19.resolve(this.#outdir, p);
|
|
8235
9791
|
}
|
|
8236
9792
|
#absFromEntryPoint(p) {
|
|
8237
|
-
if (
|
|
8238
|
-
return
|
|
8239
|
-
const candidates = [
|
|
9793
|
+
if (path19.isAbsolute(p))
|
|
9794
|
+
return path19.resolve(p);
|
|
9795
|
+
const candidates = [path19.resolve(process.cwd(), p), path19.resolve(this.#app.cwdPath, p)];
|
|
8240
9796
|
return candidates.find((candidate) => fs2.existsSync(candidate)) ?? candidates[0];
|
|
8241
9797
|
}
|
|
8242
9798
|
#collectChunkUrls(absOutPath, visited = new Set) {
|
|
@@ -8386,13 +9942,13 @@ class RouteClientBuilder {
|
|
|
8386
9942
|
ssrModuleMap[row.id][row.name] = { id: ssrOutput, chunks: [ssrOutput, ssrOutput], name: row.name, async: true };
|
|
8387
9943
|
}
|
|
8388
9944
|
for (const entry of bootstrapEntries.buildEntries) {
|
|
8389
|
-
const buildEntry =
|
|
8390
|
-
const originalEntry =
|
|
9945
|
+
const buildEntry = path20.resolve(entry);
|
|
9946
|
+
const originalEntry = path20.resolve(bootstrapEntries.originalByBuildEntry.get(buildEntry) ?? buildEntry);
|
|
8391
9947
|
if (!acceptedEntries.has(originalEntry))
|
|
8392
9948
|
continue;
|
|
8393
9949
|
const deps = new Set([originalEntry]);
|
|
8394
9950
|
for (const dep of browserBundle.entryDepsByAbsPath.get(buildEntry) ?? [])
|
|
8395
|
-
deps.add(
|
|
9951
|
+
deps.add(path20.resolve(dep));
|
|
8396
9952
|
const sortedDeps = [...deps].sort();
|
|
8397
9953
|
clientDepsByEntry[originalEntry] = sortedDeps;
|
|
8398
9954
|
for (const dep of sortedDeps)
|
|
@@ -8444,25 +10000,25 @@ class RouteClientBuilder {
|
|
|
8444
10000
|
}).bundle();
|
|
8445
10001
|
}
|
|
8446
10002
|
async#createBootstrapEntries(entries) {
|
|
8447
|
-
if (!await Bun.file(
|
|
10003
|
+
if (!await Bun.file(path20.join(this.#app.cwdPath, "lib", "st.ts")).exists()) {
|
|
8448
10004
|
return { buildEntries: entries, originalByBuildEntry: new Map };
|
|
8449
10005
|
}
|
|
8450
|
-
const outdir =
|
|
10006
|
+
const outdir = path20.join(this.#app.cwdPath, ".akan", "generated", "client-entry-bootstrap");
|
|
8451
10007
|
await mkdir4(outdir, { recursive: true });
|
|
8452
10008
|
const originalByBuildEntry = new Map;
|
|
8453
10009
|
const buildEntries = await Promise.all(entries.map(async (entry) => {
|
|
8454
|
-
const absEntry =
|
|
10010
|
+
const absEntry = path20.resolve(entry);
|
|
8455
10011
|
const hash = Bun.hash(`${this.#app.name}
|
|
8456
10012
|
${absEntry}`).toString(36);
|
|
8457
|
-
const base =
|
|
8458
|
-
const wrapperEntry =
|
|
10013
|
+
const base = path20.basename(absEntry).replace(/[^A-Za-z0-9._-]/g, "_");
|
|
10014
|
+
const wrapperEntry = path20.join(outdir, `${base}-${hash}.tsx`);
|
|
8459
10015
|
const exportNames = await this.#scanExportNames(absEntry);
|
|
8460
10016
|
await Bun.write(wrapperEntry, RouteClientBuilder.createStoreBootstrapEntrySource({
|
|
8461
10017
|
appName: this.#app.name,
|
|
8462
10018
|
originalEntry: absEntry,
|
|
8463
10019
|
exportNames
|
|
8464
10020
|
}));
|
|
8465
|
-
originalByBuildEntry.set(
|
|
10021
|
+
originalByBuildEntry.set(path20.resolve(wrapperEntry), absEntry);
|
|
8466
10022
|
return wrapperEntry;
|
|
8467
10023
|
}));
|
|
8468
10024
|
return { buildEntries, originalByBuildEntry };
|
|
@@ -8514,11 +10070,11 @@ ${defaultNames.map((name) => `export default ${name};`).join(`
|
|
|
8514
10070
|
try {
|
|
8515
10071
|
return Bun.resolveSync("akanjs/server", import.meta.dir);
|
|
8516
10072
|
} catch {
|
|
8517
|
-
return
|
|
10073
|
+
return path20.resolve(import.meta.dir, "../../../server/index.ts");
|
|
8518
10074
|
}
|
|
8519
10075
|
}
|
|
8520
10076
|
static createStoreBootstrapEntrySource(args) {
|
|
8521
|
-
const originalEntry = JSON.stringify(
|
|
10077
|
+
const originalEntry = JSON.stringify(path20.resolve(args.originalEntry));
|
|
8522
10078
|
const namedExports = args.exportNames.filter((name) => name !== "default");
|
|
8523
10079
|
const lines = [
|
|
8524
10080
|
`import ${JSON.stringify(`@apps/${args.appName}/client`)};`,
|
|
@@ -8544,7 +10100,7 @@ ${defaultNames.map((name) => `export default ${name};`).join(`
|
|
|
8544
10100
|
}
|
|
8545
10101
|
|
|
8546
10102
|
// pkgs/@akanjs/devkit/frontendBuild/routesManifestArtifactSerializer.ts
|
|
8547
|
-
import
|
|
10103
|
+
import path21 from "path";
|
|
8548
10104
|
|
|
8549
10105
|
class RoutesManifestArtifactSerializer {
|
|
8550
10106
|
#manifest;
|
|
@@ -8552,7 +10108,7 @@ class RoutesManifestArtifactSerializer {
|
|
|
8552
10108
|
#production;
|
|
8553
10109
|
constructor(manifest, artifactDir, options = {}) {
|
|
8554
10110
|
this.#manifest = manifest;
|
|
8555
|
-
this.#artifactDir =
|
|
10111
|
+
this.#artifactDir = path21.resolve(artifactDir);
|
|
8556
10112
|
this.#production = options.production ?? false;
|
|
8557
10113
|
}
|
|
8558
10114
|
static serialize(manifest, artifactDir, options = {}) {
|
|
@@ -8585,9 +10141,9 @@ class RoutesManifestArtifactSerializer {
|
|
|
8585
10141
|
};
|
|
8586
10142
|
}
|
|
8587
10143
|
#serializeArtifactPath(artifactPath) {
|
|
8588
|
-
if (!
|
|
10144
|
+
if (!path21.isAbsolute(artifactPath))
|
|
8589
10145
|
return artifactPath;
|
|
8590
|
-
return
|
|
10146
|
+
return path21.relative(this.#artifactDir, artifactPath).split(path21.sep).join("/");
|
|
8591
10147
|
}
|
|
8592
10148
|
}
|
|
8593
10149
|
|
|
@@ -8627,7 +10183,7 @@ class AllRoutesBuilder {
|
|
|
8627
10183
|
routeIds: this.#routeIds,
|
|
8628
10184
|
...this.#merged
|
|
8629
10185
|
};
|
|
8630
|
-
const manifestPath =
|
|
10186
|
+
const manifestPath = path22.join(path22.resolve(this.#artifactDir), "routes-manifest.json");
|
|
8631
10187
|
await Bun.write(manifestPath, `${JSON.stringify(RoutesManifestArtifactSerializer.serialize(manifest, this.#artifactDir, {
|
|
8632
10188
|
production: this.#command === "build"
|
|
8633
10189
|
}), null, 2)}
|
|
@@ -8664,12 +10220,12 @@ class AllRoutesBuilder {
|
|
|
8664
10220
|
}
|
|
8665
10221
|
// pkgs/@akanjs/devkit/frontendBuild/csrArtifactBuilder.ts
|
|
8666
10222
|
import { mkdir as mkdir5, rm, unlink } from "fs/promises";
|
|
8667
|
-
import
|
|
10223
|
+
import path24 from "path";
|
|
8668
10224
|
|
|
8669
10225
|
// pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
|
|
8670
10226
|
import fs3 from "fs";
|
|
8671
|
-
import
|
|
8672
|
-
import
|
|
10227
|
+
import path23 from "path";
|
|
10228
|
+
import ts8 from "typescript";
|
|
8673
10229
|
|
|
8674
10230
|
class PagesEntrySourceGenerator {
|
|
8675
10231
|
#pageEntries;
|
|
@@ -8681,7 +10237,7 @@ class PagesEntrySourceGenerator {
|
|
|
8681
10237
|
}
|
|
8682
10238
|
generate() {
|
|
8683
10239
|
const lines = this.#pageEntries.map(({ key, moduleAbsPath }) => {
|
|
8684
|
-
const absPath =
|
|
10240
|
+
const absPath = path23.resolve(moduleAbsPath);
|
|
8685
10241
|
return ` ${JSON.stringify(key)}: () => import(${JSON.stringify(absPath)}),`;
|
|
8686
10242
|
});
|
|
8687
10243
|
return `export const pages = {
|
|
@@ -8695,7 +10251,7 @@ ${lines.join(`
|
|
|
8695
10251
|
}
|
|
8696
10252
|
generateStatic() {
|
|
8697
10253
|
const imports = this.#pageEntries.map(({ moduleAbsPath }, index) => {
|
|
8698
|
-
const absPath =
|
|
10254
|
+
const absPath = path23.resolve(moduleAbsPath);
|
|
8699
10255
|
return `import * as page${index} from ${JSON.stringify(absPath)};`;
|
|
8700
10256
|
});
|
|
8701
10257
|
const entries = this.#pageEntries.map(({ key, moduleAbsPath }, index) => {
|
|
@@ -8712,8 +10268,8 @@ ${entries.join(`
|
|
|
8712
10268
|
}
|
|
8713
10269
|
static #hasAsyncDefaultExport(moduleAbsPath) {
|
|
8714
10270
|
try {
|
|
8715
|
-
const source2 = fs3.readFileSync(
|
|
8716
|
-
const sourceFile2 =
|
|
10271
|
+
const source2 = fs3.readFileSync(path23.resolve(moduleAbsPath), "utf8");
|
|
10272
|
+
const sourceFile2 = ts8.createSourceFile(moduleAbsPath, source2, ts8.ScriptTarget.Latest, true, PagesEntrySourceGenerator.#scriptKind(moduleAbsPath));
|
|
8717
10273
|
return PagesEntrySourceGenerator.#sourceFileHasAsyncDefaultExport(sourceFile2);
|
|
8718
10274
|
} catch {
|
|
8719
10275
|
return false;
|
|
@@ -8723,31 +10279,31 @@ ${entries.join(`
|
|
|
8723
10279
|
const asyncBindings = new Map;
|
|
8724
10280
|
let defaultIdentifier = null;
|
|
8725
10281
|
for (const statement of sourceFile2.statements) {
|
|
8726
|
-
if (
|
|
8727
|
-
if (PagesEntrySourceGenerator.#hasModifier(statement,
|
|
8728
|
-
return PagesEntrySourceGenerator.#hasModifier(statement,
|
|
10282
|
+
if (ts8.isFunctionDeclaration(statement)) {
|
|
10283
|
+
if (PagesEntrySourceGenerator.#hasModifier(statement, ts8.SyntaxKind.DefaultKeyword)) {
|
|
10284
|
+
return PagesEntrySourceGenerator.#hasModifier(statement, ts8.SyntaxKind.AsyncKeyword);
|
|
8729
10285
|
}
|
|
8730
10286
|
if (statement.name) {
|
|
8731
|
-
asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement,
|
|
10287
|
+
asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement, ts8.SyntaxKind.AsyncKeyword));
|
|
8732
10288
|
}
|
|
8733
10289
|
continue;
|
|
8734
10290
|
}
|
|
8735
|
-
if (
|
|
10291
|
+
if (ts8.isVariableStatement(statement)) {
|
|
8736
10292
|
for (const declaration of statement.declarationList.declarations) {
|
|
8737
|
-
if (!
|
|
10293
|
+
if (!ts8.isIdentifier(declaration.name))
|
|
8738
10294
|
continue;
|
|
8739
10295
|
asyncBindings.set(declaration.name.text, PagesEntrySourceGenerator.#isAsyncFunctionExpression(declaration.initializer));
|
|
8740
10296
|
}
|
|
8741
10297
|
continue;
|
|
8742
10298
|
}
|
|
8743
|
-
if (
|
|
10299
|
+
if (ts8.isExportAssignment(statement)) {
|
|
8744
10300
|
if (PagesEntrySourceGenerator.#isAsyncFunctionExpression(statement.expression))
|
|
8745
10301
|
return true;
|
|
8746
|
-
if (
|
|
10302
|
+
if (ts8.isIdentifier(statement.expression))
|
|
8747
10303
|
defaultIdentifier = statement.expression.text;
|
|
8748
10304
|
continue;
|
|
8749
10305
|
}
|
|
8750
|
-
if (
|
|
10306
|
+
if (ts8.isExportDeclaration(statement) && statement.exportClause && ts8.isNamedExports(statement.exportClause)) {
|
|
8751
10307
|
const exportClause = statement.exportClause;
|
|
8752
10308
|
for (const specifier of exportClause.elements) {
|
|
8753
10309
|
if (specifier.name.text !== "default")
|
|
@@ -8759,13 +10315,13 @@ ${entries.join(`
|
|
|
8759
10315
|
return defaultIdentifier ? asyncBindings.get(defaultIdentifier) === true : false;
|
|
8760
10316
|
}
|
|
8761
10317
|
static #hasModifier(node, kind) {
|
|
8762
|
-
return
|
|
10318
|
+
return ts8.canHaveModifiers(node) && (ts8.getModifiers(node)?.some((modifier) => modifier.kind === kind) ?? false);
|
|
8763
10319
|
}
|
|
8764
10320
|
static #isAsyncFunctionExpression(node) {
|
|
8765
|
-
return Boolean(node && (
|
|
10321
|
+
return Boolean(node && (ts8.isArrowFunction(node) || ts8.isFunctionExpression(node)) && PagesEntrySourceGenerator.#hasModifier(node, ts8.SyntaxKind.AsyncKeyword));
|
|
8766
10322
|
}
|
|
8767
10323
|
static #scriptKind(moduleAbsPath) {
|
|
8768
|
-
return moduleAbsPath.endsWith(".tsx") || moduleAbsPath.endsWith(".jsx") ?
|
|
10324
|
+
return moduleAbsPath.endsWith(".tsx") || moduleAbsPath.endsWith(".jsx") ? ts8.ScriptKind.TSX : ts8.ScriptKind.TS;
|
|
8769
10325
|
}
|
|
8770
10326
|
}
|
|
8771
10327
|
|
|
@@ -8791,7 +10347,7 @@ class CsrArtifactBuilder {
|
|
|
8791
10347
|
const csrBasePaths = [...akanConfig2.basePaths];
|
|
8792
10348
|
const htmlEntries = csrBasePaths.length > 0 ? csrBasePaths : ["index"];
|
|
8793
10349
|
await rm(this.#outputDir, { recursive: true, force: true });
|
|
8794
|
-
await mkdir5(
|
|
10350
|
+
await mkdir5(path24.join(this.#app.cwdPath, ".akan/generated/csr"), { recursive: true });
|
|
8795
10351
|
const generatedHtmlFiles = Object.fromEntries(htmlEntries.map((basePath2) => this.#createHtmlFile(basePath2)));
|
|
8796
10352
|
const result = await Bun.build({
|
|
8797
10353
|
target: "browser",
|
|
@@ -8823,7 +10379,7 @@ ${logs}` : ""}`);
|
|
|
8823
10379
|
return { outputDir: this.#outputDir };
|
|
8824
10380
|
}
|
|
8825
10381
|
get #outputDir() {
|
|
8826
|
-
return
|
|
10382
|
+
return path24.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, this.#command === "build" ? "csr" : ".akan/artifact/csr");
|
|
8827
10383
|
}
|
|
8828
10384
|
#define() {
|
|
8829
10385
|
const nodeEnv = this.#command === "build" ? "production" : "development";
|
|
@@ -8854,8 +10410,8 @@ ${logs}` : ""}`);
|
|
|
8854
10410
|
];
|
|
8855
10411
|
}
|
|
8856
10412
|
async#loadCsrArtifact() {
|
|
8857
|
-
const artifactDir =
|
|
8858
|
-
const artifactFile = Bun.file(
|
|
10413
|
+
const artifactDir = path24.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact");
|
|
10414
|
+
const artifactFile = Bun.file(path24.join(artifactDir, "base-artifact.json"));
|
|
8859
10415
|
if (!await artifactFile.exists())
|
|
8860
10416
|
return { cssAssets: {} };
|
|
8861
10417
|
const artifact = await artifactFile.json();
|
|
@@ -8868,7 +10424,7 @@ ${logs}` : ""}`);
|
|
|
8868
10424
|
const htmlFile = Bun.file(htmlPath);
|
|
8869
10425
|
if (!await htmlFile.exists())
|
|
8870
10426
|
continue;
|
|
8871
|
-
const basePath2 =
|
|
10427
|
+
const basePath2 = path24.basename(htmlPath, ".html") === "index" ? "" : path24.basename(htmlPath, ".html");
|
|
8872
10428
|
const inlined = await this.#inlineHtmlAssets(await htmlFile.text(), htmlPath, cssAssets[basePath2]);
|
|
8873
10429
|
for (const filePath of inlined.jsFiles)
|
|
8874
10430
|
jsFiles.add(filePath);
|
|
@@ -8910,7 +10466,7 @@ ${remainingAssets.join(`
|
|
|
8910
10466
|
next = CsrArtifactBuilder.injectBeforeHeadEnd(next, style);
|
|
8911
10467
|
}
|
|
8912
10468
|
if (cssAsset) {
|
|
8913
|
-
const cssPath =
|
|
10469
|
+
const cssPath = path24.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact", cssAsset.cssRelPath);
|
|
8914
10470
|
const css = await Bun.file(cssPath).text();
|
|
8915
10471
|
const style = CsrArtifactBuilder.createInlineStyle(css);
|
|
8916
10472
|
if (!next.includes(style))
|
|
@@ -8981,16 +10537,16 @@ ${CsrArtifactBuilder.escapeInlineScript(await loadScript(src))}
|
|
|
8981
10537
|
throw new Error(`[csr-build] cannot inline external script: ${src}`);
|
|
8982
10538
|
}
|
|
8983
10539
|
const normalized = src.startsWith("/") ? src.slice(1) : src;
|
|
8984
|
-
return
|
|
10540
|
+
return path24.resolve(path24.dirname(htmlPath), normalized);
|
|
8985
10541
|
}
|
|
8986
10542
|
}
|
|
8987
10543
|
// pkgs/@akanjs/devkit/frontendBuild/cssCompiler.ts
|
|
8988
|
-
import
|
|
10544
|
+
import path26 from "path";
|
|
8989
10545
|
import { Logger as Logger8 } from "akanjs/common";
|
|
8990
10546
|
import { compile } from "tailwindcss";
|
|
8991
10547
|
|
|
8992
10548
|
// pkgs/@akanjs/devkit/frontendBuild/cssImportResolver.ts
|
|
8993
|
-
import
|
|
10549
|
+
import path25 from "path";
|
|
8994
10550
|
var CSS_IMPORT_EXTS = ["", ".css", "/styles.css", "/index.css"];
|
|
8995
10551
|
|
|
8996
10552
|
class CssImportResolver {
|
|
@@ -9043,7 +10599,7 @@ class CssImportResolver {
|
|
|
9043
10599
|
const exact = this.#paths[id];
|
|
9044
10600
|
if (exact) {
|
|
9045
10601
|
for (const repl of exact) {
|
|
9046
|
-
const resolved = await this.#firstExisting(
|
|
10602
|
+
const resolved = await this.#firstExisting(path25.resolve(this.#workspaceRoot, repl));
|
|
9047
10603
|
if (resolved)
|
|
9048
10604
|
return resolved;
|
|
9049
10605
|
}
|
|
@@ -9054,7 +10610,7 @@ class CssImportResolver {
|
|
|
9054
10610
|
const suffix = id.slice(prefix.length);
|
|
9055
10611
|
for (const repl of replacements) {
|
|
9056
10612
|
const replPath = repl.endsWith("/*") ? repl.slice(0, -1) : repl;
|
|
9057
|
-
const resolved = await this.#firstExisting(
|
|
10613
|
+
const resolved = await this.#firstExisting(path25.resolve(this.#workspaceRoot, replPath + suffix));
|
|
9058
10614
|
if (resolved)
|
|
9059
10615
|
return resolved;
|
|
9060
10616
|
}
|
|
@@ -9084,25 +10640,25 @@ class CssImportResolver {
|
|
|
9084
10640
|
try {
|
|
9085
10641
|
if (!await Bun.file(pkgPath).exists())
|
|
9086
10642
|
return null;
|
|
9087
|
-
const pkgDir =
|
|
10643
|
+
const pkgDir = path25.dirname(pkgPath);
|
|
9088
10644
|
const pkg = await Bun.file(pkgPath).json();
|
|
9089
10645
|
const subpath = id === pkgName ? "." : `.${id.slice(pkgName.length)}`;
|
|
9090
10646
|
const exportValue = pkg.exports?.[subpath];
|
|
9091
10647
|
const styleEntry = (typeof exportValue === "string" ? exportValue : exportValue?.style || exportValue?.import || exportValue?.default) || pkg.exports?.["."]?.style || pkg.style || "index.css";
|
|
9092
|
-
return await this.#firstExisting(
|
|
10648
|
+
return await this.#firstExisting(path25.resolve(pkgDir, styleEntry));
|
|
9093
10649
|
} catch {
|
|
9094
10650
|
return null;
|
|
9095
10651
|
}
|
|
9096
10652
|
}
|
|
9097
10653
|
#resolutionBases(fromBase) {
|
|
9098
|
-
return [fromBase, this.#workspaceRoot,
|
|
10654
|
+
return [fromBase, this.#workspaceRoot, path25.dirname(Bun.main), path25.resolve(path25.dirname(Bun.main), "../..")];
|
|
9099
10655
|
}
|
|
9100
10656
|
#packageJsonCandidates(pkgName) {
|
|
9101
10657
|
return [
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
|
|
10658
|
+
path25.join(this.#workspaceRoot, "pkgs", pkgName, "package.json"),
|
|
10659
|
+
path25.join(this.#workspaceRoot, "node_modules", pkgName, "package.json"),
|
|
10660
|
+
path25.join(path25.dirname(Bun.main), "node_modules", pkgName, "package.json"),
|
|
10661
|
+
path25.join(path25.dirname(Bun.main), "../../", pkgName, "package.json")
|
|
9106
10662
|
];
|
|
9107
10663
|
}
|
|
9108
10664
|
async#firstExisting(basePath2) {
|
|
@@ -9120,7 +10676,7 @@ class CssImportResolver {
|
|
|
9120
10676
|
return parts[0] ?? null;
|
|
9121
10677
|
}
|
|
9122
10678
|
static isCssFile(filePath) {
|
|
9123
|
-
return
|
|
10679
|
+
return path25.extname(filePath) === ".css";
|
|
9124
10680
|
}
|
|
9125
10681
|
}
|
|
9126
10682
|
|
|
@@ -9187,7 +10743,7 @@ class CssCompiler {
|
|
|
9187
10743
|
pageKeys
|
|
9188
10744
|
} = {}) {
|
|
9189
10745
|
pageKeys ??= await this.#app.getPageKeys({ refresh });
|
|
9190
|
-
const seeds = pageKeys.map((key) =>
|
|
10746
|
+
const seeds = pageKeys.map((key) => path26.resolve(this.#app.cwdPath, "page", key));
|
|
9191
10747
|
const cssFiles = new Set;
|
|
9192
10748
|
const sourceFiles = new Set;
|
|
9193
10749
|
const queue = [...seeds];
|
|
@@ -9219,7 +10775,7 @@ class CssCompiler {
|
|
|
9219
10775
|
} catch {
|
|
9220
10776
|
continue;
|
|
9221
10777
|
}
|
|
9222
|
-
const importerDir =
|
|
10778
|
+
const importerDir = path26.dirname(filePath);
|
|
9223
10779
|
for (const imp of imports) {
|
|
9224
10780
|
const spec = imp.path;
|
|
9225
10781
|
if (!spec)
|
|
@@ -9245,7 +10801,7 @@ class CssCompiler {
|
|
|
9245
10801
|
const compileStarted = Date.now();
|
|
9246
10802
|
const compilers = await Promise.all(cssPaths.map(async (cssPath) => {
|
|
9247
10803
|
const css = await Bun.file(cssPath).text();
|
|
9248
|
-
const base =
|
|
10804
|
+
const base = path26.dirname(cssPath);
|
|
9249
10805
|
const compiler = await compile(css, {
|
|
9250
10806
|
base,
|
|
9251
10807
|
loadStylesheet: (id, fromBase) => this.#loadStylesheet(id, fromBase),
|
|
@@ -9276,11 +10832,11 @@ class CssCompiler {
|
|
|
9276
10832
|
async#loadStylesheet(id, fromBase) {
|
|
9277
10833
|
const p = await this.#resolveCssImport(id, fromBase);
|
|
9278
10834
|
const content = await Bun.file(p).text();
|
|
9279
|
-
return { path: p, base:
|
|
10835
|
+
return { path: p, base: path26.dirname(p), content };
|
|
9280
10836
|
}
|
|
9281
10837
|
async#resolveCssImport(id, fromBase) {
|
|
9282
10838
|
if (id.startsWith(".") || id.startsWith("/"))
|
|
9283
|
-
return
|
|
10839
|
+
return path26.resolve(fromBase, id);
|
|
9284
10840
|
const resolver = await this.#getCssImportResolver();
|
|
9285
10841
|
const resolved = await resolver.resolve(id, fromBase);
|
|
9286
10842
|
if (resolved)
|
|
@@ -9296,11 +10852,11 @@ class CssCompiler {
|
|
|
9296
10852
|
async#loadModule(id, fromBase) {
|
|
9297
10853
|
const p = __require.resolve(id, { paths: [fromBase] });
|
|
9298
10854
|
const mod = await import(p);
|
|
9299
|
-
return { path: p, base:
|
|
10855
|
+
return { path: p, base: path26.dirname(p), module: mod.default ?? mod };
|
|
9300
10856
|
}
|
|
9301
10857
|
async#resolveSourceImport(id, fromBase, resolvePackage) {
|
|
9302
10858
|
if (id.startsWith(".") || id.startsWith("/")) {
|
|
9303
|
-
const abs = id.startsWith("/") ? id :
|
|
10859
|
+
const abs = id.startsWith("/") ? id : path26.resolve(fromBase, id);
|
|
9304
10860
|
return resolveSourceFileCandidate(abs);
|
|
9305
10861
|
}
|
|
9306
10862
|
const pkg = await resolvePackage(id);
|
|
@@ -9342,7 +10898,7 @@ async function resolveSourceFileCandidate(absPathNoExt) {
|
|
|
9342
10898
|
return filePath;
|
|
9343
10899
|
}
|
|
9344
10900
|
for (const ext of SOURCE_EXTS3) {
|
|
9345
|
-
const filePath =
|
|
10901
|
+
const filePath = path26.join(absPathNoExt, `index${ext}`);
|
|
9346
10902
|
if (await Bun.file(filePath).exists())
|
|
9347
10903
|
return filePath;
|
|
9348
10904
|
}
|
|
@@ -9365,19 +10921,19 @@ function resolveSourceWithRequire(id, fromBase) {
|
|
|
9365
10921
|
}
|
|
9366
10922
|
}
|
|
9367
10923
|
function isSourceFile(filePath) {
|
|
9368
|
-
return SOURCE_EXTS3.includes(
|
|
10924
|
+
return SOURCE_EXTS3.includes(path26.extname(filePath));
|
|
9369
10925
|
}
|
|
9370
10926
|
function isIgnoredNodeModuleSource(filePath) {
|
|
9371
10927
|
return NODE_MODULES_RE3.test(filePath) && !AKANJS_NODE_MODULE_RE3.test(filePath);
|
|
9372
10928
|
}
|
|
9373
10929
|
function getPageKeyBasePath(pageKey, basePaths) {
|
|
9374
|
-
const normalized = pageKey.split(
|
|
10930
|
+
const normalized = pageKey.split(path26.sep).join("/").replace(/^\.\//, "");
|
|
9375
10931
|
const segments = normalized.split("/");
|
|
9376
10932
|
const firstPublicSegment = segments.find((segment) => segment !== "[lang]" && !/^\(.+\)$/.test(segment));
|
|
9377
10933
|
return firstPublicSegment && basePaths.includes(firstPublicSegment) ? firstPublicSegment : null;
|
|
9378
10934
|
}
|
|
9379
10935
|
// pkgs/@akanjs/devkit/frontendBuild/devChangePlanner.ts
|
|
9380
|
-
import
|
|
10936
|
+
import path27 from "path";
|
|
9381
10937
|
var SOURCE_EXTS4 = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
9382
10938
|
var CONFIG_BASENAMES = new Set(["akan.config.ts", "bunfig.toml", "tsconfig.json", "package.json"]);
|
|
9383
10939
|
var BARREL_FACETS = new Set(["common", "srvkit", "ui", "webkit"]);
|
|
@@ -9389,11 +10945,11 @@ var RUNTIME_METADATA_BASENAMES2 = new Set(["dict.ts", "sig.ts", "useClient.ts",
|
|
|
9389
10945
|
class DevChangePlanner {
|
|
9390
10946
|
#workspaceRoot;
|
|
9391
10947
|
constructor({ workspaceRoot }) {
|
|
9392
|
-
this.#workspaceRoot =
|
|
10948
|
+
this.#workspaceRoot = path27.resolve(workspaceRoot);
|
|
9393
10949
|
}
|
|
9394
10950
|
plan({ generation, files, kinds, generatedFiles: generatedFiles2 = [] }) {
|
|
9395
10951
|
const fileList = uniqueResolved([...files, ...generatedFiles2]);
|
|
9396
|
-
const generatedSet = new Set(generatedFiles2.map((file) =>
|
|
10952
|
+
const generatedSet = new Set(generatedFiles2.map((file) => path27.resolve(file)));
|
|
9397
10953
|
const kindSet = new Set(kinds);
|
|
9398
10954
|
const roles = new Set;
|
|
9399
10955
|
const actions = new Set;
|
|
@@ -9410,13 +10966,13 @@ class DevChangePlanner {
|
|
|
9410
10966
|
}
|
|
9411
10967
|
for (const file of fileList) {
|
|
9412
10968
|
const reasons = new Set;
|
|
9413
|
-
const fileRoles = this.#rolesForFile(file, { isGenerated: generatedSet.has(
|
|
10969
|
+
const fileRoles = this.#rolesForFile(file, { isGenerated: generatedSet.has(path27.resolve(file)), reasons });
|
|
9414
10970
|
for (const role of fileRoles)
|
|
9415
10971
|
roles.add(role);
|
|
9416
10972
|
if (reasons.has("runtime-metadata"))
|
|
9417
10973
|
actions.add("restart-builder");
|
|
9418
10974
|
if (reasons.size > 0)
|
|
9419
|
-
reasonByFile[
|
|
10975
|
+
reasonByFile[path27.resolve(file)] = [...reasons].sort();
|
|
9420
10976
|
}
|
|
9421
10977
|
if (roles.has("barrel"))
|
|
9422
10978
|
actions.add("sync-generated");
|
|
@@ -9437,12 +10993,12 @@ class DevChangePlanner {
|
|
|
9437
10993
|
}
|
|
9438
10994
|
#rolesForFile(file, { isGenerated, reasons }) {
|
|
9439
10995
|
const roles = new Set;
|
|
9440
|
-
const abs =
|
|
9441
|
-
const base =
|
|
9442
|
-
const ext =
|
|
10996
|
+
const abs = path27.resolve(file);
|
|
10997
|
+
const base = path27.basename(abs);
|
|
10998
|
+
const ext = path27.extname(abs).toLowerCase();
|
|
9443
10999
|
const isSource = SOURCE_EXTS4.has(ext);
|
|
9444
|
-
const rel =
|
|
9445
|
-
const parts = rel.split(
|
|
11000
|
+
const rel = path27.relative(this.#workspaceRoot, abs);
|
|
11001
|
+
const parts = rel.split(path27.sep).filter(Boolean);
|
|
9446
11002
|
if (CONFIG_BASENAMES.has(base)) {
|
|
9447
11003
|
roles.add("config");
|
|
9448
11004
|
reasons.add("config-file");
|
|
@@ -9483,15 +11039,15 @@ class DevChangePlanner {
|
|
|
9483
11039
|
return roles;
|
|
9484
11040
|
}
|
|
9485
11041
|
#isServerBiased(abs, parts) {
|
|
9486
|
-
const base =
|
|
11042
|
+
const base = path27.basename(abs);
|
|
9487
11043
|
return parts.includes("srvkit") || SERVER_SUFFIXES2.some((suffix) => base.endsWith(suffix)) || base === "main.ts" || base === "server.ts";
|
|
9488
11044
|
}
|
|
9489
11045
|
#isClientBiased(abs, parts) {
|
|
9490
|
-
const base =
|
|
11046
|
+
const base = path27.basename(abs);
|
|
9491
11047
|
return parts.includes("ui") || parts.includes("webkit") || parts.includes("page") || CLIENT_SUFFIXES.some((suffix) => base.endsWith(suffix));
|
|
9492
11048
|
}
|
|
9493
11049
|
#isSharedBiased(abs, parts) {
|
|
9494
|
-
const base =
|
|
11050
|
+
const base = path27.basename(abs);
|
|
9495
11051
|
return parts.includes("common") || SHARED_SUFFIXES2.some((suffix) => base.endsWith(suffix)) || RUNTIME_METADATA_BASENAMES2.has(base);
|
|
9496
11052
|
}
|
|
9497
11053
|
#isRuntimeMetadataFile(parts, base) {
|
|
@@ -9516,16 +11072,16 @@ class DevChangePlanner {
|
|
|
9516
11072
|
return true;
|
|
9517
11073
|
}
|
|
9518
11074
|
#isWorkspaceSource(rel) {
|
|
9519
|
-
if (!rel || rel.startsWith("..") ||
|
|
11075
|
+
if (!rel || rel.startsWith("..") || path27.isAbsolute(rel))
|
|
9520
11076
|
return false;
|
|
9521
|
-
const [scope] = rel.split(
|
|
11077
|
+
const [scope] = rel.split(path27.sep);
|
|
9522
11078
|
return scope === "apps" || scope === "libs" || scope === "pkgs";
|
|
9523
11079
|
}
|
|
9524
11080
|
}
|
|
9525
|
-
var uniqueResolved = (files) => [...new Set(files.map((file) =>
|
|
11081
|
+
var uniqueResolved = (files) => [...new Set(files.map((file) => path27.resolve(file)))].sort();
|
|
9526
11082
|
// pkgs/@akanjs/devkit/frontendBuild/devGeneratedIndexSync.ts
|
|
9527
11083
|
import { mkdir as mkdir6, readdir as readdir2, readFile, rm as rm2, stat as stat3, writeFile } from "fs/promises";
|
|
9528
|
-
import
|
|
11084
|
+
import path28 from "path";
|
|
9529
11085
|
var BARREL_FACETS2 = new Set(["common", "srvkit", "ui", "webkit"]);
|
|
9530
11086
|
var FACET_SOURCE_FILE_RE = /\.(ts|tsx)$/;
|
|
9531
11087
|
var FACET_EXCLUDED_FILE_RE = /(^index\.tsx?$|\.d\.ts$|\.(test|spec)\.(ts|tsx)$|\.css$|\.scss$|\.sass$)/;
|
|
@@ -9536,7 +11092,7 @@ var SCALAR_UI_TYPES = ["Template", "Unit"];
|
|
|
9536
11092
|
class DevGeneratedIndexSync {
|
|
9537
11093
|
#workspaceRoot;
|
|
9538
11094
|
constructor({ workspaceRoot }) {
|
|
9539
|
-
this.#workspaceRoot =
|
|
11095
|
+
this.#workspaceRoot = path28.resolve(workspaceRoot);
|
|
9540
11096
|
}
|
|
9541
11097
|
async syncForBatch(files) {
|
|
9542
11098
|
const indexPaths = new Set;
|
|
@@ -9545,12 +11101,12 @@ class DevGeneratedIndexSync {
|
|
|
9545
11101
|
const facetIndex = this.#facetIndexFor(file);
|
|
9546
11102
|
if (facetIndex)
|
|
9547
11103
|
indexPaths.add(facetIndex);
|
|
9548
|
-
const
|
|
11104
|
+
const moduleIndex2 = await this.#moduleIndexForDirectoryEvent(file).catch((err) => {
|
|
9549
11105
|
errors.push(`[generated-index] module detection failed for ${file}: ${formatError(err)}`);
|
|
9550
11106
|
return null;
|
|
9551
11107
|
});
|
|
9552
|
-
if (
|
|
9553
|
-
indexPaths.add(
|
|
11108
|
+
if (moduleIndex2)
|
|
11109
|
+
indexPaths.add(moduleIndex2);
|
|
9554
11110
|
}
|
|
9555
11111
|
const changedFiles = [];
|
|
9556
11112
|
for (const indexPath of [...indexPaths].sort()) {
|
|
@@ -9565,11 +11121,11 @@ class DevGeneratedIndexSync {
|
|
|
9565
11121
|
return { changedFiles, errors };
|
|
9566
11122
|
}
|
|
9567
11123
|
#facetIndexFor(file) {
|
|
9568
|
-
const abs =
|
|
9569
|
-
const rel =
|
|
9570
|
-
if (rel.startsWith("..") ||
|
|
11124
|
+
const abs = path28.resolve(file);
|
|
11125
|
+
const rel = path28.relative(this.#workspaceRoot, abs);
|
|
11126
|
+
if (rel.startsWith("..") || path28.isAbsolute(rel))
|
|
9571
11127
|
return null;
|
|
9572
|
-
const parts = rel.split(
|
|
11128
|
+
const parts = rel.split(path28.sep).filter(Boolean);
|
|
9573
11129
|
if (parts.length < 4)
|
|
9574
11130
|
return null;
|
|
9575
11131
|
const [scope, project, facet, child] = parts;
|
|
@@ -9577,32 +11133,32 @@ class DevGeneratedIndexSync {
|
|
|
9577
11133
|
return null;
|
|
9578
11134
|
if (!child || child.startsWith(".") || child === "index.ts" || child === "index.tsx")
|
|
9579
11135
|
return null;
|
|
9580
|
-
return
|
|
11136
|
+
return path28.join(this.#workspaceRoot, scope, project, facet, "index.ts");
|
|
9581
11137
|
}
|
|
9582
11138
|
async#moduleIndexForDirectoryEvent(file) {
|
|
9583
|
-
const abs =
|
|
9584
|
-
const rel =
|
|
9585
|
-
if (rel.startsWith("..") ||
|
|
11139
|
+
const abs = path28.resolve(file);
|
|
11140
|
+
const rel = path28.relative(this.#workspaceRoot, abs);
|
|
11141
|
+
if (rel.startsWith("..") || path28.isAbsolute(rel))
|
|
9586
11142
|
return null;
|
|
9587
|
-
const parts = rel.split(
|
|
11143
|
+
const parts = rel.split(path28.sep).filter(Boolean);
|
|
9588
11144
|
if (parts.length !== 4 && parts.length !== 5)
|
|
9589
11145
|
return null;
|
|
9590
11146
|
const [scope, project, libSegment, moduleSegment, scalarSegment] = parts;
|
|
9591
11147
|
if (scope !== "apps" && scope !== "libs" || !project || libSegment !== "lib")
|
|
9592
11148
|
return null;
|
|
9593
11149
|
const isExistingDirectory = await stat3(abs).then((s) => s.isDirectory()).catch(() => false);
|
|
9594
|
-
const looksLikeDeletedDirectory = !
|
|
11150
|
+
const looksLikeDeletedDirectory = !path28.extname(abs);
|
|
9595
11151
|
if (!isExistingDirectory && !looksLikeDeletedDirectory)
|
|
9596
11152
|
return null;
|
|
9597
11153
|
if (moduleSegment === "__scalar" && scalarSegment) {
|
|
9598
|
-
return
|
|
11154
|
+
return path28.join(this.#workspaceRoot, scope, project, "lib", "__scalar", scalarSegment, "index.ts");
|
|
9599
11155
|
}
|
|
9600
11156
|
if (!moduleSegment || moduleSegment === "__scalar")
|
|
9601
11157
|
return null;
|
|
9602
|
-
return
|
|
11158
|
+
return path28.join(this.#workspaceRoot, scope, project, "lib", moduleSegment, "index.ts");
|
|
9603
11159
|
}
|
|
9604
11160
|
async#syncIndex(indexPath) {
|
|
9605
|
-
const dir =
|
|
11161
|
+
const dir = path28.dirname(indexPath);
|
|
9606
11162
|
const content = await this.#contentForIndex(indexPath);
|
|
9607
11163
|
if (content === null) {
|
|
9608
11164
|
if (!await exists(indexPath))
|
|
@@ -9618,11 +11174,11 @@ class DevGeneratedIndexSync {
|
|
|
9618
11174
|
return true;
|
|
9619
11175
|
}
|
|
9620
11176
|
async#contentForIndex(indexPath) {
|
|
9621
|
-
const parts =
|
|
11177
|
+
const parts = path28.relative(this.#workspaceRoot, indexPath).split(path28.sep).filter(Boolean);
|
|
9622
11178
|
const facet = parts.at(-2);
|
|
9623
11179
|
if (facet && BARREL_FACETS2.has(facet))
|
|
9624
|
-
return this.#facetContent(
|
|
9625
|
-
return this.#moduleContent(
|
|
11180
|
+
return this.#facetContent(path28.dirname(indexPath));
|
|
11181
|
+
return this.#moduleContent(path28.dirname(indexPath));
|
|
9626
11182
|
}
|
|
9627
11183
|
async#facetContent(dir) {
|
|
9628
11184
|
const entries = await readdir2(dir, { withFileTypes: true }).catch(() => []);
|
|
@@ -9645,8 +11201,8 @@ class DevGeneratedIndexSync {
|
|
|
9645
11201
|
`;
|
|
9646
11202
|
}
|
|
9647
11203
|
async#moduleContent(dir) {
|
|
9648
|
-
const rel =
|
|
9649
|
-
const parts = rel.split(
|
|
11204
|
+
const rel = path28.relative(this.#workspaceRoot, dir);
|
|
11205
|
+
const parts = rel.split(path28.sep).filter(Boolean);
|
|
9650
11206
|
const moduleSegment = parts.at(-1);
|
|
9651
11207
|
if (!moduleSegment)
|
|
9652
11208
|
return null;
|
|
@@ -9654,11 +11210,11 @@ class DevGeneratedIndexSync {
|
|
|
9654
11210
|
const rawModel = moduleSegment.startsWith("_") ? moduleSegment.slice(1) : moduleSegment;
|
|
9655
11211
|
if (!rawModel)
|
|
9656
11212
|
return null;
|
|
9657
|
-
const modelName =
|
|
11213
|
+
const modelName = capitalize4(rawModel);
|
|
9658
11214
|
const allowedTypes = isScalar ? SCALAR_UI_TYPES : moduleSegment.startsWith("_") ? SERVICE_UI_TYPES : MODULE_UI_TYPES;
|
|
9659
11215
|
const fileTypes = [];
|
|
9660
11216
|
for (const type of allowedTypes) {
|
|
9661
|
-
if (await exists(
|
|
11217
|
+
if (await exists(path28.join(dir, `${modelName}.${type}.tsx`)))
|
|
9662
11218
|
fileTypes.push(type);
|
|
9663
11219
|
}
|
|
9664
11220
|
if (fileTypes.length === 0)
|
|
@@ -9671,11 +11227,11 @@ export const ${modelName} = { ${fileTypes.join(", ")} };`;
|
|
|
9671
11227
|
}
|
|
9672
11228
|
}
|
|
9673
11229
|
var exists = async (file) => stat3(file).then(() => true).catch(() => false);
|
|
9674
|
-
var
|
|
11230
|
+
var capitalize4 = (value) => `${value.charAt(0).toUpperCase()}${value.slice(1)}`;
|
|
9675
11231
|
var formatError = (err) => err instanceof Error ? err.message : String(err);
|
|
9676
11232
|
// pkgs/@akanjs/devkit/frontendBuild/fontOptimizer.ts
|
|
9677
11233
|
import { mkdir as mkdir7 } from "fs/promises";
|
|
9678
|
-
import
|
|
11234
|
+
import path29 from "path";
|
|
9679
11235
|
import {
|
|
9680
11236
|
generateFontFace,
|
|
9681
11237
|
getMetricsForFamily,
|
|
@@ -9684,7 +11240,7 @@ import {
|
|
|
9684
11240
|
} from "fontaine";
|
|
9685
11241
|
import { createFont, woff2 } from "fonteditor-core";
|
|
9686
11242
|
import subsetFont from "subset-font";
|
|
9687
|
-
import
|
|
11243
|
+
import ts9 from "typescript";
|
|
9688
11244
|
var FONT_URL_PREFIX = "/_akan/fonts";
|
|
9689
11245
|
var DEFAULT_FONT_SUBSETS = ["latin"];
|
|
9690
11246
|
|
|
@@ -9699,7 +11255,7 @@ class FontOptimizer {
|
|
|
9699
11255
|
constructor(app, command = "start") {
|
|
9700
11256
|
this.#app = app;
|
|
9701
11257
|
this.#command = command;
|
|
9702
|
-
this.#artifactRoot =
|
|
11258
|
+
this.#artifactRoot = path29.join(command === "build" ? app.dist.cwdPath : app.cwdPath, ".akan/artifact");
|
|
9703
11259
|
}
|
|
9704
11260
|
async optimize() {
|
|
9705
11261
|
const fonts = await this.discoverFonts();
|
|
@@ -9718,7 +11274,7 @@ class FontOptimizer {
|
|
|
9718
11274
|
const pageKeys = await this.#app.getPageKeys();
|
|
9719
11275
|
const fonts = [];
|
|
9720
11276
|
await Promise.all(pageKeys.map(async (key) => {
|
|
9721
|
-
const filePath =
|
|
11277
|
+
const filePath = path29.resolve(this.#app.cwdPath, "page", key);
|
|
9722
11278
|
const file = Bun.file(filePath);
|
|
9723
11279
|
if (!await file.exists())
|
|
9724
11280
|
return;
|
|
@@ -9734,8 +11290,8 @@ class FontOptimizer {
|
|
|
9734
11290
|
this.#app.logger.warn(`[font] source not found: ${face.src}`);
|
|
9735
11291
|
continue;
|
|
9736
11292
|
}
|
|
9737
|
-
const outputPath =
|
|
9738
|
-
await mkdir7(
|
|
11293
|
+
const outputPath = path29.join(this.#artifactRoot, face.optimizedSrc.replace(/^\/_akan\//, ""));
|
|
11294
|
+
await mkdir7(path29.dirname(outputPath), { recursive: true });
|
|
9739
11295
|
const sourceBuffer = Buffer.from(await Bun.file(sourcePath).arrayBuffer());
|
|
9740
11296
|
const outputBuffer = font.subset === false ? await this.#convertToWoff2(sourceBuffer, sourcePath) : await subsetFont(sourceBuffer, await this.#getSubsetText(font), { targetFormat: "woff2" });
|
|
9741
11297
|
await Bun.write(outputPath, outputBuffer);
|
|
@@ -9749,17 +11305,17 @@ class FontOptimizer {
|
|
|
9749
11305
|
this.#cssParts.push(...faceCss, this.#buildRootVariableRule(font));
|
|
9750
11306
|
}
|
|
9751
11307
|
#extractFontsExport(source2, filePath) {
|
|
9752
|
-
const sourceFile2 =
|
|
11308
|
+
const sourceFile2 = ts9.createSourceFile(filePath, source2, ts9.ScriptTarget.Latest, true, ts9.ScriptKind.TSX);
|
|
9753
11309
|
const fonts = [];
|
|
9754
11310
|
for (const statement of sourceFile2.statements) {
|
|
9755
|
-
if (!
|
|
11311
|
+
if (!ts9.isVariableStatement(statement))
|
|
9756
11312
|
continue;
|
|
9757
|
-
const modifiers =
|
|
9758
|
-
const isExported = modifiers?.some((modifier) => modifier.kind ===
|
|
11313
|
+
const modifiers = ts9.canHaveModifiers(statement) ? ts9.getModifiers(statement) : undefined;
|
|
11314
|
+
const isExported = modifiers?.some((modifier) => modifier.kind === ts9.SyntaxKind.ExportKeyword) ?? false;
|
|
9759
11315
|
if (!isExported)
|
|
9760
11316
|
continue;
|
|
9761
11317
|
for (const declaration of statement.declarationList.declarations) {
|
|
9762
|
-
if (!
|
|
11318
|
+
if (!ts9.isIdentifier(declaration.name) || declaration.name.text !== "fonts")
|
|
9763
11319
|
continue;
|
|
9764
11320
|
const value = declaration.initializer ? this.#literalToValue(declaration.initializer) : null;
|
|
9765
11321
|
if (Array.isArray(value)) {
|
|
@@ -9770,20 +11326,20 @@ class FontOptimizer {
|
|
|
9770
11326
|
return fonts;
|
|
9771
11327
|
}
|
|
9772
11328
|
#literalToValue(node) {
|
|
9773
|
-
if (
|
|
11329
|
+
if (ts9.isStringLiteralLike(node))
|
|
9774
11330
|
return node.text;
|
|
9775
|
-
if (
|
|
11331
|
+
if (ts9.isNumericLiteral(node))
|
|
9776
11332
|
return Number(node.text);
|
|
9777
|
-
if (node.kind ===
|
|
11333
|
+
if (node.kind === ts9.SyntaxKind.TrueKeyword)
|
|
9778
11334
|
return true;
|
|
9779
|
-
if (node.kind ===
|
|
11335
|
+
if (node.kind === ts9.SyntaxKind.FalseKeyword)
|
|
9780
11336
|
return false;
|
|
9781
|
-
if (
|
|
11337
|
+
if (ts9.isArrayLiteralExpression(node))
|
|
9782
11338
|
return node.elements.map((element) => this.#literalToValue(element));
|
|
9783
|
-
if (
|
|
11339
|
+
if (ts9.isObjectLiteralExpression(node)) {
|
|
9784
11340
|
const obj = {};
|
|
9785
11341
|
for (const prop of node.properties) {
|
|
9786
|
-
if (!
|
|
11342
|
+
if (!ts9.isPropertyAssignment(prop))
|
|
9787
11343
|
continue;
|
|
9788
11344
|
const name = this.#getPropertyName(prop.name);
|
|
9789
11345
|
if (!name)
|
|
@@ -9792,13 +11348,13 @@ class FontOptimizer {
|
|
|
9792
11348
|
}
|
|
9793
11349
|
return obj;
|
|
9794
11350
|
}
|
|
9795
|
-
if (
|
|
11351
|
+
if (ts9.isAsExpression(node) || ts9.isSatisfiesExpression(node) || ts9.isParenthesizedExpression(node)) {
|
|
9796
11352
|
return this.#literalToValue(node.expression);
|
|
9797
11353
|
}
|
|
9798
11354
|
return;
|
|
9799
11355
|
}
|
|
9800
11356
|
#getPropertyName(name) {
|
|
9801
|
-
if (
|
|
11357
|
+
if (ts9.isIdentifier(name) || ts9.isStringLiteral(name) || ts9.isNumericLiteral(name))
|
|
9802
11358
|
return name.text;
|
|
9803
11359
|
return null;
|
|
9804
11360
|
}
|
|
@@ -9882,8 +11438,8 @@ class FontOptimizer {
|
|
|
9882
11438
|
return null;
|
|
9883
11439
|
const rel = src.replace(/^\//, "");
|
|
9884
11440
|
const candidates = [
|
|
9885
|
-
this.#command === "build" ?
|
|
9886
|
-
|
|
11441
|
+
this.#command === "build" ? path29.join(this.#app.dist.cwdPath, "public", rel) : null,
|
|
11442
|
+
path29.join(this.#app.cwdPath, "public", rel),
|
|
9887
11443
|
this.#resolveWorkspacePublicPath(rel)
|
|
9888
11444
|
].filter(Boolean);
|
|
9889
11445
|
for (const candidate of candidates) {
|
|
@@ -9911,7 +11467,7 @@ class FontOptimizer {
|
|
|
9911
11467
|
return "woff2";
|
|
9912
11468
|
if (signature === "OTTO")
|
|
9913
11469
|
return "otf";
|
|
9914
|
-
const ext =
|
|
11470
|
+
const ext = path29.extname(sourcePath).slice(1).toLowerCase();
|
|
9915
11471
|
if (ext === "otf" || ext === "woff" || ext === "woff2")
|
|
9916
11472
|
return ext;
|
|
9917
11473
|
return "ttf";
|
|
@@ -9920,7 +11476,7 @@ class FontOptimizer {
|
|
|
9920
11476
|
const [root, dep, ...rest] = rel.split("/");
|
|
9921
11477
|
if (root !== "libs" || !dep || rest.length === 0)
|
|
9922
11478
|
return null;
|
|
9923
|
-
return
|
|
11479
|
+
return path29.join(this.#app.workspace.workspaceRoot, "libs", dep, "public", ...rest);
|
|
9924
11480
|
}
|
|
9925
11481
|
async#getSubsetText(font) {
|
|
9926
11482
|
const parts = new Set;
|
|
@@ -9930,7 +11486,7 @@ class FontOptimizer {
|
|
|
9930
11486
|
if (font.subsetText)
|
|
9931
11487
|
parts.add(font.subsetText);
|
|
9932
11488
|
for (const filePath of font.subsetFiles ?? []) {
|
|
9933
|
-
const abs =
|
|
11489
|
+
const abs = path29.isAbsolute(filePath) ? filePath : path29.join(this.#app.cwdPath, filePath);
|
|
9934
11490
|
const file = Bun.file(abs);
|
|
9935
11491
|
if (await file.exists())
|
|
9936
11492
|
parts.add(await file.text());
|
|
@@ -9949,7 +11505,7 @@ class FontOptimizer {
|
|
|
9949
11505
|
return "";
|
|
9950
11506
|
}
|
|
9951
11507
|
async#collectAutoSubsetText() {
|
|
9952
|
-
const roots = ["page", "ui"].map((dir) =>
|
|
11508
|
+
const roots = ["page", "ui"].map((dir) => path29.join(this.#app.cwdPath, dir));
|
|
9953
11509
|
const glob = new Bun.Glob("**/*.{ts,tsx,js,jsx,html,md}");
|
|
9954
11510
|
const parts = [];
|
|
9955
11511
|
await Promise.all(roots.map(async (root) => {
|
|
@@ -10063,7 +11619,7 @@ ${declarations.map(([prop, value]) => ` ${prop}: ${value};`).join(`
|
|
|
10063
11619
|
}
|
|
10064
11620
|
}
|
|
10065
11621
|
// pkgs/@akanjs/devkit/frontendBuild/hmrChangeClassifier.ts
|
|
10066
|
-
import
|
|
11622
|
+
import path30 from "path";
|
|
10067
11623
|
var SOURCE_EXTS5 = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
10068
11624
|
var CSS_EXTS = new Set([".css"]);
|
|
10069
11625
|
var CONFIG_BASENAMES2 = new Set(["akan.config.ts", "bunfig.toml", "tsconfig.json", "package.json"]);
|
|
@@ -10072,10 +11628,10 @@ class HmrChangeClassifier {
|
|
|
10072
11628
|
classify(abs) {
|
|
10073
11629
|
if (this.#isUninteresting(abs))
|
|
10074
11630
|
return "ignore";
|
|
10075
|
-
const base =
|
|
11631
|
+
const base = path30.basename(abs);
|
|
10076
11632
|
if (CONFIG_BASENAMES2.has(base))
|
|
10077
11633
|
return "config";
|
|
10078
|
-
const ext =
|
|
11634
|
+
const ext = path30.extname(abs).toLowerCase();
|
|
10079
11635
|
if (CSS_EXTS.has(ext))
|
|
10080
11636
|
return "css";
|
|
10081
11637
|
if (SOURCE_EXTS5.has(ext))
|
|
@@ -10083,23 +11639,23 @@ class HmrChangeClassifier {
|
|
|
10083
11639
|
return "ignore";
|
|
10084
11640
|
}
|
|
10085
11641
|
#isUninteresting(abs) {
|
|
10086
|
-
const base =
|
|
11642
|
+
const base = path30.basename(abs);
|
|
10087
11643
|
if (!base)
|
|
10088
11644
|
return true;
|
|
10089
11645
|
if (base.startsWith("."))
|
|
10090
11646
|
return true;
|
|
10091
11647
|
if (base.endsWith("~") || base.endsWith(".swp") || base.endsWith(".swx") || base.endsWith(".tmp"))
|
|
10092
11648
|
return true;
|
|
10093
|
-
if (abs.includes(`${
|
|
11649
|
+
if (abs.includes(`${path30.sep}node_modules${path30.sep}`))
|
|
10094
11650
|
return true;
|
|
10095
|
-
if (abs.includes(`${
|
|
11651
|
+
if (abs.includes(`${path30.sep}.akan${path30.sep}`))
|
|
10096
11652
|
return true;
|
|
10097
11653
|
return false;
|
|
10098
11654
|
}
|
|
10099
11655
|
}
|
|
10100
11656
|
// pkgs/@akanjs/devkit/frontendBuild/hmrWatcher.ts
|
|
10101
11657
|
import fs4 from "fs";
|
|
10102
|
-
import
|
|
11658
|
+
import path31 from "path";
|
|
10103
11659
|
class HmrWatcher {
|
|
10104
11660
|
#roots;
|
|
10105
11661
|
#debounceMs;
|
|
@@ -10112,7 +11668,7 @@ class HmrWatcher {
|
|
|
10112
11668
|
#stopped = false;
|
|
10113
11669
|
#flushing = false;
|
|
10114
11670
|
constructor(opts) {
|
|
10115
|
-
this.#roots = [...new Set(opts.roots.map((r) =>
|
|
11671
|
+
this.#roots = [...new Set(opts.roots.map((r) => path31.resolve(r)))];
|
|
10116
11672
|
this.#debounceMs = opts.debounceMs ?? 80;
|
|
10117
11673
|
this.#onBatch = opts.onBatch;
|
|
10118
11674
|
this.#logger = opts.logger;
|
|
@@ -10123,7 +11679,7 @@ class HmrWatcher {
|
|
|
10123
11679
|
const w = fs4.watch(root, { recursive: true, persistent: false }, (_event, filename) => {
|
|
10124
11680
|
if (!filename)
|
|
10125
11681
|
return;
|
|
10126
|
-
const abs =
|
|
11682
|
+
const abs = path31.resolve(root, filename.toString());
|
|
10127
11683
|
this.#queue(abs);
|
|
10128
11684
|
});
|
|
10129
11685
|
this.#watchers.push(w);
|
|
@@ -10181,10 +11737,10 @@ class HmrWatcher {
|
|
|
10181
11737
|
}
|
|
10182
11738
|
}
|
|
10183
11739
|
// pkgs/@akanjs/devkit/frontendBuild/pagesBundleBuilder.ts
|
|
10184
|
-
import
|
|
11740
|
+
import path33 from "path";
|
|
10185
11741
|
|
|
10186
11742
|
// pkgs/@akanjs/devkit/transforms/externalizeFrameworkPlugin.ts
|
|
10187
|
-
import
|
|
11743
|
+
import path32 from "path";
|
|
10188
11744
|
var DEFAULT_INCLUDE = ["akanjs/", "@apps/", "@libs/"];
|
|
10189
11745
|
var DEFAULT_EXCLUDE_EXACT = new Set(["akanjs/webkit", "@akanjs/cli", "@akanjs/devkit"]);
|
|
10190
11746
|
var DEFAULT_EXCLUDE_PREFIX = ["@akanjs/cli/", "@akanjs/devkit/"];
|
|
@@ -10227,7 +11783,7 @@ async function createExternalizeFrameworkPlugin(options) {
|
|
|
10227
11783
|
const replPath = repl?.endsWith("/*") ? repl.slice(0, -1) : repl ?? "";
|
|
10228
11784
|
if (!replPath)
|
|
10229
11785
|
continue;
|
|
10230
|
-
const candidate =
|
|
11786
|
+
const candidate = path32.resolve(workspaceRoot, replPath + suffix);
|
|
10231
11787
|
const hit = await firstExisting(candidate);
|
|
10232
11788
|
if (hit)
|
|
10233
11789
|
return hit;
|
|
@@ -10239,8 +11795,8 @@ async function createExternalizeFrameworkPlugin(options) {
|
|
|
10239
11795
|
if (spec === pkg)
|
|
10240
11796
|
continue;
|
|
10241
11797
|
const suffix = spec.slice(pkg.length + 1);
|
|
10242
|
-
const pkgDir =
|
|
10243
|
-
const candidate =
|
|
11798
|
+
const pkgDir = path32.dirname(path32.resolve(workspaceRoot, entryFile));
|
|
11799
|
+
const candidate = path32.join(pkgDir, suffix);
|
|
10244
11800
|
const hit = await firstExisting(candidate);
|
|
10245
11801
|
if (hit)
|
|
10246
11802
|
return hit;
|
|
@@ -10290,7 +11846,7 @@ async function firstExisting(basePath2) {
|
|
|
10290
11846
|
return candidate;
|
|
10291
11847
|
}
|
|
10292
11848
|
for (const ext of CANDIDATE_EXTS3) {
|
|
10293
|
-
const candidate =
|
|
11849
|
+
const candidate = path32.join(basePath2, `index${ext}`);
|
|
10294
11850
|
if (await Bun.file(candidate).exists())
|
|
10295
11851
|
return candidate;
|
|
10296
11852
|
}
|
|
@@ -10381,11 +11937,11 @@ class PagesBundleBuilder {
|
|
|
10381
11937
|
const entryArtifact = result.outputs.find((a) => a.kind === "entry-point");
|
|
10382
11938
|
if (!entryArtifact)
|
|
10383
11939
|
throw new Error("[PagesBundleBuilder] Bun.build emitted no entry-point artifact");
|
|
10384
|
-
const bundlePath =
|
|
11940
|
+
const bundlePath = path33.resolve(entryArtifact.path);
|
|
10385
11941
|
const buildId = Date.now();
|
|
10386
11942
|
const outputBytes = result.outputs.reduce((sum, output) => sum + output.size, 0);
|
|
10387
11943
|
const chunkCount = result.outputs.filter((output) => output.kind === "chunk").length;
|
|
10388
|
-
this.#app.verbose(`[PagesBundleBuilder] ${
|
|
11944
|
+
this.#app.verbose(`[PagesBundleBuilder] ${path33.basename(bundlePath)} emitted in ${Date.now() - this.#started}ms splitting=${this.#splitting} entry=${entryArtifact.size} bytes outputs=${result.outputs.length} chunks=${chunkCount} total=${outputBytes} bytes`);
|
|
10389
11945
|
return {
|
|
10390
11946
|
bundlePath,
|
|
10391
11947
|
buildId,
|
|
@@ -10467,11 +12023,11 @@ function loaderFor4(absPath) {
|
|
|
10467
12023
|
}
|
|
10468
12024
|
// pkgs/@akanjs/devkit/frontendBuild/precompressArtifacts.ts
|
|
10469
12025
|
import fs5 from "fs";
|
|
10470
|
-
import
|
|
12026
|
+
import path34 from "path";
|
|
10471
12027
|
var COMPRESSIBLE_EXTS = new Set([".css", ".html", ".js", ".json", ".svg"]);
|
|
10472
12028
|
var MIN_COMPRESS_BYTES = 1024;
|
|
10473
12029
|
async function precompressArtifacts(app) {
|
|
10474
|
-
const roots = [
|
|
12030
|
+
const roots = [path34.join(app.dist.cwdPath, ".akan/artifact/client")];
|
|
10475
12031
|
const result = { files: 0, inputBytes: 0, outputBytes: 0 };
|
|
10476
12032
|
await Promise.all(roots.map((root) => precompressRoot(root, result)));
|
|
10477
12033
|
if (result.files > 0) {
|
|
@@ -10497,7 +12053,7 @@ async function precompressRoot(root, result) {
|
|
|
10497
12053
|
async function shouldPrecompress(filePath) {
|
|
10498
12054
|
if (filePath.endsWith(".gz"))
|
|
10499
12055
|
return false;
|
|
10500
|
-
if (!COMPRESSIBLE_EXTS.has(
|
|
12056
|
+
if (!COMPRESSIBLE_EXTS.has(path34.extname(filePath).toLowerCase()))
|
|
10501
12057
|
return false;
|
|
10502
12058
|
const file = Bun.file(filePath);
|
|
10503
12059
|
if (!await file.exists())
|
|
@@ -10515,7 +12071,7 @@ function formatBytes(bytes) {
|
|
|
10515
12071
|
return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
|
|
10516
12072
|
}
|
|
10517
12073
|
// pkgs/@akanjs/devkit/frontendBuild/ssrBaseArtifactBuilder.ts
|
|
10518
|
-
import
|
|
12074
|
+
import path35 from "path";
|
|
10519
12075
|
import { optimize } from "@tailwindcss/node";
|
|
10520
12076
|
function prepareCssAsset(command, basePath2, cssText) {
|
|
10521
12077
|
return optimize(cssText, { file: `${basePath2 || "root"}.css`, minify: command === "build" }).code;
|
|
@@ -10531,7 +12087,7 @@ class SsrBaseArtifactBuilder {
|
|
|
10531
12087
|
this.#app = app;
|
|
10532
12088
|
this.#command = command;
|
|
10533
12089
|
this.#artifactDir = `${command === "build" ? app.dist.cwdPath : app.cwdPath}/.akan/artifact`;
|
|
10534
|
-
this.#absArtifactDir =
|
|
12090
|
+
this.#absArtifactDir = path35.resolve(this.#artifactDir);
|
|
10535
12091
|
}
|
|
10536
12092
|
async build() {
|
|
10537
12093
|
const akanConfig2 = await this.#app.getConfig();
|
|
@@ -10553,7 +12109,7 @@ class SsrBaseArtifactBuilder {
|
|
|
10553
12109
|
rscRuntimeSsrManifest,
|
|
10554
12110
|
vendorMap,
|
|
10555
12111
|
cssAssets,
|
|
10556
|
-
pagesBundlePath: this.#command === "build" ?
|
|
12112
|
+
pagesBundlePath: this.#command === "build" ? path35.relative(this.#absArtifactDir, pagesBundle.bundlePath) : pagesBundle.bundlePath,
|
|
10557
12113
|
pagesBundleBuildId: pagesBundle.buildId,
|
|
10558
12114
|
domains: [...akanConfig2.domains],
|
|
10559
12115
|
subRoutes: Object.fromEntries(Array.from(akanConfig2.subRoutes.entries()).map(([basePath2, domains]) => [basePath2, [...domains]])),
|
|
@@ -10562,7 +12118,7 @@ class SsrBaseArtifactBuilder {
|
|
|
10562
12118
|
i18n: akanConfig2.i18n,
|
|
10563
12119
|
imageConfig: akanConfig2.images
|
|
10564
12120
|
};
|
|
10565
|
-
await Bun.write(
|
|
12121
|
+
await Bun.write(path35.join(this.#absArtifactDir, "base-artifact.json"), `${JSON.stringify(artifact, null, 2)}
|
|
10566
12122
|
`);
|
|
10567
12123
|
this.#app.verbose(`[base-artifact] complete in ${Date.now() - this.#started}ms`);
|
|
10568
12124
|
return { artifact, seedIndex, cssCompiler, optimizedFonts };
|
|
@@ -10610,15 +12166,15 @@ class SsrBaseArtifactBuilder {
|
|
|
10610
12166
|
async#resolveAkanServerPath() {
|
|
10611
12167
|
const candidates = [];
|
|
10612
12168
|
try {
|
|
10613
|
-
candidates.push(
|
|
12169
|
+
candidates.push(path35.dirname(Bun.resolveSync("akanjs/server", this.#app.workspace.workspaceRoot)));
|
|
10614
12170
|
} catch {}
|
|
10615
|
-
candidates.push(
|
|
12171
|
+
candidates.push(path35.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server"), path35.join(this.#app.workspace.workspaceRoot, "node_modules/akanjs/server"));
|
|
10616
12172
|
try {
|
|
10617
|
-
candidates.push(
|
|
12173
|
+
candidates.push(path35.dirname(Bun.resolveSync("akanjs/server", path35.dirname(Bun.main))));
|
|
10618
12174
|
} catch {}
|
|
10619
|
-
candidates.push(
|
|
12175
|
+
candidates.push(path35.join(path35.dirname(Bun.main), "node_modules/akanjs/server"), path35.join(path35.dirname(Bun.main), "../../akanjs/server"), path35.resolve(import.meta.dir, "../../server"), path35.resolve(import.meta.dir, "../server"));
|
|
10620
12176
|
for (const candidate of candidates) {
|
|
10621
|
-
if (await Bun.file(
|
|
12177
|
+
if (await Bun.file(path35.join(candidate, "rscClient.tsx")).exists())
|
|
10622
12178
|
return candidate;
|
|
10623
12179
|
}
|
|
10624
12180
|
throw new Error(`[base-artifact] failed to locate akanjs/server; looked in: ${candidates.join(", ")}`);
|
|
@@ -10647,14 +12203,14 @@ ${preparedCssText}`).toString(36);
|
|
|
10647
12203
|
`styles/${cssAssetName}-${cssHash}.css`,
|
|
10648
12204
|
`/_akan/styles/${cssAssetName}-${cssHash}.css`
|
|
10649
12205
|
];
|
|
10650
|
-
await Bun.write(
|
|
12206
|
+
await Bun.write(path35.join(this.#absArtifactDir, cssRelPath), preparedCssText);
|
|
10651
12207
|
this.#app.verbose(`[base-artifact] wrote ${preparedCssText.length} bytes of CSS for ${basePath2} -> ${cssRelPath}`);
|
|
10652
12208
|
return [basePath2, { cssUrl, cssRelPath }];
|
|
10653
12209
|
}
|
|
10654
12210
|
}
|
|
10655
12211
|
// pkgs/@akanjs/devkit/frontendBuild/watchRootResolver.ts
|
|
10656
12212
|
import fs6 from "fs";
|
|
10657
|
-
import
|
|
12213
|
+
import path36 from "path";
|
|
10658
12214
|
|
|
10659
12215
|
class WatchRootResolver {
|
|
10660
12216
|
#app;
|
|
@@ -10664,15 +12220,15 @@ class WatchRootResolver {
|
|
|
10664
12220
|
async resolve() {
|
|
10665
12221
|
const tsconfig = await this.#app.getTsConfig();
|
|
10666
12222
|
const set = new Set;
|
|
10667
|
-
set.add(
|
|
12223
|
+
set.add(path36.resolve(`${this.#app.cwdPath}/page`));
|
|
10668
12224
|
for (const targets of Object.values(tsconfig.compilerOptions.paths ?? {})) {
|
|
10669
12225
|
for (const target of targets) {
|
|
10670
12226
|
if (!target)
|
|
10671
12227
|
continue;
|
|
10672
|
-
if (
|
|
12228
|
+
if (path36.isAbsolute(target))
|
|
10673
12229
|
continue;
|
|
10674
12230
|
const cleaned = target.replace(/\/?\*+.*$/, "").replace(/\/[^/]+\.[^/]+$/, "");
|
|
10675
|
-
const resolved =
|
|
12231
|
+
const resolved = path36.resolve(this.#app.workspace.workspaceRoot, cleaned);
|
|
10676
12232
|
if (fs6.existsSync(resolved))
|
|
10677
12233
|
set.add(resolved);
|
|
10678
12234
|
}
|
|
@@ -10739,7 +12295,7 @@ class ApplicationBuildRunner {
|
|
|
10739
12295
|
phases: this.#phases,
|
|
10740
12296
|
durationMs: Date.now() - this.#startedAt,
|
|
10741
12297
|
outputDir: this.#app.dist.cwdPath,
|
|
10742
|
-
artifactDir:
|
|
12298
|
+
artifactDir: path37.join(this.#app.dist.cwdPath, ".akan/artifact")
|
|
10743
12299
|
};
|
|
10744
12300
|
}
|
|
10745
12301
|
async typecheck(options = {}) {
|
|
@@ -10747,7 +12303,7 @@ class ApplicationBuildRunner {
|
|
|
10747
12303
|
await this.#app.getPageKeys({ refresh: true });
|
|
10748
12304
|
const { typecheckDir, tsconfigPath } = await this.#writeTypecheckTsconfig({ incremental });
|
|
10749
12305
|
if (clean)
|
|
10750
|
-
await rm3(
|
|
12306
|
+
await rm3(path37.join(typecheckDir, "tsconfig.tsbuildinfo"), { force: true });
|
|
10751
12307
|
await this.#checkProjectInChildProcess(tsconfigPath);
|
|
10752
12308
|
}
|
|
10753
12309
|
async#runPhase(id, label, task, summarize, options = {}) {
|
|
@@ -10819,7 +12375,7 @@ class ApplicationBuildRunner {
|
|
|
10819
12375
|
};
|
|
10820
12376
|
}
|
|
10821
12377
|
async#writeConsoleShim() {
|
|
10822
|
-
await Bun.write(
|
|
12378
|
+
await Bun.write(path37.join(this.#app.dist.cwdPath, "console.js"), `import { cnst, db, dict, option, server, sig, srv } from "./server.js";
|
|
10823
12379
|
import { assertAkanConsoleAllowed, startAkanConsole } from "./console-runtime.js";
|
|
10824
12380
|
|
|
10825
12381
|
const run = async () => {
|
|
@@ -10842,14 +12398,14 @@ void run().catch((error) => {
|
|
|
10842
12398
|
try {
|
|
10843
12399
|
return Bun.resolveSync("akanjs/server/rsc-worker", import.meta.dir);
|
|
10844
12400
|
} catch {
|
|
10845
|
-
return
|
|
12401
|
+
return path37.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/rscWorker.tsx");
|
|
10846
12402
|
}
|
|
10847
12403
|
}
|
|
10848
12404
|
#resolveConsoleRuntimeBuildEntry() {
|
|
10849
12405
|
try {
|
|
10850
|
-
return
|
|
12406
|
+
return path37.join(path37.dirname(Bun.resolveSync("akanjs/server", import.meta.dir)), "console.ts");
|
|
10851
12407
|
} catch {
|
|
10852
|
-
return
|
|
12408
|
+
return path37.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/console.ts");
|
|
10853
12409
|
}
|
|
10854
12410
|
}
|
|
10855
12411
|
async#buildCsr() {
|
|
@@ -10866,7 +12422,7 @@ void run().catch((error) => {
|
|
|
10866
12422
|
return { base, allRoutes };
|
|
10867
12423
|
}
|
|
10868
12424
|
async#writeTypecheckTsconfig({ incremental = true } = {}) {
|
|
10869
|
-
const typecheckDir =
|
|
12425
|
+
const typecheckDir = path37.join(this.#app.cwdPath, ".akan", "typecheck");
|
|
10870
12426
|
await mkdir8(typecheckDir, { recursive: true });
|
|
10871
12427
|
const tsconfig = {
|
|
10872
12428
|
extends: "../../tsconfig.json",
|
|
@@ -10885,7 +12441,7 @@ void run().catch((error) => {
|
|
|
10885
12441
|
],
|
|
10886
12442
|
references: []
|
|
10887
12443
|
};
|
|
10888
|
-
const tsconfigPath =
|
|
12444
|
+
const tsconfigPath = path37.join(typecheckDir, "tsconfig.json");
|
|
10889
12445
|
await Bun.write(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
|
|
10890
12446
|
`);
|
|
10891
12447
|
return { typecheckDir, tsconfigPath };
|
|
@@ -10911,10 +12467,10 @@ void run().catch((error) => {
|
|
|
10911
12467
|
}
|
|
10912
12468
|
async#resolveTypecheckWorkerEntry() {
|
|
10913
12469
|
const candidates = [
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
12470
|
+
path37.join(this.#app.workspace.workspaceRoot, "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
|
|
12471
|
+
path37.join(this.#app.workspace.workspaceRoot, "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
|
|
12472
|
+
path37.join(import.meta.dir, "typecheck.proc.js"),
|
|
12473
|
+
path37.join(import.meta.dir, "typecheck.proc.ts")
|
|
10918
12474
|
];
|
|
10919
12475
|
for (const candidate of candidates)
|
|
10920
12476
|
if (await Bun.file(candidate).exists())
|
|
@@ -11090,13 +12646,13 @@ class ApplicationReleasePackager {
|
|
|
11090
12646
|
await cp(this.#app.dist.cwdPath, `${sourceRoot}/apps/${this.#app.name}`, { recursive: true });
|
|
11091
12647
|
const libDeps = ["social", "shared", "platform", "util"];
|
|
11092
12648
|
await Promise.all(libDeps.map((lib) => cp(`${this.#app.workspace.cwdPath}/libs/${lib}`, `${sourceRoot}/libs/${lib}`, { recursive: true })));
|
|
11093
|
-
await Promise.all([".next", "ios", "android", "public/libs"].map(async (
|
|
11094
|
-
const targetPath = `${sourceRoot}/apps/${this.#app.name}/${
|
|
12649
|
+
await Promise.all([".next", "ios", "android", "public/libs"].map(async (path38) => {
|
|
12650
|
+
const targetPath = `${sourceRoot}/apps/${this.#app.name}/${path38}`;
|
|
11095
12651
|
if (await FileSys.dirExists(targetPath))
|
|
11096
12652
|
await rm4(targetPath, { recursive: true, force: true });
|
|
11097
12653
|
}));
|
|
11098
12654
|
const syncPaths = [".husky", ".gitignore", "package.json"];
|
|
11099
|
-
await Promise.all(syncPaths.map((
|
|
12655
|
+
await Promise.all(syncPaths.map((path38) => cp(`${this.#app.workspace.cwdPath}/${path38}`, `${sourceRoot}/${path38}`, { recursive: true })));
|
|
11100
12656
|
await this.#writeSourceTsconfig(sourceRoot, libDeps);
|
|
11101
12657
|
await Bun.write(`${sourceRoot}/README.md`, readme);
|
|
11102
12658
|
await this.#app.workspace.spawn("tar", [
|
|
@@ -11187,20 +12743,20 @@ class ApplicationReleasePackager {
|
|
|
11187
12743
|
}
|
|
11188
12744
|
}
|
|
11189
12745
|
// pkgs/@akanjs/devkit/applicationTestPreload.ts
|
|
11190
|
-
import
|
|
12746
|
+
import path38 from "path";
|
|
11191
12747
|
var SIGNAL_TEST_PRELOAD_PATH = "test/signalTest.preload.ts";
|
|
11192
12748
|
async function resolveSignalTestPreloadPath(target) {
|
|
11193
12749
|
const candidates = [];
|
|
11194
12750
|
const addResolvedPackageCandidate = (basePath2) => {
|
|
11195
12751
|
try {
|
|
11196
|
-
candidates.push(
|
|
12752
|
+
candidates.push(path38.join(path38.dirname(Bun.resolveSync("akanjs/package.json", basePath2)), SIGNAL_TEST_PRELOAD_PATH));
|
|
11197
12753
|
} catch {}
|
|
11198
12754
|
};
|
|
11199
12755
|
addResolvedPackageCandidate(target.cwdPath);
|
|
11200
12756
|
addResolvedPackageCandidate(process.cwd());
|
|
11201
|
-
addResolvedPackageCandidate(
|
|
12757
|
+
addResolvedPackageCandidate(path38.dirname(Bun.main));
|
|
11202
12758
|
addResolvedPackageCandidate(import.meta.dir);
|
|
11203
|
-
candidates.push(
|
|
12759
|
+
candidates.push(path38.join(target.cwdPath, "../../node_modules/akanjs", SIGNAL_TEST_PRELOAD_PATH), path38.join(target.cwdPath, "../../pkgs/akanjs", SIGNAL_TEST_PRELOAD_PATH), path38.join(process.cwd(), "node_modules/akanjs", SIGNAL_TEST_PRELOAD_PATH), path38.join(process.cwd(), "pkgs/akanjs", SIGNAL_TEST_PRELOAD_PATH), path38.join(path38.dirname(Bun.main), "../../akanjs", SIGNAL_TEST_PRELOAD_PATH), path38.resolve(import.meta.dir, "../../akanjs", SIGNAL_TEST_PRELOAD_PATH));
|
|
11204
12760
|
for (const candidate of [...new Set(candidates)]) {
|
|
11205
12761
|
if (await Bun.file(candidate).exists())
|
|
11206
12762
|
return candidate;
|
|
@@ -11210,7 +12766,7 @@ async function resolveSignalTestPreloadPath(target) {
|
|
|
11210
12766
|
// pkgs/@akanjs/devkit/builder.ts
|
|
11211
12767
|
import { existsSync as existsSync2 } from "fs";
|
|
11212
12768
|
import { mkdir as mkdir10 } from "fs/promises";
|
|
11213
|
-
import
|
|
12769
|
+
import path39 from "path";
|
|
11214
12770
|
var SKIP_ENTRY_DIR_SET = new Set(["node_modules", "dist", "build", ".git", ".next"]);
|
|
11215
12771
|
var assetExtensions = [".css", ".md", ".js", ".png", ".ico", ".svg", ".json", ".template"];
|
|
11216
12772
|
var assetLoader = Object.fromEntries(assetExtensions.map((ext) => [ext, "file"]));
|
|
@@ -11227,14 +12783,14 @@ class Builder {
|
|
|
11227
12783
|
#globEntrypoints(cwd, pattern) {
|
|
11228
12784
|
const glob = new Bun.Glob(pattern);
|
|
11229
12785
|
return Array.from(glob.scanSync({ cwd, onlyFiles: true })).filter((relativePath) => {
|
|
11230
|
-
const segments = relativePath.split(
|
|
12786
|
+
const segments = relativePath.split(path39.sep);
|
|
11231
12787
|
return !segments.some((segment) => SKIP_ENTRY_DIR_SET.has(segment));
|
|
11232
|
-
}).map((rel) =>
|
|
12788
|
+
}).map((rel) => path39.join(cwd, rel));
|
|
11233
12789
|
}
|
|
11234
12790
|
#globFiles(cwd, pattern = "**/*.*") {
|
|
11235
12791
|
const glob = new Bun.Glob(pattern);
|
|
11236
12792
|
return Array.from(glob.scanSync({ cwd, onlyFiles: true })).filter((relativePath) => {
|
|
11237
|
-
const segments = relativePath.split(
|
|
12793
|
+
const segments = relativePath.split(path39.sep);
|
|
11238
12794
|
return !segments.some((segment) => SKIP_ENTRY_DIR_SET.has(segment));
|
|
11239
12795
|
});
|
|
11240
12796
|
}
|
|
@@ -11242,17 +12798,17 @@ class Builder {
|
|
|
11242
12798
|
const out = [];
|
|
11243
12799
|
for (const p of additionalEntryPoints) {
|
|
11244
12800
|
if (p.includes("*")) {
|
|
11245
|
-
const rel = p.startsWith(`${cwd}/`) || p.startsWith(`${cwd}${
|
|
12801
|
+
const rel = p.startsWith(`${cwd}/`) || p.startsWith(`${cwd}${path39.sep}`) ? p.slice(cwd.length + 1) : p;
|
|
11246
12802
|
out.push(...this.#globEntrypoints(cwd, rel));
|
|
11247
12803
|
} else
|
|
11248
|
-
out.push(
|
|
12804
|
+
out.push(path39.isAbsolute(p) ? p : path39.join(cwd, p));
|
|
11249
12805
|
}
|
|
11250
12806
|
return out;
|
|
11251
12807
|
}
|
|
11252
12808
|
#getBuildOptions({ bundle = false, additionalEntryPoints = [] } = {}) {
|
|
11253
12809
|
const cwd = this.#executor.cwdPath;
|
|
11254
12810
|
const entrypoints = [
|
|
11255
|
-
...bundle ? [
|
|
12811
|
+
...bundle ? [path39.join(cwd, "index.ts")] : this.#globEntrypoints(cwd, "**/*.{ts,tsx}"),
|
|
11256
12812
|
...this.#resolveAdditionalEntrypoints(cwd, additionalEntryPoints)
|
|
11257
12813
|
];
|
|
11258
12814
|
return {
|
|
@@ -11273,9 +12829,9 @@ class Builder {
|
|
|
11273
12829
|
for (const relativePath of this.#globFiles(cwd)) {
|
|
11274
12830
|
if (relativePath === "package.json")
|
|
11275
12831
|
continue;
|
|
11276
|
-
const sourcePath =
|
|
11277
|
-
const targetPath =
|
|
11278
|
-
await mkdir10(
|
|
12832
|
+
const sourcePath = path39.join(cwd, relativePath);
|
|
12833
|
+
const targetPath = path39.join(this.#distExecutor.cwdPath, relativePath);
|
|
12834
|
+
await mkdir10(path39.dirname(targetPath), { recursive: true });
|
|
11279
12835
|
await Bun.write(targetPath, Bun.file(sourcePath));
|
|
11280
12836
|
}
|
|
11281
12837
|
}
|
|
@@ -11286,13 +12842,13 @@ class Builder {
|
|
|
11286
12842
|
return withoutFormatDir;
|
|
11287
12843
|
if (!hasDotSlash && withoutFormatDir === publishedPath)
|
|
11288
12844
|
return publishedPath;
|
|
11289
|
-
const parsed =
|
|
12845
|
+
const parsed = path39.posix.parse(withoutFormatDir);
|
|
11290
12846
|
if (![".js", ".mjs", ".cjs"].includes(parsed.ext))
|
|
11291
12847
|
return withoutFormatDir;
|
|
11292
|
-
const withoutExt =
|
|
12848
|
+
const withoutExt = path39.posix.join(parsed.dir, parsed.name);
|
|
11293
12849
|
const sourcePath = withoutExt.startsWith("./") ? withoutExt.slice(2) : withoutExt;
|
|
11294
12850
|
const sourceCandidates = [`${sourcePath}.ts`, `${sourcePath}.tsx`];
|
|
11295
|
-
const matchedSource = sourceCandidates.find((candidate) => existsSync2(
|
|
12851
|
+
const matchedSource = sourceCandidates.find((candidate) => existsSync2(path39.join(this.#executor.cwdPath, candidate)));
|
|
11296
12852
|
if (!matchedSource)
|
|
11297
12853
|
return withoutFormatDir;
|
|
11298
12854
|
return hasDotSlash ? `./${matchedSource}` : matchedSource;
|
|
@@ -11343,10 +12899,10 @@ class Builder {
|
|
|
11343
12899
|
// pkgs/@akanjs/devkit/capacitorApp.ts
|
|
11344
12900
|
import { cp as cp2, mkdir as mkdir11, rm as rm5 } from "fs/promises";
|
|
11345
12901
|
import os from "os";
|
|
11346
|
-
import
|
|
12902
|
+
import path40 from "path";
|
|
11347
12903
|
import { select as select2 } from "@inquirer/prompts";
|
|
11348
12904
|
import { MobileProject } from "@trapezedev/project";
|
|
11349
|
-
import { capitalize as
|
|
12905
|
+
import { capitalize as capitalize5 } from "akanjs/common";
|
|
11350
12906
|
|
|
11351
12907
|
// pkgs/@akanjs/devkit/fileEditor.ts
|
|
11352
12908
|
class FileEditor {
|
|
@@ -11550,13 +13106,13 @@ var rootCapacitorConfigFilenames = [
|
|
|
11550
13106
|
"capacitor.config.js",
|
|
11551
13107
|
"capacitor.config.json"
|
|
11552
13108
|
];
|
|
11553
|
-
var rootCapacitorConfigPaths = (appRoot) => rootCapacitorConfigFilenames.map((file) =>
|
|
13109
|
+
var rootCapacitorConfigPaths = (appRoot) => rootCapacitorConfigFilenames.map((file) => path40.join(appRoot, file));
|
|
11554
13110
|
async function clearRootCapacitorConfigs(appRoot) {
|
|
11555
13111
|
await Promise.all(rootCapacitorConfigPaths(appRoot).map((file) => rm5(file, { force: true })));
|
|
11556
13112
|
}
|
|
11557
13113
|
async function writeRootCapacitorConfig(appRoot, content) {
|
|
11558
13114
|
await clearRootCapacitorConfigs(appRoot);
|
|
11559
|
-
await Bun.write(
|
|
13115
|
+
await Bun.write(path40.join(appRoot, "capacitor.config.json"), content);
|
|
11560
13116
|
}
|
|
11561
13117
|
var getLocalIP = () => {
|
|
11562
13118
|
const interfaces = os.networkInterfaces();
|
|
@@ -11570,7 +13126,7 @@ var getLocalIP = () => {
|
|
|
11570
13126
|
}
|
|
11571
13127
|
return "127.0.0.1";
|
|
11572
13128
|
};
|
|
11573
|
-
var
|
|
13129
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11574
13130
|
var asString = (value) => typeof value === "string" ? value : undefined;
|
|
11575
13131
|
var firstString = (...values) => values.find((value) => typeof value === "string");
|
|
11576
13132
|
var scoreIosDeviceTarget = (target) => {
|
|
@@ -11594,7 +13150,7 @@ function walkRecords(value, visit) {
|
|
|
11594
13150
|
walkRecords(item, visit);
|
|
11595
13151
|
return;
|
|
11596
13152
|
}
|
|
11597
|
-
if (!
|
|
13153
|
+
if (!isRecord2(value))
|
|
11598
13154
|
return;
|
|
11599
13155
|
visit(value);
|
|
11600
13156
|
for (const item of Object.values(value))
|
|
@@ -11605,9 +13161,9 @@ function parseDevicectlDevices(output) {
|
|
|
11605
13161
|
const json = JSON.parse(output);
|
|
11606
13162
|
const targets = new Map;
|
|
11607
13163
|
walkRecords(json, (record) => {
|
|
11608
|
-
const deviceProperties =
|
|
11609
|
-
const hardwareProperties =
|
|
11610
|
-
const connectionProperties =
|
|
13164
|
+
const deviceProperties = isRecord2(record.deviceProperties) ? record.deviceProperties : {};
|
|
13165
|
+
const hardwareProperties = isRecord2(record.hardwareProperties) ? record.hardwareProperties : {};
|
|
13166
|
+
const connectionProperties = isRecord2(record.connectionProperties) ? record.connectionProperties : {};
|
|
11611
13167
|
const devicectlId = firstString(record.identifier, record.deviceIdentifier);
|
|
11612
13168
|
const potentialHostnames = Array.isArray(connectionProperties.potentialHostnames) ? connectionProperties.potentialHostnames.filter((value) => typeof value === "string") : [];
|
|
11613
13169
|
const hostnameUdid = potentialHostnames.map((hostname) => hostname.match(/([0-9A-Fa-f]{8}-[0-9A-Fa-f]{16})\.coredevice\.local/)?.[1]).find((value) => Boolean(value));
|
|
@@ -11640,7 +13196,7 @@ function parseSimctlDevices(output) {
|
|
|
11640
13196
|
try {
|
|
11641
13197
|
const json = JSON.parse(output);
|
|
11642
13198
|
const devices = json.devices ?? {};
|
|
11643
|
-
return Object.values(devices).flatMap((runtimeDevices) => runtimeDevices).filter(
|
|
13199
|
+
return Object.values(devices).flatMap((runtimeDevices) => runtimeDevices).filter(isRecord2).flatMap((device) => {
|
|
11644
13200
|
const id = firstString(device.udid, device.UDID, device.identifier);
|
|
11645
13201
|
const name = firstString(device.name, device.displayName);
|
|
11646
13202
|
const isAvailable = device.isAvailable !== false && device.availabilityError === undefined;
|
|
@@ -11665,13 +13221,13 @@ function buildIosNativeRunCommand({
|
|
|
11665
13221
|
scheme = "App",
|
|
11666
13222
|
configuration = "Debug"
|
|
11667
13223
|
}) {
|
|
11668
|
-
const derivedDataPath =
|
|
13224
|
+
const derivedDataPath = path40.join(appRoot, "ios/DerivedData", device.id);
|
|
11669
13225
|
const productPlatform = device.kind === "device" ? "iphoneos" : "iphonesimulator";
|
|
11670
13226
|
const destination = device.kind === "device" ? `id=${device.xcodebuildId ?? device.id}` : `platform=iOS Simulator,id=${device.id}`;
|
|
11671
13227
|
return {
|
|
11672
13228
|
configuration,
|
|
11673
13229
|
derivedDataPath,
|
|
11674
|
-
appPath:
|
|
13230
|
+
appPath: path40.join(derivedDataPath, "Build/Products", `${configuration}-${productPlatform}`, "App.app"),
|
|
11675
13231
|
xcodebuildArgs: [
|
|
11676
13232
|
"-project",
|
|
11677
13233
|
"App.xcodeproj",
|
|
@@ -11872,16 +13428,16 @@ function materializeCapacitorConfig(target, { operation, localServerUrl, localIp
|
|
|
11872
13428
|
experimental,
|
|
11873
13429
|
...capacitorConfig
|
|
11874
13430
|
} = target;
|
|
11875
|
-
const serverConfig =
|
|
11876
|
-
const cordovaConfig =
|
|
11877
|
-
const experimentalConfig =
|
|
11878
|
-
const pluginsConfig =
|
|
11879
|
-
const keyboardPluginConfig =
|
|
13431
|
+
const serverConfig = isRecord2(server) ? server : undefined;
|
|
13432
|
+
const cordovaConfig = isRecord2(cordova) ? cordova : undefined;
|
|
13433
|
+
const experimentalConfig = isRecord2(experimental) ? experimental : undefined;
|
|
13434
|
+
const pluginsConfig = isRecord2(plugins) ? plugins : {};
|
|
13435
|
+
const keyboardPluginConfig = isRecord2(pluginsConfig.Keyboard) ? pluginsConfig.Keyboard : {};
|
|
11880
13436
|
const config = {
|
|
11881
13437
|
...capacitorConfig,
|
|
11882
13438
|
appId,
|
|
11883
13439
|
appName,
|
|
11884
|
-
webDir:
|
|
13440
|
+
webDir: path40.posix.join(".akan", "mobile", name, "www"),
|
|
11885
13441
|
plugins: {
|
|
11886
13442
|
CapacitorCookies: { enabled: true },
|
|
11887
13443
|
...pluginsConfig,
|
|
@@ -11891,11 +13447,11 @@ function materializeCapacitorConfig(target, { operation, localServerUrl, localIp
|
|
|
11891
13447
|
}
|
|
11892
13448
|
},
|
|
11893
13449
|
android: {
|
|
11894
|
-
...
|
|
13450
|
+
...isRecord2(android) ? android : {},
|
|
11895
13451
|
path: "android"
|
|
11896
13452
|
},
|
|
11897
13453
|
ios: {
|
|
11898
|
-
...
|
|
13454
|
+
...isRecord2(ios) ? ios : {},
|
|
11899
13455
|
path: "ios"
|
|
11900
13456
|
}
|
|
11901
13457
|
};
|
|
@@ -11938,10 +13494,10 @@ class CapacitorApp {
|
|
|
11938
13494
|
constructor(app, target) {
|
|
11939
13495
|
this.app = app;
|
|
11940
13496
|
this.target = target;
|
|
11941
|
-
this.targetRootPath =
|
|
11942
|
-
this.targetRoot =
|
|
11943
|
-
this.targetWebRoot =
|
|
11944
|
-
this.targetAssetRoot =
|
|
13497
|
+
this.targetRootPath = path40.posix.join(".akan", "mobile", this.target.name);
|
|
13498
|
+
this.targetRoot = path40.join(this.app.cwdPath, this.targetRootPath);
|
|
13499
|
+
this.targetWebRoot = path40.join(this.targetRoot, "www");
|
|
13500
|
+
this.targetAssetRoot = path40.join(this.targetRoot, "assets");
|
|
11945
13501
|
this.project = new MobileProject(this.app.cwdPath, {
|
|
11946
13502
|
android: { path: this.androidRootPath },
|
|
11947
13503
|
ios: { path: this.iosProjectPath }
|
|
@@ -11956,9 +13512,9 @@ class CapacitorApp {
|
|
|
11956
13512
|
await mkdir11(this.targetRoot, { recursive: true });
|
|
11957
13513
|
if (regenerate) {
|
|
11958
13514
|
if (!platform || platform === "ios")
|
|
11959
|
-
await rm5(
|
|
13515
|
+
await rm5(path40.join(this.app.cwdPath, this.iosRootPath), { recursive: true, force: true });
|
|
11960
13516
|
if (!platform || platform === "android")
|
|
11961
|
-
await rm5(
|
|
13517
|
+
await rm5(path40.join(this.app.cwdPath, this.androidRootPath), { recursive: true, force: true });
|
|
11962
13518
|
}
|
|
11963
13519
|
const project = this.project;
|
|
11964
13520
|
await this.project.load();
|
|
@@ -12081,7 +13637,7 @@ ${textError instanceof Error ? textError.message : ""}`);
|
|
|
12081
13637
|
const xcodebuildArgs = noAllowProvisioningUpdates ? command.xcodebuildArgs : [...command.xcodebuildArgs.slice(0, -1), "-allowProvisioningUpdates", ...command.xcodebuildArgs.slice(-1)];
|
|
12082
13638
|
try {
|
|
12083
13639
|
await this.#spawn("xcodebuild", xcodebuildArgs, {
|
|
12084
|
-
cwd:
|
|
13640
|
+
cwd: path40.join(this.app.cwdPath, this.iosProjectPath),
|
|
12085
13641
|
env: mobileEnv
|
|
12086
13642
|
});
|
|
12087
13643
|
const devicectlId = runTarget.devicectlId ?? runTarget.id;
|
|
@@ -12103,10 +13659,10 @@ ${textError instanceof Error ? textError.message : ""}`);
|
|
|
12103
13659
|
}
|
|
12104
13660
|
}
|
|
12105
13661
|
#iosScheme() {
|
|
12106
|
-
return
|
|
13662
|
+
return isRecord2(this.target.ios) && typeof this.target.ios.scheme === "string" ? this.target.ios.scheme : "App";
|
|
12107
13663
|
}
|
|
12108
13664
|
async#getIosDevelopmentTeam() {
|
|
12109
|
-
const pbxprojPath =
|
|
13665
|
+
const pbxprojPath = path40.join(this.app.cwdPath, this.iosProjectPath, "App.xcodeproj/project.pbxproj");
|
|
12110
13666
|
if (!await Bun.file(pbxprojPath).exists())
|
|
12111
13667
|
return;
|
|
12112
13668
|
return (await Bun.file(pbxprojPath).text()).match(/DEVELOPMENT_TEAM = ([^;]+);/)?.[1]?.trim();
|
|
@@ -12132,7 +13688,7 @@ ${error.message}`;
|
|
|
12132
13688
|
await this.#spawnMobile("npx", ["cap", "sync", "android"], { operation, env });
|
|
12133
13689
|
}
|
|
12134
13690
|
async#updateAndroidBuildTypes() {
|
|
12135
|
-
const appGradle = await FileEditor.create(
|
|
13691
|
+
const appGradle = await FileEditor.create(path40.join(this.app.cwdPath, this.androidRootPath, "app/build.gradle"));
|
|
12136
13692
|
const buildTypesBlock = `
|
|
12137
13693
|
debug {
|
|
12138
13694
|
applicationIdSuffix ".debug"
|
|
@@ -12176,7 +13732,7 @@ ${error.message}`;
|
|
|
12176
13732
|
const gradleCommand = isWindows ? "gradlew.bat" : "./gradlew";
|
|
12177
13733
|
await this.app.spawn(gradleCommand, [assembleType === "apk" ? "assembleRelease" : "bundleRelease"], {
|
|
12178
13734
|
stdio: "inherit",
|
|
12179
|
-
cwd:
|
|
13735
|
+
cwd: path40.join(this.app.cwdPath, this.androidRootPath),
|
|
12180
13736
|
env: await this.#commandEnv("release", env)
|
|
12181
13737
|
});
|
|
12182
13738
|
}
|
|
@@ -12184,10 +13740,10 @@ ${error.message}`;
|
|
|
12184
13740
|
await this.#spawnMobile("npx", ["cap", "open", "android"], { operation: "local", env: "local" });
|
|
12185
13741
|
}
|
|
12186
13742
|
async#ensureAndroidAssetsDir() {
|
|
12187
|
-
await mkdir11(
|
|
13743
|
+
await mkdir11(path40.join(this.app.cwdPath, this.androidAssetsPath), { recursive: true });
|
|
12188
13744
|
}
|
|
12189
13745
|
async#ensureAndroidDebugKeystore() {
|
|
12190
|
-
const keystorePath =
|
|
13746
|
+
const keystorePath = path40.join(this.app.cwdPath, this.androidRootPath, "app/debug.keystore");
|
|
12191
13747
|
if (await Bun.file(keystorePath).exists())
|
|
12192
13748
|
return;
|
|
12193
13749
|
await this.#spawn("keytool", [
|
|
@@ -12226,7 +13782,7 @@ ${error.message}`;
|
|
|
12226
13782
|
await this.#spawnMobile("npx", args, { operation, env }, { stdio: "inherit" });
|
|
12227
13783
|
}
|
|
12228
13784
|
async#assertAndroidReleaseSigningConfig() {
|
|
12229
|
-
const gradlePropertiesPath =
|
|
13785
|
+
const gradlePropertiesPath = path40.join(this.app.cwdPath, this.androidRootPath, "gradle.properties");
|
|
12230
13786
|
const gradleProperties = await Bun.file(gradlePropertiesPath).exists() ? await Bun.file(gradlePropertiesPath).text() : "";
|
|
12231
13787
|
const missingKeys = getMissingAndroidReleaseSigningKeys({ gradleProperties });
|
|
12232
13788
|
if (missingKeys.length > 0)
|
|
@@ -12253,12 +13809,12 @@ ${error.message}`;
|
|
|
12253
13809
|
await this.#prepareAndroid({ operation: "release", env: "main" });
|
|
12254
13810
|
}
|
|
12255
13811
|
async prepareWww() {
|
|
12256
|
-
const htmlSource =
|
|
13812
|
+
const htmlSource = path40.join(this.app.dist.cwdPath, "csr", targetHtmlFilename(this.target));
|
|
12257
13813
|
if (!await Bun.file(htmlSource).exists())
|
|
12258
13814
|
throw new Error(`CSR html for mobile target '${this.target.name}' not found: ${htmlSource}`);
|
|
12259
13815
|
await rm5(this.targetWebRoot, { recursive: true, force: true });
|
|
12260
13816
|
await mkdir11(this.targetWebRoot, { recursive: true });
|
|
12261
|
-
await Bun.write(
|
|
13817
|
+
await Bun.write(path40.join(this.targetWebRoot, "index.html"), this.#injectMobileTargetMeta(await Bun.file(htmlSource).text()));
|
|
12262
13818
|
}
|
|
12263
13819
|
#injectMobileTargetMeta(html) {
|
|
12264
13820
|
const basePath2 = this.target.basePath?.replace(/^\/+|\/+$/g, "") ?? "";
|
|
@@ -12278,7 +13834,7 @@ ${error.message}`;
|
|
|
12278
13834
|
});
|
|
12279
13835
|
const content = `${JSON.stringify(config, null, 2)}
|
|
12280
13836
|
`;
|
|
12281
|
-
await Bun.write(
|
|
13837
|
+
await Bun.write(path40.join(this.targetRoot, "capacitor.config.json"), content);
|
|
12282
13838
|
return content;
|
|
12283
13839
|
}
|
|
12284
13840
|
async#prepareTargetAssets() {
|
|
@@ -12286,11 +13842,11 @@ ${error.message}`;
|
|
|
12286
13842
|
return;
|
|
12287
13843
|
await mkdir11(this.targetAssetRoot, { recursive: true });
|
|
12288
13844
|
if (this.target.assets.icon)
|
|
12289
|
-
await cp2(
|
|
13845
|
+
await cp2(path40.join(this.app.cwdPath, this.target.assets.icon), path40.join(this.targetAssetRoot, "icon.png"), {
|
|
12290
13846
|
force: true
|
|
12291
13847
|
});
|
|
12292
13848
|
if (this.target.assets.splash)
|
|
12293
|
-
await cp2(
|
|
13849
|
+
await cp2(path40.join(this.app.cwdPath, this.target.assets.splash), path40.join(this.targetAssetRoot, "splash.png"), {
|
|
12294
13850
|
force: true
|
|
12295
13851
|
});
|
|
12296
13852
|
}
|
|
@@ -12298,11 +13854,11 @@ ${error.message}`;
|
|
|
12298
13854
|
const files = this.target.files?.[platform];
|
|
12299
13855
|
if (!files)
|
|
12300
13856
|
return;
|
|
12301
|
-
const platformRoot =
|
|
13857
|
+
const platformRoot = path40.join(this.app.cwdPath, platform === "ios" ? this.iosRootPath : this.androidRootPath);
|
|
12302
13858
|
await Promise.all(Object.entries(files).map(async ([to, from]) => {
|
|
12303
|
-
const targetPath =
|
|
12304
|
-
await mkdir11(
|
|
12305
|
-
await cp2(
|
|
13859
|
+
const targetPath = path40.join(platformRoot, to);
|
|
13860
|
+
await mkdir11(path40.dirname(targetPath), { recursive: true });
|
|
13861
|
+
await cp2(path40.join(this.app.cwdPath, from), targetPath, { force: true });
|
|
12306
13862
|
}));
|
|
12307
13863
|
}
|
|
12308
13864
|
async#generateAssets({ operation, env }) {
|
|
@@ -12312,7 +13868,7 @@ ${error.message}`;
|
|
|
12312
13868
|
"@capacitor/assets",
|
|
12313
13869
|
"generate",
|
|
12314
13870
|
"--assetPath",
|
|
12315
|
-
|
|
13871
|
+
path40.posix.join(this.targetRootPath, "assets"),
|
|
12316
13872
|
"--iosProject",
|
|
12317
13873
|
this.iosProjectPath,
|
|
12318
13874
|
"--androidProject",
|
|
@@ -12437,7 +13993,7 @@ ${error.message}`;
|
|
|
12437
13993
|
this.#setPermissionsInAndroid(["POST_NOTIFICATIONS"]);
|
|
12438
13994
|
}
|
|
12439
13995
|
async#setPermissionInIos(permissions) {
|
|
12440
|
-
const updateNs = Object.fromEntries(Object.entries(permissions).map(([key, value]) => [`NS${
|
|
13996
|
+
const updateNs = Object.fromEntries(Object.entries(permissions).map(([key, value]) => [`NS${capitalize5(key)}`, value]));
|
|
12441
13997
|
await Promise.all([
|
|
12442
13998
|
this.project.ios.updateInfoPlist(this.iosTargetName, "Debug", updateNs),
|
|
12443
13999
|
this.project.ios.updateInfoPlist(this.iosTargetName, "Release", updateNs)
|
|
@@ -12522,15 +14078,15 @@ var Pkg = createInternalArgToken("Pkg");
|
|
|
12522
14078
|
var Module = createInternalArgToken("Module");
|
|
12523
14079
|
var Workspace = createInternalArgToken("Workspace");
|
|
12524
14080
|
// pkgs/@akanjs/devkit/commandDecorators/command.ts
|
|
12525
|
-
import
|
|
14081
|
+
import path41 from "path";
|
|
12526
14082
|
import { confirm, input as input2, select as select3 } from "@inquirer/prompts";
|
|
12527
14083
|
import { Logger as Logger10 } from "akanjs/common";
|
|
12528
14084
|
import chalk6 from "chalk";
|
|
12529
14085
|
import { program } from "commander";
|
|
12530
14086
|
|
|
12531
14087
|
// pkgs/@akanjs/devkit/commandDecorators/dependencyBuilder.ts
|
|
12532
|
-
var
|
|
12533
|
-
var createDependencyKey = (refName, kind) => `${refName}${
|
|
14088
|
+
var capitalize6 = (value) => value.slice(0, 1).toUpperCase() + value.slice(1);
|
|
14089
|
+
var createDependencyKey = (refName, kind) => `${refName}${capitalize6(kind)}`;
|
|
12534
14090
|
|
|
12535
14091
|
class CommandContainer {
|
|
12536
14092
|
static #instances = new Map;
|
|
@@ -13026,7 +14582,7 @@ var runCommands = async (...commands) => {
|
|
|
13026
14582
|
process.exit(1);
|
|
13027
14583
|
});
|
|
13028
14584
|
const __dirname2 = getDirname(import.meta.url);
|
|
13029
|
-
const packageJsonCandidates = [`${
|
|
14585
|
+
const packageJsonCandidates = [`${path41.dirname(Bun.main)}/package.json`, `${__dirname2}/../package.json`];
|
|
13030
14586
|
let cliPackageJson = null;
|
|
13031
14587
|
for (const packageJsonPath of packageJsonCandidates) {
|
|
13032
14588
|
if (!await FileSys.fileExists(packageJsonPath))
|
|
@@ -13269,11 +14825,11 @@ var NODE_NATIVE_MODULE_SET = new Set([
|
|
|
13269
14825
|
// pkgs/@akanjs/devkit/getCredentials.ts
|
|
13270
14826
|
import yaml from "js-yaml";
|
|
13271
14827
|
// pkgs/@akanjs/devkit/getModelFileData.ts
|
|
13272
|
-
import { capitalize as
|
|
14828
|
+
import { capitalize as capitalize7 } from "akanjs/common";
|
|
13273
14829
|
// pkgs/@akanjs/devkit/getRelatedCnsts.ts
|
|
13274
14830
|
import { readFileSync as readFileSync4, realpathSync } from "fs";
|
|
13275
14831
|
import ora2 from "ora";
|
|
13276
|
-
import * as
|
|
14832
|
+
import * as ts10 from "typescript";
|
|
13277
14833
|
var tsTranspiler = new Bun.Transpiler({ loader: "ts" });
|
|
13278
14834
|
var tsxTranspiler = new Bun.Transpiler({ loader: "tsx" });
|
|
13279
14835
|
var getTranspiler = (filePath) => filePath.endsWith(".tsx") ? tsxTranspiler : tsTranspiler;
|
|
@@ -13306,10 +14862,10 @@ var scanModuleSpecifiers = (source2, filePath, includeExports) => {
|
|
|
13306
14862
|
return importSpecifiers;
|
|
13307
14863
|
};
|
|
13308
14864
|
var parseTsConfig = (tsConfigPath = "./tsconfig.json") => {
|
|
13309
|
-
const configFile =
|
|
13310
|
-
return
|
|
14865
|
+
const configFile = ts10.readConfigFile(tsConfigPath, (path42) => {
|
|
14866
|
+
return ts10.sys.readFile(path42);
|
|
13311
14867
|
});
|
|
13312
|
-
return
|
|
14868
|
+
return ts10.parseJsonConfigFileContent(configFile.config, ts10.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
|
|
13313
14869
|
};
|
|
13314
14870
|
var collectImportedFiles = (constantFilePath, parsedConfig) => {
|
|
13315
14871
|
const allFilesToAnalyze = new Set([constantFilePath]);
|
|
@@ -13324,7 +14880,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
|
|
|
13324
14880
|
for (const importPath of scanModuleSpecifiers(source2, filePath, false)) {
|
|
13325
14881
|
if (!importPath.startsWith("."))
|
|
13326
14882
|
continue;
|
|
13327
|
-
const resolved =
|
|
14883
|
+
const resolved = ts10.resolveModuleName(importPath, filePath, parsedConfig.options, ts10.sys).resolvedModule?.resolvedFileName;
|
|
13328
14884
|
if (resolved && !allFilesToAnalyze.has(resolved)) {
|
|
13329
14885
|
allFilesToAnalyze.add(resolved);
|
|
13330
14886
|
collectImported(resolved);
|
|
@@ -13341,7 +14897,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
|
|
|
13341
14897
|
var createTsProgram = (filePaths, options) => {
|
|
13342
14898
|
const spinner = ora2("Creating TypeScript program for all files...");
|
|
13343
14899
|
spinner.start();
|
|
13344
|
-
const program2 =
|
|
14900
|
+
const program2 = ts10.createProgram(Array.from(filePaths), options);
|
|
13345
14901
|
const checker = program2.getTypeChecker();
|
|
13346
14902
|
spinner.succeed("TypeScript program created.");
|
|
13347
14903
|
return {
|
|
@@ -13381,17 +14937,17 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
|
|
|
13381
14937
|
function visit(node) {
|
|
13382
14938
|
if (!source2)
|
|
13383
14939
|
return;
|
|
13384
|
-
if (
|
|
14940
|
+
if (ts10.isPropertyAccessExpression(node)) {
|
|
13385
14941
|
const left = node.expression;
|
|
13386
14942
|
const right = node.name;
|
|
13387
|
-
const { line } =
|
|
13388
|
-
if (
|
|
14943
|
+
const { line } = ts10.getLineAndCharacterOfPosition(source2, node.getStart());
|
|
14944
|
+
if (ts10.isIdentifier(left) && sourceLines && sourceLines.length > line && sourceLines[line] && (sourceLines[line]?.includes(`@Field.Prop(() => ${left.text}.${right.text}`) || sourceLines[line].includes(`base.Filter(${left.text}.${right.text},`))) {
|
|
13389
14945
|
const symbol = getCachedSymbol(right);
|
|
13390
14946
|
if (symbol?.declarations && symbol.declarations.length > 0) {
|
|
13391
14947
|
const key = symbol.declarations[0]?.getSourceFile().fileName.split("/").pop()?.split(".")[0] ?? "";
|
|
13392
14948
|
const property = propertyMap.get(key);
|
|
13393
14949
|
const isScalar = symbol.declarations[0]?.getSourceFile().fileName.includes("_") ?? false;
|
|
13394
|
-
const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${
|
|
14950
|
+
const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${ts10.sys.getCurrentDirectory()}/`, "");
|
|
13395
14951
|
if (!symbolFilePath)
|
|
13396
14952
|
throw new Error(`No symbol file path found for ${left.text}.${right.text}`);
|
|
13397
14953
|
if (property) {
|
|
@@ -13415,10 +14971,10 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
|
|
|
13415
14971
|
}
|
|
13416
14972
|
}
|
|
13417
14973
|
}
|
|
13418
|
-
} else if (
|
|
14974
|
+
} else if (ts10.isImportDeclaration(node) && ts10.isStringLiteral(node.moduleSpecifier)) {
|
|
13419
14975
|
const importPath = node.moduleSpecifier.text;
|
|
13420
14976
|
if (importPath.startsWith(".")) {
|
|
13421
|
-
const resolved =
|
|
14977
|
+
const resolved = ts10.resolveModuleName(importPath, filePath, program2.getCompilerOptions(), ts10.sys).resolvedModule?.resolvedFileName;
|
|
13422
14978
|
const moduleName = importPath.split("/").pop()?.split(".")[0] ?? "";
|
|
13423
14979
|
const property = propertyMap.get(moduleName);
|
|
13424
14980
|
const isScalar = importPath.includes("_");
|
|
@@ -13433,7 +14989,7 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
|
|
|
13433
14989
|
}
|
|
13434
14990
|
}
|
|
13435
14991
|
}
|
|
13436
|
-
|
|
14992
|
+
ts10.forEachChild(node, visit);
|
|
13437
14993
|
}
|
|
13438
14994
|
visit(source2);
|
|
13439
14995
|
}
|
|
@@ -13640,10 +15196,10 @@ class IncrementalBuilder {
|
|
|
13640
15196
|
}
|
|
13641
15197
|
}
|
|
13642
15198
|
batchTouchesPagesTree(appDir, batch) {
|
|
13643
|
-
const absAppDir =
|
|
15199
|
+
const absAppDir = path42.resolve(appDir);
|
|
13644
15200
|
for (const f of batch.files) {
|
|
13645
|
-
const abs =
|
|
13646
|
-
if (!abs.startsWith(`${absAppDir}${
|
|
15201
|
+
const abs = path42.resolve(f);
|
|
15202
|
+
if (!abs.startsWith(`${absAppDir}${path42.sep}`) && abs !== absAppDir)
|
|
13647
15203
|
continue;
|
|
13648
15204
|
if (/\.(tsx|ts|jsx|js)$/.test(abs))
|
|
13649
15205
|
return true;
|
|
@@ -13651,15 +15207,15 @@ class IncrementalBuilder {
|
|
|
13651
15207
|
return false;
|
|
13652
15208
|
}
|
|
13653
15209
|
async batchMayChangePageKeys(appDir, batch) {
|
|
13654
|
-
const absAppDir =
|
|
13655
|
-
const pageKeys = new Set((await this.#app.getPageKeys()).map((key) =>
|
|
15210
|
+
const absAppDir = path42.resolve(appDir);
|
|
15211
|
+
const pageKeys = new Set((await this.#app.getPageKeys()).map((key) => path42.normalize(key)));
|
|
13656
15212
|
for (const f of batch.files) {
|
|
13657
|
-
const abs =
|
|
13658
|
-
if (!abs.startsWith(`${absAppDir}${
|
|
15213
|
+
const abs = path42.resolve(f);
|
|
15214
|
+
if (!abs.startsWith(`${absAppDir}${path42.sep}`) && abs !== absAppDir)
|
|
13659
15215
|
continue;
|
|
13660
15216
|
if (!/\.(tsx|ts|jsx|js)$/.test(abs))
|
|
13661
15217
|
continue;
|
|
13662
|
-
const rel =
|
|
15218
|
+
const rel = path42.normalize(path42.relative(absAppDir, abs));
|
|
13663
15219
|
if (!await Bun.file(abs).exists() || !pageKeys.has(rel))
|
|
13664
15220
|
return true;
|
|
13665
15221
|
}
|
|
@@ -13687,7 +15243,7 @@ class IncrementalBuilder {
|
|
|
13687
15243
|
${cssText}`).toString(36);
|
|
13688
15244
|
const cssRelPath = `styles/${cssAssetName}-${cssHash}.css`;
|
|
13689
15245
|
const cssUrl = `/_akan/styles/${cssAssetName}-${cssHash}.css`;
|
|
13690
|
-
await Bun.write(
|
|
15246
|
+
await Bun.write(path42.join(artifactDir, cssRelPath), cssText);
|
|
13691
15247
|
cssAssetEntries.push([basePath2, { cssUrl, cssRelPath }]);
|
|
13692
15248
|
cssBase64ByUrl[cssUrl] = Buffer.from(new TextEncoder().encode(cssText)).toString("base64");
|
|
13693
15249
|
})()
|
|
@@ -13755,10 +15311,10 @@ ${cssText}`).toString(36);
|
|
|
13755
15311
|
if (changedFiles.length === 0)
|
|
13756
15312
|
return false;
|
|
13757
15313
|
return changedFiles.some((file) => {
|
|
13758
|
-
const normalized =
|
|
15314
|
+
const normalized = path42.resolve(file);
|
|
13759
15315
|
if (/\.(woff2?|ttf|otf)$/i.test(normalized))
|
|
13760
15316
|
return true;
|
|
13761
|
-
return this.#optimizedFonts.files.some((fontFile) =>
|
|
15317
|
+
return this.#optimizedFonts.files.some((fontFile) => path42.resolve(fontFile) === normalized);
|
|
13762
15318
|
});
|
|
13763
15319
|
}
|
|
13764
15320
|
async installWatcher() {
|