@akanjs/cli 2.3.9-rc.4 → 2.3.9-rc.6
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 +1009 -402
- package/index.js +1174 -430
- package/package.json +2 -2
- package/templates/module/__model__.constant.ts +1 -1
- package/templates/module/__model__.dictionary.ts +10 -4
package/index.js
CHANGED
|
@@ -3394,28 +3394,28 @@ class SysExecutor extends Executor {
|
|
|
3394
3394
|
return scalarModules;
|
|
3395
3395
|
}
|
|
3396
3396
|
async getViewComponents() {
|
|
3397
|
-
const viewComponents = (await this.readdir("lib")).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${name}.View.tsx`).exists());
|
|
3397
|
+
const viewComponents = (await this.readdir("lib")).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${capitalize(name)}.View.tsx`).exists());
|
|
3398
3398
|
return viewComponents;
|
|
3399
3399
|
}
|
|
3400
3400
|
async getUnitComponents() {
|
|
3401
|
-
const unitComponents = (await this.readdir("lib")).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${name}.Unit.tsx`).exists());
|
|
3401
|
+
const unitComponents = (await this.readdir("lib")).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${capitalize(name)}.Unit.tsx`).exists());
|
|
3402
3402
|
return unitComponents;
|
|
3403
3403
|
}
|
|
3404
3404
|
async getTemplateComponents() {
|
|
3405
|
-
const templateComponents = (await this.readdir("lib")).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${name}.Template.tsx`).exists());
|
|
3405
|
+
const templateComponents = (await this.readdir("lib")).filter((name) => !name.startsWith("_") && !name.startsWith("__") && !name.endsWith(".ts")).filter((name) => Bun.file(`${this.cwdPath}/lib/${name}/${capitalize(name)}.Template.tsx`).exists());
|
|
3406
3406
|
return templateComponents;
|
|
3407
3407
|
}
|
|
3408
3408
|
async getViewsSourceCode() {
|
|
3409
3409
|
const viewComponents = await this.getViewComponents();
|
|
3410
|
-
return Promise.all(viewComponents.map((viewComponent) => this.getLocalFile(`lib/${viewComponent}/${viewComponent}.View.tsx`)));
|
|
3410
|
+
return Promise.all(viewComponents.map((viewComponent) => this.getLocalFile(`lib/${viewComponent}/${capitalize(viewComponent)}.View.tsx`)));
|
|
3411
3411
|
}
|
|
3412
3412
|
async getUnitsSourceCode() {
|
|
3413
3413
|
const unitComponents = await this.getUnitComponents();
|
|
3414
|
-
return Promise.all(unitComponents.map((unitComponent) => this.getLocalFile(`lib/${unitComponent}/${unitComponent}.Unit.tsx`)));
|
|
3414
|
+
return Promise.all(unitComponents.map((unitComponent) => this.getLocalFile(`lib/${unitComponent}/${capitalize(unitComponent)}.Unit.tsx`)));
|
|
3415
3415
|
}
|
|
3416
3416
|
async getTemplatesSourceCode() {
|
|
3417
3417
|
const templateComponents = await this.getTemplateComponents();
|
|
3418
|
-
return Promise.all(templateComponents.map((templateComponent) => this.getLocalFile(`lib/${templateComponent}/${templateComponent}.Template.tsx`)));
|
|
3418
|
+
return Promise.all(templateComponents.map((templateComponent) => this.getLocalFile(`lib/${templateComponent}/${capitalize(templateComponent)}.Template.tsx`)));
|
|
3419
3419
|
}
|
|
3420
3420
|
async getScalarConstantFiles() {
|
|
3421
3421
|
const scalarModules = await this.getScalarModules();
|
|
@@ -4805,11 +4805,17 @@ var createWorkflowApplyReport = ({
|
|
|
4805
4805
|
recommendedValidationCommands,
|
|
4806
4806
|
commands = [],
|
|
4807
4807
|
diagnostics = [],
|
|
4808
|
+
postApplyChecks = [],
|
|
4808
4809
|
recommendations = [],
|
|
4809
4810
|
nextActions = [],
|
|
4810
4811
|
plan
|
|
4811
4812
|
}) => {
|
|
4812
4813
|
const validationCommands = recommendedValidationCommands ?? commands;
|
|
4814
|
+
const orderedNextActions = uniqueBy(nextActions, (action) => action.command).sort((left, right) => {
|
|
4815
|
+
const leftRepair = left.command.startsWith("akan workflow explain") ? 0 : 1;
|
|
4816
|
+
const rightRepair = right.command.startsWith("akan workflow explain") ? 0 : 1;
|
|
4817
|
+
return leftRepair - rightRepair;
|
|
4818
|
+
});
|
|
4813
4819
|
return {
|
|
4814
4820
|
schemaVersion: 1,
|
|
4815
4821
|
workflow,
|
|
@@ -4821,8 +4827,9 @@ var createWorkflowApplyReport = ({
|
|
|
4821
4827
|
recommendedValidationCommands: uniqueBy(validationCommands, (command) => command.command),
|
|
4822
4828
|
commands: uniqueBy(validationCommands, (command) => command.command),
|
|
4823
4829
|
diagnostics,
|
|
4830
|
+
postApplyChecks,
|
|
4824
4831
|
recommendations: uniqueBy(recommendations, (recommendation) => `${recommendation.kind}:${recommendation.code}`),
|
|
4825
|
-
nextActions:
|
|
4832
|
+
nextActions: orderedNextActions.slice(0, 3),
|
|
4826
4833
|
plan
|
|
4827
4834
|
};
|
|
4828
4835
|
};
|
|
@@ -4887,6 +4894,12 @@ var statusForScope = (commands, diagnostics, scopes, expectedScope) => {
|
|
|
4887
4894
|
return "unknown";
|
|
4888
4895
|
return hasScopeFailure(scopes, expectedScope, diagnostics) ? "failed" : "passed";
|
|
4889
4896
|
};
|
|
4897
|
+
var statusForValidationKind = (commands, kind) => {
|
|
4898
|
+
const matching = commands.filter((command) => command.kind === kind);
|
|
4899
|
+
if (matching.length === 0)
|
|
4900
|
+
return "unknown";
|
|
4901
|
+
return matching.some((command) => command.status === "failed") ? "failed" : "passed";
|
|
4902
|
+
};
|
|
4890
4903
|
var createKnownBlockers = (commands, diagnostics) => {
|
|
4891
4904
|
const commandBlockers = commands.filter((command) => command.status === "failed" && (command.failureScope === "workspace-config" || command.failureScope === "environment")).map((command) => ({
|
|
4892
4905
|
code: `workflow-validation-${command.failureScope}`,
|
|
@@ -4920,7 +4933,17 @@ var createValidationStatuses = (commands, diagnostics) => {
|
|
|
4920
4933
|
const sourceStatus = statusForScope(commands, diagnostics, scopes, "source-change");
|
|
4921
4934
|
const workspaceStatus = hasScopeFailure(scopes, "workspace-config", diagnostics) || hasScopeFailure(scopes, "environment", diagnostics) ? "failed" : commands.length || diagnostics.length ? "passed" : "unknown";
|
|
4922
4935
|
const overallStatus = hasScopeFailure(scopes, "source-change", diagnostics) ? "failed" : hasScopeFailure(scopes, "workspace-config", diagnostics) ? "blocked-by-workspace-config" : hasScopeFailure(scopes, "environment", diagnostics) ? "blocked-by-environment" : workflowStatus(diagnostics) === "failed" || commandStatus(commands) === "failed" ? "failed" : "passed";
|
|
4923
|
-
return {
|
|
4936
|
+
return {
|
|
4937
|
+
sourceStatus,
|
|
4938
|
+
workspaceStatus,
|
|
4939
|
+
overallStatus,
|
|
4940
|
+
summary: {
|
|
4941
|
+
sourceChange: sourceStatus,
|
|
4942
|
+
generatedSync: statusForValidationKind(commands, "sync"),
|
|
4943
|
+
workspaceConfig: statusForScope(commands, diagnostics, scopes, "workspace-config"),
|
|
4944
|
+
environment: statusForScope(commands, diagnostics, scopes, "environment")
|
|
4945
|
+
}
|
|
4946
|
+
};
|
|
4924
4947
|
};
|
|
4925
4948
|
var createWorkflowValidationRunReport = async ({
|
|
4926
4949
|
runId = createWorkflowRunId("validation"),
|
|
@@ -5030,221 +5053,7 @@ var createRepairReport = ({
|
|
|
5030
5053
|
});
|
|
5031
5054
|
// pkgs/@akanjs/devkit/workflow/executor.ts
|
|
5032
5055
|
import { capitalize as capitalize2 } from "akanjs/common";
|
|
5033
|
-
|
|
5034
|
-
var primitiveReportToWorkflowStepResult = (report) => ({
|
|
5035
|
-
changedFiles: report.changedFiles,
|
|
5036
|
-
generatedFiles: report.generatedFiles,
|
|
5037
|
-
commands: report.validationCommands,
|
|
5038
|
-
diagnostics: report.diagnostics,
|
|
5039
|
-
recommendations: [],
|
|
5040
|
-
nextActions: report.nextActions
|
|
5041
|
-
});
|
|
5042
|
-
var workflowStringInput = (value) => typeof value === "string" ? value : null;
|
|
5043
|
-
var workflowStringListInput = (value) => Array.isArray(value) ? value.join(",") : null;
|
|
5044
|
-
var resolveWorkflowSys = async (workspace, target) => {
|
|
5045
|
-
if (!target)
|
|
5046
|
-
return null;
|
|
5047
|
-
const [apps, libs] = await workspace.getSyss();
|
|
5048
|
-
if (apps.includes(target))
|
|
5049
|
-
return AppExecutor.from(workspace, target);
|
|
5050
|
-
if (libs.includes(target))
|
|
5051
|
-
return LibExecutor.from(workspace, target);
|
|
5052
|
-
return null;
|
|
5053
|
-
};
|
|
5054
|
-
var targetMissing = (input2 = "app") => ({
|
|
5055
|
-
severity: "error",
|
|
5056
|
-
code: "workflow-target-missing",
|
|
5057
|
-
input: input2,
|
|
5058
|
-
message: "Workflow target app or library was not found."
|
|
5059
|
-
});
|
|
5060
|
-
var inputMissing = (input2) => ({
|
|
5061
|
-
severity: "error",
|
|
5062
|
-
code: "workflow-input-missing",
|
|
5063
|
-
input: input2,
|
|
5064
|
-
message: `Workflow input "${input2}" is required for apply.`
|
|
5065
|
-
});
|
|
5066
|
-
var unsupportedInput = (input2, message) => ({
|
|
5067
|
-
severity: "error",
|
|
5068
|
-
code: "workflow-input-unsupported",
|
|
5069
|
-
input: input2,
|
|
5070
|
-
message
|
|
5071
|
-
});
|
|
5072
|
-
var addFieldUiSurfaceInspection = (plan) => {
|
|
5073
|
-
const app = workflowStringInput(plan.inputs.app);
|
|
5074
|
-
const module = workflowStringInput(plan.inputs.module) ?? "<module>";
|
|
5075
|
-
const field = workflowStringInput(plan.inputs.field) ?? "<field>";
|
|
5076
|
-
const typeName = workflowStringInput(plan.inputs.type);
|
|
5077
|
-
const isNumeric = typeName === "Int" || typeName === "Float" || typeName === "integer" || typeName === "float";
|
|
5078
|
-
const moduleClassName = capitalize2(module);
|
|
5079
|
-
const target = `${app ? `apps/${app}` : "*"}/lib/${module}/${moduleClassName}.Template.tsx`;
|
|
5080
|
-
return {
|
|
5081
|
-
recommendations: [
|
|
5082
|
-
{
|
|
5083
|
-
code: "add-field-ui-surface-review",
|
|
5084
|
-
kind: "manual-action",
|
|
5085
|
-
target,
|
|
5086
|
-
action: isNumeric ? `Review ${moduleClassName} Template/Unit/View/Store surfaces before adding ${field}; confirm the local Field.Text numeric parser/formatter, validation rule, and dictionary label pattern.` : `Add ${field} to ${moduleClassName} UI surfaces only when the local Field.* pattern is clear.`,
|
|
5087
|
-
confidence: "medium",
|
|
5088
|
-
message: isNumeric ? `No UI file was modified automatically because a safe numeric input component pattern is not yet detected for ${module}.${field}.` : `Review Template/Unit/View/Store surfaces for ${module}.${field}; no UI file was modified automatically.`
|
|
5089
|
-
}
|
|
5090
|
-
],
|
|
5091
|
-
nextActions: [
|
|
5092
|
-
{
|
|
5093
|
-
command: `akan workflow explain ${plan.workflow}`,
|
|
5094
|
-
reason: "Review UI surface guidance before manually editing ambiguous UI files."
|
|
5095
|
-
}
|
|
5096
|
-
]
|
|
5097
|
-
};
|
|
5098
|
-
};
|
|
5099
|
-
var createWorkflowStepRegistry = ({
|
|
5100
|
-
workspace,
|
|
5101
|
-
createModule,
|
|
5102
|
-
createScalar,
|
|
5103
|
-
createUi,
|
|
5104
|
-
addField,
|
|
5105
|
-
addEnumField
|
|
5106
|
-
}) => {
|
|
5107
|
-
const inspect = async () => {
|
|
5108
|
-
return;
|
|
5109
|
-
};
|
|
5110
|
-
const commandOnly = async () => {
|
|
5111
|
-
return;
|
|
5112
|
-
};
|
|
5113
|
-
return {
|
|
5114
|
-
inspectSystem: inspect,
|
|
5115
|
-
inspectModule: inspect,
|
|
5116
|
-
syncTarget: commandOnly,
|
|
5117
|
-
lintTarget: commandOnly,
|
|
5118
|
-
[workflowStepKey("create-module", "create-module")]: async (_step, plan) => {
|
|
5119
|
-
const app = workflowStringInput(plan.inputs.app);
|
|
5120
|
-
const module = workflowStringInput(plan.inputs.module);
|
|
5121
|
-
const sys2 = await resolveWorkflowSys(workspace, app);
|
|
5122
|
-
if (!sys2 || !module)
|
|
5123
|
-
return { diagnostics: [!sys2 ? targetMissing() : inputMissing("module")] };
|
|
5124
|
-
return primitiveReportToWorkflowStepResult(await createModule(sys2, module));
|
|
5125
|
-
},
|
|
5126
|
-
[workflowStepKey("create-scalar", "create-scalar")]: async (_step, plan) => {
|
|
5127
|
-
const app = workflowStringInput(plan.inputs.app);
|
|
5128
|
-
const scalar = workflowStringInput(plan.inputs.scalar);
|
|
5129
|
-
const sys2 = await resolveWorkflowSys(workspace, app);
|
|
5130
|
-
if (!sys2 || !scalar)
|
|
5131
|
-
return { diagnostics: [!sys2 ? targetMissing() : inputMissing("scalar")] };
|
|
5132
|
-
return primitiveReportToWorkflowStepResult(await createScalar(sys2, scalar));
|
|
5133
|
-
},
|
|
5134
|
-
[workflowStepKey("create-ui", "create-ui")]: async (_step, plan) => {
|
|
5135
|
-
const surface = workflowStringInput(plan.inputs.surface);
|
|
5136
|
-
if (surface !== "view" && surface !== "unit" && surface !== "template") {
|
|
5137
|
-
return {
|
|
5138
|
-
diagnostics: [
|
|
5139
|
-
unsupportedInput("surface", "Workflow apply currently supports create-ui surfaces: view, unit, template.")
|
|
5140
|
-
]
|
|
5141
|
-
};
|
|
5142
|
-
}
|
|
5143
|
-
return primitiveReportToWorkflowStepResult(await createUi({
|
|
5144
|
-
app: workflowStringInput(plan.inputs.app),
|
|
5145
|
-
module: workflowStringInput(plan.inputs.module),
|
|
5146
|
-
surface
|
|
5147
|
-
}));
|
|
5148
|
-
},
|
|
5149
|
-
[workflowStepKey("add-field", "update-constant")]: async (_step, plan) => {
|
|
5150
|
-
if (workflowStringInput(plan.inputs.type)?.toLowerCase() === "enum") {
|
|
5151
|
-
return primitiveReportToWorkflowStepResult(await addEnumField({
|
|
5152
|
-
app: workflowStringInput(plan.inputs.app),
|
|
5153
|
-
module: workflowStringInput(plan.inputs.module),
|
|
5154
|
-
field: workflowStringInput(plan.inputs.field),
|
|
5155
|
-
values: workflowStringListInput(plan.inputs.values),
|
|
5156
|
-
defaultValue: workflowStringInput(plan.inputs.default)
|
|
5157
|
-
}));
|
|
5158
|
-
}
|
|
5159
|
-
return primitiveReportToWorkflowStepResult(await addField({
|
|
5160
|
-
app: workflowStringInput(plan.inputs.app),
|
|
5161
|
-
module: workflowStringInput(plan.inputs.module),
|
|
5162
|
-
field: workflowStringInput(plan.inputs.field),
|
|
5163
|
-
type: workflowStringInput(plan.inputs.type),
|
|
5164
|
-
defaultValue: workflowStringInput(plan.inputs.default)
|
|
5165
|
-
}));
|
|
5166
|
-
},
|
|
5167
|
-
[workflowStepKey("add-field", "update-dictionary")]: inspect,
|
|
5168
|
-
[workflowStepKey("add-field", "update-ui-surfaces")]: async (_step, plan) => addFieldUiSurfaceInspection(plan),
|
|
5169
|
-
[workflowStepKey("add-enum-field", "update-constant")]: async (_step, plan) => primitiveReportToWorkflowStepResult(await addEnumField({
|
|
5170
|
-
app: workflowStringInput(plan.inputs.app),
|
|
5171
|
-
module: workflowStringInput(plan.inputs.module),
|
|
5172
|
-
field: workflowStringInput(plan.inputs.field),
|
|
5173
|
-
values: workflowStringListInput(plan.inputs.values),
|
|
5174
|
-
defaultValue: workflowStringInput(plan.inputs.default)
|
|
5175
|
-
})),
|
|
5176
|
-
[workflowStepKey("add-enum-field", "update-dictionary")]: inspect,
|
|
5177
|
-
[workflowStepKey("add-enum-field", "update-option")]: inspect
|
|
5178
|
-
};
|
|
5179
|
-
};
|
|
5180
|
-
class WorkflowExecutor {
|
|
5181
|
-
registry;
|
|
5182
|
-
constructor(registry) {
|
|
5183
|
-
this.registry = registry;
|
|
5184
|
-
}
|
|
5185
|
-
async apply(plan) {
|
|
5186
|
-
const changedFiles = [];
|
|
5187
|
-
const generatedFiles = [];
|
|
5188
|
-
const recommendedValidationCommands = [];
|
|
5189
|
-
const diagnostics = [...plan.diagnostics];
|
|
5190
|
-
const recommendations = [...plan.recommendations];
|
|
5191
|
-
const nextActions = [];
|
|
5192
|
-
if (diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
|
|
5193
|
-
return createWorkflowApplyReport({
|
|
5194
|
-
workflow: plan.workflow,
|
|
5195
|
-
mode: "apply",
|
|
5196
|
-
changedFiles,
|
|
5197
|
-
generatedFiles,
|
|
5198
|
-
recommendedValidationCommands,
|
|
5199
|
-
diagnostics,
|
|
5200
|
-
recommendations,
|
|
5201
|
-
nextActions,
|
|
5202
|
-
plan
|
|
5203
|
-
});
|
|
5204
|
-
}
|
|
5205
|
-
recommendedValidationCommands.push(...workflowCommandsForPlan(plan));
|
|
5206
|
-
nextActions.push(...workflowCommandsForPlan(plan));
|
|
5207
|
-
for (const step of plan.steps) {
|
|
5208
|
-
const runner = this.registry[workflowStepKey(plan.workflow, step.id)] ?? this.registry[step.tool] ?? this.registry[step.id];
|
|
5209
|
-
if (!runner) {
|
|
5210
|
-
diagnostics.push({
|
|
5211
|
-
severity: "error",
|
|
5212
|
-
code: "workflow-step-unsupported",
|
|
5213
|
-
message: `Workflow ${plan.workflow} step "${step.id}" is not supported by workflow apply yet.`
|
|
5214
|
-
});
|
|
5215
|
-
nextActions.push({
|
|
5216
|
-
command: `akan workflow explain ${plan.workflow}`,
|
|
5217
|
-
reason: "Review the unsupported workflow step before retrying apply."
|
|
5218
|
-
});
|
|
5219
|
-
break;
|
|
5220
|
-
}
|
|
5221
|
-
const result = await runner(step, plan);
|
|
5222
|
-
if (!result)
|
|
5223
|
-
continue;
|
|
5224
|
-
changedFiles.push(...result.changedFiles ?? []);
|
|
5225
|
-
generatedFiles.push(...result.generatedFiles ?? []);
|
|
5226
|
-
recommendedValidationCommands.push(...result.commands ?? []);
|
|
5227
|
-
diagnostics.push(...result.diagnostics ?? []);
|
|
5228
|
-
recommendations.push(...result.recommendations ?? []);
|
|
5229
|
-
nextActions.push(...result.nextActions ?? []);
|
|
5230
|
-
if (diagnostics.some((diagnostic) => diagnostic.severity === "error"))
|
|
5231
|
-
break;
|
|
5232
|
-
}
|
|
5233
|
-
return createWorkflowApplyReport({
|
|
5234
|
-
workflow: plan.workflow,
|
|
5235
|
-
mode: "apply",
|
|
5236
|
-
changedFiles,
|
|
5237
|
-
generatedFiles,
|
|
5238
|
-
recommendedValidationCommands,
|
|
5239
|
-
diagnostics,
|
|
5240
|
-
recommendations,
|
|
5241
|
-
nextActions,
|
|
5242
|
-
plan
|
|
5243
|
-
});
|
|
5244
|
-
}
|
|
5245
|
-
}
|
|
5246
|
-
// pkgs/@akanjs/devkit/workflow/plan.ts
|
|
5247
|
-
import { capitalize as capitalize3 } from "akanjs/common";
|
|
5056
|
+
import ts4 from "typescript";
|
|
5248
5057
|
|
|
5249
5058
|
// pkgs/@akanjs/devkit/workflow/primitive.ts
|
|
5250
5059
|
var createPrimitiveWriteReport = ({
|
|
@@ -5296,6 +5105,23 @@ var sourceFile = (sys2, path10, action, reason) => ({
|
|
|
5296
5105
|
action,
|
|
5297
5106
|
reason
|
|
5298
5107
|
});
|
|
5108
|
+
var moduleComponentName = (moduleName) => `${moduleName.slice(0, 1).toUpperCase()}${moduleName.slice(1)}`;
|
|
5109
|
+
var moduleSourcePaths = (moduleName) => {
|
|
5110
|
+
const componentName = moduleComponentName(moduleName);
|
|
5111
|
+
return {
|
|
5112
|
+
abstract: `lib/${moduleName}/${moduleName}.abstract.md`,
|
|
5113
|
+
constant: `lib/${moduleName}/${moduleName}.constant.ts`,
|
|
5114
|
+
dictionary: `lib/${moduleName}/${moduleName}.dictionary.ts`,
|
|
5115
|
+
service: `lib/${moduleName}/${moduleName}.service.ts`,
|
|
5116
|
+
signal: `lib/${moduleName}/${moduleName}.signal.ts`,
|
|
5117
|
+
store: `lib/${moduleName}/${moduleName}.store.ts`,
|
|
5118
|
+
template: `lib/${moduleName}/${componentName}.Template.tsx`,
|
|
5119
|
+
unit: `lib/${moduleName}/${componentName}.Unit.tsx`,
|
|
5120
|
+
util: `lib/${moduleName}/${componentName}.Util.tsx`,
|
|
5121
|
+
view: `lib/${moduleName}/${componentName}.View.tsx`,
|
|
5122
|
+
zone: `lib/${moduleName}/${componentName}.Zone.tsx`
|
|
5123
|
+
};
|
|
5124
|
+
};
|
|
5299
5125
|
var generatedFilesForSync = (sys2, reason = "Generated files may change after sync.") => generatedFilePathsForTarget(getSysRoot(sys2), reason);
|
|
5300
5126
|
var validationCommandsForTarget = (target) => [
|
|
5301
5127
|
{ command: `akan sync ${target}`, reason: "Refresh generated Akan files from source conventions." },
|
|
@@ -5322,6 +5148,50 @@ var createPassedPrimitiveReport = ({
|
|
|
5322
5148
|
var scalarChangedFiles = (sys2, scalarName, files) => Object.values(files).map((file) => sourceFile(sys2, `lib/__scalar/${scalarName}/${file.filename}`, "create", "Scalar source file was created."));
|
|
5323
5149
|
var titleize = (value) => value.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").replace(/\b\w/g, (char) => char.toUpperCase());
|
|
5324
5150
|
var lowerlize = (value) => `${value.slice(0, 1).toLowerCase()}${value.slice(1)}`;
|
|
5151
|
+
var koLabels = {
|
|
5152
|
+
amount: "\uAE08\uC561",
|
|
5153
|
+
budget: "\uC608\uC0B0",
|
|
5154
|
+
category: "\uCE74\uD14C\uACE0\uB9AC",
|
|
5155
|
+
content: "\uB0B4\uC6A9",
|
|
5156
|
+
count: "\uAC1C\uC218",
|
|
5157
|
+
createdAt: "\uC0DD\uC131\uC77C",
|
|
5158
|
+
date: "\uB0A0\uC9DC",
|
|
5159
|
+
description: "\uC124\uBA85",
|
|
5160
|
+
due: "\uB9C8\uAC10\uC77C",
|
|
5161
|
+
dueAt: "\uB9C8\uAC10\uC77C",
|
|
5162
|
+
email: "\uC774\uBA54\uC77C",
|
|
5163
|
+
enabled: "\uD65C\uC131\uD654",
|
|
5164
|
+
endAt: "\uC885\uB8CC\uC77C",
|
|
5165
|
+
id: "ID",
|
|
5166
|
+
name: "\uC774\uB984",
|
|
5167
|
+
owner: "\uB2F4\uB2F9\uC790",
|
|
5168
|
+
priority: "\uC6B0\uC120\uC21C\uC704",
|
|
5169
|
+
project: "\uD504\uB85C\uC81D\uD2B8",
|
|
5170
|
+
rating: "\uD3C9\uC810",
|
|
5171
|
+
startAt: "\uC2DC\uC791\uC77C",
|
|
5172
|
+
status: "\uC0C1\uD0DC",
|
|
5173
|
+
title: "\uC81C\uBAA9",
|
|
5174
|
+
updatedAt: "\uC218\uC815\uC77C"
|
|
5175
|
+
};
|
|
5176
|
+
var splitFieldWords = (fieldName) => fieldName.replace(/([a-z0-9])([A-Z])/g, "$1 $2").replace(/[-_]+/g, " ").split(/\s+/).map((word) => word.trim()).filter(Boolean);
|
|
5177
|
+
var koLabelForField = (fieldName) => {
|
|
5178
|
+
if (koLabels[fieldName])
|
|
5179
|
+
return koLabels[fieldName];
|
|
5180
|
+
const words = splitFieldWords(fieldName);
|
|
5181
|
+
const translated = words.map((word) => koLabels[word] ?? koLabels[lowerlize(word)] ?? null);
|
|
5182
|
+
return translated.every(Boolean) ? translated.join(" ") : null;
|
|
5183
|
+
};
|
|
5184
|
+
var bilingualLabelForField = (fieldName) => {
|
|
5185
|
+
const en = titleize(fieldName);
|
|
5186
|
+
return { en, ko: koLabelForField(fieldName) ?? en };
|
|
5187
|
+
};
|
|
5188
|
+
var bilingualDescriptionForField = (fieldName) => {
|
|
5189
|
+
const label = bilingualLabelForField(fieldName);
|
|
5190
|
+
return {
|
|
5191
|
+
en: `Enter ${label.en.toLowerCase()}.`,
|
|
5192
|
+
ko: `${label.ko} \uAC12\uC744 \uC785\uB825\uD569\uB2C8\uB2E4.`
|
|
5193
|
+
};
|
|
5194
|
+
};
|
|
5325
5195
|
var normalizeFieldType = (typeName) => {
|
|
5326
5196
|
const normalizedTypes = {
|
|
5327
5197
|
string: "String",
|
|
@@ -5349,6 +5219,15 @@ var ensureBaseTypeImport = (content, typeName) => {
|
|
|
5349
5219
|
${content}`;
|
|
5350
5220
|
};
|
|
5351
5221
|
var numericDefault = (typeName, rawDefault) => {
|
|
5222
|
+
if (typeof rawDefault === "number") {
|
|
5223
|
+
if (!Number.isFinite(rawDefault))
|
|
5224
|
+
return null;
|
|
5225
|
+
if (typeName === "Int" && !Number.isInteger(rawDefault))
|
|
5226
|
+
return null;
|
|
5227
|
+
return String(rawDefault);
|
|
5228
|
+
}
|
|
5229
|
+
if (typeof rawDefault !== "string")
|
|
5230
|
+
return null;
|
|
5352
5231
|
const trimmed = rawDefault.trim();
|
|
5353
5232
|
if (!trimmed || !Number.isFinite(Number(trimmed)))
|
|
5354
5233
|
return null;
|
|
@@ -5356,16 +5235,41 @@ var numericDefault = (typeName, rawDefault) => {
|
|
|
5356
5235
|
return null;
|
|
5357
5236
|
return trimmed;
|
|
5358
5237
|
};
|
|
5359
|
-
var
|
|
5360
|
-
if (
|
|
5361
|
-
return
|
|
5362
|
-
|
|
5238
|
+
var booleanDefault = (rawDefault) => {
|
|
5239
|
+
if (typeof rawDefault === "boolean")
|
|
5240
|
+
return String(rawDefault);
|
|
5241
|
+
if (typeof rawDefault !== "string")
|
|
5242
|
+
return null;
|
|
5243
|
+
const lowered = rawDefault.trim().toLowerCase();
|
|
5244
|
+
return lowered === "true" || lowered === "false" ? lowered : null;
|
|
5245
|
+
};
|
|
5246
|
+
var dateDefault = (rawDefault) => {
|
|
5247
|
+
if (typeof rawDefault === "number" && Number.isFinite(rawDefault))
|
|
5248
|
+
return `new Date(${rawDefault})`;
|
|
5249
|
+
if (typeof rawDefault !== "string")
|
|
5250
|
+
return null;
|
|
5251
|
+
const trimmed = rawDefault.trim();
|
|
5252
|
+
if (!trimmed)
|
|
5253
|
+
return null;
|
|
5254
|
+
if (trimmed === "now")
|
|
5255
|
+
return "new Date()";
|
|
5256
|
+
if (!Number.isNaN(Date.parse(trimmed)))
|
|
5257
|
+
return `new Date(${JSON.stringify(trimmed)})`;
|
|
5258
|
+
return null;
|
|
5259
|
+
};
|
|
5260
|
+
var coerceFieldDefault = (typeName, defaultValue, options = {}) => {
|
|
5261
|
+
const normalizedType = typeName.toLowerCase() === "enum" ? "enum" : normalizeFieldType(typeName);
|
|
5262
|
+
if (defaultValue === undefined || defaultValue === null || defaultValue === "") {
|
|
5263
|
+
return { expression: null, normalized: false, normalizedType };
|
|
5264
|
+
}
|
|
5363
5265
|
if (normalizedType === "Int" || normalizedType === "Float") {
|
|
5364
5266
|
const expression = numericDefault(normalizedType, defaultValue);
|
|
5365
5267
|
if (expression !== null)
|
|
5366
|
-
return { expression };
|
|
5268
|
+
return { expression, normalized: typeof defaultValue === "string", normalizedType };
|
|
5367
5269
|
return {
|
|
5368
5270
|
expression: null,
|
|
5271
|
+
normalized: false,
|
|
5272
|
+
normalizedType,
|
|
5369
5273
|
diagnostic: {
|
|
5370
5274
|
severity: "error",
|
|
5371
5275
|
code: "primitive-default-value-invalid",
|
|
@@ -5376,11 +5280,13 @@ var coerceFieldDefault = (typeName, defaultValue) => {
|
|
|
5376
5280
|
};
|
|
5377
5281
|
}
|
|
5378
5282
|
if (normalizedType === "Boolean") {
|
|
5379
|
-
const
|
|
5380
|
-
if (
|
|
5381
|
-
return { expression:
|
|
5283
|
+
const expression = booleanDefault(defaultValue);
|
|
5284
|
+
if (expression !== null)
|
|
5285
|
+
return { expression, normalized: typeof defaultValue === "string", normalizedType };
|
|
5382
5286
|
return {
|
|
5383
5287
|
expression: null,
|
|
5288
|
+
normalized: false,
|
|
5289
|
+
normalizedType,
|
|
5384
5290
|
diagnostic: {
|
|
5385
5291
|
severity: "error",
|
|
5386
5292
|
code: "primitive-default-value-invalid",
|
|
@@ -5390,13 +5296,58 @@ var coerceFieldDefault = (typeName, defaultValue) => {
|
|
|
5390
5296
|
}
|
|
5391
5297
|
};
|
|
5392
5298
|
}
|
|
5393
|
-
|
|
5299
|
+
if (normalizedType === "Date") {
|
|
5300
|
+
const expression = dateDefault(defaultValue);
|
|
5301
|
+
if (expression !== null)
|
|
5302
|
+
return { expression, normalized: true, normalizedType };
|
|
5303
|
+
return {
|
|
5304
|
+
expression: null,
|
|
5305
|
+
normalized: false,
|
|
5306
|
+
normalizedType,
|
|
5307
|
+
diagnostic: {
|
|
5308
|
+
severity: "error",
|
|
5309
|
+
code: "primitive-default-value-invalid",
|
|
5310
|
+
input: "default",
|
|
5311
|
+
failureScope: "source-change",
|
|
5312
|
+
message: `Default value for Date must be "now", a timestamp, or a parseable date string. Received: ${JSON.stringify(defaultValue)}.`
|
|
5313
|
+
}
|
|
5314
|
+
};
|
|
5315
|
+
}
|
|
5316
|
+
if (normalizedType === "enum") {
|
|
5317
|
+
if (typeof defaultValue === "string" && options.enumValues?.includes(defaultValue)) {
|
|
5318
|
+
return { expression: JSON.stringify(defaultValue), normalized: false, normalizedType };
|
|
5319
|
+
}
|
|
5320
|
+
return {
|
|
5321
|
+
expression: null,
|
|
5322
|
+
normalized: false,
|
|
5323
|
+
normalizedType,
|
|
5324
|
+
diagnostic: {
|
|
5325
|
+
severity: "error",
|
|
5326
|
+
code: "primitive-default-value-invalid",
|
|
5327
|
+
input: "default",
|
|
5328
|
+
failureScope: "source-change",
|
|
5329
|
+
message: `Default value for enum must be one of: ${(options.enumValues ?? []).join(", ")}. Received: ${JSON.stringify(defaultValue)}.`
|
|
5330
|
+
}
|
|
5331
|
+
};
|
|
5332
|
+
}
|
|
5333
|
+
return {
|
|
5334
|
+
expression: JSON.stringify(String(defaultValue)),
|
|
5335
|
+
normalized: typeof defaultValue !== "string",
|
|
5336
|
+
normalizedType
|
|
5337
|
+
};
|
|
5394
5338
|
};
|
|
5395
|
-
var fieldExpression = (typeName, defaultValue) => {
|
|
5339
|
+
var fieldExpression = (typeName, defaultValue, options = {}) => {
|
|
5396
5340
|
const typeExpression = normalizeFieldType(typeName);
|
|
5397
|
-
const defaultExpression = coerceFieldDefault(typeExpression, defaultValue).expression;
|
|
5341
|
+
const defaultExpression = coerceFieldDefault(options.enumValues ? "enum" : typeExpression, defaultValue, options).expression;
|
|
5398
5342
|
const defaultOption = defaultExpression ? `, { default: ${defaultExpression} }` : "";
|
|
5399
|
-
return
|
|
5343
|
+
return `${options.builderName ?? "field"}(${typeExpression}${defaultOption})`;
|
|
5344
|
+
};
|
|
5345
|
+
var viaBuilderParameterName = (content, className) => {
|
|
5346
|
+
const classIndex = content.indexOf(`export class ${className} extends via`);
|
|
5347
|
+
if (classIndex < 0)
|
|
5348
|
+
return null;
|
|
5349
|
+
const signature = content.slice(classIndex, content.indexOf("=>", classIndex));
|
|
5350
|
+
return /via\(\(\s*([A-Za-z_$][\w$]*)\s*\)/.exec(signature)?.[1] ?? null;
|
|
5400
5351
|
};
|
|
5401
5352
|
var insertIntoObject = (content, className, line) => {
|
|
5402
5353
|
const classIndex = content.indexOf(`export class ${className} extends via`);
|
|
@@ -5414,6 +5365,50 @@ var insertIntoObject = (content, className, line) => {
|
|
|
5414
5365
|
`;
|
|
5415
5366
|
return `${prefix}${insertion}${suffix}`;
|
|
5416
5367
|
};
|
|
5368
|
+
var insertLightProjectionField = (content, moduleClassName, fieldName) => {
|
|
5369
|
+
const classIndex = content.indexOf(`export class Light${moduleClassName} extends via`);
|
|
5370
|
+
if (classIndex < 0)
|
|
5371
|
+
return null;
|
|
5372
|
+
const arrayMatch = /\[([\s\S]*?)\]\s+as const/.exec(content.slice(classIndex));
|
|
5373
|
+
if (!arrayMatch || arrayMatch.index === undefined)
|
|
5374
|
+
return null;
|
|
5375
|
+
const arrayStart = classIndex + arrayMatch.index;
|
|
5376
|
+
const arrayEnd = arrayStart + arrayMatch[0].length;
|
|
5377
|
+
const fields = [...arrayMatch[1].matchAll(/"([^"]+)"/g)].map((match) => match[1]).filter(Boolean);
|
|
5378
|
+
if (fields.includes(fieldName))
|
|
5379
|
+
return content;
|
|
5380
|
+
const nextFields = [...fields, fieldName];
|
|
5381
|
+
const nextArray = nextFields.length === 0 ? "[] as const" : `[
|
|
5382
|
+
${nextFields.map((field) => ` ${JSON.stringify(field)},`).join(`
|
|
5383
|
+
`)}
|
|
5384
|
+
] as const`;
|
|
5385
|
+
return `${content.slice(0, arrayStart)}${nextArray}${content.slice(arrayEnd)}`;
|
|
5386
|
+
};
|
|
5387
|
+
var insertTemplateField = ({
|
|
5388
|
+
content,
|
|
5389
|
+
moduleName,
|
|
5390
|
+
moduleClassName,
|
|
5391
|
+
fieldName,
|
|
5392
|
+
component
|
|
5393
|
+
}) => {
|
|
5394
|
+
if (content.includes(`l("${moduleName}.${fieldName}")`) || content.includes(`.${fieldName}`))
|
|
5395
|
+
return content;
|
|
5396
|
+
const layoutEndIndex = content.indexOf(" </Layout.Template>");
|
|
5397
|
+
if (layoutEndIndex < 0)
|
|
5398
|
+
return null;
|
|
5399
|
+
const formName = `${moduleName}Form`;
|
|
5400
|
+
if (!content.includes(`const ${formName} = st.use.${moduleName}Form();`))
|
|
5401
|
+
return null;
|
|
5402
|
+
const fieldSetter = `st.do.set${moduleComponentName(fieldName)}On${moduleClassName}`;
|
|
5403
|
+
const fieldBlock = ` <${component}
|
|
5404
|
+
label={l("${moduleName}.${fieldName}")}
|
|
5405
|
+
desc={l("${moduleName}.${fieldName}.desc")}
|
|
5406
|
+
value={${formName}.${fieldName}}
|
|
5407
|
+
onChange={${fieldSetter}}
|
|
5408
|
+
/>
|
|
5409
|
+
`;
|
|
5410
|
+
return `${content.slice(0, layoutEndIndex)}${fieldBlock}${content.slice(layoutEndIndex)}`;
|
|
5411
|
+
};
|
|
5417
5412
|
var ensureEnumImport = (content) => {
|
|
5418
5413
|
if (content.includes("enumOf"))
|
|
5419
5414
|
return content;
|
|
@@ -5440,48 +5435,468 @@ ${values.map((value) => ` ${JSON.stringify(value)},`).join(`
|
|
|
5440
5435
|
${enumClass}`;
|
|
5441
5436
|
return `${content.slice(0, firstClassIndex)}${enumClass}${content.slice(firstClassIndex)}`;
|
|
5442
5437
|
};
|
|
5438
|
+
var findMatchingBrace = (content, openIndex) => {
|
|
5439
|
+
let depth = 0;
|
|
5440
|
+
let quote = null;
|
|
5441
|
+
let escaped = false;
|
|
5442
|
+
for (let index = openIndex;index < content.length; index++) {
|
|
5443
|
+
const char = content[index];
|
|
5444
|
+
if (quote) {
|
|
5445
|
+
if (escaped) {
|
|
5446
|
+
escaped = false;
|
|
5447
|
+
continue;
|
|
5448
|
+
}
|
|
5449
|
+
if (char === "\\") {
|
|
5450
|
+
escaped = true;
|
|
5451
|
+
continue;
|
|
5452
|
+
}
|
|
5453
|
+
if (char === quote)
|
|
5454
|
+
quote = null;
|
|
5455
|
+
continue;
|
|
5456
|
+
}
|
|
5457
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
5458
|
+
quote = char;
|
|
5459
|
+
continue;
|
|
5460
|
+
}
|
|
5461
|
+
if (char === "{")
|
|
5462
|
+
depth += 1;
|
|
5463
|
+
if (char === "}") {
|
|
5464
|
+
depth -= 1;
|
|
5465
|
+
if (depth === 0)
|
|
5466
|
+
return index;
|
|
5467
|
+
}
|
|
5468
|
+
}
|
|
5469
|
+
return -1;
|
|
5470
|
+
};
|
|
5471
|
+
var dictionaryModelFieldLine = (fieldName) => {
|
|
5472
|
+
const label = bilingualLabelForField(fieldName);
|
|
5473
|
+
const desc = bilingualDescriptionForField(fieldName);
|
|
5474
|
+
return `${fieldName}: t([${JSON.stringify(label.en)}, ${JSON.stringify(label.ko)}]).desc([${JSON.stringify(desc.en)}, ${JSON.stringify(desc.ko)}]),`;
|
|
5475
|
+
};
|
|
5443
5476
|
var insertDictionaryModelField = (content, moduleClassName, fieldName) => {
|
|
5444
5477
|
if (new RegExp(`\\b${fieldName}\\s*:`).test(content))
|
|
5445
5478
|
return content;
|
|
5446
|
-
const
|
|
5447
|
-
const modelIndex = content.indexOf(`.model<${moduleClassName}>((t) => ({`);
|
|
5479
|
+
const modelIndex = content.indexOf(`.model<${moduleClassName}>((t) => (`);
|
|
5448
5480
|
if (modelIndex < 0)
|
|
5449
5481
|
return null;
|
|
5450
|
-
const
|
|
5482
|
+
const objectStartIndex = content.indexOf("{", modelIndex);
|
|
5483
|
+
if (objectStartIndex < 0)
|
|
5484
|
+
return null;
|
|
5485
|
+
const objectEndIndex = findMatchingBrace(content, objectStartIndex);
|
|
5451
5486
|
if (objectEndIndex < 0)
|
|
5452
5487
|
return null;
|
|
5453
|
-
|
|
5454
|
-
|
|
5488
|
+
const fieldLine = dictionaryModelFieldLine(fieldName);
|
|
5489
|
+
const body = content.slice(objectStartIndex + 1, objectEndIndex);
|
|
5490
|
+
if (body.trim().length === 0) {
|
|
5491
|
+
return `${content.slice(0, objectStartIndex + 1)}
|
|
5492
|
+
${fieldLine}
|
|
5493
|
+
${content.slice(objectEndIndex)}`;
|
|
5494
|
+
}
|
|
5495
|
+
const insertion = body.endsWith(`
|
|
5496
|
+
`) ? ` ${fieldLine}
|
|
5497
|
+
` : `
|
|
5498
|
+
${fieldLine}
|
|
5499
|
+
`;
|
|
5500
|
+
return `${content.slice(0, objectEndIndex)}${insertion}${content.slice(objectEndIndex)}`;
|
|
5501
|
+
};
|
|
5502
|
+
var ensureConstantTypeImport = (content, constantPath, typeName) => {
|
|
5503
|
+
if (new RegExp(`import type \\{[^}]*\\b${typeName}\\b[^}]*\\} from "${constantPath}";`).test(content))
|
|
5504
|
+
return content;
|
|
5505
|
+
const importPattern = new RegExp(`import type \\{ ([^}]+) \\} from "${constantPath}";`);
|
|
5506
|
+
const existingImport = content.match(importPattern);
|
|
5507
|
+
if (existingImport !== null) {
|
|
5508
|
+
const names = existingImport[1]?.split(",").map((name) => name.trim()) ?? [];
|
|
5509
|
+
return content.replace(existingImport[0], `import type { ${[...names, typeName].sort().join(", ")} } from "${constantPath}";`);
|
|
5510
|
+
}
|
|
5511
|
+
return `import type { ${typeName} } from "${constantPath}";
|
|
5512
|
+
${content}`;
|
|
5513
|
+
};
|
|
5514
|
+
var insertDictionaryEnum = (content, enumClassName, enumName, values) => {
|
|
5515
|
+
if (content.includes(`.enum<${enumClassName}>("${enumName}"`))
|
|
5516
|
+
return content;
|
|
5517
|
+
const enumBlock = ` .enum<${enumClassName}>("${enumName}", (t) => ({
|
|
5518
|
+
${values.map((value) => ` ${value}: t([${JSON.stringify(titleize(value))}, ${JSON.stringify(titleize(value))}]),`).join(`
|
|
5519
|
+
`)}
|
|
5520
|
+
}))
|
|
5521
|
+
`;
|
|
5522
|
+
const chainEndIndex = content.lastIndexOf(";");
|
|
5523
|
+
const insertBeforeIndex = [content.indexOf(".error("), content.indexOf(".translate("), chainEndIndex].filter((index) => index >= 0).sort((a, b) => a - b)[0];
|
|
5524
|
+
if (insertBeforeIndex === undefined)
|
|
5525
|
+
return null;
|
|
5526
|
+
return `${content.slice(0, insertBeforeIndex)}${enumBlock}${content.slice(insertBeforeIndex)}`;
|
|
5527
|
+
};
|
|
5528
|
+
var parseValues = (value) => value?.split(",").map((item) => item.trim()).filter(Boolean) ?? [];
|
|
5529
|
+
|
|
5530
|
+
// pkgs/@akanjs/devkit/workflow/uiPolicy.ts
|
|
5531
|
+
var addFieldUiPolicyForType = (typeName) => {
|
|
5532
|
+
const normalizedType = typeName.toLowerCase() === "enum" ? "enum" : normalizeFieldType(typeName);
|
|
5533
|
+
if (normalizedType === "Int" || normalizedType === "Float") {
|
|
5534
|
+
return {
|
|
5535
|
+
normalizedType,
|
|
5536
|
+
component: "Field.Number",
|
|
5537
|
+
confidence: "high",
|
|
5538
|
+
autoTemplateSupported: true
|
|
5539
|
+
};
|
|
5540
|
+
}
|
|
5541
|
+
if (normalizedType === "Date") {
|
|
5542
|
+
return {
|
|
5543
|
+
normalizedType,
|
|
5544
|
+
component: "Field.Date",
|
|
5545
|
+
confidence: "high",
|
|
5546
|
+
autoTemplateSupported: true
|
|
5547
|
+
};
|
|
5548
|
+
}
|
|
5549
|
+
if (normalizedType === "Boolean" || normalizedType === "enum") {
|
|
5550
|
+
return {
|
|
5551
|
+
normalizedType,
|
|
5552
|
+
component: "Field.ToggleSelect",
|
|
5553
|
+
confidence: "medium",
|
|
5554
|
+
autoTemplateSupported: false
|
|
5555
|
+
};
|
|
5556
|
+
}
|
|
5557
|
+
if (normalizedType === "String") {
|
|
5558
|
+
return {
|
|
5559
|
+
normalizedType,
|
|
5560
|
+
component: "Field.Text",
|
|
5561
|
+
confidence: "high",
|
|
5562
|
+
autoTemplateSupported: true
|
|
5563
|
+
};
|
|
5564
|
+
}
|
|
5565
|
+
return {
|
|
5566
|
+
normalizedType,
|
|
5567
|
+
component: "Field.Text",
|
|
5568
|
+
confidence: "low",
|
|
5569
|
+
autoTemplateSupported: false
|
|
5570
|
+
};
|
|
5571
|
+
};
|
|
5572
|
+
|
|
5573
|
+
// pkgs/@akanjs/devkit/workflow/executor.ts
|
|
5574
|
+
var workflowStepKey = (workflow, stepId) => `${workflow}:${stepId}`;
|
|
5575
|
+
var primitiveReportToWorkflowStepResult = (report) => ({
|
|
5576
|
+
changedFiles: report.changedFiles,
|
|
5577
|
+
generatedFiles: report.generatedFiles,
|
|
5578
|
+
commands: report.validationCommands,
|
|
5579
|
+
diagnostics: report.diagnostics,
|
|
5580
|
+
recommendations: [],
|
|
5581
|
+
nextActions: report.nextActions
|
|
5582
|
+
});
|
|
5583
|
+
var workflowStringInput = (value) => typeof value === "string" ? value : null;
|
|
5584
|
+
var workflowStringListInput = (value) => Array.isArray(value) ? value.join(",") : null;
|
|
5585
|
+
var workflowStringArrayInput = (value) => Array.isArray(value) ? value : null;
|
|
5586
|
+
var workflowBooleanInput = (value) => typeof value === "boolean" ? value : null;
|
|
5587
|
+
var postApplyDiagnostic = (code, message, target) => ({
|
|
5588
|
+
severity: "error",
|
|
5589
|
+
code,
|
|
5590
|
+
message,
|
|
5591
|
+
failureScope: "source-change",
|
|
5592
|
+
context: { target }
|
|
5593
|
+
});
|
|
5594
|
+
var sourceKindForPath = (filePath) => {
|
|
5595
|
+
if (filePath.endsWith(".tsx"))
|
|
5596
|
+
return ts4.ScriptKind.TSX;
|
|
5597
|
+
if (filePath.endsWith(".ts"))
|
|
5598
|
+
return ts4.ScriptKind.TS;
|
|
5599
|
+
return null;
|
|
5600
|
+
};
|
|
5601
|
+
var checkPathCasing = async (workspace, filePath) => {
|
|
5602
|
+
const segments = filePath.split("/").filter(Boolean);
|
|
5603
|
+
let current = ".";
|
|
5604
|
+
for (const segment of segments) {
|
|
5605
|
+
const entries = await workspace.readdir(current);
|
|
5606
|
+
if (entries.includes(segment)) {
|
|
5607
|
+
current = current === "." ? segment : `${current}/${segment}`;
|
|
5608
|
+
continue;
|
|
5609
|
+
}
|
|
5610
|
+
const caseInsensitiveMatch = entries.find((entry) => entry.toLowerCase() === segment.toLowerCase());
|
|
5611
|
+
return caseInsensitiveMatch ? {
|
|
5612
|
+
code: "workflow-path-casing-mismatch",
|
|
5613
|
+
message: `Reported path segment "${segment}" does not match actual casing "${caseInsensitiveMatch}" in ${filePath}.`
|
|
5614
|
+
} : {
|
|
5615
|
+
code: "workflow-path-missing",
|
|
5616
|
+
message: `Reported path does not exist: ${filePath}.`
|
|
5617
|
+
};
|
|
5618
|
+
}
|
|
5619
|
+
return null;
|
|
5620
|
+
};
|
|
5621
|
+
var checkTypeScriptSyntax = async (workspace, filePath) => {
|
|
5622
|
+
const scriptKind = sourceKindForPath(filePath);
|
|
5623
|
+
if (!scriptKind)
|
|
5624
|
+
return null;
|
|
5625
|
+
const content = await workspace.readFile(filePath);
|
|
5626
|
+
const source = ts4.createSourceFile(filePath, content, ts4.ScriptTarget.Latest, true, scriptKind);
|
|
5627
|
+
const diagnostic = source.parseDiagnostics[0];
|
|
5628
|
+
if (!diagnostic)
|
|
5629
|
+
return null;
|
|
5630
|
+
const position = diagnostic.file?.getLineAndCharacterOfPosition(diagnostic.start ?? 0);
|
|
5631
|
+
const location = position ? `:${position.line + 1}:${position.character + 1}` : "";
|
|
5632
|
+
return {
|
|
5633
|
+
code: "workflow-post-apply-syntax-error",
|
|
5634
|
+
message: `Generated source has a TypeScript syntax error at ${filePath}${location}: ${ts4.flattenDiagnosticMessageText(diagnostic.messageText, " ")}`
|
|
5635
|
+
};
|
|
5636
|
+
};
|
|
5637
|
+
var checkChangedFile = async (workspace, file) => {
|
|
5638
|
+
if (file.action === "remove")
|
|
5639
|
+
return { postApplyChecks: [] };
|
|
5640
|
+
const diagnostics = [];
|
|
5641
|
+
const checks = [];
|
|
5642
|
+
const pathIssue = await checkPathCasing(workspace, file.path);
|
|
5643
|
+
if (pathIssue) {
|
|
5644
|
+
diagnostics.push(postApplyDiagnostic(pathIssue.code, pathIssue.message, file.path));
|
|
5645
|
+
checks.push({ ...pathIssue, target: file.path, status: "failed" });
|
|
5646
|
+
return { diagnostics, postApplyChecks: checks };
|
|
5647
|
+
}
|
|
5648
|
+
const syntaxIssue = await checkTypeScriptSyntax(workspace, file.path);
|
|
5649
|
+
if (syntaxIssue) {
|
|
5650
|
+
diagnostics.push(postApplyDiagnostic(syntaxIssue.code, syntaxIssue.message, file.path));
|
|
5651
|
+
checks.push({ ...syntaxIssue, target: file.path, status: "failed" });
|
|
5652
|
+
return { diagnostics, postApplyChecks: checks };
|
|
5653
|
+
}
|
|
5654
|
+
checks.push({
|
|
5655
|
+
code: "workflow-post-apply-file-valid",
|
|
5656
|
+
target: file.path,
|
|
5657
|
+
status: "passed",
|
|
5658
|
+
message: "Changed file exists with exact casing and parses as source when applicable."
|
|
5659
|
+
});
|
|
5660
|
+
return { postApplyChecks: checks };
|
|
5661
|
+
};
|
|
5662
|
+
var checkRecommendationPath = async (workspace, recommendation) => {
|
|
5663
|
+
if (!recommendation.target || recommendation.target.includes("*") || recommendation.target.startsWith("<"))
|
|
5664
|
+
return null;
|
|
5665
|
+
const pathIssue = await checkPathCasing(workspace, recommendation.target);
|
|
5666
|
+
if (!pathIssue)
|
|
5667
|
+
return null;
|
|
5668
|
+
return {
|
|
5669
|
+
severity: "warning",
|
|
5670
|
+
code: "workflow-recommendation-path-unverified",
|
|
5671
|
+
message: `${pathIssue.message} Recommendation "${recommendation.code}" should not be treated as an exact file target until the path is corrected.`,
|
|
5672
|
+
failureScope: "source-change",
|
|
5673
|
+
context: { target: recommendation.target }
|
|
5674
|
+
};
|
|
5675
|
+
};
|
|
5676
|
+
var resolveWorkflowSys = async (workspace, target) => {
|
|
5677
|
+
if (!target)
|
|
5678
|
+
return null;
|
|
5679
|
+
const [apps, libs] = await workspace.getSyss();
|
|
5680
|
+
if (apps.includes(target))
|
|
5681
|
+
return AppExecutor.from(workspace, target);
|
|
5682
|
+
if (libs.includes(target))
|
|
5683
|
+
return LibExecutor.from(workspace, target);
|
|
5684
|
+
return null;
|
|
5685
|
+
};
|
|
5686
|
+
var targetMissing = (input2 = "app") => ({
|
|
5687
|
+
severity: "error",
|
|
5688
|
+
code: "workflow-target-missing",
|
|
5689
|
+
input: input2,
|
|
5690
|
+
message: "Workflow target app or library was not found."
|
|
5691
|
+
});
|
|
5692
|
+
var inputMissing = (input2) => ({
|
|
5693
|
+
severity: "error",
|
|
5694
|
+
code: "workflow-input-missing",
|
|
5695
|
+
input: input2,
|
|
5696
|
+
message: `Workflow input "${input2}" is required for apply.`
|
|
5697
|
+
});
|
|
5698
|
+
var unsupportedInput = (input2, message) => ({
|
|
5699
|
+
severity: "error",
|
|
5700
|
+
code: "workflow-input-unsupported",
|
|
5701
|
+
input: input2,
|
|
5702
|
+
message
|
|
5703
|
+
});
|
|
5704
|
+
var addFieldUiSurfaceInspection = (plan) => {
|
|
5705
|
+
const app = workflowStringInput(plan.inputs.app);
|
|
5706
|
+
const module = workflowStringInput(plan.inputs.module) ?? "<module>";
|
|
5707
|
+
const field = workflowStringInput(plan.inputs.field) ?? "<field>";
|
|
5708
|
+
const typeName = workflowStringInput(plan.inputs.type);
|
|
5709
|
+
const policy = addFieldUiPolicyForType(typeName ?? "String");
|
|
5710
|
+
const surfaces = workflowStringArrayInput(plan.inputs.surfaces);
|
|
5711
|
+
const templateRequested = surfaces?.includes("template") ?? false;
|
|
5712
|
+
const moduleClassName = capitalize2(module);
|
|
5713
|
+
const target = `${app ? `apps/${app}` : "*"}/${moduleSourcePaths(module).template}`;
|
|
5714
|
+
return {
|
|
5715
|
+
recommendations: [
|
|
5716
|
+
{
|
|
5717
|
+
code: "add-field-ui-surface-review",
|
|
5718
|
+
kind: "manual-action",
|
|
5719
|
+
target,
|
|
5720
|
+
action: templateRequested ? `Template was requested for ${field}. If no Template file changed, auto-edit was skipped because the file was missing, the generated ${module}Form/Layout.Template pattern was not found, or ${policy.component} needs option binding. Candidate position: inside Layout.Template near the existing Field components.` : `Template was not selected, so UI files are intentionally left unchanged. Candidate positions if you expose it later: Layout.Template field list for editing, Light${moduleClassName} projection for list/card data, and Unit/View card sections for display.`,
|
|
5721
|
+
confidence: "medium",
|
|
5722
|
+
message: `Review UI surfaces for ${module}.${field}; recommended component is ${policy.component}, with manual reasons and candidate positions in action.`
|
|
5723
|
+
}
|
|
5724
|
+
],
|
|
5725
|
+
nextActions: [
|
|
5726
|
+
{
|
|
5727
|
+
command: `akan workflow explain ${plan.workflow}`,
|
|
5728
|
+
reason: "Review UI surface guidance before manually editing ambiguous UI files."
|
|
5729
|
+
}
|
|
5730
|
+
]
|
|
5731
|
+
};
|
|
5732
|
+
};
|
|
5733
|
+
var createWorkflowStepRegistry = ({
|
|
5734
|
+
workspace,
|
|
5735
|
+
createModule,
|
|
5736
|
+
createScalar,
|
|
5737
|
+
createUi,
|
|
5738
|
+
addField,
|
|
5739
|
+
addEnumField
|
|
5740
|
+
}) => {
|
|
5741
|
+
const inspect = async () => {
|
|
5742
|
+
return;
|
|
5743
|
+
};
|
|
5744
|
+
const commandOnly = async () => {
|
|
5745
|
+
return;
|
|
5746
|
+
};
|
|
5747
|
+
return {
|
|
5748
|
+
inspectSystem: inspect,
|
|
5749
|
+
inspectModule: inspect,
|
|
5750
|
+
syncTarget: commandOnly,
|
|
5751
|
+
lintTarget: commandOnly,
|
|
5752
|
+
[workflowStepKey("create-module", "create-module")]: async (_step, plan) => {
|
|
5753
|
+
const app = workflowStringInput(plan.inputs.app);
|
|
5754
|
+
const module = workflowStringInput(plan.inputs.module);
|
|
5755
|
+
const sys2 = await resolveWorkflowSys(workspace, app);
|
|
5756
|
+
if (!sys2 || !module)
|
|
5757
|
+
return { diagnostics: [!sys2 ? targetMissing() : inputMissing("module")] };
|
|
5758
|
+
return primitiveReportToWorkflowStepResult(await createModule(sys2, module));
|
|
5759
|
+
},
|
|
5760
|
+
[workflowStepKey("create-scalar", "create-scalar")]: async (_step, plan) => {
|
|
5761
|
+
const app = workflowStringInput(plan.inputs.app);
|
|
5762
|
+
const scalar = workflowStringInput(plan.inputs.scalar);
|
|
5763
|
+
const sys2 = await resolveWorkflowSys(workspace, app);
|
|
5764
|
+
if (!sys2 || !scalar)
|
|
5765
|
+
return { diagnostics: [!sys2 ? targetMissing() : inputMissing("scalar")] };
|
|
5766
|
+
return primitiveReportToWorkflowStepResult(await createScalar(sys2, scalar));
|
|
5767
|
+
},
|
|
5768
|
+
[workflowStepKey("create-ui", "create-ui")]: async (_step, plan) => {
|
|
5769
|
+
const surface = workflowStringInput(plan.inputs.surface);
|
|
5770
|
+
if (surface !== "view" && surface !== "unit" && surface !== "template") {
|
|
5771
|
+
return {
|
|
5772
|
+
diagnostics: [
|
|
5773
|
+
unsupportedInput("surface", "Workflow apply currently supports create-ui surfaces: view, unit, template.")
|
|
5774
|
+
]
|
|
5775
|
+
};
|
|
5776
|
+
}
|
|
5777
|
+
return primitiveReportToWorkflowStepResult(await createUi({
|
|
5778
|
+
app: workflowStringInput(plan.inputs.app),
|
|
5779
|
+
module: workflowStringInput(plan.inputs.module),
|
|
5780
|
+
surface
|
|
5781
|
+
}));
|
|
5782
|
+
},
|
|
5783
|
+
[workflowStepKey("add-field", "update-constant")]: async (_step, plan) => {
|
|
5784
|
+
if (workflowStringInput(plan.inputs.type)?.toLowerCase() === "enum") {
|
|
5785
|
+
return primitiveReportToWorkflowStepResult(await addEnumField({
|
|
5786
|
+
app: workflowStringInput(plan.inputs.app),
|
|
5787
|
+
module: workflowStringInput(plan.inputs.module),
|
|
5788
|
+
field: workflowStringInput(plan.inputs.field),
|
|
5789
|
+
values: workflowStringListInput(plan.inputs.values),
|
|
5790
|
+
defaultValue: workflowStringInput(plan.inputs.default),
|
|
5791
|
+
surfaces: workflowStringArrayInput(plan.inputs.surfaces),
|
|
5792
|
+
includeInLight: workflowBooleanInput(plan.inputs.includeInLight)
|
|
5793
|
+
}));
|
|
5794
|
+
}
|
|
5795
|
+
return primitiveReportToWorkflowStepResult(await addField({
|
|
5796
|
+
app: workflowStringInput(plan.inputs.app),
|
|
5797
|
+
module: workflowStringInput(plan.inputs.module),
|
|
5798
|
+
field: workflowStringInput(plan.inputs.field),
|
|
5799
|
+
type: workflowStringInput(plan.inputs.type),
|
|
5800
|
+
defaultValue: workflowStringInput(plan.inputs.default),
|
|
5801
|
+
surfaces: workflowStringArrayInput(plan.inputs.surfaces),
|
|
5802
|
+
includeInLight: workflowBooleanInput(plan.inputs.includeInLight)
|
|
5803
|
+
}));
|
|
5804
|
+
},
|
|
5805
|
+
[workflowStepKey("add-field", "update-dictionary")]: inspect,
|
|
5806
|
+
[workflowStepKey("add-field", "update-ui-surfaces")]: async (_step, plan) => addFieldUiSurfaceInspection(plan),
|
|
5807
|
+
[workflowStepKey("add-enum-field", "update-constant")]: async (_step, plan) => primitiveReportToWorkflowStepResult(await addEnumField({
|
|
5808
|
+
app: workflowStringInput(plan.inputs.app),
|
|
5809
|
+
module: workflowStringInput(plan.inputs.module),
|
|
5810
|
+
field: workflowStringInput(plan.inputs.field),
|
|
5811
|
+
values: workflowStringListInput(plan.inputs.values),
|
|
5812
|
+
defaultValue: workflowStringInput(plan.inputs.default)
|
|
5813
|
+
})),
|
|
5814
|
+
[workflowStepKey("add-enum-field", "update-dictionary")]: inspect,
|
|
5815
|
+
[workflowStepKey("add-enum-field", "update-option")]: inspect
|
|
5816
|
+
};
|
|
5455
5817
|
};
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
|
|
5461
|
-
|
|
5462
|
-
const names = existingImport[1]?.split(",").map((name) => name.trim()) ?? [];
|
|
5463
|
-
return content.replace(existingImport[0], `import type { ${[...names, typeName].sort().join(", ")} } from "${constantPath}";`);
|
|
5818
|
+
class WorkflowExecutor {
|
|
5819
|
+
registry;
|
|
5820
|
+
workspace;
|
|
5821
|
+
constructor(registry, workspace) {
|
|
5822
|
+
this.registry = registry;
|
|
5823
|
+
this.workspace = workspace;
|
|
5464
5824
|
}
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5468
|
-
|
|
5469
|
-
|
|
5470
|
-
|
|
5471
|
-
|
|
5472
|
-
|
|
5473
|
-
|
|
5474
|
-
|
|
5475
|
-
|
|
5476
|
-
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
5480
|
-
|
|
5481
|
-
|
|
5482
|
-
|
|
5483
|
-
|
|
5825
|
+
async apply(plan) {
|
|
5826
|
+
const changedFiles = [];
|
|
5827
|
+
const generatedFiles = [];
|
|
5828
|
+
const recommendedValidationCommands = [];
|
|
5829
|
+
const diagnostics = [...plan.diagnostics];
|
|
5830
|
+
const postApplyChecks = [];
|
|
5831
|
+
const recommendations = [...plan.recommendations];
|
|
5832
|
+
const nextActions = [];
|
|
5833
|
+
if (diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
|
|
5834
|
+
return createWorkflowApplyReport({
|
|
5835
|
+
workflow: plan.workflow,
|
|
5836
|
+
mode: "apply",
|
|
5837
|
+
changedFiles,
|
|
5838
|
+
generatedFiles,
|
|
5839
|
+
recommendedValidationCommands,
|
|
5840
|
+
diagnostics,
|
|
5841
|
+
postApplyChecks,
|
|
5842
|
+
recommendations,
|
|
5843
|
+
nextActions,
|
|
5844
|
+
plan
|
|
5845
|
+
});
|
|
5846
|
+
}
|
|
5847
|
+
recommendedValidationCommands.push(...workflowCommandsForPlan(plan));
|
|
5848
|
+
nextActions.push(...workflowCommandsForPlan(plan));
|
|
5849
|
+
for (const step of plan.steps) {
|
|
5850
|
+
const runner = this.registry[workflowStepKey(plan.workflow, step.id)] ?? this.registry[step.tool] ?? this.registry[step.id];
|
|
5851
|
+
if (!runner) {
|
|
5852
|
+
diagnostics.push({
|
|
5853
|
+
severity: "error",
|
|
5854
|
+
code: "workflow-step-unsupported",
|
|
5855
|
+
message: `Workflow ${plan.workflow} step "${step.id}" is not supported by workflow apply yet.`
|
|
5856
|
+
});
|
|
5857
|
+
nextActions.push({
|
|
5858
|
+
command: `akan workflow explain ${plan.workflow}`,
|
|
5859
|
+
reason: "Review the unsupported workflow step before retrying apply."
|
|
5860
|
+
});
|
|
5861
|
+
break;
|
|
5862
|
+
}
|
|
5863
|
+
const result = await runner(step, plan);
|
|
5864
|
+
if (!result)
|
|
5865
|
+
continue;
|
|
5866
|
+
changedFiles.push(...result.changedFiles ?? []);
|
|
5867
|
+
generatedFiles.push(...result.generatedFiles ?? []);
|
|
5868
|
+
recommendedValidationCommands.push(...result.commands ?? []);
|
|
5869
|
+
diagnostics.push(...result.diagnostics ?? []);
|
|
5870
|
+
recommendations.push(...result.recommendations ?? []);
|
|
5871
|
+
nextActions.push(...result.nextActions ?? []);
|
|
5872
|
+
if (diagnostics.some((diagnostic) => diagnostic.severity === "error"))
|
|
5873
|
+
break;
|
|
5874
|
+
}
|
|
5875
|
+
if (this.workspace && !diagnostics.some((diagnostic) => diagnostic.severity === "error")) {
|
|
5876
|
+
for (const file of changedFiles) {
|
|
5877
|
+
const result = await checkChangedFile(this.workspace, file);
|
|
5878
|
+
postApplyChecks.push(...result.postApplyChecks ?? []);
|
|
5879
|
+
diagnostics.push(...result.diagnostics ?? []);
|
|
5880
|
+
}
|
|
5881
|
+
const recommendationDiagnostics = await Promise.all(recommendations.map((recommendation) => checkRecommendationPath(this.workspace, recommendation)));
|
|
5882
|
+
diagnostics.push(...recommendationDiagnostics.filter((diagnostic) => !!diagnostic));
|
|
5883
|
+
}
|
|
5884
|
+
return createWorkflowApplyReport({
|
|
5885
|
+
workflow: plan.workflow,
|
|
5886
|
+
mode: "apply",
|
|
5887
|
+
changedFiles,
|
|
5888
|
+
generatedFiles,
|
|
5889
|
+
recommendedValidationCommands,
|
|
5890
|
+
diagnostics,
|
|
5891
|
+
postApplyChecks,
|
|
5892
|
+
recommendations,
|
|
5893
|
+
nextActions,
|
|
5894
|
+
plan
|
|
5895
|
+
});
|
|
5896
|
+
}
|
|
5897
|
+
}
|
|
5484
5898
|
// pkgs/@akanjs/devkit/workflow/plan.ts
|
|
5899
|
+
import { capitalize as capitalize3 } from "akanjs/common";
|
|
5485
5900
|
var surfaceModes = new Set(["infer", "include", "skip"]);
|
|
5486
5901
|
var parseStringList = (value) => {
|
|
5487
5902
|
if (Array.isArray(value)) {
|
|
@@ -5499,6 +5914,18 @@ var normalizeInputValue = (name, spec, value) => {
|
|
|
5499
5914
|
const values = parseStringList(value);
|
|
5500
5915
|
return values && values.length > 0 ? values : null;
|
|
5501
5916
|
}
|
|
5917
|
+
if (spec.type === "boolean") {
|
|
5918
|
+
if (typeof value === "boolean")
|
|
5919
|
+
return value;
|
|
5920
|
+
if (typeof value !== "string")
|
|
5921
|
+
return null;
|
|
5922
|
+
const lowered = value.trim().toLowerCase();
|
|
5923
|
+
if (lowered === "true")
|
|
5924
|
+
return true;
|
|
5925
|
+
if (lowered === "false")
|
|
5926
|
+
return false;
|
|
5927
|
+
return null;
|
|
5928
|
+
}
|
|
5502
5929
|
if (typeof value === "string" && surfaceModes.has(value))
|
|
5503
5930
|
return value;
|
|
5504
5931
|
throw new Error(`Unsupported workflow input value for ${name}`);
|
|
@@ -5506,17 +5933,45 @@ var normalizeInputValue = (name, spec, value) => {
|
|
|
5506
5933
|
var listWorkflowSpecs = (specs) => [...specs].sort((a, b) => a.name.localeCompare(b.name));
|
|
5507
5934
|
var getWorkflowSpec = (specs, name) => specs.find((spec) => spec.name === name) ?? null;
|
|
5508
5935
|
var compactWorkflowInputs = (inputs) => Object.fromEntries(Object.entries(inputs).filter(([, value]) => value !== null && value !== ""));
|
|
5509
|
-
var
|
|
5510
|
-
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5936
|
+
var addFieldTargetRoot = (app) => app ? `apps/${app}` : "*";
|
|
5937
|
+
var addFieldPaths = (inputs) => {
|
|
5938
|
+
const app = typeof inputs.app === "string" ? inputs.app : null;
|
|
5939
|
+
const module = typeof inputs.module === "string" ? inputs.module : "<module>";
|
|
5940
|
+
const paths = moduleSourcePaths(module);
|
|
5941
|
+
const root = addFieldTargetRoot(app);
|
|
5942
|
+
return {
|
|
5943
|
+
constant: `${root}/${paths.constant}`,
|
|
5944
|
+
dictionary: `${root}/${paths.dictionary}`,
|
|
5945
|
+
template: `${root}/${paths.template}`,
|
|
5946
|
+
unit: `${root}/${paths.unit}`,
|
|
5947
|
+
view: `${root}/${paths.view}`
|
|
5948
|
+
};
|
|
5949
|
+
};
|
|
5950
|
+
var selectedAddFieldSurfaces = (inputs) => Array.isArray(inputs.surfaces) ? new Set(inputs.surfaces) : null;
|
|
5951
|
+
var addFieldDefaultCoercion = (inputs) => {
|
|
5952
|
+
const typeName = typeof inputs.type === "string" ? inputs.type : null;
|
|
5953
|
+
const defaultValue = typeof inputs.default === "string" ? inputs.default : null;
|
|
5954
|
+
if (!typeName || defaultValue === null)
|
|
5955
|
+
return null;
|
|
5956
|
+
if (typeName.toLowerCase() === "number" || typeName.toLowerCase() === "numeric")
|
|
5957
|
+
return null;
|
|
5958
|
+
const enumValues = Array.isArray(inputs.values) ? inputs.values : null;
|
|
5959
|
+
return coerceFieldDefault(typeName.toLowerCase() === "enum" ? "enum" : typeName, defaultValue, { enumValues });
|
|
5960
|
+
};
|
|
5961
|
+
var createAddFieldDefaultRecommendations = (inputs) => {
|
|
5962
|
+
const field = typeof inputs.field === "string" ? inputs.field : "<field>";
|
|
5963
|
+
const coercion = addFieldDefaultCoercion(inputs);
|
|
5964
|
+
if (!coercion?.normalized || !coercion.expression)
|
|
5965
|
+
return [];
|
|
5966
|
+
return [
|
|
5967
|
+
{
|
|
5968
|
+
code: "add-field-default-normalized",
|
|
5969
|
+
kind: "manual-action",
|
|
5970
|
+
confidence: "high",
|
|
5971
|
+
message: `Default for ${field} will be normalized to ${coercion.normalizedType} literal ${coercion.expression}.`,
|
|
5972
|
+
action: "Review the normalized default in the apply report if this value should stay unset."
|
|
5973
|
+
}
|
|
5974
|
+
];
|
|
5520
5975
|
};
|
|
5521
5976
|
var createAddFieldRecommendations = (inputs) => {
|
|
5522
5977
|
const app = typeof inputs.app === "string" ? inputs.app : "<app-or-lib>";
|
|
@@ -5525,16 +5980,18 @@ var createAddFieldRecommendations = (inputs) => {
|
|
|
5525
5980
|
const typeName = typeof inputs.type === "string" ? inputs.type : null;
|
|
5526
5981
|
if (!typeName)
|
|
5527
5982
|
return [];
|
|
5528
|
-
const
|
|
5529
|
-
const
|
|
5530
|
-
const
|
|
5531
|
-
const
|
|
5983
|
+
const policy = addFieldUiPolicyForType(typeName);
|
|
5984
|
+
const normalizedType = policy.normalizedType;
|
|
5985
|
+
const paths = addFieldPaths(inputs);
|
|
5986
|
+
const surfaces = selectedAddFieldSurfaces(inputs);
|
|
5987
|
+
const templateRequested = surfaces?.has("template") ?? false;
|
|
5988
|
+
const includeInLight = inputs.includeInLight === true;
|
|
5532
5989
|
return [
|
|
5533
5990
|
...normalizedType === "Int" || normalizedType === "Float" ? [
|
|
5534
5991
|
{
|
|
5535
5992
|
code: "add-field-import",
|
|
5536
5993
|
kind: "import",
|
|
5537
|
-
target:
|
|
5994
|
+
target: paths.constant,
|
|
5538
5995
|
confidence: "high",
|
|
5539
5996
|
message: `Import ${normalizedType} from "akanjs/base" before writing field(${normalizedType}).`
|
|
5540
5997
|
}
|
|
@@ -5542,35 +5999,122 @@ var createAddFieldRecommendations = (inputs) => {
|
|
|
5542
5999
|
{
|
|
5543
6000
|
code: "add-field-placement-constant",
|
|
5544
6001
|
kind: "placement",
|
|
5545
|
-
target:
|
|
6002
|
+
target: paths.constant,
|
|
5546
6003
|
confidence: "high",
|
|
5547
6004
|
message: `Insert ${field}: field(${normalizedType}) in ${capitalize3(module)}Input.`
|
|
5548
6005
|
},
|
|
5549
6006
|
{
|
|
5550
6007
|
code: "add-field-placement-dictionary",
|
|
5551
6008
|
kind: "placement",
|
|
5552
|
-
target:
|
|
6009
|
+
target: paths.dictionary,
|
|
5553
6010
|
confidence: "high",
|
|
5554
6011
|
message: `Add dictionary labels for ${module}.${field}.`
|
|
5555
6012
|
},
|
|
5556
6013
|
{
|
|
5557
6014
|
code: "add-field-component",
|
|
5558
6015
|
kind: "ui-component",
|
|
5559
|
-
target:
|
|
5560
|
-
confidence:
|
|
5561
|
-
action:
|
|
5562
|
-
message:
|
|
6016
|
+
target: paths.template,
|
|
6017
|
+
confidence: policy.confidence,
|
|
6018
|
+
action: templateRequested ? `apply_workflow will try to add ${policy.component} to Template when the existing Template has a safe generated field-list pattern.` : `Recommended component is ${policy.component}. Pass surfaces=["template"] when this field should be rendered in the Template form.`,
|
|
6019
|
+
message: `Recommended UI component for ${field} (${normalizedType}): ${policy.component}.`
|
|
5563
6020
|
},
|
|
6021
|
+
...!surfaces ? [
|
|
6022
|
+
{
|
|
6023
|
+
code: "add-field-template-surface-choice",
|
|
6024
|
+
kind: "manual-action",
|
|
6025
|
+
target: paths.template,
|
|
6026
|
+
action: `Choose whether to expose ${field} in Template by passing surfaces=["template"].`,
|
|
6027
|
+
confidence: "medium",
|
|
6028
|
+
message: `Template exposure for ${module}.${field} is not selected yet.`
|
|
6029
|
+
}
|
|
6030
|
+
] : [],
|
|
6031
|
+
...!includeInLight ? [
|
|
6032
|
+
{
|
|
6033
|
+
code: "add-field-light-projection-choice",
|
|
6034
|
+
kind: "manual-action",
|
|
6035
|
+
target: paths.constant,
|
|
6036
|
+
action: `Pass includeInLight=true when ${field} should appear in Light${capitalize3(module)} list/card projections.`,
|
|
6037
|
+
confidence: "medium",
|
|
6038
|
+
message: `Light projection exposure for ${module}.${field} is not selected yet.`
|
|
6039
|
+
}
|
|
6040
|
+
] : [],
|
|
6041
|
+
...includeInLight ? [
|
|
6042
|
+
{
|
|
6043
|
+
code: "add-field-light-projection",
|
|
6044
|
+
kind: "placement",
|
|
6045
|
+
target: paths.constant,
|
|
6046
|
+
confidence: "high",
|
|
6047
|
+
message: `Add ${field} to Light${capitalize3(module)} projection fields.`
|
|
6048
|
+
}
|
|
6049
|
+
] : [],
|
|
6050
|
+
...surfaces && !templateRequested ? [
|
|
6051
|
+
{
|
|
6052
|
+
code: "add-field-ui-surface-skip",
|
|
6053
|
+
kind: "manual-action",
|
|
6054
|
+
target: paths.template,
|
|
6055
|
+
confidence: "medium",
|
|
6056
|
+
message: `Template is not included in surfaces, so ${module}.${field} will not be auto-rendered there.`
|
|
6057
|
+
}
|
|
6058
|
+
] : [],
|
|
5564
6059
|
{
|
|
5565
6060
|
code: "add-field-ui-manual-review",
|
|
5566
6061
|
kind: "manual-action",
|
|
5567
|
-
target:
|
|
5568
|
-
action: `Review ${app}:${module} Template
|
|
6062
|
+
target: paths.template,
|
|
6063
|
+
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${capitalize3(module)} projection array for list data, and Unit/View card sections for display.`,
|
|
5569
6064
|
confidence: "medium",
|
|
5570
|
-
message:
|
|
6065
|
+
message: "UI manual review includes the reason auto-edit may be skipped and candidate insertion positions."
|
|
6066
|
+
},
|
|
6067
|
+
...createAddFieldDefaultRecommendations(inputs)
|
|
6068
|
+
];
|
|
6069
|
+
};
|
|
6070
|
+
var createWorkflowPlanPredictedChanges = (spec, inputs) => {
|
|
6071
|
+
if (spec.name !== "add-field")
|
|
6072
|
+
return spec.predictedChanges;
|
|
6073
|
+
const paths = addFieldPaths(inputs);
|
|
6074
|
+
const surfaces = selectedAddFieldSurfaces(inputs);
|
|
6075
|
+
const includeInLight = inputs.includeInLight === true;
|
|
6076
|
+
return [
|
|
6077
|
+
{
|
|
6078
|
+
target: paths.constant,
|
|
6079
|
+
action: "modify",
|
|
6080
|
+
applyScope: "auto",
|
|
6081
|
+
reason: includeInLight ? "Field shape and Light projection are added." : "Field shape is added."
|
|
6082
|
+
},
|
|
6083
|
+
{
|
|
6084
|
+
target: paths.dictionary,
|
|
6085
|
+
action: "modify",
|
|
6086
|
+
applyScope: "auto",
|
|
6087
|
+
reason: "Field label is added."
|
|
6088
|
+
},
|
|
6089
|
+
...!surfaces || surfaces.has("template") ? [
|
|
6090
|
+
{
|
|
6091
|
+
target: paths.template,
|
|
6092
|
+
action: "modify",
|
|
6093
|
+
applyScope: surfaces?.has("template") ? "auto" : "manual-review",
|
|
6094
|
+
reason: surfaces?.has("template") ? "Template form is selected for safe-pattern auto insertion." : "Form surface may include the field."
|
|
6095
|
+
}
|
|
6096
|
+
] : [],
|
|
6097
|
+
{
|
|
6098
|
+
target: `${addFieldTargetRoot(typeof inputs.app === "string" ? inputs.app : null)}/lib/cnst.ts`,
|
|
6099
|
+
action: "sync",
|
|
6100
|
+
applyScope: "generated-sync",
|
|
6101
|
+
reason: "Generated constants may change after sync."
|
|
6102
|
+
},
|
|
6103
|
+
{
|
|
6104
|
+
target: `${addFieldTargetRoot(typeof inputs.app === "string" ? inputs.app : null)}/lib/dict.ts`,
|
|
6105
|
+
action: "sync",
|
|
6106
|
+
applyScope: "generated-sync",
|
|
6107
|
+
reason: "Generated dictionary barrel may change after sync."
|
|
5571
6108
|
}
|
|
5572
6109
|
];
|
|
5573
6110
|
};
|
|
6111
|
+
var createWorkflowPlanOptionalSurfaces = (spec, inputs) => {
|
|
6112
|
+
const optionalSurfaces = spec.optionalSurfaces ?? {};
|
|
6113
|
+
const surfaces = selectedAddFieldSurfaces(inputs);
|
|
6114
|
+
if (spec.name !== "add-field" || !surfaces)
|
|
6115
|
+
return optionalSurfaces;
|
|
6116
|
+
return Object.fromEntries(Object.entries(optionalSurfaces).map(([surface, mode]) => [surface, surfaces.has(surface) ? "include" : mode]));
|
|
6117
|
+
};
|
|
5574
6118
|
var createWorkflowPlanRecommendations = (spec, inputs) => [
|
|
5575
6119
|
{
|
|
5576
6120
|
code: "workflow-apply-first",
|
|
@@ -5634,14 +6178,32 @@ var createWorkflowPlan = (spec, rawInputs) => {
|
|
|
5634
6178
|
message: `Field type "${fieldType}" is ambiguous in Akan. Use Int for integer fields or Float for decimal fields.`
|
|
5635
6179
|
});
|
|
5636
6180
|
}
|
|
6181
|
+
if (spec.name === "add-field") {
|
|
6182
|
+
const defaultCoercion = addFieldDefaultCoercion(inputs);
|
|
6183
|
+
if (defaultCoercion?.diagnostic) {
|
|
6184
|
+
diagnostics.push({
|
|
6185
|
+
...defaultCoercion.diagnostic,
|
|
6186
|
+
code: "workflow-default-value-invalid",
|
|
6187
|
+
message: `Plan input default is not valid for ${defaultCoercion.normalizedType}: ${defaultCoercion.diagnostic.message}`
|
|
6188
|
+
});
|
|
6189
|
+
} else if (defaultCoercion?.normalized && defaultCoercion.expression) {
|
|
6190
|
+
diagnostics.push({
|
|
6191
|
+
severity: "warning",
|
|
6192
|
+
code: "workflow-default-value-normalized",
|
|
6193
|
+
input: "default",
|
|
6194
|
+
failureScope: "source-change",
|
|
6195
|
+
message: `Plan input default will be written as ${defaultCoercion.normalizedType} literal ${defaultCoercion.expression}.`
|
|
6196
|
+
});
|
|
6197
|
+
}
|
|
6198
|
+
}
|
|
5637
6199
|
return {
|
|
5638
6200
|
schemaVersion: 1,
|
|
5639
6201
|
workflow: spec.name,
|
|
5640
6202
|
mode: "plan",
|
|
5641
6203
|
inputs,
|
|
5642
|
-
optionalSurfaces: spec
|
|
6204
|
+
optionalSurfaces: createWorkflowPlanOptionalSurfaces(spec, inputs),
|
|
5643
6205
|
steps: spec.steps,
|
|
5644
|
-
predictedChanges: spec
|
|
6206
|
+
predictedChanges: createWorkflowPlanPredictedChanges(spec, inputs),
|
|
5645
6207
|
validation: spec.validation,
|
|
5646
6208
|
diagnostics,
|
|
5647
6209
|
recommendations: createWorkflowPlanRecommendations(spec, inputs),
|
|
@@ -5710,35 +6272,65 @@ var renderWorkflowPlan = (plan) => [
|
|
|
5710
6272
|
""
|
|
5711
6273
|
].join(`
|
|
5712
6274
|
`);
|
|
5713
|
-
var
|
|
5714
|
-
|
|
5715
|
-
""
|
|
5716
|
-
`-
|
|
5717
|
-
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
"
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
]
|
|
6275
|
+
var renderRecommendation = (recommendation) => {
|
|
6276
|
+
const target = recommendation.target ? ` ${recommendation.target}` : "";
|
|
6277
|
+
const action = recommendation.action ? ` Action: ${recommendation.action}` : "";
|
|
6278
|
+
return `- [${recommendation.kind}]${target} ${recommendation.message}${action}`;
|
|
6279
|
+
};
|
|
6280
|
+
var renderDiagnostic = (diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`;
|
|
6281
|
+
var applySourceStatus = (report) => report.diagnostics.some((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown")) ? "failed" : "passed";
|
|
6282
|
+
var renderWorkflowApplyReport = (report) => {
|
|
6283
|
+
const manualReviewItems = [
|
|
6284
|
+
...report.diagnostics.filter((diagnostic) => diagnostic.severity === "warning").map(renderDiagnostic),
|
|
6285
|
+
...report.recommendations.filter((recommendation) => recommendation.kind === "manual-action").map(renderRecommendation)
|
|
6286
|
+
];
|
|
6287
|
+
const validationBlockers = report.diagnostics.filter((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "workspace-config" || diagnostic.failureScope === "environment")).map(renderDiagnostic);
|
|
6288
|
+
const sourceBlockers = report.diagnostics.filter((diagnostic) => diagnostic.severity === "error" && (diagnostic.failureScope === "source-change" || !diagnostic.failureScope || diagnostic.failureScope === "unknown")).map(renderDiagnostic);
|
|
6289
|
+
return [
|
|
6290
|
+
`# Workflow Apply: ${report.workflow}`,
|
|
6291
|
+
"",
|
|
6292
|
+
`- Mode: ${report.mode}`,
|
|
6293
|
+
`- Status: ${report.status}`,
|
|
6294
|
+
`- Source-change status: ${applySourceStatus(report)}`,
|
|
6295
|
+
`- Workspace status: ${validationBlockers.length ? "blocked" : "not blocked during apply"}`,
|
|
6296
|
+
...report.validationTarget ? [`- Validation target: ${report.validationTarget}`] : [],
|
|
6297
|
+
"",
|
|
6298
|
+
"## Apply Checks",
|
|
6299
|
+
...report.postApplyChecks?.length ? report.postApplyChecks.map((check) => `- [${check.status}] ${check.code} ${check.target}: ${check.message}`) : ["- not run"],
|
|
6300
|
+
"",
|
|
6301
|
+
"## Source Change Blockers",
|
|
6302
|
+
...sourceBlockers.length ? sourceBlockers : ["- none"],
|
|
6303
|
+
"",
|
|
6304
|
+
"## Automatically Modified",
|
|
6305
|
+
...report.changedFiles.length ? report.changedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
|
|
6306
|
+
"",
|
|
6307
|
+
"## Generated Sync",
|
|
6308
|
+
...report.generatedFiles.length ? report.generatedFiles.map((file) => `- \`${file.action}\` ${file.path}: ${file.reason}`) : ["- none"],
|
|
6309
|
+
"",
|
|
6310
|
+
"## Applied Commands",
|
|
6311
|
+
...report.appliedCommands.length ? report.appliedCommands.map((command) => `- \`${command.command}\`: ${command.reason}`) : ["- none"],
|
|
6312
|
+
"",
|
|
6313
|
+
"## Recommended Validation Commands",
|
|
6314
|
+
...report.recommendedValidationCommands.length ? report.recommendedValidationCommands.map((command) => `- \`${command.command}\`: ${command.reason}`) : ["- none"],
|
|
6315
|
+
"",
|
|
6316
|
+
"## User Review Required",
|
|
6317
|
+
...manualReviewItems.length ? manualReviewItems : ["- none"],
|
|
6318
|
+
"",
|
|
6319
|
+
"## Validation Blockers",
|
|
6320
|
+
...validationBlockers.length ? validationBlockers : report.recommendedValidationCommands.length ? ["- none detected during apply; run validation with the validation target for command-level blockers."] : ["- none"],
|
|
6321
|
+
"",
|
|
6322
|
+
"## Diagnostics",
|
|
6323
|
+
...report.diagnostics.length ? report.diagnostics.map(renderDiagnostic) : ["- none"],
|
|
6324
|
+
"",
|
|
6325
|
+
"## Recommendations",
|
|
6326
|
+
...report.recommendations.length ? report.recommendations.slice(0, 3).map(renderRecommendation) : ["- none"],
|
|
6327
|
+
"",
|
|
6328
|
+
"## Next Actions",
|
|
6329
|
+
...report.nextActions.length ? report.nextActions.map((action) => `- \`${action.command}\`: ${action.reason}`) : ["- none"],
|
|
6330
|
+
""
|
|
6331
|
+
].join(`
|
|
5741
6332
|
`);
|
|
6333
|
+
};
|
|
5742
6334
|
var renderWorkflowApply = (report, format = "markdown") => format === "json" ? jsonText(report) : renderWorkflowApplyReport(report);
|
|
5743
6335
|
var renderWorkflowValidationRunReport = (report) => [
|
|
5744
6336
|
`# Workflow Validation: ${report.workflow}`,
|
|
@@ -5749,11 +6341,24 @@ var renderWorkflowValidationRunReport = (report) => [
|
|
|
5749
6341
|
`- Workspace status: ${report.workspaceStatus}`,
|
|
5750
6342
|
`- Overall status: ${report.overallStatus}`,
|
|
5751
6343
|
"",
|
|
6344
|
+
"## Status Summary",
|
|
6345
|
+
`- Source-change: ${report.summary.sourceChange}`,
|
|
6346
|
+
`- Generated sync: ${report.summary.generatedSync}`,
|
|
6347
|
+
`- Workspace config: ${report.summary.workspaceConfig}`,
|
|
6348
|
+
`- Environment: ${report.summary.environment}`,
|
|
6349
|
+
"",
|
|
6350
|
+
"## Source Change Diagnostics",
|
|
6351
|
+
...report.workflowDiagnostics?.length ? report.workflowDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
|
|
6352
|
+
"",
|
|
6353
|
+
"## Existing Workspace Blockers",
|
|
6354
|
+
...report.baselineDiagnostics?.length ? report.baselineDiagnostics.map((diagnostic) => `- [${diagnostic.severity}] ${diagnostic.code}: ${diagnostic.message}`) : ["- none"],
|
|
6355
|
+
"",
|
|
5752
6356
|
"## Known Blockers",
|
|
5753
6357
|
...report.knownBlockers.length ? report.knownBlockers.map((blocker) => {
|
|
5754
6358
|
const command = blocker.command ? ` \`${blocker.command}\`` : "";
|
|
5755
6359
|
const count = blocker.count > 1 ? ` (${blocker.count}x)` : "";
|
|
5756
|
-
|
|
6360
|
+
const known = blocker.known ? " known" : "";
|
|
6361
|
+
return `- [${blocker.failureScope}${known}]${command}${count}: ${blocker.message}`;
|
|
5757
6362
|
}) : ["- none"],
|
|
5758
6363
|
"",
|
|
5759
6364
|
"## Commands",
|
|
@@ -6822,7 +7427,7 @@ var collapseIndex = (relPathNoExt) => {
|
|
|
6822
7427
|
|
|
6823
7428
|
// pkgs/@akanjs/devkit/transforms/barrelImportsPlugin.ts
|
|
6824
7429
|
import path14 from "path";
|
|
6825
|
-
import
|
|
7430
|
+
import ts5 from "typescript";
|
|
6826
7431
|
var createBarrelImportsPlugin = async (app, { skipPath = defaultSkipPath, pipeAfter } = {}) => {
|
|
6827
7432
|
const akanConfig2 = await app.getConfig();
|
|
6828
7433
|
const barrels = [...new Set(akanConfig2.barrelImports)].filter(Boolean);
|
|
@@ -7063,11 +7668,11 @@ var rewriteBarrelImports = async (source2, barrels, analyzer) => {
|
|
|
7063
7668
|
};
|
|
7064
7669
|
var findImportStatements = (source2) => {
|
|
7065
7670
|
const statements = [];
|
|
7066
|
-
const sourceFile2 =
|
|
7671
|
+
const sourceFile2 = ts5.createSourceFile("barrel-imports.tsx", source2, ts5.ScriptTarget.Latest, true, ts5.ScriptKind.TSX);
|
|
7067
7672
|
for (const statement of sourceFile2.statements) {
|
|
7068
|
-
if (!
|
|
7673
|
+
if (!ts5.isImportDeclaration(statement))
|
|
7069
7674
|
continue;
|
|
7070
|
-
if (!
|
|
7675
|
+
if (!ts5.isStringLiteral(statement.moduleSpecifier))
|
|
7071
7676
|
continue;
|
|
7072
7677
|
const importClause = statement.importClause;
|
|
7073
7678
|
if (!importClause)
|
|
@@ -8062,7 +8667,7 @@ import path22 from "path";
|
|
|
8062
8667
|
// pkgs/@akanjs/devkit/frontendBuild/pagesEntrySourceGenerator.ts
|
|
8063
8668
|
import fs3 from "fs";
|
|
8064
8669
|
import path21 from "path";
|
|
8065
|
-
import
|
|
8670
|
+
import ts6 from "typescript";
|
|
8066
8671
|
|
|
8067
8672
|
class PagesEntrySourceGenerator {
|
|
8068
8673
|
#pageEntries;
|
|
@@ -8106,7 +8711,7 @@ ${entries.join(`
|
|
|
8106
8711
|
static #hasAsyncDefaultExport(moduleAbsPath) {
|
|
8107
8712
|
try {
|
|
8108
8713
|
const source2 = fs3.readFileSync(path21.resolve(moduleAbsPath), "utf8");
|
|
8109
|
-
const sourceFile2 =
|
|
8714
|
+
const sourceFile2 = ts6.createSourceFile(moduleAbsPath, source2, ts6.ScriptTarget.Latest, true, PagesEntrySourceGenerator.#scriptKind(moduleAbsPath));
|
|
8110
8715
|
return PagesEntrySourceGenerator.#sourceFileHasAsyncDefaultExport(sourceFile2);
|
|
8111
8716
|
} catch {
|
|
8112
8717
|
return false;
|
|
@@ -8116,31 +8721,31 @@ ${entries.join(`
|
|
|
8116
8721
|
const asyncBindings = new Map;
|
|
8117
8722
|
let defaultIdentifier = null;
|
|
8118
8723
|
for (const statement of sourceFile2.statements) {
|
|
8119
|
-
if (
|
|
8120
|
-
if (PagesEntrySourceGenerator.#hasModifier(statement,
|
|
8121
|
-
return PagesEntrySourceGenerator.#hasModifier(statement,
|
|
8724
|
+
if (ts6.isFunctionDeclaration(statement)) {
|
|
8725
|
+
if (PagesEntrySourceGenerator.#hasModifier(statement, ts6.SyntaxKind.DefaultKeyword)) {
|
|
8726
|
+
return PagesEntrySourceGenerator.#hasModifier(statement, ts6.SyntaxKind.AsyncKeyword);
|
|
8122
8727
|
}
|
|
8123
8728
|
if (statement.name) {
|
|
8124
|
-
asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement,
|
|
8729
|
+
asyncBindings.set(statement.name.text, PagesEntrySourceGenerator.#hasModifier(statement, ts6.SyntaxKind.AsyncKeyword));
|
|
8125
8730
|
}
|
|
8126
8731
|
continue;
|
|
8127
8732
|
}
|
|
8128
|
-
if (
|
|
8733
|
+
if (ts6.isVariableStatement(statement)) {
|
|
8129
8734
|
for (const declaration of statement.declarationList.declarations) {
|
|
8130
|
-
if (!
|
|
8735
|
+
if (!ts6.isIdentifier(declaration.name))
|
|
8131
8736
|
continue;
|
|
8132
8737
|
asyncBindings.set(declaration.name.text, PagesEntrySourceGenerator.#isAsyncFunctionExpression(declaration.initializer));
|
|
8133
8738
|
}
|
|
8134
8739
|
continue;
|
|
8135
8740
|
}
|
|
8136
|
-
if (
|
|
8741
|
+
if (ts6.isExportAssignment(statement)) {
|
|
8137
8742
|
if (PagesEntrySourceGenerator.#isAsyncFunctionExpression(statement.expression))
|
|
8138
8743
|
return true;
|
|
8139
|
-
if (
|
|
8744
|
+
if (ts6.isIdentifier(statement.expression))
|
|
8140
8745
|
defaultIdentifier = statement.expression.text;
|
|
8141
8746
|
continue;
|
|
8142
8747
|
}
|
|
8143
|
-
if (
|
|
8748
|
+
if (ts6.isExportDeclaration(statement) && statement.exportClause && ts6.isNamedExports(statement.exportClause)) {
|
|
8144
8749
|
const exportClause = statement.exportClause;
|
|
8145
8750
|
for (const specifier of exportClause.elements) {
|
|
8146
8751
|
if (specifier.name.text !== "default")
|
|
@@ -8152,13 +8757,13 @@ ${entries.join(`
|
|
|
8152
8757
|
return defaultIdentifier ? asyncBindings.get(defaultIdentifier) === true : false;
|
|
8153
8758
|
}
|
|
8154
8759
|
static #hasModifier(node, kind) {
|
|
8155
|
-
return
|
|
8760
|
+
return ts6.canHaveModifiers(node) && (ts6.getModifiers(node)?.some((modifier) => modifier.kind === kind) ?? false);
|
|
8156
8761
|
}
|
|
8157
8762
|
static #isAsyncFunctionExpression(node) {
|
|
8158
|
-
return Boolean(node && (
|
|
8763
|
+
return Boolean(node && (ts6.isArrowFunction(node) || ts6.isFunctionExpression(node)) && PagesEntrySourceGenerator.#hasModifier(node, ts6.SyntaxKind.AsyncKeyword));
|
|
8159
8764
|
}
|
|
8160
8765
|
static #scriptKind(moduleAbsPath) {
|
|
8161
|
-
return moduleAbsPath.endsWith(".tsx") || moduleAbsPath.endsWith(".jsx") ?
|
|
8766
|
+
return moduleAbsPath.endsWith(".tsx") || moduleAbsPath.endsWith(".jsx") ? ts6.ScriptKind.TSX : ts6.ScriptKind.TS;
|
|
8162
8767
|
}
|
|
8163
8768
|
}
|
|
8164
8769
|
|
|
@@ -9077,7 +9682,7 @@ import {
|
|
|
9077
9682
|
} from "fontaine";
|
|
9078
9683
|
import { createFont, woff2 } from "fonteditor-core";
|
|
9079
9684
|
import subsetFont from "subset-font";
|
|
9080
|
-
import
|
|
9685
|
+
import ts7 from "typescript";
|
|
9081
9686
|
var FONT_URL_PREFIX = "/_akan/fonts";
|
|
9082
9687
|
var DEFAULT_FONT_SUBSETS = ["latin"];
|
|
9083
9688
|
|
|
@@ -9142,17 +9747,17 @@ class FontOptimizer {
|
|
|
9142
9747
|
this.#cssParts.push(...faceCss, this.#buildRootVariableRule(font));
|
|
9143
9748
|
}
|
|
9144
9749
|
#extractFontsExport(source2, filePath) {
|
|
9145
|
-
const sourceFile2 =
|
|
9750
|
+
const sourceFile2 = ts7.createSourceFile(filePath, source2, ts7.ScriptTarget.Latest, true, ts7.ScriptKind.TSX);
|
|
9146
9751
|
const fonts = [];
|
|
9147
9752
|
for (const statement of sourceFile2.statements) {
|
|
9148
|
-
if (!
|
|
9753
|
+
if (!ts7.isVariableStatement(statement))
|
|
9149
9754
|
continue;
|
|
9150
|
-
const modifiers =
|
|
9151
|
-
const isExported = modifiers?.some((modifier) => modifier.kind ===
|
|
9755
|
+
const modifiers = ts7.canHaveModifiers(statement) ? ts7.getModifiers(statement) : undefined;
|
|
9756
|
+
const isExported = modifiers?.some((modifier) => modifier.kind === ts7.SyntaxKind.ExportKeyword) ?? false;
|
|
9152
9757
|
if (!isExported)
|
|
9153
9758
|
continue;
|
|
9154
9759
|
for (const declaration of statement.declarationList.declarations) {
|
|
9155
|
-
if (!
|
|
9760
|
+
if (!ts7.isIdentifier(declaration.name) || declaration.name.text !== "fonts")
|
|
9156
9761
|
continue;
|
|
9157
9762
|
const value = declaration.initializer ? this.#literalToValue(declaration.initializer) : null;
|
|
9158
9763
|
if (Array.isArray(value)) {
|
|
@@ -9163,20 +9768,20 @@ class FontOptimizer {
|
|
|
9163
9768
|
return fonts;
|
|
9164
9769
|
}
|
|
9165
9770
|
#literalToValue(node) {
|
|
9166
|
-
if (
|
|
9771
|
+
if (ts7.isStringLiteralLike(node))
|
|
9167
9772
|
return node.text;
|
|
9168
|
-
if (
|
|
9773
|
+
if (ts7.isNumericLiteral(node))
|
|
9169
9774
|
return Number(node.text);
|
|
9170
|
-
if (node.kind ===
|
|
9775
|
+
if (node.kind === ts7.SyntaxKind.TrueKeyword)
|
|
9171
9776
|
return true;
|
|
9172
|
-
if (node.kind ===
|
|
9777
|
+
if (node.kind === ts7.SyntaxKind.FalseKeyword)
|
|
9173
9778
|
return false;
|
|
9174
|
-
if (
|
|
9779
|
+
if (ts7.isArrayLiteralExpression(node))
|
|
9175
9780
|
return node.elements.map((element) => this.#literalToValue(element));
|
|
9176
|
-
if (
|
|
9781
|
+
if (ts7.isObjectLiteralExpression(node)) {
|
|
9177
9782
|
const obj = {};
|
|
9178
9783
|
for (const prop of node.properties) {
|
|
9179
|
-
if (!
|
|
9784
|
+
if (!ts7.isPropertyAssignment(prop))
|
|
9180
9785
|
continue;
|
|
9181
9786
|
const name = this.#getPropertyName(prop.name);
|
|
9182
9787
|
if (!name)
|
|
@@ -9185,13 +9790,13 @@ class FontOptimizer {
|
|
|
9185
9790
|
}
|
|
9186
9791
|
return obj;
|
|
9187
9792
|
}
|
|
9188
|
-
if (
|
|
9793
|
+
if (ts7.isAsExpression(node) || ts7.isSatisfiesExpression(node) || ts7.isParenthesizedExpression(node)) {
|
|
9189
9794
|
return this.#literalToValue(node.expression);
|
|
9190
9795
|
}
|
|
9191
9796
|
return;
|
|
9192
9797
|
}
|
|
9193
9798
|
#getPropertyName(name) {
|
|
9194
|
-
if (
|
|
9799
|
+
if (ts7.isIdentifier(name) || ts7.isStringLiteral(name) || ts7.isNumericLiteral(name))
|
|
9195
9800
|
return name.text;
|
|
9196
9801
|
return null;
|
|
9197
9802
|
}
|
|
@@ -12661,10 +13266,12 @@ var NODE_NATIVE_MODULE_SET = new Set([
|
|
|
12661
13266
|
]);
|
|
12662
13267
|
// pkgs/@akanjs/devkit/getCredentials.ts
|
|
12663
13268
|
import yaml from "js-yaml";
|
|
13269
|
+
// pkgs/@akanjs/devkit/getModelFileData.ts
|
|
13270
|
+
import { capitalize as capitalize8 } from "akanjs/common";
|
|
12664
13271
|
// pkgs/@akanjs/devkit/getRelatedCnsts.ts
|
|
12665
13272
|
import { readFileSync as readFileSync4, realpathSync } from "fs";
|
|
12666
13273
|
import ora2 from "ora";
|
|
12667
|
-
import * as
|
|
13274
|
+
import * as ts8 from "typescript";
|
|
12668
13275
|
var tsTranspiler = new Bun.Transpiler({ loader: "ts" });
|
|
12669
13276
|
var tsxTranspiler = new Bun.Transpiler({ loader: "tsx" });
|
|
12670
13277
|
var getTranspiler = (filePath) => filePath.endsWith(".tsx") ? tsxTranspiler : tsTranspiler;
|
|
@@ -12697,10 +13304,10 @@ var scanModuleSpecifiers = (source2, filePath, includeExports) => {
|
|
|
12697
13304
|
return importSpecifiers;
|
|
12698
13305
|
};
|
|
12699
13306
|
var parseTsConfig = (tsConfigPath = "./tsconfig.json") => {
|
|
12700
|
-
const configFile =
|
|
12701
|
-
return
|
|
13307
|
+
const configFile = ts8.readConfigFile(tsConfigPath, (path40) => {
|
|
13308
|
+
return ts8.sys.readFile(path40);
|
|
12702
13309
|
});
|
|
12703
|
-
return
|
|
13310
|
+
return ts8.parseJsonConfigFileContent(configFile.config, ts8.sys, realpathSync(tsConfigPath).replace(/[^/\\]+$/, ""));
|
|
12704
13311
|
};
|
|
12705
13312
|
var collectImportedFiles = (constantFilePath, parsedConfig) => {
|
|
12706
13313
|
const allFilesToAnalyze = new Set([constantFilePath]);
|
|
@@ -12715,7 +13322,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
|
|
|
12715
13322
|
for (const importPath of scanModuleSpecifiers(source2, filePath, false)) {
|
|
12716
13323
|
if (!importPath.startsWith("."))
|
|
12717
13324
|
continue;
|
|
12718
|
-
const resolved =
|
|
13325
|
+
const resolved = ts8.resolveModuleName(importPath, filePath, parsedConfig.options, ts8.sys).resolvedModule?.resolvedFileName;
|
|
12719
13326
|
if (resolved && !allFilesToAnalyze.has(resolved)) {
|
|
12720
13327
|
allFilesToAnalyze.add(resolved);
|
|
12721
13328
|
collectImported(resolved);
|
|
@@ -12732,7 +13339,7 @@ var collectImportedFiles = (constantFilePath, parsedConfig) => {
|
|
|
12732
13339
|
var createTsProgram = (filePaths, options) => {
|
|
12733
13340
|
const spinner = ora2("Creating TypeScript program for all files...");
|
|
12734
13341
|
spinner.start();
|
|
12735
|
-
const program2 =
|
|
13342
|
+
const program2 = ts8.createProgram(Array.from(filePaths), options);
|
|
12736
13343
|
const checker = program2.getTypeChecker();
|
|
12737
13344
|
spinner.succeed("TypeScript program created.");
|
|
12738
13345
|
return {
|
|
@@ -12772,17 +13379,17 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
|
|
|
12772
13379
|
function visit(node) {
|
|
12773
13380
|
if (!source2)
|
|
12774
13381
|
return;
|
|
12775
|
-
if (
|
|
13382
|
+
if (ts8.isPropertyAccessExpression(node)) {
|
|
12776
13383
|
const left = node.expression;
|
|
12777
13384
|
const right = node.name;
|
|
12778
|
-
const { line } =
|
|
12779
|
-
if (
|
|
13385
|
+
const { line } = ts8.getLineAndCharacterOfPosition(source2, node.getStart());
|
|
13386
|
+
if (ts8.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},`))) {
|
|
12780
13387
|
const symbol = getCachedSymbol(right);
|
|
12781
13388
|
if (symbol?.declarations && symbol.declarations.length > 0) {
|
|
12782
13389
|
const key = symbol.declarations[0]?.getSourceFile().fileName.split("/").pop()?.split(".")[0] ?? "";
|
|
12783
13390
|
const property = propertyMap.get(key);
|
|
12784
13391
|
const isScalar = symbol.declarations[0]?.getSourceFile().fileName.includes("_") ?? false;
|
|
12785
|
-
const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${
|
|
13392
|
+
const symbolFilePath = symbol.declarations[0]?.getSourceFile().fileName.replace(`${ts8.sys.getCurrentDirectory()}/`, "");
|
|
12786
13393
|
if (!symbolFilePath)
|
|
12787
13394
|
throw new Error(`No symbol file path found for ${left.text}.${right.text}`);
|
|
12788
13395
|
if (property) {
|
|
@@ -12806,10 +13413,10 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
|
|
|
12806
13413
|
}
|
|
12807
13414
|
}
|
|
12808
13415
|
}
|
|
12809
|
-
} else if (
|
|
13416
|
+
} else if (ts8.isImportDeclaration(node) && ts8.isStringLiteral(node.moduleSpecifier)) {
|
|
12810
13417
|
const importPath = node.moduleSpecifier.text;
|
|
12811
13418
|
if (importPath.startsWith(".")) {
|
|
12812
|
-
const resolved =
|
|
13419
|
+
const resolved = ts8.resolveModuleName(importPath, filePath, program2.getCompilerOptions(), ts8.sys).resolvedModule?.resolvedFileName;
|
|
12813
13420
|
const moduleName = importPath.split("/").pop()?.split(".")[0] ?? "";
|
|
12814
13421
|
const property = propertyMap.get(moduleName);
|
|
12815
13422
|
const isScalar = importPath.includes("_");
|
|
@@ -12824,7 +13431,7 @@ var analyzeProperties = (filesToAnalyze, program2, checker) => {
|
|
|
12824
13431
|
}
|
|
12825
13432
|
}
|
|
12826
13433
|
}
|
|
12827
|
-
|
|
13434
|
+
ts8.forEachChild(node, visit);
|
|
12828
13435
|
}
|
|
12829
13436
|
visit(source2);
|
|
12830
13437
|
}
|
|
@@ -14611,7 +15218,7 @@ import path43 from "path";
|
|
|
14611
15218
|
|
|
14612
15219
|
// pkgs/@akanjs/cli/module/module.script.ts
|
|
14613
15220
|
import { input as input6 } from "@inquirer/prompts";
|
|
14614
|
-
import { capitalize as
|
|
15221
|
+
import { capitalize as capitalize11, randomPicks } from "akanjs/common";
|
|
14615
15222
|
|
|
14616
15223
|
// pkgs/@akanjs/cli/page/page.runner.ts
|
|
14617
15224
|
class PageRunner extends runner("page") {
|
|
@@ -14641,7 +15248,7 @@ function pluralizeName(name) {
|
|
|
14641
15248
|
}
|
|
14642
15249
|
|
|
14643
15250
|
// pkgs/@akanjs/cli/module/module.request.ts
|
|
14644
|
-
import { capitalize as
|
|
15251
|
+
import { capitalize as capitalize9 } from "akanjs/common";
|
|
14645
15252
|
|
|
14646
15253
|
// pkgs/@akanjs/cli/module/module.prompt.ts
|
|
14647
15254
|
var componentDefaultDescription = ({
|
|
@@ -14766,7 +15373,7 @@ var requestTemplate = ({
|
|
|
14766
15373
|
${componentDefaultDescription({
|
|
14767
15374
|
sysName,
|
|
14768
15375
|
modelName,
|
|
14769
|
-
ModelName: ModelName ??
|
|
15376
|
+
ModelName: ModelName ?? capitalize9(modelName),
|
|
14770
15377
|
exampleFiles,
|
|
14771
15378
|
constant,
|
|
14772
15379
|
properties
|
|
@@ -14823,7 +15430,7 @@ var requestView = ({
|
|
|
14823
15430
|
${componentDefaultDescription({
|
|
14824
15431
|
sysName,
|
|
14825
15432
|
modelName,
|
|
14826
|
-
ModelName: ModelName ??
|
|
15433
|
+
ModelName: ModelName ?? capitalize9(modelName),
|
|
14827
15434
|
exampleFiles,
|
|
14828
15435
|
constant,
|
|
14829
15436
|
properties
|
|
@@ -14884,7 +15491,7 @@ var requestUnit = ({
|
|
|
14884
15491
|
${componentDefaultDescription({
|
|
14885
15492
|
sysName,
|
|
14886
15493
|
modelName,
|
|
14887
|
-
ModelName: ModelName ??
|
|
15494
|
+
ModelName: ModelName ?? capitalize9(modelName),
|
|
14888
15495
|
exampleFiles,
|
|
14889
15496
|
constant,
|
|
14890
15497
|
properties
|
|
@@ -14933,22 +15540,29 @@ var requestUnit = ({
|
|
|
14933
15540
|
`;
|
|
14934
15541
|
|
|
14935
15542
|
// pkgs/@akanjs/cli/module/module.runner.ts
|
|
14936
|
-
import { capitalize as
|
|
15543
|
+
import { capitalize as capitalize10 } from "akanjs/common";
|
|
15544
|
+
var purposeByModule = {
|
|
15545
|
+
budget: "Budget represents planned or actual money allocated inside the app.",
|
|
15546
|
+
project: "Project represents a project workspace or business initiative managed by the app.",
|
|
15547
|
+
task: "Task represents work items that move through the app workflow."
|
|
15548
|
+
};
|
|
14937
15549
|
var moduleAbstractContent = (moduleName) => {
|
|
14938
|
-
const title =
|
|
15550
|
+
const title = capitalize10(moduleName);
|
|
15551
|
+
const label = bilingualLabelForField(moduleName);
|
|
15552
|
+
const purpose = purposeByModule[moduleName] ?? `${title} represents ${label.en.toLowerCase()} records managed by the app.`;
|
|
14939
15553
|
return `# ${title} Module Abstract
|
|
14940
15554
|
|
|
14941
15555
|
## Purpose
|
|
14942
15556
|
|
|
14943
|
-
${
|
|
15557
|
+
${purpose}
|
|
14944
15558
|
|
|
14945
15559
|
## Domain Rules
|
|
14946
15560
|
|
|
14947
|
-
-
|
|
15561
|
+
- Keep ${label.en.toLowerCase()} data consistent with user-facing dictionary labels.
|
|
14948
15562
|
|
|
14949
15563
|
## Data Meaning
|
|
14950
15564
|
|
|
14951
|
-
|
|
15565
|
+
${label.en} (${label.ko}) is the primary business concept for this module.
|
|
14952
15566
|
|
|
14953
15567
|
## Workflows
|
|
14954
15568
|
|
|
@@ -14965,6 +15579,7 @@ No lifecycle workflow yet.
|
|
|
14965
15579
|
- None yet.
|
|
14966
15580
|
`;
|
|
14967
15581
|
};
|
|
15582
|
+
var localModuleFilename = (moduleName, pathKey2) => moduleSourcePaths(moduleName)[pathKey2].replace(`lib/${moduleName}/`, "");
|
|
14968
15583
|
|
|
14969
15584
|
class ModuleRunner extends runner("module") {
|
|
14970
15585
|
async createService(module) {
|
|
@@ -14995,24 +15610,47 @@ class ModuleRunner extends runner("module") {
|
|
|
14995
15610
|
async createComponentTemplate(module, type) {
|
|
14996
15611
|
await module.sys.applyTemplate({
|
|
14997
15612
|
basePath: `./lib/${module.name}`,
|
|
14998
|
-
template: `module/__Model__.${
|
|
15613
|
+
template: `module/__Model__.${capitalize10(type)}.tsx`,
|
|
14999
15614
|
dict: { model: module.name, appName: module.sys.name }
|
|
15000
15615
|
});
|
|
15001
15616
|
return {
|
|
15002
15617
|
component: {
|
|
15003
|
-
filename: `${module.name}.${
|
|
15004
|
-
content: await module.sys.readFile(`lib/${module.name}/${
|
|
15618
|
+
filename: `${capitalize10(module.name)}.${capitalize10(type)}.tsx`,
|
|
15619
|
+
content: await module.sys.readFile(`lib/${module.name}/${capitalize10(module.name)}.${capitalize10(type)}.tsx`)
|
|
15005
15620
|
}
|
|
15006
15621
|
};
|
|
15007
15622
|
}
|
|
15008
15623
|
async createModuleTemplate(module) {
|
|
15009
15624
|
const names = pluralizeName(module.name);
|
|
15625
|
+
const modelLabel = bilingualLabelForField(module.name);
|
|
15626
|
+
const modelDescription = bilingualDescriptionForField(module.name);
|
|
15627
|
+
const filenames = {
|
|
15628
|
+
abstract: localModuleFilename(module.name, "abstract"),
|
|
15629
|
+
constant: localModuleFilename(module.name, "constant"),
|
|
15630
|
+
dictionary: localModuleFilename(module.name, "dictionary"),
|
|
15631
|
+
service: localModuleFilename(module.name, "service"),
|
|
15632
|
+
store: localModuleFilename(module.name, "store"),
|
|
15633
|
+
signal: localModuleFilename(module.name, "signal"),
|
|
15634
|
+
unit: localModuleFilename(module.name, "unit"),
|
|
15635
|
+
view: localModuleFilename(module.name, "view"),
|
|
15636
|
+
template: localModuleFilename(module.name, "template"),
|
|
15637
|
+
zone: localModuleFilename(module.name, "zone"),
|
|
15638
|
+
util: localModuleFilename(module.name, "util")
|
|
15639
|
+
};
|
|
15010
15640
|
await module.applyTemplate({
|
|
15011
15641
|
basePath: `.`,
|
|
15012
15642
|
template: "module",
|
|
15013
|
-
dict: {
|
|
15643
|
+
dict: {
|
|
15644
|
+
model: module.name,
|
|
15645
|
+
models: names,
|
|
15646
|
+
sysName: module.sys.name,
|
|
15647
|
+
modelLabelEn: modelLabel.en,
|
|
15648
|
+
modelLabelKo: modelLabel.ko,
|
|
15649
|
+
modelDescEn: modelDescription.en,
|
|
15650
|
+
modelDescKo: modelDescription.ko
|
|
15651
|
+
}
|
|
15014
15652
|
});
|
|
15015
|
-
await module.writeFile(
|
|
15653
|
+
await module.writeFile(filenames.abstract, moduleAbstractContent(module.name));
|
|
15016
15654
|
const [
|
|
15017
15655
|
abstractContent,
|
|
15018
15656
|
constantContent,
|
|
@@ -15026,30 +15664,30 @@ class ModuleRunner extends runner("module") {
|
|
|
15026
15664
|
zoneContent,
|
|
15027
15665
|
utilContent
|
|
15028
15666
|
] = await Promise.all([
|
|
15029
|
-
module.readFile(
|
|
15030
|
-
module.readFile(
|
|
15031
|
-
module.readFile(
|
|
15032
|
-
module.readFile(
|
|
15033
|
-
module.readFile(
|
|
15034
|
-
module.readFile(
|
|
15035
|
-
module.readFile(
|
|
15036
|
-
module.readFile(
|
|
15037
|
-
module.readFile(
|
|
15038
|
-
module.readFile(
|
|
15039
|
-
module.readFile(
|
|
15667
|
+
module.readFile(filenames.abstract),
|
|
15668
|
+
module.readFile(filenames.constant),
|
|
15669
|
+
module.readFile(filenames.dictionary),
|
|
15670
|
+
module.readFile(filenames.service),
|
|
15671
|
+
module.readFile(filenames.store),
|
|
15672
|
+
module.readFile(filenames.signal),
|
|
15673
|
+
module.readFile(filenames.unit),
|
|
15674
|
+
module.readFile(filenames.view),
|
|
15675
|
+
module.readFile(filenames.template),
|
|
15676
|
+
module.readFile(filenames.zone),
|
|
15677
|
+
module.readFile(filenames.util)
|
|
15040
15678
|
]);
|
|
15041
15679
|
return {
|
|
15042
|
-
abstract: { filename:
|
|
15043
|
-
constant: { filename:
|
|
15044
|
-
dictionary: { filename:
|
|
15045
|
-
service: { filename:
|
|
15046
|
-
store: { filename:
|
|
15047
|
-
signal: { filename:
|
|
15048
|
-
unit: { filename:
|
|
15049
|
-
view: { filename:
|
|
15050
|
-
template: { filename:
|
|
15051
|
-
zone: { filename:
|
|
15052
|
-
util: { filename:
|
|
15680
|
+
abstract: { filename: filenames.abstract, content: abstractContent },
|
|
15681
|
+
constant: { filename: filenames.constant, content: constantContent },
|
|
15682
|
+
dictionary: { filename: filenames.dictionary, content: dictionaryContent },
|
|
15683
|
+
service: { filename: filenames.service, content: serviceContent },
|
|
15684
|
+
store: { filename: filenames.store, content: storeContent },
|
|
15685
|
+
signal: { filename: filenames.signal, content: signalContent },
|
|
15686
|
+
unit: { filename: filenames.unit, content: unitContent },
|
|
15687
|
+
view: { filename: filenames.view, content: viewContent },
|
|
15688
|
+
template: { filename: filenames.template, content: templateContent },
|
|
15689
|
+
zone: { filename: filenames.zone, content: zoneContent },
|
|
15690
|
+
util: { filename: filenames.util, content: utilContent }
|
|
15053
15691
|
};
|
|
15054
15692
|
}
|
|
15055
15693
|
}
|
|
@@ -15151,8 +15789,9 @@ class ModuleScript extends script("module", [ModuleRunner, PageScript]) {
|
|
|
15151
15789
|
async createTest(workspace, name) {}
|
|
15152
15790
|
async createTemplate(mod) {
|
|
15153
15791
|
const { component: template } = await this.moduleRunner.createComponentTemplate(mod, "template");
|
|
15154
|
-
const
|
|
15155
|
-
const
|
|
15792
|
+
const paths = moduleSourcePaths(mod.name);
|
|
15793
|
+
const templateExampleFiles = (await mod.sys.getTemplatesSourceCode()).filter((f) => !f.filePath.includes(paths.template));
|
|
15794
|
+
const Name = capitalize11(mod.name);
|
|
15156
15795
|
const relatedCnsts = getRelatedCnsts(`${mod.sys.cwdPath}/lib/${mod.name}/${mod.name}.constant.ts`);
|
|
15157
15796
|
const constant = await FileSys.readText(`${mod.sys.cwdPath}/lib/${mod.name}/${mod.name}.constant.ts`);
|
|
15158
15797
|
const session = new AiSession("createTemplate", { workspace: mod.sys.workspace, cacheKey: mod.name });
|
|
@@ -15178,8 +15817,9 @@ class ModuleScript extends script("module", [ModuleRunner, PageScript]) {
|
|
|
15178
15817
|
}
|
|
15179
15818
|
async createUnit(mod) {
|
|
15180
15819
|
const { component: unit } = await this.moduleRunner.createComponentTemplate(mod, "unit");
|
|
15181
|
-
const
|
|
15182
|
-
const
|
|
15820
|
+
const paths = moduleSourcePaths(mod.name);
|
|
15821
|
+
const Name = capitalize11(mod.name);
|
|
15822
|
+
const unitExampleFiles = (await mod.sys.getUnitsSourceCode()).filter((f) => !f.filePath.includes(paths.unit));
|
|
15183
15823
|
const relatedCnsts = getRelatedCnsts(`${mod.sys.cwdPath}/lib/${mod.name}/${mod.name}.constant.ts`);
|
|
15184
15824
|
const constant = await FileSys.readText(`${mod.sys.cwdPath}/lib/${mod.name}/${mod.name}.constant.ts`);
|
|
15185
15825
|
const session = new AiSession("createUnit", { workspace: mod.sys.workspace, cacheKey: mod.name });
|
|
@@ -15203,8 +15843,9 @@ class ModuleScript extends script("module", [ModuleRunner, PageScript]) {
|
|
|
15203
15843
|
}
|
|
15204
15844
|
async createView(mod) {
|
|
15205
15845
|
const { component: view } = await this.moduleRunner.createComponentTemplate(mod, "view");
|
|
15206
|
-
const
|
|
15207
|
-
const
|
|
15846
|
+
const paths = moduleSourcePaths(mod.name);
|
|
15847
|
+
const viewExampleFiles = (await mod.sys.getViewsSourceCode()).filter((f) => !f.filePath.includes(paths.view));
|
|
15848
|
+
const Name = capitalize11(mod.name);
|
|
15208
15849
|
const relatedCnsts = getRelatedCnsts(`${mod.sys.cwdPath}/lib/${mod.name}/${mod.name}.constant.ts`);
|
|
15209
15850
|
const constant = await FileSys.readText(`${mod.sys.cwdPath}/lib/${mod.name}/${mod.name}.constant.ts`);
|
|
15210
15851
|
const session = new AiSession("createView", { workspace: mod.sys.workspace, cacheKey: mod.name });
|
|
@@ -15229,7 +15870,7 @@ class ModuleScript extends script("module", [ModuleRunner, PageScript]) {
|
|
|
15229
15870
|
}
|
|
15230
15871
|
|
|
15231
15872
|
// pkgs/@akanjs/cli/primitive/primitive.script.ts
|
|
15232
|
-
import { capitalize as
|
|
15873
|
+
import { capitalize as capitalize12 } from "akanjs/common";
|
|
15233
15874
|
class PrimitiveScript extends script("primitive", [ModuleScript]) {
|
|
15234
15875
|
async resolveSys(workspace, target) {
|
|
15235
15876
|
if (!target)
|
|
@@ -15277,7 +15918,7 @@ class PrimitiveScript extends script("primitive", [ModuleScript]) {
|
|
|
15277
15918
|
}
|
|
15278
15919
|
async addEnumField(workspace, input7) {
|
|
15279
15920
|
const values = parseValues(input7.values);
|
|
15280
|
-
return await this.addFieldToSources(workspace, { ...input7, type: `${
|
|
15921
|
+
return await this.addFieldToSources(workspace, { ...input7, type: `${capitalize12(input7.field ?? "")}` }, { enumValues: values });
|
|
15281
15922
|
}
|
|
15282
15923
|
async addFieldToSources(workspace, input7, { enumValues }) {
|
|
15283
15924
|
const sys3 = await this.resolveSys(workspace, input7.app);
|
|
@@ -15321,10 +15962,12 @@ class PrimitiveScript extends script("primitive", [ModuleScript]) {
|
|
|
15321
15962
|
nextActions: []
|
|
15322
15963
|
});
|
|
15323
15964
|
}
|
|
15324
|
-
const moduleClassName =
|
|
15965
|
+
const moduleClassName = capitalize12(input7.module);
|
|
15325
15966
|
const inputClassName = `${moduleClassName}Input`;
|
|
15326
|
-
const
|
|
15327
|
-
const
|
|
15967
|
+
const paths = moduleSourcePaths(input7.module);
|
|
15968
|
+
const constantPath = paths.constant;
|
|
15969
|
+
const dictionaryPath = paths.dictionary;
|
|
15970
|
+
const templatePath = paths.template;
|
|
15328
15971
|
const changedFiles = [];
|
|
15329
15972
|
const generatedFiles2 = generatedFilesForSync(sys3);
|
|
15330
15973
|
const [hasConstant, hasDictionary] = await Promise.all([sys3.exists(constantPath), sys3.exists(dictionaryPath)]);
|
|
@@ -15354,6 +15997,7 @@ class PrimitiveScript extends script("primitive", [ModuleScript]) {
|
|
|
15354
15997
|
}
|
|
15355
15998
|
let constantContent = await sys3.readFile(constantPath);
|
|
15356
15999
|
let dictionaryContent = await sys3.readFile(dictionaryPath);
|
|
16000
|
+
const fieldBuilderName = viaBuilderParameterName(constantContent, inputClassName) ?? "field";
|
|
15357
16001
|
if (new RegExp(`\\b${input7.field}\\s*:`).test(constantContent)) {
|
|
15358
16002
|
diagnostics.push({
|
|
15359
16003
|
severity: "error",
|
|
@@ -15363,8 +16007,8 @@ class PrimitiveScript extends script("primitive", [ModuleScript]) {
|
|
|
15363
16007
|
});
|
|
15364
16008
|
}
|
|
15365
16009
|
if (enumValues) {
|
|
15366
|
-
const enumClassName = `${moduleClassName}${
|
|
15367
|
-
const enumName = `${lowerlize(moduleClassName)}${
|
|
16010
|
+
const enumClassName = `${moduleClassName}${capitalize12(input7.field)}`;
|
|
16011
|
+
const enumName = `${lowerlize(moduleClassName)}${capitalize12(input7.field)}`;
|
|
15368
16012
|
constantContent = insertEnumClass(ensureEnumImport(constantContent), enumClassName, enumName, enumValues);
|
|
15369
16013
|
dictionaryContent = ensureConstantTypeImport(dictionaryContent, `./${input7.module}.constant`, enumClassName);
|
|
15370
16014
|
input7.type = enumClassName;
|
|
@@ -15386,9 +16030,15 @@ class PrimitiveScript extends script("primitive", [ModuleScript]) {
|
|
|
15386
16030
|
diagnostics.push(defaultCoercion.diagnostic);
|
|
15387
16031
|
constantContent = ensureBaseTypeImport(constantContent, input7.type);
|
|
15388
16032
|
}
|
|
15389
|
-
|
|
16033
|
+
if (enumValues) {
|
|
16034
|
+
const defaultCoercion = coerceFieldDefault("enum", input7.defaultValue, { enumValues });
|
|
16035
|
+
if (defaultCoercion.diagnostic)
|
|
16036
|
+
diagnostics.push(defaultCoercion.diagnostic);
|
|
16037
|
+
}
|
|
16038
|
+
const nextConstantContent = insertIntoObject(constantContent, inputClassName, `${input7.field}: ${fieldExpression(input7.type, input7.defaultValue, { enumValues, builderName: fieldBuilderName })},`);
|
|
16039
|
+
const nextConstantContentWithLight = nextConstantContent && input7.includeInLight ? insertLightProjectionField(nextConstantContent, moduleClassName, input7.field) : nextConstantContent;
|
|
15390
16040
|
const nextDictionaryContent = insertDictionaryModelField(dictionaryContent, moduleClassName, input7.field);
|
|
15391
|
-
if (
|
|
16041
|
+
if (nextConstantContentWithLight && (input7.type === "Int" || input7.type === "Float") && new RegExp(`\\b${input7.field}\\s*:\\s*field\\(${input7.type}, \\{ default: "`, "m").test(nextConstantContentWithLight)) {
|
|
15392
16042
|
diagnostics.push({
|
|
15393
16043
|
severity: "error",
|
|
15394
16044
|
code: "primitive-default-value-invalid",
|
|
@@ -15397,7 +16047,7 @@ class PrimitiveScript extends script("primitive", [ModuleScript]) {
|
|
|
15397
16047
|
message: `Generated ${input7.type} default for "${input7.field}" would be a string literal; refusing to write source.`
|
|
15398
16048
|
});
|
|
15399
16049
|
}
|
|
15400
|
-
if (
|
|
16050
|
+
if (nextConstantContentWithLight && (input7.type === "Int" || input7.type === "Float") && !new RegExp(`import \\{[^}]*\\b${input7.type}\\b[^}]*\\} from "akanjs/base";`).test(nextConstantContentWithLight)) {
|
|
15401
16051
|
diagnostics.push({
|
|
15402
16052
|
severity: "error",
|
|
15403
16053
|
code: "primitive-base-type-import-missing",
|
|
@@ -15412,6 +16062,14 @@ class PrimitiveScript extends script("primitive", [ModuleScript]) {
|
|
|
15412
16062
|
message: `Could not find ${inputClassName} object shape in ${constantPath}.`
|
|
15413
16063
|
});
|
|
15414
16064
|
}
|
|
16065
|
+
if (nextConstantContent && input7.includeInLight && !nextConstantContentWithLight) {
|
|
16066
|
+
diagnostics.push({
|
|
16067
|
+
severity: "warning",
|
|
16068
|
+
code: "primitive-light-projection-shape-unsupported",
|
|
16069
|
+
failureScope: "source-change",
|
|
16070
|
+
message: `Could not find a safe Light${moduleClassName} projection insertion point in ${constantPath}.`
|
|
16071
|
+
});
|
|
16072
|
+
}
|
|
15415
16073
|
if (!nextDictionaryContent) {
|
|
15416
16074
|
diagnostics.push({
|
|
15417
16075
|
severity: "error",
|
|
@@ -15419,10 +16077,51 @@ class PrimitiveScript extends script("primitive", [ModuleScript]) {
|
|
|
15419
16077
|
message: `Could not find ${moduleClassName} dictionary model shape in ${dictionaryPath}.`
|
|
15420
16078
|
});
|
|
15421
16079
|
}
|
|
15422
|
-
|
|
15423
|
-
|
|
16080
|
+
let nextTemplateContent;
|
|
16081
|
+
if (input7.surfaces?.includes("template")) {
|
|
16082
|
+
const policy = addFieldUiPolicyForType(enumValues ? "enum" : input7.type);
|
|
16083
|
+
const hasTemplate = await sys3.exists(templatePath);
|
|
16084
|
+
if (!hasTemplate) {
|
|
16085
|
+
diagnostics.push({
|
|
16086
|
+
severity: "warning",
|
|
16087
|
+
code: "primitive-template-missing",
|
|
16088
|
+
failureScope: "source-change",
|
|
16089
|
+
message: `Template source file was not found: ${templatePath}. Auto-edit skipped; add the field to the Template form manually if this module renders one.`
|
|
16090
|
+
});
|
|
16091
|
+
} else if (!policy.autoTemplateSupported || policy.component === "Field.ToggleSelect") {
|
|
16092
|
+
diagnostics.push({
|
|
16093
|
+
severity: "warning",
|
|
16094
|
+
code: "primitive-template-component-manual",
|
|
16095
|
+
failureScope: "source-change",
|
|
16096
|
+
message: `Template auto insertion for ${policy.component} is not supported because option binding must be confirmed. Candidate position: inside Layout.Template near existing Field components in ${templatePath}.`
|
|
16097
|
+
});
|
|
16098
|
+
} else {
|
|
16099
|
+
const templateContent = await sys3.readFile(templatePath);
|
|
16100
|
+
nextTemplateContent = insertTemplateField({
|
|
16101
|
+
content: templateContent,
|
|
16102
|
+
moduleName: input7.module,
|
|
16103
|
+
moduleClassName,
|
|
16104
|
+
fieldName: input7.field,
|
|
16105
|
+
component: policy.component
|
|
16106
|
+
});
|
|
16107
|
+
if (!nextTemplateContent) {
|
|
16108
|
+
diagnostics.push({
|
|
16109
|
+
severity: "warning",
|
|
16110
|
+
code: "primitive-template-shape-unsupported",
|
|
16111
|
+
failureScope: "source-change",
|
|
16112
|
+
message: `Could not find a safe Template insertion point in ${templatePath}. Expected generated ${input7.module}Form hook and Layout.Template closing tag; candidate position is the existing field list before </Layout.Template>.`
|
|
16113
|
+
});
|
|
16114
|
+
}
|
|
16115
|
+
}
|
|
16116
|
+
}
|
|
16117
|
+
if (!diagnostics.some((diagnostic) => diagnostic.severity === "error") && nextConstantContentWithLight && nextDictionaryContent) {
|
|
16118
|
+
await sys3.writeFile(constantPath, nextConstantContentWithLight);
|
|
15424
16119
|
await sys3.writeFile(dictionaryPath, nextDictionaryContent);
|
|
15425
16120
|
changedFiles.push(sourceFile(sys3, constantPath, "modify", "Field source shape was updated."), sourceFile(sys3, dictionaryPath, "modify", "Field dictionary labels were updated."));
|
|
16121
|
+
if (nextTemplateContent !== undefined && nextTemplateContent !== null) {
|
|
16122
|
+
await sys3.writeFile(templatePath, nextTemplateContent);
|
|
16123
|
+
changedFiles.push(sourceFile(sys3, templatePath, "modify", "Template field surface was updated."));
|
|
16124
|
+
}
|
|
15426
16125
|
}
|
|
15427
16126
|
return createPrimitiveWriteReport({
|
|
15428
16127
|
command: enumValues ? "add-enum-field" : "add-field",
|
|
@@ -15791,7 +16490,7 @@ class ScalarScript extends script("scalar", [ScalarRunner]) {
|
|
|
15791
16490
|
// pkgs/@akanjs/cli/workflow/workflow.runner.ts
|
|
15792
16491
|
import { mkdir as mkdir12, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
|
|
15793
16492
|
import path42 from "path";
|
|
15794
|
-
import { capitalize as
|
|
16493
|
+
import { capitalize as capitalize13 } from "akanjs/common";
|
|
15795
16494
|
|
|
15796
16495
|
// pkgs/@akanjs/cli/workflows/shared.ts
|
|
15797
16496
|
var sysInputs = {
|
|
@@ -15907,7 +16606,15 @@ var addFieldWorkflowSpec = {
|
|
|
15907
16606
|
values: { type: "string-list", description: "Comma-separated enum values when type is enum." },
|
|
15908
16607
|
default: {
|
|
15909
16608
|
type: "string",
|
|
15910
|
-
description: "Optional default value.
|
|
16609
|
+
description: "Optional default value. plan/apply coerce by field type: Int/Float to numeric literals, Boolean to true/false, Date to new Date(...), String/scalar to string literals, and enum only when the value is in values."
|
|
16610
|
+
},
|
|
16611
|
+
surfaces: {
|
|
16612
|
+
type: "string-list",
|
|
16613
|
+
description: "Optional UI surfaces to update, comma-separated. Use template to auto-update simple generated Template forms; View/Unit stay planned as manual review."
|
|
16614
|
+
},
|
|
16615
|
+
includeInLight: {
|
|
16616
|
+
type: "boolean",
|
|
16617
|
+
description: "Whether to add the field to the Light<Model> projection used by list/card displays."
|
|
15911
16618
|
}
|
|
15912
16619
|
},
|
|
15913
16620
|
optionalSurfaces: {
|
|
@@ -16430,7 +17137,7 @@ var planInputString2 = (plan2, key) => {
|
|
|
16430
17137
|
var workflowPathsForPlanLike = (plan2) => {
|
|
16431
17138
|
const app = planInputString2(plan2, "app");
|
|
16432
17139
|
const module = planInputString2(plan2, "module");
|
|
16433
|
-
const moduleClass = module ?
|
|
17140
|
+
const moduleClass = module ? capitalize13(module) : "<Module>";
|
|
16434
17141
|
return plan2.predictedChanges.map((change) => change.target.replace(/^\*\//, app ? `apps/${app}/` : "").replaceAll("<module>", module || "<module>").replaceAll("<Module>", moduleClass));
|
|
16435
17142
|
};
|
|
16436
17143
|
var workflowDiagnosticFromDoctor = (diagnostic, fallbackScope) => ({
|
|
@@ -16441,6 +17148,43 @@ var workflowDiagnosticFromDoctor = (diagnostic, fallbackScope) => ({
|
|
|
16441
17148
|
failureScope: (diagnostic.scope ?? fallbackScope) === "baseline" ? "workspace-config" : (diagnostic.scope ?? fallbackScope) === "workflow" ? "source-change" : "unknown",
|
|
16442
17149
|
context: diagnostic.context
|
|
16443
17150
|
});
|
|
17151
|
+
var baselineBlockerCachePath = (workflow2) => `.akan/workflows/baseline/${workflow2}.json`;
|
|
17152
|
+
var blockerFingerprint = (blocker) => [blocker.failureScope, blocker.code, blocker.command ?? "", blocker.kind ?? "", blocker.message].join("|");
|
|
17153
|
+
var applyBaselineBlockerCache = async (workspace, report) => {
|
|
17154
|
+
const cacheableBlockers = report.knownBlockers.filter((blocker) => blocker.failureScope === "workspace-config" || blocker.failureScope === "environment");
|
|
17155
|
+
if (cacheableBlockers.length === 0)
|
|
17156
|
+
return report;
|
|
17157
|
+
const cachePath = baselineBlockerCachePath(report.workflow);
|
|
17158
|
+
const cached = (await workspace.exists(cachePath) ? await workspace.readJson(cachePath) : null) ?? { schemaVersion: 1, workflow: report.workflow, blockers: [] };
|
|
17159
|
+
const knownFingerprints = new Set(cached.blockers.map((blocker) => blocker.fingerprint));
|
|
17160
|
+
const now = new Date().toISOString();
|
|
17161
|
+
const blockers = new Map(cached.blockers.map((blocker) => [blocker.fingerprint, blocker]));
|
|
17162
|
+
for (const blocker of cacheableBlockers) {
|
|
17163
|
+
const fingerprint = blockerFingerprint(blocker);
|
|
17164
|
+
blockers.set(fingerprint, {
|
|
17165
|
+
fingerprint,
|
|
17166
|
+
code: blocker.code,
|
|
17167
|
+
message: blocker.message,
|
|
17168
|
+
failureScope: blocker.failureScope,
|
|
17169
|
+
command: blocker.command,
|
|
17170
|
+
kind: blocker.kind,
|
|
17171
|
+
lastSeenAt: now
|
|
17172
|
+
});
|
|
17173
|
+
}
|
|
17174
|
+
await workspace.writeFile(cachePath, jsonText({ schemaVersion: 1, workflow: report.workflow, blockers: [...blockers.values()] }), { silent: true });
|
|
17175
|
+
return {
|
|
17176
|
+
...report,
|
|
17177
|
+
knownBlockers: report.knownBlockers.map((blocker) => {
|
|
17178
|
+
if (!knownFingerprints.has(blockerFingerprint(blocker)))
|
|
17179
|
+
return blocker;
|
|
17180
|
+
return {
|
|
17181
|
+
...blocker,
|
|
17182
|
+
known: true,
|
|
17183
|
+
message: `Known baseline blocker, unrelated to this source change: ${blocker.message}`
|
|
17184
|
+
};
|
|
17185
|
+
})
|
|
17186
|
+
};
|
|
17187
|
+
};
|
|
16444
17188
|
|
|
16445
17189
|
class WorkflowRunner extends runner("workflow") {
|
|
16446
17190
|
list({ format = "markdown" } = {}) {
|
|
@@ -16529,7 +17273,7 @@ class WorkflowRunner extends runner("workflow") {
|
|
|
16529
17273
|
], plan2);
|
|
16530
17274
|
return await renderApplyReport(report);
|
|
16531
17275
|
}
|
|
16532
|
-
return await renderApplyReport(await new WorkflowExecutor(registry).apply(plan2));
|
|
17276
|
+
return await renderApplyReport(await new WorkflowExecutor(registry, workspace).apply(plan2));
|
|
16533
17277
|
}
|
|
16534
17278
|
async validate(runIdOrPlan, {
|
|
16535
17279
|
format = "markdown",
|
|
@@ -16542,7 +17286,7 @@ class WorkflowRunner extends runner("workflow") {
|
|
|
16542
17286
|
runIdOrPlan,
|
|
16543
17287
|
changedFiles: loaded.changedFiles
|
|
16544
17288
|
});
|
|
16545
|
-
const report = await createWorkflowValidationRunReport({
|
|
17289
|
+
const report = await applyBaselineBlockerCache(workspace, await createWorkflowValidationRunReport({
|
|
16546
17290
|
workflow: loaded.plan?.workflow ?? loaded.workflow,
|
|
16547
17291
|
source: loaded.source,
|
|
16548
17292
|
plan: loaded.plan,
|
|
@@ -16552,7 +17296,7 @@ class WorkflowRunner extends runner("workflow") {
|
|
|
16552
17296
|
baselineDiagnostics: (doctor.baselineDiagnostics ?? []).map((diagnostic) => workflowDiagnosticFromDoctor(diagnostic, "baseline")),
|
|
16553
17297
|
workflowDiagnostics: (doctor.workflowDiagnostics ?? []).map((diagnostic) => workflowDiagnosticFromDoctor(diagnostic, "workflow")),
|
|
16554
17298
|
repairActions: loaded.repairActions
|
|
16555
|
-
});
|
|
17299
|
+
}));
|
|
16556
17300
|
await writeWorkflowRunArtifact(workspace, report);
|
|
16557
17301
|
return renderWorkflowValidation(report, format);
|
|
16558
17302
|
}
|