@platforma-sdk/block-tools 2.16.13 → 2.16.15

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.
@@ -1,8 +1,9 @@
1
+ import { RunContext } from '../engine/api';
1
2
  /** Seeded so the scaffold's own PR passes the `require-package-path-bump` gate
2
3
  * without bumping: `changeset version` consumes it and leaves the facade at
3
4
  * `INITIAL_MODULE_VERSION`, so the first version a user sees is 1.0.0 rather
4
5
  * than 1.0.1. Seeded (not managed) — a refresh must never resurrect it once
5
6
  * the first release has consumed it. */
6
7
  export declare const EMPTY_CHANGESET_SEED = "---\n---\n\nInitial release.\n";
7
- export declare function rootChangesetConfigInitial(): Record<string, unknown>;
8
- export declare function rootChangesetConfigRules(): void;
8
+ export declare function rootChangesetConfigInitial(ctx: RunContext): Record<string, unknown>;
9
+ export declare function rootChangesetConfigRules(ctx: RunContext): void;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@platforma-sdk/block-tools",
3
- "version": "2.16.13",
3
+ "version": "2.16.15",
4
4
  "description": "Utility to manipulate Platforma Blocks and Block Registry",
5
5
  "license": "UNLICENSED",
6
6
  "bin": {
@@ -36,12 +36,12 @@
36
36
  "zod": "~3.25.76",
37
37
  "@milaboratories/pl-http": "1.2.4",
38
38
  "@milaboratories/pl-model-backend": "1.4.36",
39
- "@milaboratories/pl-model-middle-layer": "1.34.2",
40
39
  "@milaboratories/pl-model-common": "1.53.0",
41
- "@milaboratories/ts-helpers": "1.8.6",
40
+ "@milaboratories/pl-model-middle-layer": "1.34.3",
42
41
  "@milaboratories/resolve-helper": "1.1.3",
43
42
  "@platforma-sdk/blocks-deps-updater": "2.2.0",
44
- "@platforma-sdk/package-builder-lib": "1.4.1"
43
+ "@platforma-sdk/package-builder-lib": "1.4.1",
44
+ "@milaboratories/ts-helpers": "1.8.6"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@rollup/plugin-node-resolve": "^16.0.1",
@@ -57,8 +57,8 @@
57
57
  "vite-plugin-dts": "^5.0.3",
58
58
  "vitest": "^4.1.3",
59
59
  "@milaboratories/build-configs": "2.0.2",
60
- "@milaboratories/ts-configs": "1.4.0",
61
- "@milaboratories/ts-builder": "1.7.2"
60
+ "@milaboratories/ts-builder": "1.7.2",
61
+ "@milaboratories/ts-configs": "1.4.0"
62
62
  },
63
63
  "scripts": {
64
64
  "build": "vite build",
@@ -19,6 +19,13 @@ const VARS: BlockVars = {
19
19
 
20
20
  const PATH = ".changeset/config.json";
21
21
 
22
+ const FIXED_GROUP = [
23
+ "@platforma-open/test-org.demo.block",
24
+ "@platforma-open/test-org.demo.model",
25
+ "@platforma-open/test-org.demo.ui",
26
+ "@platforma-open/test-org.demo.workflow",
27
+ ];
28
+
22
29
  function refresh(fs: MemoryFileSystem, isSdkInternal = false) {
23
30
  return engineRun(STRUCTURE, fs, discoverRunContext({ fs, isSdkInternal }), {
24
31
  templates: defaultTemplateProvider(),
@@ -65,6 +72,46 @@ describe("root .changeset/config.json", () => {
65
72
  expect(after.access).toBe("restricted");
66
73
  });
67
74
 
75
+ test("init fixes the facade to its model/ui/workflow siblings", () => {
76
+ const { fs } = simulateInit({ vars: VARS });
77
+ expect(JSON.parse(fs.read(PATH)).fixed).toEqual([FIXED_GROUP]);
78
+ });
79
+
80
+ test("refresh adds the group to a block that predates it", () => {
81
+ const { fs } = simulateInit({ vars: VARS });
82
+ fs.write(PATH, JSON.stringify({ ...JSON.parse(fs.read(PATH)), fixed: [] }, null, 2));
83
+
84
+ refresh(fs);
85
+ expect(JSON.parse(fs.read(PATH)).fixed).toEqual([FIXED_GROUP]);
86
+ });
87
+
88
+ test("refresh merges into the author group that overlaps and keeps the others", () => {
89
+ const { fs } = simulateInit({ vars: VARS });
90
+ const authored = {
91
+ ...JSON.parse(fs.read(PATH)),
92
+ fixed: [
93
+ ["@platforma-open/test-org.demo.software-a", "@platforma-open/test-org.demo.software-b"],
94
+ ["@platforma-open/test-org.demo.extra", "@platforma-open/test-org.demo.ui"],
95
+ ["@platforma-open/test-org.demo.model"],
96
+ ],
97
+ };
98
+ fs.write(PATH, JSON.stringify(authored, null, 2));
99
+
100
+ refresh(fs);
101
+ expect(JSON.parse(fs.read(PATH)).fixed).toEqual([
102
+ ["@platforma-open/test-org.demo.software-a", "@platforma-open/test-org.demo.software-b"],
103
+ [...FIXED_GROUP, "@platforma-open/test-org.demo.extra"],
104
+ ]);
105
+ });
106
+
107
+ test("refresh of a canonical config changes nothing", () => {
108
+ const { fs } = simulateInit({ vars: VARS });
109
+ const before = fs.read(PATH);
110
+
111
+ refresh(fs);
112
+ expect(fs.read(PATH)).toBe(before);
113
+ });
114
+
68
115
  test("sdk-internal blocks get no config — the monorepo owns it", () => {
69
116
  const { fs } = simulateInit({ vars: VARS, isSdkInternal: true });
70
117
  expect(fs.exists(PATH)).toBe(false);
@@ -5,9 +5,17 @@
5
5
  //
6
6
  // Managed, not fixed: `$schema` is whatever `changeset init` last wrote (seven
7
7
  // versions are in use across the blocks) and `fixed`/`linked`/`ignore` are
8
- // author-owned lists. Only the fields CI depends on are re-asserted.
8
+ // author-owned lists. Only the fields CI depends on are re-asserted, plus the
9
+ // block's own `fixed` group.
9
10
 
10
- import { ensureField, enforceFieldOrder } from "../engine/api";
11
+ import {
12
+ ensureField,
13
+ enforceFieldOrder,
14
+ transformAt,
15
+ type RunContext,
16
+ type Scope,
17
+ } from "../engine/api";
18
+ import { findModules } from "../engine/ctx";
11
19
 
12
20
  /** Seeded so the scaffold's own PR passes the `require-package-path-bump` gate
13
21
  * without bumping: `changeset version` consumes it and leaves the facade at
@@ -20,6 +28,33 @@ export const EMPTY_CHANGESET_SEED = `---
20
28
  Initial release.
21
29
  `;
22
30
 
31
+ export function rootChangesetConfigInitial(ctx: RunContext): Record<string, unknown> {
32
+ return {
33
+ $schema: "https://unpkg.com/@changesets/config@3.1.1/schema.json",
34
+ changelog: CHANGELOG,
35
+ commit: false,
36
+ fixed: [blockFixedGroup(ctx)],
37
+ linked: [],
38
+ access: ACCESS,
39
+ baseBranch: BASE_BRANCH,
40
+ updateInternalDependencies: UPDATE_INTERNAL_DEPENDENCIES,
41
+ ignore: [],
42
+ };
43
+ }
44
+
45
+ export function rootChangesetConfigRules(ctx: RunContext): void {
46
+ ensureField("changelog", CHANGELOG);
47
+ ensureField("commit", false);
48
+ ensureField("access", ACCESS);
49
+ ensureField("baseBranch", BASE_BRANCH);
50
+ ensureField("updateInternalDependencies", UPDATE_INTERNAL_DEPENDENCIES);
51
+ const group = blockFixedGroup(ctx);
52
+ transformAt<unknown>("fixed", (current) => withFixedGroup(current, group));
53
+ enforceFieldOrder(FIELD_ORDER);
54
+ }
55
+
56
+ // Internals
57
+
23
58
  const CHANGELOG = "@changesets/cli/changelog";
24
59
  const ACCESS = "restricted";
25
60
  const BASE_BRANCH = "main";
@@ -37,25 +72,35 @@ const FIELD_ORDER = [
37
72
  "ignore",
38
73
  ];
39
74
 
40
- export function rootChangesetConfigInitial(): Record<string, unknown> {
41
- return {
42
- $schema: "https://unpkg.com/@changesets/config@3.1.1/schema.json",
43
- changelog: CHANGELOG,
44
- commit: false,
45
- fixed: [],
46
- linked: [],
47
- access: ACCESS,
48
- baseBranch: BASE_BRANCH,
49
- updateInternalDependencies: UPDATE_INTERNAL_DEPENDENCIES,
50
- ignore: [],
51
- };
75
+ /** Packages released under one version. The facade lists its siblings only as
76
+ * devDependencies, and changesets never bumps a package for a devDependency
77
+ * release — without this group a model/ui/workflow change ships no new block.
78
+ * The kind and software stay out: they are runtime dependencies of the model
79
+ * and the workflow, so their bumps already reach the group. */
80
+ const FIXED_SCOPES: Scope[] = ["block", "model", "ui", "workflow"];
81
+
82
+ function blockFixedGroup(ctx: RunContext): string[] {
83
+ return FIXED_SCOPES.flatMap((scope) => findModules(ctx, scope).map((m) => m.name));
52
84
  }
53
85
 
54
- export function rootChangesetConfigRules(): void {
55
- ensureField("changelog", CHANGELOG);
56
- ensureField("commit", false);
57
- ensureField("access", ACCESS);
58
- ensureField("baseBranch", BASE_BRANCH);
59
- ensureField("updateInternalDependencies", UPDATE_INTERNAL_DEPENDENCIES);
60
- enforceFieldOrder(FIELD_ORDER);
86
+ /** Merges `group` into the first author group that shares a package with it,
87
+ * keeping that group's extra packages after the block's own; drops the
88
+ * block's packages from every other group, since changesets rejects a package
89
+ * listed in two fixed groups. Appends `group` when no author group overlaps. */
90
+ function withFixedGroup(current: unknown, group: string[]): string[][] {
91
+ const owned = new Set(group);
92
+ const groups = Array.isArray(current) ? current.filter(isStringArray) : [];
93
+ const hostIndex = groups.findIndex((g) => g.some((name) => owned.has(name)));
94
+ const result: string[][] = [];
95
+ groups.forEach((g, i) => {
96
+ const extras = g.filter((name) => !owned.has(name));
97
+ if (i === hostIndex) result.push([...group, ...extras]);
98
+ else if (extras.length > 0) result.push(extras);
99
+ });
100
+ if (hostIndex === -1) result.push(group);
101
+ return result;
102
+ }
103
+
104
+ function isStringArray(value: unknown): value is string[] {
105
+ return Array.isArray(value) && value.every((v) => typeof v === "string");
61
106
  }
@@ -50,9 +50,9 @@ export function rootRules(): void {
50
50
 
51
51
  managed(
52
52
  ".changeset/config.json",
53
- generate(() => rootChangesetConfigInitial()),
54
- () => {
55
- rootChangesetConfigRules();
53
+ generate((ctx) => rootChangesetConfigInitial(ctx)),
54
+ (ctx) => {
55
+ rootChangesetConfigRules(ctx);
56
56
  },
57
57
  );
58
58
  seed(".changeset/scaffold.md", text(EMPTY_CHANGESET_SEED));