@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.
- package/dist/cli.js +23 -2
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +1944 -100
- package/dist/cli.mjs.map +1 -1
- package/dist/cmd/index.d.ts +10 -4
- package/dist/cmd/structure/check.d.ts +10 -0
- package/dist/cmd/structure/init.d.ts +18 -0
- package/dist/cmd/structure/refresh.d.ts +11 -0
- package/dist/cmd/update-deps.d.ts +7 -0
- package/dist/structure/cli/run-structure.d.ts +19 -0
- package/dist/structure/engine/api.d.ts +55 -0
- package/dist/structure/engine/builders.d.ts +95 -0
- package/dist/structure/engine/content-rules.d.ts +148 -0
- package/dist/structure/engine/ctx.d.ts +34 -0
- package/dist/structure/engine/discovery-fs.d.ts +22 -0
- package/dist/structure/engine/discovery.d.ts +39 -0
- package/dist/structure/engine/flatten.d.ts +3 -0
- package/dist/structure/engine/fs/api.d.ts +27 -0
- package/dist/structure/engine/fs/memory.d.ts +16 -0
- package/dist/structure/engine/fs/node.d.ts +14 -0
- package/dist/structure/engine/glob.d.ts +4 -0
- package/dist/structure/engine/ir.d.ts +124 -0
- package/dist/structure/engine/parsers/json.d.ts +37 -0
- package/dist/structure/engine/parsers/lines.d.ts +9 -0
- package/dist/structure/engine/parsers/yaml.d.ts +18 -0
- package/dist/structure/engine/registry-client.d.ts +34 -0
- package/dist/structure/engine/runner.d.ts +45 -0
- package/dist/structure/engine/templates.d.ts +30 -0
- package/dist/structure/engine/testing.d.ts +34 -0
- package/dist/structure/engine/version.d.ts +18 -0
- package/dist/structure/init-block-constructor.d.ts +32 -0
- package/dist/structure/rules/block-package-json.d.ts +9 -0
- package/dist/structure/rules/block.d.ts +1 -0
- package/dist/structure/rules/migrations.d.ts +2 -0
- package/dist/structure/rules/model-package-json.d.ts +3 -0
- package/dist/structure/rules/model.d.ts +1 -0
- package/dist/structure/rules/root-catalog-bump.d.ts +1 -0
- package/dist/structure/rules/root-gitignore.d.ts +2 -0
- package/dist/structure/rules/root-package-json.d.ts +3 -0
- package/dist/structure/rules/root-pnpm-workspace.d.ts +15 -0
- package/dist/structure/rules/root.d.ts +1 -0
- package/dist/structure/rules/shared/colocated-tests.d.ts +2 -0
- package/dist/structure/rules/shared/key-order.d.ts +1 -0
- package/dist/structure/rules/software-package-json.d.ts +3 -0
- package/dist/structure/rules/software.d.ts +1 -0
- package/dist/structure/rules/test-package-json.d.ts +3 -0
- package/dist/structure/rules/test.d.ts +1 -0
- package/dist/structure/rules/ui-package-json.d.ts +3 -0
- package/dist/structure/rules/ui.d.ts +1 -0
- package/dist/structure/rules/workflow-package-json.d.ts +3 -0
- package/dist/structure/rules/workflow.d.ts +1 -0
- package/dist/structure/structure-definition.d.ts +1 -0
- package/package.json +9 -7
- package/src/cmd/index.ts +10 -4
- package/src/cmd/structure/check.ts +51 -0
- package/src/cmd/structure/init.ts +65 -0
- package/src/cmd/structure/refresh.ts +44 -0
- package/src/cmd/update-deps.ts +15 -3
- package/src/structure/__tests__/colocated-test-wiring.test.ts +107 -0
- package/src/structure/__tests__/floor-version.test.ts +52 -0
- package/src/structure/__tests__/init-catalog-resolution.test.ts +82 -0
- package/src/structure/__tests__/init-check-parity.test.ts +59 -0
- package/src/structure/__tests__/model-package-json.snapshot.test.ts +60 -0
- package/src/structure/__tests__/oxfmt-clean-init.test.ts +64 -0
- package/src/structure/__tests__/root-catalog-bump.test.ts +110 -0
- package/src/structure/__tests__/seed-disjointness.test.ts +79 -0
- package/src/structure/cli/run-structure.ts +89 -0
- package/src/structure/engine/__tests__/content-rules/active-state-guards.test.ts +61 -0
- package/src/structure/engine/__tests__/content-rules/catalog-pin.test.ts +46 -0
- package/src/structure/engine/__tests__/content-rules/enforce-alphabetical-order.test.ts +55 -0
- package/src/structure/engine/__tests__/content-rules/enforce-field-order.test.ts +73 -0
- package/src/structure/engine/__tests__/content-rules/ensure-catalog-absent.test.ts +29 -0
- package/src/structure/engine/__tests__/content-rules/ensure-catalog-latest.test.ts +70 -0
- package/src/structure/engine/__tests__/content-rules/ensure-dep.test.ts +63 -0
- package/src/structure/engine/__tests__/content-rules/ensure-deps-bulk.test.ts +46 -0
- package/src/structure/engine/__tests__/content-rules/ensure-field-entries.test.ts +35 -0
- package/src/structure/engine/__tests__/content-rules/ensure-field.test.ts +56 -0
- package/src/structure/engine/__tests__/content-rules/ensure-script.test.ts +39 -0
- package/src/structure/engine/__tests__/content-rules/ensure-workspace-scope-deps.test.ts +92 -0
- package/src/structure/engine/__tests__/content-rules/gitignore.test.ts +50 -0
- package/src/structure/engine/__tests__/content-rules/pin-catalog-to.test.ts +64 -0
- package/src/structure/engine/__tests__/content-rules/prune-keys.test.ts +59 -0
- package/src/structure/engine/__tests__/content-rules/registry-client.test.ts +116 -0
- package/src/structure/engine/__tests__/content-rules/remove-field.test.ts +49 -0
- package/src/structure/engine/__tests__/content-rules/require-field.test.ts +40 -0
- package/src/structure/engine/__tests__/content-rules/transform-at.test.ts +33 -0
- package/src/structure/engine/__tests__/content-rules/when-inner.test.ts +244 -0
- package/src/structure/engine/__tests__/content-rules/workspace-module-paths.test.ts +53 -0
- package/src/structure/engine/__tests__/discovery.test.ts +160 -0
- package/src/structure/engine/__tests__/fs-memory.test.ts +59 -0
- package/src/structure/engine/__tests__/glob.test.ts +43 -0
- package/src/structure/engine/__tests__/parsers-json.test.ts +189 -0
- package/src/structure/engine/__tests__/parsers-lines.test.ts +44 -0
- package/src/structure/engine/__tests__/parsers-yaml.test.ts +90 -0
- package/src/structure/engine/__tests__/recheck.test.ts +99 -0
- package/src/structure/engine/__tests__/registry-lookup.test.ts +49 -0
- package/src/structure/engine/__tests__/runner-when-inside-managed.test.ts +136 -0
- package/src/structure/engine/__tests__/runner.test.ts +136 -0
- package/src/structure/engine/__tests__/synthetic.test.ts +153 -0
- package/src/structure/engine/__tests__/version.test.ts +44 -0
- package/src/structure/engine/__tests__/when-files-exist.test.ts +89 -0
- package/src/structure/engine/api.ts +131 -0
- package/src/structure/engine/builders.ts +341 -0
- package/src/structure/engine/content-rules.ts +616 -0
- package/src/structure/engine/ctx.ts +94 -0
- package/src/structure/engine/discovery-fs.ts +209 -0
- package/src/structure/engine/discovery.ts +168 -0
- package/src/structure/engine/flatten.ts +117 -0
- package/src/structure/engine/fs/api.ts +40 -0
- package/src/structure/engine/fs/memory.ts +132 -0
- package/src/structure/engine/fs/node.ts +89 -0
- package/src/structure/engine/glob.ts +42 -0
- package/src/structure/engine/ir.ts +149 -0
- package/src/structure/engine/parsers/json.ts +212 -0
- package/src/structure/engine/parsers/lines.ts +42 -0
- package/src/structure/engine/parsers/yaml.ts +72 -0
- package/src/structure/engine/registry-client.ts +140 -0
- package/src/structure/engine/runner.ts +519 -0
- package/src/structure/engine/templates.ts +74 -0
- package/src/structure/engine/testing.ts +93 -0
- package/src/structure/engine/version.ts +60 -0
- package/src/structure/init-block-constructor.ts +164 -0
- package/src/structure/rules/block-package-json.ts +156 -0
- package/src/structure/rules/block.ts +29 -0
- package/src/structure/rules/migrations.ts +63 -0
- package/src/structure/rules/model-package-json.ts +123 -0
- package/src/structure/rules/model.ts +65 -0
- package/src/structure/rules/root-catalog-bump.ts +77 -0
- package/src/structure/rules/root-gitignore.ts +27 -0
- package/src/structure/rules/root-package-json.ts +119 -0
- package/src/structure/rules/root-pnpm-workspace.ts +103 -0
- package/src/structure/rules/root.ts +43 -0
- package/src/structure/rules/shared/colocated-tests.ts +11 -0
- package/src/structure/rules/shared/key-order.ts +34 -0
- package/src/structure/rules/software-package-json.ts +86 -0
- package/src/structure/rules/software.ts +33 -0
- package/src/structure/rules/test-package-json.ts +70 -0
- package/src/structure/rules/test.ts +40 -0
- package/src/structure/rules/ui-package-json.ts +108 -0
- package/src/structure/rules/ui.ts +75 -0
- package/src/structure/rules/workflow-package-json.ts +92 -0
- package/src/structure/rules/workflow.ts +51 -0
- package/src/structure/structure-definition.ts +28 -0
- package/src/structure/templates/static/block/index.d.ts +6 -0
- package/src/structure/templates/static/block/index.js +8 -0
- package/src/structure/templates/static/block/logos/block-logo.png +0 -0
- package/src/structure/templates/static/block/logos/organization-logo.png +0 -0
- package/src/structure/templates/static/model/.oxfmtrc.json +4 -0
- package/src/structure/templates/static/model/.oxlintrc.json +3 -0
- package/src/structure/templates/static/model/src/index.ts +13 -0
- package/src/structure/templates/static/model/tsconfig.json +4 -0
- package/src/structure/templates/static/root/.gitignore +13 -0
- package/src/structure/templates/static/root/.vscode/settings.json +3 -0
- package/src/structure/templates/static/root/turbo.json +35 -0
- package/src/structure/templates/static/test/tsconfig.json +5 -0
- package/src/structure/templates/static/test/vitest.config.mts +8 -0
- package/src/structure/templates/static/ui/.oxfmtrc.json +3 -0
- package/src/structure/templates/static/ui/.oxlintrc.json +3 -0
- package/src/structure/templates/static/ui/index.html +12 -0
- package/src/structure/templates/static/ui/src/main.ts +5 -0
- package/src/structure/templates/static/ui/tsconfig.json +4 -0
- package/src/structure/templates/static/workflow/format.el +42 -0
- package/src/structure/templates/static/workflow/tsconfig.json +16 -0
- package/src/structure/templates/static/workflow/vitest.config.mts +9 -0
- package/src/structure/templates/text/README.md +5 -0
- package/src/structure/templates/text/docs/description.md +3 -0
- package/src/structure/templates/text/ui/src/MainPage.tpl.vue +9 -0
- package/src/structure/templates/text/ui/src/app.tpl.ts +11 -0
- 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
|
+
}
|