@platforma-sdk/block-tools 2.10.18 → 2.10.19

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/block-tools",
3
- "version": "2.10.18",
3
+ "version": "2.10.19",
4
4
  "description": "Utility to manipulate Platforma Blocks and Block Registry",
5
5
  "license": "UNLICENSED",
6
6
  "bin": {
@@ -34,13 +34,13 @@
34
34
  "yaml": "^2.8.0",
35
35
  "zod": "~3.25.76",
36
36
  "@milaboratories/pl-http": "1.2.4",
37
- "@milaboratories/pl-model-middle-layer": "1.30.6",
38
37
  "@milaboratories/pl-model-common": "1.46.1",
38
+ "@milaboratories/pl-model-middle-layer": "1.30.6",
39
39
  "@milaboratories/resolve-helper": "1.1.3",
40
- "@milaboratories/pl-model-backend": "1.4.7",
41
- "@milaboratories/ts-helpers": "1.8.3",
42
40
  "@milaboratories/ts-helpers-oclif": "1.1.42",
43
- "@platforma-sdk/blocks-deps-updater": "2.2.0"
41
+ "@platforma-sdk/blocks-deps-updater": "2.2.0",
42
+ "@milaboratories/ts-helpers": "1.8.3",
43
+ "@milaboratories/pl-model-backend": "1.4.7"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@rollup/plugin-node-resolve": "^16.0.1",
@@ -56,10 +56,10 @@
56
56
  "vite": "^8.0.6",
57
57
  "vite-plugin-dts": "^4.5.3",
58
58
  "vitest": "^4.1.3",
59
+ "@milaboratories/build-configs": "2.0.0",
59
60
  "@milaboratories/oclif-index": "1.1.1",
60
- "@milaboratories/ts-configs": "1.2.3",
61
61
  "@milaboratories/ts-builder": "1.5.2",
62
- "@milaboratories/build-configs": "2.0.0"
62
+ "@milaboratories/ts-configs": "1.2.3"
63
63
  },
64
64
  "oclif": {
65
65
  "bin": "block-tools",
@@ -0,0 +1,28 @@
1
+ # structurer — mental model
2
+
3
+ A declarative reconciler for a block's scaffolding. `rules/` DECLARE the
4
+ canonical end-state of every non-source file in a block (package.json, configs,
5
+ tsconfig, scripts, catalog); `engine/` reconciles any block toward that state.
6
+ To change what "canonical" means, edit `rules/`; the engine is block-agnostic.
7
+
8
+ ## Boundaries
9
+
10
+ - `engine/` — generic reconciliation primitives, module discovery, IR. Knows nothing about blocks.
11
+ - `rules/` — the only home of block-specific layout knowledge. `templates/` holds the verbatim file bodies the rules reference.
12
+ - Owns: the shape of a block's scaffolding. Is NOT a build tool, and NOT the author of a block's source — seeded/scaffolded files become author-owned once written.
13
+
14
+ ## Reading posture
15
+
16
+ - Each `rules/*` file pairs a generator (init: full initial content) with a body (refresh: drift-correcting assertions). Read as "what the file should be" + "how to nudge an existing file there", not as sequential logic.
17
+ - The primitive choice IS the design: `fixed` (overwrite verbatim, engine-owned), `managed` (reconcile named fields, author keeps the rest), `scaffold` (write-once default, author may tune), `seed` (written once at init, author owns forever), `remove` (one-way). Wrong primitive is the main design error — `fixed` on an author-tunable file clobbers their work; `seed` on engine-owned content lets drift accumulate.
18
+
19
+ ## Invariants
20
+
21
+ - Fixpoint: `refresh` on an already-canonical block makes zero changes. Every rule must converge.
22
+ - Generators emit oxfmt-clean output (the `enforce*` calls mirror oxfmt's order), so build→check passes with no prior `fmt`.
23
+ - sdk-internal blocks (`etc/blocks/*`) skip root-scope and standalone test wiring — the monorepo owns that infra; the structurer must neither impose nor strip it.
24
+
25
+ ## Gotchas
26
+
27
+ - A rule change also changes the canonical for `etc/blocks/*`: refresh them in the SAME PR (`pnpm run check-blocks`) or CI fails.
28
+ - Dep/peer changes need a `pnpm i` lockfile sync — pnpm records peers and per-importer deps in pnpm-lock.yaml; frozen-install CI fails otherwise.
@@ -23,40 +23,39 @@ export function testFrameworkMigration(): void {
23
23
  // Unconditional legacy-cleanup rules. Each is a no-op on an
24
24
  // already-canonical block (remove on an absent path, removeScript /
25
25
  // removeDep on an absent key) and idempotent, so they sit at top level
26
- // with no `when` gate. The trailing comment on each line names the real
27
- // block(s) that carry the artefact being cleaned.
26
+ // with no `when` gate.
28
27
  //
29
28
  // Root-scope cleanup is skipped for `--sdk-internal` blocks (no root
30
29
  // module in that mode), so it never touches in-monorepo blocks.
31
30
  export function legacyCleanup(): void {
32
- // eslint → oxlint: the canonical layout ships `.oxlintrc.json` /
33
- // `.oxfmtrc.json`; flat eslint configs are retired.
31
+ // Retired per-scope config files: flat eslint configs and vite-era build /
32
+ // split-tsconfig files, replaced by the oxlint/oxfmt + ts-builder layout.
34
33
  scope("model", () => {
35
- remove("eslint.config.mjs"); // samples-and-data, mixcr-clonotyping, clonotype-clustering, antibody-sequence-liabilities
36
- remove("vite.config.mts"); // samples-and-data (vite build → ts-builder)
34
+ remove("eslint.config.mjs");
35
+ remove("vite.config.mts");
37
36
  });
38
37
  scope("ui", () => {
39
- remove("eslint.config.mjs"); // samples-and-data, mixcr-clonotyping, clonotype-clustering, antibody-sequence-liabilities
40
- remove("vite.config.ts"); // samples-and-data (vite build → ts-builder)
41
- remove("tsconfig.app.json"); // samples-and-data (vite-era split tsconfig)
42
- remove("tsconfig.node.json"); // samples-and-data (vite-era split tsconfig)
38
+ remove("eslint.config.mjs");
39
+ remove("vite.config.ts");
40
+ remove("tsconfig.app.json");
41
+ remove("tsconfig.node.json");
43
42
  });
44
43
  scope("test", () => {
45
- remove("eslint.config.mjs"); // all 5 experiment blocks
44
+ remove("eslint.config.mjs");
46
45
  });
47
46
 
48
47
  // Root-scope cleanup. The second `managed("package.json")` body composes
49
48
  // after rootRules.
50
49
  scope("root", () => {
51
- remove(".prettierrc"); // samples-and-data, sequence-properties (prettier → oxfmt)
50
+ remove(".prettierrc");
52
51
  managed(
53
52
  "package.json",
54
53
  generate(() => rootPackageJsonInitial(getActiveRunContext())),
55
54
  () => {
56
- // `pretty` (prettier) is superseded by the canonical `fmt` (oxfmt);
57
- // the standalone deps-updater was merged into block-tools.
58
- removeScript("pretty"); // samples-and-data
59
- removeDep("@platforma-sdk/blocks-deps-updater"); // samples-and-data
55
+ // `pretty` (prettier) is superseded by `fmt` (oxfmt); the standalone
56
+ // deps-updater is now part of block-tools.
57
+ removeScript("pretty");
58
+ removeDep("@platforma-sdk/blocks-deps-updater");
60
59
  },
61
60
  );
62
61
  });
@@ -16,6 +16,7 @@ import {
16
16
  ensureDevDep,
17
17
  ensureDevDeps,
18
18
  removeDep,
19
+ removeScript,
19
20
  removeField,
20
21
  ensurePeerDeps,
21
22
  enforceAlphabeticalOrder,
@@ -26,6 +27,7 @@ import {
26
27
  } from "../engine/api";
27
28
  import { canonicalPackageJsonOrder } from "./shared/key-order";
28
29
  import { COLOCATED_TEST_GLOB } from "./shared/colocated-tests";
30
+ import { removeRetiredToolchainDeps } from "./shared/retired-deps";
29
31
 
30
32
  export function modelPackageJsonInitial(ctx: RunContext): Record<string, unknown> {
31
33
  const v = ctx.blockVars;
@@ -127,12 +129,9 @@ export function modelPackageJsonRules(): void {
127
129
  ),
128
130
  );
129
131
 
130
- // vite/tsup-era artefacts: the canonical model builds via ts-builder, so the
131
- // legacy `tsup`/`vite` devDeps and the top-level `tsup` bundler config block
132
- // are dropped.
133
- removeDep("tsup");
134
- removeDep("vite");
132
+ removeRetiredToolchainDeps();
135
133
  removeField("tsup");
134
+ removeScript("lint");
136
135
 
137
136
  enforceAlphabeticalOrder("dependencies");
138
137
  enforceAlphabeticalOrder("devDependencies");
@@ -8,6 +8,7 @@ import {
8
8
  ensureScript,
9
9
  ensureDevDeps,
10
10
  ensurePeerDeps,
11
+ removeScript,
11
12
  removeField,
12
13
  pruneKeysMatching,
13
14
  enforceAlphabeticalOrder,
@@ -34,10 +35,9 @@ export function rootPackageJsonInitial(_ctx: RunContext): Record<string, unknown
34
35
  watch: "turbo watch build",
35
36
  changeset: "changeset",
36
37
  "version-packages": "changeset version",
37
- // Deprecated in favour of `update` (the full refresh → install →
38
- // refresh → format flow); kept for compatibility.
38
+ // Deprecated alias of `upgrade-sdk`; kept for compatibility.
39
39
  "update-sdk": "block-tools structure refresh --update-deps-only",
40
- update:
40
+ "upgrade-sdk":
41
41
  "block-tools structure refresh --update-deps-only && pnpm i && block-tools structure refresh && pnpm i && pnpm fmt",
42
42
  },
43
43
  peerDependencies: {
@@ -76,16 +76,18 @@ export function rootPackageJsonRules(): void {
76
76
  ensureScript("watch", "turbo watch build");
77
77
  ensureScript("changeset", "changeset");
78
78
  ensureScript("version-packages", "changeset version");
79
- // Deprecated in favour of `update`; kept for compatibility.
79
+ // `update-sdk` is a deprecated alias of `upgrade-sdk`, kept for compatibility;
80
+ // `update` is the pre-rename name — drop it so refreshed blocks converge.
80
81
  ensureScript("update-sdk", "block-tools structure refresh --update-deps-only");
81
- // Full SDK-update flow: bump catalog (deps-only) → install → re-apply
82
+ removeScript("update");
83
+ // Full SDK-upgrade flow: bump catalog (deps-only) → install → re-apply
82
84
  // structure against the freshly-pulled deps → install AGAIN (the structural
83
85
  // pass can add new devDeps — e.g. ts-builder/oxlint/oxfmt on a first
84
86
  // migration — that `pnpm fmt` then needs on PATH) → format. Wrapped as one
85
87
  // script. `pnpm fmt` (turbo run fmt) leaves the tree oxfmt-clean after the
86
88
  // structural rewrite so a follow-up `pnpm check` passes.
87
89
  ensureScript(
88
- "update",
90
+ "upgrade-sdk",
89
91
  "block-tools structure refresh --update-deps-only && pnpm i && block-tools structure refresh && pnpm i && pnpm fmt",
90
92
  );
91
93
 
@@ -20,6 +20,7 @@
20
20
 
21
21
  import { ensureWorkspaceModulePaths, ensureCatalogAbsent, type RunContext } from "../engine/api";
22
22
  import { matchesBumpPattern, type DerivedCatalogPin } from "../engine/registry-client";
23
+ import { RETIRED_TOOLCHAIN_DEPS } from "./shared/retired-deps";
23
24
 
24
25
  /** SDK packages that live in the catalog (membership only — no versions).
25
26
  * Init fetches npm latest for each; refresh leaves them as the lockfile has
@@ -109,11 +110,7 @@ export function rootPnpmWorkspaceInitial(ctx: RunContext): Record<string, unknow
109
110
 
110
111
  export function rootPnpmWorkspaceRules(): void {
111
112
  ensureWorkspaceModulePaths();
112
- // vite/tsup/vue-tsc-era catalog entries: the canonical toolchain (ts-builder
113
- // owns vue-tsc; ts-builder + rolldown replace vite/tsup) does not use them.
114
- // Drop the orphaned catalog keys — paired with the per-package `removeDep`
115
- // so a migrated block sheds both the dep and its catalog entry.
116
- ensureCatalogAbsent("vite");
117
- ensureCatalogAbsent("tsup");
118
- ensureCatalogAbsent("vue-tsc");
113
+ // Catalog side of the retired-dep cleanup — the per-package side sheds the
114
+ // matching `catalog:` references.
115
+ for (const name of RETIRED_TOOLCHAIN_DEPS) ensureCatalogAbsent(name);
119
116
  }
@@ -14,7 +14,6 @@ export function rootRules(): void {
14
14
  when(
15
15
  ({ ctx }) => !ctx.isSdkInternal,
16
16
  () => {
17
- // see templates/static/root/turbo.json — verbatim canonical content.
18
17
  fixed("turbo.json", file("root/turbo.json"));
19
18
  fixed(".vscode/settings.json", file("root/.vscode/settings.json"));
20
19
 
@@ -0,0 +1,42 @@
1
+ // Retired toolchain dependencies — a SINGLE source of truth.
2
+ //
3
+ // These packages are superseded by the canonical toolchain (ts-builder owns
4
+ // the build, vue-tsc, and the vite plugins; oxlint/oxfmt replace eslint) and
5
+ // must be shed from a migrated block in BOTH places at once:
6
+ // - the root catalog → `ensureCatalogAbsent` (root-pnpm-workspace)
7
+ // - every package.json scope → `removeDep` (via removeRetiredToolchainDeps)
8
+ //
9
+ // Removing from only one side is a latent bug: a catalog entry dropped while a
10
+ // package still references `<dep>: "catalog:"` leaves a dangling reference that
11
+ // breaks `pnpm install`. Driving both from this one list makes that impossible
12
+ // — add (or un-retire) a dependency HERE, once.
13
+ //
14
+ // Per-entry rationale:
15
+ // vite / tsup — bundling now goes through ts-builder + rolldown.
16
+ // vue-tsc — ts-builder runs vue-tsc internally for `block-ui`; a
17
+ // direct dep resolves a different version than the
18
+ // toolchain pins, causing type clashes in main.ts.
19
+ // @vitejs/plugin-vue — bundled by ts-builder's internal vite config.
20
+ // vite-plugin-dts — .d.ts emit is handled by ts-builder.
21
+ // @platforma-sdk/eslint-config — eslint is retired; linting runs via oxlint
22
+ // inside `ts-builder check`.
23
+
24
+ import { removeDep } from "../../engine/api";
25
+
26
+ export const RETIRED_TOOLCHAIN_DEPS: readonly string[] = [
27
+ "vite",
28
+ "tsup",
29
+ "vue-tsc",
30
+ "@vitejs/plugin-vue",
31
+ "vite-plugin-dts",
32
+ "@platforma-sdk/eslint-config",
33
+ ];
34
+
35
+ /** Drop every retired toolchain dep from the current package.json scope.
36
+ * Idempotent (a `removeDep` on an absent key is a no-op), so it is safe to
37
+ * call uniformly from every package.json rules body regardless of which deps
38
+ * a given scope ever carried. Pairs with the catalog-side removal in
39
+ * `rootPnpmWorkspaceRules`. */
40
+ export function removeRetiredToolchainDeps(): void {
41
+ for (const name of RETIRED_TOOLCHAIN_DEPS) removeDep(name);
42
+ }
@@ -7,11 +7,13 @@ import {
7
7
  ensureDevDeps,
8
8
  ensurePeerDeps,
9
9
  removeDep,
10
+ removeScript,
10
11
  enforceAlphabeticalOrder,
11
12
  enforceFieldOrder,
12
13
  type RunContext,
13
14
  } from "../engine/api";
14
15
  import { canonicalPackageJsonOrder } from "./shared/key-order";
16
+ import { removeRetiredToolchainDeps } from "./shared/retired-deps";
15
17
 
16
18
  export function testPackageJsonInitial(ctx: RunContext): Record<string, unknown> {
17
19
  const v = ctx.blockVars;
@@ -21,9 +23,9 @@ export function testPackageJsonInitial(ctx: RunContext): Record<string, unknown>
21
23
  private: true,
22
24
  type: "module",
23
25
  scripts: {
24
- // Type-only check (no oxlint/oxfmt — the test scope ships no lint/fmt
25
- // config). Slots into the turbo `check` task.
26
- check: "ts-builder type-check --target block-test",
26
+ fmt: "ts-builder format",
27
+ // `ts-builder check` runs type-check + lint (oxlint) + fmt-check (oxfmt).
28
+ check: "ts-builder check --target block-test",
27
29
  test: "vitest run --passWithNoTests",
28
30
  },
29
31
  peerDependencies: {
@@ -41,12 +43,13 @@ export function testPackageJsonInitial(ctx: RunContext): Record<string, unknown>
41
43
  export function testPackageJsonRules(): void {
42
44
  ensureField("type", "module");
43
45
 
44
- // Type-only check (no oxlint/oxfmt — the test scope ships no lint/fmt
45
- // config); slots into the turbo `check` task.
46
- ensureScript("check", "ts-builder type-check --target block-test");
46
+ ensureScript("fmt", "ts-builder format");
47
+ // `ts-builder check` runs type-check + lint (oxlint) + fmt-check (oxfmt).
48
+ ensureScript("check", "ts-builder check --target block-test");
47
49
  ensureScript("test", "vitest run --passWithNoTests");
50
+ // Linting runs inside `ts-builder check` — no separate `lint` script.
51
+ removeScript("lint");
48
52
 
49
- // @platforma-sdk/test is a test-time dep → devDependencies (matches prod).
50
53
  ensureDevDeps({
51
54
  "@platforma-sdk/test": "sdk:",
52
55
  "@milaboratories/ts-builder": "sdk:",
@@ -55,12 +58,12 @@ export function testPackageJsonRules(): void {
55
58
  });
56
59
 
57
60
  // The test tsconfig (@milaboratories/ts-configs/block/test) supplies the
58
- // ambient types; only the `typescript` peer is needed. Drop any stray
59
- // `@types/node` peer a legacy block declares.
61
+ // ambient types, so only the `typescript` peer is needed — no `@types/node`.
60
62
  ensurePeerDeps({
61
63
  typescript: "*",
62
64
  });
63
65
  removeDep("@types/node");
66
+ removeRetiredToolchainDeps();
64
67
 
65
68
  enforceAlphabeticalOrder("dependencies");
66
69
  enforceAlphabeticalOrder("devDependencies");
@@ -11,6 +11,10 @@ export function testRules(): void {
11
11
  // lets the check pass on a test-less block while `include` still
12
12
  // type-checks real tests once present.
13
13
  fixed("tsconfig.json", file("test/tsconfig.json"));
14
+ // Block-local oxlint/oxfmt config — test sources are lint + fmt-checked
15
+ // (the `check` script runs `ts-builder check --target block-test`).
16
+ fixed(".oxlintrc.json", file("test/.oxlintrc.json"));
17
+ fixed(".oxfmtrc.json", file("test/.oxfmtrc.json"));
14
18
  // scaffold (not fixed): integration tests legitimately tune timeout /
15
19
  // retry per block. Write the canonical default if absent; never
16
20
  // overwrite an author's config.
@@ -26,6 +26,7 @@ import {
26
26
  import { scopeDepMap } from "../engine/ctx";
27
27
  import { canonicalPackageJsonOrder } from "./shared/key-order";
28
28
  import { COLOCATED_TEST_GLOB } from "./shared/colocated-tests";
29
+ import { removeRetiredToolchainDeps } from "./shared/retired-deps";
29
30
 
30
31
  export function uiPackageJsonInitial(ctx: RunContext): Record<string, unknown> {
31
32
  const v = ctx.blockVars;
@@ -52,6 +53,7 @@ export function uiPackageJsonInitial(ctx: RunContext): Record<string, unknown> {
52
53
  "@milaboratories/ts-configs": "sdk:",
53
54
  },
54
55
  peerDependencies: {
56
+ "@types/node": "*",
55
57
  typescript: "*",
56
58
  },
57
59
  };
@@ -77,33 +79,25 @@ export function uiPackageJsonRules(): void {
77
79
  "@milaboratories/ts-configs": "sdk:",
78
80
  });
79
81
 
80
- // `vue-tsc` is owned by `ts-builder` (which runs it internally for
81
- // `--target block-ui`), so the ui must NOT declare its own. A direct
82
- // `vue-tsc` dep is the vestigial vite/vue-tsc-era artefact: it resolves
83
- // independently of the version ts-builder pins, which is how a block ended
84
- // up type-checking under a different vue-tsc than the toolchain intends.
85
- removeDep("vue-tsc");
86
-
87
- // vite-era artefacts: the canonical ui builds + dev-serves via ts-builder,
88
- // so a legacy `vite` dep and the `preview` (vite preview) script are dropped.
89
- removeDep("vite");
82
+ removeRetiredToolchainDeps();
90
83
  removeScript("preview");
84
+ removeScript("lint");
91
85
 
92
- // The ui builds with `--target block-ui` (types: []), so by default it
93
- // carries no browser/vitest/node ambient types — only the `typescript`
94
- // peer for IDE type resolution. Drop any stray `@types/node` a legacy
95
- // block declares...
86
+ // `@types/node` is declared as a peer by default — mirrors the model scope
87
+ // (the block author resolves it from the workspace root). The ui builds with
88
+ // `--target block-ui` (types: []), so it pulls no node ambient types into the
89
+ // build; the peer only satisfies IDE / type resolution, alongside `typescript`.
96
90
  ensurePeerDeps({
91
+ "@types/node": "*",
97
92
  typescript: "*",
98
93
  });
99
- removeDep("@types/node");
100
94
 
101
- // ...but a ui WITH co-located unit tests (`src/**/*.test.ts`) needs the
102
- // vitest `test` script, the `vitest` devDep, AND node ambient types: re-add
103
- // `@types/node` as a devDep so `types: ["node"]` in ui/tsconfig (wired under
104
- // the same predicate) resolves the tests' `node:*` imports. A test-less ui
105
- // keeps the lean default (no test script, no vitest, no @types/node) and
106
- // stays a fixpoint. Runs AFTER removeDep so the dev deps are not stripped.
95
+ // A ui WITH co-located unit tests (`src/**/*.test.ts`) needs the vitest
96
+ // `test` script, the `vitest` devDep, AND node ambient types promoted from
97
+ // peer to a devDep (the single-section invariant drops the peer) so that
98
+ // `types: ["node"]` in ui/tsconfig — wired under the same predicate —
99
+ // resolves the tests' `node:*` imports. A test-less ui keeps `@types/node`
100
+ // as a peer and carries no vitest, staying a refresh fixpoint.
107
101
  //
108
102
  // Skipped entirely for sdk-internal (in-monorepo) blocks: they own their test
109
103
  // wiring under the monorepo's shared infrastructure — see model-package-json.
@@ -19,6 +19,7 @@ import {
19
19
  import { scopeDepMaps } from "../engine/ctx";
20
20
  import { canonicalPackageJsonOrder } from "./shared/key-order";
21
21
  import { COLOCATED_TEST_GLOB } from "./shared/colocated-tests";
22
+ import { removeRetiredToolchainDeps } from "./shared/retired-deps";
22
23
 
23
24
  export function workflowPackageJsonInitial(ctx: RunContext): Record<string, unknown> {
24
25
  const v = ctx.blockVars;
@@ -55,11 +56,10 @@ export function workflowPackageJsonInitial(ctx: RunContext): Record<string, unkn
55
56
  export function workflowPackageJsonRules(): void {
56
57
  ensureField("type", "module");
57
58
 
58
- // No `fmt`: the workflow is Tengo, not TS. Build + check go through
59
- // pl-tengo. shx powers the cross-platform build clean-up.
59
+ // No `fmt` script: the workflow is Tengo, not TS — build + check run via
60
+ // pl-tengo; `format` runs the emacs-batch Tengo formatter (no-op when absent).
60
61
  ensureScript("build", "shx rm -rf dist && pl-tengo build");
61
62
  ensureScript("check", "pl-tengo check");
62
- // Tengo source formatter (emacs batch); no-op notice when emacs is absent.
63
63
  ensureScript("format", "/usr/bin/env emacs --script ./format.el || echo 'No emacs.'");
64
64
  // The vitest `test` script AND the `vitest` devDep are wired ONLY when the
65
65
  // workflow carries co-located integration tests (`src/**/*.test.ts`, incl.
@@ -98,6 +98,10 @@ export function workflowPackageJsonRules(): void {
98
98
  shx: "catalog:",
99
99
  });
100
100
 
101
+ // No-op for a canonical Tengo workflow; called uniformly across every scope
102
+ // for safety.
103
+ removeRetiredToolchainDeps();
104
+
101
105
  enforceAlphabeticalOrder("dependencies");
102
106
  enforceAlphabeticalOrder("devDependencies");
103
107
  enforceAlphabeticalOrder("peerDependencies");
@@ -21,16 +21,15 @@ import { COLOCATED_TEST_GLOB } from "./shared/colocated-tests";
21
21
 
22
22
  export function workflowRules(): void {
23
23
  scope("workflow", () => {
24
- // tsconfig for the TypeScript vitest integration tests under src/test
25
- // (e.g. mixcr's workflow/src/test/columns.test.ts). types:[] keeps the
26
- // isomorphic workflow free of ambient Node/DOM types.
27
- fixed("tsconfig.json", file("workflow/tsconfig.json"));
28
24
  // Tengo source formatter (emacs batch); the `format` script invokes it.
29
25
  fixed("format.el", file("workflow/format.el"));
30
- // vitest config only when the workflow carries co-located tests
31
- // (`src/**/*.test.ts`, incl. `src/test/`) — paired with the conditional
32
- // `vitest` devDep + `test` script in workflow-package-json. scaffold (not
33
- // fixed): author-tunable when present; a test-less workflow gets none.
26
+ // The TS-test tsconfig + vitest config exist ONLY when the workflow carries
27
+ // co-located tests (`src/**/*.test.ts`, incl. `src/test/` — e.g. mixcr's
28
+ // workflow/src/test/columns.test.ts). They pair with the conditional
29
+ // `vitest` devDep + `test` script in workflow-package-json. tsconfig is
30
+ // `fixed` (structural: types:[] keeps the isomorphic workflow free of
31
+ // ambient Node/DOM types); vitest.config is `scaffold` (author-tunable once
32
+ // present). A test-less workflow gets neither and stays a refresh fixpoint.
34
33
  //
35
34
  // Skipped entirely for sdk-internal (in-monorepo) blocks: they own their
36
35
  // test config under the monorepo's shared infrastructure (e.g. a bespoke
@@ -41,14 +40,20 @@ export function workflowRules(): void {
41
40
  () =>
42
41
  when(
43
42
  whenFilesExist(COLOCATED_TEST_GLOB),
44
- () => scaffold("vitest.config.mts", file("workflow/vitest.config.mts")),
45
- () => remove("vitest.config.mts"),
43
+ () => {
44
+ fixed("tsconfig.json", file("workflow/tsconfig.json"));
45
+ scaffold("vitest.config.mts", file("workflow/vitest.config.mts"));
46
+ },
47
+ () => {
48
+ remove("tsconfig.json");
49
+ remove("vitest.config.mts");
50
+ },
46
51
  ),
47
52
  );
48
53
  // No workflow facade (index.js / index.d.ts): the block loader resolves the
49
54
  // workflow via the `block:` components dist path (workflow/dist/.../main.plj.gz),
50
- // never the JS facade. It was orphaned in production — dropped. Actively
51
- // removed so existing blocks that carry it get cleaned (idempotent on absence).
55
+ // never the JS facade. Removed so blocks that carry one get cleaned
56
+ // (idempotent on absence).
52
57
  remove("index.js");
53
58
  remove("index.d.ts");
54
59
 
@@ -0,0 +1,4 @@
1
+ {
2
+ "extends": ["node_modules/@milaboratories/ts-builder/configs/oxfmt.json"],
3
+ "ignorePatterns": ["dist", "coverage", "CHANGELOG.md"]
4
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": ["node_modules/@milaboratories/ts-builder/dist/configs/oxlint-test.json"]
3
+ }