@geonosis/oxlint-plugin-biological-architecture 1.0.0 → 1.2.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/dist/index.d.ts +29 -0
- package/dist/index.js +328 -3
- package/package.json +15 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,28 @@
|
|
|
1
1
|
import { Preset } from './presets.js';
|
|
2
2
|
export { PRESETS, PresetName, rulesOfPreset } from './presets.js';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* The file a rule says MUST fire it, given the options it was handed.
|
|
6
|
+
*
|
|
7
|
+
* `requireOption` closed one hole: an enabled rule with no option refuses the run instead of
|
|
8
|
+
* reading as a clean tree. It leaves the next one open. A rule CONFIGURED with a repo's own
|
|
9
|
+
* vocabulary — its own brand, `packages/workflows/src/`, `@repo/db` — cannot be exercised by a corpus
|
|
10
|
+
* that ships fixtures saying `acme` and `corpus/workflows/`, so "fires nowhere" is what an
|
|
11
|
+
* adoption's doctor reports about a rule the repo is enforcing perfectly well. Both consumers filed
|
|
12
|
+
* exactly that on 2026-08-30, and both were right about the fact and wrong about whose defect it is.
|
|
13
|
+
*
|
|
14
|
+
* A probe is the answer the rule itself can give: hand it the options and it writes the smallest
|
|
15
|
+
* source that must fire it under THOSE options, at a path that lands where it looks. It is a claim,
|
|
16
|
+
* so it is tested through the real binary — a probe that does not fire is a rule that cannot be
|
|
17
|
+
* exercised, and the honest thing then is to say so rather than to widen the probe until it does.
|
|
18
|
+
*/
|
|
19
|
+
type Probe = {
|
|
20
|
+
/** Repo-root-relative, `/`-separated. It must satisfy every PATH option the rule reads. */
|
|
21
|
+
path: string;
|
|
22
|
+
source: string;
|
|
23
|
+
};
|
|
24
|
+
type ProbeFn = (options: readonly unknown[]) => Probe;
|
|
25
|
+
|
|
4
26
|
type Rule = {
|
|
5
27
|
create: (context: never) => Record<string, unknown>;
|
|
6
28
|
fixShape: string;
|
|
@@ -12,6 +34,13 @@ type Rule = {
|
|
|
12
34
|
schema: unknown[];
|
|
13
35
|
type: string;
|
|
14
36
|
};
|
|
37
|
+
/**
|
|
38
|
+
* Present only on a rule whose REACH depends on an option. It answers with the smallest source
|
|
39
|
+
* that must fire the rule under the options it is handed, so a repo whose corpus carries no such
|
|
40
|
+
* file can still be shown the rule reaching something — and a rule with no probe that fires
|
|
41
|
+
* nowhere stays a failure, which is the whole point of the check that reads this.
|
|
42
|
+
*/
|
|
43
|
+
probe?: ProbeFn;
|
|
15
44
|
};
|
|
16
45
|
declare const rules: Record<string, Rule>;
|
|
17
46
|
type RuleName = string;
|
package/dist/index.js
CHANGED
|
@@ -602,6 +602,40 @@ var requireOption = (rule, value, option) => {
|
|
|
602
602
|
return value;
|
|
603
603
|
};
|
|
604
604
|
|
|
605
|
+
// src/rules/lib/probe.ts
|
|
606
|
+
var bagOf = (options) => typeof options[0] === "object" && options[0] !== null && !Array.isArray(options[0]) ? options[0] : {};
|
|
607
|
+
var firstOf = (configured, fallback) => {
|
|
608
|
+
const [first] = configured !== void 0 && configured.length > 0 ? configured : fallback;
|
|
609
|
+
if (first === void 0) throw new Error("no value and no default to build a probe from");
|
|
610
|
+
return first;
|
|
611
|
+
};
|
|
612
|
+
var LOOKAHEAD = /\(\?[!=][^)]*\)/g;
|
|
613
|
+
var OPTIONAL_GROUP = /\(\?:[^)]*\)\?/g;
|
|
614
|
+
var FIRST_ALTERNATIVE = /\(\?:([^)|]*)\|[^)]*\)/g;
|
|
615
|
+
var GROUP = /\(\?:([^)]*)\)/g;
|
|
616
|
+
var ANY_SEGMENT = /\[\^\/\]\+|\.\+|\.\*/g;
|
|
617
|
+
var OPTIONAL_CLASS = /\[[^\]]*\]\?/g;
|
|
618
|
+
var CLASS = /\[([^\]])[^\]]*\]/g;
|
|
619
|
+
var OPTIONAL_CHAR = /[^/]\?/g;
|
|
620
|
+
var QUANTIFIER = /[*+]/g;
|
|
621
|
+
var LINTABLE = /\.[cm]?[jt]sx?$/;
|
|
622
|
+
var EXTENSIONS = [".ts", ".tsx", ".js", ".jsx"];
|
|
623
|
+
var pathMatching = (pattern, leaf) => {
|
|
624
|
+
const literal = pattern.replaceAll(LOOKAHEAD, "").replaceAll(OPTIONAL_GROUP, "").replaceAll(FIRST_ALTERNATIVE, "$1").replaceAll(GROUP, "$1").replaceAll(ANY_SEGMENT, "probe").replaceAll(OPTIONAL_CLASS, "").replaceAll(CLASS, "$1").replaceAll(String.raw`\.`, ".").replaceAll(String.raw`\/`, "/").replaceAll(OPTIONAL_CHAR, "").replaceAll("^", "").replaceAll("$", "").replaceAll(QUANTIFIER, "");
|
|
625
|
+
const here = new RegExp(pattern);
|
|
626
|
+
const candidates = [
|
|
627
|
+
literal.endsWith("/") ? `${literal}${leaf}` : literal,
|
|
628
|
+
...EXTENSIONS.map((extension) => `${literal}${extension}`)
|
|
629
|
+
];
|
|
630
|
+
const found = candidates.find((one) => LINTABLE.test(one) && here.test(one));
|
|
631
|
+
if (found === void 0) {
|
|
632
|
+
throw new Error(
|
|
633
|
+
`no probe path can be built from the pattern ${pattern}: nothing of the shape "${candidates[0] ?? ""}" both matches it and is a file oxlint would parse. Write the file by hand, or narrow the option to a path a probe can be placed at.`
|
|
634
|
+
);
|
|
635
|
+
}
|
|
636
|
+
return found;
|
|
637
|
+
};
|
|
638
|
+
|
|
605
639
|
// src/rules/document-sagas-are-generic.ts
|
|
606
640
|
var escapeForRegex = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
607
641
|
var documentSagasAreGeneric = {
|
|
@@ -642,6 +676,17 @@ rule refuses the run.`,
|
|
|
642
676
|
}
|
|
643
677
|
],
|
|
644
678
|
type: "problem"
|
|
679
|
+
},
|
|
680
|
+
/** The guarded tree is compiled in, so only the kind vocabulary has to come from the options. */
|
|
681
|
+
probe(options) {
|
|
682
|
+
const { perKindPrefixes = [] } = bagOf(options);
|
|
683
|
+
return {
|
|
684
|
+
path: "packages/workflows/src/geonosis-probe-saga.ts",
|
|
685
|
+
source: `import { saga } from 'sagaflow-js'
|
|
686
|
+
|
|
687
|
+
export const geonosisProbe = saga('${perKindPrefixes[0] ?? ""}.geonosis-probe', {})
|
|
688
|
+
`
|
|
689
|
+
};
|
|
645
690
|
}
|
|
646
691
|
};
|
|
647
692
|
var document_sagas_are_generic_default = documentSagasAreGeneric;
|
|
@@ -692,6 +737,17 @@ schema silently.`,
|
|
|
692
737
|
}
|
|
693
738
|
],
|
|
694
739
|
type: "problem"
|
|
740
|
+
},
|
|
741
|
+
/** The schema directory is compiled in; the forbidden table names are this repo's vocabulary. */
|
|
742
|
+
probe(options) {
|
|
743
|
+
const { perKindTables = [] } = bagOf(options);
|
|
744
|
+
return {
|
|
745
|
+
path: "packages/db/src/schema/geonosis-probe-table.ts",
|
|
746
|
+
source: `import { pgTable, text } from 'drizzle-orm/pg-core'
|
|
747
|
+
|
|
748
|
+
export const geonosisProbe = pgTable('${perKindTables[0] ?? ""}', { id: text('id') })
|
|
749
|
+
`
|
|
750
|
+
};
|
|
695
751
|
}
|
|
696
752
|
};
|
|
697
753
|
var documents_share_one_table_default = documentsShareOneTable;
|
|
@@ -856,6 +912,20 @@ under another name.`,
|
|
|
856
912
|
}
|
|
857
913
|
],
|
|
858
914
|
type: "problem"
|
|
915
|
+
},
|
|
916
|
+
/**
|
|
917
|
+
* The emit with no budget at all — the shape the rule speaks about first. `emitters` defaults to
|
|
918
|
+
* Medusa's spelling, so the probe reads the option the way `create` does, default included: a
|
|
919
|
+
* repo that wraps the emit under its own name gets a probe naming ITS wrapper, and a repo that
|
|
920
|
+
* does not gets `emitEventStep`.
|
|
921
|
+
*/
|
|
922
|
+
probe(options) {
|
|
923
|
+
const emitter = firstOf(bagOf(options).emitters, DEFAULT_EMITTERS);
|
|
924
|
+
return {
|
|
925
|
+
path: "geonosis-probe-emit.ts",
|
|
926
|
+
source: `export const geonosisProbe = () => ${emitter}({ eventName: 'geonosis.probe' })
|
|
927
|
+
`
|
|
928
|
+
};
|
|
859
929
|
}
|
|
860
930
|
};
|
|
861
931
|
var emit_declares_attempts_default = emitDeclaresAttempts;
|
|
@@ -996,6 +1066,17 @@ run.`,
|
|
|
996
1066
|
}
|
|
997
1067
|
],
|
|
998
1068
|
type: "problem"
|
|
1069
|
+
},
|
|
1070
|
+
/**
|
|
1071
|
+
* A family literal, which fires whatever the declared roles are — the question `exercised` asks
|
|
1072
|
+
* is whether the rule RUNS here, and a probe built out of an undeclared role name would be
|
|
1073
|
+
* defeated by a repo that happened to declare one spelled the same.
|
|
1074
|
+
*/
|
|
1075
|
+
probe() {
|
|
1076
|
+
return {
|
|
1077
|
+
path: "geonosis-probe-font.tsx",
|
|
1078
|
+
source: "export const GeonosisProbe = () => <p style={{ fontFamily: 'Georgia, serif' }} />\n"
|
|
1079
|
+
};
|
|
999
1080
|
}
|
|
1000
1081
|
};
|
|
1001
1082
|
var font_roles_only_default = fontRolesOnly;
|
|
@@ -1076,6 +1157,36 @@ with no \`layers\` at all the rule refuses the run: walls nobody declared are no
|
|
|
1076
1157
|
}
|
|
1077
1158
|
],
|
|
1078
1159
|
type: "problem"
|
|
1160
|
+
},
|
|
1161
|
+
/**
|
|
1162
|
+
* A file in one declared layer importing a specifier that lands in another it may not reach.
|
|
1163
|
+
*
|
|
1164
|
+
* Both halves come out of the same regex sources the walls are written in — the filename from the
|
|
1165
|
+
* layer it must sit in, the import from the layer it must not reach — and both are re-tested
|
|
1166
|
+
* against the patterns they were built from. A pair the inversion cannot express is a sentence
|
|
1167
|
+
* rather than a silent zero: the walls are a repo's own vocabulary, so there is no fixture
|
|
1168
|
+
* anywhere that could stand in for them.
|
|
1169
|
+
*/
|
|
1170
|
+
probe(options) {
|
|
1171
|
+
const { layers = [] } = bagOf(options);
|
|
1172
|
+
for (const here of layers) {
|
|
1173
|
+
const mayImport = new Set(here.mayImport ?? []);
|
|
1174
|
+
const target = layers.find((other) => other.name !== here.name && !mayImport.has(other.name));
|
|
1175
|
+
const [herePath] = here.paths;
|
|
1176
|
+
const [targetPath] = target?.paths ?? [];
|
|
1177
|
+
if (target === void 0 || herePath === void 0 || targetPath === void 0) continue;
|
|
1178
|
+
const source = pathMatching(targetPath, "geonosis-probe-target.ts");
|
|
1179
|
+
return {
|
|
1180
|
+
path: pathMatching(herePath, "geonosis-probe-wall.ts"),
|
|
1181
|
+
source: `import { geonosisProbe } from '${source}'
|
|
1182
|
+
|
|
1183
|
+
export const geonosisProbeWall = geonosisProbe
|
|
1184
|
+
`
|
|
1185
|
+
};
|
|
1186
|
+
}
|
|
1187
|
+
throw new Error(
|
|
1188
|
+
"biological-architecture/layer-walls: every declared layer may import every other, so no single file can cross a wall \u2014 there is no wall here to probe."
|
|
1189
|
+
);
|
|
1079
1190
|
}
|
|
1080
1191
|
};
|
|
1081
1192
|
var layer_walls_default = layerWalls;
|
|
@@ -1467,6 +1578,15 @@ name.`,
|
|
|
1467
1578
|
}
|
|
1468
1579
|
],
|
|
1469
1580
|
type: "problem"
|
|
1581
|
+
},
|
|
1582
|
+
/** The unnamed overload, told by ARITY — two arguments, which is the shape that fires. */
|
|
1583
|
+
probe(options) {
|
|
1584
|
+
const block = firstOf(bagOf(options).blocks, DEFAULT_BLOCKS);
|
|
1585
|
+
return {
|
|
1586
|
+
path: "geonosis-probe-when.ts",
|
|
1587
|
+
source: `export const geonosisProbe = (input) => ${block}(input, (values) => values.ok)
|
|
1588
|
+
`
|
|
1589
|
+
};
|
|
1470
1590
|
}
|
|
1471
1591
|
};
|
|
1472
1592
|
var named_when_block_default = namedWhenBlock;
|
|
@@ -1730,6 +1850,21 @@ exactly like a clean tree.`,
|
|
|
1730
1850
|
}
|
|
1731
1851
|
],
|
|
1732
1852
|
type: "problem"
|
|
1853
|
+
},
|
|
1854
|
+
/**
|
|
1855
|
+
* The brand list is dielime's and the corpus says `acme`, so this rule reads as firing nowhere in
|
|
1856
|
+
* the repo whose brands it was configured with — one of the two findings that opened this. The
|
|
1857
|
+
* brand goes on a line of its own so no `allowedSubstrings` entry can strip it away: a CDN host
|
|
1858
|
+
* is stripped before the scan, and a probe hiding inside one would prove the opposite of what it
|
|
1859
|
+
* claims.
|
|
1860
|
+
*/
|
|
1861
|
+
probe(options) {
|
|
1862
|
+
const { brands = [] } = bagOf(options);
|
|
1863
|
+
return {
|
|
1864
|
+
path: "geonosis-probe-brand.ts",
|
|
1865
|
+
source: `export const geonosisProbeBrand = '${brands[0] ?? ""}'
|
|
1866
|
+
`
|
|
1867
|
+
};
|
|
1733
1868
|
}
|
|
1734
1869
|
};
|
|
1735
1870
|
var no_brand_names_default = noBrandNames;
|
|
@@ -2232,6 +2367,16 @@ since the field names are the engine's and the label is the API's.`,
|
|
|
2232
2367
|
}
|
|
2233
2368
|
],
|
|
2234
2369
|
type: "problem"
|
|
2370
|
+
},
|
|
2371
|
+
/** One payload reading an estimate field, with no label beside it. */
|
|
2372
|
+
probe(options) {
|
|
2373
|
+
const bag = bagOf(options);
|
|
2374
|
+
const field = firstOf(bag.estimateFields, DEFAULT_ESTIMATE_FIELDS);
|
|
2375
|
+
return {
|
|
2376
|
+
path: "geonosis-probe-count.ts",
|
|
2377
|
+
source: `export const geonosisProbe = (metadata, rows) => ({ rows, total: metadata.${field} })
|
|
2378
|
+
`
|
|
2379
|
+
};
|
|
2235
2380
|
}
|
|
2236
2381
|
};
|
|
2237
2382
|
var no_index_count_as_exact_default = noIndexCountAsExact;
|
|
@@ -2502,6 +2647,18 @@ adds \`workflows/\` back.`,
|
|
|
2502
2647
|
}
|
|
2503
2648
|
],
|
|
2504
2649
|
type: "problem"
|
|
2650
|
+
},
|
|
2651
|
+
/**
|
|
2652
|
+
* A default export in a file named `index`, inside a directory the loader still skips. The
|
|
2653
|
+
* directory is a regex option, so the path is built back out of it and refused if it does not
|
|
2654
|
+
* match — a probe placed outside the tree fires nothing however right its source is.
|
|
2655
|
+
*/
|
|
2656
|
+
probe(options) {
|
|
2657
|
+
const directory = firstOf(bagOf(options).directories, DEFAULT_DIRECTORIES);
|
|
2658
|
+
return {
|
|
2659
|
+
path: pathMatching(directory, "index.ts"),
|
|
2660
|
+
source: "export default async function geonosisProbe() {\n return { ok: true }\n}\n"
|
|
2661
|
+
};
|
|
2505
2662
|
}
|
|
2506
2663
|
};
|
|
2507
2664
|
var no_loader_side_effect_in_index_file_default = noLoaderSideEffectInIndexFile;
|
|
@@ -2599,7 +2756,8 @@ var no_logic_in_component_files_default = noLogicInComponentFiles;
|
|
|
2599
2756
|
|
|
2600
2757
|
// src/rules/no-mock-db-in-integration.ts
|
|
2601
2758
|
var RULE6 = "no-mock-db-in-integration";
|
|
2602
|
-
var
|
|
2759
|
+
var BUN_MOCK = "mock.module";
|
|
2760
|
+
var MOCK_CALLS = /* @__PURE__ */ new Set(["jest.mock", BUN_MOCK, "vi.mock"]);
|
|
2603
2761
|
var calleeOf = (node) => {
|
|
2604
2762
|
const callee = node.callee;
|
|
2605
2763
|
if (callee?.type !== "MemberExpression") return "";
|
|
@@ -2677,6 +2835,21 @@ mock call can be seen in: a handle built in a setup file and threaded through a
|
|
|
2677
2835
|
}
|
|
2678
2836
|
],
|
|
2679
2837
|
type: "problem"
|
|
2838
|
+
},
|
|
2839
|
+
/**
|
|
2840
|
+
* A suite under the configured integration tree, mocking the module that IS the database —
|
|
2841
|
+
* written in bun's spelling, which is what `BUN_MOCK` above is for and not a preference.
|
|
2842
|
+
*/
|
|
2843
|
+
probe(options) {
|
|
2844
|
+
const { dbModules = [], integrationDirs = [] } = bagOf(options);
|
|
2845
|
+
const directory = (integrationDirs[0] ?? "").replace(/^\/+/, "").replace(/\/+$/, "");
|
|
2846
|
+
return {
|
|
2847
|
+
path: `${directory}/geonosis-probe/tests.ts`,
|
|
2848
|
+
source: `import { mock } from 'bun:test'
|
|
2849
|
+
|
|
2850
|
+
${BUN_MOCK}('${dbModules[0] ?? ""}')
|
|
2851
|
+
`
|
|
2852
|
+
};
|
|
2680
2853
|
}
|
|
2681
2854
|
};
|
|
2682
2855
|
var no_mock_db_in_integration_default = noMockDbInIntegration;
|
|
@@ -2769,6 +2942,21 @@ with no map to check reads exactly like a tree with no raw elements in it.`,
|
|
|
2769
2942
|
}
|
|
2770
2943
|
],
|
|
2771
2944
|
type: "problem"
|
|
2945
|
+
},
|
|
2946
|
+
/**
|
|
2947
|
+
* The element→atom map is POSITIONAL, so the probe reads `options[0]` rather than a bag. The path
|
|
2948
|
+
* goes into the first tier the run is scoped to, which is never `atoms` — inside the atom the raw
|
|
2949
|
+
* element is the point of the file and the rule is deliberately silent there.
|
|
2950
|
+
*/
|
|
2951
|
+
probe(options) {
|
|
2952
|
+
const map = Array.isArray(options[0]) ? options[0] : [];
|
|
2953
|
+
const scope = options[1]?.scope;
|
|
2954
|
+
const tier = scope?.[0] ?? "molecules";
|
|
2955
|
+
return {
|
|
2956
|
+
path: `${tier}/geonosis-probe.tsx`,
|
|
2957
|
+
source: `export const GeonosisProbe = () => <${map[0]?.element ?? ""} />
|
|
2958
|
+
`
|
|
2959
|
+
};
|
|
2772
2960
|
}
|
|
2773
2961
|
};
|
|
2774
2962
|
var no_raw_html_atoms_default = noRawHtmlAtoms;
|
|
@@ -3289,6 +3477,25 @@ rather than directories is out of scope \u2014 nothing under a root matches, so
|
|
|
3289
3477
|
}
|
|
3290
3478
|
],
|
|
3291
3479
|
type: "problem"
|
|
3480
|
+
},
|
|
3481
|
+
/**
|
|
3482
|
+
* A directory under a configured root, carrying a manifest, that the registry does not name — and
|
|
3483
|
+
* the one probe in this plugin a single file cannot make fire on its own.
|
|
3484
|
+
*
|
|
3485
|
+
* The rule reads the registry off disk, and a registry it cannot read is a configuration answer
|
|
3486
|
+
* rather than a verdict about the tree, so it returns silently. The probe sits under `roots` and
|
|
3487
|
+
* the registry sits at the consumer's own path; one file cannot be both. It fires when the
|
|
3488
|
+
* registry ALSO exists beside it and fires nothing when it does not, which is the truth and is
|
|
3489
|
+
* left as the truth: a probe widened until it fired would be this rule claiming evidence it does
|
|
3490
|
+
* not have, which is precisely the defect the rule is about.
|
|
3491
|
+
*/
|
|
3492
|
+
probe(options) {
|
|
3493
|
+
const { manifests = [], roots = [] } = bagOf(options);
|
|
3494
|
+
const root = trimSlashes(roots[0] ?? "");
|
|
3495
|
+
return {
|
|
3496
|
+
path: `${root}/geonosis-probe/${manifests[0] ?? ""}`,
|
|
3497
|
+
source: "export const geonosisProbe = { id: 'geonosis-probe' }\n"
|
|
3498
|
+
};
|
|
3292
3499
|
}
|
|
3293
3500
|
};
|
|
3294
3501
|
var no_unregistered_plugin_dir_default = noUnregisteredPluginDir;
|
|
@@ -3579,6 +3786,20 @@ name"); left off, only the presence of a namespace is checked. \`scopes\` defaul
|
|
|
3579
3786
|
}
|
|
3580
3787
|
],
|
|
3581
3788
|
type: "problem"
|
|
3789
|
+
},
|
|
3790
|
+
/**
|
|
3791
|
+
* A plugin route sitting bare on a scope: `/store` and nothing of the plugin's own after it. The
|
|
3792
|
+
* package directory is invented rather than read, because the offence is a PATH shape and a
|
|
3793
|
+
* directory that does not exist yet has the same one.
|
|
3794
|
+
*/
|
|
3795
|
+
probe(options) {
|
|
3796
|
+
const bag = bagOf(options);
|
|
3797
|
+
const under = bag.packages?.find((one) => one.namespaced === true)?.under ?? "";
|
|
3798
|
+
const scope = firstOf(bag.scopes, DEFAULT_SCOPES);
|
|
3799
|
+
return {
|
|
3800
|
+
path: `${under}/geonosis-probe/src/api/${scope}/route.ts`,
|
|
3801
|
+
source: "export async function GET(req, res) {\n res.json({ ok: true })\n}\n"
|
|
3802
|
+
};
|
|
3582
3803
|
}
|
|
3583
3804
|
};
|
|
3584
3805
|
var plugin_route_namespaced_default = pluginRouteNamespaced;
|
|
@@ -3766,6 +3987,25 @@ annotation wording.`,
|
|
|
3766
3987
|
}
|
|
3767
3988
|
],
|
|
3768
3989
|
type: "problem"
|
|
3990
|
+
},
|
|
3991
|
+
/**
|
|
3992
|
+
* A route writing through a service in its own body, with no escape marker on it. The write name
|
|
3993
|
+
* is built from the configured prefix, because `writesWith` reads a capital after the prefix and
|
|
3994
|
+
* a probe spelling `creatething` would pass the rule it is meant to trip.
|
|
3995
|
+
*/
|
|
3996
|
+
probe(options) {
|
|
3997
|
+
const bag = bagOf(options);
|
|
3998
|
+
const prefix = firstOf(bag.mutationPrefixes, DEFAULT_MUTATION_PREFIXES);
|
|
3999
|
+
return {
|
|
4000
|
+
path: pathMatching(firstOf(bag.paths, DEFAULT_PATHS), "route.ts"),
|
|
4001
|
+
source: `export async function POST(req, res) {
|
|
4002
|
+
const service = req.scope.resolve('geonosis_probe')
|
|
4003
|
+
const made = await service.${prefix}GeonosisProbes(req.validatedBody)
|
|
4004
|
+
|
|
4005
|
+
res.json({ made })
|
|
4006
|
+
}
|
|
4007
|
+
`
|
|
4008
|
+
};
|
|
3769
4009
|
}
|
|
3770
4010
|
};
|
|
3771
4011
|
var route_no_inline_mutation_default = routeNoInlineMutation;
|
|
@@ -3773,10 +4013,10 @@ var route_no_inline_mutation_default = routeNoInlineMutation;
|
|
|
3773
4013
|
// src/rules/router-schema-parity.ts
|
|
3774
4014
|
import { existsSync as existsSync2 } from "fs";
|
|
3775
4015
|
var RULE11 = "router-schema-parity";
|
|
3776
|
-
var
|
|
4016
|
+
var EXTENSIONS2 = [".ts", ".tsx"];
|
|
3777
4017
|
var trimSlashes2 = (path2) => path2.replace(/^\/+/, "").replace(/\/+$/, "");
|
|
3778
4018
|
var baseOf = (file) => file.replace(/\.[cm]?[jt]sx?$/, "");
|
|
3779
|
-
var existsWithAnyExtension = (withoutExtension) =>
|
|
4019
|
+
var existsWithAnyExtension = (withoutExtension) => EXTENSIONS2.map((extension) => `${withoutExtension}${extension}`).find(
|
|
3780
4020
|
(path2) => existsSync2(path2)
|
|
3781
4021
|
) ?? null;
|
|
3782
4022
|
var directlyUnder = (filename, directory) => {
|
|
@@ -3847,6 +4087,17 @@ repo-root-relative, because in one consumer they live in different packages.`,
|
|
|
3847
4087
|
}
|
|
3848
4088
|
],
|
|
3849
4089
|
type: "problem"
|
|
4090
|
+
},
|
|
4091
|
+
/**
|
|
4092
|
+
* A router with no schema half. The two directories are repo-root-relative, and the missing half
|
|
4093
|
+
* is a question about the tree the run is over: nothing writes the twin, so nothing is there.
|
|
4094
|
+
*/
|
|
4095
|
+
probe(options) {
|
|
4096
|
+
const { routers = "" } = bagOf(options);
|
|
4097
|
+
return {
|
|
4098
|
+
path: `${trimSlashes2(routers)}/geonosis-probe.ts`,
|
|
4099
|
+
source: "export const geonosisProbeRouter = { list: () => [] }\n"
|
|
4100
|
+
};
|
|
3850
4101
|
}
|
|
3851
4102
|
};
|
|
3852
4103
|
var router_schema_parity_default = routerSchemaParity;
|
|
@@ -3954,6 +4205,16 @@ the 33 keys of 2.19 as its default \u2014 pin your own version's if you are not
|
|
|
3954
4205
|
}
|
|
3955
4206
|
],
|
|
3956
4207
|
type: "problem"
|
|
4208
|
+
},
|
|
4209
|
+
/** A module registered under a key the framework owns — the first of the configured list. */
|
|
4210
|
+
probe(options) {
|
|
4211
|
+
const bag = bagOf(options);
|
|
4212
|
+
const factory = firstOf(bag.moduleFactories, DEFAULT_MODULE_FACTORIES);
|
|
4213
|
+
return {
|
|
4214
|
+
path: "geonosis-probe-module.ts",
|
|
4215
|
+
source: `export default ${factory}('${firstOf(bag.reserved, MODULES_2_19)}', { service: class GeonosisProbeService {} })
|
|
4216
|
+
`
|
|
4217
|
+
};
|
|
3957
4218
|
}
|
|
3958
4219
|
};
|
|
3959
4220
|
var service_name_not_reserved_default = serviceNameNotReserved;
|
|
@@ -4290,6 +4551,29 @@ connection it uses rather than share one opened once per run \u2014 the wrapper
|
|
|
4290
4551
|
}
|
|
4291
4552
|
],
|
|
4292
4553
|
type: "problem"
|
|
4554
|
+
},
|
|
4555
|
+
/**
|
|
4556
|
+
* during.day guards `packages/workflows/src/` and the shipped corpus guards
|
|
4557
|
+
* `corpus/workflows/`, so its fixture lands outside the tree this repo asked about and the rule
|
|
4558
|
+
* reads as firing nowhere in a package that enforces it on every file. This is the same fixture
|
|
4559
|
+
* moved to where the option points — and out of the `wrapper`, which is the one file allowed
|
|
4560
|
+
* to reach the engine.
|
|
4561
|
+
*/
|
|
4562
|
+
probe(options) {
|
|
4563
|
+
const { engine = "", within = "", wrapper } = bagOf(options);
|
|
4564
|
+
const path2 = pathMatching(within, "geonosis-probe-engine-step.ts");
|
|
4565
|
+
if (wrapper !== void 0 && new RegExp(wrapper).test(path2)) {
|
|
4566
|
+
throw new Error(
|
|
4567
|
+
`biological-architecture/${RULE14}: 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.`
|
|
4568
|
+
);
|
|
4569
|
+
}
|
|
4570
|
+
return {
|
|
4571
|
+
path: path2,
|
|
4572
|
+
source: `import { step } from '${engine}'
|
|
4573
|
+
|
|
4574
|
+
export const probe = step('geonosis-probe', async () => ({ ok: true }))
|
|
4575
|
+
`
|
|
4576
|
+
};
|
|
4293
4577
|
}
|
|
4294
4578
|
};
|
|
4295
4579
|
var step_opens_its_own_cell_default = stepOpensItsOwnCell;
|
|
@@ -4404,6 +4688,16 @@ other than \`subscribers/\`.`,
|
|
|
4404
4688
|
}
|
|
4405
4689
|
],
|
|
4406
4690
|
type: "problem"
|
|
4691
|
+
},
|
|
4692
|
+
/** A subscriber config with an event and no id, inside the configured subscriber tree. */
|
|
4693
|
+
probe(options) {
|
|
4694
|
+
return {
|
|
4695
|
+
path: pathMatching(
|
|
4696
|
+
firstOf(bagOf(options).paths, DEFAULT_PATHS2),
|
|
4697
|
+
"geonosis-probe.ts"
|
|
4698
|
+
),
|
|
4699
|
+
source: "export default async function geonosisProbe() {}\n\nexport const config = { event: 'geonosis.probe' }\n"
|
|
4700
|
+
};
|
|
4407
4701
|
}
|
|
4408
4702
|
};
|
|
4409
4703
|
var subscriber_declares_id_default = subscriberDeclaresId;
|
|
@@ -5263,6 +5557,17 @@ exactly like a clean tree.`,
|
|
|
5263
5557
|
}
|
|
5264
5558
|
],
|
|
5265
5559
|
type: "problem"
|
|
5560
|
+
},
|
|
5561
|
+
/**
|
|
5562
|
+
* A named colour in an inline style, which fires under any token prefix — the question is whether
|
|
5563
|
+
* the rule RUNS in this repo, and a probe spelled out of the prefix would be defeated by a repo
|
|
5564
|
+
* that happened to declare a token of the same name.
|
|
5565
|
+
*/
|
|
5566
|
+
probe() {
|
|
5567
|
+
return {
|
|
5568
|
+
path: "geonosis-probe-colour.tsx",
|
|
5569
|
+
source: "export const GeonosisProbe = () => <span style={{ color: 'rebeccapurple' }} />\n"
|
|
5570
|
+
};
|
|
5266
5571
|
}
|
|
5267
5572
|
};
|
|
5268
5573
|
var isNamedOnly = (value) => /^[a-z]+$/i.test(value.trim());
|
|
@@ -5378,6 +5683,26 @@ wraps the query steps.`,
|
|
|
5378
5683
|
}
|
|
5379
5684
|
],
|
|
5380
5685
|
type: "problem"
|
|
5686
|
+
},
|
|
5687
|
+
/**
|
|
5688
|
+
* Two query steps in one body, one named and one not — which is one finding rather than two. A
|
|
5689
|
+
* body with a single un-named step collides with nothing and is deliberately exempt, so a probe
|
|
5690
|
+
* built from one would fire nothing and read as a rule that cannot be exercised.
|
|
5691
|
+
*/
|
|
5692
|
+
probe(options) {
|
|
5693
|
+
const bag = bagOf(options);
|
|
5694
|
+
const factory = firstOf(bag.workflowFactories, DEFAULT_WORKFLOW_FACTORIES);
|
|
5695
|
+
const step = firstOf(bag.queryStepCalls, DEFAULT_QUERY_STEP_CALLS);
|
|
5696
|
+
return {
|
|
5697
|
+
path: "geonosis-probe-query-steps.ts",
|
|
5698
|
+
source: `export const geonosisProbe = ${factory}('geonosis-probe', () => {
|
|
5699
|
+
const first = ${step}({ entity: 'first' }).config({ name: 'geonosis-probe-first' })
|
|
5700
|
+
const second = ${step}({ entity: 'second' })
|
|
5701
|
+
|
|
5702
|
+
return { first, second }
|
|
5703
|
+
})
|
|
5704
|
+
`
|
|
5705
|
+
};
|
|
5381
5706
|
}
|
|
5382
5707
|
};
|
|
5383
5708
|
var unique_query_step_name_default = uniqueQueryStepName;
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@geonosis/oxlint-plugin-biological-architecture",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"types": "./dist/index.d.ts",
|
|
4
5
|
"description": "Biological tier architecture as lint — the union of the dielime and during.day rule sets, shipped as presets.",
|
|
5
6
|
"keywords": [
|
|
6
7
|
"oxlint",
|
|
@@ -21,9 +22,18 @@
|
|
|
21
22
|
"type": "module",
|
|
22
23
|
"main": "dist/index.js",
|
|
23
24
|
"exports": {
|
|
24
|
-
".":
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"default": "./dist/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./discover-atoms": {
|
|
30
|
+
"types": "./dist/discover-atoms.d.ts",
|
|
31
|
+
"default": "./dist/discover-atoms.js"
|
|
32
|
+
},
|
|
33
|
+
"./presets": {
|
|
34
|
+
"types": "./dist/presets.d.ts",
|
|
35
|
+
"default": "./dist/presets.js"
|
|
36
|
+
}
|
|
27
37
|
},
|
|
28
38
|
"files": [
|
|
29
39
|
"corpus",
|
|
@@ -33,7 +43,7 @@
|
|
|
33
43
|
"oxlint": ">=1.77"
|
|
34
44
|
},
|
|
35
45
|
"devDependencies": {
|
|
36
|
-
"@geonosis/lint-parity": "1.
|
|
46
|
+
"@geonosis/lint-parity": "1.2.0"
|
|
37
47
|
},
|
|
38
48
|
"engines": {
|
|
39
49
|
"node": ">=22"
|