@platforma-sdk/block-tools 2.10.14 → 2.10.16

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.
Files changed (169) hide show
  1. package/dist/cli.js +23 -2
  2. package/dist/cli.js.map +1 -1
  3. package/dist/cli.mjs +1944 -100
  4. package/dist/cli.mjs.map +1 -1
  5. package/dist/cmd/index.d.ts +10 -4
  6. package/dist/cmd/structure/check.d.ts +10 -0
  7. package/dist/cmd/structure/init.d.ts +18 -0
  8. package/dist/cmd/structure/refresh.d.ts +11 -0
  9. package/dist/cmd/update-deps.d.ts +7 -0
  10. package/dist/structure/cli/run-structure.d.ts +19 -0
  11. package/dist/structure/engine/api.d.ts +55 -0
  12. package/dist/structure/engine/builders.d.ts +95 -0
  13. package/dist/structure/engine/content-rules.d.ts +148 -0
  14. package/dist/structure/engine/ctx.d.ts +34 -0
  15. package/dist/structure/engine/discovery-fs.d.ts +22 -0
  16. package/dist/structure/engine/discovery.d.ts +39 -0
  17. package/dist/structure/engine/flatten.d.ts +3 -0
  18. package/dist/structure/engine/fs/api.d.ts +27 -0
  19. package/dist/structure/engine/fs/memory.d.ts +16 -0
  20. package/dist/structure/engine/fs/node.d.ts +14 -0
  21. package/dist/structure/engine/glob.d.ts +4 -0
  22. package/dist/structure/engine/ir.d.ts +124 -0
  23. package/dist/structure/engine/parsers/json.d.ts +37 -0
  24. package/dist/structure/engine/parsers/lines.d.ts +9 -0
  25. package/dist/structure/engine/parsers/yaml.d.ts +18 -0
  26. package/dist/structure/engine/registry-client.d.ts +34 -0
  27. package/dist/structure/engine/runner.d.ts +45 -0
  28. package/dist/structure/engine/templates.d.ts +30 -0
  29. package/dist/structure/engine/testing.d.ts +34 -0
  30. package/dist/structure/engine/version.d.ts +18 -0
  31. package/dist/structure/init-block-constructor.d.ts +32 -0
  32. package/dist/structure/rules/block-package-json.d.ts +9 -0
  33. package/dist/structure/rules/block.d.ts +1 -0
  34. package/dist/structure/rules/migrations.d.ts +2 -0
  35. package/dist/structure/rules/model-package-json.d.ts +3 -0
  36. package/dist/structure/rules/model.d.ts +1 -0
  37. package/dist/structure/rules/root-catalog-bump.d.ts +1 -0
  38. package/dist/structure/rules/root-gitignore.d.ts +2 -0
  39. package/dist/structure/rules/root-package-json.d.ts +3 -0
  40. package/dist/structure/rules/root-pnpm-workspace.d.ts +15 -0
  41. package/dist/structure/rules/root.d.ts +1 -0
  42. package/dist/structure/rules/shared/colocated-tests.d.ts +2 -0
  43. package/dist/structure/rules/shared/key-order.d.ts +1 -0
  44. package/dist/structure/rules/software-package-json.d.ts +3 -0
  45. package/dist/structure/rules/software.d.ts +1 -0
  46. package/dist/structure/rules/test-package-json.d.ts +3 -0
  47. package/dist/structure/rules/test.d.ts +1 -0
  48. package/dist/structure/rules/ui-package-json.d.ts +3 -0
  49. package/dist/structure/rules/ui.d.ts +1 -0
  50. package/dist/structure/rules/workflow-package-json.d.ts +3 -0
  51. package/dist/structure/rules/workflow.d.ts +1 -0
  52. package/dist/structure/structure-definition.d.ts +1 -0
  53. package/package.json +9 -7
  54. package/src/cmd/index.ts +10 -4
  55. package/src/cmd/structure/check.ts +51 -0
  56. package/src/cmd/structure/init.ts +65 -0
  57. package/src/cmd/structure/refresh.ts +44 -0
  58. package/src/cmd/update-deps.ts +15 -3
  59. package/src/structure/__tests__/colocated-test-wiring.test.ts +107 -0
  60. package/src/structure/__tests__/floor-version.test.ts +52 -0
  61. package/src/structure/__tests__/init-catalog-resolution.test.ts +82 -0
  62. package/src/structure/__tests__/init-check-parity.test.ts +59 -0
  63. package/src/structure/__tests__/model-package-json.snapshot.test.ts +60 -0
  64. package/src/structure/__tests__/oxfmt-clean-init.test.ts +64 -0
  65. package/src/structure/__tests__/root-catalog-bump.test.ts +110 -0
  66. package/src/structure/__tests__/seed-disjointness.test.ts +79 -0
  67. package/src/structure/cli/run-structure.ts +89 -0
  68. package/src/structure/engine/__tests__/content-rules/active-state-guards.test.ts +61 -0
  69. package/src/structure/engine/__tests__/content-rules/catalog-pin.test.ts +46 -0
  70. package/src/structure/engine/__tests__/content-rules/enforce-alphabetical-order.test.ts +55 -0
  71. package/src/structure/engine/__tests__/content-rules/enforce-field-order.test.ts +73 -0
  72. package/src/structure/engine/__tests__/content-rules/ensure-catalog-absent.test.ts +29 -0
  73. package/src/structure/engine/__tests__/content-rules/ensure-catalog-latest.test.ts +70 -0
  74. package/src/structure/engine/__tests__/content-rules/ensure-dep.test.ts +63 -0
  75. package/src/structure/engine/__tests__/content-rules/ensure-deps-bulk.test.ts +46 -0
  76. package/src/structure/engine/__tests__/content-rules/ensure-field-entries.test.ts +35 -0
  77. package/src/structure/engine/__tests__/content-rules/ensure-field.test.ts +56 -0
  78. package/src/structure/engine/__tests__/content-rules/ensure-script.test.ts +39 -0
  79. package/src/structure/engine/__tests__/content-rules/ensure-workspace-scope-deps.test.ts +92 -0
  80. package/src/structure/engine/__tests__/content-rules/gitignore.test.ts +50 -0
  81. package/src/structure/engine/__tests__/content-rules/pin-catalog-to.test.ts +64 -0
  82. package/src/structure/engine/__tests__/content-rules/prune-keys.test.ts +59 -0
  83. package/src/structure/engine/__tests__/content-rules/registry-client.test.ts +116 -0
  84. package/src/structure/engine/__tests__/content-rules/remove-field.test.ts +49 -0
  85. package/src/structure/engine/__tests__/content-rules/require-field.test.ts +40 -0
  86. package/src/structure/engine/__tests__/content-rules/transform-at.test.ts +33 -0
  87. package/src/structure/engine/__tests__/content-rules/when-inner.test.ts +244 -0
  88. package/src/structure/engine/__tests__/content-rules/workspace-module-paths.test.ts +53 -0
  89. package/src/structure/engine/__tests__/discovery.test.ts +160 -0
  90. package/src/structure/engine/__tests__/fs-memory.test.ts +59 -0
  91. package/src/structure/engine/__tests__/glob.test.ts +43 -0
  92. package/src/structure/engine/__tests__/parsers-json.test.ts +189 -0
  93. package/src/structure/engine/__tests__/parsers-lines.test.ts +44 -0
  94. package/src/structure/engine/__tests__/parsers-yaml.test.ts +90 -0
  95. package/src/structure/engine/__tests__/recheck.test.ts +99 -0
  96. package/src/structure/engine/__tests__/registry-lookup.test.ts +49 -0
  97. package/src/structure/engine/__tests__/runner-when-inside-managed.test.ts +136 -0
  98. package/src/structure/engine/__tests__/runner.test.ts +136 -0
  99. package/src/structure/engine/__tests__/synthetic.test.ts +153 -0
  100. package/src/structure/engine/__tests__/version.test.ts +44 -0
  101. package/src/structure/engine/__tests__/when-files-exist.test.ts +89 -0
  102. package/src/structure/engine/api.ts +131 -0
  103. package/src/structure/engine/builders.ts +341 -0
  104. package/src/structure/engine/content-rules.ts +616 -0
  105. package/src/structure/engine/ctx.ts +94 -0
  106. package/src/structure/engine/discovery-fs.ts +209 -0
  107. package/src/structure/engine/discovery.ts +168 -0
  108. package/src/structure/engine/flatten.ts +117 -0
  109. package/src/structure/engine/fs/api.ts +40 -0
  110. package/src/structure/engine/fs/memory.ts +132 -0
  111. package/src/structure/engine/fs/node.ts +89 -0
  112. package/src/structure/engine/glob.ts +42 -0
  113. package/src/structure/engine/ir.ts +149 -0
  114. package/src/structure/engine/parsers/json.ts +212 -0
  115. package/src/structure/engine/parsers/lines.ts +42 -0
  116. package/src/structure/engine/parsers/yaml.ts +72 -0
  117. package/src/structure/engine/registry-client.ts +140 -0
  118. package/src/structure/engine/runner.ts +519 -0
  119. package/src/structure/engine/templates.ts +74 -0
  120. package/src/structure/engine/testing.ts +93 -0
  121. package/src/structure/engine/version.ts +60 -0
  122. package/src/structure/init-block-constructor.ts +164 -0
  123. package/src/structure/rules/block-package-json.ts +156 -0
  124. package/src/structure/rules/block.ts +29 -0
  125. package/src/structure/rules/migrations.ts +63 -0
  126. package/src/structure/rules/model-package-json.ts +123 -0
  127. package/src/structure/rules/model.ts +65 -0
  128. package/src/structure/rules/root-catalog-bump.ts +77 -0
  129. package/src/structure/rules/root-gitignore.ts +27 -0
  130. package/src/structure/rules/root-package-json.ts +119 -0
  131. package/src/structure/rules/root-pnpm-workspace.ts +103 -0
  132. package/src/structure/rules/root.ts +43 -0
  133. package/src/structure/rules/shared/colocated-tests.ts +11 -0
  134. package/src/structure/rules/shared/key-order.ts +34 -0
  135. package/src/structure/rules/software-package-json.ts +86 -0
  136. package/src/structure/rules/software.ts +33 -0
  137. package/src/structure/rules/test-package-json.ts +70 -0
  138. package/src/structure/rules/test.ts +40 -0
  139. package/src/structure/rules/ui-package-json.ts +108 -0
  140. package/src/structure/rules/ui.ts +75 -0
  141. package/src/structure/rules/workflow-package-json.ts +92 -0
  142. package/src/structure/rules/workflow.ts +51 -0
  143. package/src/structure/structure-definition.ts +28 -0
  144. package/src/structure/templates/static/block/index.d.ts +6 -0
  145. package/src/structure/templates/static/block/index.js +8 -0
  146. package/src/structure/templates/static/block/logos/block-logo.png +0 -0
  147. package/src/structure/templates/static/block/logos/organization-logo.png +0 -0
  148. package/src/structure/templates/static/model/.oxfmtrc.json +4 -0
  149. package/src/structure/templates/static/model/.oxlintrc.json +3 -0
  150. package/src/structure/templates/static/model/src/index.ts +13 -0
  151. package/src/structure/templates/static/model/tsconfig.json +4 -0
  152. package/src/structure/templates/static/root/.gitignore +13 -0
  153. package/src/structure/templates/static/root/.vscode/settings.json +3 -0
  154. package/src/structure/templates/static/root/turbo.json +35 -0
  155. package/src/structure/templates/static/test/tsconfig.json +5 -0
  156. package/src/structure/templates/static/test/vitest.config.mts +8 -0
  157. package/src/structure/templates/static/ui/.oxfmtrc.json +3 -0
  158. package/src/structure/templates/static/ui/.oxlintrc.json +3 -0
  159. package/src/structure/templates/static/ui/index.html +12 -0
  160. package/src/structure/templates/static/ui/src/main.ts +5 -0
  161. package/src/structure/templates/static/ui/tsconfig.json +4 -0
  162. package/src/structure/templates/static/workflow/format.el +42 -0
  163. package/src/structure/templates/static/workflow/tsconfig.json +16 -0
  164. package/src/structure/templates/static/workflow/vitest.config.mts +9 -0
  165. package/src/structure/templates/text/README.md +5 -0
  166. package/src/structure/templates/text/docs/description.md +3 -0
  167. package/src/structure/templates/text/ui/src/MainPage.tpl.vue +9 -0
  168. package/src/structure/templates/text/ui/src/app.tpl.ts +11 -0
  169. package/src/structure/templates/text/workflow/src/main.tpl.tengo +10 -0
@@ -0,0 +1,72 @@
1
+ // YAML parser + serialiser, comment-preserving via the `yaml` lib's
2
+ // Document API (CST-preserving). Wraps `parseDocument` + `Document.toString`.
3
+ // Helpers (`yamlGet`, `yamlSet`, `yamlHas`, `yamlDelete`) operate on the
4
+ // Document by jsonPath-style addresses, matching the JSON parser's API.
5
+ // Comments attached to map entries survive set/delete operations as long
6
+ // as the affected nodes are mutated in place (not reassigned wholesale).
7
+
8
+ import {
9
+ Document,
10
+ isMap,
11
+ isPair,
12
+ isSeq,
13
+ parseDocument,
14
+ YAMLMap,
15
+ YAMLSeq,
16
+ Scalar,
17
+ Node,
18
+ } from "yaml";
19
+
20
+ export type YamlDocument = Document.Parsed;
21
+
22
+ /** Parse YAML into a CST-preserving Document. */
23
+ export function parseYaml(raw: string): YamlDocument {
24
+ return parseDocument(raw);
25
+ }
26
+
27
+ /** Serialise back to string. Preserves comments + ordering of unchanged
28
+ * nodes per the `yaml` library's contract. */
29
+ export function stringifyYaml(doc: YamlDocument): string {
30
+ return doc.toString();
31
+ }
32
+
33
+ function splitPath(jsonPath: string): string[] {
34
+ if (jsonPath === "" || jsonPath === undefined) return [];
35
+ return jsonPath.split(".");
36
+ }
37
+
38
+ /** Get the JS value at the given jsonPath in the document. */
39
+ export function yamlGet(doc: YamlDocument, jsonPath: string): unknown {
40
+ const parts = splitPath(jsonPath);
41
+ if (parts.length === 0) return doc.toJS();
42
+ return doc.getIn(parts, false) as unknown;
43
+ }
44
+
45
+ export function yamlHas(doc: YamlDocument, jsonPath: string): boolean {
46
+ const parts = splitPath(jsonPath);
47
+ if (parts.length === 0) return true;
48
+ return doc.hasIn(parts);
49
+ }
50
+
51
+ /** Set a value at jsonPath. Auto-creates intermediate maps. Existing
52
+ * comments on parent map entries are preserved by the yaml library. */
53
+ export function yamlSet(doc: YamlDocument, jsonPath: string, value: unknown): void {
54
+ const parts = splitPath(jsonPath);
55
+ if (parts.length === 0) {
56
+ throw new Error("yamlSet: jsonPath must be non-empty");
57
+ }
58
+ doc.setIn(parts, value);
59
+ }
60
+
61
+ /** Delete a value at jsonPath. No-op if missing. */
62
+ export function yamlDelete(doc: YamlDocument, jsonPath: string): void {
63
+ const parts = splitPath(jsonPath);
64
+ if (parts.length === 0) {
65
+ throw new Error("yamlDelete: jsonPath must be non-empty");
66
+ }
67
+ doc.deleteIn(parts);
68
+ }
69
+
70
+ /** Re-export selected `yaml` lib types for downstream content-rule builders. */
71
+ export { isMap, isPair, isSeq, YAMLMap, YAMLSeq, Scalar };
72
+ export type { Node };
@@ -0,0 +1,140 @@
1
+ // npm registry client used by the catalog ensure-family (`ensureCatalogLatest`).
2
+ //
3
+ // The content-rule builder is synchronous; the runner pre-resolves
4
+ // "latest" versions via this client and passes a sync lookup function
5
+ // to `withManagedYaml(..., { getLatestVersion })`. The real impl talks
6
+ // to https://registry.npmjs.org with retry + Retry-After handling
7
+ // ported from `tools/blocks-deps-updater/src/updater.ts`. The mock
8
+ // impl wraps an in-memory map and is the only client used in unit
9
+ // tests.
10
+
11
+ import { setTimeout as sleep } from "node:timers/promises";
12
+
13
+ export interface RegistryClient {
14
+ getLatestVersion(packageName: string): Promise<string>;
15
+ }
16
+
17
+ const RETRY_COUNT = 2;
18
+ const RETRY_BASE_MS = 500;
19
+ const TIMEOUT_MS = 30_000;
20
+
21
+ /** Parse the HTTP Retry-After header (RFC 9110): either a delay in
22
+ * seconds or an absolute HTTP-date. Returns the delay in ms, or null
23
+ * if the header is missing / unparseable. */
24
+ export function parseRetryAfter(header: string | null): number | null {
25
+ if (!header) return null;
26
+ const seconds = Number(header);
27
+ if (Number.isFinite(seconds) && seconds > 0) return seconds * 1000;
28
+ const date = Date.parse(header);
29
+ if (!Number.isNaN(date)) return Math.max(0, date - Date.now());
30
+ return null;
31
+ }
32
+
33
+ async function fetchWithRetry(url: string): Promise<Response> {
34
+ for (let attempt = 1; ; attempt++) {
35
+ let res: Response;
36
+ // Only the network call is retry-eligible: a transport error
37
+ // (timeout, DNS, reset) is transient. HTTP-status handling sits
38
+ // OUTSIDE this catch so a non-retryable status (404/403) throws
39
+ // immediately instead of being swallowed and retried.
40
+ try {
41
+ res = await fetch(url, { signal: AbortSignal.timeout(TIMEOUT_MS) });
42
+ } catch (err) {
43
+ if (attempt > RETRY_COUNT) throw err;
44
+ const delay = RETRY_BASE_MS * 2 ** (attempt - 1) * (0.8 + 0.4 * Math.random());
45
+ await sleep(delay);
46
+ continue;
47
+ }
48
+ if (res.ok) return res;
49
+ const retryable = res.status === 429 || res.status >= 500;
50
+ if (!retryable || attempt > RETRY_COUNT) {
51
+ throw new Error(`registry returned HTTP ${res.status}`);
52
+ }
53
+ const retryAfterMs = parseRetryAfter(res.headers.get("retry-after"));
54
+ if (retryAfterMs != null) {
55
+ await sleep(retryAfterMs);
56
+ continue;
57
+ }
58
+ const delay = RETRY_BASE_MS * 2 ** (attempt - 1) * (0.8 + 0.4 * Math.random());
59
+ await sleep(delay);
60
+ }
61
+ }
62
+
63
+ /** Live npm registry client. Hits the network on each call. */
64
+ export function createRealRegistryClient(): RegistryClient {
65
+ return {
66
+ async getLatestVersion(packageName: string): Promise<string> {
67
+ const res = await fetchWithRetry(
68
+ `https://registry.npmjs.org/-/package/${packageName}/dist-tags`,
69
+ );
70
+ const tags = (await res.json()) as Record<string, string>;
71
+ const latest = tags.latest;
72
+ if (!latest) {
73
+ throw new Error("no 'latest' dist-tag in registry response");
74
+ }
75
+ return latest;
76
+ },
77
+ };
78
+ }
79
+
80
+ /** In-memory client backed by a fixed `name → version` map. */
81
+ export function createMockRegistryClient(versions: Record<string, string>): RegistryClient {
82
+ return {
83
+ async getLatestVersion(packageName: string): Promise<string> {
84
+ const v = versions[packageName];
85
+ if (v === undefined) {
86
+ throw new Error(`mock registry: no version configured for '${packageName}'`);
87
+ }
88
+ return v;
89
+ },
90
+ };
91
+ }
92
+
93
+ /** Resolve a batch of `name → latest` entries in parallel. */
94
+ export async function prefetchLatestVersions(
95
+ client: RegistryClient,
96
+ packageNames: readonly string[],
97
+ ): Promise<Map<string, string>> {
98
+ const entries = await Promise.all(
99
+ packageNames.map(async (n) => [n, await client.getLatestVersion(n)] as const),
100
+ );
101
+ return new Map(entries);
102
+ }
103
+
104
+ /** Build a sync lookup function (the shape `withManagedYaml` consumes)
105
+ * from a prefetched map. Returns undefined for unknown names. */
106
+ export function makeSyncLookup(
107
+ resolved: Map<string, string>,
108
+ ): (packageName: string) => string | undefined {
109
+ return (name) => resolved.get(name);
110
+ }
111
+
112
+ /** Catalog package-name patterns the version-resolution rules
113
+ * (`ensureCatalogLatest`) match against — the `@platforma-sdk/*` and
114
+ * `@milaboratories/*` SDK families. Infra/runtime entries (turbo, shx,
115
+ * …) are deliberately NOT here: they stay a curated floor, not auto-latest.
116
+ * Shared so `init` (names from the SDK pin map) and `refresh
117
+ * --update-deps-only` (names from the on-disk catalog) select the same
118
+ * set. */
119
+ export const CATALOG_BUMP_PATTERNS: readonly RegExp[] = [/^@platforma-sdk\//, /^@milaboratories\//];
120
+
121
+ /** True if `name` is a version-resolved SDK package (matches any bump
122
+ * pattern). */
123
+ export function matchesBumpPattern(name: string): boolean {
124
+ return CATALOG_BUMP_PATTERNS.some((p) => p.test(name));
125
+ }
126
+
127
+ /** Prefetch npm "latest" for `names` and return the sync lookup the
128
+ * runner passes to the catalog ensure-family (`ensureCatalogLatest`).
129
+ * Empty list → a lookup that
130
+ * resolves nothing (no network). A network/registry failure REJECTS
131
+ * (callers that require the network — `init` — let it propagate).
132
+ * `client` defaults to the live npm client; tests inject a mock. */
133
+ export async function buildRegistryLookupForNames(
134
+ names: readonly string[],
135
+ client: RegistryClient = createRealRegistryClient(),
136
+ ): Promise<(packageName: string) => string | undefined> {
137
+ if (names.length === 0) return () => undefined;
138
+ const resolved = await prefetchLatestVersions(client, names);
139
+ return makeSyncLookup(resolved);
140
+ }