@akanjs/cli 2.3.9-rc.6 → 2.3.9-rc.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/incrementalBuilder.proc.js +1870 -485
- package/index.js +4045 -2821
- 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,24 @@ 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 inferNextActionCode = (action, diagnostics) => {
|
|
4803
|
+
if (action.action)
|
|
4804
|
+
return action.action;
|
|
4805
|
+
if (sourceChangeBlocked(diagnostics) && action.command.startsWith("akan workflow explain"))
|
|
4806
|
+
return "blocked";
|
|
4807
|
+
if (action.command.startsWith("akan workflow repair"))
|
|
4808
|
+
return "repair";
|
|
4809
|
+
if (action.command.startsWith("akan workflow explain"))
|
|
4810
|
+
return "manual-review";
|
|
4811
|
+
if (action.command.startsWith("akan "))
|
|
4812
|
+
return "validate";
|
|
4813
|
+
return "answer";
|
|
4814
|
+
};
|
|
4815
|
+
var nextActionPriority = (action, diagnostics) => {
|
|
4816
|
+
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 };
|
|
4817
|
+
return priority[action.action ?? "answer"];
|
|
4818
|
+
};
|
|
4801
4819
|
var createWorkflowApplyReport = ({
|
|
4802
4820
|
workflow,
|
|
4803
4821
|
mode,
|
|
@@ -4813,11 +4831,18 @@ var createWorkflowApplyReport = ({
|
|
|
4813
4831
|
plan
|
|
4814
4832
|
}) => {
|
|
4815
4833
|
const validationCommands = recommendedValidationCommands ?? commands;
|
|
4816
|
-
const
|
|
4817
|
-
|
|
4818
|
-
|
|
4819
|
-
|
|
4820
|
-
|
|
4834
|
+
const nextActionsWithIntent = nextActions.map((action) => ({
|
|
4835
|
+
...action,
|
|
4836
|
+
action: inferNextActionCode(action, diagnostics)
|
|
4837
|
+
}));
|
|
4838
|
+
if (sourceChangeBlocked(diagnostics) && !nextActionsWithIntent.some((action) => action.action === "blocked")) {
|
|
4839
|
+
nextActionsWithIntent.unshift({
|
|
4840
|
+
command: `akan workflow explain ${workflow}`,
|
|
4841
|
+
reason: "Review source-change blockers before running validation.",
|
|
4842
|
+
action: "blocked"
|
|
4843
|
+
});
|
|
4844
|
+
}
|
|
4845
|
+
const orderedNextActions = uniqueBy(nextActionsWithIntent, (action) => action.command).sort((left, right) => nextActionPriority(left, diagnostics) - nextActionPriority(right, diagnostics));
|
|
4821
4846
|
return {
|
|
4822
4847
|
schemaVersion: 1,
|
|
4823
4848
|
workflow,
|
|
@@ -5054,7 +5079,14 @@ var createRepairReport = ({
|
|
|
5054
5079
|
...syncedAt ? { syncedAt } : {}
|
|
5055
5080
|
});
|
|
5056
5081
|
// pkgs/@akanjs/devkit/workflow/executor.ts
|
|
5057
|
-
import
|
|
5082
|
+
import ts6 from "typescript";
|
|
5083
|
+
|
|
5084
|
+
// pkgs/@akanjs/devkit/workflow/moduleIndex.ts
|
|
5085
|
+
import { access } from "fs/promises";
|
|
5086
|
+
import path10 from "path";
|
|
5087
|
+
import ts5 from "typescript";
|
|
5088
|
+
|
|
5089
|
+
// pkgs/@akanjs/devkit/workflow/source.ts
|
|
5058
5090
|
import ts4 from "typescript";
|
|
5059
5091
|
|
|
5060
5092
|
// pkgs/@akanjs/devkit/workflow/primitive.ts
|
|
@@ -5107,7 +5139,7 @@ var sourceFile = (sys2, path10, action, reason) => ({
|
|
|
5107
5139
|
action,
|
|
5108
5140
|
reason
|
|
5109
5141
|
});
|
|
5110
|
-
var moduleComponentName = (moduleName) =>
|
|
5142
|
+
var moduleComponentName = (moduleName) => moduleName.replace(/[-_]+/g, " ").replace(/(?:^|\s+)([a-zA-Z0-9])/g, (_, char) => char.toUpperCase()).replace(/\s+/g, "");
|
|
5111
5143
|
var moduleSourcePaths = (moduleName) => {
|
|
5112
5144
|
const componentName = moduleComponentName(moduleName);
|
|
5113
5145
|
return {
|
|
@@ -5210,12 +5242,13 @@ var normalizeFieldType = (typeName) => {
|
|
|
5210
5242
|
var ensureBaseTypeImport = (content, typeName) => {
|
|
5211
5243
|
if (typeName !== "Int" && typeName !== "Float")
|
|
5212
5244
|
return content;
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
const baseImport = /import \{ ([^}]+) \} from "akanjs\/base";/.exec(content);
|
|
5245
|
+
const source = sourceFileFor("constant.ts", content);
|
|
5246
|
+
const baseImport = findNamedImport(source, "akanjs/base");
|
|
5216
5247
|
if (baseImport) {
|
|
5217
|
-
|
|
5218
|
-
|
|
5248
|
+
if (baseImport.names.includes(typeName))
|
|
5249
|
+
return content;
|
|
5250
|
+
const nextNames = [...baseImport.names, typeName].sort();
|
|
5251
|
+
return spliceText(content, baseImport.namedBindingsStart, baseImport.namedBindingsEnd, `{ ${nextNames.join(", ")} }`);
|
|
5219
5252
|
}
|
|
5220
5253
|
return `import { ${typeName} } from "akanjs/base";
|
|
5221
5254
|
${content}`;
|
|
@@ -5344,47 +5377,350 @@ var fieldExpression = (typeName, defaultValue, options = {}) => {
|
|
|
5344
5377
|
const defaultOption = defaultExpression ? `, { default: ${defaultExpression} }` : "";
|
|
5345
5378
|
return `${options.builderName ?? "field"}(${typeExpression}${defaultOption})`;
|
|
5346
5379
|
};
|
|
5347
|
-
var
|
|
5348
|
-
|
|
5349
|
-
|
|
5380
|
+
var fieldOrderingPriority = [
|
|
5381
|
+
"id",
|
|
5382
|
+
"name",
|
|
5383
|
+
"title",
|
|
5384
|
+
"status",
|
|
5385
|
+
"category",
|
|
5386
|
+
"description",
|
|
5387
|
+
"content",
|
|
5388
|
+
"startAt",
|
|
5389
|
+
"dueAt",
|
|
5390
|
+
"endAt",
|
|
5391
|
+
"createdAt",
|
|
5392
|
+
"updatedAt"
|
|
5393
|
+
];
|
|
5394
|
+
var sourceFileFor = (fileName, content, scriptKind = ts4.ScriptKind.TS) => ts4.createSourceFile(fileName, content, ts4.ScriptTarget.Latest, true, scriptKind);
|
|
5395
|
+
var hasParseDiagnostics = (source) => (source.parseDiagnostics ?? []).length > 0;
|
|
5396
|
+
var spliceText = (content, start, end, replacement) => `${content.slice(0, start)}${replacement}${content.slice(end)}`;
|
|
5397
|
+
var lineStartAt = (content, position) => content.lastIndexOf(`
|
|
5398
|
+
`, Math.max(0, position - 1)) + 1;
|
|
5399
|
+
var lineEndAt = (content, position) => {
|
|
5400
|
+
const end = content.indexOf(`
|
|
5401
|
+
`, position);
|
|
5402
|
+
return end < 0 ? content.length : end + 1;
|
|
5403
|
+
};
|
|
5404
|
+
var lineIndentAt = (content, position) => /^[ \t]*/.exec(content.slice(lineStartAt(content, position)))?.[0] ?? "";
|
|
5405
|
+
var nodeName = (node) => {
|
|
5406
|
+
if (!node)
|
|
5407
|
+
return null;
|
|
5408
|
+
if (ts4.isIdentifier(node) || ts4.isStringLiteral(node) || ts4.isNumericLiteral(node))
|
|
5409
|
+
return node.text;
|
|
5410
|
+
return null;
|
|
5411
|
+
};
|
|
5412
|
+
var propertyName = (node) => ts4.isPropertyAssignment(node) || ts4.isShorthandPropertyAssignment(node) || ts4.isMethodDeclaration(node) ? nodeName(node.name) : null;
|
|
5413
|
+
var expressionName = (expression) => {
|
|
5414
|
+
if (ts4.isIdentifier(expression))
|
|
5415
|
+
return expression.text;
|
|
5416
|
+
if (ts4.isPropertyAccessExpression(expression))
|
|
5417
|
+
return expression.name.text;
|
|
5418
|
+
if (ts4.isCallExpression(expression))
|
|
5419
|
+
return expressionName(expression.expression);
|
|
5420
|
+
if (ts4.isAsExpression(expression))
|
|
5421
|
+
return expressionName(expression.expression);
|
|
5422
|
+
return null;
|
|
5423
|
+
};
|
|
5424
|
+
var firstObjectReturnedByArrow = (node) => {
|
|
5425
|
+
if (!ts4.isArrowFunction(node) && !ts4.isFunctionExpression(node))
|
|
5426
|
+
return null;
|
|
5427
|
+
if (ts4.isObjectLiteralExpression(node.body))
|
|
5428
|
+
return node.body;
|
|
5429
|
+
if (ts4.isParenthesizedExpression(node.body) && ts4.isObjectLiteralExpression(node.body.expression)) {
|
|
5430
|
+
return node.body.expression;
|
|
5431
|
+
}
|
|
5432
|
+
if (!ts4.isBlock(node.body))
|
|
5433
|
+
return null;
|
|
5434
|
+
for (const statement of node.body.statements) {
|
|
5435
|
+
if (ts4.isReturnStatement(statement) && statement.expression && ts4.isObjectLiteralExpression(statement.expression)) {
|
|
5436
|
+
return statement.expression;
|
|
5437
|
+
}
|
|
5438
|
+
}
|
|
5439
|
+
return null;
|
|
5440
|
+
};
|
|
5441
|
+
var isViaCall = (expression) => ts4.isCallExpression(expression) && expressionName(expression.expression) === "via";
|
|
5442
|
+
var heritageCall = (node) => {
|
|
5443
|
+
const heritage = node.heritageClauses?.flatMap((clause) => [...clause.types]) ?? [];
|
|
5444
|
+
const expression = heritage.find((clause) => isViaCall(clause.expression))?.expression;
|
|
5445
|
+
return expression && ts4.isCallExpression(expression) ? expression : null;
|
|
5446
|
+
};
|
|
5447
|
+
var callExpressionName = (node) => ts4.isPropertyAccessExpression(node.expression) ? node.expression.name.text : expressionName(node.expression);
|
|
5448
|
+
var locatedObject = (source, objectLiteral) => ({
|
|
5449
|
+
objectStart: objectLiteral.getStart(source),
|
|
5450
|
+
objectEnd: objectLiteral.getEnd(),
|
|
5451
|
+
fields: objectLiteral.properties.map((property) => {
|
|
5452
|
+
const name = propertyName(property);
|
|
5453
|
+
if (!name)
|
|
5454
|
+
return null;
|
|
5455
|
+
return {
|
|
5456
|
+
name,
|
|
5457
|
+
start: property.getStart(source),
|
|
5458
|
+
fullStart: property.getFullStart(),
|
|
5459
|
+
end: property.getEnd()
|
|
5460
|
+
};
|
|
5461
|
+
}).filter((field) => field !== null)
|
|
5462
|
+
});
|
|
5463
|
+
var findConstantInputObject = (source, className) => {
|
|
5464
|
+
let locator = null;
|
|
5465
|
+
const visit = (node) => {
|
|
5466
|
+
if (locator)
|
|
5467
|
+
return;
|
|
5468
|
+
if (!ts4.isClassDeclaration(node) || node.name?.text !== className) {
|
|
5469
|
+
ts4.forEachChild(node, visit);
|
|
5470
|
+
return;
|
|
5471
|
+
}
|
|
5472
|
+
const viaCall = heritageCall(node);
|
|
5473
|
+
const callback = viaCall?.arguments.find((arg) => ts4.isArrowFunction(arg) || ts4.isFunctionExpression(arg));
|
|
5474
|
+
const objectLiteral = callback ? firstObjectReturnedByArrow(callback) : null;
|
|
5475
|
+
if (objectLiteral)
|
|
5476
|
+
locator = locatedObject(source, objectLiteral);
|
|
5477
|
+
};
|
|
5478
|
+
ts4.forEachChild(source, visit);
|
|
5479
|
+
return locator;
|
|
5480
|
+
};
|
|
5481
|
+
var chainMethodsForCall = (node) => {
|
|
5482
|
+
if (ts4.isAsExpression(node) || ts4.isParenthesizedExpression(node))
|
|
5483
|
+
return chainMethodsForCall(node.expression);
|
|
5484
|
+
if (!ts4.isCallExpression(node))
|
|
5485
|
+
return [];
|
|
5486
|
+
if (ts4.isPropertyAccessExpression(node.expression)) {
|
|
5487
|
+
return [...chainMethodsForCall(node.expression.expression), node.expression.name.text];
|
|
5488
|
+
}
|
|
5489
|
+
const name = expressionName(node.expression);
|
|
5490
|
+
return name ? [name] : [];
|
|
5491
|
+
};
|
|
5492
|
+
var outermostFluentCall = (node) => {
|
|
5493
|
+
let current = node;
|
|
5494
|
+
while (ts4.isPropertyAccessExpression(current.parent) && current.parent.expression === current && ts4.isCallExpression(current.parent.parent) && current.parent.parent.expression === current.parent) {
|
|
5495
|
+
current = current.parent.parent;
|
|
5496
|
+
}
|
|
5497
|
+
return current;
|
|
5498
|
+
};
|
|
5499
|
+
var protectedDictionaryChainOrder = ["model", "slice", "enum", "error", "translate"];
|
|
5500
|
+
var dictionaryChainOrderValid = (chainMethods) => {
|
|
5501
|
+
const protectedOrder = new Map(protectedDictionaryChainOrder.map((method, index) => [method, index]));
|
|
5502
|
+
let lastOrder = -1;
|
|
5503
|
+
for (const method of chainMethods) {
|
|
5504
|
+
const order = protectedOrder.get(method);
|
|
5505
|
+
if (order === undefined)
|
|
5506
|
+
continue;
|
|
5507
|
+
if (order < lastOrder)
|
|
5508
|
+
return false;
|
|
5509
|
+
lastOrder = order;
|
|
5510
|
+
}
|
|
5511
|
+
return true;
|
|
5512
|
+
};
|
|
5513
|
+
var findDictionaryModelObject = (source, moduleClassName) => {
|
|
5514
|
+
let locator = null;
|
|
5515
|
+
const visit = (node) => {
|
|
5516
|
+
if (locator)
|
|
5517
|
+
return;
|
|
5518
|
+
if (!ts4.isCallExpression(node) || callExpressionName(node) !== "model") {
|
|
5519
|
+
ts4.forEachChild(node, visit);
|
|
5520
|
+
return;
|
|
5521
|
+
}
|
|
5522
|
+
const typeArgument = node.typeArguments?.[0];
|
|
5523
|
+
if (!typeArgument || typeArgument.getText(source) !== moduleClassName) {
|
|
5524
|
+
ts4.forEachChild(node, visit);
|
|
5525
|
+
return;
|
|
5526
|
+
}
|
|
5527
|
+
const callback = node.arguments.find((arg) => ts4.isArrowFunction(arg) || ts4.isFunctionExpression(arg));
|
|
5528
|
+
const objectLiteral = callback ? firstObjectReturnedByArrow(callback) : null;
|
|
5529
|
+
if (objectLiteral) {
|
|
5530
|
+
locator = {
|
|
5531
|
+
...locatedObject(source, objectLiteral),
|
|
5532
|
+
chainMethods: chainMethodsForCall(outermostFluentCall(node))
|
|
5533
|
+
};
|
|
5534
|
+
}
|
|
5535
|
+
};
|
|
5536
|
+
ts4.forEachChild(source, visit);
|
|
5537
|
+
return locator;
|
|
5538
|
+
};
|
|
5539
|
+
var findLightProjectionArray = (source, moduleClassName) => {
|
|
5540
|
+
let locator = null;
|
|
5541
|
+
const visit = (node) => {
|
|
5542
|
+
if (locator)
|
|
5543
|
+
return;
|
|
5544
|
+
if (!ts4.isClassDeclaration(node) || node.name?.text !== `Light${moduleClassName}`) {
|
|
5545
|
+
ts4.forEachChild(node, visit);
|
|
5546
|
+
return;
|
|
5547
|
+
}
|
|
5548
|
+
const viaCall = heritageCall(node);
|
|
5549
|
+
const projectionArg = viaCall?.arguments.find((arg) => {
|
|
5550
|
+
const expression = ts4.isAsExpression(arg) ? arg.expression : arg;
|
|
5551
|
+
return ts4.isArrayLiteralExpression(expression);
|
|
5552
|
+
});
|
|
5553
|
+
const arrayLiteral = projectionArg ? ts4.isAsExpression(projectionArg) ? projectionArg.expression : projectionArg : null;
|
|
5554
|
+
if (!projectionArg || !arrayLiteral || !ts4.isArrayLiteralExpression(arrayLiteral))
|
|
5555
|
+
return;
|
|
5556
|
+
locator = {
|
|
5557
|
+
projectionStart: projectionArg.getStart(source),
|
|
5558
|
+
projectionEnd: projectionArg.getEnd(),
|
|
5559
|
+
fields: arrayLiteral.elements.map((element) => ts4.isStringLiteralLike(element) ? element.text : null).filter((field) => field !== null)
|
|
5560
|
+
};
|
|
5561
|
+
};
|
|
5562
|
+
ts4.forEachChild(source, visit);
|
|
5563
|
+
return locator;
|
|
5564
|
+
};
|
|
5565
|
+
var findNamedImport = (source, moduleSpecifier) => {
|
|
5566
|
+
for (const statement of source.statements) {
|
|
5567
|
+
if (!ts4.isImportDeclaration(statement) || !ts4.isStringLiteral(statement.moduleSpecifier))
|
|
5568
|
+
continue;
|
|
5569
|
+
if (statement.moduleSpecifier.text !== moduleSpecifier)
|
|
5570
|
+
continue;
|
|
5571
|
+
const namedBindings = statement.importClause?.namedBindings;
|
|
5572
|
+
if (!namedBindings || !ts4.isNamedImports(namedBindings))
|
|
5573
|
+
continue;
|
|
5574
|
+
return {
|
|
5575
|
+
names: namedBindings.elements.map((element) => element.name.text),
|
|
5576
|
+
namedBindingsStart: namedBindings.getStart(source),
|
|
5577
|
+
namedBindingsEnd: namedBindings.getEnd()
|
|
5578
|
+
};
|
|
5579
|
+
}
|
|
5580
|
+
return null;
|
|
5581
|
+
};
|
|
5582
|
+
var fieldExpressionBuilder = (property) => {
|
|
5583
|
+
if (!ts4.isPropertyAssignment(property))
|
|
5584
|
+
return null;
|
|
5585
|
+
const initializer = ts4.isAsExpression(property.initializer) ? property.initializer.expression : property.initializer;
|
|
5586
|
+
if (!ts4.isCallExpression(initializer))
|
|
5350
5587
|
return null;
|
|
5351
|
-
|
|
5352
|
-
|
|
5588
|
+
return expressionName(initializer.expression);
|
|
5589
|
+
};
|
|
5590
|
+
var priorityOf = (fieldName) => {
|
|
5591
|
+
const priority = fieldOrderingPriority.indexOf(fieldName);
|
|
5592
|
+
return priority < 0 ? null : priority;
|
|
5593
|
+
};
|
|
5594
|
+
var insertionIndexForFieldOrder = (fieldNames, newFieldName) => {
|
|
5595
|
+
const newPriority = priorityOf(newFieldName);
|
|
5596
|
+
if (newPriority !== null) {
|
|
5597
|
+
const greaterPriorityIndex = fieldNames.findIndex((name) => {
|
|
5598
|
+
const existingPriority = priorityOf(name);
|
|
5599
|
+
return existingPriority !== null && existingPriority > newPriority;
|
|
5600
|
+
});
|
|
5601
|
+
if (greaterPriorityIndex >= 0)
|
|
5602
|
+
return greaterPriorityIndex;
|
|
5603
|
+
const lastPriorityIndex = fieldNames.reduce((lastIndex, name, index) => {
|
|
5604
|
+
const existingPriority = priorityOf(name);
|
|
5605
|
+
return existingPriority !== null ? index : lastIndex;
|
|
5606
|
+
}, -1);
|
|
5607
|
+
return lastPriorityIndex + 1;
|
|
5608
|
+
}
|
|
5609
|
+
const lastNonPriorityIndex = fieldNames.reduce((lastIndex, name, index) => priorityOf(name) === null ? index : lastIndex, -1);
|
|
5610
|
+
return lastNonPriorityIndex >= 0 ? lastNonPriorityIndex + 1 : fieldNames.length;
|
|
5611
|
+
};
|
|
5612
|
+
var insertOrderedFieldLine = (content, locator, fieldName, line, options) => {
|
|
5613
|
+
if (locator.fields.some((field) => field.name === fieldName))
|
|
5614
|
+
return content;
|
|
5615
|
+
const insertIndex = insertionIndexForFieldOrder(locator.fields.map((field) => field.name), fieldName);
|
|
5616
|
+
const formattedLine = line.trim();
|
|
5617
|
+
if (locator.fields.length === 0) {
|
|
5618
|
+
return spliceText(content, locator.objectStart, locator.objectEnd, `{
|
|
5619
|
+
${options.fieldIndent}${formattedLine}
|
|
5620
|
+
${options.closingIndent}}`);
|
|
5621
|
+
}
|
|
5622
|
+
const beforeField = locator.fields[insertIndex];
|
|
5623
|
+
if (beforeField) {
|
|
5624
|
+
const leadingComments = ts4.getLeadingCommentRanges(content, beforeField.fullStart) ?? [];
|
|
5625
|
+
const insertAt2 = lineStartAt(content, leadingComments[0]?.pos ?? beforeField.start);
|
|
5626
|
+
const indent2 = lineIndentAt(content, beforeField.start) || options.fieldIndent;
|
|
5627
|
+
return spliceText(content, insertAt2, insertAt2, `${indent2}${formattedLine}
|
|
5628
|
+
`);
|
|
5629
|
+
}
|
|
5630
|
+
const afterField = locator.fields[locator.fields.length - 1];
|
|
5631
|
+
const insertAt = lineEndAt(content, afterField.end);
|
|
5632
|
+
const indent = lineIndentAt(content, afterField.start) || options.fieldIndent;
|
|
5633
|
+
return spliceText(content, insertAt, insertAt, `${indent}${formattedLine}
|
|
5634
|
+
`);
|
|
5635
|
+
};
|
|
5636
|
+
var viaBuilderParameterName = (content, className) => {
|
|
5637
|
+
const source = sourceFileFor("constant.ts", content);
|
|
5638
|
+
let builderName = null;
|
|
5639
|
+
const visit = (node) => {
|
|
5640
|
+
if (builderName !== null)
|
|
5641
|
+
return;
|
|
5642
|
+
if (!ts4.isClassDeclaration(node) || node.name?.text !== className) {
|
|
5643
|
+
ts4.forEachChild(node, visit);
|
|
5644
|
+
return;
|
|
5645
|
+
}
|
|
5646
|
+
const viaCall = heritageCall(node);
|
|
5647
|
+
const callback = viaCall?.arguments.find((arg) => ts4.isArrowFunction(arg) || ts4.isFunctionExpression(arg));
|
|
5648
|
+
if (callback && (ts4.isArrowFunction(callback) || ts4.isFunctionExpression(callback))) {
|
|
5649
|
+
builderName = nodeName(callback.parameters[0]?.name);
|
|
5650
|
+
}
|
|
5651
|
+
};
|
|
5652
|
+
ts4.forEachChild(source, visit);
|
|
5653
|
+
return builderName;
|
|
5654
|
+
};
|
|
5655
|
+
var inspectConstantStructure = (content, className, moduleClassName) => {
|
|
5656
|
+
const source = sourceFileFor("constant.ts", content);
|
|
5657
|
+
const inputObject = findConstantInputObject(source, className);
|
|
5658
|
+
const lightProjection = findLightProjectionArray(source, moduleClassName);
|
|
5659
|
+
const baseImport = findNamedImport(source, "akanjs/base");
|
|
5660
|
+
const fields = [];
|
|
5661
|
+
if (inputObject) {
|
|
5662
|
+
const visit = (node) => {
|
|
5663
|
+
if (!ts4.isClassDeclaration(node) || node.name?.text !== className) {
|
|
5664
|
+
ts4.forEachChild(node, visit);
|
|
5665
|
+
return;
|
|
5666
|
+
}
|
|
5667
|
+
const viaCall = heritageCall(node);
|
|
5668
|
+
const callback = viaCall?.arguments.find((arg) => ts4.isArrowFunction(arg) || ts4.isFunctionExpression(arg));
|
|
5669
|
+
const objectLiteral = callback ? firstObjectReturnedByArrow(callback) : null;
|
|
5670
|
+
if (!objectLiteral)
|
|
5671
|
+
return;
|
|
5672
|
+
fields.push(...objectLiteral.properties.map((property) => {
|
|
5673
|
+
const name = propertyName(property);
|
|
5674
|
+
if (!name)
|
|
5675
|
+
return null;
|
|
5676
|
+
return { name, expressionBuilder: fieldExpressionBuilder(property) };
|
|
5677
|
+
}).filter((field) => field !== null));
|
|
5678
|
+
};
|
|
5679
|
+
ts4.forEachChild(source, visit);
|
|
5680
|
+
}
|
|
5681
|
+
return {
|
|
5682
|
+
parseValid: !hasParseDiagnostics(source),
|
|
5683
|
+
inputObjectFound: inputObject !== null,
|
|
5684
|
+
builderName: viaBuilderParameterName(content, className),
|
|
5685
|
+
fields,
|
|
5686
|
+
lightProjectionFields: lightProjection?.fields ?? [],
|
|
5687
|
+
baseImports: baseImport?.names ?? []
|
|
5688
|
+
};
|
|
5689
|
+
};
|
|
5690
|
+
var inspectDictionaryStructure = (content, moduleClassName) => {
|
|
5691
|
+
const source = sourceFileFor("dictionary.ts", content);
|
|
5692
|
+
const modelObject = findDictionaryModelObject(source, moduleClassName);
|
|
5693
|
+
return {
|
|
5694
|
+
parseValid: !hasParseDiagnostics(source),
|
|
5695
|
+
modelObjectFound: modelObject !== null,
|
|
5696
|
+
chainOrderValid: modelObject ? dictionaryChainOrderValid(modelObject.chainMethods) : false,
|
|
5697
|
+
chainMethods: modelObject?.chainMethods ?? [],
|
|
5698
|
+
fields: modelObject?.fields.map((field) => field.name) ?? []
|
|
5699
|
+
};
|
|
5353
5700
|
};
|
|
5354
5701
|
var insertIntoObject = (content, className, line) => {
|
|
5355
|
-
const
|
|
5356
|
-
if (
|
|
5702
|
+
const fieldName = /^([A-Za-z_$][\w$]*)\s*:/.exec(line.trim())?.[1];
|
|
5703
|
+
if (!fieldName)
|
|
5357
5704
|
return null;
|
|
5358
|
-
const
|
|
5359
|
-
|
|
5705
|
+
const source = sourceFileFor("constant.ts", content);
|
|
5706
|
+
const locator = findConstantInputObject(source, className);
|
|
5707
|
+
if (!locator)
|
|
5360
5708
|
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}`;
|
|
5709
|
+
return insertOrderedFieldLine(content, locator, fieldName, line, { fieldIndent: " ", closingIndent: "" });
|
|
5369
5710
|
};
|
|
5370
5711
|
var insertLightProjectionField = (content, moduleClassName, fieldName) => {
|
|
5371
|
-
const
|
|
5372
|
-
|
|
5712
|
+
const source = sourceFileFor("constant.ts", content);
|
|
5713
|
+
const locator = findLightProjectionArray(source, moduleClassName);
|
|
5714
|
+
if (!locator)
|
|
5373
5715
|
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))
|
|
5716
|
+
if (locator.fields.includes(fieldName))
|
|
5381
5717
|
return content;
|
|
5382
|
-
const nextFields = [...fields, fieldName];
|
|
5718
|
+
const nextFields = [...locator.fields, fieldName];
|
|
5383
5719
|
const nextArray = nextFields.length === 0 ? "[] as const" : `[
|
|
5384
5720
|
${nextFields.map((field) => ` ${JSON.stringify(field)},`).join(`
|
|
5385
5721
|
`)}
|
|
5386
5722
|
] as const`;
|
|
5387
|
-
return
|
|
5723
|
+
return spliceText(content, locator.projectionStart, locator.projectionEnd, nextArray);
|
|
5388
5724
|
};
|
|
5389
5725
|
var insertTemplateField = ({
|
|
5390
5726
|
content,
|
|
@@ -5437,69 +5773,32 @@ ${values.map((value) => ` ${JSON.stringify(value)},`).join(`
|
|
|
5437
5773
|
${enumClass}`;
|
|
5438
5774
|
return `${content.slice(0, firstClassIndex)}${enumClass}${content.slice(firstClassIndex)}`;
|
|
5439
5775
|
};
|
|
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
5776
|
var dictionaryModelFieldLine = (fieldName) => {
|
|
5474
5777
|
const label = bilingualLabelForField(fieldName);
|
|
5475
5778
|
const desc = bilingualDescriptionForField(fieldName);
|
|
5476
5779
|
return `${fieldName}: t([${JSON.stringify(label.en)}, ${JSON.stringify(label.ko)}]).desc([${JSON.stringify(desc.en)}, ${JSON.stringify(desc.ko)}]),`;
|
|
5477
5780
|
};
|
|
5478
5781
|
var insertDictionaryModelField = (content, moduleClassName, fieldName) => {
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
if (modelIndex < 0)
|
|
5483
|
-
return null;
|
|
5484
|
-
const objectStartIndex = content.indexOf("{", modelIndex);
|
|
5485
|
-
if (objectStartIndex < 0)
|
|
5782
|
+
const source = sourceFileFor("dictionary.ts", content);
|
|
5783
|
+
const locator = findDictionaryModelObject(source, moduleClassName);
|
|
5784
|
+
if (!locator)
|
|
5486
5785
|
return null;
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5497
|
-
|
|
5498
|
-
|
|
5499
|
-
|
|
5500
|
-
|
|
5501
|
-
|
|
5502
|
-
return
|
|
5786
|
+
return insertOrderedFieldLine(content, locator, fieldName, dictionaryModelFieldLine(fieldName), {
|
|
5787
|
+
fieldIndent: " ",
|
|
5788
|
+
closingIndent: " "
|
|
5789
|
+
});
|
|
5790
|
+
};
|
|
5791
|
+
var hasConstantInputField = (content, className, fieldName) => {
|
|
5792
|
+
const source = sourceFileFor("constant.ts", content);
|
|
5793
|
+
if (hasParseDiagnostics(source))
|
|
5794
|
+
return false;
|
|
5795
|
+
return findConstantInputObject(source, className)?.fields.some((field) => field.name === fieldName) ?? false;
|
|
5796
|
+
};
|
|
5797
|
+
var hasDictionaryModelField = (content, moduleClassName, fieldName) => {
|
|
5798
|
+
const source = sourceFileFor("dictionary.ts", content);
|
|
5799
|
+
if (hasParseDiagnostics(source))
|
|
5800
|
+
return false;
|
|
5801
|
+
return findDictionaryModelObject(source, moduleClassName)?.fields.some((field) => field.name === fieldName) ?? false;
|
|
5503
5802
|
};
|
|
5504
5803
|
var ensureConstantTypeImport = (content, constantPath, typeName) => {
|
|
5505
5804
|
if (new RegExp(`import type \\{[^}]*\\b${typeName}\\b[^}]*\\} from "${constantPath}";`).test(content))
|
|
@@ -5529,6 +5828,401 @@ ${values.map((value) => ` ${value}: t([${JSON.stringify(titleize(value))}, ${
|
|
|
5529
5828
|
};
|
|
5530
5829
|
var parseValues = (value) => value?.split(",").map((item) => item.trim()).filter(Boolean) ?? [];
|
|
5531
5830
|
|
|
5831
|
+
// pkgs/@akanjs/devkit/workflow/moduleIndex.ts
|
|
5832
|
+
var indexFileKinds = [
|
|
5833
|
+
"abstract",
|
|
5834
|
+
"constant",
|
|
5835
|
+
"dictionary",
|
|
5836
|
+
"service",
|
|
5837
|
+
"signal",
|
|
5838
|
+
"store",
|
|
5839
|
+
"template",
|
|
5840
|
+
"unit",
|
|
5841
|
+
"util",
|
|
5842
|
+
"view",
|
|
5843
|
+
"zone"
|
|
5844
|
+
];
|
|
5845
|
+
var sourceText = async (filePath) => {
|
|
5846
|
+
try {
|
|
5847
|
+
return await Bun.file(filePath).text();
|
|
5848
|
+
} catch {
|
|
5849
|
+
return null;
|
|
5850
|
+
}
|
|
5851
|
+
};
|
|
5852
|
+
var fileExists = async (filePath) => {
|
|
5853
|
+
try {
|
|
5854
|
+
await access(filePath);
|
|
5855
|
+
return true;
|
|
5856
|
+
} catch {
|
|
5857
|
+
return false;
|
|
5858
|
+
}
|
|
5859
|
+
};
|
|
5860
|
+
var sourceFileFor2 = (filePath, content) => ts5.createSourceFile(filePath, content, ts5.ScriptTarget.Latest, true, ts5.ScriptKind.TS);
|
|
5861
|
+
var parseDiagnosticsFor = (source, filePath) => {
|
|
5862
|
+
const parseDiagnostics = source.parseDiagnostics ?? [];
|
|
5863
|
+
return parseDiagnostics.map((diagnostic) => ({
|
|
5864
|
+
severity: "error",
|
|
5865
|
+
code: "module-index-typescript-parse-error",
|
|
5866
|
+
message: `TypeScript parse diagnostic TS${diagnostic.code} in ${filePath}: ${ts5.flattenDiagnosticMessageText(diagnostic.messageText, `
|
|
5867
|
+
`)}`,
|
|
5868
|
+
context: { target: filePath, paths: [filePath] }
|
|
5869
|
+
}));
|
|
5870
|
+
};
|
|
5871
|
+
var spanFor = (source, file, node) => {
|
|
5872
|
+
const startOffset = node.getStart(source);
|
|
5873
|
+
const endOffset = node.getEnd();
|
|
5874
|
+
const start = source.getLineAndCharacterOfPosition(startOffset);
|
|
5875
|
+
const end = source.getLineAndCharacterOfPosition(endOffset);
|
|
5876
|
+
return {
|
|
5877
|
+
file,
|
|
5878
|
+
startLine: start.line + 1,
|
|
5879
|
+
endLine: end.line + 1,
|
|
5880
|
+
startOffset,
|
|
5881
|
+
endOffset
|
|
5882
|
+
};
|
|
5883
|
+
};
|
|
5884
|
+
var nodeName2 = (node) => {
|
|
5885
|
+
if (!node)
|
|
5886
|
+
return null;
|
|
5887
|
+
if (ts5.isIdentifier(node) || ts5.isStringLiteral(node) || ts5.isNumericLiteral(node))
|
|
5888
|
+
return node.text;
|
|
5889
|
+
return null;
|
|
5890
|
+
};
|
|
5891
|
+
var propertyName2 = (node) => ts5.isPropertyAssignment(node) || ts5.isShorthandPropertyAssignment(node) || ts5.isMethodDeclaration(node) ? nodeName2(node.name) : null;
|
|
5892
|
+
var expressionName2 = (expression) => {
|
|
5893
|
+
if (ts5.isIdentifier(expression))
|
|
5894
|
+
return expression.text;
|
|
5895
|
+
if (ts5.isPropertyAccessExpression(expression))
|
|
5896
|
+
return expression.name.text;
|
|
5897
|
+
if (ts5.isCallExpression(expression))
|
|
5898
|
+
return expressionName2(expression.expression);
|
|
5899
|
+
if (ts5.isAsExpression(expression))
|
|
5900
|
+
return expressionName2(expression.expression);
|
|
5901
|
+
return null;
|
|
5902
|
+
};
|
|
5903
|
+
var expressionSummary = (expression) => {
|
|
5904
|
+
if (ts5.isAsExpression(expression))
|
|
5905
|
+
return expressionSummary(expression.expression);
|
|
5906
|
+
if (ts5.isIdentifier(expression) || ts5.isPropertyAccessExpression(expression))
|
|
5907
|
+
return expressionName2(expression) ?? "expression";
|
|
5908
|
+
if (ts5.isArrayLiteralExpression(expression))
|
|
5909
|
+
return "array-literal";
|
|
5910
|
+
if (ts5.isObjectLiteralExpression(expression))
|
|
5911
|
+
return "object-literal";
|
|
5912
|
+
if (ts5.isStringLiteralLike(expression))
|
|
5913
|
+
return "string-literal";
|
|
5914
|
+
if (ts5.isNumericLiteral(expression))
|
|
5915
|
+
return "numeric-literal";
|
|
5916
|
+
if (expression.kind === ts5.SyntaxKind.TrueKeyword || expression.kind === ts5.SyntaxKind.FalseKeyword) {
|
|
5917
|
+
return "boolean-literal";
|
|
5918
|
+
}
|
|
5919
|
+
if (ts5.isCallExpression(expression)) {
|
|
5920
|
+
const callee = expressionName2(expression.expression);
|
|
5921
|
+
return callee ? `${callee}(...)` : "call-expression";
|
|
5922
|
+
}
|
|
5923
|
+
return ts5.SyntaxKind[expression.kind] ?? "expression";
|
|
5924
|
+
};
|
|
5925
|
+
var typeSummaryForInitializer = (initializer) => {
|
|
5926
|
+
if (!initializer)
|
|
5927
|
+
return;
|
|
5928
|
+
const expression = ts5.isAsExpression(initializer) ? initializer.expression : initializer;
|
|
5929
|
+
if (!ts5.isCallExpression(expression))
|
|
5930
|
+
return expressionSummary(expression);
|
|
5931
|
+
const callee = expressionName2(expression.expression);
|
|
5932
|
+
const firstArg = expression.arguments[0];
|
|
5933
|
+
const argSummary = firstArg ? expressionSummary(firstArg) : "";
|
|
5934
|
+
return [callee, argSummary ? `(${argSummary})` : ""].filter(Boolean).join("");
|
|
5935
|
+
};
|
|
5936
|
+
var fieldsFromObject = (source, file, objectLiteral, kind) => objectLiteral.properties.map((property, index) => {
|
|
5937
|
+
const name = propertyName2(property);
|
|
5938
|
+
if (!name)
|
|
5939
|
+
return null;
|
|
5940
|
+
const initializer = ts5.isPropertyAssignment(property) ? property.initializer : undefined;
|
|
5941
|
+
return {
|
|
5942
|
+
name,
|
|
5943
|
+
kind,
|
|
5944
|
+
order: index,
|
|
5945
|
+
...initializer ? { typeSummary: typeSummaryForInitializer(initializer) } : {},
|
|
5946
|
+
sourceSpan: spanFor(source, file, property)
|
|
5947
|
+
};
|
|
5948
|
+
}).filter((field) => field !== null);
|
|
5949
|
+
var firstObjectReturnedByArrow2 = (node) => {
|
|
5950
|
+
if (!ts5.isArrowFunction(node) && !ts5.isFunctionExpression(node))
|
|
5951
|
+
return null;
|
|
5952
|
+
if (ts5.isObjectLiteralExpression(node.body))
|
|
5953
|
+
return node.body;
|
|
5954
|
+
if (ts5.isParenthesizedExpression(node.body) && ts5.isObjectLiteralExpression(node.body.expression)) {
|
|
5955
|
+
return node.body.expression;
|
|
5956
|
+
}
|
|
5957
|
+
if (!ts5.isBlock(node.body))
|
|
5958
|
+
return null;
|
|
5959
|
+
for (const statement of node.body.statements) {
|
|
5960
|
+
if (ts5.isReturnStatement(statement) && statement.expression && ts5.isObjectLiteralExpression(statement.expression)) {
|
|
5961
|
+
return statement.expression;
|
|
5962
|
+
}
|
|
5963
|
+
}
|
|
5964
|
+
return null;
|
|
5965
|
+
};
|
|
5966
|
+
var isViaCall2 = (expression) => ts5.isCallExpression(expression) && expressionName2(expression.expression) === "via";
|
|
5967
|
+
var heritageCall2 = (node) => {
|
|
5968
|
+
const heritage = node.heritageClauses?.flatMap((clause) => [...clause.types]) ?? [];
|
|
5969
|
+
const expression = heritage.find((clause) => isViaCall2(clause.expression))?.expression;
|
|
5970
|
+
return expression && ts5.isCallExpression(expression) ? expression : null;
|
|
5971
|
+
};
|
|
5972
|
+
var parseConstantIndex = (filePath, content, moduleClassName) => {
|
|
5973
|
+
const source = sourceFileFor2(filePath, content);
|
|
5974
|
+
const diagnostics = parseDiagnosticsFor(source, filePath);
|
|
5975
|
+
const inputClassName = `${moduleClassName}Input`;
|
|
5976
|
+
let inputClass = null;
|
|
5977
|
+
let inputViaFound = false;
|
|
5978
|
+
let inputBuilderFound = false;
|
|
5979
|
+
let inputBuilderObjectFound = false;
|
|
5980
|
+
let builderName = null;
|
|
5981
|
+
let fields = [];
|
|
5982
|
+
let lightProjection;
|
|
5983
|
+
const visit = (node) => {
|
|
5984
|
+
if (!ts5.isClassDeclaration(node) || !node.name) {
|
|
5985
|
+
ts5.forEachChild(node, visit);
|
|
5986
|
+
return;
|
|
5987
|
+
}
|
|
5988
|
+
const className = node.name.text;
|
|
5989
|
+
const viaCall = heritageCall2(node);
|
|
5990
|
+
if (className === inputClassName) {
|
|
5991
|
+
inputClass = node;
|
|
5992
|
+
if (!viaCall)
|
|
5993
|
+
return;
|
|
5994
|
+
inputViaFound = true;
|
|
5995
|
+
const callback = viaCall.arguments.find((arg) => ts5.isArrowFunction(arg) || ts5.isFunctionExpression(arg));
|
|
5996
|
+
if (callback && (ts5.isArrowFunction(callback) || ts5.isFunctionExpression(callback))) {
|
|
5997
|
+
inputBuilderFound = true;
|
|
5998
|
+
builderName = nodeName2(callback.parameters[0]?.name) ?? null;
|
|
5999
|
+
const objectLiteral = firstObjectReturnedByArrow2(callback);
|
|
6000
|
+
if (objectLiteral) {
|
|
6001
|
+
inputBuilderObjectFound = true;
|
|
6002
|
+
fields = fieldsFromObject(source, filePath, objectLiteral, "constant");
|
|
6003
|
+
}
|
|
6004
|
+
}
|
|
6005
|
+
}
|
|
6006
|
+
if (!viaCall)
|
|
6007
|
+
return;
|
|
6008
|
+
if (className === `Light${moduleClassName}`) {
|
|
6009
|
+
const projectionArg = viaCall.arguments.find((arg) => {
|
|
6010
|
+
const expression = ts5.isAsExpression(arg) ? arg.expression : arg;
|
|
6011
|
+
return ts5.isArrayLiteralExpression(expression);
|
|
6012
|
+
});
|
|
6013
|
+
const arrayLiteral = projectionArg ? ts5.isAsExpression(projectionArg) ? projectionArg.expression : projectionArg : null;
|
|
6014
|
+
if (arrayLiteral && ts5.isArrayLiteralExpression(arrayLiteral)) {
|
|
6015
|
+
lightProjection = {
|
|
6016
|
+
className,
|
|
6017
|
+
sourceSpan: spanFor(source, filePath, arrayLiteral),
|
|
6018
|
+
fields: arrayLiteral.elements.map((element, order) => ts5.isStringLiteralLike(element) ? {
|
|
6019
|
+
name: element.text,
|
|
6020
|
+
kind: "lightProjection",
|
|
6021
|
+
order,
|
|
6022
|
+
typeSummary: "string-literal",
|
|
6023
|
+
sourceSpan: spanFor(source, filePath, element)
|
|
6024
|
+
} : null).filter((field) => field !== null)
|
|
6025
|
+
};
|
|
6026
|
+
}
|
|
6027
|
+
}
|
|
6028
|
+
};
|
|
6029
|
+
ts5.forEachChild(source, visit);
|
|
6030
|
+
if (!inputClass) {
|
|
6031
|
+
diagnostics.push({
|
|
6032
|
+
severity: "error",
|
|
6033
|
+
code: "module-index-constant-input-missing",
|
|
6034
|
+
message: `Constant input class ${inputClassName} was not found in ${filePath}.`,
|
|
6035
|
+
context: { target: inputClassName, paths: [filePath] }
|
|
6036
|
+
});
|
|
6037
|
+
} else if (!inputViaFound) {
|
|
6038
|
+
diagnostics.push({
|
|
6039
|
+
severity: "error",
|
|
6040
|
+
code: "module-index-constant-via-missing",
|
|
6041
|
+
message: `Constant input class ${inputClassName} does not extend via(...) in ${filePath}.`,
|
|
6042
|
+
context: { target: inputClassName, paths: [filePath] }
|
|
6043
|
+
});
|
|
6044
|
+
} else if (!inputBuilderFound) {
|
|
6045
|
+
diagnostics.push({
|
|
6046
|
+
severity: "error",
|
|
6047
|
+
code: "module-index-constant-builder-missing",
|
|
6048
|
+
message: `Constant input class ${inputClassName} does not provide a via(...) builder callback in ${filePath}.`,
|
|
6049
|
+
context: { target: inputClassName, paths: [filePath] }
|
|
6050
|
+
});
|
|
6051
|
+
} else if (!inputBuilderObjectFound) {
|
|
6052
|
+
diagnostics.push({
|
|
6053
|
+
severity: "error",
|
|
6054
|
+
code: "module-index-constant-builder-object-missing",
|
|
6055
|
+
message: `Constant input class ${inputClassName} builder does not return an object literal in ${filePath}.`,
|
|
6056
|
+
context: { target: inputClassName, paths: [filePath] }
|
|
6057
|
+
});
|
|
6058
|
+
}
|
|
6059
|
+
return {
|
|
6060
|
+
index: {
|
|
6061
|
+
path: filePath,
|
|
6062
|
+
inputClassName,
|
|
6063
|
+
builderName,
|
|
6064
|
+
fields,
|
|
6065
|
+
...lightProjection ? { lightProjection } : {},
|
|
6066
|
+
...inputClass ? { sourceSpan: spanFor(source, filePath, inputClass) } : {}
|
|
6067
|
+
},
|
|
6068
|
+
diagnostics
|
|
6069
|
+
};
|
|
6070
|
+
};
|
|
6071
|
+
var callExpressionName2 = (node) => ts5.isPropertyAccessExpression(node.expression) ? node.expression.name.text : expressionName2(node.expression);
|
|
6072
|
+
var parseDictionaryIndex = (filePath, content, moduleClassName) => {
|
|
6073
|
+
const source = sourceFileFor2(filePath, content);
|
|
6074
|
+
const diagnostics = parseDiagnosticsFor(source, filePath);
|
|
6075
|
+
let index;
|
|
6076
|
+
let modelFound = false;
|
|
6077
|
+
const visit = (node) => {
|
|
6078
|
+
if (modelFound || !ts5.isCallExpression(node)) {
|
|
6079
|
+
ts5.forEachChild(node, visit);
|
|
6080
|
+
return;
|
|
6081
|
+
}
|
|
6082
|
+
if (callExpressionName2(node) !== "model") {
|
|
6083
|
+
ts5.forEachChild(node, visit);
|
|
6084
|
+
return;
|
|
6085
|
+
}
|
|
6086
|
+
const typeArgument = node.typeArguments?.[0];
|
|
6087
|
+
if (!typeArgument || typeArgument.getText(source) !== moduleClassName) {
|
|
6088
|
+
ts5.forEachChild(node, visit);
|
|
6089
|
+
return;
|
|
6090
|
+
}
|
|
6091
|
+
modelFound = true;
|
|
6092
|
+
const callback = node.arguments.find((arg) => ts5.isArrowFunction(arg) || ts5.isFunctionExpression(arg));
|
|
6093
|
+
if (!callback || !ts5.isArrowFunction(callback) && !ts5.isFunctionExpression(callback)) {
|
|
6094
|
+
diagnostics.push({
|
|
6095
|
+
severity: "error",
|
|
6096
|
+
code: "module-index-dictionary-builder-missing",
|
|
6097
|
+
message: `Dictionary .model<${moduleClassName}> branch does not provide a builder callback in ${filePath}.`,
|
|
6098
|
+
context: { target: moduleClassName, paths: [filePath] }
|
|
6099
|
+
});
|
|
6100
|
+
return;
|
|
6101
|
+
}
|
|
6102
|
+
const objectLiteral = firstObjectReturnedByArrow2(callback);
|
|
6103
|
+
if (!objectLiteral) {
|
|
6104
|
+
diagnostics.push({
|
|
6105
|
+
severity: "error",
|
|
6106
|
+
code: "module-index-dictionary-builder-object-missing",
|
|
6107
|
+
message: `Dictionary .model<${moduleClassName}> builder does not return an object literal in ${filePath}.`,
|
|
6108
|
+
context: { target: moduleClassName, paths: [filePath] }
|
|
6109
|
+
});
|
|
6110
|
+
}
|
|
6111
|
+
index = {
|
|
6112
|
+
path: filePath,
|
|
6113
|
+
modelClassName: moduleClassName,
|
|
6114
|
+
translatorName: nodeName2(callback.parameters[0]?.name),
|
|
6115
|
+
fields: objectLiteral ? fieldsFromObject(source, filePath, objectLiteral, "dictionary") : [],
|
|
6116
|
+
sourceSpan: spanFor(source, filePath, node)
|
|
6117
|
+
};
|
|
6118
|
+
};
|
|
6119
|
+
ts5.forEachChild(source, visit);
|
|
6120
|
+
return { index, diagnostics, modelFound };
|
|
6121
|
+
};
|
|
6122
|
+
var expectedFilesFor = (module) => {
|
|
6123
|
+
const paths = moduleSourcePaths(module.name);
|
|
6124
|
+
return indexFileKinds.map((kind) => {
|
|
6125
|
+
const expectedModulePath = paths[kind];
|
|
6126
|
+
const expectedFilename = path10.basename(expectedModulePath);
|
|
6127
|
+
const actualFilename = module.files.find((file) => file === expectedFilename) ?? module.files.find((file) => file.toLowerCase() === expectedFilename.toLowerCase());
|
|
6128
|
+
const present = actualFilename !== undefined;
|
|
6129
|
+
const casing = !present ? "missing" : actualFilename === expectedFilename ? "match" : "mismatch";
|
|
6130
|
+
return {
|
|
6131
|
+
kind,
|
|
6132
|
+
path: `${module.path}/${actualFilename ?? expectedFilename}`,
|
|
6133
|
+
expectedPath: `${module.path}/${expectedFilename}`,
|
|
6134
|
+
filename: actualFilename ?? expectedFilename,
|
|
6135
|
+
expectedFilename,
|
|
6136
|
+
present,
|
|
6137
|
+
casing
|
|
6138
|
+
};
|
|
6139
|
+
});
|
|
6140
|
+
};
|
|
6141
|
+
var diagnosticsForFiles = (files) => files.flatMap((file) => {
|
|
6142
|
+
if (file.kind !== "constant" && file.kind !== "dictionary")
|
|
6143
|
+
return [];
|
|
6144
|
+
if (file.casing === "match")
|
|
6145
|
+
return [];
|
|
6146
|
+
return [
|
|
6147
|
+
{
|
|
6148
|
+
severity: "error",
|
|
6149
|
+
code: file.casing === "missing" ? "module-index-file-missing" : "module-index-file-casing-mismatch",
|
|
6150
|
+
message: file.casing === "missing" ? `Expected ${file.kind} file is missing: ${file.expectedPath}.` : `Expected ${file.expectedPath}, but found ${file.path}.`,
|
|
6151
|
+
context: { target: file.expectedPath, paths: [file.path, file.expectedPath] }
|
|
6152
|
+
}
|
|
6153
|
+
];
|
|
6154
|
+
});
|
|
6155
|
+
var fieldPresence = (requestedField, constantFields, dictionaryFields, lightFields) => {
|
|
6156
|
+
const names = new Set([
|
|
6157
|
+
...constantFields.map((field) => field.name),
|
|
6158
|
+
...dictionaryFields.map((field) => field.name),
|
|
6159
|
+
...lightFields.map((field) => field.name),
|
|
6160
|
+
...requestedField ? [requestedField] : []
|
|
6161
|
+
]);
|
|
6162
|
+
return [...names].sort().map((name) => ({
|
|
6163
|
+
name,
|
|
6164
|
+
requested: requestedField === name,
|
|
6165
|
+
constant: constantFields.some((field) => field.name === name),
|
|
6166
|
+
dictionary: dictionaryFields.some((field) => field.name === name),
|
|
6167
|
+
lightProjection: lightFields.some((field) => field.name === name)
|
|
6168
|
+
}));
|
|
6169
|
+
};
|
|
6170
|
+
var partialPresenceDiagnostics = (presence, module) => presence.filter((field) => field.constant !== field.dictionary || field.lightProjection && (!field.constant || !field.dictionary)).map((field) => ({
|
|
6171
|
+
severity: "warning",
|
|
6172
|
+
code: "module-index-field-presence-partial",
|
|
6173
|
+
message: `${module.sysName}:${module.name}.${field.name} presence differs across constant, dictionary, and lightProjection.`,
|
|
6174
|
+
context: {
|
|
6175
|
+
target: `${module.sysName}:${module.name}.${field.name}`,
|
|
6176
|
+
paths: [`${module.path}/${module.name}.constant.ts`, `${module.path}/${module.name}.dictionary.ts`]
|
|
6177
|
+
}
|
|
6178
|
+
}));
|
|
6179
|
+
var buildAkanModuleContextIndex = async (workspace, module, options = {}) => {
|
|
6180
|
+
const files = expectedFilesFor(module);
|
|
6181
|
+
const diagnostics = diagnosticsForFiles(files);
|
|
6182
|
+
const moduleClassName = moduleComponentName(module.name);
|
|
6183
|
+
const constantFile = files.find((file) => file.kind === "constant");
|
|
6184
|
+
const dictionaryFile = files.find((file) => file.kind === "dictionary");
|
|
6185
|
+
const constantContent = constantFile?.present && constantFile.casing === "match" ? await sourceText(path10.join(workspace.workspaceRoot, constantFile.path)) : null;
|
|
6186
|
+
const dictionaryContent = dictionaryFile?.present && dictionaryFile.casing === "match" ? await sourceText(path10.join(workspace.workspaceRoot, dictionaryFile.path)) : null;
|
|
6187
|
+
const parsedConstant = constantFile && constantContent ? parseConstantIndex(constantFile.path, constantContent, moduleClassName) : undefined;
|
|
6188
|
+
const constant = parsedConstant?.index;
|
|
6189
|
+
const parsedDictionary = dictionaryFile && dictionaryContent ? parseDictionaryIndex(dictionaryFile.path, dictionaryContent, moduleClassName) : undefined;
|
|
6190
|
+
const dictionary = parsedDictionary?.index;
|
|
6191
|
+
const presence = fieldPresence(options.field, constant?.fields ?? [], dictionary?.fields ?? [], constant?.lightProjection?.fields ?? []);
|
|
6192
|
+
if (constantFile?.present && constantFile.casing === "match" && !await fileExists(path10.join(workspace.workspaceRoot, constantFile.path))) {
|
|
6193
|
+
diagnostics.push({
|
|
6194
|
+
severity: "error",
|
|
6195
|
+
code: "module-index-file-unreadable",
|
|
6196
|
+
message: `Expected constant file could not be read: ${constantFile.path}.`,
|
|
6197
|
+
context: { paths: [constantFile.path] }
|
|
6198
|
+
});
|
|
6199
|
+
}
|
|
6200
|
+
if (parsedConstant)
|
|
6201
|
+
diagnostics.push(...parsedConstant.diagnostics);
|
|
6202
|
+
if (parsedDictionary)
|
|
6203
|
+
diagnostics.push(...parsedDictionary.diagnostics);
|
|
6204
|
+
if (dictionaryFile?.present && dictionaryFile.casing === "match" && !parsedDictionary?.modelFound) {
|
|
6205
|
+
diagnostics.push({
|
|
6206
|
+
severity: "error",
|
|
6207
|
+
code: "module-index-dictionary-model-missing",
|
|
6208
|
+
message: `Dictionary .model<${moduleClassName}> branch was not found in ${dictionaryFile.path}.`,
|
|
6209
|
+
context: { paths: [dictionaryFile.path] }
|
|
6210
|
+
});
|
|
6211
|
+
}
|
|
6212
|
+
diagnostics.push(...partialPresenceDiagnostics(presence, module));
|
|
6213
|
+
return {
|
|
6214
|
+
schemaVersion: 1,
|
|
6215
|
+
app: module.sysName,
|
|
6216
|
+
module: module.name,
|
|
6217
|
+
moduleClassName,
|
|
6218
|
+
files,
|
|
6219
|
+
fieldPresence: presence,
|
|
6220
|
+
...constant ? { constant } : {},
|
|
6221
|
+
...dictionary ? { dictionary } : {},
|
|
6222
|
+
diagnostics
|
|
6223
|
+
};
|
|
6224
|
+
};
|
|
6225
|
+
|
|
5532
6226
|
// pkgs/@akanjs/devkit/workflow/uiPolicy.ts
|
|
5533
6227
|
var addFieldUiPolicyForType = (typeName) => {
|
|
5534
6228
|
const normalizedType = typeName.toLowerCase() === "enum" ? "enum" : normalizeFieldType(typeName);
|
|
@@ -5593,11 +6287,18 @@ var postApplyDiagnostic = (code, message, target) => ({
|
|
|
5593
6287
|
failureScope: "source-change",
|
|
5594
6288
|
context: { target }
|
|
5595
6289
|
});
|
|
6290
|
+
var postApplyWarning = (code, message, target) => ({
|
|
6291
|
+
severity: "warning",
|
|
6292
|
+
code,
|
|
6293
|
+
message,
|
|
6294
|
+
failureScope: "source-change",
|
|
6295
|
+
context: { target }
|
|
6296
|
+
});
|
|
5596
6297
|
var sourceKindForPath = (filePath) => {
|
|
5597
6298
|
if (filePath.endsWith(".tsx"))
|
|
5598
|
-
return
|
|
6299
|
+
return ts6.ScriptKind.TSX;
|
|
5599
6300
|
if (filePath.endsWith(".ts"))
|
|
5600
|
-
return
|
|
6301
|
+
return ts6.ScriptKind.TS;
|
|
5601
6302
|
return null;
|
|
5602
6303
|
};
|
|
5603
6304
|
var checkPathCasing = async (workspace, filePath) => {
|
|
@@ -5625,7 +6326,7 @@ var checkTypeScriptSyntax = async (workspace, filePath) => {
|
|
|
5625
6326
|
if (!scriptKind)
|
|
5626
6327
|
return null;
|
|
5627
6328
|
const content = await workspace.readFile(filePath);
|
|
5628
|
-
const source =
|
|
6329
|
+
const source = ts6.createSourceFile(filePath, content, ts6.ScriptTarget.Latest, true, scriptKind);
|
|
5629
6330
|
const diagnostic = source.parseDiagnostics[0];
|
|
5630
6331
|
if (!diagnostic)
|
|
5631
6332
|
return null;
|
|
@@ -5633,7 +6334,7 @@ var checkTypeScriptSyntax = async (workspace, filePath) => {
|
|
|
5633
6334
|
const location = position ? `:${position.line + 1}:${position.character + 1}` : "";
|
|
5634
6335
|
return {
|
|
5635
6336
|
code: "workflow-post-apply-syntax-error",
|
|
5636
|
-
message: `Generated source has a TypeScript syntax error at ${filePath}${location}: ${
|
|
6337
|
+
message: `Generated source has a TypeScript syntax error at ${filePath}${location}: ${ts6.flattenDiagnosticMessageText(diagnostic.messageText, " ")}`
|
|
5637
6338
|
};
|
|
5638
6339
|
};
|
|
5639
6340
|
var checkChangedFile = async (workspace, file) => {
|
|
@@ -5675,6 +6376,111 @@ var checkRecommendationPath = async (workspace, recommendation) => {
|
|
|
5675
6376
|
context: { target: recommendation.target }
|
|
5676
6377
|
};
|
|
5677
6378
|
};
|
|
6379
|
+
var sourceChangeError = (diagnostics) => diagnostics.some((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown"));
|
|
6380
|
+
var fieldCount = (fields, fieldName) => fields.filter((field) => field === fieldName).length;
|
|
6381
|
+
var fieldOrderValid = (fields, fieldName) => {
|
|
6382
|
+
const actualIndex = fields.indexOf(fieldName);
|
|
6383
|
+
if (actualIndex < 0 || fields.lastIndexOf(fieldName) !== actualIndex)
|
|
6384
|
+
return false;
|
|
6385
|
+
const fieldsWithoutRequested = fields.filter((_, index) => index !== actualIndex);
|
|
6386
|
+
return insertionIndexForFieldOrder(fieldsWithoutRequested, fieldName) === actualIndex;
|
|
6387
|
+
};
|
|
6388
|
+
var workflowModuleContext = async (workspace, plan) => {
|
|
6389
|
+
const app = workflowStringInput(plan.inputs.app);
|
|
6390
|
+
const moduleName = workflowStringInput(plan.inputs.module);
|
|
6391
|
+
if (!app || !moduleName)
|
|
6392
|
+
return null;
|
|
6393
|
+
const [apps, libs] = await workspace.getSyss();
|
|
6394
|
+
const sysType = apps.includes(app) ? "app" : libs.includes(app) ? "lib" : null;
|
|
6395
|
+
if (!sysType)
|
|
6396
|
+
return null;
|
|
6397
|
+
const modulePath = `${sysType}s/${app}/lib/${moduleName}`;
|
|
6398
|
+
const files = await workspace.readdir(modulePath);
|
|
6399
|
+
const abstractPath = `${modulePath}/${moduleName}.abstract.md`;
|
|
6400
|
+
return {
|
|
6401
|
+
kind: "domain",
|
|
6402
|
+
name: moduleName,
|
|
6403
|
+
folderName: moduleName,
|
|
6404
|
+
sysName: app,
|
|
6405
|
+
sysType,
|
|
6406
|
+
path: modulePath,
|
|
6407
|
+
abstract: {
|
|
6408
|
+
path: abstractPath,
|
|
6409
|
+
exists: files.includes(`${moduleName}.abstract.md`),
|
|
6410
|
+
headings: []
|
|
6411
|
+
},
|
|
6412
|
+
files
|
|
6413
|
+
};
|
|
6414
|
+
};
|
|
6415
|
+
var structureCheck = (code, target, status, message) => ({
|
|
6416
|
+
code,
|
|
6417
|
+
target,
|
|
6418
|
+
status,
|
|
6419
|
+
message
|
|
6420
|
+
});
|
|
6421
|
+
var checkAddFieldStructure = async (workspace, plan) => {
|
|
6422
|
+
if (plan.workflow !== "add-field" && plan.workflow !== "add-enum-field")
|
|
6423
|
+
return {};
|
|
6424
|
+
const app = workflowStringInput(plan.inputs.app);
|
|
6425
|
+
const moduleName = workflowStringInput(plan.inputs.module);
|
|
6426
|
+
const fieldName = workflowStringInput(plan.inputs.field);
|
|
6427
|
+
const typeName = workflowStringInput(plan.inputs.type);
|
|
6428
|
+
if (!app || !moduleName || !fieldName || !typeName)
|
|
6429
|
+
return {};
|
|
6430
|
+
const moduleContext = await workflowModuleContext(workspace, plan);
|
|
6431
|
+
if (!moduleContext)
|
|
6432
|
+
return {};
|
|
6433
|
+
const paths = moduleSourcePaths(moduleName);
|
|
6434
|
+
const constantPath = `${moduleContext.path}/${paths.constant.replace(`lib/${moduleName}/`, "")}`;
|
|
6435
|
+
const dictionaryPath = `${moduleContext.path}/${paths.dictionary.replace(`lib/${moduleName}/`, "")}`;
|
|
6436
|
+
const moduleClassName = moduleComponentName(moduleName);
|
|
6437
|
+
const inputClassName = `${moduleClassName}Input`;
|
|
6438
|
+
const index = await buildAkanModuleContextIndex(workspace, moduleContext, { field: fieldName });
|
|
6439
|
+
const diagnostics = [];
|
|
6440
|
+
const postApplyChecks = [];
|
|
6441
|
+
const constantContent = await workspace.readFile(constantPath);
|
|
6442
|
+
const constantStructure = inspectConstantStructure(constantContent, inputClassName, moduleClassName);
|
|
6443
|
+
const constantNames = constantStructure.fields.map((field) => field.name);
|
|
6444
|
+
const requestedConstantFields = constantStructure.fields.filter((field) => field.name === fieldName);
|
|
6445
|
+
const normalizedType = typeName.toLowerCase() === "enum" ? typeName : normalizeFieldType(typeName);
|
|
6446
|
+
const constantFailures = [
|
|
6447
|
+
!constantStructure.parseValid ? "constant file does not parse" : null,
|
|
6448
|
+
!constantStructure.inputObjectFound ? `${inputClassName} via builder object was not found` : null,
|
|
6449
|
+
requestedConstantFields.length !== 1 ? `field "${fieldName}" appears ${requestedConstantFields.length} time(s) in ${inputClassName}` : null,
|
|
6450
|
+
constantStructure.builderName && requestedConstantFields[0]?.expressionBuilder && requestedConstantFields[0].expressionBuilder !== constantStructure.builderName ? `field "${fieldName}" uses builder "${requestedConstantFields[0].expressionBuilder}" instead of "${constantStructure.builderName}"` : null,
|
|
6451
|
+
!constantStructure.builderName ? `${inputClassName} via builder parameter was not found` : null,
|
|
6452
|
+
(normalizedType === "Int" || normalizedType === "Float") && !constantStructure.baseImports.includes(normalizedType) ? `missing ${normalizedType} import from "akanjs/base"` : null,
|
|
6453
|
+
workflowBooleanInput(plan.inputs.includeInLight) === true && fieldCount(constantStructure.lightProjectionFields, fieldName) !== 1 ? `field "${fieldName}" is not present exactly once in Light${moduleClassName}` : null,
|
|
6454
|
+
...index.diagnostics.filter((diagnostic) => diagnostic.severity === "error" && diagnostic.context?.paths?.includes(constantPath)).map((diagnostic) => diagnostic.message)
|
|
6455
|
+
].filter((failure) => failure !== null);
|
|
6456
|
+
const constantValid = constantFailures.length === 0;
|
|
6457
|
+
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(" ")));
|
|
6458
|
+
if (!constantValid) {
|
|
6459
|
+
diagnostics.push(postApplyDiagnostic("workflow-post-apply-structure-invalid", constantFailures.join(" "), constantPath));
|
|
6460
|
+
}
|
|
6461
|
+
const dictionaryContent = await workspace.readFile(dictionaryPath);
|
|
6462
|
+
const dictionaryStructure = inspectDictionaryStructure(dictionaryContent, moduleClassName);
|
|
6463
|
+
const dictionaryFailures = [
|
|
6464
|
+
!dictionaryStructure.parseValid ? "dictionary file does not parse" : null,
|
|
6465
|
+
!dictionaryStructure.modelObjectFound ? `.model<${moduleClassName}> object was not found` : null,
|
|
6466
|
+
dictionaryStructure.modelObjectFound && !dictionaryStructure.chainOrderValid ? `.model(), .slice(), .enum(), .error(), and .translate() chain order is broken: ${dictionaryStructure.chainMethods.join(" -> ")}` : null,
|
|
6467
|
+
fieldCount(dictionaryStructure.fields, fieldName) !== 1 ? `field "${fieldName}" appears ${fieldCount(dictionaryStructure.fields, fieldName)} time(s) in .model<${moduleClassName}>` : null,
|
|
6468
|
+
...index.diagnostics.filter((diagnostic) => diagnostic.severity === "error" && diagnostic.context?.paths?.includes(dictionaryPath)).map((diagnostic) => diagnostic.message)
|
|
6469
|
+
].filter((failure) => failure !== null);
|
|
6470
|
+
const dictionaryValid = dictionaryFailures.length === 0;
|
|
6471
|
+
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(" ")));
|
|
6472
|
+
if (!dictionaryValid) {
|
|
6473
|
+
diagnostics.push(postApplyDiagnostic("workflow-post-apply-structure-invalid", dictionaryFailures.join(" "), dictionaryPath));
|
|
6474
|
+
}
|
|
6475
|
+
const constantOrderValid = fieldOrderValid(constantNames, fieldName);
|
|
6476
|
+
const dictionaryOrderValid = fieldOrderValid(dictionaryStructure.fields, fieldName);
|
|
6477
|
+
const orderValid = constantOrderValid && dictionaryOrderValid;
|
|
6478
|
+
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.`));
|
|
6479
|
+
if (!orderValid) {
|
|
6480
|
+
diagnostics.push(postApplyWarning("workflow-post-apply-field-order-mismatch", `Field "${fieldName}" is present but does not match the shared priority ordering policy.`, `${constantPath}, ${dictionaryPath}`));
|
|
6481
|
+
}
|
|
6482
|
+
return { diagnostics, postApplyChecks };
|
|
6483
|
+
};
|
|
5678
6484
|
var resolveWorkflowSys = async (workspace, target) => {
|
|
5679
6485
|
if (!target)
|
|
5680
6486
|
return null;
|
|
@@ -5711,7 +6517,7 @@ var addFieldUiSurfaceInspection = (plan) => {
|
|
|
5711
6517
|
const policy = addFieldUiPolicyForType(typeName ?? "String");
|
|
5712
6518
|
const surfaces = workflowStringArrayInput(plan.inputs.surfaces);
|
|
5713
6519
|
const templateRequested = surfaces?.includes("template") ?? false;
|
|
5714
|
-
const moduleClassName =
|
|
6520
|
+
const moduleClassName = moduleComponentName(module);
|
|
5715
6521
|
const target = `${app ? `apps/${app}` : "*"}/${moduleSourcePaths(module).template}`;
|
|
5716
6522
|
return {
|
|
5717
6523
|
recommendations: [
|
|
@@ -5880,6 +6686,11 @@ class WorkflowExecutor {
|
|
|
5880
6686
|
postApplyChecks.push(...result.postApplyChecks ?? []);
|
|
5881
6687
|
diagnostics.push(...result.diagnostics ?? []);
|
|
5882
6688
|
}
|
|
6689
|
+
if (!sourceChangeError(diagnostics)) {
|
|
6690
|
+
const result = await checkAddFieldStructure(this.workspace, plan);
|
|
6691
|
+
postApplyChecks.push(...result.postApplyChecks ?? []);
|
|
6692
|
+
diagnostics.push(...result.diagnostics ?? []);
|
|
6693
|
+
}
|
|
5883
6694
|
const recommendationDiagnostics = await Promise.all(recommendations.map((recommendation) => checkRecommendationPath(this.workspace, recommendation)));
|
|
5884
6695
|
diagnostics.push(...recommendationDiagnostics.filter((diagnostic) => !!diagnostic));
|
|
5885
6696
|
}
|
|
@@ -5898,7 +6709,7 @@ class WorkflowExecutor {
|
|
|
5898
6709
|
}
|
|
5899
6710
|
}
|
|
5900
6711
|
// pkgs/@akanjs/devkit/workflow/plan.ts
|
|
5901
|
-
import { capitalize as
|
|
6712
|
+
import { capitalize as capitalize2 } from "akanjs/common";
|
|
5902
6713
|
var surfaceModes = new Set(["infer", "include", "skip"]);
|
|
5903
6714
|
var parseStringList = (value) => {
|
|
5904
6715
|
if (Array.isArray(value)) {
|
|
@@ -6003,7 +6814,7 @@ var createAddFieldRecommendations = (inputs) => {
|
|
|
6003
6814
|
kind: "placement",
|
|
6004
6815
|
target: paths.constant,
|
|
6005
6816
|
confidence: "high",
|
|
6006
|
-
message: `Insert ${field}: field(${normalizedType}) in ${
|
|
6817
|
+
message: `Insert ${field}: field(${normalizedType}) in ${capitalize2(module)}Input.`
|
|
6007
6818
|
},
|
|
6008
6819
|
{
|
|
6009
6820
|
code: "add-field-placement-dictionary",
|
|
@@ -6035,7 +6846,7 @@ var createAddFieldRecommendations = (inputs) => {
|
|
|
6035
6846
|
code: "add-field-light-projection-choice",
|
|
6036
6847
|
kind: "manual-action",
|
|
6037
6848
|
target: paths.constant,
|
|
6038
|
-
action: `Pass includeInLight=true when ${field} should appear in Light${
|
|
6849
|
+
action: `Pass includeInLight=true when ${field} should appear in Light${capitalize2(module)} list/card projections.`,
|
|
6039
6850
|
confidence: "medium",
|
|
6040
6851
|
message: `Light projection exposure for ${module}.${field} is not selected yet.`
|
|
6041
6852
|
}
|
|
@@ -6046,7 +6857,7 @@ var createAddFieldRecommendations = (inputs) => {
|
|
|
6046
6857
|
kind: "placement",
|
|
6047
6858
|
target: paths.constant,
|
|
6048
6859
|
confidence: "high",
|
|
6049
|
-
message: `Add ${field} to Light${
|
|
6860
|
+
message: `Add ${field} to Light${capitalize2(module)} projection fields.`
|
|
6050
6861
|
}
|
|
6051
6862
|
] : [],
|
|
6052
6863
|
...surfaces && !templateRequested ? [
|
|
@@ -6062,7 +6873,7 @@ var createAddFieldRecommendations = (inputs) => {
|
|
|
6062
6873
|
code: "add-field-ui-manual-review",
|
|
6063
6874
|
kind: "manual-action",
|
|
6064
6875
|
target: paths.template,
|
|
6065
|
-
action: `Review ${app}:${module} UI after apply. Template auto-edit requires a generated ${module}Form hook and Layout.Template field list; Unit/View are not auto-edited because list/card placement depends on local layout. Candidate positions: Layout.Template before the closing tag, Light${
|
|
6876
|
+
action: `Review ${app}:${module} UI after apply. Template auto-edit requires a generated ${module}Form hook and Layout.Template field list; Unit/View are not auto-edited because list/card placement depends on local layout. Candidate positions: Layout.Template before the closing tag, Light${capitalize2(module)} projection array for list data, and Unit/View card sections for display.`,
|
|
6066
6877
|
confidence: "medium",
|
|
6067
6878
|
message: "UI manual review includes the reason auto-edit may be skipped and candidate insertion positions."
|
|
6068
6879
|
},
|
|
@@ -6280,6 +7091,7 @@ var renderRecommendation = (recommendation) => {
|
|
|
6280
7091
|
return `- [${recommendation.kind}]${target} ${recommendation.message}${action}`;
|
|
6281
7092
|
};
|
|
6282
7093
|
var renderDiagnostic = (diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`;
|
|
7094
|
+
var renderNextAction = (action) => `- \`${action.command}\`: ${action.reason}`;
|
|
6283
7095
|
var applySourceStatus = (report) => report.diagnostics.some((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown")) ? "failed" : "passed";
|
|
6284
7096
|
var renderWorkflowApplyReport = (report) => {
|
|
6285
7097
|
const manualReviewItems = [
|
|
@@ -6328,7 +7140,7 @@ var renderWorkflowApplyReport = (report) => {
|
|
|
6328
7140
|
...report.recommendations.length ? report.recommendations.slice(0, 3).map(renderRecommendation) : ["- none"],
|
|
6329
7141
|
"",
|
|
6330
7142
|
"## Next Actions",
|
|
6331
|
-
...report.nextActions.length ? report.nextActions.
|
|
7143
|
+
...report.nextActions.length ? report.nextActions.slice(0, 3).map(renderNextAction) : ["- none"],
|
|
6332
7144
|
""
|
|
6333
7145
|
].join(`
|
|
6334
7146
|
`);
|
|
@@ -6409,6 +7221,66 @@ var renderWorkflowRunArtifact = (artifact, format = "markdown") => {
|
|
|
6409
7221
|
}
|
|
6410
7222
|
return jsonText(artifact);
|
|
6411
7223
|
};
|
|
7224
|
+
// pkgs/@akanjs/devkit/workflow/rolloutGate.ts
|
|
7225
|
+
var toolingRolloutCandidates = [
|
|
7226
|
+
{
|
|
7227
|
+
packageName: "typescript",
|
|
7228
|
+
status: "allowed",
|
|
7229
|
+
role: "Primary TypeScript Compiler API baseline for AST locator, text splice, and reparse checks.",
|
|
7230
|
+
adoptionGate: "Already present; keep using stable Bun-compatible package builds."
|
|
7231
|
+
},
|
|
7232
|
+
{
|
|
7233
|
+
packageName: "@ttsc/graph",
|
|
7234
|
+
status: "reference-only",
|
|
7235
|
+
role: "Source-free graph shape and lazy resident model reference.",
|
|
7236
|
+
adoptionGate: "Do not add as an Akan runtime dependency without a separate proposal or milestone update."
|
|
7237
|
+
},
|
|
7238
|
+
{
|
|
7239
|
+
packageName: "ts-morph",
|
|
7240
|
+
status: "experiment-only",
|
|
7241
|
+
role: "Prototype candidate for complex object literal insertion, import update, and class traversal.",
|
|
7242
|
+
adoptionGate: "Use only in isolated prototypes until package size and formatting churn are measured."
|
|
7243
|
+
},
|
|
7244
|
+
{
|
|
7245
|
+
packageName: "ast-grep",
|
|
7246
|
+
status: "experiment-only",
|
|
7247
|
+
role: "Prototype candidate for shape detection, CI rules, and migration rules.",
|
|
7248
|
+
adoptionGate: "Use as a local rule/check experiment, not as the edit engine."
|
|
7249
|
+
},
|
|
7250
|
+
{
|
|
7251
|
+
packageName: "recast",
|
|
7252
|
+
status: "experiment-only",
|
|
7253
|
+
role: "Prototype candidate for formatting preservation.",
|
|
7254
|
+
adoptionGate: "Low priority; require proof that formatting churn is lower than the baseline."
|
|
7255
|
+
},
|
|
7256
|
+
{
|
|
7257
|
+
packageName: "typescript-go",
|
|
7258
|
+
status: "blocked",
|
|
7259
|
+
role: "TypeScript-Go toolchain transition placeholder.",
|
|
7260
|
+
adoptionGate: "Out of scope for Season 2 rollout."
|
|
7261
|
+
},
|
|
7262
|
+
{
|
|
7263
|
+
packageName: "@typescript/native-preview",
|
|
7264
|
+
status: "blocked",
|
|
7265
|
+
role: "TypeScript-Go native preview package placeholder.",
|
|
7266
|
+
adoptionGate: "Out of scope for Season 2 rollout."
|
|
7267
|
+
}
|
|
7268
|
+
];
|
|
7269
|
+
var toolingRolloutGate = {
|
|
7270
|
+
schemaVersion: 1,
|
|
7271
|
+
strategy: "reference-first-dependency-later",
|
|
7272
|
+
dependencyPolicy: "Season 2 keeps new AST and graph tooling as references or isolated experiments until a separate proposal or milestone update approves adoption.",
|
|
7273
|
+
gateConditions: [
|
|
7274
|
+
"Works in Bun runtime and published package artifacts.",
|
|
7275
|
+
"Does not break dist/pkgs package verification.",
|
|
7276
|
+
"Keeps generated source formatting churn limited.",
|
|
7277
|
+
"Reduces add-field regression fixture failures compared with the current TypeScript API baseline.",
|
|
7278
|
+
"Does not move MCP responses toward returning source bodies."
|
|
7279
|
+
],
|
|
7280
|
+
candidates: toolingRolloutCandidates
|
|
7281
|
+
};
|
|
7282
|
+
var isRestrictedCandidate = (candidate) => candidate.status !== "allowed";
|
|
7283
|
+
var restrictedCandidates = new Map(toolingRolloutCandidates.filter(isRestrictedCandidate).map((candidate) => [candidate.packageName, candidate]));
|
|
6412
7284
|
// pkgs/@akanjs/devkit/akanContext.ts
|
|
6413
7285
|
var resourceList = [
|
|
6414
7286
|
{ uri: "akan://docs/framework", name: "Akan framework guide", mimeType: "text/markdown" },
|
|
@@ -6551,7 +7423,7 @@ var planInputString = (plan2, key) => {
|
|
|
6551
7423
|
var expandWorkflowTarget = (target, plan2) => {
|
|
6552
7424
|
const app = planInputString(plan2, "app");
|
|
6553
7425
|
const module = planInputString(plan2, "module");
|
|
6554
|
-
const moduleClass = module ?
|
|
7426
|
+
const moduleClass = module ? capitalize3(module) : "<Module>";
|
|
6555
7427
|
return target.replace(/^\*\//, app ? `apps/${app}/` : "").replaceAll("<module>", module || "<module>").replaceAll("<Module>", moduleClass);
|
|
6556
7428
|
};
|
|
6557
7429
|
var workflowPathsForPlan = (plan2) => plan2.predictedChanges.map((change) => expandWorkflowTarget(change.target, plan2));
|
|
@@ -6573,8 +7445,8 @@ var loadWorkflowContextPaths = async (workspace, runIdOrPlan, changedFiles) => {
|
|
|
6573
7445
|
const paths = [...changedFiles];
|
|
6574
7446
|
if (!runIdOrPlan)
|
|
6575
7447
|
return paths;
|
|
6576
|
-
const inputPath =
|
|
6577
|
-
const artifact = await safeReadJson(inputPath) ?? await safeReadJson(
|
|
7448
|
+
const inputPath = path11.isAbsolute(runIdOrPlan) ? runIdOrPlan : path11.join(workspace.workspaceRoot, runIdOrPlan);
|
|
7449
|
+
const artifact = await safeReadJson(inputPath) ?? await safeReadJson(path11.join(workspace.workspaceRoot, workflowRunArtifactPath(runIdOrPlan)));
|
|
6578
7450
|
if (artifact && isWorkflowRunArtifact(artifact))
|
|
6579
7451
|
paths.push(...workflowPathsForArtifact(artifact));
|
|
6580
7452
|
return [...new Set(paths.filter(Boolean))];
|
|
@@ -6592,9 +7464,9 @@ var isWorkflowRelatedDiagnostic = (diagnostic, workflowPaths) => {
|
|
|
6592
7464
|
});
|
|
6593
7465
|
};
|
|
6594
7466
|
var readGeneratedSyncStates = async (workspace) => {
|
|
6595
|
-
const syncDir =
|
|
7467
|
+
const syncDir = path11.join(workspace.workspaceRoot, workflowSyncDir);
|
|
6596
7468
|
const entries = await safeReadDir(syncDir);
|
|
6597
|
-
const states = await Promise.all(entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => safeReadJson(
|
|
7469
|
+
const states = await Promise.all(entries.filter((entry) => entry.isFile() && entry.name.endsWith(".json")).map((entry) => safeReadJson(path11.join(syncDir, entry.name))));
|
|
6598
7470
|
return states.filter((state) => !!state && state.schemaVersion === 1 && typeof state.target === "string" && typeof state.syncedAt === "string");
|
|
6599
7471
|
};
|
|
6600
7472
|
var generatedFreshnessFromStates = async (workspace) => {
|
|
@@ -6631,12 +7503,12 @@ var parseAbstractSummary = (relativePath, content, includeContent) => {
|
|
|
6631
7503
|
};
|
|
6632
7504
|
};
|
|
6633
7505
|
var readFiles = async (dirPath) => (await safeReadDir(dirPath)).filter((entry) => entry.isFile()).map((entry) => entry.name).sort();
|
|
6634
|
-
var getRelative = (workspace, absolutePath) =>
|
|
7506
|
+
var getRelative = (workspace, absolutePath) => path11.relative(workspace.workspaceRoot, absolutePath).replaceAll(path11.sep, "/");
|
|
6635
7507
|
var createModuleContext = async (workspace, sys2, kind, folderName, moduleName, includeAbstractContent) => {
|
|
6636
|
-
const modulePath = kind === "scalar" ?
|
|
7508
|
+
const modulePath = kind === "scalar" ? path11.join(sys2.cwdPath, "lib", "__scalar", moduleName) : path11.join(sys2.cwdPath, "lib", folderName);
|
|
6637
7509
|
const relativePath = getRelative(workspace, modulePath);
|
|
6638
7510
|
const abstractPath = `${relativePath}/${moduleName}.abstract.md`;
|
|
6639
|
-
const abstractContent = await safeReadText(
|
|
7511
|
+
const abstractContent = await safeReadText(path11.join(workspace.workspaceRoot, abstractPath));
|
|
6640
7512
|
return {
|
|
6641
7513
|
kind,
|
|
6642
7514
|
name: moduleName,
|
|
@@ -6652,7 +7524,7 @@ var getSysModules = async (workspace, sys2, {
|
|
|
6652
7524
|
includeAbstractContent = false,
|
|
6653
7525
|
module: moduleFilter
|
|
6654
7526
|
} = {}) => {
|
|
6655
|
-
const libPath =
|
|
7527
|
+
const libPath = path11.join(sys2.cwdPath, "lib");
|
|
6656
7528
|
const entries = await safeReadDir(libPath);
|
|
6657
7529
|
const modules = [];
|
|
6658
7530
|
for (const entry of entries) {
|
|
@@ -6666,24 +7538,24 @@ var getSysModules = async (workspace, sys2, {
|
|
|
6666
7538
|
const serviceName = entry.name.replace(/^_+/, "");
|
|
6667
7539
|
if (moduleFilter && moduleFilter !== serviceName && moduleFilter !== entry.name)
|
|
6668
7540
|
continue;
|
|
6669
|
-
if (!await FileSys.fileExists(
|
|
7541
|
+
if (!await FileSys.fileExists(path11.join(libPath, entry.name, `${serviceName}.service.ts`)))
|
|
6670
7542
|
continue;
|
|
6671
7543
|
modules.push(await createModuleContext(workspace, sys2, "service", entry.name, serviceName, includeAbstractContent));
|
|
6672
7544
|
} else {
|
|
6673
7545
|
if (moduleFilter && moduleFilter !== entry.name)
|
|
6674
7546
|
continue;
|
|
6675
|
-
if (!await FileSys.fileExists(
|
|
7547
|
+
if (!await FileSys.fileExists(path11.join(libPath, entry.name, `${entry.name}.constant.ts`)))
|
|
6676
7548
|
continue;
|
|
6677
7549
|
modules.push(await createModuleContext(workspace, sys2, "domain", entry.name, entry.name, includeAbstractContent));
|
|
6678
7550
|
}
|
|
6679
7551
|
}
|
|
6680
|
-
const scalarRoot =
|
|
7552
|
+
const scalarRoot = path11.join(libPath, "__scalar");
|
|
6681
7553
|
for (const entry of await safeReadDir(scalarRoot)) {
|
|
6682
7554
|
if (!entry.isDirectory() || entry.name.startsWith("_"))
|
|
6683
7555
|
continue;
|
|
6684
7556
|
if (moduleFilter && moduleFilter !== entry.name)
|
|
6685
7557
|
continue;
|
|
6686
|
-
if (!await FileSys.fileExists(
|
|
7558
|
+
if (!await FileSys.fileExists(path11.join(scalarRoot, entry.name, `${entry.name}.constant.ts`)))
|
|
6687
7559
|
continue;
|
|
6688
7560
|
modules.push(await createModuleContext(workspace, sys2, "scalar", entry.name, entry.name, includeAbstractContent));
|
|
6689
7561
|
}
|
|
@@ -6695,7 +7567,7 @@ var getSysContext = async (workspace, type, name, options) => {
|
|
|
6695
7567
|
type,
|
|
6696
7568
|
name,
|
|
6697
7569
|
path: `${type}s/${name}`,
|
|
6698
|
-
hasConfig: await FileSys.fileExists(
|
|
7570
|
+
hasConfig: await FileSys.fileExists(path11.join(sys2.cwdPath, "akan.config.ts")),
|
|
6699
7571
|
modules: await getSysModules(workspace, sys2, {
|
|
6700
7572
|
includeAbstractContent: options.includeAbstractContent,
|
|
6701
7573
|
module: options.module
|
|
@@ -6706,13 +7578,13 @@ var getSysContext = async (workspace, type, name, options) => {
|
|
|
6706
7578
|
class AkanContextAnalyzer {
|
|
6707
7579
|
static async analyze(workspace, options = {}) {
|
|
6708
7580
|
const [appNames, libNames, pkgNames] = await workspace.getExecs();
|
|
6709
|
-
const rootPackageJson = await safeReadJson(
|
|
7581
|
+
const rootPackageJson = await safeReadJson(path11.join(workspace.workspaceRoot, "package.json"));
|
|
6710
7582
|
const filteredApps = options.app ? appNames.filter((name) => name === options.app) : appNames;
|
|
6711
7583
|
const [apps, libs, pkgs] = await Promise.all([
|
|
6712
7584
|
Promise.all(filteredApps.map((name) => getSysContext(workspace, "app", name, options))),
|
|
6713
7585
|
Promise.all(libNames.map((name) => getSysContext(workspace, "lib", name, options))),
|
|
6714
7586
|
Promise.all(pkgNames.map(async (name) => {
|
|
6715
|
-
const packageJson = await safeReadJson(
|
|
7587
|
+
const packageJson = await safeReadJson(path11.join(workspace.workspaceRoot, "pkgs", name, "package.json"));
|
|
6716
7588
|
return {
|
|
6717
7589
|
name,
|
|
6718
7590
|
path: `pkgs/${name}`,
|
|
@@ -6745,7 +7617,7 @@ class AkanContextAnalyzer {
|
|
|
6745
7617
|
repairAction("format", "akan repair format --target <app-or-lib-or-pkg>", "Run the formatter/linter repair path.", true)
|
|
6746
7618
|
];
|
|
6747
7619
|
for (const app of context.apps) {
|
|
6748
|
-
const appPath =
|
|
7620
|
+
const appPath = path11.join(workspace.workspaceRoot, app.path);
|
|
6749
7621
|
for (const entry of await safeReadDir(appPath)) {
|
|
6750
7622
|
const allowed = entry.isDirectory() ? appRootAllowDirs.has(entry.name) : appRootAllowFiles.has(entry.name);
|
|
6751
7623
|
if (!allowed) {
|
|
@@ -6769,7 +7641,7 @@ class AkanContextAnalyzer {
|
|
|
6769
7641
|
severity: strict ? "error" : "warning",
|
|
6770
7642
|
code: "module-abstract-missing",
|
|
6771
7643
|
path: module.abstract.path,
|
|
6772
|
-
message: `${
|
|
7644
|
+
message: `${capitalize3(module.kind)} module ${sys2.name}:${module.name} should include ${module.abstract.path}`,
|
|
6773
7645
|
repairActions: [action]
|
|
6774
7646
|
});
|
|
6775
7647
|
repairActions.push(action);
|
|
@@ -6781,14 +7653,14 @@ class AkanContextAnalyzer {
|
|
|
6781
7653
|
severity: "error",
|
|
6782
7654
|
code: "module-shape-invalid",
|
|
6783
7655
|
path: module.path,
|
|
6784
|
-
message: `${
|
|
7656
|
+
message: `${capitalize3(module.kind)} module ${sys2.name}:${module.name} is missing required files: ${missingFiles.join(", ")}`,
|
|
6785
7657
|
repairActions: [action]
|
|
6786
7658
|
});
|
|
6787
7659
|
repairActions.push(action);
|
|
6788
7660
|
}
|
|
6789
7661
|
if (module.kind !== "service" && module.files.includes(`${module.name}.dictionary.ts`)) {
|
|
6790
|
-
const constantPath =
|
|
6791
|
-
const dictionaryPath =
|
|
7662
|
+
const constantPath = path11.join(workspace.workspaceRoot, module.path, `${module.name}.constant.ts`);
|
|
7663
|
+
const dictionaryPath = path11.join(workspace.workspaceRoot, module.path, `${module.name}.dictionary.ts`);
|
|
6792
7664
|
const [constantContent, dictionaryContent] = await Promise.all([
|
|
6793
7665
|
safeReadText(constantPath),
|
|
6794
7666
|
safeReadText(dictionaryPath)
|
|
@@ -6860,6 +7732,519 @@ class AkanContextAnalyzer {
|
|
|
6860
7732
|
`;
|
|
6861
7733
|
}
|
|
6862
7734
|
}
|
|
7735
|
+
// pkgs/@akanjs/devkit/akanMcpContract.ts
|
|
7736
|
+
import path12 from "path";
|
|
7737
|
+
var emptySchema = { type: "object", properties: {} };
|
|
7738
|
+
var stringProperty = { type: "string" };
|
|
7739
|
+
var booleanProperty = { type: "boolean" };
|
|
7740
|
+
var objectProperty = { type: "object", additionalProperties: true };
|
|
7741
|
+
var stringArrayProperty = { type: "array", items: stringProperty };
|
|
7742
|
+
var inspectAkanContextRequestTypes = [
|
|
7743
|
+
"workspaceOverview",
|
|
7744
|
+
"moduleContext",
|
|
7745
|
+
"fieldInsertionContext",
|
|
7746
|
+
"workflowDiagnostics",
|
|
7747
|
+
"escape"
|
|
7748
|
+
];
|
|
7749
|
+
var inspectAkanContextRequestTypeProperty = { type: "string", enum: inspectAkanContextRequestTypes };
|
|
7750
|
+
var inspectAkanContextRequestBranches = [
|
|
7751
|
+
{
|
|
7752
|
+
type: "object",
|
|
7753
|
+
properties: { type: { const: "workspaceOverview" } },
|
|
7754
|
+
required: ["type"]
|
|
7755
|
+
},
|
|
7756
|
+
{
|
|
7757
|
+
type: "object",
|
|
7758
|
+
properties: { type: { const: "moduleContext" }, app: stringProperty, module: stringProperty },
|
|
7759
|
+
required: ["type", "app", "module"]
|
|
7760
|
+
},
|
|
7761
|
+
{
|
|
7762
|
+
type: "object",
|
|
7763
|
+
properties: {
|
|
7764
|
+
type: { const: "fieldInsertionContext" },
|
|
7765
|
+
app: stringProperty,
|
|
7766
|
+
module: stringProperty,
|
|
7767
|
+
field: stringProperty,
|
|
7768
|
+
fieldType: stringProperty
|
|
7769
|
+
},
|
|
7770
|
+
required: ["type", "app", "module", "field", "fieldType"]
|
|
7771
|
+
},
|
|
7772
|
+
{
|
|
7773
|
+
type: "object",
|
|
7774
|
+
properties: { type: { const: "workflowDiagnostics" }, runIdOrPlan: stringProperty },
|
|
7775
|
+
required: ["type", "runIdOrPlan"]
|
|
7776
|
+
},
|
|
7777
|
+
{
|
|
7778
|
+
type: "object",
|
|
7779
|
+
properties: { type: { const: "escape" }, reason: stringProperty, nextStep: stringProperty },
|
|
7780
|
+
required: ["type", "reason"]
|
|
7781
|
+
}
|
|
7782
|
+
];
|
|
7783
|
+
var inspectAkanContextInputSchema = {
|
|
7784
|
+
type: "object",
|
|
7785
|
+
properties: {
|
|
7786
|
+
question: {
|
|
7787
|
+
...stringProperty,
|
|
7788
|
+
description: "The user-facing question the agent is trying to answer before reading source bodies."
|
|
7789
|
+
},
|
|
7790
|
+
draft: {
|
|
7791
|
+
type: "object",
|
|
7792
|
+
properties: {
|
|
7793
|
+
reason: stringProperty,
|
|
7794
|
+
type: inspectAkanContextRequestTypeProperty
|
|
7795
|
+
},
|
|
7796
|
+
required: ["reason", "type"]
|
|
7797
|
+
},
|
|
7798
|
+
review: {
|
|
7799
|
+
...stringProperty,
|
|
7800
|
+
description: "A short self-review explaining why this minimal request is sufficient."
|
|
7801
|
+
},
|
|
7802
|
+
request: {
|
|
7803
|
+
type: "object",
|
|
7804
|
+
properties: {
|
|
7805
|
+
type: inspectAkanContextRequestTypeProperty,
|
|
7806
|
+
app: stringProperty,
|
|
7807
|
+
module: stringProperty,
|
|
7808
|
+
field: stringProperty,
|
|
7809
|
+
fieldType: stringProperty,
|
|
7810
|
+
runIdOrPlan: stringProperty,
|
|
7811
|
+
reason: stringProperty,
|
|
7812
|
+
nextStep: stringProperty
|
|
7813
|
+
},
|
|
7814
|
+
required: ["type"],
|
|
7815
|
+
oneOf: inspectAkanContextRequestBranches
|
|
7816
|
+
}
|
|
7817
|
+
},
|
|
7818
|
+
required: ["question", "draft", "review", "request"]
|
|
7819
|
+
};
|
|
7820
|
+
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7821
|
+
var slugPart = (value) => typeof value === "string" ? value.trim().replace(/[^a-zA-Z0-9]+/g, "-").replace(/^-+|-+$/g, "").toLowerCase() : "";
|
|
7822
|
+
var optionalString = (args, key) => {
|
|
7823
|
+
const value = args[key];
|
|
7824
|
+
return typeof value === "string" && value ? value : undefined;
|
|
7825
|
+
};
|
|
7826
|
+
var nestedStringArg = (args, key) => {
|
|
7827
|
+
const value = args[key];
|
|
7828
|
+
if (typeof value !== "string" || !value)
|
|
7829
|
+
throw new Error(`MCP tool argument "${key}" is required.`);
|
|
7830
|
+
return value;
|
|
7831
|
+
};
|
|
7832
|
+
var isInspectAkanContextRequestType = (value) => typeof value === "string" && inspectAkanContextRequestTypes.includes(value);
|
|
7833
|
+
var parseJsonOutput = (output) => JSON.parse(output);
|
|
7834
|
+
var workspacePath = (workspace, filePath) => path12.isAbsolute(filePath) ? filePath : path12.join(workspace.workspaceRoot, filePath);
|
|
7835
|
+
var defaultWorkflowPlanPath = (workflow, inputs) => {
|
|
7836
|
+
const slug = [
|
|
7837
|
+
slugPart(workflow),
|
|
7838
|
+
slugPart(inputs.app),
|
|
7839
|
+
slugPart(inputs.module),
|
|
7840
|
+
slugPart(inputs.field),
|
|
7841
|
+
slugPart(inputs.scalar),
|
|
7842
|
+
slugPart(inputs.surface),
|
|
7843
|
+
slugPart(inputs.mutation),
|
|
7844
|
+
slugPart(inputs.slice)
|
|
7845
|
+
].filter(Boolean).join("-");
|
|
7846
|
+
return `.akan/workflows/plans/${slug || "workflow-plan"}.json`;
|
|
7847
|
+
};
|
|
7848
|
+
var applyFirstPolicy = {
|
|
7849
|
+
mode: "apply-first",
|
|
7850
|
+
directSourceEdits: "fallback-only",
|
|
7851
|
+
applyRequiredWhen: ["plan_workflow returns planPath", "plan_workflow returns next.tool=apply_workflow"],
|
|
7852
|
+
validationRequiredAfterApply: ["validationTarget", "applyReportPath"],
|
|
7853
|
+
fallbackAllowedWhen: [
|
|
7854
|
+
"list_workflows and explain_workflow show no matching workflow",
|
|
7855
|
+
"apply_workflow reports unsupported/no-op/failed diagnostics that require manual action",
|
|
7856
|
+
"recommendations include manual-action follow-up after workflow apply and repairs"
|
|
7857
|
+
],
|
|
7858
|
+
baselineDiagnosticsPolicy: "Do not fix unrelated baselineDiagnostics unless the user asks."
|
|
7859
|
+
};
|
|
7860
|
+
var stringArg = (args, key) => {
|
|
7861
|
+
const value = args[key];
|
|
7862
|
+
if (typeof value !== "string" || !value)
|
|
7863
|
+
throw new Error(`MCP tool argument "${key}" is required.`);
|
|
7864
|
+
return value;
|
|
7865
|
+
};
|
|
7866
|
+
var workflowInputsArg = (args) => {
|
|
7867
|
+
const value = args.inputs;
|
|
7868
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
7869
|
+
return {};
|
|
7870
|
+
return value;
|
|
7871
|
+
};
|
|
7872
|
+
var inspectAkanContextPropsArg = (args) => {
|
|
7873
|
+
const question = stringArg(args, "question");
|
|
7874
|
+
const review = stringArg(args, "review");
|
|
7875
|
+
if (!isRecord(args.draft))
|
|
7876
|
+
throw new Error('MCP tool argument "draft" is required.');
|
|
7877
|
+
if (!isRecord(args.request))
|
|
7878
|
+
throw new Error('MCP tool argument "request" is required.');
|
|
7879
|
+
if (!isInspectAkanContextRequestType(args.draft.type)) {
|
|
7880
|
+
throw new Error('MCP tool argument "draft.type" must be a supported inspect_akan_context request type.');
|
|
7881
|
+
}
|
|
7882
|
+
if (!isInspectAkanContextRequestType(args.request.type)) {
|
|
7883
|
+
throw new Error('MCP tool argument "request.type" must be a supported inspect_akan_context request type.');
|
|
7884
|
+
}
|
|
7885
|
+
const draft = { reason: nestedStringArg(args.draft, "reason"), type: args.draft.type };
|
|
7886
|
+
const request = args.request;
|
|
7887
|
+
if (request.type === "workspaceOverview")
|
|
7888
|
+
return { question, draft, review, request: { type: request.type } };
|
|
7889
|
+
if (request.type === "moduleContext")
|
|
7890
|
+
return {
|
|
7891
|
+
question,
|
|
7892
|
+
draft,
|
|
7893
|
+
review,
|
|
7894
|
+
request: {
|
|
7895
|
+
type: request.type,
|
|
7896
|
+
app: nestedStringArg(request, "app"),
|
|
7897
|
+
module: nestedStringArg(request, "module")
|
|
7898
|
+
}
|
|
7899
|
+
};
|
|
7900
|
+
if (request.type === "fieldInsertionContext")
|
|
7901
|
+
return {
|
|
7902
|
+
question,
|
|
7903
|
+
draft,
|
|
7904
|
+
review,
|
|
7905
|
+
request: {
|
|
7906
|
+
type: request.type,
|
|
7907
|
+
app: nestedStringArg(request, "app"),
|
|
7908
|
+
module: nestedStringArg(request, "module"),
|
|
7909
|
+
field: nestedStringArg(request, "field"),
|
|
7910
|
+
fieldType: nestedStringArg(request, "fieldType")
|
|
7911
|
+
}
|
|
7912
|
+
};
|
|
7913
|
+
if (request.type === "workflowDiagnostics")
|
|
7914
|
+
return {
|
|
7915
|
+
question,
|
|
7916
|
+
draft,
|
|
7917
|
+
review,
|
|
7918
|
+
request: { type: request.type, runIdOrPlan: nestedStringArg(request, "runIdOrPlan") }
|
|
7919
|
+
};
|
|
7920
|
+
return {
|
|
7921
|
+
question,
|
|
7922
|
+
draft,
|
|
7923
|
+
review,
|
|
7924
|
+
request: {
|
|
7925
|
+
type: "escape",
|
|
7926
|
+
reason: nestedStringArg(request, "reason"),
|
|
7927
|
+
nextStep: optionalString(request, "nextStep")
|
|
7928
|
+
}
|
|
7929
|
+
};
|
|
7930
|
+
};
|
|
7931
|
+
var inspectDiagnostic = (severity, code, message) => ({ severity, code, message });
|
|
7932
|
+
var moduleEvidence = (module) => ({
|
|
7933
|
+
kind: "module",
|
|
7934
|
+
target: `${module.sysName}:${module.name}`,
|
|
7935
|
+
path: module.path,
|
|
7936
|
+
summary: `${module.kind} module at ${module.path} with ${module.files.length} source file(s).`
|
|
7937
|
+
});
|
|
7938
|
+
var moduleCandidate = (module) => ({
|
|
7939
|
+
app: module.sysName,
|
|
7940
|
+
sysType: module.sysType,
|
|
7941
|
+
module: module.name,
|
|
7942
|
+
kind: module.kind,
|
|
7943
|
+
path: module.path,
|
|
7944
|
+
files: module.files
|
|
7945
|
+
});
|
|
7946
|
+
var readonlyMcpTools = [
|
|
7947
|
+
{
|
|
7948
|
+
name: "inspect_akan_context",
|
|
7949
|
+
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.",
|
|
7950
|
+
inputSchema: inspectAkanContextInputSchema
|
|
7951
|
+
},
|
|
7952
|
+
{
|
|
7953
|
+
name: "get_workspace_summary",
|
|
7954
|
+
description: "Legacy broad workspace summary. Prefer inspect_akan_context.workspaceOverview for typed source-body-free evidence.",
|
|
7955
|
+
inputSchema: emptySchema
|
|
7956
|
+
},
|
|
7957
|
+
{
|
|
7958
|
+
name: "list_apps",
|
|
7959
|
+
description: "List Akan apps from the workspace context without reading source bodies.",
|
|
7960
|
+
inputSchema: emptySchema
|
|
7961
|
+
},
|
|
7962
|
+
{
|
|
7963
|
+
name: "list_modules",
|
|
7964
|
+
description: "List Akan modules across apps and libs; use inspect_akan_context.moduleContext for typed evidence.",
|
|
7965
|
+
inputSchema: emptySchema
|
|
7966
|
+
},
|
|
7967
|
+
{
|
|
7968
|
+
name: "get_module_context",
|
|
7969
|
+
description: "Legacy broad module context. Pass app in monorepos; prefer inspect_akan_context.moduleContext or fieldInsertionContext for typed add-field evidence.",
|
|
7970
|
+
inputSchema: { type: "object", properties: { app: stringProperty, module: stringProperty }, required: ["module"] }
|
|
7971
|
+
},
|
|
7972
|
+
{
|
|
7973
|
+
name: "get_guideline",
|
|
7974
|
+
description: "Return an Akan agent guideline resource by name.",
|
|
7975
|
+
inputSchema: { type: "object", properties: { name: stringProperty }, required: ["name"] }
|
|
7976
|
+
},
|
|
7977
|
+
{
|
|
7978
|
+
name: "explain_command",
|
|
7979
|
+
description: "Explain one Akan CLI command and its agent-facing workflow policy.",
|
|
7980
|
+
inputSchema: { type: "object", properties: { command: stringProperty }, required: ["command"] }
|
|
7981
|
+
},
|
|
7982
|
+
{
|
|
7983
|
+
name: "doctor_workspace",
|
|
7984
|
+
description: "Report workspace diagnostics, optionally split into baseline and workflow scopes.",
|
|
7985
|
+
inputSchema: {
|
|
7986
|
+
type: "object",
|
|
7987
|
+
properties: { strict: booleanProperty, runIdOrPlan: stringProperty, changedFiles: stringArrayProperty }
|
|
7988
|
+
}
|
|
7989
|
+
},
|
|
7990
|
+
{
|
|
7991
|
+
name: "get_validation_contract",
|
|
7992
|
+
description: "Return validation, artifact chain, and apply-first fallback policy.",
|
|
7993
|
+
inputSchema: emptySchema
|
|
7994
|
+
}
|
|
7995
|
+
];
|
|
7996
|
+
var planMcpTools = [
|
|
7997
|
+
{
|
|
7998
|
+
name: "list_workflows",
|
|
7999
|
+
description: "List available read-only workflow specs before creating a plan.",
|
|
8000
|
+
inputSchema: emptySchema
|
|
8001
|
+
},
|
|
8002
|
+
{
|
|
8003
|
+
name: "explain_workflow",
|
|
8004
|
+
description: "Explain one workflow's inputs, predicted changes, validation, and completion criteria.",
|
|
8005
|
+
inputSchema: { type: "object", properties: { workflow: stringProperty }, required: ["workflow"] }
|
|
8006
|
+
},
|
|
8007
|
+
{
|
|
8008
|
+
name: "plan_workflow",
|
|
8009
|
+
description: "Create a read-only workflow plan after context inspection and return planPath plus next.tool=apply_workflow.",
|
|
8010
|
+
inputSchema: {
|
|
8011
|
+
type: "object",
|
|
8012
|
+
properties: { workflow: stringProperty, inputs: objectProperty, out: stringProperty },
|
|
8013
|
+
required: ["workflow"]
|
|
8014
|
+
}
|
|
8015
|
+
}
|
|
8016
|
+
];
|
|
8017
|
+
var applyMcpTools = [
|
|
8018
|
+
{
|
|
8019
|
+
name: "apply_workflow",
|
|
8020
|
+
description: "Apply a stored workflow plan before direct edits and return validationTarget for run_validation.",
|
|
8021
|
+
inputSchema: {
|
|
8022
|
+
type: "object",
|
|
8023
|
+
properties: { planPath: stringProperty, dryRun: booleanProperty },
|
|
8024
|
+
required: ["planPath"]
|
|
8025
|
+
}
|
|
8026
|
+
},
|
|
8027
|
+
{
|
|
8028
|
+
name: "run_validation",
|
|
8029
|
+
description: "Validate a plan, apply report, validationTarget, or run artifact.",
|
|
8030
|
+
inputSchema: {
|
|
8031
|
+
type: "object",
|
|
8032
|
+
properties: { runIdOrPlan: stringProperty },
|
|
8033
|
+
required: ["runIdOrPlan"]
|
|
8034
|
+
}
|
|
8035
|
+
},
|
|
8036
|
+
{
|
|
8037
|
+
name: "repair_generated",
|
|
8038
|
+
description: "Refresh generated Akan files before direct generated-file edits.",
|
|
8039
|
+
inputSchema: { type: "object", properties: { app: stringProperty }, required: ["app"] }
|
|
8040
|
+
},
|
|
8041
|
+
{
|
|
8042
|
+
name: "repair_imports",
|
|
8043
|
+
description: "Run the import repair path before manual import edits.",
|
|
8044
|
+
inputSchema: { type: "object", properties: { target: stringProperty }, required: ["target"] }
|
|
8045
|
+
},
|
|
8046
|
+
{
|
|
8047
|
+
name: "repair_module_shape",
|
|
8048
|
+
description: "Report module-shape repair actions before direct module file fixes.",
|
|
8049
|
+
inputSchema: {
|
|
8050
|
+
type: "object",
|
|
8051
|
+
properties: { app: stringProperty, module: stringProperty },
|
|
8052
|
+
required: ["app", "module"]
|
|
8053
|
+
}
|
|
8054
|
+
}
|
|
8055
|
+
];
|
|
8056
|
+
var listAkanMcpTools = (mode = "readonly") => {
|
|
8057
|
+
if (mode === "readonly")
|
|
8058
|
+
return readonlyMcpTools;
|
|
8059
|
+
if (mode === "plan")
|
|
8060
|
+
return [...readonlyMcpTools, ...planMcpTools];
|
|
8061
|
+
return [...readonlyMcpTools, ...planMcpTools, ...applyMcpTools];
|
|
8062
|
+
};
|
|
8063
|
+
var createAkanValidationContract = (listTools = listAkanMcpTools) => ({
|
|
8064
|
+
schemaVersion: 1,
|
|
8065
|
+
reports: ["WorkflowPlan", "WorkflowApplyReport", "WorkflowValidationRunReport", "RepairReport"],
|
|
8066
|
+
modes: {
|
|
8067
|
+
readonly: listTools("readonly").map((tool) => tool.name),
|
|
8068
|
+
plan: listTools("plan").map((tool) => tool.name),
|
|
8069
|
+
apply: listTools("apply").map((tool) => tool.name)
|
|
8070
|
+
},
|
|
8071
|
+
validationCommands: [
|
|
8072
|
+
"akan workflow validate <run-id-or-plan> --format json",
|
|
8073
|
+
"akan workflow report <run-id> --format json",
|
|
8074
|
+
"akan doctor --strict --format json"
|
|
8075
|
+
],
|
|
8076
|
+
validationFailureScopes: ["workspace-config", "environment", "source-change", "unknown"],
|
|
8077
|
+
artifactChainFields: ["planPath", "applyReportPath", "repairReportPath", "runId", "validationTarget", "next"],
|
|
8078
|
+
diagnosticScopes: ["baseline", "workflow", "unknown"],
|
|
8079
|
+
validationStatuses: {
|
|
8080
|
+
sourceStatus: ["passed", "failed", "unknown"],
|
|
8081
|
+
workspaceStatus: ["passed", "failed", "unknown"],
|
|
8082
|
+
overallStatus: ["passed", "failed", "blocked-by-workspace-config", "blocked-by-environment"],
|
|
8083
|
+
knownBlockers: "Repeated workspace-config/environment failures are summarized before command output."
|
|
8084
|
+
},
|
|
8085
|
+
moduleContextInputs: {
|
|
8086
|
+
module: "required",
|
|
8087
|
+
app: "required"
|
|
8088
|
+
},
|
|
8089
|
+
generatedFreshnessStatuses: ["fresh", "stale", "missing", "unknown"],
|
|
8090
|
+
toolingRolloutGate,
|
|
8091
|
+
directEditFallbackPolicy: applyFirstPolicy,
|
|
8092
|
+
applyReportFields: [
|
|
8093
|
+
"appliedCommands",
|
|
8094
|
+
"recommendedValidationCommands",
|
|
8095
|
+
"commands",
|
|
8096
|
+
"recommendations",
|
|
8097
|
+
"validationTarget"
|
|
8098
|
+
],
|
|
8099
|
+
repairCommands: [
|
|
8100
|
+
"akan repair generated --app <app-or-lib> --format json",
|
|
8101
|
+
"akan repair format --target <app-or-lib-or-pkg> --format json",
|
|
8102
|
+
"akan repair imports --target <app-or-lib-or-pkg> --format json",
|
|
8103
|
+
"akan repair dictionary --app <app-or-lib> --module <module> --format json",
|
|
8104
|
+
"akan repair module-shape --app <app-or-lib> --module <module> --format json"
|
|
8105
|
+
]
|
|
8106
|
+
});
|
|
8107
|
+
var inspectAkanContext = async (workspace, args) => {
|
|
8108
|
+
const props = inspectAkanContextPropsArg(args);
|
|
8109
|
+
const diagnostics = [];
|
|
8110
|
+
if (props.draft.type !== props.request.type) {
|
|
8111
|
+
diagnostics.push(inspectDiagnostic("warning", "inspect-draft-request-mismatch", `Draft chose ${props.draft.type}, but request uses ${props.request.type}.`));
|
|
8112
|
+
}
|
|
8113
|
+
const baseResult = (type, evidence, next, data) => ({
|
|
8114
|
+
schemaVersion: 1,
|
|
8115
|
+
type,
|
|
8116
|
+
question: props.question,
|
|
8117
|
+
diagnostics,
|
|
8118
|
+
evidence,
|
|
8119
|
+
next,
|
|
8120
|
+
...data ? { data } : {}
|
|
8121
|
+
});
|
|
8122
|
+
if (props.request.type === "escape") {
|
|
8123
|
+
return baseResult("escape", [{ kind: "escape", summary: props.request.reason }], {
|
|
8124
|
+
action: "escape",
|
|
8125
|
+
reason: props.request.reason,
|
|
8126
|
+
...props.request.nextStep ? { args: { nextStep: props.request.nextStep } } : {}
|
|
8127
|
+
}, { reason: props.request.reason, nextStep: props.request.nextStep ?? null });
|
|
8128
|
+
}
|
|
8129
|
+
if (props.request.type === "workflowDiagnostics") {
|
|
8130
|
+
const doctor = await AkanContextAnalyzer.doctor(workspace, {
|
|
8131
|
+
strict: true,
|
|
8132
|
+
runIdOrPlan: workspacePath(workspace, props.request.runIdOrPlan)
|
|
8133
|
+
});
|
|
8134
|
+
diagnostics.push(...doctor.diagnostics.map((diagnostic) => ({
|
|
8135
|
+
severity: diagnostic.severity,
|
|
8136
|
+
code: diagnostic.code,
|
|
8137
|
+
message: diagnostic.message,
|
|
8138
|
+
scope: diagnostic.scope,
|
|
8139
|
+
context: {
|
|
8140
|
+
...diagnostic.context,
|
|
8141
|
+
...diagnostic.path ? { paths: [diagnostic.path] } : {}
|
|
8142
|
+
}
|
|
8143
|
+
})));
|
|
8144
|
+
return baseResult("workflowDiagnostics", [
|
|
8145
|
+
{
|
|
8146
|
+
kind: "workflow",
|
|
8147
|
+
target: props.request.runIdOrPlan,
|
|
8148
|
+
summary: `Workflow diagnostics status is ${doctor.status}.`
|
|
8149
|
+
}
|
|
8150
|
+
], {
|
|
8151
|
+
action: doctor.status === "passed" ? "answer" : "validate",
|
|
8152
|
+
reason: doctor.status === "passed" ? "No strict workspace diagnostics were found for the workflow context." : "Review diagnostics before applying or manually editing source files."
|
|
8153
|
+
}, {
|
|
8154
|
+
status: doctor.status,
|
|
8155
|
+
baselineDiagnostics: doctor.baselineDiagnostics?.length ?? 0,
|
|
8156
|
+
workflowDiagnostics: doctor.workflowDiagnostics?.length ?? 0
|
|
8157
|
+
});
|
|
8158
|
+
}
|
|
8159
|
+
const context = await AkanContextAnalyzer.analyze(workspace, {
|
|
8160
|
+
app: props.request.type === "moduleContext" || props.request.type === "fieldInsertionContext" ? props.request.app : null,
|
|
8161
|
+
module: props.request.type === "moduleContext" || props.request.type === "fieldInsertionContext" ? props.request.module : null,
|
|
8162
|
+
includeAbstractContent: false
|
|
8163
|
+
});
|
|
8164
|
+
if (props.request.type === "workspaceOverview") {
|
|
8165
|
+
return baseResult("workspaceOverview", [
|
|
8166
|
+
{
|
|
8167
|
+
kind: "workspace",
|
|
8168
|
+
summary: `${context.repoName} has ${context.apps.length} app(s), ${context.libs.length} lib(s), and ${context.pkgs.length} package(s).`
|
|
8169
|
+
}
|
|
8170
|
+
], {
|
|
8171
|
+
action: "inspect",
|
|
8172
|
+
reason: "Choose moduleContext or fieldInsertionContext for module-scoped evidence before planning a workflow.",
|
|
8173
|
+
tool: "inspect_akan_context"
|
|
8174
|
+
}, {
|
|
8175
|
+
repoName: context.repoName,
|
|
8176
|
+
apps: context.apps.map((app) => ({ name: app.name, path: app.path, modules: app.modules.length })),
|
|
8177
|
+
libs: context.libs.map((lib) => ({ name: lib.name, path: lib.path, modules: lib.modules.length })),
|
|
8178
|
+
pkgs: context.pkgs.map((pkg) => ({ name: pkg.name, path: pkg.path, version: pkg.version ?? null })),
|
|
8179
|
+
generatedFiles: context.generatedFiles,
|
|
8180
|
+
validationCommands: context.validationCommands
|
|
8181
|
+
});
|
|
8182
|
+
}
|
|
8183
|
+
const modules = AkanContextAnalyzer.findModules(context, props.request.module, {
|
|
8184
|
+
app: props.request.app ?? null
|
|
8185
|
+
});
|
|
8186
|
+
if (modules.length === 0) {
|
|
8187
|
+
diagnostics.push(inspectDiagnostic("error", "inspect-module-not-found", `No module matched ${props.request.app ? `${props.request.app}:` : ""}${props.request.module}.`));
|
|
8188
|
+
return baseResult(props.request.type, [], {
|
|
8189
|
+
action: "escape",
|
|
8190
|
+
reason: "The requested module was not found in the workspace index; inspect workspace files or clarify the target."
|
|
8191
|
+
}, { candidates: [] });
|
|
8192
|
+
}
|
|
8193
|
+
if (!props.request.app && modules.length > 1) {
|
|
8194
|
+
diagnostics.push(inspectDiagnostic("error", "inspect-module-ambiguous", `Multiple modules match "${props.request.module}". Re-run with app to disambiguate.`));
|
|
8195
|
+
return baseResult(props.request.type, modules.map(moduleEvidence), {
|
|
8196
|
+
action: "clarify",
|
|
8197
|
+
reason: "Multiple modules have the same name; choose an app before planning a workflow."
|
|
8198
|
+
}, { candidates: modules.map(moduleCandidate) });
|
|
8199
|
+
}
|
|
8200
|
+
const module = modules[0];
|
|
8201
|
+
if (props.request.type === "moduleContext") {
|
|
8202
|
+
return baseResult("moduleContext", [moduleEvidence(module)], {
|
|
8203
|
+
action: "inspect",
|
|
8204
|
+
reason: "Use fieldInsertionContext when preparing add-field or escape when source body details are required.",
|
|
8205
|
+
tool: "inspect_akan_context"
|
|
8206
|
+
}, { module: moduleCandidate(module) });
|
|
8207
|
+
}
|
|
8208
|
+
if (module.kind !== "domain") {
|
|
8209
|
+
diagnostics.push(inspectDiagnostic("error", "field-insertion-unsupported-module-kind", `fieldInsertionContext currently targets domain modules; ${module.sysName}:${module.name} is ${module.kind}.`));
|
|
8210
|
+
}
|
|
8211
|
+
const moduleIndex2 = await buildAkanModuleContextIndex(workspace, module, { field: props.request.field });
|
|
8212
|
+
diagnostics.push(...moduleIndex2.diagnostics);
|
|
8213
|
+
return baseResult("fieldInsertionContext", [
|
|
8214
|
+
moduleEvidence(module),
|
|
8215
|
+
{
|
|
8216
|
+
kind: "field-insertion",
|
|
8217
|
+
target: `${module.sysName}:${module.name}.${props.request.field}`,
|
|
8218
|
+
path: module.path,
|
|
8219
|
+
summary: "M2 returns source-body-free AST index evidence for constant fields, dictionary model labels, and light projection fields."
|
|
8220
|
+
}
|
|
8221
|
+
], module.kind === "domain" ? {
|
|
8222
|
+
action: "plan_workflow",
|
|
8223
|
+
reason: "The module target is unambiguous; create an add-field workflow plan before source edits.",
|
|
8224
|
+
tool: "plan_workflow",
|
|
8225
|
+
args: {
|
|
8226
|
+
workflow: "add-field",
|
|
8227
|
+
inputs: {
|
|
8228
|
+
app: module.sysName,
|
|
8229
|
+
module: module.name,
|
|
8230
|
+
field: props.request.field,
|
|
8231
|
+
type: props.request.fieldType
|
|
8232
|
+
}
|
|
8233
|
+
}
|
|
8234
|
+
} : {
|
|
8235
|
+
action: "escape",
|
|
8236
|
+
reason: "This module kind is not a supported add-field target in the P1 context contract."
|
|
8237
|
+
}, {
|
|
8238
|
+
target: {
|
|
8239
|
+
app: module.sysName,
|
|
8240
|
+
module: module.name,
|
|
8241
|
+
field: props.request.field,
|
|
8242
|
+
fieldType: props.request.fieldType
|
|
8243
|
+
},
|
|
8244
|
+
files: moduleIndex2.files,
|
|
8245
|
+
moduleIndex: moduleIndex2
|
|
8246
|
+
});
|
|
8247
|
+
};
|
|
6863
8248
|
// pkgs/@akanjs/devkit/applicationBuildReporter.ts
|
|
6864
8249
|
import { Logger as Logger6 } from "akanjs/common";
|
|
6865
8250
|
|
|
@@ -6906,20 +8291,20 @@ Caused by: ${ApplicationBuildReporter.formatError(error.cause)}` : "";
|
|
|
6906
8291
|
}
|
|
6907
8292
|
// pkgs/@akanjs/devkit/applicationBuildRunner.ts
|
|
6908
8293
|
import { mkdir as mkdir8, rm as rm3 } from "fs/promises";
|
|
6909
|
-
import
|
|
8294
|
+
import path37 from "path";
|
|
6910
8295
|
|
|
6911
8296
|
// pkgs/@akanjs/devkit/frontendBuild/allRoutesBuilder.ts
|
|
6912
|
-
import
|
|
8297
|
+
import path22 from "path";
|
|
6913
8298
|
|
|
6914
8299
|
// pkgs/@akanjs/devkit/artifact/implicitRootLayout.ts
|
|
6915
8300
|
import { mkdir as mkdir3 } from "fs/promises";
|
|
6916
|
-
import
|
|
8301
|
+
import path13 from "path";
|
|
6917
8302
|
var LAYOUT_KEY_RE = /^\.\/(.+\/)?_layout\.(tsx|ts|jsx|js)$/;
|
|
6918
8303
|
async function appHasStModule(appCwdPath) {
|
|
6919
|
-
return Bun.file(
|
|
8304
|
+
return Bun.file(path13.join(appCwdPath, "lib", "st.ts")).exists();
|
|
6920
8305
|
}
|
|
6921
|
-
var IMPLICIT_LAYOUT_DIR =
|
|
6922
|
-
var IMPLICIT_DICT_DIR =
|
|
8306
|
+
var IMPLICIT_LAYOUT_DIR = path13.join(".akan", "generated", "root-layouts");
|
|
8307
|
+
var IMPLICIT_DICT_DIR = path13.join(".akan", "generated", "dict");
|
|
6923
8308
|
function getRootBoundarySegments(key) {
|
|
6924
8309
|
const match = LAYOUT_KEY_RE.exec(key);
|
|
6925
8310
|
if (!match)
|
|
@@ -6934,10 +8319,10 @@ function implicitRootLayoutKey(segments) {
|
|
|
6934
8319
|
}
|
|
6935
8320
|
function implicitRootLayoutAbsPath(appCwdPath, segments) {
|
|
6936
8321
|
const filename = segments.length ? `${segments.join("__")}__root_layout.tsx` : "__root_layout.tsx";
|
|
6937
|
-
return
|
|
8322
|
+
return path13.join(path13.resolve(appCwdPath), IMPLICIT_LAYOUT_DIR, filename);
|
|
6938
8323
|
}
|
|
6939
8324
|
function implicitDictionaryMacroAbsPath(appCwdPath) {
|
|
6940
|
-
return
|
|
8325
|
+
return path13.join(path13.resolve(appCwdPath), IMPLICIT_DICT_DIR, "useDict.ts");
|
|
6941
8326
|
}
|
|
6942
8327
|
function isRootBoundarySegments(segments, basePaths) {
|
|
6943
8328
|
const firstVisibleIndex = segments.findIndex((segment) => !/^\(.+\)$/.test(segment));
|
|
@@ -6960,7 +8345,7 @@ function findRootBoundaries(pageKeys, appCwdPath, basePaths) {
|
|
|
6960
8345
|
const id = segments.join("/");
|
|
6961
8346
|
boundaries.set(id, {
|
|
6962
8347
|
sourceKey: key,
|
|
6963
|
-
sourceAbsPath:
|
|
8348
|
+
sourceAbsPath: path13.resolve(appCwdPath, "page", key.replace(/^\.\//, "")),
|
|
6964
8349
|
segments
|
|
6965
8350
|
});
|
|
6966
8351
|
}
|
|
@@ -6978,21 +8363,21 @@ function findExplicitRootLayoutAbsPath(pageKeys, appCwdPath) {
|
|
|
6978
8363
|
const segments = getRootBoundarySegments(key);
|
|
6979
8364
|
return segments !== null && segments.length === 0;
|
|
6980
8365
|
});
|
|
6981
|
-
return rootLayoutKey ?
|
|
8366
|
+
return rootLayoutKey ? path13.resolve(appCwdPath, "page", rootLayoutKey.replace(/^\.\//, "")) : null;
|
|
6982
8367
|
}
|
|
6983
8368
|
function routePrefixForSegments(segments) {
|
|
6984
8369
|
const visible = segments.filter((segment) => !/^\(.+\)$/.test(segment));
|
|
6985
8370
|
return visible[0] ?? null;
|
|
6986
8371
|
}
|
|
6987
8372
|
async function assertEnvClientConvention(appCwdPath, appName) {
|
|
6988
|
-
const envPath =
|
|
8373
|
+
const envPath = path13.join(appCwdPath, "env", "env.client.ts");
|
|
6989
8374
|
if (!await Bun.file(envPath).exists()) {
|
|
6990
8375
|
throw new Error(`[route-convention] app "${appName}" must provide env/env.client.ts exporting "env" for generated System.Provider`);
|
|
6991
8376
|
}
|
|
6992
8377
|
}
|
|
6993
8378
|
async function writeGeneratedDictionaryMacroFile(appCwdPath, appName) {
|
|
6994
8379
|
const absPath = implicitDictionaryMacroAbsPath(appCwdPath);
|
|
6995
|
-
await mkdir3(
|
|
8380
|
+
await mkdir3(path13.dirname(absPath), { recursive: true });
|
|
6996
8381
|
await Bun.write(absPath, `import { getAllDictionary } from "@apps/${appName}/lib/dict" with { type: "macro" };
|
|
6997
8382
|
|
|
6998
8383
|
export const allDictionary = getAllDictionary();
|
|
@@ -7003,13 +8388,13 @@ async function writeGeneratedRootLayoutFile(opts) {
|
|
|
7003
8388
|
await assertEnvClientConvention(opts.appCwdPath, opts.appName);
|
|
7004
8389
|
const dictMacroAbsPath = opts.includeSystemProvider ? await writeGeneratedDictionaryMacroFile(opts.appCwdPath, opts.appName) : null;
|
|
7005
8390
|
const absPath = implicitRootLayoutAbsPath(opts.appCwdPath, opts.boundary.segments);
|
|
7006
|
-
await mkdir3(
|
|
7007
|
-
const dictMacroRel = dictMacroAbsPath ?
|
|
8391
|
+
await mkdir3(path13.dirname(absPath), { recursive: true });
|
|
8392
|
+
const dictMacroRel = dictMacroAbsPath ? path13.relative(path13.dirname(absPath), dictMacroAbsPath).split(path13.sep).join("/") : null;
|
|
7008
8393
|
const dictMacroSpecifier = dictMacroRel ? dictMacroRel.startsWith(".") ? dictMacroRel : `./${dictMacroRel}` : null;
|
|
7009
|
-
const sourceRel = opts.boundary.sourceAbsPath ?
|
|
8394
|
+
const sourceRel = opts.boundary.sourceAbsPath ? path13.relative(path13.dirname(absPath), opts.boundary.sourceAbsPath).split(path13.sep).join("/") : null;
|
|
7010
8395
|
const sourceSpecifier = sourceRel ? sourceRel.startsWith(".") ? sourceRel : `./${sourceRel}` : null;
|
|
7011
8396
|
const inheritedSourceAbsPath = opts.rootSourceAbsPath && opts.rootSourceAbsPath !== opts.boundary.sourceAbsPath ? opts.rootSourceAbsPath : null;
|
|
7012
|
-
const inheritedSourceRel = inheritedSourceAbsPath ?
|
|
8397
|
+
const inheritedSourceRel = inheritedSourceAbsPath ? path13.relative(path13.dirname(absPath), inheritedSourceAbsPath).split(path13.sep).join("/") : null;
|
|
7013
8398
|
const inheritedSourceSpecifier = inheritedSourceRel ? inheritedSourceRel.startsWith(".") ? inheritedSourceRel : `./${inheritedSourceRel}` : null;
|
|
7014
8399
|
const clientImport = opts.includeStInit ? `import { st } from "@apps/${opts.appName}/client";
|
|
7015
8400
|
void st;
|
|
@@ -7103,7 +8488,7 @@ export default function GeneratedLayout({ children, params, searchParams }: Layo
|
|
|
7103
8488
|
return absPath;
|
|
7104
8489
|
}
|
|
7105
8490
|
async function resolveSsrPageEntries(opts) {
|
|
7106
|
-
const absPageDir =
|
|
8491
|
+
const absPageDir = path13.resolve(opts.appCwdPath, "page");
|
|
7107
8492
|
const hasSt = await appHasStModule(opts.appCwdPath);
|
|
7108
8493
|
const basePaths = opts.basePaths ?? [];
|
|
7109
8494
|
const rootSourceAbsPath = findExplicitRootLayoutAbsPath(opts.pageKeys, opts.appCwdPath);
|
|
@@ -7114,7 +8499,7 @@ async function resolveSsrPageEntries(opts) {
|
|
|
7114
8499
|
}));
|
|
7115
8500
|
const base = opts.pageKeys.filter((key) => !rootLayoutKeys.has(key)).map((key) => ({
|
|
7116
8501
|
key,
|
|
7117
|
-
moduleAbsPath:
|
|
8502
|
+
moduleAbsPath: path13.resolve(absPageDir, key)
|
|
7118
8503
|
}));
|
|
7119
8504
|
const generated = await Promise.all(rootBoundaries.map(async (boundary) => ({
|
|
7120
8505
|
key: implicitRootLayoutKey(boundary.segments),
|
|
@@ -7138,14 +8523,14 @@ async function resolveSsrPageEntriesForApp(app, pageKeys) {
|
|
|
7138
8523
|
}
|
|
7139
8524
|
|
|
7140
8525
|
// pkgs/@akanjs/devkit/artifact/routeSeedIndex.ts
|
|
7141
|
-
import
|
|
8526
|
+
import path14 from "path";
|
|
7142
8527
|
import { assertUniqueRoutePatterns, compareRouteSpecificity, parseRouteModuleKey as parseRouteModuleKey2 } from "akanjs/common";
|
|
7143
8528
|
function computeRouteSeedIndex(pageEntries) {
|
|
7144
8529
|
const layoutsByPrefix = new Map;
|
|
7145
8530
|
const pagesBySegments = [];
|
|
7146
8531
|
for (const { key, moduleAbsPath, seedAbsPaths } of pageEntries) {
|
|
7147
8532
|
const parsed = parseRouteModuleKey2(key);
|
|
7148
|
-
const files = [
|
|
8533
|
+
const files = [path14.resolve(moduleAbsPath), ...(seedAbsPaths ?? []).map((seed) => path14.resolve(seed))];
|
|
7149
8534
|
if (parsed.kind === "layout") {
|
|
7150
8535
|
const prefix = parsed.routeSegments.join("/");
|
|
7151
8536
|
const prev = layoutsByPrefix.get(prefix) ?? [];
|
|
@@ -7182,7 +8567,7 @@ function computeRouteSeedIndex(pageEntries) {
|
|
|
7182
8567
|
}
|
|
7183
8568
|
var ROUTE_SEED_INDEX_JSON = "route-seed-index.json";
|
|
7184
8569
|
function serializeRouteSeedIndexForArtifact(index, artifactDir, options = {}) {
|
|
7185
|
-
const normalizedArtifactDir =
|
|
8570
|
+
const normalizedArtifactDir = path14.resolve(artifactDir);
|
|
7186
8571
|
if (options.production) {
|
|
7187
8572
|
return {
|
|
7188
8573
|
entries: index.entries.map((entry) => ({ routeId: entry.routeId }))
|
|
@@ -7197,22 +8582,22 @@ function serializeRouteSeedIndexForArtifact(index, artifactDir, options = {}) {
|
|
|
7197
8582
|
};
|
|
7198
8583
|
}
|
|
7199
8584
|
async function saveRouteSeedIndex(artifactDir, index, options = {}) {
|
|
7200
|
-
const absPath =
|
|
8585
|
+
const absPath = path14.join(path14.resolve(artifactDir), ROUTE_SEED_INDEX_JSON);
|
|
7201
8586
|
await Bun.write(absPath, `${JSON.stringify(serializeRouteSeedIndexForArtifact(index, artifactDir, options), null, 2)}
|
|
7202
8587
|
`);
|
|
7203
8588
|
return absPath;
|
|
7204
8589
|
}
|
|
7205
8590
|
function serializeArtifactPath(artifactPath, artifactDir) {
|
|
7206
|
-
if (!
|
|
8591
|
+
if (!path14.isAbsolute(artifactPath))
|
|
7207
8592
|
return artifactPath;
|
|
7208
|
-
return
|
|
8593
|
+
return path14.relative(artifactDir, artifactPath).split(path14.sep).join("/");
|
|
7209
8594
|
}
|
|
7210
8595
|
|
|
7211
8596
|
// pkgs/@akanjs/devkit/frontendBuild/clientEntryDiscovery.ts
|
|
7212
|
-
import
|
|
8597
|
+
import path17 from "path";
|
|
7213
8598
|
|
|
7214
8599
|
// pkgs/@akanjs/devkit/transforms/barrelAnalyzer.ts
|
|
7215
|
-
import
|
|
8600
|
+
import path15 from "path";
|
|
7216
8601
|
import { Logger as Logger7 } from "akanjs/common";
|
|
7217
8602
|
var REEXPORT_RE = /(?:^|\n)\s*export\s+(?:type\s+)?(?:(\*)(?:\s+as\s+(\w+))?|\{\s*([^}]*?)\s*\})\s+from\s+(["'])([^"']+)\4;?/g;
|
|
7218
8603
|
var LOCAL_NAMED_RE = /(?:^|\n)\s*export\s+\{\s*([^}]*?)\s*\}(?!\s*from)/g;
|
|
@@ -7335,7 +8720,7 @@ class BarrelAnalyzer {
|
|
|
7335
8720
|
}
|
|
7336
8721
|
#scanExports(source2, absFile) {
|
|
7337
8722
|
try {
|
|
7338
|
-
const transpiler = [".tsx", ".jsx"].includes(
|
|
8723
|
+
const transpiler = [".tsx", ".jsx"].includes(path15.extname(absFile)) ? this.#tsxTranspiler : this.#tsTranspiler;
|
|
7339
8724
|
const { exports } = transpiler.scan(source2);
|
|
7340
8725
|
return new Set(exports);
|
|
7341
8726
|
} catch (err) {
|
|
@@ -7344,16 +8729,16 @@ class BarrelAnalyzer {
|
|
|
7344
8729
|
}
|
|
7345
8730
|
}
|
|
7346
8731
|
#subpathFor(pkg, absFile) {
|
|
7347
|
-
const rel =
|
|
7348
|
-
if (!rel || rel.startsWith("..") ||
|
|
8732
|
+
const rel = path15.relative(pkg.pkgDir, absFile);
|
|
8733
|
+
if (!rel || rel.startsWith("..") || path15.isAbsolute(rel))
|
|
7349
8734
|
return null;
|
|
7350
8735
|
if (pkg.preserveFilePath)
|
|
7351
|
-
return `${pkg.pkgName}/${rel.split(
|
|
8736
|
+
return `${pkg.pkgName}/${rel.split(path15.sep).join("/")}`;
|
|
7352
8737
|
const noExt = stripKnownExt(rel);
|
|
7353
8738
|
const tail = collapseIndex(noExt);
|
|
7354
8739
|
if (tail === "")
|
|
7355
8740
|
return pkg.pkgName;
|
|
7356
|
-
return `${pkg.pkgName}/${tail.split(
|
|
8741
|
+
return `${pkg.pkgName}/${tail.split(path15.sep).join("/")}`;
|
|
7357
8742
|
}
|
|
7358
8743
|
async#resolveRel(fromFile, relSpec) {
|
|
7359
8744
|
if (this.#opts.resolveRelative)
|
|
@@ -7394,9 +8779,9 @@ var readIfExists = async (absFile) => {
|
|
|
7394
8779
|
return file.text();
|
|
7395
8780
|
};
|
|
7396
8781
|
var defaultResolveRelative = async (fromFile, relSpec) => {
|
|
7397
|
-
const baseDir =
|
|
7398
|
-
const joined =
|
|
7399
|
-
if (
|
|
8782
|
+
const baseDir = path15.dirname(fromFile);
|
|
8783
|
+
const joined = path15.resolve(baseDir, relSpec);
|
|
8784
|
+
if (path15.extname(joined)) {
|
|
7400
8785
|
if (await Bun.file(joined).exists())
|
|
7401
8786
|
return joined;
|
|
7402
8787
|
return null;
|
|
@@ -7407,7 +8792,7 @@ var defaultResolveRelative = async (fromFile, relSpec) => {
|
|
|
7407
8792
|
return cand;
|
|
7408
8793
|
}
|
|
7409
8794
|
for (const ext of CANDIDATE_EXTS) {
|
|
7410
|
-
const cand =
|
|
8795
|
+
const cand = path15.join(joined, `index${ext}`);
|
|
7411
8796
|
if (await Bun.file(cand).exists())
|
|
7412
8797
|
return cand;
|
|
7413
8798
|
}
|
|
@@ -7421,15 +8806,15 @@ var stripKnownExt = (relPath) => {
|
|
|
7421
8806
|
return relPath;
|
|
7422
8807
|
};
|
|
7423
8808
|
var collapseIndex = (relPathNoExt) => {
|
|
7424
|
-
const parts = relPathNoExt.split(
|
|
8809
|
+
const parts = relPathNoExt.split(path15.sep);
|
|
7425
8810
|
if (parts[parts.length - 1] === "index")
|
|
7426
8811
|
parts.pop();
|
|
7427
|
-
return parts.join(
|
|
8812
|
+
return parts.join(path15.sep);
|
|
7428
8813
|
};
|
|
7429
8814
|
|
|
7430
8815
|
// pkgs/@akanjs/devkit/transforms/barrelImportsPlugin.ts
|
|
7431
|
-
import
|
|
7432
|
-
import
|
|
8816
|
+
import path16 from "path";
|
|
8817
|
+
import ts7 from "typescript";
|
|
7433
8818
|
var createBarrelImportsPlugin = async (app, { skipPath = defaultSkipPath, pipeAfter } = {}) => {
|
|
7434
8819
|
const akanConfig2 = await app.getConfig();
|
|
7435
8820
|
const barrels = [...new Set(akanConfig2.barrelImports)].filter(Boolean);
|
|
@@ -7487,10 +8872,10 @@ var createTsconfigPackageResolver = async (app) => {
|
|
|
7487
8872
|
const raw = exact[0];
|
|
7488
8873
|
if (!raw)
|
|
7489
8874
|
return null;
|
|
7490
|
-
const entryFile =
|
|
8875
|
+
const entryFile = path16.resolve(app.workspace.workspaceRoot, raw);
|
|
7491
8876
|
if (!await Bun.file(entryFile).exists())
|
|
7492
8877
|
return null;
|
|
7493
|
-
const parsed =
|
|
8878
|
+
const parsed = path16.parse(entryFile);
|
|
7494
8879
|
const lastSlash = pkgName.lastIndexOf("/");
|
|
7495
8880
|
if (parsed.name !== "index" && lastSlash !== -1) {
|
|
7496
8881
|
const facet = pkgName.slice(lastSlash + 1);
|
|
@@ -7499,7 +8884,7 @@ var createTsconfigPackageResolver = async (app) => {
|
|
|
7499
8884
|
return { pkgName: parentSpec, entryFile, pkgDir: parsed.dir };
|
|
7500
8885
|
}
|
|
7501
8886
|
}
|
|
7502
|
-
return { pkgName, entryFile, pkgDir:
|
|
8887
|
+
return { pkgName, entryFile, pkgDir: path16.dirname(entryFile) };
|
|
7503
8888
|
}
|
|
7504
8889
|
for (const { prefix, replacements } of wildcardEntries) {
|
|
7505
8890
|
if (!pkgName.startsWith(prefix))
|
|
@@ -7509,7 +8894,7 @@ var createTsconfigPackageResolver = async (app) => {
|
|
|
7509
8894
|
if (!repl)
|
|
7510
8895
|
continue;
|
|
7511
8896
|
const replPath = repl.endsWith("/*") ? repl.slice(0, -1) : repl;
|
|
7512
|
-
const candidate =
|
|
8897
|
+
const candidate = path16.resolve(app.workspace.workspaceRoot, replPath + suffix);
|
|
7513
8898
|
for (const ext of CANDIDATE_EXTS2) {
|
|
7514
8899
|
const file = `${candidate}${ext}`;
|
|
7515
8900
|
if (await Bun.file(file).exists()) {
|
|
@@ -7517,14 +8902,14 @@ var createTsconfigPackageResolver = async (app) => {
|
|
|
7517
8902
|
if (lastSlash !== -1) {
|
|
7518
8903
|
const parentSpec = pkgName.slice(0, lastSlash);
|
|
7519
8904
|
if (parentSpec.length > 0) {
|
|
7520
|
-
return { pkgName: parentSpec, entryFile: file, pkgDir:
|
|
8905
|
+
return { pkgName: parentSpec, entryFile: file, pkgDir: path16.dirname(file) };
|
|
7521
8906
|
}
|
|
7522
8907
|
}
|
|
7523
|
-
return { pkgName, entryFile: file, pkgDir:
|
|
8908
|
+
return { pkgName, entryFile: file, pkgDir: path16.dirname(file) };
|
|
7524
8909
|
}
|
|
7525
8910
|
}
|
|
7526
8911
|
for (const ext of CANDIDATE_EXTS2) {
|
|
7527
|
-
const file =
|
|
8912
|
+
const file = path16.join(candidate, `index${ext}`);
|
|
7528
8913
|
if (await Bun.file(file).exists()) {
|
|
7529
8914
|
return { pkgName, entryFile: file, pkgDir: candidate };
|
|
7530
8915
|
}
|
|
@@ -7535,16 +8920,16 @@ var createTsconfigPackageResolver = async (app) => {
|
|
|
7535
8920
|
const exported = await resolveNodePackageExport(app.workspace.workspaceRoot, pkgName);
|
|
7536
8921
|
if (exported)
|
|
7537
8922
|
return exported;
|
|
7538
|
-
const pkgJsonPath =
|
|
8923
|
+
const pkgJsonPath = path16.join(app.workspace.workspaceRoot, "node_modules", pkgName, "package.json");
|
|
7539
8924
|
if (!await Bun.file(pkgJsonPath).exists())
|
|
7540
8925
|
return null;
|
|
7541
8926
|
try {
|
|
7542
8927
|
const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
|
|
7543
8928
|
const rel = pkgJson.module ?? pkgJson.main ?? "index.js";
|
|
7544
|
-
const entryFile =
|
|
8929
|
+
const entryFile = path16.resolve(path16.dirname(pkgJsonPath), rel);
|
|
7545
8930
|
if (!await Bun.file(entryFile).exists())
|
|
7546
8931
|
return null;
|
|
7547
|
-
return { pkgName, entryFile, pkgDir:
|
|
8932
|
+
return { pkgName, entryFile, pkgDir: path16.dirname(pkgJsonPath) };
|
|
7548
8933
|
} catch {
|
|
7549
8934
|
return null;
|
|
7550
8935
|
}
|
|
@@ -7558,22 +8943,22 @@ var resolveNodePackageExport = async (workspaceRoot, specifier) => {
|
|
|
7558
8943
|
const packageName = getPackageName(specifier);
|
|
7559
8944
|
if (!packageName)
|
|
7560
8945
|
return null;
|
|
7561
|
-
const pkgJsonPath =
|
|
8946
|
+
const pkgJsonPath = path16.join(workspaceRoot, "node_modules", packageName, "package.json");
|
|
7562
8947
|
if (!await Bun.file(pkgJsonPath).exists())
|
|
7563
8948
|
return null;
|
|
7564
8949
|
try {
|
|
7565
|
-
const pkgDir =
|
|
8950
|
+
const pkgDir = path16.dirname(pkgJsonPath);
|
|
7566
8951
|
const pkgJson = JSON.parse(await Bun.file(pkgJsonPath).text());
|
|
7567
8952
|
const subpath = specifier === packageName ? "." : `.${specifier.slice(packageName.length)}`;
|
|
7568
8953
|
const exported = resolvePackageExport(pkgJson.exports, subpath);
|
|
7569
8954
|
const rel = exported ?? (subpath === "." ? pkgJson.module ?? pkgJson.main ?? "index.js" : null);
|
|
7570
8955
|
if (!rel || !rel.startsWith("."))
|
|
7571
8956
|
return null;
|
|
7572
|
-
const entryFile = await resolveFileCandidate(
|
|
8957
|
+
const entryFile = await resolveFileCandidate(path16.resolve(pkgDir, rel));
|
|
7573
8958
|
if (!entryFile)
|
|
7574
8959
|
return null;
|
|
7575
8960
|
const pkgEntryName = specifier;
|
|
7576
|
-
return { pkgName: pkgEntryName, entryFile, pkgDir:
|
|
8961
|
+
return { pkgName: pkgEntryName, entryFile, pkgDir: path16.dirname(entryFile), preserveFilePath: true };
|
|
7577
8962
|
} catch {
|
|
7578
8963
|
return null;
|
|
7579
8964
|
}
|
|
@@ -7630,7 +9015,7 @@ var getPackageName = (specifier) => {
|
|
|
7630
9015
|
var resolveFileCandidate = async (candidate) => {
|
|
7631
9016
|
if (await Bun.file(candidate).exists())
|
|
7632
9017
|
return candidate;
|
|
7633
|
-
if (
|
|
9018
|
+
if (path16.extname(candidate))
|
|
7634
9019
|
return null;
|
|
7635
9020
|
for (const ext of CANDIDATE_EXTS2) {
|
|
7636
9021
|
const file = `${candidate}${ext}`;
|
|
@@ -7638,7 +9023,7 @@ var resolveFileCandidate = async (candidate) => {
|
|
|
7638
9023
|
return file;
|
|
7639
9024
|
}
|
|
7640
9025
|
for (const ext of CANDIDATE_EXTS2) {
|
|
7641
|
-
const file =
|
|
9026
|
+
const file = path16.join(candidate, `index${ext}`);
|
|
7642
9027
|
if (await Bun.file(file).exists())
|
|
7643
9028
|
return file;
|
|
7644
9029
|
}
|
|
@@ -7670,11 +9055,11 @@ var rewriteBarrelImports = async (source2, barrels, analyzer) => {
|
|
|
7670
9055
|
};
|
|
7671
9056
|
var findImportStatements = (source2) => {
|
|
7672
9057
|
const statements = [];
|
|
7673
|
-
const sourceFile2 =
|
|
9058
|
+
const sourceFile2 = ts7.createSourceFile("barrel-imports.tsx", source2, ts7.ScriptTarget.Latest, true, ts7.ScriptKind.TSX);
|
|
7674
9059
|
for (const statement of sourceFile2.statements) {
|
|
7675
|
-
if (!
|
|
9060
|
+
if (!ts7.isImportDeclaration(statement))
|
|
7676
9061
|
continue;
|
|
7677
|
-
if (!
|
|
9062
|
+
if (!ts7.isStringLiteral(statement.moduleSpecifier))
|
|
7678
9063
|
continue;
|
|
7679
9064
|
const importClause = statement.importClause;
|
|
7680
9065
|
if (!importClause)
|
|
@@ -7852,7 +9237,7 @@ class GraphClientEntryDiscovery {
|
|
|
7852
9237
|
}
|
|
7853
9238
|
invalidate(files) {
|
|
7854
9239
|
for (const file of files) {
|
|
7855
|
-
const absPath =
|
|
9240
|
+
const absPath = path17.resolve(file);
|
|
7856
9241
|
this.#readCache.delete(absPath);
|
|
7857
9242
|
this.#rewriteCache.delete(absPath);
|
|
7858
9243
|
this.#importCache.delete(absPath);
|
|
@@ -7862,7 +9247,7 @@ class GraphClientEntryDiscovery {
|
|
|
7862
9247
|
this.#reachableEntriesCache.clear();
|
|
7863
9248
|
}
|
|
7864
9249
|
async#fileExists(p) {
|
|
7865
|
-
const absPath =
|
|
9250
|
+
const absPath = path17.resolve(p);
|
|
7866
9251
|
let cached = this.#fileExistsCache.get(absPath);
|
|
7867
9252
|
if (!cached) {
|
|
7868
9253
|
cached = Bun.file(absPath).exists();
|
|
@@ -7871,7 +9256,7 @@ class GraphClientEntryDiscovery {
|
|
|
7871
9256
|
return cached;
|
|
7872
9257
|
}
|
|
7873
9258
|
#readFile(file) {
|
|
7874
|
-
const absPath =
|
|
9259
|
+
const absPath = path17.resolve(file);
|
|
7875
9260
|
let cached = this.#readCache.get(absPath);
|
|
7876
9261
|
if (!cached) {
|
|
7877
9262
|
cached = Bun.file(absPath).text().catch(() => null);
|
|
@@ -7880,7 +9265,7 @@ class GraphClientEntryDiscovery {
|
|
|
7880
9265
|
return cached;
|
|
7881
9266
|
}
|
|
7882
9267
|
async#resolveFileCandidate(absPathNoExt) {
|
|
7883
|
-
const cacheKey =
|
|
9268
|
+
const cacheKey = path17.resolve(absPathNoExt);
|
|
7884
9269
|
let cached = this.#resolvedFileCache.get(cacheKey);
|
|
7885
9270
|
if (cached)
|
|
7886
9271
|
return cached;
|
|
@@ -7893,7 +9278,7 @@ class GraphClientEntryDiscovery {
|
|
|
7893
9278
|
return f;
|
|
7894
9279
|
}
|
|
7895
9280
|
for (const ext of SOURCE_EXTS2) {
|
|
7896
|
-
const f =
|
|
9281
|
+
const f = path17.join(cacheKey, `index${ext}`);
|
|
7897
9282
|
if (await this.#fileExists(f))
|
|
7898
9283
|
return f;
|
|
7899
9284
|
}
|
|
@@ -7909,7 +9294,7 @@ class GraphClientEntryDiscovery {
|
|
|
7909
9294
|
return cached;
|
|
7910
9295
|
cached = (async () => {
|
|
7911
9296
|
if (spec.startsWith(".") || spec.startsWith("/")) {
|
|
7912
|
-
const abs = spec.startsWith("/") ? spec :
|
|
9297
|
+
const abs = spec.startsWith("/") ? spec : path17.resolve(importerDir, spec);
|
|
7913
9298
|
return this.#resolveFileCandidate(abs);
|
|
7914
9299
|
}
|
|
7915
9300
|
const pkg = await this.#resolvePackage(spec);
|
|
@@ -7921,7 +9306,7 @@ class GraphClientEntryDiscovery {
|
|
|
7921
9306
|
return cached;
|
|
7922
9307
|
}
|
|
7923
9308
|
async#getRewrittenSource(file, content) {
|
|
7924
|
-
const absPath =
|
|
9309
|
+
const absPath = path17.resolve(file);
|
|
7925
9310
|
let cached = this.#rewriteCache.get(absPath);
|
|
7926
9311
|
if (!cached) {
|
|
7927
9312
|
cached = (async () => {
|
|
@@ -7938,7 +9323,7 @@ class GraphClientEntryDiscovery {
|
|
|
7938
9323
|
return cached;
|
|
7939
9324
|
}
|
|
7940
9325
|
async#getImports(file, source2) {
|
|
7941
|
-
const absPath =
|
|
9326
|
+
const absPath = path17.resolve(file);
|
|
7942
9327
|
let cached = this.#importCache.get(absPath);
|
|
7943
9328
|
if (!cached) {
|
|
7944
9329
|
cached = Promise.resolve().then(() => {
|
|
@@ -7953,7 +9338,7 @@ class GraphClientEntryDiscovery {
|
|
|
7953
9338
|
return cached;
|
|
7954
9339
|
}
|
|
7955
9340
|
async#discoverFromFile(file, visiting) {
|
|
7956
|
-
const absPath =
|
|
9341
|
+
const absPath = path17.resolve(file);
|
|
7957
9342
|
const cached = this.#reachableEntriesCache.get(absPath);
|
|
7958
9343
|
if (cached)
|
|
7959
9344
|
return new Set(cached);
|
|
@@ -7970,7 +9355,7 @@ class GraphClientEntryDiscovery {
|
|
|
7970
9355
|
}
|
|
7971
9356
|
const source2 = await this.#getRewrittenSource(absPath, content);
|
|
7972
9357
|
const imports = await this.#getImports(absPath, source2);
|
|
7973
|
-
const importerDir =
|
|
9358
|
+
const importerDir = path17.dirname(absPath);
|
|
7974
9359
|
for (const imp of imports) {
|
|
7975
9360
|
const spec = imp.path;
|
|
7976
9361
|
if (!spec)
|
|
@@ -7996,14 +9381,14 @@ class GraphClientEntryDiscovery {
|
|
|
7996
9381
|
|
|
7997
9382
|
// pkgs/@akanjs/devkit/frontendBuild/routeClientBuilder.ts
|
|
7998
9383
|
import { mkdir as mkdir4 } from "fs/promises";
|
|
7999
|
-
import
|
|
9384
|
+
import path20 from "path";
|
|
8000
9385
|
|
|
8001
9386
|
// pkgs/@akanjs/devkit/transforms/rscUseClientTransform.ts
|
|
8002
|
-
import
|
|
9387
|
+
import path18 from "path";
|
|
8003
9388
|
var USE_CLIENT_RE2 = /^\s*(?:\/\*[\s\S]*?\*\/\s*|\/\/[^\n]*\n\s*)*["']use client["']/;
|
|
8004
9389
|
var IMPLICIT_ROOT_LAYOUT_RE = /[/\\]\.akan[/\\]generated[/\\](?:implicit-root-layout|root-layouts[/\\].*__root_layout)\.(tsx|ts|jsx|js)$/;
|
|
8005
9390
|
function toClientReferencePath(absPath, workspaceRoot) {
|
|
8006
|
-
return
|
|
9391
|
+
return path18.relative(path18.resolve(workspaceRoot), path18.resolve(absPath)).split(path18.sep).join("/");
|
|
8007
9392
|
}
|
|
8008
9393
|
function transformUseClient(source2, args) {
|
|
8009
9394
|
if (!USE_CLIENT_RE2.test(source2))
|
|
@@ -8039,7 +9424,7 @@ function loaderFor2(absPath) {
|
|
|
8039
9424
|
|
|
8040
9425
|
// pkgs/@akanjs/devkit/frontendBuild/clientEntriesBundler.ts
|
|
8041
9426
|
import fs2 from "fs";
|
|
8042
|
-
import
|
|
9427
|
+
import path19 from "path";
|
|
8043
9428
|
|
|
8044
9429
|
// pkgs/@akanjs/devkit/frontendBuild/clientBuildTypes.ts
|
|
8045
9430
|
var CLIENT_BUNDLE_NAMING = {
|
|
@@ -8128,23 +9513,23 @@ class ClientEntriesBundler {
|
|
|
8128
9513
|
};
|
|
8129
9514
|
}
|
|
8130
9515
|
async#createOpaqueEntryAliases() {
|
|
8131
|
-
const aliasDir =
|
|
9516
|
+
const aliasDir = path19.join(this.#app.cwdPath, ".akan", "generated", "client-entry-alias", this.#outputSubdir);
|
|
8132
9517
|
fs2.mkdirSync(aliasDir, { recursive: true });
|
|
8133
9518
|
const originalByAlias = new Map;
|
|
8134
9519
|
const aliasedEntries = await Promise.all(this.#entries.map(async (entry) => {
|
|
8135
|
-
const absEntry =
|
|
9520
|
+
const absEntry = path19.resolve(entry);
|
|
8136
9521
|
const hash = Bun.hash(`${this.#app.name}
|
|
8137
9522
|
${this.#outputSubdir}
|
|
8138
9523
|
${absEntry}`).toString(36);
|
|
8139
|
-
const aliasPath =
|
|
9524
|
+
const aliasPath = path19.join(aliasDir, `${hash}.tsx`);
|
|
8140
9525
|
await Bun.write(aliasPath, this.#createOpaqueEntryAliasSource(absEntry, await this.#scanEntryExportNames(absEntry)));
|
|
8141
|
-
originalByAlias.set(
|
|
9526
|
+
originalByAlias.set(path19.resolve(aliasPath), absEntry);
|
|
8142
9527
|
return aliasPath;
|
|
8143
9528
|
}));
|
|
8144
9529
|
return { entries: aliasedEntries, originalByAlias, aliasDir };
|
|
8145
9530
|
}
|
|
8146
9531
|
#createOpaqueEntryAliasSource(absEntry, exportNames) {
|
|
8147
|
-
const entryLit = JSON.stringify(
|
|
9532
|
+
const entryLit = JSON.stringify(path19.resolve(absEntry));
|
|
8148
9533
|
if (exportNames.length === 0)
|
|
8149
9534
|
return `export * from ${entryLit};
|
|
8150
9535
|
`;
|
|
@@ -8227,16 +9612,16 @@ ${absEntry}`).toString(36);
|
|
|
8227
9612
|
return rewritten;
|
|
8228
9613
|
}
|
|
8229
9614
|
#toServeUrl(absOutPath) {
|
|
8230
|
-
const rel =
|
|
9615
|
+
const rel = path19.relative(this.#outdir, absOutPath).split(path19.sep).join("/");
|
|
8231
9616
|
return `${this.#servePrefix}/${rel}`;
|
|
8232
9617
|
}
|
|
8233
9618
|
#absFromOutdir(p) {
|
|
8234
|
-
return
|
|
9619
|
+
return path19.isAbsolute(p) ? p : path19.resolve(this.#outdir, p);
|
|
8235
9620
|
}
|
|
8236
9621
|
#absFromEntryPoint(p) {
|
|
8237
|
-
if (
|
|
8238
|
-
return
|
|
8239
|
-
const candidates = [
|
|
9622
|
+
if (path19.isAbsolute(p))
|
|
9623
|
+
return path19.resolve(p);
|
|
9624
|
+
const candidates = [path19.resolve(process.cwd(), p), path19.resolve(this.#app.cwdPath, p)];
|
|
8240
9625
|
return candidates.find((candidate) => fs2.existsSync(candidate)) ?? candidates[0];
|
|
8241
9626
|
}
|
|
8242
9627
|
#collectChunkUrls(absOutPath, visited = new Set) {
|
|
@@ -8386,13 +9771,13 @@ class RouteClientBuilder {
|
|
|
8386
9771
|
ssrModuleMap[row.id][row.name] = { id: ssrOutput, chunks: [ssrOutput, ssrOutput], name: row.name, async: true };
|
|
8387
9772
|
}
|
|
8388
9773
|
for (const entry of bootstrapEntries.buildEntries) {
|
|
8389
|
-
const buildEntry =
|
|
8390
|
-
const originalEntry =
|
|
9774
|
+
const buildEntry = path20.resolve(entry);
|
|
9775
|
+
const originalEntry = path20.resolve(bootstrapEntries.originalByBuildEntry.get(buildEntry) ?? buildEntry);
|
|
8391
9776
|
if (!acceptedEntries.has(originalEntry))
|
|
8392
9777
|
continue;
|
|
8393
9778
|
const deps = new Set([originalEntry]);
|
|
8394
9779
|
for (const dep of browserBundle.entryDepsByAbsPath.get(buildEntry) ?? [])
|
|
8395
|
-
deps.add(
|
|
9780
|
+
deps.add(path20.resolve(dep));
|
|
8396
9781
|
const sortedDeps = [...deps].sort();
|
|
8397
9782
|
clientDepsByEntry[originalEntry] = sortedDeps;
|
|
8398
9783
|
for (const dep of sortedDeps)
|
|
@@ -8444,25 +9829,25 @@ class RouteClientBuilder {
|
|
|
8444
9829
|
}).bundle();
|
|
8445
9830
|
}
|
|
8446
9831
|
async#createBootstrapEntries(entries) {
|
|
8447
|
-
if (!await Bun.file(
|
|
9832
|
+
if (!await Bun.file(path20.join(this.#app.cwdPath, "lib", "st.ts")).exists()) {
|
|
8448
9833
|
return { buildEntries: entries, originalByBuildEntry: new Map };
|
|
8449
9834
|
}
|
|
8450
|
-
const outdir =
|
|
9835
|
+
const outdir = path20.join(this.#app.cwdPath, ".akan", "generated", "client-entry-bootstrap");
|
|
8451
9836
|
await mkdir4(outdir, { recursive: true });
|
|
8452
9837
|
const originalByBuildEntry = new Map;
|
|
8453
9838
|
const buildEntries = await Promise.all(entries.map(async (entry) => {
|
|
8454
|
-
const absEntry =
|
|
9839
|
+
const absEntry = path20.resolve(entry);
|
|
8455
9840
|
const hash = Bun.hash(`${this.#app.name}
|
|
8456
9841
|
${absEntry}`).toString(36);
|
|
8457
|
-
const base =
|
|
8458
|
-
const wrapperEntry =
|
|
9842
|
+
const base = path20.basename(absEntry).replace(/[^A-Za-z0-9._-]/g, "_");
|
|
9843
|
+
const wrapperEntry = path20.join(outdir, `${base}-${hash}.tsx`);
|
|
8459
9844
|
const exportNames = await this.#scanExportNames(absEntry);
|
|
8460
9845
|
await Bun.write(wrapperEntry, RouteClientBuilder.createStoreBootstrapEntrySource({
|
|
8461
9846
|
appName: this.#app.name,
|
|
8462
9847
|
originalEntry: absEntry,
|
|
8463
9848
|
exportNames
|
|
8464
9849
|
}));
|
|
8465
|
-
originalByBuildEntry.set(
|
|
9850
|
+
originalByBuildEntry.set(path20.resolve(wrapperEntry), absEntry);
|
|
8466
9851
|
return wrapperEntry;
|
|
8467
9852
|
}));
|
|
8468
9853
|
return { buildEntries, originalByBuildEntry };
|
|
@@ -8514,11 +9899,11 @@ ${defaultNames.map((name) => `export default ${name};`).join(`
|
|
|
8514
9899
|
try {
|
|
8515
9900
|
return Bun.resolveSync("akanjs/server", import.meta.dir);
|
|
8516
9901
|
} catch {
|
|
8517
|
-
return
|
|
9902
|
+
return path20.resolve(import.meta.dir, "../../../server/index.ts");
|
|
8518
9903
|
}
|
|
8519
9904
|
}
|
|
8520
9905
|
static createStoreBootstrapEntrySource(args) {
|
|
8521
|
-
const originalEntry = JSON.stringify(
|
|
9906
|
+
const originalEntry = JSON.stringify(path20.resolve(args.originalEntry));
|
|
8522
9907
|
const namedExports = args.exportNames.filter((name) => name !== "default");
|
|
8523
9908
|
const lines = [
|
|
8524
9909
|
`import ${JSON.stringify(`@apps/${args.appName}/client`)};`,
|
|
@@ -8544,7 +9929,7 @@ ${defaultNames.map((name) => `export default ${name};`).join(`
|
|
|
8544
9929
|
}
|
|
8545
9930
|
|
|
8546
9931
|
// pkgs/@akanjs/devkit/frontendBuild/routesManifestArtifactSerializer.ts
|
|
8547
|
-
import
|
|
9932
|
+
import path21 from "path";
|
|
8548
9933
|
|
|
8549
9934
|
class RoutesManifestArtifactSerializer {
|
|
8550
9935
|
#manifest;
|
|
@@ -8552,7 +9937,7 @@ class RoutesManifestArtifactSerializer {
|
|
|
8552
9937
|
#production;
|
|
8553
9938
|
constructor(manifest, artifactDir, options = {}) {
|
|
8554
9939
|
this.#manifest = manifest;
|
|
8555
|
-
this.#artifactDir =
|
|
9940
|
+
this.#artifactDir = path21.resolve(artifactDir);
|
|
8556
9941
|
this.#production = options.production ?? false;
|
|
8557
9942
|
}
|
|
8558
9943
|
static serialize(manifest, artifactDir, options = {}) {
|
|
@@ -8585,9 +9970,9 @@ class RoutesManifestArtifactSerializer {
|
|
|
8585
9970
|
};
|
|
8586
9971
|
}
|
|
8587
9972
|
#serializeArtifactPath(artifactPath) {
|
|
8588
|
-
if (!
|
|
9973
|
+
if (!path21.isAbsolute(artifactPath))
|
|
8589
9974
|
return artifactPath;
|
|
8590
|
-
return
|
|
9975
|
+
return path21.relative(this.#artifactDir, artifactPath).split(path21.sep).join("/");
|
|
8591
9976
|
}
|
|
8592
9977
|
}
|
|
8593
9978
|
|
|
@@ -8627,7 +10012,7 @@ class AllRoutesBuilder {
|
|
|
8627
10012
|
routeIds: this.#routeIds,
|
|
8628
10013
|
...this.#merged
|
|
8629
10014
|
};
|
|
8630
|
-
const manifestPath =
|
|
10015
|
+
const manifestPath = path22.join(path22.resolve(this.#artifactDir), "routes-manifest.json");
|
|
8631
10016
|
await Bun.write(manifestPath, `${JSON.stringify(RoutesManifestArtifactSerializer.serialize(manifest, this.#artifactDir, {
|
|
8632
10017
|
production: this.#command === "build"
|
|
8633
10018
|
}), null, 2)}
|
|
@@ -8664,12 +10049,12 @@ class AllRoutesBuilder {
|
|
|
8664
10049
|
}
|
|
8665
10050
|
// pkgs/@akanjs/devkit/frontendBuild/csrArtifactBuilder.ts
|
|
8666
10051
|
import { mkdir as mkdir5, rm, unlink } from "fs/promises";
|
|
8667
|
-
import
|
|
10052
|
+
import path24 from "path";
|
|
8668
10053
|
|
|
8669
10054
|
// pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
|
|
8670
10055
|
import fs3 from "fs";
|
|
8671
|
-
import
|
|
8672
|
-
import
|
|
10056
|
+
import path23 from "path";
|
|
10057
|
+
import ts8 from "typescript";
|
|
8673
10058
|
|
|
8674
10059
|
class PagesEntrySourceGenerator {
|
|
8675
10060
|
#pageEntries;
|
|
@@ -8681,7 +10066,7 @@ class PagesEntrySourceGenerator {
|
|
|
8681
10066
|
}
|
|
8682
10067
|
generate() {
|
|
8683
10068
|
const lines = this.#pageEntries.map(({ key, moduleAbsPath }) => {
|
|
8684
|
-
const absPath =
|
|
10069
|
+
const absPath = path23.resolve(moduleAbsPath);
|
|
8685
10070
|
return ` ${JSON.stringify(key)}: () => import(${JSON.stringify(absPath)}),`;
|
|
8686
10071
|
});
|
|
8687
10072
|
return `export const pages = {
|
|
@@ -8695,7 +10080,7 @@ ${lines.join(`
|
|
|
8695
10080
|
}
|
|
8696
10081
|
generateStatic() {
|
|
8697
10082
|
const imports = this.#pageEntries.map(({ moduleAbsPath }, index) => {
|
|
8698
|
-
const absPath =
|
|
10083
|
+
const absPath = path23.resolve(moduleAbsPath);
|
|
8699
10084
|
return `import * as page${index} from ${JSON.stringify(absPath)};`;
|
|
8700
10085
|
});
|
|
8701
10086
|
const entries = this.#pageEntries.map(({ key, moduleAbsPath }, index) => {
|
|
@@ -8712,8 +10097,8 @@ ${entries.join(`
|
|
|
8712
10097
|
}
|
|
8713
10098
|
static #hasAsyncDefaultExport(moduleAbsPath) {
|
|
8714
10099
|
try {
|
|
8715
|
-
const source2 = fs3.readFileSync(
|
|
8716
|
-
const sourceFile2 =
|
|
10100
|
+
const source2 = fs3.readFileSync(path23.resolve(moduleAbsPath), "utf8");
|
|
10101
|
+
const sourceFile2 = ts8.createSourceFile(moduleAbsPath, source2, ts8.ScriptTarget.Latest, true, PagesEntrySourceGenerator.#scriptKind(moduleAbsPath));
|
|
8717
10102
|
return PagesEntrySourceGenerator.#sourceFileHasAsyncDefaultExport(sourceFile2);
|
|
8718
10103
|
} catch {
|
|
8719
10104
|
return false;
|
|
@@ -8723,31 +10108,31 @@ ${entries.join(`
|
|
|
8723
10108
|
const asyncBindings = new Map;
|
|
8724
10109
|
let defaultIdentifier = null;
|
|
8725
10110
|
for (const statement of sourceFile2.statements) {
|
|
8726
|
-
if (
|
|
8727
|
-
if (PagesEntrySourceGenerator.#hasModifier(statement,
|
|
8728
|
-
return PagesEntrySourceGenerator.#hasModifier(statement,
|
|
10111
|
+
if (ts8.isFunctionDeclaration(statement)) {
|
|
10112
|
+
if (PagesEntrySourceGenerator.#hasModifier(statement, ts8.SyntaxKind.DefaultKeyword)) {
|
|
10113
|
+
return PagesEntrySourceGenerator.#hasModifier(statement, ts8.SyntaxKind.AsyncKeyword);
|
|
8729
10114
|
}
|
|
8730
10115
|
if (statement.name) {
|
|
8731
|
-
asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement,
|
|
10116
|
+
asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement, ts8.SyntaxKind.AsyncKeyword));
|
|
8732
10117
|
}
|
|
8733
10118
|
continue;
|
|
8734
10119
|
}
|
|
8735
|
-
if (
|
|
10120
|
+
if (ts8.isVariableStatement(statement)) {
|
|
8736
10121
|
for (const declaration of statement.declarationList.declarations) {
|
|
8737
|
-
if (!
|
|
10122
|
+
if (!ts8.isIdentifier(declaration.name))
|
|
8738
10123
|
continue;
|
|
8739
10124
|
asyncBindings.set(declaration.name.text, PagesEntrySourceGenerator.#isAsyncFunctionExpression(declaration.initializer));
|
|
8740
10125
|
}
|
|
8741
10126
|
continue;
|
|
8742
10127
|
}
|
|
8743
|
-
if (
|
|
10128
|
+
if (ts8.isExportAssignment(statement)) {
|
|
8744
10129
|
if (PagesEntrySourceGenerator.#isAsyncFunctionExpression(statement.expression))
|
|
8745
10130
|
return true;
|
|
8746
|
-
if (
|
|
10131
|
+
if (ts8.isIdentifier(statement.expression))
|
|
8747
10132
|
defaultIdentifier = statement.expression.text;
|
|
8748
10133
|
continue;
|
|
8749
10134
|
}
|
|
8750
|
-
if (
|
|
10135
|
+
if (ts8.isExportDeclaration(statement) && statement.exportClause && ts8.isNamedExports(statement.exportClause)) {
|
|
8751
10136
|
const exportClause = statement.exportClause;
|
|
8752
10137
|
for (const specifier of exportClause.elements) {
|
|
8753
10138
|
if (specifier.name.text !== "default")
|
|
@@ -8759,13 +10144,13 @@ ${entries.join(`
|
|
|
8759
10144
|
return defaultIdentifier ? asyncBindings.get(defaultIdentifier) === true : false;
|
|
8760
10145
|
}
|
|
8761
10146
|
static #hasModifier(node, kind) {
|
|
8762
|
-
return
|
|
10147
|
+
return ts8.canHaveModifiers(node) && (ts8.getModifiers(node)?.some((modifier) => modifier.kind === kind) ?? false);
|
|
8763
10148
|
}
|
|
8764
10149
|
static #isAsyncFunctionExpression(node) {
|
|
8765
|
-
return Boolean(node && (
|
|
10150
|
+
return Boolean(node && (ts8.isArrowFunction(node) || ts8.isFunctionExpression(node)) && PagesEntrySourceGenerator.#hasModifier(node, ts8.SyntaxKind.AsyncKeyword));
|
|
8766
10151
|
}
|
|
8767
10152
|
static #scriptKind(moduleAbsPath) {
|
|
8768
|
-
return moduleAbsPath.endsWith(".tsx") || moduleAbsPath.endsWith(".jsx") ?
|
|
10153
|
+
return moduleAbsPath.endsWith(".tsx") || moduleAbsPath.endsWith(".jsx") ? ts8.ScriptKind.TSX : ts8.ScriptKind.TS;
|
|
8769
10154
|
}
|
|
8770
10155
|
}
|
|
8771
10156
|
|
|
@@ -8791,7 +10176,7 @@ class CsrArtifactBuilder {
|
|
|
8791
10176
|
const csrBasePaths = [...akanConfig2.basePaths];
|
|
8792
10177
|
const htmlEntries = csrBasePaths.length > 0 ? csrBasePaths : ["index"];
|
|
8793
10178
|
await rm(this.#outputDir, { recursive: true, force: true });
|
|
8794
|
-
await mkdir5(
|
|
10179
|
+
await mkdir5(path24.join(this.#app.cwdPath, ".akan/generated/csr"), { recursive: true });
|
|
8795
10180
|
const generatedHtmlFiles = Object.fromEntries(htmlEntries.map((basePath2) => this.#createHtmlFile(basePath2)));
|
|
8796
10181
|
const result = await Bun.build({
|
|
8797
10182
|
target: "browser",
|
|
@@ -8823,7 +10208,7 @@ ${logs}` : ""}`);
|
|
|
8823
10208
|
return { outputDir: this.#outputDir };
|
|
8824
10209
|
}
|
|
8825
10210
|
get #outputDir() {
|
|
8826
|
-
return
|
|
10211
|
+
return path24.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, this.#command === "build" ? "csr" : ".akan/artifact/csr");
|
|
8827
10212
|
}
|
|
8828
10213
|
#define() {
|
|
8829
10214
|
const nodeEnv = this.#command === "build" ? "production" : "development";
|
|
@@ -8854,8 +10239,8 @@ ${logs}` : ""}`);
|
|
|
8854
10239
|
];
|
|
8855
10240
|
}
|
|
8856
10241
|
async#loadCsrArtifact() {
|
|
8857
|
-
const artifactDir =
|
|
8858
|
-
const artifactFile = Bun.file(
|
|
10242
|
+
const artifactDir = path24.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact");
|
|
10243
|
+
const artifactFile = Bun.file(path24.join(artifactDir, "base-artifact.json"));
|
|
8859
10244
|
if (!await artifactFile.exists())
|
|
8860
10245
|
return { cssAssets: {} };
|
|
8861
10246
|
const artifact = await artifactFile.json();
|
|
@@ -8868,7 +10253,7 @@ ${logs}` : ""}`);
|
|
|
8868
10253
|
const htmlFile = Bun.file(htmlPath);
|
|
8869
10254
|
if (!await htmlFile.exists())
|
|
8870
10255
|
continue;
|
|
8871
|
-
const basePath2 =
|
|
10256
|
+
const basePath2 = path24.basename(htmlPath, ".html") === "index" ? "" : path24.basename(htmlPath, ".html");
|
|
8872
10257
|
const inlined = await this.#inlineHtmlAssets(await htmlFile.text(), htmlPath, cssAssets[basePath2]);
|
|
8873
10258
|
for (const filePath of inlined.jsFiles)
|
|
8874
10259
|
jsFiles.add(filePath);
|
|
@@ -8910,7 +10295,7 @@ ${remainingAssets.join(`
|
|
|
8910
10295
|
next = CsrArtifactBuilder.injectBeforeHeadEnd(next, style);
|
|
8911
10296
|
}
|
|
8912
10297
|
if (cssAsset) {
|
|
8913
|
-
const cssPath =
|
|
10298
|
+
const cssPath = path24.join(this.#command === "build" ? this.#app.dist.cwdPath : this.#app.cwdPath, ".akan/artifact", cssAsset.cssRelPath);
|
|
8914
10299
|
const css = await Bun.file(cssPath).text();
|
|
8915
10300
|
const style = CsrArtifactBuilder.createInlineStyle(css);
|
|
8916
10301
|
if (!next.includes(style))
|
|
@@ -8981,16 +10366,16 @@ ${CsrArtifactBuilder.escapeInlineScript(await loadScript(src))}
|
|
|
8981
10366
|
throw new Error(`[csr-build] cannot inline external script: ${src}`);
|
|
8982
10367
|
}
|
|
8983
10368
|
const normalized = src.startsWith("/") ? src.slice(1) : src;
|
|
8984
|
-
return
|
|
10369
|
+
return path24.resolve(path24.dirname(htmlPath), normalized);
|
|
8985
10370
|
}
|
|
8986
10371
|
}
|
|
8987
10372
|
// pkgs/@akanjs/devkit/frontendBuild/cssCompiler.ts
|
|
8988
|
-
import
|
|
10373
|
+
import path26 from "path";
|
|
8989
10374
|
import { Logger as Logger8 } from "akanjs/common";
|
|
8990
10375
|
import { compile } from "tailwindcss";
|
|
8991
10376
|
|
|
8992
10377
|
// pkgs/@akanjs/devkit/frontendBuild/cssImportResolver.ts
|
|
8993
|
-
import
|
|
10378
|
+
import path25 from "path";
|
|
8994
10379
|
var CSS_IMPORT_EXTS = ["", ".css", "/styles.css", "/index.css"];
|
|
8995
10380
|
|
|
8996
10381
|
class CssImportResolver {
|
|
@@ -9043,7 +10428,7 @@ class CssImportResolver {
|
|
|
9043
10428
|
const exact = this.#paths[id];
|
|
9044
10429
|
if (exact) {
|
|
9045
10430
|
for (const repl of exact) {
|
|
9046
|
-
const resolved = await this.#firstExisting(
|
|
10431
|
+
const resolved = await this.#firstExisting(path25.resolve(this.#workspaceRoot, repl));
|
|
9047
10432
|
if (resolved)
|
|
9048
10433
|
return resolved;
|
|
9049
10434
|
}
|
|
@@ -9054,7 +10439,7 @@ class CssImportResolver {
|
|
|
9054
10439
|
const suffix = id.slice(prefix.length);
|
|
9055
10440
|
for (const repl of replacements) {
|
|
9056
10441
|
const replPath = repl.endsWith("/*") ? repl.slice(0, -1) : repl;
|
|
9057
|
-
const resolved = await this.#firstExisting(
|
|
10442
|
+
const resolved = await this.#firstExisting(path25.resolve(this.#workspaceRoot, replPath + suffix));
|
|
9058
10443
|
if (resolved)
|
|
9059
10444
|
return resolved;
|
|
9060
10445
|
}
|
|
@@ -9084,25 +10469,25 @@ class CssImportResolver {
|
|
|
9084
10469
|
try {
|
|
9085
10470
|
if (!await Bun.file(pkgPath).exists())
|
|
9086
10471
|
return null;
|
|
9087
|
-
const pkgDir =
|
|
10472
|
+
const pkgDir = path25.dirname(pkgPath);
|
|
9088
10473
|
const pkg = await Bun.file(pkgPath).json();
|
|
9089
10474
|
const subpath = id === pkgName ? "." : `.${id.slice(pkgName.length)}`;
|
|
9090
10475
|
const exportValue = pkg.exports?.[subpath];
|
|
9091
10476
|
const styleEntry = (typeof exportValue === "string" ? exportValue : exportValue?.style || exportValue?.import || exportValue?.default) || pkg.exports?.["."]?.style || pkg.style || "index.css";
|
|
9092
|
-
return await this.#firstExisting(
|
|
10477
|
+
return await this.#firstExisting(path25.resolve(pkgDir, styleEntry));
|
|
9093
10478
|
} catch {
|
|
9094
10479
|
return null;
|
|
9095
10480
|
}
|
|
9096
10481
|
}
|
|
9097
10482
|
#resolutionBases(fromBase) {
|
|
9098
|
-
return [fromBase, this.#workspaceRoot,
|
|
10483
|
+
return [fromBase, this.#workspaceRoot, path25.dirname(Bun.main), path25.resolve(path25.dirname(Bun.main), "../..")];
|
|
9099
10484
|
}
|
|
9100
10485
|
#packageJsonCandidates(pkgName) {
|
|
9101
10486
|
return [
|
|
9102
|
-
|
|
9103
|
-
|
|
9104
|
-
|
|
9105
|
-
|
|
10487
|
+
path25.join(this.#workspaceRoot, "pkgs", pkgName, "package.json"),
|
|
10488
|
+
path25.join(this.#workspaceRoot, "node_modules", pkgName, "package.json"),
|
|
10489
|
+
path25.join(path25.dirname(Bun.main), "node_modules", pkgName, "package.json"),
|
|
10490
|
+
path25.join(path25.dirname(Bun.main), "../../", pkgName, "package.json")
|
|
9106
10491
|
];
|
|
9107
10492
|
}
|
|
9108
10493
|
async#firstExisting(basePath2) {
|
|
@@ -9120,7 +10505,7 @@ class CssImportResolver {
|
|
|
9120
10505
|
return parts[0] ?? null;
|
|
9121
10506
|
}
|
|
9122
10507
|
static isCssFile(filePath) {
|
|
9123
|
-
return
|
|
10508
|
+
return path25.extname(filePath) === ".css";
|
|
9124
10509
|
}
|
|
9125
10510
|
}
|
|
9126
10511
|
|
|
@@ -9187,7 +10572,7 @@ class CssCompiler {
|
|
|
9187
10572
|
pageKeys
|
|
9188
10573
|
} = {}) {
|
|
9189
10574
|
pageKeys ??= await this.#app.getPageKeys({ refresh });
|
|
9190
|
-
const seeds = pageKeys.map((key) =>
|
|
10575
|
+
const seeds = pageKeys.map((key) => path26.resolve(this.#app.cwdPath, "page", key));
|
|
9191
10576
|
const cssFiles = new Set;
|
|
9192
10577
|
const sourceFiles = new Set;
|
|
9193
10578
|
const queue = [...seeds];
|
|
@@ -9219,7 +10604,7 @@ class CssCompiler {
|
|
|
9219
10604
|
} catch {
|
|
9220
10605
|
continue;
|
|
9221
10606
|
}
|
|
9222
|
-
const importerDir =
|
|
10607
|
+
const importerDir = path26.dirname(filePath);
|
|
9223
10608
|
for (const imp of imports) {
|
|
9224
10609
|
const spec = imp.path;
|
|
9225
10610
|
if (!spec)
|
|
@@ -9245,7 +10630,7 @@ class CssCompiler {
|
|
|
9245
10630
|
const compileStarted = Date.now();
|
|
9246
10631
|
const compilers = await Promise.all(cssPaths.map(async (cssPath) => {
|
|
9247
10632
|
const css = await Bun.file(cssPath).text();
|
|
9248
|
-
const base =
|
|
10633
|
+
const base = path26.dirname(cssPath);
|
|
9249
10634
|
const compiler = await compile(css, {
|
|
9250
10635
|
base,
|
|
9251
10636
|
loadStylesheet: (id, fromBase) => this.#loadStylesheet(id, fromBase),
|
|
@@ -9276,11 +10661,11 @@ class CssCompiler {
|
|
|
9276
10661
|
async#loadStylesheet(id, fromBase) {
|
|
9277
10662
|
const p = await this.#resolveCssImport(id, fromBase);
|
|
9278
10663
|
const content = await Bun.file(p).text();
|
|
9279
|
-
return { path: p, base:
|
|
10664
|
+
return { path: p, base: path26.dirname(p), content };
|
|
9280
10665
|
}
|
|
9281
10666
|
async#resolveCssImport(id, fromBase) {
|
|
9282
10667
|
if (id.startsWith(".") || id.startsWith("/"))
|
|
9283
|
-
return
|
|
10668
|
+
return path26.resolve(fromBase, id);
|
|
9284
10669
|
const resolver = await this.#getCssImportResolver();
|
|
9285
10670
|
const resolved = await resolver.resolve(id, fromBase);
|
|
9286
10671
|
if (resolved)
|
|
@@ -9296,11 +10681,11 @@ class CssCompiler {
|
|
|
9296
10681
|
async#loadModule(id, fromBase) {
|
|
9297
10682
|
const p = __require.resolve(id, { paths: [fromBase] });
|
|
9298
10683
|
const mod = await import(p);
|
|
9299
|
-
return { path: p, base:
|
|
10684
|
+
return { path: p, base: path26.dirname(p), module: mod.default ?? mod };
|
|
9300
10685
|
}
|
|
9301
10686
|
async#resolveSourceImport(id, fromBase, resolvePackage) {
|
|
9302
10687
|
if (id.startsWith(".") || id.startsWith("/")) {
|
|
9303
|
-
const abs = id.startsWith("/") ? id :
|
|
10688
|
+
const abs = id.startsWith("/") ? id : path26.resolve(fromBase, id);
|
|
9304
10689
|
return resolveSourceFileCandidate(abs);
|
|
9305
10690
|
}
|
|
9306
10691
|
const pkg = await resolvePackage(id);
|
|
@@ -9342,7 +10727,7 @@ async function resolveSourceFileCandidate(absPathNoExt) {
|
|
|
9342
10727
|
return filePath;
|
|
9343
10728
|
}
|
|
9344
10729
|
for (const ext of SOURCE_EXTS3) {
|
|
9345
|
-
const filePath =
|
|
10730
|
+
const filePath = path26.join(absPathNoExt, `index${ext}`);
|
|
9346
10731
|
if (await Bun.file(filePath).exists())
|
|
9347
10732
|
return filePath;
|
|
9348
10733
|
}
|
|
@@ -9365,19 +10750,19 @@ function resolveSourceWithRequire(id, fromBase) {
|
|
|
9365
10750
|
}
|
|
9366
10751
|
}
|
|
9367
10752
|
function isSourceFile(filePath) {
|
|
9368
|
-
return SOURCE_EXTS3.includes(
|
|
10753
|
+
return SOURCE_EXTS3.includes(path26.extname(filePath));
|
|
9369
10754
|
}
|
|
9370
10755
|
function isIgnoredNodeModuleSource(filePath) {
|
|
9371
10756
|
return NODE_MODULES_RE3.test(filePath) && !AKANJS_NODE_MODULE_RE3.test(filePath);
|
|
9372
10757
|
}
|
|
9373
10758
|
function getPageKeyBasePath(pageKey, basePaths) {
|
|
9374
|
-
const normalized = pageKey.split(
|
|
10759
|
+
const normalized = pageKey.split(path26.sep).join("/").replace(/^\.\//, "");
|
|
9375
10760
|
const segments = normalized.split("/");
|
|
9376
10761
|
const firstPublicSegment = segments.find((segment) => segment !== "[lang]" && !/^\(.+\)$/.test(segment));
|
|
9377
10762
|
return firstPublicSegment && basePaths.includes(firstPublicSegment) ? firstPublicSegment : null;
|
|
9378
10763
|
}
|
|
9379
10764
|
// pkgs/@akanjs/devkit/frontendBuild/devChangePlanner.ts
|
|
9380
|
-
import
|
|
10765
|
+
import path27 from "path";
|
|
9381
10766
|
var SOURCE_EXTS4 = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
9382
10767
|
var CONFIG_BASENAMES = new Set(["akan.config.ts", "bunfig.toml", "tsconfig.json", "package.json"]);
|
|
9383
10768
|
var BARREL_FACETS = new Set(["common", "srvkit", "ui", "webkit"]);
|
|
@@ -9389,11 +10774,11 @@ var RUNTIME_METADATA_BASENAMES2 = new Set(["dict.ts", "sig.ts", "useClient.ts",
|
|
|
9389
10774
|
class DevChangePlanner {
|
|
9390
10775
|
#workspaceRoot;
|
|
9391
10776
|
constructor({ workspaceRoot }) {
|
|
9392
|
-
this.#workspaceRoot =
|
|
10777
|
+
this.#workspaceRoot = path27.resolve(workspaceRoot);
|
|
9393
10778
|
}
|
|
9394
10779
|
plan({ generation, files, kinds, generatedFiles: generatedFiles2 = [] }) {
|
|
9395
10780
|
const fileList = uniqueResolved([...files, ...generatedFiles2]);
|
|
9396
|
-
const generatedSet = new Set(generatedFiles2.map((file) =>
|
|
10781
|
+
const generatedSet = new Set(generatedFiles2.map((file) => path27.resolve(file)));
|
|
9397
10782
|
const kindSet = new Set(kinds);
|
|
9398
10783
|
const roles = new Set;
|
|
9399
10784
|
const actions = new Set;
|
|
@@ -9410,13 +10795,13 @@ class DevChangePlanner {
|
|
|
9410
10795
|
}
|
|
9411
10796
|
for (const file of fileList) {
|
|
9412
10797
|
const reasons = new Set;
|
|
9413
|
-
const fileRoles = this.#rolesForFile(file, { isGenerated: generatedSet.has(
|
|
10798
|
+
const fileRoles = this.#rolesForFile(file, { isGenerated: generatedSet.has(path27.resolve(file)), reasons });
|
|
9414
10799
|
for (const role of fileRoles)
|
|
9415
10800
|
roles.add(role);
|
|
9416
10801
|
if (reasons.has("runtime-metadata"))
|
|
9417
10802
|
actions.add("restart-builder");
|
|
9418
10803
|
if (reasons.size > 0)
|
|
9419
|
-
reasonByFile[
|
|
10804
|
+
reasonByFile[path27.resolve(file)] = [...reasons].sort();
|
|
9420
10805
|
}
|
|
9421
10806
|
if (roles.has("barrel"))
|
|
9422
10807
|
actions.add("sync-generated");
|
|
@@ -9437,12 +10822,12 @@ class DevChangePlanner {
|
|
|
9437
10822
|
}
|
|
9438
10823
|
#rolesForFile(file, { isGenerated, reasons }) {
|
|
9439
10824
|
const roles = new Set;
|
|
9440
|
-
const abs =
|
|
9441
|
-
const base =
|
|
9442
|
-
const ext =
|
|
10825
|
+
const abs = path27.resolve(file);
|
|
10826
|
+
const base = path27.basename(abs);
|
|
10827
|
+
const ext = path27.extname(abs).toLowerCase();
|
|
9443
10828
|
const isSource = SOURCE_EXTS4.has(ext);
|
|
9444
|
-
const rel =
|
|
9445
|
-
const parts = rel.split(
|
|
10829
|
+
const rel = path27.relative(this.#workspaceRoot, abs);
|
|
10830
|
+
const parts = rel.split(path27.sep).filter(Boolean);
|
|
9446
10831
|
if (CONFIG_BASENAMES.has(base)) {
|
|
9447
10832
|
roles.add("config");
|
|
9448
10833
|
reasons.add("config-file");
|
|
@@ -9483,15 +10868,15 @@ class DevChangePlanner {
|
|
|
9483
10868
|
return roles;
|
|
9484
10869
|
}
|
|
9485
10870
|
#isServerBiased(abs, parts) {
|
|
9486
|
-
const base =
|
|
10871
|
+
const base = path27.basename(abs);
|
|
9487
10872
|
return parts.includes("srvkit") || SERVER_SUFFIXES2.some((suffix) => base.endsWith(suffix)) || base === "main.ts" || base === "server.ts";
|
|
9488
10873
|
}
|
|
9489
10874
|
#isClientBiased(abs, parts) {
|
|
9490
|
-
const base =
|
|
10875
|
+
const base = path27.basename(abs);
|
|
9491
10876
|
return parts.includes("ui") || parts.includes("webkit") || parts.includes("page") || CLIENT_SUFFIXES.some((suffix) => base.endsWith(suffix));
|
|
9492
10877
|
}
|
|
9493
10878
|
#isSharedBiased(abs, parts) {
|
|
9494
|
-
const base =
|
|
10879
|
+
const base = path27.basename(abs);
|
|
9495
10880
|
return parts.includes("common") || SHARED_SUFFIXES2.some((suffix) => base.endsWith(suffix)) || RUNTIME_METADATA_BASENAMES2.has(base);
|
|
9496
10881
|
}
|
|
9497
10882
|
#isRuntimeMetadataFile(parts, base) {
|
|
@@ -9516,16 +10901,16 @@ class DevChangePlanner {
|
|
|
9516
10901
|
return true;
|
|
9517
10902
|
}
|
|
9518
10903
|
#isWorkspaceSource(rel) {
|
|
9519
|
-
if (!rel || rel.startsWith("..") ||
|
|
10904
|
+
if (!rel || rel.startsWith("..") || path27.isAbsolute(rel))
|
|
9520
10905
|
return false;
|
|
9521
|
-
const [scope] = rel.split(
|
|
10906
|
+
const [scope] = rel.split(path27.sep);
|
|
9522
10907
|
return scope === "apps" || scope === "libs" || scope === "pkgs";
|
|
9523
10908
|
}
|
|
9524
10909
|
}
|
|
9525
|
-
var uniqueResolved = (files) => [...new Set(files.map((file) =>
|
|
10910
|
+
var uniqueResolved = (files) => [...new Set(files.map((file) => path27.resolve(file)))].sort();
|
|
9526
10911
|
// pkgs/@akanjs/devkit/frontendBuild/devGeneratedIndexSync.ts
|
|
9527
10912
|
import { mkdir as mkdir6, readdir as readdir2, readFile, rm as rm2, stat as stat3, writeFile } from "fs/promises";
|
|
9528
|
-
import
|
|
10913
|
+
import path28 from "path";
|
|
9529
10914
|
var BARREL_FACETS2 = new Set(["common", "srvkit", "ui", "webkit"]);
|
|
9530
10915
|
var FACET_SOURCE_FILE_RE = /\.(ts|tsx)$/;
|
|
9531
10916
|
var FACET_EXCLUDED_FILE_RE = /(^index\.tsx?$|\.d\.ts$|\.(test|spec)\.(ts|tsx)$|\.css$|\.scss$|\.sass$)/;
|
|
@@ -9536,7 +10921,7 @@ var SCALAR_UI_TYPES = ["Template", "Unit"];
|
|
|
9536
10921
|
class DevGeneratedIndexSync {
|
|
9537
10922
|
#workspaceRoot;
|
|
9538
10923
|
constructor({ workspaceRoot }) {
|
|
9539
|
-
this.#workspaceRoot =
|
|
10924
|
+
this.#workspaceRoot = path28.resolve(workspaceRoot);
|
|
9540
10925
|
}
|
|
9541
10926
|
async syncForBatch(files) {
|
|
9542
10927
|
const indexPaths = new Set;
|
|
@@ -9545,12 +10930,12 @@ class DevGeneratedIndexSync {
|
|
|
9545
10930
|
const facetIndex = this.#facetIndexFor(file);
|
|
9546
10931
|
if (facetIndex)
|
|
9547
10932
|
indexPaths.add(facetIndex);
|
|
9548
|
-
const
|
|
10933
|
+
const moduleIndex2 = await this.#moduleIndexForDirectoryEvent(file).catch((err) => {
|
|
9549
10934
|
errors.push(`[generated-index] module detection failed for ${file}: ${formatError(err)}`);
|
|
9550
10935
|
return null;
|
|
9551
10936
|
});
|
|
9552
|
-
if (
|
|
9553
|
-
indexPaths.add(
|
|
10937
|
+
if (moduleIndex2)
|
|
10938
|
+
indexPaths.add(moduleIndex2);
|
|
9554
10939
|
}
|
|
9555
10940
|
const changedFiles = [];
|
|
9556
10941
|
for (const indexPath of [...indexPaths].sort()) {
|
|
@@ -9565,11 +10950,11 @@ class DevGeneratedIndexSync {
|
|
|
9565
10950
|
return { changedFiles, errors };
|
|
9566
10951
|
}
|
|
9567
10952
|
#facetIndexFor(file) {
|
|
9568
|
-
const abs =
|
|
9569
|
-
const rel =
|
|
9570
|
-
if (rel.startsWith("..") ||
|
|
10953
|
+
const abs = path28.resolve(file);
|
|
10954
|
+
const rel = path28.relative(this.#workspaceRoot, abs);
|
|
10955
|
+
if (rel.startsWith("..") || path28.isAbsolute(rel))
|
|
9571
10956
|
return null;
|
|
9572
|
-
const parts = rel.split(
|
|
10957
|
+
const parts = rel.split(path28.sep).filter(Boolean);
|
|
9573
10958
|
if (parts.length < 4)
|
|
9574
10959
|
return null;
|
|
9575
10960
|
const [scope, project, facet, child] = parts;
|
|
@@ -9577,32 +10962,32 @@ class DevGeneratedIndexSync {
|
|
|
9577
10962
|
return null;
|
|
9578
10963
|
if (!child || child.startsWith(".") || child === "index.ts" || child === "index.tsx")
|
|
9579
10964
|
return null;
|
|
9580
|
-
return
|
|
10965
|
+
return path28.join(this.#workspaceRoot, scope, project, facet, "index.ts");
|
|
9581
10966
|
}
|
|
9582
10967
|
async#moduleIndexForDirectoryEvent(file) {
|
|
9583
|
-
const abs =
|
|
9584
|
-
const rel =
|
|
9585
|
-
if (rel.startsWith("..") ||
|
|
10968
|
+
const abs = path28.resolve(file);
|
|
10969
|
+
const rel = path28.relative(this.#workspaceRoot, abs);
|
|
10970
|
+
if (rel.startsWith("..") || path28.isAbsolute(rel))
|
|
9586
10971
|
return null;
|
|
9587
|
-
const parts = rel.split(
|
|
10972
|
+
const parts = rel.split(path28.sep).filter(Boolean);
|
|
9588
10973
|
if (parts.length !== 4 && parts.length !== 5)
|
|
9589
10974
|
return null;
|
|
9590
10975
|
const [scope, project, libSegment, moduleSegment, scalarSegment] = parts;
|
|
9591
10976
|
if (scope !== "apps" && scope !== "libs" || !project || libSegment !== "lib")
|
|
9592
10977
|
return null;
|
|
9593
10978
|
const isExistingDirectory = await stat3(abs).then((s) => s.isDirectory()).catch(() => false);
|
|
9594
|
-
const looksLikeDeletedDirectory = !
|
|
10979
|
+
const looksLikeDeletedDirectory = !path28.extname(abs);
|
|
9595
10980
|
if (!isExistingDirectory && !looksLikeDeletedDirectory)
|
|
9596
10981
|
return null;
|
|
9597
10982
|
if (moduleSegment === "__scalar" && scalarSegment) {
|
|
9598
|
-
return
|
|
10983
|
+
return path28.join(this.#workspaceRoot, scope, project, "lib", "__scalar", scalarSegment, "index.ts");
|
|
9599
10984
|
}
|
|
9600
10985
|
if (!moduleSegment || moduleSegment === "__scalar")
|
|
9601
10986
|
return null;
|
|
9602
|
-
return
|
|
10987
|
+
return path28.join(this.#workspaceRoot, scope, project, "lib", moduleSegment, "index.ts");
|
|
9603
10988
|
}
|
|
9604
10989
|
async#syncIndex(indexPath) {
|
|
9605
|
-
const dir =
|
|
10990
|
+
const dir = path28.dirname(indexPath);
|
|
9606
10991
|
const content = await this.#contentForIndex(indexPath);
|
|
9607
10992
|
if (content === null) {
|
|
9608
10993
|
if (!await exists(indexPath))
|
|
@@ -9618,11 +11003,11 @@ class DevGeneratedIndexSync {
|
|
|
9618
11003
|
return true;
|
|
9619
11004
|
}
|
|
9620
11005
|
async#contentForIndex(indexPath) {
|
|
9621
|
-
const parts =
|
|
11006
|
+
const parts = path28.relative(this.#workspaceRoot, indexPath).split(path28.sep).filter(Boolean);
|
|
9622
11007
|
const facet = parts.at(-2);
|
|
9623
11008
|
if (facet && BARREL_FACETS2.has(facet))
|
|
9624
|
-
return this.#facetContent(
|
|
9625
|
-
return this.#moduleContent(
|
|
11009
|
+
return this.#facetContent(path28.dirname(indexPath));
|
|
11010
|
+
return this.#moduleContent(path28.dirname(indexPath));
|
|
9626
11011
|
}
|
|
9627
11012
|
async#facetContent(dir) {
|
|
9628
11013
|
const entries = await readdir2(dir, { withFileTypes: true }).catch(() => []);
|
|
@@ -9645,8 +11030,8 @@ class DevGeneratedIndexSync {
|
|
|
9645
11030
|
`;
|
|
9646
11031
|
}
|
|
9647
11032
|
async#moduleContent(dir) {
|
|
9648
|
-
const rel =
|
|
9649
|
-
const parts = rel.split(
|
|
11033
|
+
const rel = path28.relative(this.#workspaceRoot, dir);
|
|
11034
|
+
const parts = rel.split(path28.sep).filter(Boolean);
|
|
9650
11035
|
const moduleSegment = parts.at(-1);
|
|
9651
11036
|
if (!moduleSegment)
|
|
9652
11037
|
return null;
|
|
@@ -9654,11 +11039,11 @@ class DevGeneratedIndexSync {
|
|
|
9654
11039
|
const rawModel = moduleSegment.startsWith("_") ? moduleSegment.slice(1) : moduleSegment;
|
|
9655
11040
|
if (!rawModel)
|
|
9656
11041
|
return null;
|
|
9657
|
-
const modelName =
|
|
11042
|
+
const modelName = capitalize4(rawModel);
|
|
9658
11043
|
const allowedTypes = isScalar ? SCALAR_UI_TYPES : moduleSegment.startsWith("_") ? SERVICE_UI_TYPES : MODULE_UI_TYPES;
|
|
9659
11044
|
const fileTypes = [];
|
|
9660
11045
|
for (const type of allowedTypes) {
|
|
9661
|
-
if (await exists(
|
|
11046
|
+
if (await exists(path28.join(dir, `${modelName}.${type}.tsx`)))
|
|
9662
11047
|
fileTypes.push(type);
|
|
9663
11048
|
}
|
|
9664
11049
|
if (fileTypes.length === 0)
|
|
@@ -9671,11 +11056,11 @@ export const ${modelName} = { ${fileTypes.join(", ")} };`;
|
|
|
9671
11056
|
}
|
|
9672
11057
|
}
|
|
9673
11058
|
var exists = async (file) => stat3(file).then(() => true).catch(() => false);
|
|
9674
|
-
var
|
|
11059
|
+
var capitalize4 = (value) => `${value.charAt(0).toUpperCase()}${value.slice(1)}`;
|
|
9675
11060
|
var formatError = (err) => err instanceof Error ? err.message : String(err);
|
|
9676
11061
|
// pkgs/@akanjs/devkit/frontendBuild/fontOptimizer.ts
|
|
9677
11062
|
import { mkdir as mkdir7 } from "fs/promises";
|
|
9678
|
-
import
|
|
11063
|
+
import path29 from "path";
|
|
9679
11064
|
import {
|
|
9680
11065
|
generateFontFace,
|
|
9681
11066
|
getMetricsForFamily,
|
|
@@ -9684,7 +11069,7 @@ import {
|
|
|
9684
11069
|
} from "fontaine";
|
|
9685
11070
|
import { createFont, woff2 } from "fonteditor-core";
|
|
9686
11071
|
import subsetFont from "subset-font";
|
|
9687
|
-
import
|
|
11072
|
+
import ts9 from "typescript";
|
|
9688
11073
|
var FONT_URL_PREFIX = "/_akan/fonts";
|
|
9689
11074
|
var DEFAULT_FONT_SUBSETS = ["latin"];
|
|
9690
11075
|
|
|
@@ -9699,7 +11084,7 @@ class FontOptimizer {
|
|
|
9699
11084
|
constructor(app, command = "start") {
|
|
9700
11085
|
this.#app = app;
|
|
9701
11086
|
this.#command = command;
|
|
9702
|
-
this.#artifactRoot =
|
|
11087
|
+
this.#artifactRoot = path29.join(command === "build" ? app.dist.cwdPath : app.cwdPath, ".akan/artifact");
|
|
9703
11088
|
}
|
|
9704
11089
|
async optimize() {
|
|
9705
11090
|
const fonts = await this.discoverFonts();
|
|
@@ -9718,7 +11103,7 @@ class FontOptimizer {
|
|
|
9718
11103
|
const pageKeys = await this.#app.getPageKeys();
|
|
9719
11104
|
const fonts = [];
|
|
9720
11105
|
await Promise.all(pageKeys.map(async (key) => {
|
|
9721
|
-
const filePath =
|
|
11106
|
+
const filePath = path29.resolve(this.#app.cwdPath, "page", key);
|
|
9722
11107
|
const file = Bun.file(filePath);
|
|
9723
11108
|
if (!await file.exists())
|
|
9724
11109
|
return;
|
|
@@ -9734,8 +11119,8 @@ class FontOptimizer {
|
|
|
9734
11119
|
this.#app.logger.warn(`[font] source not found: ${face.src}`);
|
|
9735
11120
|
continue;
|
|
9736
11121
|
}
|
|
9737
|
-
const outputPath =
|
|
9738
|
-
await mkdir7(
|
|
11122
|
+
const outputPath = path29.join(this.#artifactRoot, face.optimizedSrc.replace(/^\/_akan\//, ""));
|
|
11123
|
+
await mkdir7(path29.dirname(outputPath), { recursive: true });
|
|
9739
11124
|
const sourceBuffer = Buffer.from(await Bun.file(sourcePath).arrayBuffer());
|
|
9740
11125
|
const outputBuffer = font.subset === false ? await this.#convertToWoff2(sourceBuffer, sourcePath) : await subsetFont(sourceBuffer, await this.#getSubsetText(font), { targetFormat: "woff2" });
|
|
9741
11126
|
await Bun.write(outputPath, outputBuffer);
|
|
@@ -9749,17 +11134,17 @@ class FontOptimizer {
|
|
|
9749
11134
|
this.#cssParts.push(...faceCss, this.#buildRootVariableRule(font));
|
|
9750
11135
|
}
|
|
9751
11136
|
#extractFontsExport(source2, filePath) {
|
|
9752
|
-
const sourceFile2 =
|
|
11137
|
+
const sourceFile2 = ts9.createSourceFile(filePath, source2, ts9.ScriptTarget.Latest, true, ts9.ScriptKind.TSX);
|
|
9753
11138
|
const fonts = [];
|
|
9754
11139
|
for (const statement of sourceFile2.statements) {
|
|
9755
|
-
if (!
|
|
11140
|
+
if (!ts9.isVariableStatement(statement))
|
|
9756
11141
|
continue;
|
|
9757
|
-
const modifiers =
|
|
9758
|
-
const isExported = modifiers?.some((modifier) => modifier.kind ===
|
|
11142
|
+
const modifiers = ts9.canHaveModifiers(statement) ? ts9.getModifiers(statement) : undefined;
|
|
11143
|
+
const isExported = modifiers?.some((modifier) => modifier.kind === ts9.SyntaxKind.ExportKeyword) ?? false;
|
|
9759
11144
|
if (!isExported)
|
|
9760
11145
|
continue;
|
|
9761
11146
|
for (const declaration of statement.declarationList.declarations) {
|
|
9762
|
-
if (!
|
|
11147
|
+
if (!ts9.isIdentifier(declaration.name) || declaration.name.text !== "fonts")
|
|
9763
11148
|
continue;
|
|
9764
11149
|
const value = declaration.initializer ? this.#literalToValue(declaration.initializer) : null;
|
|
9765
11150
|
if (Array.isArray(value)) {
|
|
@@ -9770,20 +11155,20 @@ class FontOptimizer {
|
|
|
9770
11155
|
return fonts;
|
|
9771
11156
|
}
|
|
9772
11157
|
#literalToValue(node) {
|
|
9773
|
-
if (
|
|
11158
|
+
if (ts9.isStringLiteralLike(node))
|
|
9774
11159
|
return node.text;
|
|
9775
|
-
if (
|
|
11160
|
+
if (ts9.isNumericLiteral(node))
|
|
9776
11161
|
return Number(node.text);
|
|
9777
|
-
if (node.kind ===
|
|
11162
|
+
if (node.kind === ts9.SyntaxKind.TrueKeyword)
|
|
9778
11163
|
return true;
|
|
9779
|
-
if (node.kind ===
|
|
11164
|
+
if (node.kind === ts9.SyntaxKind.FalseKeyword)
|
|
9780
11165
|
return false;
|
|
9781
|
-
if (
|
|
11166
|
+
if (ts9.isArrayLiteralExpression(node))
|
|
9782
11167
|
return node.elements.map((element) => this.#literalToValue(element));
|
|
9783
|
-
if (
|
|
11168
|
+
if (ts9.isObjectLiteralExpression(node)) {
|
|
9784
11169
|
const obj = {};
|
|
9785
11170
|
for (const prop of node.properties) {
|
|
9786
|
-
if (!
|
|
11171
|
+
if (!ts9.isPropertyAssignment(prop))
|
|
9787
11172
|
continue;
|
|
9788
11173
|
const name = this.#getPropertyName(prop.name);
|
|
9789
11174
|
if (!name)
|
|
@@ -9792,13 +11177,13 @@ class FontOptimizer {
|
|
|
9792
11177
|
}
|
|
9793
11178
|
return obj;
|
|
9794
11179
|
}
|
|
9795
|
-
if (
|
|
11180
|
+
if (ts9.isAsExpression(node) || ts9.isSatisfiesExpression(node) || ts9.isParenthesizedExpression(node)) {
|
|
9796
11181
|
return this.#literalToValue(node.expression);
|
|
9797
11182
|
}
|
|
9798
11183
|
return;
|
|
9799
11184
|
}
|
|
9800
11185
|
#getPropertyName(name) {
|
|
9801
|
-
if (
|
|
11186
|
+
if (ts9.isIdentifier(name) || ts9.isStringLiteral(name) || ts9.isNumericLiteral(name))
|
|
9802
11187
|
return name.text;
|
|
9803
11188
|
return null;
|
|
9804
11189
|
}
|
|
@@ -9882,8 +11267,8 @@ class FontOptimizer {
|
|
|
9882
11267
|
return null;
|
|
9883
11268
|
const rel = src.replace(/^\//, "");
|
|
9884
11269
|
const candidates = [
|
|
9885
|
-
this.#command === "build" ?
|
|
9886
|
-
|
|
11270
|
+
this.#command === "build" ? path29.join(this.#app.dist.cwdPath, "public", rel) : null,
|
|
11271
|
+
path29.join(this.#app.cwdPath, "public", rel),
|
|
9887
11272
|
this.#resolveWorkspacePublicPath(rel)
|
|
9888
11273
|
].filter(Boolean);
|
|
9889
11274
|
for (const candidate of candidates) {
|
|
@@ -9911,7 +11296,7 @@ class FontOptimizer {
|
|
|
9911
11296
|
return "woff2";
|
|
9912
11297
|
if (signature === "OTTO")
|
|
9913
11298
|
return "otf";
|
|
9914
|
-
const ext =
|
|
11299
|
+
const ext = path29.extname(sourcePath).slice(1).toLowerCase();
|
|
9915
11300
|
if (ext === "otf" || ext === "woff" || ext === "woff2")
|
|
9916
11301
|
return ext;
|
|
9917
11302
|
return "ttf";
|
|
@@ -9920,7 +11305,7 @@ class FontOptimizer {
|
|
|
9920
11305
|
const [root, dep, ...rest] = rel.split("/");
|
|
9921
11306
|
if (root !== "libs" || !dep || rest.length === 0)
|
|
9922
11307
|
return null;
|
|
9923
|
-
return
|
|
11308
|
+
return path29.join(this.#app.workspace.workspaceRoot, "libs", dep, "public", ...rest);
|
|
9924
11309
|
}
|
|
9925
11310
|
async#getSubsetText(font) {
|
|
9926
11311
|
const parts = new Set;
|
|
@@ -9930,7 +11315,7 @@ class FontOptimizer {
|
|
|
9930
11315
|
if (font.subsetText)
|
|
9931
11316
|
parts.add(font.subsetText);
|
|
9932
11317
|
for (const filePath of font.subsetFiles ?? []) {
|
|
9933
|
-
const abs =
|
|
11318
|
+
const abs = path29.isAbsolute(filePath) ? filePath : path29.join(this.#app.cwdPath, filePath);
|
|
9934
11319
|
const file = Bun.file(abs);
|
|
9935
11320
|
if (await file.exists())
|
|
9936
11321
|
parts.add(await file.text());
|
|
@@ -9949,7 +11334,7 @@ class FontOptimizer {
|
|
|
9949
11334
|
return "";
|
|
9950
11335
|
}
|
|
9951
11336
|
async#collectAutoSubsetText() {
|
|
9952
|
-
const roots = ["page", "ui"].map((dir) =>
|
|
11337
|
+
const roots = ["page", "ui"].map((dir) => path29.join(this.#app.cwdPath, dir));
|
|
9953
11338
|
const glob = new Bun.Glob("**/*.{ts,tsx,js,jsx,html,md}");
|
|
9954
11339
|
const parts = [];
|
|
9955
11340
|
await Promise.all(roots.map(async (root) => {
|
|
@@ -10063,7 +11448,7 @@ ${declarations.map(([prop, value]) => ` ${prop}: ${value};`).join(`
|
|
|
10063
11448
|
}
|
|
10064
11449
|
}
|
|
10065
11450
|
// pkgs/@akanjs/devkit/frontendBuild/hmrChangeClassifier.ts
|
|
10066
|
-
import
|
|
11451
|
+
import path30 from "path";
|
|
10067
11452
|
var SOURCE_EXTS5 = new Set([".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
10068
11453
|
var CSS_EXTS = new Set([".css"]);
|
|
10069
11454
|
var CONFIG_BASENAMES2 = new Set(["akan.config.ts", "bunfig.toml", "tsconfig.json", "package.json"]);
|
|
@@ -10072,10 +11457,10 @@ class HmrChangeClassifier {
|
|
|
10072
11457
|
classify(abs) {
|
|
10073
11458
|
if (this.#isUninteresting(abs))
|
|
10074
11459
|
return "ignore";
|
|
10075
|
-
const base =
|
|
11460
|
+
const base = path30.basename(abs);
|
|
10076
11461
|
if (CONFIG_BASENAMES2.has(base))
|
|
10077
11462
|
return "config";
|
|
10078
|
-
const ext =
|
|
11463
|
+
const ext = path30.extname(abs).toLowerCase();
|
|
10079
11464
|
if (CSS_EXTS.has(ext))
|
|
10080
11465
|
return "css";
|
|
10081
11466
|
if (SOURCE_EXTS5.has(ext))
|
|
@@ -10083,23 +11468,23 @@ class HmrChangeClassifier {
|
|
|
10083
11468
|
return "ignore";
|
|
10084
11469
|
}
|
|
10085
11470
|
#isUninteresting(abs) {
|
|
10086
|
-
const base =
|
|
11471
|
+
const base = path30.basename(abs);
|
|
10087
11472
|
if (!base)
|
|
10088
11473
|
return true;
|
|
10089
11474
|
if (base.startsWith("."))
|
|
10090
11475
|
return true;
|
|
10091
11476
|
if (base.endsWith("~") || base.endsWith(".swp") || base.endsWith(".swx") || base.endsWith(".tmp"))
|
|
10092
11477
|
return true;
|
|
10093
|
-
if (abs.includes(`${
|
|
11478
|
+
if (abs.includes(`${path30.sep}node_modules${path30.sep}`))
|
|
10094
11479
|
return true;
|
|
10095
|
-
if (abs.includes(`${
|
|
11480
|
+
if (abs.includes(`${path30.sep}.akan${path30.sep}`))
|
|
10096
11481
|
return true;
|
|
10097
11482
|
return false;
|
|
10098
11483
|
}
|
|
10099
11484
|
}
|
|
10100
11485
|
// pkgs/@akanjs/devkit/frontendBuild/hmrWatcher.ts
|
|
10101
11486
|
import fs4 from "fs";
|
|
10102
|
-
import
|
|
11487
|
+
import path31 from "path";
|
|
10103
11488
|
class HmrWatcher {
|
|
10104
11489
|
#roots;
|
|
10105
11490
|
#debounceMs;
|
|
@@ -10112,7 +11497,7 @@ class HmrWatcher {
|
|
|
10112
11497
|
#stopped = false;
|
|
10113
11498
|
#flushing = false;
|
|
10114
11499
|
constructor(opts) {
|
|
10115
|
-
this.#roots = [...new Set(opts.roots.map((r) =>
|
|
11500
|
+
this.#roots = [...new Set(opts.roots.map((r) => path31.resolve(r)))];
|
|
10116
11501
|
this.#debounceMs = opts.debounceMs ?? 80;
|
|
10117
11502
|
this.#onBatch = opts.onBatch;
|
|
10118
11503
|
this.#logger = opts.logger;
|
|
@@ -10123,7 +11508,7 @@ class HmrWatcher {
|
|
|
10123
11508
|
const w = fs4.watch(root, { recursive: true, persistent: false }, (_event, filename) => {
|
|
10124
11509
|
if (!filename)
|
|
10125
11510
|
return;
|
|
10126
|
-
const abs =
|
|
11511
|
+
const abs = path31.resolve(root, filename.toString());
|
|
10127
11512
|
this.#queue(abs);
|
|
10128
11513
|
});
|
|
10129
11514
|
this.#watchers.push(w);
|
|
@@ -10181,10 +11566,10 @@ class HmrWatcher {
|
|
|
10181
11566
|
}
|
|
10182
11567
|
}
|
|
10183
11568
|
// pkgs/@akanjs/devkit/frontendBuild/pagesBundleBuilder.ts
|
|
10184
|
-
import
|
|
11569
|
+
import path33 from "path";
|
|
10185
11570
|
|
|
10186
11571
|
// pkgs/@akanjs/devkit/transforms/externalizeFrameworkPlugin.ts
|
|
10187
|
-
import
|
|
11572
|
+
import path32 from "path";
|
|
10188
11573
|
var DEFAULT_INCLUDE = ["akanjs/", "@apps/", "@libs/"];
|
|
10189
11574
|
var DEFAULT_EXCLUDE_EXACT = new Set(["akanjs/webkit", "@akanjs/cli", "@akanjs/devkit"]);
|
|
10190
11575
|
var DEFAULT_EXCLUDE_PREFIX = ["@akanjs/cli/", "@akanjs/devkit/"];
|
|
@@ -10227,7 +11612,7 @@ async function createExternalizeFrameworkPlugin(options) {
|
|
|
10227
11612
|
const replPath = repl?.endsWith("/*") ? repl.slice(0, -1) : repl ?? "";
|
|
10228
11613
|
if (!replPath)
|
|
10229
11614
|
continue;
|
|
10230
|
-
const candidate =
|
|
11615
|
+
const candidate = path32.resolve(workspaceRoot, replPath + suffix);
|
|
10231
11616
|
const hit = await firstExisting(candidate);
|
|
10232
11617
|
if (hit)
|
|
10233
11618
|
return hit;
|
|
@@ -10239,8 +11624,8 @@ async function createExternalizeFrameworkPlugin(options) {
|
|
|
10239
11624
|
if (spec === pkg)
|
|
10240
11625
|
continue;
|
|
10241
11626
|
const suffix = spec.slice(pkg.length + 1);
|
|
10242
|
-
const pkgDir =
|
|
10243
|
-
const candidate =
|
|
11627
|
+
const pkgDir = path32.dirname(path32.resolve(workspaceRoot, entryFile));
|
|
11628
|
+
const candidate = path32.join(pkgDir, suffix);
|
|
10244
11629
|
const hit = await firstExisting(candidate);
|
|
10245
11630
|
if (hit)
|
|
10246
11631
|
return hit;
|
|
@@ -10290,7 +11675,7 @@ async function firstExisting(basePath2) {
|
|
|
10290
11675
|
return candidate;
|
|
10291
11676
|
}
|
|
10292
11677
|
for (const ext of CANDIDATE_EXTS3) {
|
|
10293
|
-
const candidate =
|
|
11678
|
+
const candidate = path32.join(basePath2, `index${ext}`);
|
|
10294
11679
|
if (await Bun.file(candidate).exists())
|
|
10295
11680
|
return candidate;
|
|
10296
11681
|
}
|
|
@@ -10381,11 +11766,11 @@ class PagesBundleBuilder {
|
|
|
10381
11766
|
const entryArtifact = result.outputs.find((a) => a.kind === "entry-point");
|
|
10382
11767
|
if (!entryArtifact)
|
|
10383
11768
|
throw new Error("[PagesBundleBuilder] Bun.build emitted no entry-point artifact");
|
|
10384
|
-
const bundlePath =
|
|
11769
|
+
const bundlePath = path33.resolve(entryArtifact.path);
|
|
10385
11770
|
const buildId = Date.now();
|
|
10386
11771
|
const outputBytes = result.outputs.reduce((sum, output) => sum + output.size, 0);
|
|
10387
11772
|
const chunkCount = result.outputs.filter((output) => output.kind === "chunk").length;
|
|
10388
|
-
this.#app.verbose(`[PagesBundleBuilder] ${
|
|
11773
|
+
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
11774
|
return {
|
|
10390
11775
|
bundlePath,
|
|
10391
11776
|
buildId,
|
|
@@ -10467,11 +11852,11 @@ function loaderFor4(absPath) {
|
|
|
10467
11852
|
}
|
|
10468
11853
|
// pkgs/@akanjs/devkit/frontendBuild/precompressArtifacts.ts
|
|
10469
11854
|
import fs5 from "fs";
|
|
10470
|
-
import
|
|
11855
|
+
import path34 from "path";
|
|
10471
11856
|
var COMPRESSIBLE_EXTS = new Set([".css", ".html", ".js", ".json", ".svg"]);
|
|
10472
11857
|
var MIN_COMPRESS_BYTES = 1024;
|
|
10473
11858
|
async function precompressArtifacts(app) {
|
|
10474
|
-
const roots = [
|
|
11859
|
+
const roots = [path34.join(app.dist.cwdPath, ".akan/artifact/client")];
|
|
10475
11860
|
const result = { files: 0, inputBytes: 0, outputBytes: 0 };
|
|
10476
11861
|
await Promise.all(roots.map((root) => precompressRoot(root, result)));
|
|
10477
11862
|
if (result.files > 0) {
|
|
@@ -10497,7 +11882,7 @@ async function precompressRoot(root, result) {
|
|
|
10497
11882
|
async function shouldPrecompress(filePath) {
|
|
10498
11883
|
if (filePath.endsWith(".gz"))
|
|
10499
11884
|
return false;
|
|
10500
|
-
if (!COMPRESSIBLE_EXTS.has(
|
|
11885
|
+
if (!COMPRESSIBLE_EXTS.has(path34.extname(filePath).toLowerCase()))
|
|
10501
11886
|
return false;
|
|
10502
11887
|
const file = Bun.file(filePath);
|
|
10503
11888
|
if (!await file.exists())
|
|
@@ -10515,7 +11900,7 @@ function formatBytes(bytes) {
|
|
|
10515
11900
|
return `${(bytes / 1024 / 1024).toFixed(1)}MB`;
|
|
10516
11901
|
}
|
|
10517
11902
|
// pkgs/@akanjs/devkit/frontendBuild/ssrBaseArtifactBuilder.ts
|
|
10518
|
-
import
|
|
11903
|
+
import path35 from "path";
|
|
10519
11904
|
import { optimize } from "@tailwindcss/node";
|
|
10520
11905
|
function prepareCssAsset(command, basePath2, cssText) {
|
|
10521
11906
|
return optimize(cssText, { file: `${basePath2 || "root"}.css`, minify: command === "build" }).code;
|
|
@@ -10531,7 +11916,7 @@ class SsrBaseArtifactBuilder {
|
|
|
10531
11916
|
this.#app = app;
|
|
10532
11917
|
this.#command = command;
|
|
10533
11918
|
this.#artifactDir = `${command === "build" ? app.dist.cwdPath : app.cwdPath}/.akan/artifact`;
|
|
10534
|
-
this.#absArtifactDir =
|
|
11919
|
+
this.#absArtifactDir = path35.resolve(this.#artifactDir);
|
|
10535
11920
|
}
|
|
10536
11921
|
async build() {
|
|
10537
11922
|
const akanConfig2 = await this.#app.getConfig();
|
|
@@ -10553,7 +11938,7 @@ class SsrBaseArtifactBuilder {
|
|
|
10553
11938
|
rscRuntimeSsrManifest,
|
|
10554
11939
|
vendorMap,
|
|
10555
11940
|
cssAssets,
|
|
10556
|
-
pagesBundlePath: this.#command === "build" ?
|
|
11941
|
+
pagesBundlePath: this.#command === "build" ? path35.relative(this.#absArtifactDir, pagesBundle.bundlePath) : pagesBundle.bundlePath,
|
|
10557
11942
|
pagesBundleBuildId: pagesBundle.buildId,
|
|
10558
11943
|
domains: [...akanConfig2.domains],
|
|
10559
11944
|
subRoutes: Object.fromEntries(Array.from(akanConfig2.subRoutes.entries()).map(([basePath2, domains]) => [basePath2, [...domains]])),
|
|
@@ -10562,7 +11947,7 @@ class SsrBaseArtifactBuilder {
|
|
|
10562
11947
|
i18n: akanConfig2.i18n,
|
|
10563
11948
|
imageConfig: akanConfig2.images
|
|
10564
11949
|
};
|
|
10565
|
-
await Bun.write(
|
|
11950
|
+
await Bun.write(path35.join(this.#absArtifactDir, "base-artifact.json"), `${JSON.stringify(artifact, null, 2)}
|
|
10566
11951
|
`);
|
|
10567
11952
|
this.#app.verbose(`[base-artifact] complete in ${Date.now() - this.#started}ms`);
|
|
10568
11953
|
return { artifact, seedIndex, cssCompiler, optimizedFonts };
|
|
@@ -10610,15 +11995,15 @@ class SsrBaseArtifactBuilder {
|
|
|
10610
11995
|
async#resolveAkanServerPath() {
|
|
10611
11996
|
const candidates = [];
|
|
10612
11997
|
try {
|
|
10613
|
-
candidates.push(
|
|
11998
|
+
candidates.push(path35.dirname(Bun.resolveSync("akanjs/server", this.#app.workspace.workspaceRoot)));
|
|
10614
11999
|
} catch {}
|
|
10615
|
-
candidates.push(
|
|
12000
|
+
candidates.push(path35.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server"), path35.join(this.#app.workspace.workspaceRoot, "node_modules/akanjs/server"));
|
|
10616
12001
|
try {
|
|
10617
|
-
candidates.push(
|
|
12002
|
+
candidates.push(path35.dirname(Bun.resolveSync("akanjs/server", path35.dirname(Bun.main))));
|
|
10618
12003
|
} catch {}
|
|
10619
|
-
candidates.push(
|
|
12004
|
+
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
12005
|
for (const candidate of candidates) {
|
|
10621
|
-
if (await Bun.file(
|
|
12006
|
+
if (await Bun.file(path35.join(candidate, "rscClient.tsx")).exists())
|
|
10622
12007
|
return candidate;
|
|
10623
12008
|
}
|
|
10624
12009
|
throw new Error(`[base-artifact] failed to locate akanjs/server; looked in: ${candidates.join(", ")}`);
|
|
@@ -10647,14 +12032,14 @@ ${preparedCssText}`).toString(36);
|
|
|
10647
12032
|
`styles/${cssAssetName}-${cssHash}.css`,
|
|
10648
12033
|
`/_akan/styles/${cssAssetName}-${cssHash}.css`
|
|
10649
12034
|
];
|
|
10650
|
-
await Bun.write(
|
|
12035
|
+
await Bun.write(path35.join(this.#absArtifactDir, cssRelPath), preparedCssText);
|
|
10651
12036
|
this.#app.verbose(`[base-artifact] wrote ${preparedCssText.length} bytes of CSS for ${basePath2} -> ${cssRelPath}`);
|
|
10652
12037
|
return [basePath2, { cssUrl, cssRelPath }];
|
|
10653
12038
|
}
|
|
10654
12039
|
}
|
|
10655
12040
|
// pkgs/@akanjs/devkit/frontendBuild/watchRootResolver.ts
|
|
10656
12041
|
import fs6 from "fs";
|
|
10657
|
-
import
|
|
12042
|
+
import path36 from "path";
|
|
10658
12043
|
|
|
10659
12044
|
class WatchRootResolver {
|
|
10660
12045
|
#app;
|
|
@@ -10664,15 +12049,15 @@ class WatchRootResolver {
|
|
|
10664
12049
|
async resolve() {
|
|
10665
12050
|
const tsconfig = await this.#app.getTsConfig();
|
|
10666
12051
|
const set = new Set;
|
|
10667
|
-
set.add(
|
|
12052
|
+
set.add(path36.resolve(`${this.#app.cwdPath}/page`));
|
|
10668
12053
|
for (const targets of Object.values(tsconfig.compilerOptions.paths ?? {})) {
|
|
10669
12054
|
for (const target of targets) {
|
|
10670
12055
|
if (!target)
|
|
10671
12056
|
continue;
|
|
10672
|
-
if (
|
|
12057
|
+
if (path36.isAbsolute(target))
|
|
10673
12058
|
continue;
|
|
10674
12059
|
const cleaned = target.replace(/\/?\*+.*$/, "").replace(/\/[^/]+\.[^/]+$/, "");
|
|
10675
|
-
const resolved =
|
|
12060
|
+
const resolved = path36.resolve(this.#app.workspace.workspaceRoot, cleaned);
|
|
10676
12061
|
if (fs6.existsSync(resolved))
|
|
10677
12062
|
set.add(resolved);
|
|
10678
12063
|
}
|
|
@@ -10739,7 +12124,7 @@ class ApplicationBuildRunner {
|
|
|
10739
12124
|
phases: this.#phases,
|
|
10740
12125
|
durationMs: Date.now() - this.#startedAt,
|
|
10741
12126
|
outputDir: this.#app.dist.cwdPath,
|
|
10742
|
-
artifactDir:
|
|
12127
|
+
artifactDir: path37.join(this.#app.dist.cwdPath, ".akan/artifact")
|
|
10743
12128
|
};
|
|
10744
12129
|
}
|
|
10745
12130
|
async typecheck(options = {}) {
|
|
@@ -10747,7 +12132,7 @@ class ApplicationBuildRunner {
|
|
|
10747
12132
|
await this.#app.getPageKeys({ refresh: true });
|
|
10748
12133
|
const { typecheckDir, tsconfigPath } = await this.#writeTypecheckTsconfig({ incremental });
|
|
10749
12134
|
if (clean)
|
|
10750
|
-
await rm3(
|
|
12135
|
+
await rm3(path37.join(typecheckDir, "tsconfig.tsbuildinfo"), { force: true });
|
|
10751
12136
|
await this.#checkProjectInChildProcess(tsconfigPath);
|
|
10752
12137
|
}
|
|
10753
12138
|
async#runPhase(id, label, task, summarize, options = {}) {
|
|
@@ -10819,7 +12204,7 @@ class ApplicationBuildRunner {
|
|
|
10819
12204
|
};
|
|
10820
12205
|
}
|
|
10821
12206
|
async#writeConsoleShim() {
|
|
10822
|
-
await Bun.write(
|
|
12207
|
+
await Bun.write(path37.join(this.#app.dist.cwdPath, "console.js"), `import { cnst, db, dict, option, server, sig, srv } from "./server.js";
|
|
10823
12208
|
import { assertAkanConsoleAllowed, startAkanConsole } from "./console-runtime.js";
|
|
10824
12209
|
|
|
10825
12210
|
const run = async () => {
|
|
@@ -10842,14 +12227,14 @@ void run().catch((error) => {
|
|
|
10842
12227
|
try {
|
|
10843
12228
|
return Bun.resolveSync("akanjs/server/rsc-worker", import.meta.dir);
|
|
10844
12229
|
} catch {
|
|
10845
|
-
return
|
|
12230
|
+
return path37.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/rscWorker.tsx");
|
|
10846
12231
|
}
|
|
10847
12232
|
}
|
|
10848
12233
|
#resolveConsoleRuntimeBuildEntry() {
|
|
10849
12234
|
try {
|
|
10850
|
-
return
|
|
12235
|
+
return path37.join(path37.dirname(Bun.resolveSync("akanjs/server", import.meta.dir)), "console.ts");
|
|
10851
12236
|
} catch {
|
|
10852
|
-
return
|
|
12237
|
+
return path37.join(this.#app.workspace.workspaceRoot, "pkgs/akanjs/server/console.ts");
|
|
10853
12238
|
}
|
|
10854
12239
|
}
|
|
10855
12240
|
async#buildCsr() {
|
|
@@ -10866,7 +12251,7 @@ void run().catch((error) => {
|
|
|
10866
12251
|
return { base, allRoutes };
|
|
10867
12252
|
}
|
|
10868
12253
|
async#writeTypecheckTsconfig({ incremental = true } = {}) {
|
|
10869
|
-
const typecheckDir =
|
|
12254
|
+
const typecheckDir = path37.join(this.#app.cwdPath, ".akan", "typecheck");
|
|
10870
12255
|
await mkdir8(typecheckDir, { recursive: true });
|
|
10871
12256
|
const tsconfig = {
|
|
10872
12257
|
extends: "../../tsconfig.json",
|
|
@@ -10885,7 +12270,7 @@ void run().catch((error) => {
|
|
|
10885
12270
|
],
|
|
10886
12271
|
references: []
|
|
10887
12272
|
};
|
|
10888
|
-
const tsconfigPath =
|
|
12273
|
+
const tsconfigPath = path37.join(typecheckDir, "tsconfig.json");
|
|
10889
12274
|
await Bun.write(tsconfigPath, `${JSON.stringify(tsconfig, null, 2)}
|
|
10890
12275
|
`);
|
|
10891
12276
|
return { typecheckDir, tsconfigPath };
|
|
@@ -10911,10 +12296,10 @@ void run().catch((error) => {
|
|
|
10911
12296
|
}
|
|
10912
12297
|
async#resolveTypecheckWorkerEntry() {
|
|
10913
12298
|
const candidates = [
|
|
10914
|
-
|
|
10915
|
-
|
|
10916
|
-
|
|
10917
|
-
|
|
12299
|
+
path37.join(this.#app.workspace.workspaceRoot, "pkgs/@akanjs/devkit/typecheck/typecheck.proc.ts"),
|
|
12300
|
+
path37.join(this.#app.workspace.workspaceRoot, "node_modules/@akanjs/devkit/typecheck/typecheck.proc.ts"),
|
|
12301
|
+
path37.join(import.meta.dir, "typecheck.proc.js"),
|
|
12302
|
+
path37.join(import.meta.dir, "typecheck.proc.ts")
|
|
10918
12303
|
];
|
|
10919
12304
|
for (const candidate of candidates)
|
|
10920
12305
|
if (await Bun.file(candidate).exists())
|
|
@@ -11090,13 +12475,13 @@ class ApplicationReleasePackager {
|
|
|
11090
12475
|
await cp(this.#app.dist.cwdPath, `${sourceRoot}/apps/${this.#app.name}`, { recursive: true });
|
|
11091
12476
|
const libDeps = ["social", "shared", "platform", "util"];
|
|
11092
12477
|
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}/${
|
|
12478
|
+
await Promise.all([".next", "ios", "android", "public/libs"].map(async (path38) => {
|
|
12479
|
+
const targetPath = `${sourceRoot}/apps/${this.#app.name}/${path38}`;
|
|
11095
12480
|
if (await FileSys.dirExists(targetPath))
|
|
11096
12481
|
await rm4(targetPath, { recursive: true, force: true });
|
|
11097
12482
|
}));
|
|
11098
12483
|
const syncPaths = [".husky", ".gitignore", "package.json"];
|
|
11099
|
-
await Promise.all(syncPaths.map((
|
|
12484
|
+
await Promise.all(syncPaths.map((path38) => cp(`${this.#app.workspace.cwdPath}/${path38}`, `${sourceRoot}/${path38}`, { recursive: true })));
|
|
11100
12485
|
await this.#writeSourceTsconfig(sourceRoot, libDeps);
|
|
11101
12486
|
await Bun.write(`${sourceRoot}/README.md`, readme);
|
|
11102
12487
|
await this.#app.workspace.spawn("tar", [
|
|
@@ -11187,20 +12572,20 @@ class ApplicationReleasePackager {
|
|
|
11187
12572
|
}
|
|
11188
12573
|
}
|
|
11189
12574
|
// pkgs/@akanjs/devkit/applicationTestPreload.ts
|
|
11190
|
-
import
|
|
12575
|
+
import path38 from "path";
|
|
11191
12576
|
var SIGNAL_TEST_PRELOAD_PATH = "test/signalTest.preload.ts";
|
|
11192
12577
|
async function resolveSignalTestPreloadPath(target) {
|
|
11193
12578
|
const candidates = [];
|
|
11194
12579
|
const addResolvedPackageCandidate = (basePath2) => {
|
|
11195
12580
|
try {
|
|
11196
|
-
candidates.push(
|
|
12581
|
+
candidates.push(path38.join(path38.dirname(Bun.resolveSync("akanjs/package.json", basePath2)), SIGNAL_TEST_PRELOAD_PATH));
|
|
11197
12582
|
} catch {}
|
|
11198
12583
|
};
|
|
11199
12584
|
addResolvedPackageCandidate(target.cwdPath);
|
|
11200
12585
|
addResolvedPackageCandidate(process.cwd());
|
|
11201
|
-
addResolvedPackageCandidate(
|
|
12586
|
+
addResolvedPackageCandidate(path38.dirname(Bun.main));
|
|
11202
12587
|
addResolvedPackageCandidate(import.meta.dir);
|
|
11203
|
-
candidates.push(
|
|
12588
|
+
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
12589
|
for (const candidate of [...new Set(candidates)]) {
|
|
11205
12590
|
if (await Bun.file(candidate).exists())
|
|
11206
12591
|
return candidate;
|
|
@@ -11210,7 +12595,7 @@ async function resolveSignalTestPreloadPath(target) {
|
|
|
11210
12595
|
// pkgs/@akanjs/devkit/builder.ts
|
|
11211
12596
|
import { existsSync as existsSync2 } from "fs";
|
|
11212
12597
|
import { mkdir as mkdir10 } from "fs/promises";
|
|
11213
|
-
import
|
|
12598
|
+
import path39 from "path";
|
|
11214
12599
|
var SKIP_ENTRY_DIR_SET = new Set(["node_modules", "dist", "build", ".git", ".next"]);
|
|
11215
12600
|
var assetExtensions = [".css", ".md", ".js", ".png", ".ico", ".svg", ".json", ".template"];
|
|
11216
12601
|
var assetLoader = Object.fromEntries(assetExtensions.map((ext) => [ext, "file"]));
|
|
@@ -11227,14 +12612,14 @@ class Builder {
|
|
|
11227
12612
|
#globEntrypoints(cwd, pattern) {
|
|
11228
12613
|
const glob = new Bun.Glob(pattern);
|
|
11229
12614
|
return Array.from(glob.scanSync({ cwd, onlyFiles: true })).filter((relativePath) => {
|
|
11230
|
-
const segments = relativePath.split(
|
|
12615
|
+
const segments = relativePath.split(path39.sep);
|
|
11231
12616
|
return !segments.some((segment) => SKIP_ENTRY_DIR_SET.has(segment));
|
|
11232
|
-
}).map((rel) =>
|
|
12617
|
+
}).map((rel) => path39.join(cwd, rel));
|
|
11233
12618
|
}
|
|
11234
12619
|
#globFiles(cwd, pattern = "**/*.*") {
|
|
11235
12620
|
const glob = new Bun.Glob(pattern);
|
|
11236
12621
|
return Array.from(glob.scanSync({ cwd, onlyFiles: true })).filter((relativePath) => {
|
|
11237
|
-
const segments = relativePath.split(
|
|
12622
|
+
const segments = relativePath.split(path39.sep);
|
|
11238
12623
|
return !segments.some((segment) => SKIP_ENTRY_DIR_SET.has(segment));
|
|
11239
12624
|
});
|
|
11240
12625
|
}
|
|
@@ -11242,17 +12627,17 @@ class Builder {
|
|
|
11242
12627
|
const out = [];
|
|
11243
12628
|
for (const p of additionalEntryPoints) {
|
|
11244
12629
|
if (p.includes("*")) {
|
|
11245
|
-
const rel = p.startsWith(`${cwd}/`) || p.startsWith(`${cwd}${
|
|
12630
|
+
const rel = p.startsWith(`${cwd}/`) || p.startsWith(`${cwd}${path39.sep}`) ? p.slice(cwd.length + 1) : p;
|
|
11246
12631
|
out.push(...this.#globEntrypoints(cwd, rel));
|
|
11247
12632
|
} else
|
|
11248
|
-
out.push(
|
|
12633
|
+
out.push(path39.isAbsolute(p) ? p : path39.join(cwd, p));
|
|
11249
12634
|
}
|
|
11250
12635
|
return out;
|
|
11251
12636
|
}
|
|
11252
12637
|
#getBuildOptions({ bundle = false, additionalEntryPoints = [] } = {}) {
|
|
11253
12638
|
const cwd = this.#executor.cwdPath;
|
|
11254
12639
|
const entrypoints = [
|
|
11255
|
-
...bundle ? [
|
|
12640
|
+
...bundle ? [path39.join(cwd, "index.ts")] : this.#globEntrypoints(cwd, "**/*.{ts,tsx}"),
|
|
11256
12641
|
...this.#resolveAdditionalEntrypoints(cwd, additionalEntryPoints)
|
|
11257
12642
|
];
|
|
11258
12643
|
return {
|
|
@@ -11273,9 +12658,9 @@ class Builder {
|
|
|
11273
12658
|
for (const relativePath of this.#globFiles(cwd)) {
|
|
11274
12659
|
if (relativePath === "package.json")
|
|
11275
12660
|
continue;
|
|
11276
|
-
const sourcePath =
|
|
11277
|
-
const targetPath =
|
|
11278
|
-
await mkdir10(
|
|
12661
|
+
const sourcePath = path39.join(cwd, relativePath);
|
|
12662
|
+
const targetPath = path39.join(this.#distExecutor.cwdPath, relativePath);
|
|
12663
|
+
await mkdir10(path39.dirname(targetPath), { recursive: true });
|
|
11279
12664
|
await Bun.write(targetPath, Bun.file(sourcePath));
|
|
11280
12665
|
}
|
|
11281
12666
|
}
|
|
@@ -11286,13 +12671,13 @@ class Builder {
|
|
|
11286
12671
|
return withoutFormatDir;
|
|
11287
12672
|
if (!hasDotSlash && withoutFormatDir === publishedPath)
|
|
11288
12673
|
return publishedPath;
|
|
11289
|
-
const parsed =
|
|
12674
|
+
const parsed = path39.posix.parse(withoutFormatDir);
|
|
11290
12675
|
if (![".js", ".mjs", ".cjs"].includes(parsed.ext))
|
|
11291
12676
|
return withoutFormatDir;
|
|
11292
|
-
const withoutExt =
|
|
12677
|
+
const withoutExt = path39.posix.join(parsed.dir, parsed.name);
|
|
11293
12678
|
const sourcePath = withoutExt.startsWith("./") ? withoutExt.slice(2) : withoutExt;
|
|
11294
12679
|
const sourceCandidates = [`${sourcePath}.ts`, `${sourcePath}.tsx`];
|
|
11295
|
-
const matchedSource = sourceCandidates.find((candidate) => existsSync2(
|
|
12680
|
+
const matchedSource = sourceCandidates.find((candidate) => existsSync2(path39.join(this.#executor.cwdPath, candidate)));
|
|
11296
12681
|
if (!matchedSource)
|
|
11297
12682
|
return withoutFormatDir;
|
|
11298
12683
|
return hasDotSlash ? `./${matchedSource}` : matchedSource;
|
|
@@ -11343,10 +12728,10 @@ class Builder {
|
|
|
11343
12728
|
// pkgs/@akanjs/devkit/capacitorApp.ts
|
|
11344
12729
|
import { cp as cp2, mkdir as mkdir11, rm as rm5 } from "fs/promises";
|
|
11345
12730
|
import os from "os";
|
|
11346
|
-
import
|
|
12731
|
+
import path40 from "path";
|
|
11347
12732
|
import { select as select2 } from "@inquirer/prompts";
|
|
11348
12733
|
import { MobileProject } from "@trapezedev/project";
|
|
11349
|
-
import { capitalize as
|
|
12734
|
+
import { capitalize as capitalize5 } from "akanjs/common";
|
|
11350
12735
|
|
|
11351
12736
|
// pkgs/@akanjs/devkit/fileEditor.ts
|
|
11352
12737
|
class FileEditor {
|
|
@@ -11550,13 +12935,13 @@ var rootCapacitorConfigFilenames = [
|
|
|
11550
12935
|
"capacitor.config.js",
|
|
11551
12936
|
"capacitor.config.json"
|
|
11552
12937
|
];
|
|
11553
|
-
var rootCapacitorConfigPaths = (appRoot) => rootCapacitorConfigFilenames.map((file) =>
|
|
12938
|
+
var rootCapacitorConfigPaths = (appRoot) => rootCapacitorConfigFilenames.map((file) => path40.join(appRoot, file));
|
|
11554
12939
|
async function clearRootCapacitorConfigs(appRoot) {
|
|
11555
12940
|
await Promise.all(rootCapacitorConfigPaths(appRoot).map((file) => rm5(file, { force: true })));
|
|
11556
12941
|
}
|
|
11557
12942
|
async function writeRootCapacitorConfig(appRoot, content) {
|
|
11558
12943
|
await clearRootCapacitorConfigs(appRoot);
|
|
11559
|
-
await Bun.write(
|
|
12944
|
+
await Bun.write(path40.join(appRoot, "capacitor.config.json"), content);
|
|
11560
12945
|
}
|
|
11561
12946
|
var getLocalIP = () => {
|
|
11562
12947
|
const interfaces = os.networkInterfaces();
|
|
@@ -11570,7 +12955,7 @@ var getLocalIP = () => {
|
|
|
11570
12955
|
}
|
|
11571
12956
|
return "127.0.0.1";
|
|
11572
12957
|
};
|
|
11573
|
-
var
|
|
12958
|
+
var isRecord2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
11574
12959
|
var asString = (value) => typeof value === "string" ? value : undefined;
|
|
11575
12960
|
var firstString = (...values) => values.find((value) => typeof value === "string");
|
|
11576
12961
|
var scoreIosDeviceTarget = (target) => {
|
|
@@ -11594,7 +12979,7 @@ function walkRecords(value, visit) {
|
|
|
11594
12979
|
walkRecords(item, visit);
|
|
11595
12980
|
return;
|
|
11596
12981
|
}
|
|
11597
|
-
if (!
|
|
12982
|
+
if (!isRecord2(value))
|
|
11598
12983
|
return;
|
|
11599
12984
|
visit(value);
|
|
11600
12985
|
for (const item of Object.values(value))
|
|
@@ -11605,9 +12990,9 @@ function parseDevicectlDevices(output) {
|
|
|
11605
12990
|
const json = JSON.parse(output);
|
|
11606
12991
|
const targets = new Map;
|
|
11607
12992
|
walkRecords(json, (record) => {
|
|
11608
|
-
const deviceProperties =
|
|
11609
|
-
const hardwareProperties =
|
|
11610
|
-
const connectionProperties =
|
|
12993
|
+
const deviceProperties = isRecord2(record.deviceProperties) ? record.deviceProperties : {};
|
|
12994
|
+
const hardwareProperties = isRecord2(record.hardwareProperties) ? record.hardwareProperties : {};
|
|
12995
|
+
const connectionProperties = isRecord2(record.connectionProperties) ? record.connectionProperties : {};
|
|
11611
12996
|
const devicectlId = firstString(record.identifier, record.deviceIdentifier);
|
|
11612
12997
|
const potentialHostnames = Array.isArray(connectionProperties.potentialHostnames) ? connectionProperties.potentialHostnames.filter((value) => typeof value === "string") : [];
|
|
11613
12998
|
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 +13025,7 @@ function parseSimctlDevices(output) {
|
|
|
11640
13025
|
try {
|
|
11641
13026
|
const json = JSON.parse(output);
|
|
11642
13027
|
const devices = json.devices ?? {};
|
|
11643
|
-
return Object.values(devices).flatMap((runtimeDevices) => runtimeDevices).filter(
|
|
13028
|
+
return Object.values(devices).flatMap((runtimeDevices) => runtimeDevices).filter(isRecord2).flatMap((device) => {
|
|
11644
13029
|
const id = firstString(device.udid, device.UDID, device.identifier);
|
|
11645
13030
|
const name = firstString(device.name, device.displayName);
|
|
11646
13031
|
const isAvailable = device.isAvailable !== false && device.availabilityError === undefined;
|
|
@@ -11665,13 +13050,13 @@ function buildIosNativeRunCommand({
|
|
|
11665
13050
|
scheme = "App",
|
|
11666
13051
|
configuration = "Debug"
|
|
11667
13052
|
}) {
|
|
11668
|
-
const derivedDataPath =
|
|
13053
|
+
const derivedDataPath = path40.join(appRoot, "ios/DerivedData", device.id);
|
|
11669
13054
|
const productPlatform = device.kind === "device" ? "iphoneos" : "iphonesimulator";
|
|
11670
13055
|
const destination = device.kind === "device" ? `id=${device.xcodebuildId ?? device.id}` : `platform=iOS Simulator,id=${device.id}`;
|
|
11671
13056
|
return {
|
|
11672
13057
|
configuration,
|
|
11673
13058
|
derivedDataPath,
|
|
11674
|
-
appPath:
|
|
13059
|
+
appPath: path40.join(derivedDataPath, "Build/Products", `${configuration}-${productPlatform}`, "App.app"),
|
|
11675
13060
|
xcodebuildArgs: [
|
|
11676
13061
|
"-project",
|
|
11677
13062
|
"App.xcodeproj",
|
|
@@ -11872,16 +13257,16 @@ function materializeCapacitorConfig(target, { operation, localServerUrl, localIp
|
|
|
11872
13257
|
experimental,
|
|
11873
13258
|
...capacitorConfig
|
|
11874
13259
|
} = target;
|
|
11875
|
-
const serverConfig =
|
|
11876
|
-
const cordovaConfig =
|
|
11877
|
-
const experimentalConfig =
|
|
11878
|
-
const pluginsConfig =
|
|
11879
|
-
const keyboardPluginConfig =
|
|
13260
|
+
const serverConfig = isRecord2(server) ? server : undefined;
|
|
13261
|
+
const cordovaConfig = isRecord2(cordova) ? cordova : undefined;
|
|
13262
|
+
const experimentalConfig = isRecord2(experimental) ? experimental : undefined;
|
|
13263
|
+
const pluginsConfig = isRecord2(plugins) ? plugins : {};
|
|
13264
|
+
const keyboardPluginConfig = isRecord2(pluginsConfig.Keyboard) ? pluginsConfig.Keyboard : {};
|
|
11880
13265
|
const config = {
|
|
11881
13266
|
...capacitorConfig,
|
|
11882
13267
|
appId,
|
|
11883
13268
|
appName,
|
|
11884
|
-
webDir:
|
|
13269
|
+
webDir: path40.posix.join(".akan", "mobile", name, "www"),
|
|
11885
13270
|
plugins: {
|
|
11886
13271
|
CapacitorCookies: { enabled: true },
|
|
11887
13272
|
...pluginsConfig,
|
|
@@ -11891,11 +13276,11 @@ function materializeCapacitorConfig(target, { operation, localServerUrl, localIp
|
|
|
11891
13276
|
}
|
|
11892
13277
|
},
|
|
11893
13278
|
android: {
|
|
11894
|
-
...
|
|
13279
|
+
...isRecord2(android) ? android : {},
|
|
11895
13280
|
path: "android"
|
|
11896
13281
|
},
|
|
11897
13282
|
ios: {
|
|
11898
|
-
...
|
|
13283
|
+
...isRecord2(ios) ? ios : {},
|
|
11899
13284
|
path: "ios"
|
|
11900
13285
|
}
|
|
11901
13286
|
};
|
|
@@ -11938,10 +13323,10 @@ class CapacitorApp {
|
|
|
11938
13323
|
constructor(app, target) {
|
|
11939
13324
|
this.app = app;
|
|
11940
13325
|
this.target = target;
|
|
11941
|
-
this.targetRootPath =
|
|
11942
|
-
this.targetRoot =
|
|
11943
|
-
this.targetWebRoot =
|
|
11944
|
-
this.targetAssetRoot =
|
|
13326
|
+
this.targetRootPath = path40.posix.join(".akan", "mobile", this.target.name);
|
|
13327
|
+
this.targetRoot = path40.join(this.app.cwdPath, this.targetRootPath);
|
|
13328
|
+
this.targetWebRoot = path40.join(this.targetRoot, "www");
|
|
13329
|
+
this.targetAssetRoot = path40.join(this.targetRoot, "assets");
|
|
11945
13330
|
this.project = new MobileProject(this.app.cwdPath, {
|
|
11946
13331
|
android: { path: this.androidRootPath },
|
|
11947
13332
|
ios: { path: this.iosProjectPath }
|
|
@@ -11956,9 +13341,9 @@ class CapacitorApp {
|
|
|
11956
13341
|
await mkdir11(this.targetRoot, { recursive: true });
|
|
11957
13342
|
if (regenerate) {
|
|
11958
13343
|
if (!platform || platform === "ios")
|
|
11959
|
-
await rm5(
|
|
13344
|
+
await rm5(path40.join(this.app.cwdPath, this.iosRootPath), { recursive: true, force: true });
|
|
11960
13345
|
if (!platform || platform === "android")
|
|
11961
|
-
await rm5(
|
|
13346
|
+
await rm5(path40.join(this.app.cwdPath, this.androidRootPath), { recursive: true, force: true });
|
|
11962
13347
|
}
|
|
11963
13348
|
const project = this.project;
|
|
11964
13349
|
await this.project.load();
|
|
@@ -12081,7 +13466,7 @@ ${textError instanceof Error ? textError.message : ""}`);
|
|
|
12081
13466
|
const xcodebuildArgs = noAllowProvisioningUpdates ? command.xcodebuildArgs : [...command.xcodebuildArgs.slice(0, -1), "-allowProvisioningUpdates", ...command.xcodebuildArgs.slice(-1)];
|
|
12082
13467
|
try {
|
|
12083
13468
|
await this.#spawn("xcodebuild", xcodebuildArgs, {
|
|
12084
|
-
cwd:
|
|
13469
|
+
cwd: path40.join(this.app.cwdPath, this.iosProjectPath),
|
|
12085
13470
|
env: mobileEnv
|
|
12086
13471
|
});
|
|
12087
13472
|
const devicectlId = runTarget.devicectlId ?? runTarget.id;
|
|
@@ -12103,10 +13488,10 @@ ${textError instanceof Error ? textError.message : ""}`);
|
|
|
12103
13488
|
}
|
|
12104
13489
|
}
|
|
12105
13490
|
#iosScheme() {
|
|
12106
|
-
return
|
|
13491
|
+
return isRecord2(this.target.ios) && typeof this.target.ios.scheme === "string" ? this.target.ios.scheme : "App";
|
|
12107
13492
|
}
|
|
12108
13493
|
async#getIosDevelopmentTeam() {
|
|
12109
|
-
const pbxprojPath =
|
|
13494
|
+
const pbxprojPath = path40.join(this.app.cwdPath, this.iosProjectPath, "App.xcodeproj/project.pbxproj");
|
|
12110
13495
|
if (!await Bun.file(pbxprojPath).exists())
|
|
12111
13496
|
return;
|
|
12112
13497
|
return (await Bun.file(pbxprojPath).text()).match(/DEVELOPMENT_TEAM = ([^;]+);/)?.[1]?.trim();
|
|
@@ -12132,7 +13517,7 @@ ${error.message}`;
|
|
|
12132
13517
|
await this.#spawnMobile("npx", ["cap", "sync", "android"], { operation, env });
|
|
12133
13518
|
}
|
|
12134
13519
|
async#updateAndroidBuildTypes() {
|
|
12135
|
-
const appGradle = await FileEditor.create(
|
|
13520
|
+
const appGradle = await FileEditor.create(path40.join(this.app.cwdPath, this.androidRootPath, "app/build.gradle"));
|
|
12136
13521
|
const buildTypesBlock = `
|
|
12137
13522
|
debug {
|
|
12138
13523
|
applicationIdSuffix ".debug"
|
|
@@ -12176,7 +13561,7 @@ ${error.message}`;
|
|
|
12176
13561
|
const gradleCommand = isWindows ? "gradlew.bat" : "./gradlew";
|
|
12177
13562
|
await this.app.spawn(gradleCommand, [assembleType === "apk" ? "assembleRelease" : "bundleRelease"], {
|
|
12178
13563
|
stdio: "inherit",
|
|
12179
|
-
cwd:
|
|
13564
|
+
cwd: path40.join(this.app.cwdPath, this.androidRootPath),
|
|
12180
13565
|
env: await this.#commandEnv("release", env)
|
|
12181
13566
|
});
|
|
12182
13567
|
}
|
|
@@ -12184,10 +13569,10 @@ ${error.message}`;
|
|
|
12184
13569
|
await this.#spawnMobile("npx", ["cap", "open", "android"], { operation: "local", env: "local" });
|
|
12185
13570
|
}
|
|
12186
13571
|
async#ensureAndroidAssetsDir() {
|
|
12187
|
-
await mkdir11(
|
|
13572
|
+
await mkdir11(path40.join(this.app.cwdPath, this.androidAssetsPath), { recursive: true });
|
|
12188
13573
|
}
|
|
12189
13574
|
async#ensureAndroidDebugKeystore() {
|
|
12190
|
-
const keystorePath =
|
|
13575
|
+
const keystorePath = path40.join(this.app.cwdPath, this.androidRootPath, "app/debug.keystore");
|
|
12191
13576
|
if (await Bun.file(keystorePath).exists())
|
|
12192
13577
|
return;
|
|
12193
13578
|
await this.#spawn("keytool", [
|
|
@@ -12226,7 +13611,7 @@ ${error.message}`;
|
|
|
12226
13611
|
await this.#spawnMobile("npx", args, { operation, env }, { stdio: "inherit" });
|
|
12227
13612
|
}
|
|
12228
13613
|
async#assertAndroidReleaseSigningConfig() {
|
|
12229
|
-
const gradlePropertiesPath =
|
|
13614
|
+
const gradlePropertiesPath = path40.join(this.app.cwdPath, this.androidRootPath, "gradle.properties");
|
|
12230
13615
|
const gradleProperties = await Bun.file(gradlePropertiesPath).exists() ? await Bun.file(gradlePropertiesPath).text() : "";
|
|
12231
13616
|
const missingKeys = getMissingAndroidReleaseSigningKeys({ gradleProperties });
|
|
12232
13617
|
if (missingKeys.length > 0)
|
|
@@ -12253,12 +13638,12 @@ ${error.message}`;
|
|
|
12253
13638
|
await this.#prepareAndroid({ operation: "release", env: "main" });
|
|
12254
13639
|
}
|
|
12255
13640
|
async prepareWww() {
|
|
12256
|
-
const htmlSource =
|
|
13641
|
+
const htmlSource = path40.join(this.app.dist.cwdPath, "csr", targetHtmlFilename(this.target));
|
|
12257
13642
|
if (!await Bun.file(htmlSource).exists())
|
|
12258
13643
|
throw new Error(`CSR html for mobile target '${this.target.name}' not found: ${htmlSource}`);
|
|
12259
13644
|
await rm5(this.targetWebRoot, { recursive: true, force: true });
|
|
12260
13645
|
await mkdir11(this.targetWebRoot, { recursive: true });
|
|
12261
|
-
await Bun.write(
|
|
13646
|
+
await Bun.write(path40.join(this.targetWebRoot, "index.html"), this.#injectMobileTargetMeta(await Bun.file(htmlSource).text()));
|
|
12262
13647
|
}
|
|
12263
13648
|
#injectMobileTargetMeta(html) {
|
|
12264
13649
|
const basePath2 = this.target.basePath?.replace(/^\/+|\/+$/g, "") ?? "";
|
|
@@ -12278,7 +13663,7 @@ ${error.message}`;
|
|
|
12278
13663
|
});
|
|
12279
13664
|
const content = `${JSON.stringify(config, null, 2)}
|
|
12280
13665
|
`;
|
|
12281
|
-
await Bun.write(
|
|
13666
|
+
await Bun.write(path40.join(this.targetRoot, "capacitor.config.json"), content);
|
|
12282
13667
|
return content;
|
|
12283
13668
|
}
|
|
12284
13669
|
async#prepareTargetAssets() {
|
|
@@ -12286,11 +13671,11 @@ ${error.message}`;
|
|
|
12286
13671
|
return;
|
|
12287
13672
|
await mkdir11(this.targetAssetRoot, { recursive: true });
|
|
12288
13673
|
if (this.target.assets.icon)
|
|
12289
|
-
await cp2(
|
|
13674
|
+
await cp2(path40.join(this.app.cwdPath, this.target.assets.icon), path40.join(this.targetAssetRoot, "icon.png"), {
|
|
12290
13675
|
force: true
|
|
12291
13676
|
});
|
|
12292
13677
|
if (this.target.assets.splash)
|
|
12293
|
-
await cp2(
|
|
13678
|
+
await cp2(path40.join(this.app.cwdPath, this.target.assets.splash), path40.join(this.targetAssetRoot, "splash.png"), {
|
|
12294
13679
|
force: true
|
|
12295
13680
|
});
|
|
12296
13681
|
}
|
|
@@ -12298,11 +13683,11 @@ ${error.message}`;
|
|
|
12298
13683
|
const files = this.target.files?.[platform];
|
|
12299
13684
|
if (!files)
|
|
12300
13685
|
return;
|
|
12301
|
-
const platformRoot =
|
|
13686
|
+
const platformRoot = path40.join(this.app.cwdPath, platform === "ios" ? this.iosRootPath : this.androidRootPath);
|
|
12302
13687
|
await Promise.all(Object.entries(files).map(async ([to, from]) => {
|
|
12303
|
-
const targetPath =
|
|
12304
|
-
await mkdir11(
|
|
12305
|
-
await cp2(
|
|
13688
|
+
const targetPath = path40.join(platformRoot, to);
|
|
13689
|
+
await mkdir11(path40.dirname(targetPath), { recursive: true });
|
|
13690
|
+
await cp2(path40.join(this.app.cwdPath, from), targetPath, { force: true });
|
|
12306
13691
|
}));
|
|
12307
13692
|
}
|
|
12308
13693
|
async#generateAssets({ operation, env }) {
|
|
@@ -12312,7 +13697,7 @@ ${error.message}`;
|
|
|
12312
13697
|
"@capacitor/assets",
|
|
12313
13698
|
"generate",
|
|
12314
13699
|
"--assetPath",
|
|
12315
|
-
|
|
13700
|
+
path40.posix.join(this.targetRootPath, "assets"),
|
|
12316
13701
|
"--iosProject",
|
|
12317
13702
|
this.iosProjectPath,
|
|
12318
13703
|
"--androidProject",
|
|
@@ -12437,7 +13822,7 @@ ${error.message}`;
|
|
|
12437
13822
|
this.#setPermissionsInAndroid(["POST_NOTIFICATIONS"]);
|
|
12438
13823
|
}
|
|
12439
13824
|
async#setPermissionInIos(permissions) {
|
|
12440
|
-
const updateNs = Object.fromEntries(Object.entries(permissions).map(([key, value]) => [`NS${
|
|
13825
|
+
const updateNs = Object.fromEntries(Object.entries(permissions).map(([key, value]) => [`NS${capitalize5(key)}`, value]));
|
|
12441
13826
|
await Promise.all([
|
|
12442
13827
|
this.project.ios.updateInfoPlist(this.iosTargetName, "Debug", updateNs),
|
|
12443
13828
|
this.project.ios.updateInfoPlist(this.iosTargetName, "Release", updateNs)
|
|
@@ -12522,15 +13907,15 @@ var Pkg = createInternalArgToken("Pkg");
|
|
|
12522
13907
|
var Module = createInternalArgToken("Module");
|
|
12523
13908
|
var Workspace = createInternalArgToken("Workspace");
|
|
12524
13909
|
// pkgs/@akanjs/devkit/commandDecorators/command.ts
|
|
12525
|
-
import
|
|
13910
|
+
import path41 from "path";
|
|
12526
13911
|
import { confirm, input as input2, select as select3 } from "@inquirer/prompts";
|
|
12527
13912
|
import { Logger as Logger10 } from "akanjs/common";
|
|
12528
13913
|
import chalk6 from "chalk";
|
|
12529
13914
|
import { program } from "commander";
|
|
12530
13915
|
|
|
12531
13916
|
// pkgs/@akanjs/devkit/commandDecorators/dependencyBuilder.ts
|
|
12532
|
-
var
|
|
12533
|
-
var createDependencyKey = (refName, kind) => `${refName}${
|
|
13917
|
+
var capitalize6 = (value) => value.slice(0, 1).toUpperCase() + value.slice(1);
|
|
13918
|
+
var createDependencyKey = (refName, kind) => `${refName}${capitalize6(kind)}`;
|
|
12534
13919
|
|
|
12535
13920
|
class CommandContainer {
|
|
12536
13921
|
static #instances = new Map;
|
|
@@ -13026,7 +14411,7 @@ var runCommands = async (...commands) => {
|
|
|
13026
14411
|
process.exit(1);
|
|
13027
14412
|
});
|
|
13028
14413
|
const __dirname2 = getDirname(import.meta.url);
|
|
13029
|
-
const packageJsonCandidates = [`${
|
|
14414
|
+
const packageJsonCandidates = [`${path41.dirname(Bun.main)}/package.json`, `${__dirname2}/../package.json`];
|
|
13030
14415
|
let cliPackageJson = null;
|
|
13031
14416
|
for (const packageJsonPath of packageJsonCandidates) {
|
|
13032
14417
|
if (!await FileSys.fileExists(packageJsonPath))
|
|
@@ -13269,11 +14654,11 @@ var NODE_NATIVE_MODULE_SET = new Set([
|
|
|
13269
14654
|
// pkgs/@akanjs/devkit/getCredentials.ts
|
|
13270
14655
|
import yaml from "js-yaml";
|
|
13271
14656
|
// pkgs/@akanjs/devkit/getModelFileData.ts
|
|
13272
|
-
import { capitalize as
|
|
14657
|
+
import { capitalize as capitalize7 } from "akanjs/common";
|
|
13273
14658
|
// pkgs/@akanjs/devkit/getRelatedCnsts.ts
|
|
13274
14659
|
import { readFileSync as readFileSync4, realpathSync } from "fs";
|
|
13275
14660
|
import ora2 from "ora";
|
|
13276
|
-
import * as
|
|
14661
|
+
import * as ts10 from "typescript";
|
|
13277
14662
|
var tsTranspiler = new Bun.Transpiler({ loader: "ts" });
|
|
13278
14663
|
var tsxTranspiler = new Bun.Transpiler({ loader: "tsx" });
|
|
13279
14664
|
var getTranspiler = (filePath) => filePath.endsWith(".tsx") ? tsxTranspiler : tsTranspiler;
|
|
@@ -13306,10 +14691,10 @@ var scanModuleSpecifiers = (source2, filePath, includeExports) => {
|
|
|
13306
14691
|
return importSpecifiers;
|
|
13307
14692
|
};
|
|
13308
14693
|
var parseTsConfig = (tsConfigPath = "./tsconfig.json") => {
|
|
13309
|
-
const configFile =
|
|
13310
|
-
return
|
|
14694
|
+
const configFile = ts10.readConfigFile(tsConfigPath, (path42) => {
|
|
14695
|
+
return ts10.sys.readFile(path42);
|
|
13311
14696
|
});
|
|
13312
|
-
return
|
|
14697
|
+
return ts10.parseJsonConfigFileContent(configFile.config, ts10.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
|
|
13313
14698
|
};
|
|
13314
14699
|
var collectImportedFiles = (constantFilePath, parsedConfig) => {
|
|
13315
14700
|
const allFilesToAnalyze = new Set([constantFilePath]);
|
|
@@ -13324,7 +14709,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
|
|
|
13324
14709
|
for (const importPath of scanModuleSpecifiers(source2, filePath, false)) {
|
|
13325
14710
|
if (!importPath.startsWith("."))
|
|
13326
14711
|
continue;
|
|
13327
|
-
const resolved =
|
|
14712
|
+
const resolved = ts10.resolveModuleName(importPath, filePath, parsedConfig.options, ts10.sys).resolvedModule?.resolvedFileName;
|
|
13328
14713
|
if (resolved && !allFilesToAnalyze.has(resolved)) {
|
|
13329
14714
|
allFilesToAnalyze.add(resolved);
|
|
13330
14715
|
collectImported(resolved);
|
|
@@ -13341,7 +14726,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
|
|
|
13341
14726
|
var createTsProgram = (filePaths, options) => {
|
|
13342
14727
|
const spinner = ora2("Creating TypeScript program for all files...");
|
|
13343
14728
|
spinner.start();
|
|
13344
|
-
const program2 =
|
|
14729
|
+
const program2 = ts10.createProgram(Array.from(filePaths), options);
|
|
13345
14730
|
const checker = program2.getTypeChecker();
|
|
13346
14731
|
spinner.succeed("TypeScript program created.");
|
|
13347
14732
|
return {
|
|
@@ -13381,17 +14766,17 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
|
|
|
13381
14766
|
function visit(node) {
|
|
13382
14767
|
if (!source2)
|
|
13383
14768
|
return;
|
|
13384
|
-
if (
|
|
14769
|
+
if (ts10.isPropertyAccessExpression(node)) {
|
|
13385
14770
|
const left = node.expression;
|
|
13386
14771
|
const right = node.name;
|
|
13387
|
-
const { line } =
|
|
13388
|
-
if (
|
|
14772
|
+
const { line } = ts10.getLineAndCharacterOfPosition(source2, node.getStart());
|
|
14773
|
+
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
14774
|
const symbol = getCachedSymbol(right);
|
|
13390
14775
|
if (symbol?.declarations && symbol.declarations.length > 0) {
|
|
13391
14776
|
const key = symbol.declarations[0]?.getSourceFile().fileName.split("/").pop()?.split(".")[0] ?? "";
|
|
13392
14777
|
const property = propertyMap.get(key);
|
|
13393
14778
|
const isScalar = symbol.declarations[0]?.getSourceFile().fileName.includes("_") ?? false;
|
|
13394
|
-
const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${
|
|
14779
|
+
const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${ts10.sys.getCurrentDirectory()}/`, "");
|
|
13395
14780
|
if (!symbolFilePath)
|
|
13396
14781
|
throw new Error(`No symbol file path found for ${left.text}.${right.text}`);
|
|
13397
14782
|
if (property) {
|
|
@@ -13415,10 +14800,10 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
|
|
|
13415
14800
|
}
|
|
13416
14801
|
}
|
|
13417
14802
|
}
|
|
13418
|
-
} else if (
|
|
14803
|
+
} else if (ts10.isImportDeclaration(node) && ts10.isStringLiteral(node.moduleSpecifier)) {
|
|
13419
14804
|
const importPath = node.moduleSpecifier.text;
|
|
13420
14805
|
if (importPath.startsWith(".")) {
|
|
13421
|
-
const resolved =
|
|
14806
|
+
const resolved = ts10.resolveModuleName(importPath, filePath, program2.getCompilerOptions(), ts10.sys).resolvedModule?.resolvedFileName;
|
|
13422
14807
|
const moduleName = importPath.split("/").pop()?.split(".")[0] ?? "";
|
|
13423
14808
|
const property = propertyMap.get(moduleName);
|
|
13424
14809
|
const isScalar = importPath.includes("_");
|
|
@@ -13433,7 +14818,7 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
|
|
|
13433
14818
|
}
|
|
13434
14819
|
}
|
|
13435
14820
|
}
|
|
13436
|
-
|
|
14821
|
+
ts10.forEachChild(node, visit);
|
|
13437
14822
|
}
|
|
13438
14823
|
visit(source2);
|
|
13439
14824
|
}
|
|
@@ -13640,10 +15025,10 @@ class IncrementalBuilder {
|
|
|
13640
15025
|
}
|
|
13641
15026
|
}
|
|
13642
15027
|
batchTouchesPagesTree(appDir, batch) {
|
|
13643
|
-
const absAppDir =
|
|
15028
|
+
const absAppDir = path42.resolve(appDir);
|
|
13644
15029
|
for (const f of batch.files) {
|
|
13645
|
-
const abs =
|
|
13646
|
-
if (!abs.startsWith(`${absAppDir}${
|
|
15030
|
+
const abs = path42.resolve(f);
|
|
15031
|
+
if (!abs.startsWith(`${absAppDir}${path42.sep}`) && abs !== absAppDir)
|
|
13647
15032
|
continue;
|
|
13648
15033
|
if (/\.(tsx|ts|jsx|js)$/.test(abs))
|
|
13649
15034
|
return true;
|
|
@@ -13651,15 +15036,15 @@ class IncrementalBuilder {
|
|
|
13651
15036
|
return false;
|
|
13652
15037
|
}
|
|
13653
15038
|
async batchMayChangePageKeys(appDir, batch) {
|
|
13654
|
-
const absAppDir =
|
|
13655
|
-
const pageKeys = new Set((await this.#app.getPageKeys()).map((key) =>
|
|
15039
|
+
const absAppDir = path42.resolve(appDir);
|
|
15040
|
+
const pageKeys = new Set((await this.#app.getPageKeys()).map((key) => path42.normalize(key)));
|
|
13656
15041
|
for (const f of batch.files) {
|
|
13657
|
-
const abs =
|
|
13658
|
-
if (!abs.startsWith(`${absAppDir}${
|
|
15042
|
+
const abs = path42.resolve(f);
|
|
15043
|
+
if (!abs.startsWith(`${absAppDir}${path42.sep}`) && abs !== absAppDir)
|
|
13659
15044
|
continue;
|
|
13660
15045
|
if (!/\.(tsx|ts|jsx|js)$/.test(abs))
|
|
13661
15046
|
continue;
|
|
13662
|
-
const rel =
|
|
15047
|
+
const rel = path42.normalize(path42.relative(absAppDir, abs));
|
|
13663
15048
|
if (!await Bun.file(abs).exists() || !pageKeys.has(rel))
|
|
13664
15049
|
return true;
|
|
13665
15050
|
}
|
|
@@ -13687,7 +15072,7 @@ class IncrementalBuilder {
|
|
|
13687
15072
|
${cssText}`).toString(36);
|
|
13688
15073
|
const cssRelPath = `styles/${cssAssetName}-${cssHash}.css`;
|
|
13689
15074
|
const cssUrl = `/_akan/styles/${cssAssetName}-${cssHash}.css`;
|
|
13690
|
-
await Bun.write(
|
|
15075
|
+
await Bun.write(path42.join(artifactDir, cssRelPath), cssText);
|
|
13691
15076
|
cssAssetEntries.push([basePath2, { cssUrl, cssRelPath }]);
|
|
13692
15077
|
cssBase64ByUrl[cssUrl] = Buffer.from(new TextEncoder().encode(cssText)).toString("base64");
|
|
13693
15078
|
})()
|
|
@@ -13755,10 +15140,10 @@ ${cssText}`).toString(36);
|
|
|
13755
15140
|
if (changedFiles.length === 0)
|
|
13756
15141
|
return false;
|
|
13757
15142
|
return changedFiles.some((file) => {
|
|
13758
|
-
const normalized =
|
|
15143
|
+
const normalized = path42.resolve(file);
|
|
13759
15144
|
if (/\.(woff2?|ttf|otf)$/i.test(normalized))
|
|
13760
15145
|
return true;
|
|
13761
|
-
return this.#optimizedFonts.files.some((fontFile) =>
|
|
15146
|
+
return this.#optimizedFonts.files.some((fontFile) => path42.resolve(fontFile) === normalized);
|
|
13762
15147
|
});
|
|
13763
15148
|
}
|
|
13764
15149
|
async installWatcher() {
|