@geonosis/oxlint-plugin-biological-architecture 2.6.0 → 2.7.0
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/CHANGELOG.md +36 -0
- package/README.md +0 -2
- package/RULES.md +11 -38
- package/corpus/.oxlintrc.json +0 -18
- package/corpus/manifest.json +0 -2
- package/dist/{chunk-KV7JRNAP.js → chunk-24K5232K.js} +0 -2
- package/dist/index.d.ts +11 -1
- package/dist/index.js +126 -236
- package/dist/presets.js +1 -1
- package/package.json +2 -2
- package/corpus/domains/document/workflows/bad-per-kind-saga.ts +0 -3
- package/corpus/domains/document/workflows/bad-per-kind-workflow.ts +0 -5
- package/corpus/domains/document/workflows/good-minted-workflow.ts +0 -8
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,41 @@
|
|
|
1
1
|
# @geonosis/oxlint-plugin-biological-architecture
|
|
2
2
|
|
|
3
|
+
## 2.7.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 08c9653: The kit knows no document kind. `document-sagas-are-generic` and `documents-share-one-table` are
|
|
8
|
+
gone from the plugin and from the `backend-workflows` preset, with their corpus and fixtures: both
|
|
9
|
+
took a list of one consumer's document kinds (`perKindPrefixes`, `perKindTables`) and enforced a
|
|
10
|
+
vocabulary the kit has no business holding — a document entity is whatever extends `Document`, and
|
|
11
|
+
the registry a consumer builds is the only enumeration there is. Their intent is held by types
|
|
12
|
+
now: a consumer's per-entity maps are folds over the registry, and a per-entity saga has nowhere to
|
|
13
|
+
be written once `documentWorkflows` mints them. Their ids stay for one release: oxlint refuses a
|
|
14
|
+
config that names a rule its plugin does not export, so a config naming either still parses, the
|
|
15
|
+
id reports nothing and says once that it is retired, and `geonosis doctor` WARNs naming it where
|
|
16
|
+
it would have failed. Migration: remove the block before the next major, when the ids go; the
|
|
17
|
+
doctor's floor table no longer lists them.
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- c8c5d51: `documentWorkflows(entity, { effects, ports })` at `@geonosis/document/workflows` — T3, the org
|
|
22
|
+
workflows over the engine, one body per Document: `create`, `save`, `setStatus`, `remove`, `send`
|
|
23
|
+
(durable), `convert`, `duplicate`, `share`, each named for the entity. A host decides
|
|
24
|
+
`effects.announce(fact)` — the product's events off a `DocumentFact` — and answers three ports,
|
|
25
|
+
`door`, `link` and `mail` (`Result<void, MailUndelivered>` from `better-result`); `beforeCreate`,
|
|
26
|
+
`conversion`, the mail words, `counter`, `actor`, `guard`, `now` and `seed` default, and a
|
|
27
|
+
counter-numbered entity or a template on a host that declares neither is refused by name. The
|
|
28
|
+
factory makes the two steps that reach the outside world, so the durable-body law holds on every
|
|
29
|
+
host. A third entry, like `./store`, so the core stays off every floor and browser-safe. The
|
|
30
|
+
Standard Schema builders the surface wrote for itself move to the core (`objectOf`, `enumOf`,
|
|
31
|
+
`optional`, `nullable`, `arrayOf`, `merge`, the scalars, `validate`) and `SchemaAdapter` is the
|
|
32
|
+
adapter's name (`SurfaceSchemaAdapter` stays as an alias). `@geonosis/workflows` and
|
|
33
|
+
`better-result` join the package's dependencies. The plugin's `document-sagas-are-generic` and
|
|
34
|
+
`documents-share-one-table` no longer carry `floor: pending`: the store shipped at 0.4 and the
|
|
35
|
+
workflows ship here. `documentIdentifiers` spells every identifier as a literal type off the name it was given (`CamelOf`, `DocumentIdentifiers`), so a consumer indexes a typed router map by the camel name without a cast. `documentEntities(map).keyed(pick)` answers one value per entity under its name, total by construction.
|
|
36
|
+
|
|
37
|
+
## 2.6.1
|
|
38
|
+
|
|
3
39
|
## 2.6.0
|
|
4
40
|
|
|
5
41
|
## 2.5.3
|
package/README.md
CHANGED
|
@@ -136,8 +136,6 @@ months. Carry these across, or turn the rule off:
|
|
|
136
136
|
| `no-brand-names` | `{ brands, allowedSubstrings }` | refuses the run |
|
|
137
137
|
| `organelle-dependency` | `{ sharedFeatures }` | only `shared` crosses a feature boundary |
|
|
138
138
|
| `cell-no-cross-feature-organelles` | `{ sharedFeatures }` | only `shared` crosses a feature boundary |
|
|
139
|
-
| `documents-share-one-table` | `{ perKindTables }` | refuses the run |
|
|
140
|
-
| `document-sagas-are-generic` | `{ perKindPrefixes }` | refuses the run |
|
|
141
139
|
| `step-opens-its-own-cell` | `{ engine, within, wrapper }` | refuses the run |
|
|
142
140
|
| `no-raw-html-atoms` | the positional element→atom map | refuses the run |
|
|
143
141
|
| `layer-walls` | `{ layers: [{ name, paths, mayImport }], externals? }` | refuses the run |
|
package/RULES.md
CHANGED
|
@@ -9,11 +9,14 @@ Read from the two source trees on 2026-08-29:
|
|
|
9
9
|
One plugin name, two rule sets, no shared code. **33 rules had the same filename in both trees; only
|
|
10
10
|
3 of those 33 were byte-identical.** A fix in one never reached the other.
|
|
11
11
|
|
|
12
|
-
The union here is **
|
|
13
|
-
`
|
|
14
|
-
|
|
15
|
-
`no-
|
|
16
|
-
`
|
|
12
|
+
The union here is **52 rules** — 54 when it was cut, less `document-sagas-are-generic` and
|
|
13
|
+
`documents-share-one-table`, retired in 2.7.0 because both enforced one consumer's document kinds —
|
|
14
|
+
plus twenty-eight the kit wrote for itself: `layer-walls`, `emit-declares-attempts`,
|
|
15
|
+
`cell-no-cross-feature-organelles`, the `backend-medusa` ten, `no-unregistered-plugin-dir` +
|
|
16
|
+
`router-schema-parity`, the `themekit` two, `no-mock-db-in-integration`, `todo-names-its-plan`,
|
|
17
|
+
`boundary-time-is-primitive`, `durable-body-reads-through-steps`, `subpath-over-barrel` and the six
|
|
18
|
+
of the W67 batch — **80**. The two retired ids still resolve for one release, as no-ops that say
|
|
19
|
+
they are retired, so a config naming them parses; they go at the next major.
|
|
17
20
|
Every one of the twenty-eight is marked **written here** in the inventory, and the table below is
|
|
18
21
|
held against that column rather than kept by hand.
|
|
19
22
|
|
|
@@ -22,10 +25,10 @@ held against that column rather than kept by hand.
|
|
|
22
25
|
| in both trees, byte-identical | 3 |
|
|
23
26
|
| in both trees, **diverged** | 30 |
|
|
24
27
|
| dielime only | 3 |
|
|
25
|
-
| during.day only |
|
|
26
|
-
| **union** | **
|
|
28
|
+
| during.day only | 16 |
|
|
29
|
+
| **union** | **52** |
|
|
27
30
|
| written here | 28 |
|
|
28
|
-
| **total** | **
|
|
31
|
+
| **total** | **80** |
|
|
29
32
|
|
|
30
33
|
## How divergence was resolved
|
|
31
34
|
|
|
@@ -513,26 +516,6 @@ Closing it also fixed a hole in the barrel rule's own pattern, which required a
|
|
|
513
516
|
therefore no-op'd on the cwd-relative `cells/index.ts` oxlint reports for a package whose own root
|
|
514
517
|
holds `cells/`.
|
|
515
518
|
|
|
516
|
-
### `documents-share-one-table` — matches `pgTable` as well as `sqliteTable`
|
|
517
|
-
|
|
518
|
-
during.day's fork matched `literalNamedBy(node, 'sqliteTable')` and nothing else, and every tenant
|
|
519
|
-
table on that tree has been `pgTable` since its plan 037. Its own probe: a well-formed per-kind
|
|
520
|
-
table
|
|
521
|
-
|
|
522
|
-
```ts
|
|
523
|
-
export const invoices = pgTable('invoices', { id: text('id').primaryKey(), orgId: orgIdColumn() })
|
|
524
|
-
```
|
|
525
|
-
|
|
526
|
-
under `packages/db/src/schema/tenant/` produced **zero** findings from this rule; only the malformed
|
|
527
|
-
variant was caught, by `tenant-tables-carry-org-id`, and by accident. The fork's rule had been dead
|
|
528
|
-
since the tenant plane moved to Postgres.
|
|
529
|
-
|
|
530
|
-
The kit matching both constructors is therefore a fix, not a widening for its own sake. It stands
|
|
531
|
-
because the rule is about the second storage a base entity retired — which is true whatever the
|
|
532
|
-
dialect — and because `dialect-through-the-seam` already says the dialect is a seam fact rather than
|
|
533
|
-
a thing a document kind gets to have an opinion about. Both branches are exercised through the real
|
|
534
|
-
binary in `src/rules/__fixtures__/packages/db/src/schema/tenant/`, so neither can go quiet again.
|
|
535
|
-
|
|
536
519
|
### `no-raw-html-atoms` — the tier it was always documented for (0.3.0)
|
|
537
520
|
|
|
538
521
|
Its own description said levels 2-6 and it fired at every level, `atoms/` included, where a raw
|
|
@@ -567,13 +550,9 @@ rule the option refusal exists to stop, one option along.
|
|
|
567
550
|
| `organelle-dependency` | `sharedFeatures` | `['shared']` — during.day's `charts`/`document` are config, not law |
|
|
568
551
|
| `mutating-step-declares-retry` | `retryKey` | `maxRetries` — Medusa's key. `@geonosis/workflows` spells the same budget `retry: { limit, backoff }` (`create-step.ts`), and with the key compiled in a correctly budgeted step on that engine was a finding for ever |
|
|
569
552
|
| `mutating-step-declares-retry` | `retryLimitKey` | `limit` — the key that holds the NUMBER when the budget is an object. #191: reading only the bare form let `retry: { limit: 0 }` pass, which is the same silence as `maxRetries: 0` |
|
|
570
|
-
| `documents-share-one-table` | `perKindTables` | **refuses the run** |
|
|
571
553
|
| `worker-handles-are-scoped` | `within` + `wrapper` | **refuses the run** — `withCells` and `/apps/api/src/` were compiled in, so the rule served one repo's layout and one repo's vocabulary and a scope opener called anything else read as unscoped for ever |
|
|
572
554
|
| `subpath-over-barrel` | `packages` (`{ name, subpaths: { <subpath>: string[] } }[]`) | **refuses the run** — which of a repo's own packages expose subpaths, and which names live under each, is a map only that package's owner has |
|
|
573
555
|
| `durable-body-reads-through-steps` | `ports` | **refuses the run** — what a body reaches the outside world through is the repo's vocabulary; `durableKey` / `durableValue` (default `durable: true`) say how a workflow declares itself durable |
|
|
574
|
-
| `document-sagas-are-generic` | `perKindPrefixes` | **refuses the run** |
|
|
575
|
-
| `document-sagas-are-generic` | `within` | **refuses the run** — `/packages/workflows/src/` was compiled in, so the same per-kind saga one directory over was silent and no other layout could enable the rule at all |
|
|
576
|
-
| `document-sagas-are-generic` | `factories` | `['saga', 'createWorkflow']` — the callee was `saga` alone, so a per-entity `createWorkflow('invoice.create', …)` produced no finding (026-W2, measured). A name assembled from the entity is a template literal the rule cannot read: that is the mint the rule sends people to, not a gap in it |
|
|
577
556
|
| `unique-query-step-name` | `queryStepCalls` | **refuses the run** — the two names it shipped with are Medusa framework calls with no counterpart, so on the org engine the rule had zero reach while reading as enforced (026-W2, measured through the binary). There is no second spelling to inherit: `@geonosis/workflows` has no query-step primitive, and a repeated step name there is DEFINED rather than lost — `reserve`, `reserve#2` in call order (`engine.ts:124`) |
|
|
578
557
|
| `no-raw-html-atoms` | (positional) element→atom map | **refuses the run** |
|
|
579
558
|
| `no-raw-html-atoms` | `scope` (second positional, `{ scope: ["cells", …] }`) | every file except the atom tier |
|
|
@@ -710,8 +689,6 @@ has, and one a kit that guessed at it would keep stale on somebody else's behalf
|
|
|
710
689
|
| `compound-no-stores` | frontend | — | `directionRule` | yes | yes | diverged |
|
|
711
690
|
| `constants-in-constants-file` | backend-workflows | — | `paths` | — | yes | during only |
|
|
712
691
|
| `dialect-through-the-seam` | backend-workflows | — | `onImportSource` + `mergeVisitors` + `paths` | — | yes | during only |
|
|
713
|
-
| `document-sagas-are-generic` | backend-workflows | `perKindPrefixes` | `paths` + `options` + `literal-call` | — | yes | during only |
|
|
714
|
-
| `documents-share-one-table` | backend-workflows | `perKindTables` | `paths` + `options` + `literal-call` | — | yes | during only |
|
|
715
692
|
| `durable-body-reads-through-steps` | backend-workflows | `ports` | `nodes` + `objects` + `steps` + `options` | — | — | **written here** (#167, design-026 §8) |
|
|
716
693
|
| `effect-hook-naming` | frontend | — | `paths` | yes | yes | diverged |
|
|
717
694
|
| `emit-declares-attempts` | backend-medusa | — | `options` | — | — | **written here** |
|
|
@@ -867,8 +844,6 @@ option not named here is one no rule reads.
|
|
|
867
844
|
| `compound-no-stores` | — |
|
|
868
845
|
| `constants-in-constants-file` | — |
|
|
869
846
|
| `dialect-through-the-seam` | — |
|
|
870
|
-
| `document-sagas-are-generic` | `factories`, `perKindPrefixes`, `within` |
|
|
871
|
-
| `documents-share-one-table` | `perKindTables` |
|
|
872
847
|
| `durable-body-reads-through-steps` | `durableKey`, `durableValue`, `ports`, `stepFactories`, `stepProxies`, `workflowFactories` |
|
|
873
848
|
| `effect-hook-naming` | — |
|
|
874
849
|
| `emit-declares-attempts` | `budgetHelpers`, `emitters` |
|
|
@@ -951,8 +926,6 @@ itself, and the doctor says so on the `exercised` line.
|
|
|
951
926
|
|
|
952
927
|
| Rule | Floor | Shipped |
|
|
953
928
|
|---|---|---|
|
|
954
|
-
| `document-sagas-are-generic` | `document` | PENDING |
|
|
955
|
-
| `documents-share-one-table` | `document` | PENDING |
|
|
956
929
|
| `step-opens-its-own-cell` | `workflows` | yes |
|
|
957
930
|
|
|
958
931
|
<!-- END GENERATED FLOORS -->
|
package/corpus/.oxlintrc.json
CHANGED
|
@@ -37,24 +37,6 @@
|
|
|
37
37
|
"biological-architecture/compound-no-stores": "error",
|
|
38
38
|
"biological-architecture/constants-in-constants-file": "error",
|
|
39
39
|
"biological-architecture/dialect-through-the-seam": "error",
|
|
40
|
-
"biological-architecture/document-sagas-are-generic": [
|
|
41
|
-
"error",
|
|
42
|
-
{
|
|
43
|
-
"perKindPrefixes": [
|
|
44
|
-
"invoice"
|
|
45
|
-
],
|
|
46
|
-
"within": "(?:__fixtures__|corpus)/domains/[^/]+/workflows/"
|
|
47
|
-
}
|
|
48
|
-
],
|
|
49
|
-
"biological-architecture/documents-share-one-table": [
|
|
50
|
-
"error",
|
|
51
|
-
{
|
|
52
|
-
"perKindTables": [
|
|
53
|
-
"invoices",
|
|
54
|
-
"quotes"
|
|
55
|
-
]
|
|
56
|
-
}
|
|
57
|
-
],
|
|
58
40
|
"biological-architecture/durable-body-reads-through-steps": [
|
|
59
41
|
"error",
|
|
60
42
|
{
|
package/corpus/manifest.json
CHANGED
|
@@ -12,8 +12,6 @@
|
|
|
12
12
|
"biological-architecture/compound-no-stores",
|
|
13
13
|
"biological-architecture/constants-in-constants-file",
|
|
14
14
|
"biological-architecture/dialect-through-the-seam",
|
|
15
|
-
"biological-architecture/document-sagas-are-generic",
|
|
16
|
-
"biological-architecture/documents-share-one-table",
|
|
17
15
|
"biological-architecture/durable-body-reads-through-steps",
|
|
18
16
|
"biological-architecture/effect-hook-naming",
|
|
19
17
|
"biological-architecture/emit-declares-attempts",
|
|
@@ -42,8 +42,6 @@ var BACKEND_WORKFLOWS = [
|
|
|
42
42
|
"boundary-time-is-primitive",
|
|
43
43
|
"constants-in-constants-file",
|
|
44
44
|
"dialect-through-the-seam",
|
|
45
|
-
"document-sagas-are-generic",
|
|
46
|
-
"documents-share-one-table",
|
|
47
45
|
"durable-body-reads-through-steps",
|
|
48
46
|
"mutating-step-declares-retry",
|
|
49
47
|
"no-date-string-compare",
|
package/dist/index.d.ts
CHANGED
|
@@ -36,6 +36,16 @@ type ProbeTree = {
|
|
|
36
36
|
};
|
|
37
37
|
type ProbeFn = (options: readonly unknown[]) => Probe | ProbeTree;
|
|
38
38
|
|
|
39
|
+
type RetiredRule = Rule & {
|
|
40
|
+
meta: Rule['meta'] & {
|
|
41
|
+
retired: {
|
|
42
|
+
reason: string;
|
|
43
|
+
since: string;
|
|
44
|
+
};
|
|
45
|
+
};
|
|
46
|
+
};
|
|
47
|
+
declare const RETIRED_RULES: Record<'document-sagas-are-generic' | 'documents-share-one-table', RetiredRule>;
|
|
48
|
+
|
|
39
49
|
type Rule = {
|
|
40
50
|
create: (context: never) => Record<string, unknown>;
|
|
41
51
|
fixShape: string;
|
|
@@ -123,4 +133,4 @@ declare const plugin: {
|
|
|
123
133
|
rules: Record<string, Rule>;
|
|
124
134
|
};
|
|
125
135
|
|
|
126
|
-
export { Preset, type Rule, type RuleName, plugin as default, rules };
|
|
136
|
+
export { Preset, RETIRED_RULES, type Rule, type RuleName, plugin as default, rules };
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
PRESUMED_ENGINES,
|
|
4
4
|
RENAMED_TO,
|
|
5
5
|
rulesOfPreset
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-24K5232K.js";
|
|
7
7
|
|
|
8
8
|
// src/index.ts
|
|
9
9
|
import { createRequire } from "module";
|
|
@@ -257,16 +257,6 @@ var requireOption = (rule, value, option, accepts) => {
|
|
|
257
257
|
}
|
|
258
258
|
return value;
|
|
259
259
|
};
|
|
260
|
-
var requireOptionHere = (rule, value, option, file, accepts) => {
|
|
261
|
-
if (isMissing(value)) {
|
|
262
|
-
throw new OptionMissing(
|
|
263
|
-
rule,
|
|
264
|
-
option,
|
|
265
|
-
`${refusalHeader(rule, option)} It is enabled over "${file}", which it would judge, and its \`${option}\` option is ${NOTHING}. Configure \`${option}\`, or turn the rule off for this tree.${accepts === void 0 ? "" : ` It accepts ${accepts}.`}`
|
|
266
|
-
);
|
|
267
|
-
}
|
|
268
|
-
return value;
|
|
269
|
-
};
|
|
270
260
|
var raisedOver = /* @__PURE__ */ new Map();
|
|
271
261
|
var fileOf2 = (context) => {
|
|
272
262
|
const named = context?.filename;
|
|
@@ -884,155 +874,6 @@ configs. Everywhere else, use the dialect-free aliases the seam exports (\`Datab
|
|
|
884
874
|
};
|
|
885
875
|
var dialect_through_the_seam_default = dialectThroughTheSeam;
|
|
886
876
|
|
|
887
|
-
// src/rules/document-sagas-are-generic.ts
|
|
888
|
-
var escapeForRegex = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
889
|
-
var RULE2 = "document-sagas-are-generic";
|
|
890
|
-
var DEFAULT_FACTORIES = ["saga", "createWorkflow"];
|
|
891
|
-
var perEntityNameOf = (node, factories) => {
|
|
892
|
-
for (const factory of factories) {
|
|
893
|
-
const name = literalNamedBy(node, factory);
|
|
894
|
-
if (name !== null) return name;
|
|
895
|
-
}
|
|
896
|
-
return null;
|
|
897
|
-
};
|
|
898
|
-
var declaresAFlow = (text, factories) => factories.some((factory) => new RegExp(`\\b${escapeForRegex(factory)}\\s*\\(`).test(text));
|
|
899
|
-
var documentSagasAreGeneric = {
|
|
900
|
-
create(context) {
|
|
901
|
-
const factories = requireOption(
|
|
902
|
-
RULE2,
|
|
903
|
-
context.options?.[0]?.factories ?? DEFAULT_FACTORIES,
|
|
904
|
-
"factories"
|
|
905
|
-
);
|
|
906
|
-
const filename = normalise(context.filename);
|
|
907
|
-
const named = context.options?.[0]?.within;
|
|
908
|
-
const insideTree = named === void 0 || named === "" ? void 0 : new RegExp(named).test(filename);
|
|
909
|
-
if (insideTree === false) return {};
|
|
910
|
-
if (insideTree === void 0 && !declaresAFlow(context.sourceCode?.text ?? "", factories)) {
|
|
911
|
-
return {};
|
|
912
|
-
}
|
|
913
|
-
const prefixes = requireOptionHere(
|
|
914
|
-
RULE2,
|
|
915
|
-
context.options?.[0]?.perKindPrefixes,
|
|
916
|
-
"perKindPrefixes",
|
|
917
|
-
filename
|
|
918
|
-
);
|
|
919
|
-
const within = requireOptionHere(RULE2, named, "within", filename);
|
|
920
|
-
if (!new RegExp(within).test(filename)) return {};
|
|
921
|
-
const perKindPrefix = new RegExp(`^(?:${prefixes.map(escapeForRegex).join("|")})\\.`);
|
|
922
|
-
return {
|
|
923
|
-
CallExpression(node) {
|
|
924
|
-
const name = perEntityNameOf(node, factories);
|
|
925
|
-
if (name === null || !perKindPrefix.test(name)) return;
|
|
926
|
-
context.report({ data: { name }, messageId: "perKindSaga", node });
|
|
927
|
-
}
|
|
928
|
-
};
|
|
929
|
-
},
|
|
930
|
-
fixShape: `A saga named for one document kind (\`invoice.issue\`, \`quote.accept\`) is the hand-written fork the
|
|
931
|
-
generic base entity replaced. Mint it from the generic factory \u2014 \`documentSagas(entity, effects)\` \u2014
|
|
932
|
-
and pass the kind as data. The same holds for a workflow: \`createWorkflow('invoice.create', \u2026)\` is
|
|
933
|
-
the fork, \`documentWorkflows(entity)\` is the mint. A name assembled from the entity \u2014 a template
|
|
934
|
-
literal \u2014 is what minting looks like and is left alone by construction. Configure the kind vocabulary
|
|
935
|
-
through \`perKindPrefixes\`, the tree that holds the flows through \`within\` (a regex over the
|
|
936
|
-
filename), and \`factories\` if the repo declares them under other names; enabled without
|
|
937
|
-
\`perKindPrefixes\` or \`within\` the rule refuses the run.`,
|
|
938
|
-
meta: {
|
|
939
|
-
floor: { name: "document", pending: true },
|
|
940
|
-
docs: {
|
|
941
|
-
description: "Document sagas are minted, not written: `documentSagas(entity, effects)` gives every entity that extends Document its create/save/setStatus/remove/send/convert/duplicate/share from one body. A saga or workflow named with a LITERAL for one entity is a fork; a name assembled from the entity is the mint and is unreadable here on purpose. `factories`, `perKindPrefixes` and `within` are options."
|
|
942
|
-
},
|
|
943
|
-
messages: {
|
|
944
|
-
perKindSaga: '"{{name}}" is a hand-written flow for one entity. Every entity that extends Document gets its sagas from `documentSagas(entity, effects)` and its workflows from the same mint; put what this entity decides in its `Document.extend` definition or in its `DocumentEffects`.'
|
|
945
|
-
},
|
|
946
|
-
schema: [
|
|
947
|
-
{
|
|
948
|
-
additionalProperties: false,
|
|
949
|
-
properties: {
|
|
950
|
-
factories: { items: { type: "string" }, type: "array" },
|
|
951
|
-
perKindPrefixes: { items: { type: "string" }, type: "array" },
|
|
952
|
-
within: { type: "string" }
|
|
953
|
-
},
|
|
954
|
-
type: "object"
|
|
955
|
-
}
|
|
956
|
-
],
|
|
957
|
-
type: "problem"
|
|
958
|
-
},
|
|
959
|
-
/** Every half comes from the options now: the vocabulary, the tree, and the factory it is minted by. */
|
|
960
|
-
probe(options) {
|
|
961
|
-
const { perKindPrefixes = [], within = "" } = bagOf(options);
|
|
962
|
-
const factory = firstOf(bagOf(options).factories, DEFAULT_FACTORIES);
|
|
963
|
-
return {
|
|
964
|
-
path: pathMatching(within, "geonosis-probe-saga.ts"),
|
|
965
|
-
source: `import { ${factory} } from 'sagaflow-js'
|
|
966
|
-
|
|
967
|
-
export const geonosisProbe = ${factory}('${perKindPrefixes[0] ?? ""}.geonosis-probe', {})
|
|
968
|
-
`
|
|
969
|
-
};
|
|
970
|
-
}
|
|
971
|
-
};
|
|
972
|
-
var document_sagas_are_generic_default = documentSagasAreGeneric;
|
|
973
|
-
|
|
974
|
-
// src/rules/documents-share-one-table.ts
|
|
975
|
-
var TABLE_CALLEES = ["sqliteTable", "pgTable"];
|
|
976
|
-
var documentsShareOneTable = {
|
|
977
|
-
create(context) {
|
|
978
|
-
const perKindTables = new Set(
|
|
979
|
-
requireOption(
|
|
980
|
-
"documents-share-one-table",
|
|
981
|
-
context.options?.[0]?.perKindTables,
|
|
982
|
-
"perKindTables"
|
|
983
|
-
)
|
|
984
|
-
);
|
|
985
|
-
if (!/\/packages\/db\/src\/schema\//.test(normalise(context.filename))) return {};
|
|
986
|
-
return {
|
|
987
|
-
CallExpression(node) {
|
|
988
|
-
for (const callee of TABLE_CALLEES) {
|
|
989
|
-
const table = literalNamedBy(node, callee);
|
|
990
|
-
if (table === null || !perKindTables.has(table)) continue;
|
|
991
|
-
context.report({ data: { table }, messageId: "perKindTable", node });
|
|
992
|
-
return;
|
|
993
|
-
}
|
|
994
|
-
}
|
|
995
|
-
};
|
|
996
|
-
},
|
|
997
|
-
fixShape: `Every document kind is a row of the one \`documents\` table with a \`kind\` column, not a table of its
|
|
998
|
-
own. A \`pgTable('invoices', \u2026)\` beside a \`pgTable('quotes', \u2026)\` is the second storage the base entity
|
|
999
|
-
retired: write the row, not the table. Both constructors count \u2014 \`pgTable\` and \`sqliteTable\` \u2014 since
|
|
1000
|
-
the dialect is a seam fact, not a reason for a kind to own storage. The forbidden table names are the rule's
|
|
1001
|
-
\`perKindTables\` option; enabled without it the rule refuses the run rather than passing every
|
|
1002
|
-
schema silently.`,
|
|
1003
|
-
meta: {
|
|
1004
|
-
floor: { name: "document", pending: true },
|
|
1005
|
-
docs: {
|
|
1006
|
-
description: "Documents share ONE table: `documents` holds the head every kind derives and the body its kind declares. A table named for one kind of document is a second storage."
|
|
1007
|
-
},
|
|
1008
|
-
messages: {
|
|
1009
|
-
perKindTable: '"{{table}}" is a table for one kind of document. Every kind is a row of `documents` \u2014 add the kind to `documentEntities` and let its `headOf` fill the columns.'
|
|
1010
|
-
},
|
|
1011
|
-
schema: [
|
|
1012
|
-
{
|
|
1013
|
-
additionalProperties: false,
|
|
1014
|
-
properties: {
|
|
1015
|
-
perKindTables: { items: { type: "string" }, type: "array" }
|
|
1016
|
-
},
|
|
1017
|
-
type: "object"
|
|
1018
|
-
}
|
|
1019
|
-
],
|
|
1020
|
-
type: "problem"
|
|
1021
|
-
},
|
|
1022
|
-
/** The schema directory is compiled in; the forbidden table names are this repo's vocabulary. */
|
|
1023
|
-
probe(options) {
|
|
1024
|
-
const { perKindTables = [] } = bagOf(options);
|
|
1025
|
-
return {
|
|
1026
|
-
path: "packages/db/src/schema/geonosis-probe-table.ts",
|
|
1027
|
-
source: `import { pgTable, text } from 'drizzle-orm/pg-core'
|
|
1028
|
-
|
|
1029
|
-
export const geonosisProbe = pgTable('${perKindTables[0] ?? ""}', { id: text('id') })
|
|
1030
|
-
`
|
|
1031
|
-
};
|
|
1032
|
-
}
|
|
1033
|
-
};
|
|
1034
|
-
var documents_share_one_table_default = documentsShareOneTable;
|
|
1035
|
-
|
|
1036
877
|
// src/rules/lib/objects.ts
|
|
1037
878
|
var propertiesOf = (node) => {
|
|
1038
879
|
const object = node;
|
|
@@ -1084,7 +925,7 @@ var stepNameOf = (node, config) => {
|
|
|
1084
925
|
};
|
|
1085
926
|
|
|
1086
927
|
// src/rules/durable-body-reads-through-steps.ts
|
|
1087
|
-
var
|
|
928
|
+
var RULE2 = "durable-body-reads-through-steps";
|
|
1088
929
|
var ACCEPTS2 = "{ ports: string[] (required), durableKey: string, durableValue: boolean | string, workflowFactories: string[], stepFactories: string[], stepProxies: string[] }";
|
|
1089
930
|
var DEFAULT_WORKFLOW_FACTORIES = ["createWorkflow"];
|
|
1090
931
|
var DEFAULT_DURABLE_KEY = "execution";
|
|
@@ -1116,13 +957,13 @@ var insideAStep = (node, factories) => {
|
|
|
1116
957
|
var durableBodyReadsThroughSteps = {
|
|
1117
958
|
create(context) {
|
|
1118
959
|
const bag = context.options?.[0] ?? {};
|
|
1119
|
-
const ports = new Set(requireOption(
|
|
960
|
+
const ports = new Set(requireOption(RULE2, bag.ports, "ports", ACCEPTS2));
|
|
1120
961
|
const proxies = new Set(bag.stepProxies ?? []);
|
|
1121
|
-
const steps = stepFactoriesOf(
|
|
962
|
+
const steps = stepFactoriesOf(RULE2, bag.stepFactories);
|
|
1122
963
|
const workflows = new Set(
|
|
1123
|
-
requireOption(
|
|
964
|
+
requireOption(RULE2, bag.workflowFactories ?? DEFAULT_WORKFLOW_FACTORIES, "workflowFactories")
|
|
1124
965
|
);
|
|
1125
|
-
const durableKey = requireOption(
|
|
966
|
+
const durableKey = requireOption(RULE2, bag.durableKey ?? DEFAULT_DURABLE_KEY, "durableKey");
|
|
1126
967
|
const durableValue = bag.durableValue ?? DEFAULT_DURABLE_VALUE;
|
|
1127
968
|
return {
|
|
1128
969
|
CallExpression(node) {
|
|
@@ -1272,7 +1113,7 @@ file and the export together \u2014 half the pair still fires.`,
|
|
|
1272
1113
|
var effect_hook_naming_default = effectHookNaming;
|
|
1273
1114
|
|
|
1274
1115
|
// src/rules/emit-declares-attempts.ts
|
|
1275
|
-
var
|
|
1116
|
+
var RULE3 = "emit-declares-attempts";
|
|
1276
1117
|
var DEFAULT_EMITTERS = ["emitEventStep"];
|
|
1277
1118
|
var OPTIONS = "options";
|
|
1278
1119
|
var ATTEMPTS = "attempts";
|
|
@@ -1287,7 +1128,7 @@ var valueOf2 = (properties, name) => properties.find((one) => one.key?.type ===
|
|
|
1287
1128
|
var emitDeclaresAttempts = {
|
|
1288
1129
|
create(context) {
|
|
1289
1130
|
const emitters = new Set(
|
|
1290
|
-
requireOption(
|
|
1131
|
+
requireOption(RULE3, context.options?.[0]?.emitters ?? DEFAULT_EMITTERS, "emitters")
|
|
1291
1132
|
);
|
|
1292
1133
|
const budgetHelpers = new Set(context.options?.[0]?.budgetHelpers ?? []);
|
|
1293
1134
|
return {
|
|
@@ -1957,21 +1798,21 @@ var writesWith = (prefixes) => (node) => {
|
|
|
1957
1798
|
var writeNameOf = (node) => propertyNameOf(node.callee ?? {}) ?? "a service write";
|
|
1958
1799
|
|
|
1959
1800
|
// src/rules/mutating-step-declares-retry.ts
|
|
1960
|
-
var
|
|
1801
|
+
var RULE4 = "mutating-step-declares-retry";
|
|
1961
1802
|
var DEFAULT_RETRY_KEY = "maxRetries";
|
|
1962
1803
|
var DEFAULT_RETRY_LIMIT_KEY = "limit";
|
|
1963
1804
|
var NO_RETRY2 = 0;
|
|
1964
1805
|
var mutatingStepDeclaresRetry = {
|
|
1965
1806
|
create(context) {
|
|
1966
|
-
const factories = stepFactoriesOf(
|
|
1967
|
-
const isWrite = writesWith(mutationPrefixesOf(
|
|
1807
|
+
const factories = stepFactoriesOf(RULE4, context.options?.[0]?.stepFactories);
|
|
1808
|
+
const isWrite = writesWith(mutationPrefixesOf(RULE4, context.options?.[0]?.mutationPrefixes));
|
|
1968
1809
|
const retryKey = requireOption(
|
|
1969
|
-
|
|
1810
|
+
RULE4,
|
|
1970
1811
|
context.options?.[0]?.retryKey ?? DEFAULT_RETRY_KEY,
|
|
1971
1812
|
"retryKey"
|
|
1972
1813
|
);
|
|
1973
1814
|
const retryLimitKey = requireOption(
|
|
1974
|
-
|
|
1815
|
+
RULE4,
|
|
1975
1816
|
context.options?.[0]?.retryLimitKey ?? DEFAULT_RETRY_LIMIT_KEY,
|
|
1976
1817
|
"retryLimitKey"
|
|
1977
1818
|
);
|
|
@@ -2048,13 +1889,13 @@ the repo wraps \`createStep\`, and \`mutationPrefixes\` if its writes are named
|
|
|
2048
1889
|
var mutating_step_declares_retry_default = mutatingStepDeclaresRetry;
|
|
2049
1890
|
|
|
2050
1891
|
// src/rules/named-when-block.ts
|
|
2051
|
-
var
|
|
1892
|
+
var RULE5 = "named-when-block";
|
|
2052
1893
|
var DEFAULT_BLOCKS = ["when"];
|
|
2053
1894
|
var NAMED = 3;
|
|
2054
1895
|
var namedWhenBlock = {
|
|
2055
1896
|
create(context) {
|
|
2056
1897
|
const blocks = new Set(
|
|
2057
|
-
requireOption(
|
|
1898
|
+
requireOption(RULE5, context.options?.[0]?.blocks ?? DEFAULT_BLOCKS, "blocks")
|
|
2058
1899
|
);
|
|
2059
1900
|
return {
|
|
2060
1901
|
CallExpression(node) {
|
|
@@ -2272,16 +2113,16 @@ var next_route_segment_is_thin_delegate_default = nextRouteSegmentIsThinDelegate
|
|
|
2272
2113
|
// src/rules/no-brand-names.ts
|
|
2273
2114
|
import * as fs3 from "fs";
|
|
2274
2115
|
var EXEMPT_PATH = /\/examples\//;
|
|
2275
|
-
var
|
|
2116
|
+
var escapeForRegex = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2276
2117
|
var noBrandNames = {
|
|
2277
2118
|
create(context) {
|
|
2278
2119
|
const { allowedSubstrings = [], brands = [] } = context.options?.[0] ?? {};
|
|
2279
2120
|
requireOption("no-brand-names", brands, "brands");
|
|
2280
2121
|
const filename = normalise(context.filename);
|
|
2281
2122
|
if (EXEMPT_PATH.test(filename)) return {};
|
|
2282
|
-
const brandPattern = new RegExp(`\\b(?:${brands.map(
|
|
2123
|
+
const brandPattern = new RegExp(`\\b(?:${brands.map(escapeForRegex).join("|")})\\b`, "i");
|
|
2283
2124
|
const allowedPatterns = allowedSubstrings.map(
|
|
2284
|
-
(allowed) => new RegExp(
|
|
2125
|
+
(allowed) => new RegExp(escapeForRegex(allowed), "gi")
|
|
2285
2126
|
);
|
|
2286
2127
|
let programNode = null;
|
|
2287
2128
|
return {
|
|
@@ -2956,20 +2797,20 @@ A component returns UI; a hook returns state.`,
|
|
|
2956
2797
|
var no_hook_in_component_disguise_default = noHookInComponentDisguise;
|
|
2957
2798
|
|
|
2958
2799
|
// src/rules/no-index-count-as-exact.ts
|
|
2959
|
-
var
|
|
2800
|
+
var RULE6 = "no-index-count-as-exact";
|
|
2960
2801
|
var DEFAULT_ESTIMATE_FIELDS = ["estimate_count", "count_estimate"];
|
|
2961
2802
|
var DEFAULT_LABEL_KEY = "count_is_estimate";
|
|
2962
2803
|
var noIndexCountAsExact = {
|
|
2963
2804
|
create(context) {
|
|
2964
2805
|
const fields = new Set(
|
|
2965
2806
|
requireOption(
|
|
2966
|
-
|
|
2807
|
+
RULE6,
|
|
2967
2808
|
context.options?.[0]?.estimateFields ?? DEFAULT_ESTIMATE_FIELDS,
|
|
2968
2809
|
"estimateFields"
|
|
2969
2810
|
)
|
|
2970
2811
|
);
|
|
2971
2812
|
const label = requireOption(
|
|
2972
|
-
|
|
2813
|
+
RULE6,
|
|
2973
2814
|
context.options?.[0]?.labelKey ?? DEFAULT_LABEL_KEY,
|
|
2974
2815
|
"labelKey"
|
|
2975
2816
|
);
|
|
@@ -3225,20 +3066,20 @@ logic in \`lib/\`.`,
|
|
|
3225
3066
|
var no_invalid_feature_folders_default = noInvalidFeatureFolders;
|
|
3226
3067
|
|
|
3227
3068
|
// src/rules/no-loader-side-effect-in-index-file.ts
|
|
3228
|
-
var
|
|
3069
|
+
var RULE7 = "no-loader-side-effect-in-index-file";
|
|
3229
3070
|
var DEFAULT_DIRECTORIES = ["(?:^|/)subscribers/", "(?:^|/)jobs/"];
|
|
3230
3071
|
var DEFAULT_RESOURCE_FACTORIES = ["createWorkflow", "createStep", "createHook"];
|
|
3231
3072
|
var INDEX = /(?:^|\/)index\.[cm]?[jt]sx?$/;
|
|
3232
3073
|
var noLoaderSideEffectInIndexFile = {
|
|
3233
3074
|
create(context) {
|
|
3234
3075
|
const directories = requireOption(
|
|
3235
|
-
|
|
3076
|
+
RULE7,
|
|
3236
3077
|
context.options?.[0]?.directories ?? DEFAULT_DIRECTORIES,
|
|
3237
3078
|
"directories"
|
|
3238
3079
|
).map((source) => new RegExp(source));
|
|
3239
3080
|
const factories = new Set(
|
|
3240
3081
|
requireOption(
|
|
3241
|
-
|
|
3082
|
+
RULE7,
|
|
3242
3083
|
context.options?.[0]?.resourceFactories ?? DEFAULT_RESOURCE_FACTORIES,
|
|
3243
3084
|
"resourceFactories"
|
|
3244
3085
|
)
|
|
@@ -3401,7 +3242,7 @@ the same component. Thin preset wrappers over one imported component do not coun
|
|
|
3401
3242
|
var no_logic_in_component_files_default = noLogicInComponentFiles;
|
|
3402
3243
|
|
|
3403
3244
|
// src/rules/no-mock-db-in-integration.ts
|
|
3404
|
-
var
|
|
3245
|
+
var RULE8 = "no-mock-db-in-integration";
|
|
3405
3246
|
var BUN_MOCK = "mock.module";
|
|
3406
3247
|
var MOCK_CALLS = /* @__PURE__ */ new Set(["jest.mock", BUN_MOCK, "vi.mock"]);
|
|
3407
3248
|
var calleeOf = (node) => {
|
|
@@ -3419,8 +3260,8 @@ var inDirectory = (filename, directory) => {
|
|
|
3419
3260
|
var noMockDbInIntegration = {
|
|
3420
3261
|
create(context) {
|
|
3421
3262
|
const options = context.options?.[0] ?? {};
|
|
3422
|
-
const dirs = requireOption(
|
|
3423
|
-
const modules = requireOption(
|
|
3263
|
+
const dirs = requireOption(RULE8, options.integrationDirs, "integrationDirs");
|
|
3264
|
+
const modules = requireOption(RULE8, options.dbModules, "dbModules");
|
|
3424
3265
|
const mockNames = new Set(options.mockNames ?? []);
|
|
3425
3266
|
const filename = normalise(context.filename);
|
|
3426
3267
|
const spans = /* @__PURE__ */ new Set();
|
|
@@ -3521,14 +3362,14 @@ below the seam, and a caller that names it has crossed it.`,
|
|
|
3521
3362
|
var no_orm_outside_db_default = noOrmOutsideDb;
|
|
3522
3363
|
|
|
3523
3364
|
// src/rules/no-raw-html-atoms.ts
|
|
3524
|
-
var
|
|
3365
|
+
var RULE9 = "no-raw-html-atoms";
|
|
3525
3366
|
var WHERE_RAW_HTML_IS_THE_POINT = "atoms";
|
|
3526
3367
|
var noRawHtmlAtoms = {
|
|
3527
3368
|
create(context) {
|
|
3528
|
-
const restrictions = requireOption(
|
|
3369
|
+
const restrictions = requireOption(RULE9, context.options[0], "element\u2192atom map");
|
|
3529
3370
|
const scope = context.options[1]?.scope;
|
|
3530
3371
|
const filename = context.filename;
|
|
3531
|
-
const inScope = scope === void 0 ? !inTier(filename, WHERE_RAW_HTML_IS_THE_POINT) : requireTiers(
|
|
3372
|
+
const inScope = scope === void 0 ? !inTier(filename, WHERE_RAW_HTML_IS_THE_POINT) : requireTiers(RULE9, scope).some((tier) => inTier(filename, tier));
|
|
3532
3373
|
if (!inScope) return {};
|
|
3533
3374
|
const elementMap = /* @__PURE__ */ new Map();
|
|
3534
3375
|
for (const r of restrictions) {
|
|
@@ -4178,7 +4019,7 @@ var no_type_definitions_in_components_default = noTypeDefinitionsInComponents;
|
|
|
4178
4019
|
|
|
4179
4020
|
// src/rules/no-unregistered-plugin-dir.ts
|
|
4180
4021
|
import { readFileSync as readFileSync4 } from "fs";
|
|
4181
|
-
var
|
|
4022
|
+
var RULE10 = "no-unregistered-plugin-dir";
|
|
4182
4023
|
var ACCEPTS3 = "{ roots: (string | { path: string, files: boolean })[], registry: string | string[], manifests: string[] }";
|
|
4183
4024
|
var trimSlashes = (path2) => path2.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
4184
4025
|
var withoutComments = (source) => source.replaceAll(/\/\*[\s\S]*?\*\//g, " ").replaceAll(/\/\/[^\n]*/g, " ");
|
|
@@ -4206,12 +4047,12 @@ var oneFile = (segments) => {
|
|
|
4206
4047
|
var noUnregisteredPluginDir = {
|
|
4207
4048
|
create(context) {
|
|
4208
4049
|
const options = context.options?.[0] ?? {};
|
|
4209
|
-
const roots = requireOption(
|
|
4050
|
+
const roots = requireOption(RULE10, options.roots, "roots", ACCEPTS3).map(
|
|
4210
4051
|
(one) => typeof one === "string" ? { files: false, path: trimSlashes(one) } : { files: one.files === true, path: trimSlashes(one.path) }
|
|
4211
4052
|
);
|
|
4212
|
-
const declared = requireOption(
|
|
4053
|
+
const declared = requireOption(RULE10, options.registry, "registry", ACCEPTS3);
|
|
4213
4054
|
const registries = (typeof declared === "string" ? [declared] : declared).map(trimSlashes);
|
|
4214
|
-
const manifests = new Set(requireOption(
|
|
4055
|
+
const manifests = new Set(requireOption(RULE10, options.manifests, "manifests", ACCEPTS3));
|
|
4215
4056
|
const filename = normalise(context.filename);
|
|
4216
4057
|
return {
|
|
4217
4058
|
Program(node) {
|
|
@@ -4488,16 +4329,16 @@ source. The CELL is the only level where several sources meet; it derives and pa
|
|
|
4488
4329
|
var organelle_single_source_default = organelleSingleSource;
|
|
4489
4330
|
|
|
4490
4331
|
// src/rules/plugin-route-namespaced.ts
|
|
4491
|
-
var
|
|
4332
|
+
var RULE11 = "plugin-route-namespaced";
|
|
4492
4333
|
var DEFAULT_SCOPES = ["store", "admin"];
|
|
4493
4334
|
var ROUTE_FILE = /(?:^|\/)api\/(.+\/)?route\.[cm]?[jt]sx?$/;
|
|
4494
4335
|
var NAMESPACED_FROM = 2;
|
|
4495
4336
|
var readPackages = (configured) => {
|
|
4496
|
-
const rules2 = requireOption(
|
|
4337
|
+
const rules2 = requireOption(RULE11, configured, "packages");
|
|
4497
4338
|
for (const rule of rules2) {
|
|
4498
4339
|
if (typeof rule.under !== "string" || rule.under === "") {
|
|
4499
4340
|
throw new Error(
|
|
4500
|
-
`biological-architecture/${
|
|
4341
|
+
`biological-architecture/${RULE11}: every \`packages\` entry needs \`under\` \u2014 the directory whose children are packages. Without it the rule cannot tell which files belong to a plugin.`
|
|
4501
4342
|
);
|
|
4502
4343
|
}
|
|
4503
4344
|
}
|
|
@@ -4524,7 +4365,7 @@ var pluginRouteNamespaced = {
|
|
|
4524
4365
|
create(context) {
|
|
4525
4366
|
const rules2 = readPackages(context.options?.[0]?.packages);
|
|
4526
4367
|
const scopes = new Set(
|
|
4527
|
-
requireOption(
|
|
4368
|
+
requireOption(RULE11, context.options?.[0]?.scopes ?? DEFAULT_SCOPES, "scopes")
|
|
4528
4369
|
);
|
|
4529
4370
|
const path2 = normalise(context.filename);
|
|
4530
4371
|
const route = routePathOf(path2);
|
|
@@ -4710,8 +4551,55 @@ decides what an event MEANS and throws when it cannot.`,
|
|
|
4710
4551
|
};
|
|
4711
4552
|
var queue_loop_is_the_library_default = queueLoopIsTheLibrary;
|
|
4712
4553
|
|
|
4554
|
+
// src/rules/retired.ts
|
|
4555
|
+
var SINCE = "2.7.0";
|
|
4556
|
+
var REASON = "it enforced one consumer's document kinds, which is vocabulary the kit does not hold";
|
|
4557
|
+
var announced = /* @__PURE__ */ new Set();
|
|
4558
|
+
var retired = (name, schema) => ({
|
|
4559
|
+
create: () => {
|
|
4560
|
+
if (!announced.has(name)) {
|
|
4561
|
+
announced.add(name);
|
|
4562
|
+
process.stderr.write(
|
|
4563
|
+
`biological-architecture: rule "${name}" is retired since ${SINCE} \u2014 ${REASON}. It reports nothing and goes at the next major. Remove it from your config.
|
|
4564
|
+
`
|
|
4565
|
+
);
|
|
4566
|
+
}
|
|
4567
|
+
return {};
|
|
4568
|
+
},
|
|
4569
|
+
fixShape: `\`${name}\` is retired since ${SINCE} and reports nothing. Remove it from the config.`,
|
|
4570
|
+
meta: {
|
|
4571
|
+
docs: {
|
|
4572
|
+
description: `Retired since ${SINCE}: ${REASON}. Reports nothing; goes at the next major.`
|
|
4573
|
+
},
|
|
4574
|
+
messages: {},
|
|
4575
|
+
retired: { reason: REASON, since: SINCE },
|
|
4576
|
+
schema,
|
|
4577
|
+
type: "problem"
|
|
4578
|
+
}
|
|
4579
|
+
});
|
|
4580
|
+
var RETIRED_RULES = {
|
|
4581
|
+
"document-sagas-are-generic": retired("document-sagas-are-generic", [
|
|
4582
|
+
{
|
|
4583
|
+
additionalProperties: false,
|
|
4584
|
+
properties: {
|
|
4585
|
+
factories: { items: { type: "string" }, type: "array" },
|
|
4586
|
+
perKindPrefixes: { items: { type: "string" }, type: "array" },
|
|
4587
|
+
within: { type: "string" }
|
|
4588
|
+
},
|
|
4589
|
+
type: "object"
|
|
4590
|
+
}
|
|
4591
|
+
]),
|
|
4592
|
+
"documents-share-one-table": retired("documents-share-one-table", [
|
|
4593
|
+
{
|
|
4594
|
+
additionalProperties: false,
|
|
4595
|
+
properties: { perKindTables: { items: { type: "string" }, type: "array" } },
|
|
4596
|
+
type: "object"
|
|
4597
|
+
}
|
|
4598
|
+
])
|
|
4599
|
+
};
|
|
4600
|
+
|
|
4713
4601
|
// src/rules/route-no-inline-mutation.ts
|
|
4714
|
-
var
|
|
4602
|
+
var RULE12 = "route-no-inline-mutation";
|
|
4715
4603
|
var DEFAULT_PATHS = [String.raw`(?:^|/)api/.*/route\.[cm]?[jt]sx?$`];
|
|
4716
4604
|
var DEFAULT_INLINE_MUTATION_OK = "arch:inline-mutation-ok";
|
|
4717
4605
|
var commentsOf2 = (sourceCode) => sourceCode?.getAllComments?.() ?? sourceCode?.ast?.comments ?? [];
|
|
@@ -4755,15 +4643,15 @@ var annotated = (found, comments, marker) => {
|
|
|
4755
4643
|
};
|
|
4756
4644
|
var routeNoInlineMutation = {
|
|
4757
4645
|
create(context) {
|
|
4758
|
-
const paths = requireOption(
|
|
4646
|
+
const paths = requireOption(RULE12, context.options?.[0]?.paths ?? DEFAULT_PATHS, "paths").map(
|
|
4759
4647
|
(source) => new RegExp(source)
|
|
4760
4648
|
);
|
|
4761
4649
|
const marker = requireOption(
|
|
4762
|
-
|
|
4650
|
+
RULE12,
|
|
4763
4651
|
context.options?.[0]?.inlineMutationOk ?? DEFAULT_INLINE_MUTATION_OK,
|
|
4764
4652
|
"inlineMutationOk"
|
|
4765
4653
|
);
|
|
4766
|
-
const isWrite = writesWith(mutationPrefixesOf(
|
|
4654
|
+
const isWrite = writesWith(mutationPrefixesOf(RULE12, context.options?.[0]?.mutationPrefixes));
|
|
4767
4655
|
const filename = normalise(context.filename);
|
|
4768
4656
|
if (!paths.some((pattern) => pattern.test(filename))) return {};
|
|
4769
4657
|
return {
|
|
@@ -4833,7 +4721,7 @@ var route_no_inline_mutation_default = routeNoInlineMutation;
|
|
|
4833
4721
|
|
|
4834
4722
|
// src/rules/router-schema-parity.ts
|
|
4835
4723
|
import { existsSync as existsSync2 } from "fs";
|
|
4836
|
-
var
|
|
4724
|
+
var RULE13 = "router-schema-parity";
|
|
4837
4725
|
var EXTENSIONS2 = [".ts", ".tsx"];
|
|
4838
4726
|
var trimSlashes2 = (path2) => path2.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
4839
4727
|
var baseOf = (file) => file.replace(/\.[cm]?[jt]sx?$/, "");
|
|
@@ -4851,8 +4739,8 @@ var directlyUnder = (filename, directory) => {
|
|
|
4851
4739
|
var routerSchemaParity = {
|
|
4852
4740
|
create(context) {
|
|
4853
4741
|
const options = context.options?.[0] ?? {};
|
|
4854
|
-
const routers = trimSlashes2(requireOption(
|
|
4855
|
-
const schemas = trimSlashes2(requireOption(
|
|
4742
|
+
const routers = trimSlashes2(requireOption(RULE13, options.routers, "routers"));
|
|
4743
|
+
const schemas = trimSlashes2(requireOption(RULE13, options.schemas, "schemas"));
|
|
4856
4744
|
const suffix = options.suffix ?? "";
|
|
4857
4745
|
const ignored = new Set(options.ignore ?? []);
|
|
4858
4746
|
const mounts = options.mounts ?? {};
|
|
@@ -4924,7 +4812,7 @@ repo-root-relative, because in one consumer they live in different packages.`,
|
|
|
4924
4812
|
var router_schema_parity_default = routerSchemaParity;
|
|
4925
4813
|
|
|
4926
4814
|
// src/rules/service-name-not-reserved.ts
|
|
4927
|
-
var
|
|
4815
|
+
var RULE14 = "service-name-not-reserved";
|
|
4928
4816
|
var DEFAULT_MODULE_FACTORIES = ["Module"];
|
|
4929
4817
|
var MODULES_2_19 = [
|
|
4930
4818
|
"analytics",
|
|
@@ -4964,13 +4852,13 @@ var serviceNameNotReserved = {
|
|
|
4964
4852
|
create(context) {
|
|
4965
4853
|
const factories = new Set(
|
|
4966
4854
|
requireOption(
|
|
4967
|
-
|
|
4855
|
+
RULE14,
|
|
4968
4856
|
context.options?.[0]?.moduleFactories ?? DEFAULT_MODULE_FACTORIES,
|
|
4969
4857
|
"moduleFactories"
|
|
4970
4858
|
)
|
|
4971
4859
|
);
|
|
4972
4860
|
const reserved = new Set(
|
|
4973
|
-
requireOption(
|
|
4861
|
+
requireOption(RULE14, context.options?.[0]?.reserved ?? MODULES_2_19, "reserved")
|
|
4974
4862
|
);
|
|
4975
4863
|
const constants = /* @__PURE__ */ new Map();
|
|
4976
4864
|
const pending = [];
|
|
@@ -5281,12 +5169,12 @@ can be misspelled and a second default nobody agreed to.`,
|
|
|
5281
5169
|
var ssot_no_process_env_default = ssotNoProcessEnv;
|
|
5282
5170
|
|
|
5283
5171
|
// src/rules/step-declares-compensation-or-none.ts
|
|
5284
|
-
var
|
|
5172
|
+
var RULE15 = "step-declares-compensation-or-none";
|
|
5285
5173
|
var NO_COMPENSATION = "noCompensation";
|
|
5286
5174
|
var WITH_COMPENSATION = 3;
|
|
5287
5175
|
var stepDeclaresCompensationOrNone = {
|
|
5288
5176
|
create(context) {
|
|
5289
|
-
const factories = stepFactoriesOf(
|
|
5177
|
+
const factories = stepFactoriesOf(RULE15, context.options?.[0]?.stepFactories);
|
|
5290
5178
|
return {
|
|
5291
5179
|
CallExpression(node) {
|
|
5292
5180
|
if (!isStepCall(node, factories)) return;
|
|
@@ -5330,7 +5218,7 @@ variable \u2014 passes, since the flag may be in the base. Configure \`stepFacto
|
|
|
5330
5218
|
var step_declares_compensation_or_none_default = stepDeclaresCompensationOrNone;
|
|
5331
5219
|
|
|
5332
5220
|
// src/rules/step-opens-its-own-cell.ts
|
|
5333
|
-
var
|
|
5221
|
+
var RULE16 = "step-opens-its-own-cell";
|
|
5334
5222
|
var STEP = "step";
|
|
5335
5223
|
var ACCEPTS4 = "{ within: string (required), hosts: string[], scopeKey: string, engine: string, wrapper: string }";
|
|
5336
5224
|
var DEFAULT_HOSTS = ["createRuntime", "entrypointFor"];
|
|
@@ -5365,9 +5253,9 @@ var declaresScope = (call, scopeKey) => {
|
|
|
5365
5253
|
var stepOpensItsOwnCell = {
|
|
5366
5254
|
create(context) {
|
|
5367
5255
|
const bag = context.options?.[0] ?? {};
|
|
5368
|
-
const within = requireOption(
|
|
5369
|
-
const hosts = new Set(requireOption(
|
|
5370
|
-
const scopeKey = requireOption(
|
|
5256
|
+
const within = requireOption(RULE16, bag.within, "within", ACCEPTS4);
|
|
5257
|
+
const hosts = new Set(requireOption(RULE16, bag.hosts ?? DEFAULT_HOSTS, "hosts", ACCEPTS4));
|
|
5258
|
+
const scopeKey = requireOption(RULE16, bag.scopeKey ?? DEFAULT_SCOPE_KEY, "scopeKey", ACCEPTS4);
|
|
5371
5259
|
const { engine, wrapper } = bag;
|
|
5372
5260
|
const filename = normalise(context.filename);
|
|
5373
5261
|
if (!new RegExp(within).test(filename)) return {};
|
|
@@ -5470,7 +5358,7 @@ without \`within\` the rule refuses the run.`,
|
|
|
5470
5358
|
const path2 = pathMatching(within, "geonosis-probe-engine-step.ts");
|
|
5471
5359
|
if (wrapper !== void 0 && new RegExp(wrapper).test(path2)) {
|
|
5472
5360
|
throw new Error(
|
|
5473
|
-
`biological-architecture/${
|
|
5361
|
+
`biological-architecture/${RULE16}: the probe path "${path2}" is also the \`wrapper\`, which is the one file allowed to reach \`${engine}\` \u2014 no single file inside \`within\` can both land where the rule looks and be somewhere it speaks.`
|
|
5474
5362
|
);
|
|
5475
5363
|
}
|
|
5476
5364
|
return {
|
|
@@ -5675,10 +5563,10 @@ data, it belongs on the admin surface.`,
|
|
|
5675
5563
|
var store_route_scopes_tenant_data_default = storeRouteScopesTenantData;
|
|
5676
5564
|
|
|
5677
5565
|
// src/rules/subpath-over-barrel.ts
|
|
5678
|
-
var
|
|
5566
|
+
var RULE17 = "subpath-over-barrel";
|
|
5679
5567
|
var ACCEPTS5 = "{ packages: { name: string, subpaths: { [subpath: string]: string[] } }[] (required) }";
|
|
5680
5568
|
var homesOf = (declared) => {
|
|
5681
|
-
const subpaths = requireOption(
|
|
5569
|
+
const subpaths = requireOption(RULE17, Object.keys(declared.subpaths ?? {}), "subpaths", ACCEPTS5);
|
|
5682
5570
|
return new Map(
|
|
5683
5571
|
subpaths.flatMap(
|
|
5684
5572
|
(subpath) => (declared.subpaths?.[subpath] ?? []).map((name) => [name, subpath])
|
|
@@ -5701,9 +5589,9 @@ var importedNamesOf = (node) => {
|
|
|
5701
5589
|
};
|
|
5702
5590
|
var subpathOverBarrel = {
|
|
5703
5591
|
create(context) {
|
|
5704
|
-
const declared = requireOption(
|
|
5592
|
+
const declared = requireOption(RULE17, context.options?.[0]?.packages, "packages", ACCEPTS5);
|
|
5705
5593
|
const homes = new Map(
|
|
5706
|
-
declared.map((one) => [requireOption(
|
|
5594
|
+
declared.map((one) => [requireOption(RULE17, one.name, "name", ACCEPTS5), homesOf(one)])
|
|
5707
5595
|
);
|
|
5708
5596
|
return {
|
|
5709
5597
|
ImportDeclaration(node) {
|
|
@@ -5773,7 +5661,7 @@ is a type-only import, which erases before any of that happens. Declare the map
|
|
|
5773
5661
|
const [exported] = first?.subpaths?.[subpath ?? ""] ?? [];
|
|
5774
5662
|
if (exported === void 0) {
|
|
5775
5663
|
throw new Error(
|
|
5776
|
-
`biological-architecture/${
|
|
5664
|
+
`biological-architecture/${RULE17}: the configured packages declare no subpath with a name in it, so there is nothing a probe could import from the root.`
|
|
5777
5665
|
);
|
|
5778
5666
|
}
|
|
5779
5667
|
return {
|
|
@@ -5788,7 +5676,7 @@ export const geonosisProbe = ${exported}
|
|
|
5788
5676
|
var subpath_over_barrel_default = subpathOverBarrel;
|
|
5789
5677
|
|
|
5790
5678
|
// src/rules/subscriber-declares-id.ts
|
|
5791
|
-
var
|
|
5679
|
+
var RULE18 = "subscriber-declares-id";
|
|
5792
5680
|
var DEFAULT_PATHS2 = ["(?:^|/)subscribers/"];
|
|
5793
5681
|
var CONFIG = "config";
|
|
5794
5682
|
var CONTEXT = "context";
|
|
@@ -5802,7 +5690,7 @@ var declaredName2 = (node) => {
|
|
|
5802
5690
|
};
|
|
5803
5691
|
var subscriberDeclaresId = {
|
|
5804
5692
|
create(context) {
|
|
5805
|
-
const paths = requireOption(
|
|
5693
|
+
const paths = requireOption(RULE18, context.options?.[0]?.paths ?? DEFAULT_PATHS2, "paths").map(
|
|
5806
5694
|
(source) => new RegExp(source)
|
|
5807
5695
|
);
|
|
5808
5696
|
const filename = normalise(context.filename);
|
|
@@ -6065,7 +5953,7 @@ are tests is \`testGlobs\` and which calls poll is \`pollers\`, both defaulted.`
|
|
|
6065
5953
|
var test_no_clock_polling_for_promise_flips_default = testNoClockPollingForPromiseFlips;
|
|
6066
5954
|
|
|
6067
5955
|
// src/rules/time-through-the-door.ts
|
|
6068
|
-
var
|
|
5956
|
+
var RULE19 = "time-through-the-door";
|
|
6069
5957
|
var ACCEPTS6 = "{ door: string (a regex over the filename), exempt: string[] (regex sources, default the test paths: __tests__/, .test., .spec.), libraries: string[] (default ['dayjs']) }";
|
|
6070
5958
|
var DEFAULT_LIBRARIES = ["dayjs"];
|
|
6071
5959
|
var DEFAULT_EXEMPT = ["__tests__/", String.raw`\.test\.`, String.raw`\.spec\.`];
|
|
@@ -6093,11 +5981,11 @@ var memberName = (callee) => ({
|
|
|
6093
5981
|
var readable2 = (pattern) => pattern.replaceAll("\\", "").replace(/\$$/, "");
|
|
6094
5982
|
var timeThroughTheDoor = {
|
|
6095
5983
|
create(context) {
|
|
6096
|
-
const door = requireOption(
|
|
5984
|
+
const door = requireOption(RULE19, context.options?.[0]?.door, "door", ACCEPTS6);
|
|
6097
5985
|
const exempt = context.options?.[0]?.exempt ?? DEFAULT_EXEMPT;
|
|
6098
5986
|
const exemptModules = context.options?.[0]?.exemptModules ?? [];
|
|
6099
5987
|
const libraries = requireOption(
|
|
6100
|
-
|
|
5988
|
+
RULE19,
|
|
6101
5989
|
context.options?.[0]?.libraries ?? DEFAULT_LIBRARIES,
|
|
6102
5990
|
"libraries",
|
|
6103
5991
|
ACCEPTS6
|
|
@@ -6201,7 +6089,7 @@ it internally cannot be tested at a chosen instant.`,
|
|
|
6201
6089
|
);
|
|
6202
6090
|
if (outside === void 0) {
|
|
6203
6091
|
throw new Error(
|
|
6204
|
-
`biological-architecture/${
|
|
6092
|
+
`biological-architecture/${RULE19}: every path a probe could be written at is inside the \`door\` (${door}) or one of its \`exempt\` patterns, so there is nowhere left for this rule to speak.`
|
|
6205
6093
|
);
|
|
6206
6094
|
}
|
|
6207
6095
|
return {
|
|
@@ -6588,13 +6476,13 @@ var tissue_no_stores_default = tissueNoStores;
|
|
|
6588
6476
|
// src/rules/todo-names-its-plan.ts
|
|
6589
6477
|
var ID_DEFAULT = String.raw`\d{3,}`;
|
|
6590
6478
|
var commentsOf3 = (sourceCode) => sourceCode?.getAllComments?.() ?? sourceCode?.ast?.comments ?? [];
|
|
6591
|
-
var
|
|
6479
|
+
var escapeForRegex2 = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6592
6480
|
var todoNamesItsPlan = {
|
|
6593
6481
|
create(context) {
|
|
6594
6482
|
const { id = ID_DEFAULT, markers = [] } = context.options?.[0] ?? {};
|
|
6595
6483
|
requireOption("todo-names-its-plan", markers, "markers", "{ markers: string[], id?: string }");
|
|
6596
6484
|
const marker = new RegExp(
|
|
6597
|
-
`\\b(${markers.map(
|
|
6485
|
+
`\\b(${markers.map(escapeForRegex2).join("|")})\\b(?:\\(([^)]*)\\))?`,
|
|
6598
6486
|
"g"
|
|
6599
6487
|
);
|
|
6600
6488
|
const names2 = new RegExp(`^${id}$`);
|
|
@@ -7011,7 +6899,7 @@ var isNamedOnly = (value) => /^[a-z]+$/i.test(value.trim());
|
|
|
7011
6899
|
var tokens_only_colors_default = tokensOnlyColors;
|
|
7012
6900
|
|
|
7013
6901
|
// src/rules/unique-query-step-name.ts
|
|
7014
|
-
var
|
|
6902
|
+
var RULE20 = "unique-query-step-name";
|
|
7015
6903
|
var ACCEPTS7 = "{ queryStepCalls: string[] (required), workflowFactories: string[] }";
|
|
7016
6904
|
var DEFAULT_WORKFLOW_FACTORIES2 = ["createWorkflow"];
|
|
7017
6905
|
var CONFIG2 = "config";
|
|
@@ -7055,13 +6943,13 @@ var uniqueQueryStepName = {
|
|
|
7055
6943
|
create(context) {
|
|
7056
6944
|
const factories = new Set(
|
|
7057
6945
|
requireOption(
|
|
7058
|
-
|
|
6946
|
+
RULE20,
|
|
7059
6947
|
context.options?.[0]?.workflowFactories ?? DEFAULT_WORKFLOW_FACTORIES2,
|
|
7060
6948
|
"workflowFactories"
|
|
7061
6949
|
)
|
|
7062
6950
|
);
|
|
7063
6951
|
const calls = new Set(
|
|
7064
|
-
requireOption(
|
|
6952
|
+
requireOption(RULE20, context.options?.[0]?.queryStepCalls, "queryStepCalls", ACCEPTS7)
|
|
7065
6953
|
);
|
|
7066
6954
|
return {
|
|
7067
6955
|
CallExpression(node) {
|
|
@@ -7142,7 +7030,7 @@ because the collision it reports is one framework's step-handler map and not eve
|
|
|
7142
7030
|
var unique_query_step_name_default = uniqueQueryStepName;
|
|
7143
7031
|
|
|
7144
7032
|
// src/rules/worker-handles-are-scoped.ts
|
|
7145
|
-
var
|
|
7033
|
+
var RULE21 = "worker-handles-are-scoped";
|
|
7146
7034
|
var ACCEPTS8 = "{ within: string (a regex over the filename), wrapper: string[] }";
|
|
7147
7035
|
var handlerKeys = /* @__PURE__ */ new Set(["fetch", "queue", "scheduled", "email"]);
|
|
7148
7036
|
var entrypointMakers = /* @__PURE__ */ new Set([
|
|
@@ -7152,8 +7040,8 @@ var entrypointMakers = /* @__PURE__ */ new Set([
|
|
|
7152
7040
|
]);
|
|
7153
7041
|
var cellHandlesAreScoped = {
|
|
7154
7042
|
create(context) {
|
|
7155
|
-
const within = requireOption(
|
|
7156
|
-
const wrappers = requireOption(
|
|
7043
|
+
const within = requireOption(RULE21, context.options?.[0]?.within, "within", ACCEPTS8);
|
|
7044
|
+
const wrappers = requireOption(RULE21, context.options?.[0]?.wrapper, "wrapper", ACCEPTS8);
|
|
7157
7045
|
if (!new RegExp(within).test(normalise(context.filename))) return {};
|
|
7158
7046
|
const scopedBy = new Set(wrappers);
|
|
7159
7047
|
let handler = null;
|
|
@@ -7356,8 +7244,6 @@ var rules = refusingOnce(
|
|
|
7356
7244
|
"compound-no-stores": compound_no_stores_default,
|
|
7357
7245
|
"constants-in-constants-file": constants_in_constants_file_default,
|
|
7358
7246
|
"dialect-through-the-seam": dialect_through_the_seam_default,
|
|
7359
|
-
"document-sagas-are-generic": document_sagas_are_generic_default,
|
|
7360
|
-
"documents-share-one-table": documents_share_one_table_default,
|
|
7361
7247
|
"durable-body-reads-through-steps": durable_body_reads_through_steps_default,
|
|
7362
7248
|
"effect-hook-naming": effect_hook_naming_default,
|
|
7363
7249
|
"emit-declares-attempts": emit_declares_attempts_default,
|
|
@@ -7430,18 +7316,22 @@ var rules = refusingOnce(
|
|
|
7430
7316
|
})
|
|
7431
7317
|
);
|
|
7432
7318
|
var { version } = createRequire(import.meta.url)("../package.json");
|
|
7319
|
+
var loaded = { ...rules, ...RETIRED_RULES };
|
|
7433
7320
|
var plugin = {
|
|
7434
7321
|
configs: PRESETS,
|
|
7435
7322
|
meta: {
|
|
7436
7323
|
name: "biological-architecture",
|
|
7437
7324
|
version
|
|
7438
7325
|
},
|
|
7439
|
-
|
|
7326
|
+
// A retired id resolves here and nowhere else: a config that still names one parses, and the id
|
|
7327
|
+
// reports nothing. `rules` — what the kit's own tooling reads as its rule set — does not carry it.
|
|
7328
|
+
rules: loaded
|
|
7440
7329
|
};
|
|
7441
7330
|
var index_default = plugin;
|
|
7442
7331
|
export {
|
|
7443
7332
|
PRESETS,
|
|
7444
7333
|
RENAMED_TO,
|
|
7334
|
+
RETIRED_RULES,
|
|
7445
7335
|
index_default as default,
|
|
7446
7336
|
rules,
|
|
7447
7337
|
rulesOfPreset
|
package/dist/presets.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geonosis/oxlint-plugin-biological-architecture",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.7.0",
|
|
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": [
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"oxlint": ">=1.77"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@geonosis/lint-parity": "2.
|
|
48
|
+
"@geonosis/lint-parity": "2.7.0"
|
|
49
49
|
},
|
|
50
50
|
"engines": {
|
|
51
51
|
"node": ">=22"
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import { createWorkflow } from '@corpus/workflows'
|
|
2
|
-
|
|
3
|
-
// BREACH: the same hand-written fork under the other engine's factory. A plain string names ONE
|
|
4
|
-
// entity, which is what the generic base entity replaced.
|
|
5
|
-
export const createInvoice = createWorkflow('invoice.create', async (input) => input)
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { createWorkflow } from '@corpus/workflows'
|
|
2
|
-
|
|
3
|
-
// ACCEPTED: the generic factory. Every entity's create flow comes from one body, and the name is
|
|
4
|
-
// assembled from the entity — a template literal the rule cannot read, which is the point rather
|
|
5
|
-
// than a gap: what is minted is exactly what this rule is asking for.
|
|
6
|
-
export const documentWorkflows = (entity: string) => ({
|
|
7
|
-
create: createWorkflow(`${entity}.create`, async (input) => input),
|
|
8
|
-
})
|