@platforma-sdk/block-tools 2.10.17 → 2.10.18

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.
@@ -38,7 +38,7 @@ export function rootPackageJsonInitial(_ctx: RunContext): Record<string, unknown
38
38
  // refresh → format flow); kept for compatibility.
39
39
  "update-sdk": "block-tools structure refresh --update-deps-only",
40
40
  update:
41
- "block-tools structure refresh --update-deps-only && pnpm i && block-tools structure refresh && pnpm fmt",
41
+ "block-tools structure refresh --update-deps-only && pnpm i && block-tools structure refresh && pnpm i && pnpm fmt",
42
42
  },
43
43
  peerDependencies: {
44
44
  oxlint: "*",
@@ -79,12 +79,14 @@ export function rootPackageJsonRules(): void {
79
79
  // Deprecated in favour of `update`; kept for compatibility.
80
80
  ensureScript("update-sdk", "block-tools structure refresh --update-deps-only");
81
81
  // Full SDK-update flow: bump catalog (deps-only) → install → re-apply
82
- // structure against the freshly-pulled deps → format the result, wrapped
83
- // as one script. `pnpm fmt` (turbo run fmt) leaves the tree oxfmt-clean
84
- // after the structural rewrite so a follow-up `pnpm check` passes.
82
+ // structure against the freshly-pulled deps → install AGAIN (the structural
83
+ // pass can add new devDeps — e.g. ts-builder/oxlint/oxfmt on a first
84
+ // migration — that `pnpm fmt` then needs on PATH) → format. Wrapped as one
85
+ // script. `pnpm fmt` (turbo run fmt) leaves the tree oxfmt-clean after the
86
+ // structural rewrite so a follow-up `pnpm check` passes.
85
87
  ensureScript(
86
88
  "update",
87
- "block-tools structure refresh --update-deps-only && pnpm i && block-tools structure refresh && pnpm fmt",
89
+ "block-tools structure refresh --update-deps-only && pnpm i && block-tools structure refresh && pnpm i && pnpm fmt",
88
90
  );
89
91
 
90
92
  ensureDevDeps({
@@ -18,8 +18,8 @@
18
18
  // npm-latest for the SDK families) lives in the separate `onInitOrUpdate`
19
19
  // frame (`rootCatalogBumpRules`), which fires on init + update-deps only.
20
20
 
21
- import { ensureWorkspaceModulePaths, type RunContext } from "../engine/api";
22
- import { matchesBumpPattern } from "../engine/registry-client";
21
+ import { ensureWorkspaceModulePaths, ensureCatalogAbsent, type RunContext } from "../engine/api";
22
+ import { matchesBumpPattern, type DerivedCatalogPin } from "../engine/registry-client";
23
23
 
24
24
  /** SDK packages that live in the catalog (membership only — no versions).
25
25
  * Init fetches npm latest for each; refresh leaves them as the lockfile has
@@ -62,14 +62,23 @@ export const INFRA_CATALOG_FLOOR: Record<string, string> = {
62
62
  shx: "~0.4.0",
63
63
  "@changesets/cli": "~2.29.8",
64
64
  vitest: "~4.0.18",
65
- // The seeded ui depends on `vue` (catalog:). `@platforma-sdk/ui-vue` pins
66
- // vue as an EXACT regular dependency (not a peer), so the block must pin the
67
- // SAME exact version — a floated `~` lets the ui resolve a newer 3.5.x than
68
- // ui-vue's, yielding two vue instances and a SdkPluginV3-vs-Plugin type
69
- // clash in `main.ts`. Keep this in lockstep with ui-vue's vue pin.
70
- vue: "3.5.24",
71
65
  };
72
66
 
67
+ /** Catalog entries whose exact version is DERIVED from the version another
68
+ * package declares for them (see `pinCatalogToDependencyOf`). Resolved on
69
+ * init + update-deps and OVERWRITES the on-disk entry.
70
+ *
71
+ * `vue`: the seeded ui depends on `vue` (catalog:). `@platforma-sdk/ui-vue`
72
+ * pins vue as an EXACT regular dependency (not a peer), so the block must
73
+ * pin the SAME exact version — a floated `~` lets the ui resolve a newer
74
+ * 3.5.x than ui-vue's, yielding two vue instances and a SdkPluginV3-vs-Plugin
75
+ * type clash in `main.ts`. Deriving the pin from ui-vue's declared dep keeps
76
+ * the block in lockstep with whatever vue ui-vue's npm-latest pins, with no
77
+ * hand-maintained version here. */
78
+ export const DERIVED_CATALOG_PINS: readonly DerivedCatalogPin[] = [
79
+ { entry: "vue", of: "@platforma-sdk/ui-vue" },
80
+ ];
81
+
73
82
  /** Catalog name of the python runenv. Added to a block's catalog only when
74
83
  * the block carries a software module. Pinned to an EXACT version — updating
75
84
  * the python runenv is an explicit author decision, never automatic. */
@@ -100,4 +109,11 @@ export function rootPnpmWorkspaceInitial(ctx: RunContext): Record<string, unknow
100
109
 
101
110
  export function rootPnpmWorkspaceRules(): void {
102
111
  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");
103
119
  }
@@ -16,6 +16,7 @@ import {
16
16
  ensurePeerDeps,
17
17
  ensureWorkspaceScopeDeps,
18
18
  removeDep,
19
+ removeScript,
19
20
  enforceAlphabeticalOrder,
20
21
  enforceFieldOrder,
21
22
  when,
@@ -38,8 +39,6 @@ export function uiPackageJsonInitial(ctx: RunContext): Record<string, unknown> {
38
39
  watch: "ts-builder build --target block-ui --watch",
39
40
  build: "ts-builder build --target block-ui",
40
41
  check: "ts-builder check --target block-ui",
41
- // No `test`: the vitest `test` script is wired by the body rule ONLY
42
- // when co-located test files exist (a freshly-init'd ui has none).
43
42
  },
44
43
  dependencies: {
45
44
  "@platforma-sdk/ui-vue": "sdk:",
@@ -51,7 +50,6 @@ export function uiPackageJsonInitial(ctx: RunContext): Record<string, unknown> {
51
50
  devDependencies: {
52
51
  "@milaboratories/ts-builder": "sdk:",
53
52
  "@milaboratories/ts-configs": "sdk:",
54
- vitest: "catalog:",
55
53
  },
56
54
  peerDependencies: {
57
55
  typescript: "*",
@@ -77,7 +75,6 @@ export function uiPackageJsonRules(): void {
77
75
  ensureDevDeps({
78
76
  "@milaboratories/ts-builder": "sdk:",
79
77
  "@milaboratories/ts-configs": "sdk:",
80
- vitest: "catalog:",
81
78
  });
82
79
 
83
80
  // `vue-tsc` is owned by `ts-builder` (which runs it internally for
@@ -87,6 +84,11 @@ export function uiPackageJsonRules(): void {
87
84
  // up type-checking under a different vue-tsc than the toolchain intends.
88
85
  removeDep("vue-tsc");
89
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");
90
+ removeScript("preview");
91
+
90
92
  // The ui builds with `--target block-ui` (types: []), so by default it
91
93
  // carries no browser/vitest/node ambient types — only the `typescript`
92
94
  // peer for IDE type resolution. Drop any stray `@types/node` a legacy
@@ -97,15 +99,27 @@ export function uiPackageJsonRules(): void {
97
99
  removeDep("@types/node");
98
100
 
99
101
  // ...but a ui WITH co-located unit tests (`src/**/*.test.ts`) needs the
100
- // vitest `test` script AND node ambient types: re-add `@types/node` as a
101
- // devDep so `types: ["node"]` in ui/tsconfig (wired under the same
102
- // predicate) resolves the tests' `node:*` imports. A test-less ui keeps
103
- // the lean default (no test script, no @types/node) and stays a fixpoint.
104
- // Runs AFTER removeDep so the dev dep is not stripped.
105
- when(whenFilesExist(COLOCATED_TEST_GLOB), () => {
106
- ensureScript("test", "vitest run --passWithNoTests");
107
- ensureDevDep("@types/node", "*");
108
- });
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.
107
+ //
108
+ // Skipped entirely for sdk-internal (in-monorepo) blocks: they own their test
109
+ // wiring under the monorepo's shared infrastructure — see model-package-json.
110
+ when(
111
+ ({ ctx }) => !ctx.isSdkInternal,
112
+ () =>
113
+ when(
114
+ whenFilesExist(COLOCATED_TEST_GLOB),
115
+ () => {
116
+ ensureScript("test", "vitest run --passWithNoTests");
117
+ ensureDevDep("vitest", "catalog:");
118
+ ensureDevDep("@types/node", "*");
119
+ },
120
+ () => removeDep("vitest"),
121
+ ),
122
+ );
109
123
 
110
124
  enforceAlphabeticalOrder("dependencies");
111
125
  enforceAlphabeticalOrder("devDependencies");
@@ -8,6 +8,7 @@ import {
8
8
  ensureScript,
9
9
  ensureDep,
10
10
  ensureDevDeps,
11
+ removeDep,
11
12
  ensureWorkspaceScopeDeps,
12
13
  enforceAlphabeticalOrder,
13
14
  enforceFieldOrder,
@@ -44,7 +45,8 @@ export function workflowPackageJsonInitial(ctx: RunContext): Record<string, unkn
44
45
  devDependencies: {
45
46
  "@platforma-sdk/tengo-builder": "sdk:",
46
47
  "@platforma-sdk/test": "sdk:",
47
- vitest: "catalog:",
48
+ // `vitest` is NOT seeded here — it's wired by the body rule only when the
49
+ // workflow carries co-located tests (a freshly-init'd workflow has none).
48
50
  shx: "catalog:",
49
51
  },
50
52
  };
@@ -59,15 +61,28 @@ export function workflowPackageJsonRules(): void {
59
61
  ensureScript("check", "pl-tengo check");
60
62
  // Tengo source formatter (emacs batch); no-op notice when emacs is absent.
61
63
  ensureScript("format", "/usr/bin/env emacs --script ./format.el || echo 'No emacs.'");
62
- // The vitest `test` script is wired ONLY when the workflow carries
63
- // co-located integration tests (`src/**/*.test.ts`, incl. `src/test/`).
64
- // A test-less workflow gets no `test` task and stays a refresh fixpoint.
65
- // (Workflow tests type-check via the standalone workflow/tsconfig with
66
- // `types: []` — they pull their types from `@platforma-sdk/test` — so no
67
- // node-types wiring is needed here, unlike model/ui.)
68
- when(whenFilesExist(COLOCATED_TEST_GLOB), () => {
69
- ensureScript("test", "vitest run --passWithNoTests");
70
- });
64
+ // The vitest `test` script AND the `vitest` devDep are wired ONLY when the
65
+ // workflow carries co-located integration tests (`src/**/*.test.ts`, incl.
66
+ // `src/test/`). A test-less workflow gets neither — no `test` task, no
67
+ // vitest dep — and stays a refresh fixpoint. (Workflow tests type-check via
68
+ // the standalone workflow/tsconfig with `types: []` — they pull their types
69
+ // from `@platforma-sdk/test` — so no node-types wiring is needed here,
70
+ // unlike model/ui.)
71
+ //
72
+ // Skipped entirely for sdk-internal (in-monorepo) blocks: they own their test
73
+ // wiring under the monorepo's shared infrastructure — see model-package-json.
74
+ when(
75
+ ({ ctx }) => !ctx.isSdkInternal,
76
+ () =>
77
+ when(
78
+ whenFilesExist(COLOCATED_TEST_GLOB),
79
+ () => {
80
+ ensureScript("test", "vitest run --passWithNoTests");
81
+ ensureDevDeps({ vitest: "catalog:" });
82
+ },
83
+ () => removeDep("vitest"),
84
+ ),
85
+ );
71
86
 
72
87
  ensureDep("@platforma-sdk/workflow-tengo", "sdk:");
73
88
 
@@ -80,7 +95,6 @@ export function workflowPackageJsonRules(): void {
80
95
  ensureDevDeps({
81
96
  "@platforma-sdk/tengo-builder": "sdk:",
82
97
  "@platforma-sdk/test": "sdk:",
83
- vitest: "catalog:",
84
98
  shx: "catalog:",
85
99
  });
86
100
 
@@ -11,10 +11,13 @@ import {
11
11
  tpl,
12
12
  generate,
13
13
  remove,
14
+ when,
15
+ whenFilesExist,
14
16
  blockVars,
15
17
  } from "../engine/api";
16
18
  import { getActiveRunContext } from "../engine/builders";
17
19
  import { workflowPackageJsonInitial, workflowPackageJsonRules } from "./workflow-package-json";
20
+ import { COLOCATED_TEST_GLOB } from "./shared/colocated-tests";
18
21
 
19
22
  export function workflowRules(): void {
20
23
  scope("workflow", () => {
@@ -24,8 +27,24 @@ export function workflowRules(): void {
24
27
  fixed("tsconfig.json", file("workflow/tsconfig.json"));
25
28
  // Tengo source formatter (emacs batch); the `format` script invokes it.
26
29
  fixed("format.el", file("workflow/format.el"));
27
- // scaffold (not fixed): tengo test config is author-tunable.
28
- scaffold("vitest.config.mts", file("workflow/vitest.config.mts"));
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.
34
+ //
35
+ // Skipped entirely for sdk-internal (in-monorepo) blocks: they own their
36
+ // test config under the monorepo's shared infrastructure (e.g. a bespoke
37
+ // `vitest run --coverage` + `createVitestConfig`), which the structurer
38
+ // must neither scaffold nor remove. See workflow-package-json.
39
+ when(
40
+ ({ ctx }) => !ctx.isSdkInternal,
41
+ () =>
42
+ when(
43
+ whenFilesExist(COLOCATED_TEST_GLOB),
44
+ () => scaffold("vitest.config.mts", file("workflow/vitest.config.mts")),
45
+ () => remove("vitest.config.mts"),
46
+ ),
47
+ );
29
48
  // No workflow facade (index.js / index.d.ts): the block loader resolves the
30
49
  // workflow via the `block:` components dist path (workflow/dist/.../main.plj.gz),
31
50
  // never the JS facade. It was orphaned in production — dropped. Actively