@geonosis/oxlint-plugin-biological-architecture 2.3.0 → 2.3.1

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/RULES.md CHANGED
@@ -869,7 +869,7 @@ option not named here is one no rule reads.
869
869
  | `dialect-through-the-seam` | — |
870
870
  | `document-sagas-are-generic` | `factories`, `perKindPrefixes`, `within` |
871
871
  | `documents-share-one-table` | `perKindTables` |
872
- | `durable-body-reads-through-steps` | `durableKey`, `durableValue`, `ports`, `stepFactories`, `workflowFactories` |
872
+ | `durable-body-reads-through-steps` | `durableKey`, `durableValue`, `ports`, `stepFactories`, `stepProxies`, `workflowFactories` |
873
873
  | `effect-hook-naming` | — |
874
874
  | `emit-declares-attempts` | `budgetHelpers`, `emitters` |
875
875
  | `font-roles-only` | `allow`, `exemptModules`, `prefix`, `roles` |
@@ -917,7 +917,7 @@ option not named here is one no rule reads.
917
917
  | `route-no-inline-mutation` | `inlineMutationOk`, `mutationPrefixes`, `paths` |
918
918
  | `router-schema-parity` | `ignore`, `mounts`, `routers`, `schemas`, `suffix` |
919
919
  | `service-name-not-reserved` | `moduleFactories`, `reserved` |
920
- | `ssot-no-inline-facts` | |
920
+ | `ssot-no-inline-facts` | `declarationCallees` |
921
921
  | `ssot-no-process-env` | — |
922
922
  | `step-declares-compensation-or-none` | `stepFactories` |
923
923
  | `step-opens-its-own-cell` | `engine`, `hosts`, `scopeKey`, `within`, `wrapper` |
@@ -60,7 +60,11 @@
60
60
  {
61
61
  "ports": [
62
62
  "store",
63
- "billing"
63
+ "billing",
64
+ "q"
65
+ ],
66
+ "stepProxies": [
67
+ "q"
64
68
  ]
65
69
  }
66
70
  ],
@@ -0,0 +1,13 @@
1
+ import { createWorkflow } from '@corpus/workflows'
2
+
3
+ // ACCEPTED: `q` is the engine's step proxy, so every call through it is a step — journalled under
4
+ // its own name and answered from the record on a replay.
5
+ export const settle = createWorkflow(
6
+ 'invoice.settle',
7
+ async (id: string, ctx: { q: { getInvoice: (id: string) => Promise<{ status: string }> } }) => {
8
+ const doc = await ctx.q.getInvoice(id)
9
+
10
+ return doc.status
11
+ },
12
+ { durable: true },
13
+ )
package/dist/index.js CHANGED
@@ -1053,7 +1053,7 @@ var stepNameOf = (node, config) => {
1053
1053
 
1054
1054
  // src/rules/durable-body-reads-through-steps.ts
1055
1055
  var RULE3 = "durable-body-reads-through-steps";
1056
- var ACCEPTS2 = "{ ports: string[] (required), durableKey: string, durableValue: boolean | string, workflowFactories: string[], stepFactories: string[] }";
1056
+ var ACCEPTS2 = "{ ports: string[] (required), durableKey: string, durableValue: boolean | string, workflowFactories: string[], stepFactories: string[], stepProxies: string[] }";
1057
1057
  var DEFAULT_WORKFLOW_FACTORIES = ["createWorkflow"];
1058
1058
  var DEFAULT_DURABLE_KEY = "execution";
1059
1059
  var DEFAULT_DURABLE_VALUE = "durable";
@@ -1085,6 +1085,7 @@ var durableBodyReadsThroughSteps = {
1085
1085
  create(context) {
1086
1086
  const bag = context.options?.[0] ?? {};
1087
1087
  const ports = new Set(requireOption(RULE3, bag.ports, "ports", ACCEPTS2));
1088
+ const proxies = new Set(bag.stepProxies ?? []);
1088
1089
  const steps = stepFactoriesOf(RULE3, bag.stepFactories);
1089
1090
  const workflows = new Set(
1090
1091
  requireOption(RULE3, bag.workflowFactories ?? DEFAULT_WORKFLOW_FACTORIES, "workflowFactories")
@@ -1102,7 +1103,7 @@ var durableBodyReadsThroughSteps = {
1102
1103
  walkNode(node, (inner) => {
1103
1104
  if (inner.type !== "CallExpression" || memoised.has(inner)) return;
1104
1105
  const port = portReachedBy(inner, ports);
1105
- if (port === null) return;
1106
+ if (port === null || portReachedBy(inner, proxies) !== null) return;
1106
1107
  context.report({ data: { port, workflow }, messageId: "freeRead", node: inner });
1107
1108
  });
1108
1109
  }
@@ -1113,7 +1114,9 @@ input or from a step result. A port read written straight into the body \u2014 \
1113
1114
  inline-only: the platform memoises steps by name and does not journal reads, so on a replay the read
1114
1115
  sees what the first invocation wrote, the branch flips, and the run unwinds work it had completed.
1115
1116
  Move the decision into a step (\`const doc = await ensureDraft(id)\`) and it is memoised with the run.
1116
- Name this repo's ports in \`ports\`; enabled without them the rule refuses the run. What it can SEE is a
1117
+ Name this repo's ports in \`ports\`; enabled without them the rule refuses the run. A receiver the
1118
+ engine already made steps of \u2014 \`stepsOf\`' proxy over bound queries \u2014 goes in \`stepProxies\`: a call
1119
+ through it is journalled under its own name and is what this rule asks for. What it can SEE is a
1117
1120
  call on a name \`ports\` lists: a read moved one function out \u2014 \`readStatus(id)\`, with the port inside
1118
1121
  it \u2014 is invisible here, and no lint rule that reads one file can follow it. Name the helper in
1119
1122
  \`ports\` too when a body reaches the outside world through one; a helper that is really a step is
@@ -1135,6 +1138,7 @@ better made one. \`durableKey\` /
1135
1138
  durableValue: { type: ["boolean", "string"] },
1136
1139
  ports: { items: { type: "string" }, type: "array" },
1137
1140
  stepFactories: { items: { type: "string" }, type: "array" },
1141
+ stepProxies: { items: { type: "string" }, type: "array" },
1138
1142
  workflowFactories: { items: { type: "string" }, type: "array" }
1139
1143
  },
1140
1144
  type: "object"
@@ -5136,13 +5140,14 @@ var styleAttributes = /* @__PURE__ */ new Set([
5136
5140
  "autoComplete"
5137
5141
  ]);
5138
5142
  var styleCallees = /* @__PURE__ */ new Set(["cn", "clsx", "twMerge", "cva", "tv"]);
5139
- var declarationCallees = /* @__PURE__ */ new Set([
5143
+ var DECLARATION_CALLEES = [
5140
5144
  "declare",
5141
5145
  "saga",
5142
5146
  "step",
5143
5147
  "action",
5144
5148
  "defineEvent",
5145
5149
  "defineWorkflow",
5150
+ "createWorkflow",
5146
5151
  "createStep",
5147
5152
  "sqliteTable",
5148
5153
  "text",
@@ -5156,7 +5161,7 @@ var declarationCallees = /* @__PURE__ */ new Set([
5156
5161
  "check",
5157
5162
  "literal",
5158
5163
  "enum"
5159
- ]);
5164
+ ];
5160
5165
  var formFieldCallees = /* @__PURE__ */ new Set([
5161
5166
  "register",
5162
5167
  "watch",
@@ -5189,7 +5194,7 @@ var nameOf4 = (node) => {
5189
5194
  if (node.type === "Literal") return String(node.value);
5190
5195
  return void 0;
5191
5196
  };
5192
- var isSpelledAsStyleOrModule = (node) => {
5197
+ var isSpelledAsStyleOrModule = (node, declarationCallees) => {
5193
5198
  let current = node.parent;
5194
5199
  let child = node;
5195
5200
  while (current && typeof current.type === "string" && current.type !== "Program") {
@@ -5216,9 +5221,13 @@ var ssotNoInlineFacts = {
5216
5221
  create(context) {
5217
5222
  const normalized = normalise(context.filename);
5218
5223
  if (factOwners.some((owner) => owner.test(normalized))) return {};
5224
+ const declarationCallees = /* @__PURE__ */ new Set([
5225
+ ...DECLARATION_CALLEES,
5226
+ ...context.options?.[0]?.declarationCallees ?? []
5227
+ ]);
5219
5228
  const check = (literal, node) => {
5220
5229
  if (!isFactShaped(literal)) return;
5221
- if (isSpelledAsStyleOrModule(node)) return;
5230
+ if (isSpelledAsStyleOrModule(node, declarationCallees)) return;
5222
5231
  context.report({ data: { literal }, messageId: "inlineFact", node });
5223
5232
  };
5224
5233
  return {
@@ -5233,7 +5242,9 @@ var ssotNoInlineFacts = {
5233
5242
  },
5234
5243
  fixShape: `A route, a URL, a code, a dotted key: a fact is declared once, in the module that owns it, and
5235
5244
  imported. An inline literal used as configuration is a second copy waiting to drift \u2014 name it and put
5236
- it where its owner lives.`,
5245
+ it where its owner lives. A literal that DECLARES rather than repeats \u2014 the first argument to
5246
+ \`createWorkflow\`, \`createStep\`, \`defineEvent\` \u2014 is the declaration itself and is left alone; name
5247
+ this repo's own factories in \`declarationCallees\` and they are added to those.`,
5237
5248
  meta: {
5238
5249
  docs: {
5239
5250
  description: "A fact \u2014 a route, a URL, a CODE, a dotted.name, a long key \u2014 is declared once, in its owner module (the owning module, lib/routes.ts, lib/env.ts, @during/client), and imported everywhere else. Spelling it inline makes a second source."
@@ -5241,7 +5252,15 @@ it where its owner lives.`,
5241
5252
  messages: {
5242
5253
  inlineFact: '"{{literal}}" is a fact spelled inline. Declare it once in its owner module and import it.'
5243
5254
  },
5244
- schema: [],
5255
+ schema: [
5256
+ {
5257
+ additionalProperties: false,
5258
+ properties: {
5259
+ declarationCallees: { items: { type: "string" }, type: "array" }
5260
+ },
5261
+ type: "object"
5262
+ }
5263
+ ],
5245
5264
  type: "problem"
5246
5265
  }
5247
5266
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@geonosis/oxlint-plugin-biological-architecture",
3
- "version": "2.3.0",
3
+ "version": "2.3.1",
4
4
  "types": "./dist/index.d.ts",
5
5
  "description": "Biological tier architecture as lint — the union of the dielime and during.day rule sets, shipped as presets.",
6
6
  "keywords": [
@@ -44,7 +44,7 @@
44
44
  "oxlint": ">=1.77"
45
45
  },
46
46
  "devDependencies": {
47
- "@geonosis/lint-parity": "2.3.0"
47
+ "@geonosis/lint-parity": "2.3.1"
48
48
  },
49
49
  "engines": {
50
50
  "node": ">=22"