@platforma-sdk/block-tools 2.11.3 → 2.11.5
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 +13 -13
- package/dist/cli.js.map +1 -1
- package/dist/cli.mjs +634 -580
- package/dist/cli.mjs.map +1 -1
- package/dist/config-BmJWc8sR.js +3 -0
- package/dist/config-BmJWc8sR.js.map +1 -0
- package/dist/{config-DpfTzcgG.mjs → config-CiC347sB.mjs} +453 -398
- package/dist/config-CiC347sB.mjs.map +1 -0
- package/dist/index.js +1 -1
- package/dist/index.mjs +15 -15
- package/dist/structure/engine/discovery.d.ts +2 -3
- package/dist/structure/rules/block-package-json.d.ts +3 -3
- package/dist/structure/rules/shared/pascal-case.d.ts +1 -0
- package/dist/v2/index.d.ts +1 -0
- package/dist/v2/model/block_components.d.ts +11 -0
- package/dist/v2/model/block_meta.d.ts +7 -0
- package/dist/v2/registry/schema_public.d.ts +3600 -3600
- package/dist/v2/resolve_to_registry.d.ts +37 -0
- package/dist/v2/source_package.d.ts +12 -0
- package/package.json +8 -8
- package/src/cmd/publish.test.ts +35 -0
- package/src/cmd/publish.ts +20 -0
- package/src/structure/__tests__/discovery-shortname.test.ts +3 -0
- package/src/structure/__tests__/facade-end-state.test.ts +195 -0
- package/src/structure/__tests__/model-package-json.snapshot.test.ts +1 -1
- package/src/structure/engine/__tests__/discovery.test.ts +22 -26
- package/src/structure/engine/discovery.ts +12 -30
- package/src/structure/rules/block-package-json.ts +146 -64
- package/src/structure/rules/block.ts +40 -5
- package/src/structure/rules/model-package-json.ts +6 -1
- package/src/structure/rules/shared/pascal-case.ts +16 -0
- package/src/structure/rules/software-package-json.ts +6 -1
- package/src/structure/rules/test-package-json.ts +5 -1
- package/src/structure/rules/ui-package-json.ts +5 -1
- package/src/structure/rules/workflow-package-json.ts +5 -1
- package/src/structure/templates/static/block/src/AGENTS.ts +5 -0
- package/src/structure/templates/static/block/src/agents-extra.ts +8 -0
- package/src/structure/templates/static/block/src/block-extra.ts +9 -0
- package/src/structure/templates/static/block/tsconfig.json +4 -0
- package/src/structure/templates/text/block/src/index.tpl.ts +55 -0
- package/src/v2/from_pack_v2.test.ts +142 -0
- package/src/v2/index.ts +1 -0
- package/src/v2/model/block_components.ts +33 -0
- package/src/v2/model/block_meta.ts +18 -0
- package/src/v2/resolve_to_registry.ts +84 -0
- package/src/v2/source_package.ts +34 -1
- package/dist/config-DpfTzcgG.mjs.map +0 -1
- package/dist/config-xxVy3IQR.js +0 -3
- package/dist/config-xxVy3IQR.js.map +0 -1
- package/src/structure/templates/static/block/index.d.ts +0 -6
- package/src/structure/templates/static/block/index.js +0 -8
|
@@ -1,24 +1,67 @@
|
|
|
1
|
-
//
|
|
2
|
-
//
|
|
3
|
-
//
|
|
4
|
-
//
|
|
1
|
+
// Facade `package.json`: the initial generator and the drift-correcting body
|
|
2
|
+
// rules, co-located. The facade is the only sibling of a block that publishes,
|
|
3
|
+
// and it ships SLIM: `dependencies` is empty (the consumer's install pulls zero
|
|
4
|
+
// `@platforma-sdk/*` transitive runtime deps), siblings are build-time
|
|
5
|
+
// `workspace:*` devDeps, and the built `dist/` + `block-pack/` carry everything
|
|
6
|
+
// the loader needs.
|
|
5
7
|
|
|
6
8
|
import {
|
|
7
9
|
ensureField,
|
|
8
10
|
ensureScript,
|
|
9
11
|
ensureDevDep,
|
|
10
|
-
|
|
12
|
+
ensureWorkspaceScopeDevDeps,
|
|
13
|
+
requireField,
|
|
14
|
+
removeScript,
|
|
11
15
|
enforceAlphabeticalOrder,
|
|
12
16
|
enforceFieldOrder,
|
|
13
17
|
type RunContext,
|
|
14
18
|
} from "../engine/api";
|
|
15
|
-
import { findModules,
|
|
19
|
+
import { findModules, scopeDepMaps } from "../engine/ctx";
|
|
16
20
|
import { canonicalPackageJsonOrder } from "./shared/key-order";
|
|
17
21
|
|
|
22
|
+
/** Per-org publish coordinates: the S3 upload bucket and the public registry
|
|
23
|
+
* serve URL the facade's `prepublishOnly` script passes to `block-tools
|
|
24
|
+
* publish`. One block-registry bucket serves both orgs; only the public read
|
|
25
|
+
* hostname differs by org. Safe for the never-published `etc/blocks` test
|
|
26
|
+
* blocks — the script never runs for them. Extend the map per new org. */
|
|
27
|
+
const ORG_PUBLISH_TARGETS: Record<string, { s3: string; serveUrl: string }> = {
|
|
28
|
+
"@platforma-open": {
|
|
29
|
+
s3: "s3://milab-euce1-prod-pkgs-s3-block-registry/pub/releases/?region=eu-central-1",
|
|
30
|
+
serveUrl: "https://blocks.pl-open.science",
|
|
31
|
+
},
|
|
32
|
+
"@milaboratories": {
|
|
33
|
+
s3: "s3://milab-euce1-prod-pkgs-s3-block-registry/pub/releases/?region=eu-central-1",
|
|
34
|
+
serveUrl: "https://block.registry.platforma.bio/releases",
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/** Fallback for an org not in the table — keeps the generated script valid
|
|
39
|
+
* (and inert until published) rather than throwing during a refresh. */
|
|
40
|
+
const FALLBACK_PUBLISH_TARGET = {
|
|
41
|
+
s3: "s3://milab-euce1-prod-pkgs-s3-block-registry/pub/releases/?region=eu-central-1",
|
|
42
|
+
serveUrl: "https://blocks.pl-open.science",
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
/** Where the in-SDK blocks (`etc/blocks/*`) publish: the aux/dev registry, not
|
|
46
|
+
* production `pub/releases/`. These are the monorepo's test/example blocks, so
|
|
47
|
+
* one target regardless of org — their `@milaboratories` scope must NOT route
|
|
48
|
+
* them to the real catalog alongside standalone blocks. */
|
|
49
|
+
const SDK_INTERNAL_PUBLISH_TARGET = {
|
|
50
|
+
s3: "s3://milab-euce1-prod-pkgs-s3-block-registry/aux/dev/?region=eu-central-1",
|
|
51
|
+
serveUrl: "https://aux-blocks.pl-open.science",
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
function prepublishScript(npmOrg: string, isSdkInternal: boolean): string {
|
|
55
|
+
const t = isSdkInternal
|
|
56
|
+
? SDK_INTERNAL_PUBLISH_TARGET
|
|
57
|
+
: (ORG_PUBLISH_TARGETS[npmOrg] ?? FALLBACK_PUBLISH_TARGET);
|
|
58
|
+
return `block-tools publish -r ${t.s3} --registry-serve-url ${t.serveUrl}`;
|
|
59
|
+
}
|
|
60
|
+
|
|
18
61
|
/** The facade's `block.components` map: the dist artifact each module build
|
|
19
|
-
* emits, keyed by role. Fully determined by the discovered modules — the
|
|
20
|
-
*
|
|
21
|
-
*
|
|
62
|
+
* emits, keyed by role. Fully determined by the discovered modules — the body
|
|
63
|
+
* rule re-asserts this exact value, so it is engine-managed (NOT an author
|
|
64
|
+
* seed). Mirrors the artifact paths produced by each scope's build:
|
|
22
65
|
* workflow → pl-tengo, model → build-model, ui → ts-builder. */
|
|
23
66
|
export function blockComponents(ctx: RunContext): Record<string, string> {
|
|
24
67
|
const components: Record<string, string> = {};
|
|
@@ -29,6 +72,44 @@ export function blockComponents(ctx: RunContext): Record<string, string> {
|
|
|
29
72
|
return components;
|
|
30
73
|
}
|
|
31
74
|
|
|
75
|
+
/** The slim facade's canonical scripts (build / check / prepublishOnly /
|
|
76
|
+
* do-pack). Shared by the initial generator and the body rule so they cannot
|
|
77
|
+
* drift apart. `prepublishOnly` routes by block kind: in-SDK blocks publish to
|
|
78
|
+
* the aux/dev registry, standalone blocks to their per-org production target. */
|
|
79
|
+
function blockScripts(npmOrg: string, isSdkInternal: boolean): Record<string, string> {
|
|
80
|
+
return {
|
|
81
|
+
build: "ts-builder build --target block-facade && block-tools pack",
|
|
82
|
+
check: "ts-builder type-check --target block-facade",
|
|
83
|
+
prepublishOnly: prepublishScript(npmOrg, isSdkInternal),
|
|
84
|
+
"do-pack": "pnpm pack && shx mv *.tgz package.tgz",
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** The facade's build/publish devDependencies (the workspace `model`/`ui`/
|
|
89
|
+
* `workflow` siblings are added separately, from discovery). `sdk:` resolves
|
|
90
|
+
* to `workspace:*` for in-monorepo blocks and `catalog:` for standalone — the
|
|
91
|
+
* body rule re-asserts the same set. */
|
|
92
|
+
const FACADE_DEV_DEPS = {
|
|
93
|
+
"@milaboratories/ts-builder": "sdk:",
|
|
94
|
+
"@milaboratories/ts-configs": "sdk:",
|
|
95
|
+
"@platforma-sdk/block-tools": "sdk:",
|
|
96
|
+
"@platforma-sdk/model": "sdk:",
|
|
97
|
+
shx: "catalog:",
|
|
98
|
+
typescript: "catalog:",
|
|
99
|
+
} as const;
|
|
100
|
+
|
|
101
|
+
/** The facade's `exports` map: a single `.` entry. `sources` keeps monorepo IDE
|
|
102
|
+
* go-to-definition pointing at `src/` (external consumers don't enable it);
|
|
103
|
+
* `types`/`default` carry the bundled `.d.ts` / `.js` from `dist/`. No
|
|
104
|
+
* `./AGENTS` subpath — that surface ships as a registry-side component. */
|
|
105
|
+
const FACADE_EXPORTS = {
|
|
106
|
+
".": {
|
|
107
|
+
sources: "./src/index.ts",
|
|
108
|
+
types: "./dist/index.d.ts",
|
|
109
|
+
default: "./dist/index.js",
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
|
|
32
113
|
/** Fail loudly if any required `block.*` field is empty — a missing
|
|
33
114
|
* title / description / logo / organization or empty components map would
|
|
34
115
|
* otherwise produce an init block that `block-tools pack` rejects only
|
|
@@ -63,20 +144,18 @@ function assertBlockFieldsFilled(block: {
|
|
|
63
144
|
|
|
64
145
|
export function blockPackageJsonInitial(ctx: RunContext): Record<string, unknown> {
|
|
65
146
|
const v = ctx.blockVars;
|
|
66
|
-
// The facade
|
|
67
|
-
//
|
|
68
|
-
//
|
|
69
|
-
//
|
|
70
|
-
const
|
|
71
|
-
...
|
|
72
|
-
...
|
|
73
|
-
...
|
|
147
|
+
// The facade's siblings are build-time devDeps, never runtime deps — the
|
|
148
|
+
// facade ships its content bundled inside dist/ + block-pack/, so the
|
|
149
|
+
// consumer needs no runtime resolution into siblings. Software/test are
|
|
150
|
+
// excluded (the workflow owns software; a test→facade dep would be a cycle).
|
|
151
|
+
const devDeps: Record<string, string> = {
|
|
152
|
+
...FACADE_DEV_DEPS,
|
|
153
|
+
...scopeDepMaps(ctx, "model"),
|
|
154
|
+
...scopeDepMaps(ctx, "ui"),
|
|
155
|
+
...scopeDepMaps(ctx, "workflow"),
|
|
74
156
|
};
|
|
75
|
-
// `block
|
|
76
|
-
//
|
|
77
|
-
// refresh, so the author owns title / description / organization / logo.
|
|
78
|
-
// `block-tools pack` requires both. The author edits the placeholder meta
|
|
79
|
-
// before publishing.
|
|
157
|
+
// `block-tools pack` requires both `block.components` and `block.meta`. The
|
|
158
|
+
// author edits the placeholder meta before publishing.
|
|
80
159
|
const block = {
|
|
81
160
|
components: blockComponents(ctx),
|
|
82
161
|
meta: {
|
|
@@ -94,59 +173,62 @@ export function blockPackageJsonInitial(ctx: RunContext): Record<string, unknown
|
|
|
94
173
|
return {
|
|
95
174
|
name: `${v.facadeName}.block`,
|
|
96
175
|
version: "1.0.0",
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
176
|
+
// Facade is ESM: rolldown-plugin-dts requires it, and the BlockPointer's
|
|
177
|
+
// `import.meta.url` path math needs it.
|
|
178
|
+
type: "module",
|
|
179
|
+
// Drives the npm tarball: only the built outputs ship; sources, tsconfig,
|
|
180
|
+
// and node_modules stay out.
|
|
181
|
+
files: ["dist", "block-pack"],
|
|
182
|
+
main: "./dist/index.js",
|
|
183
|
+
module: "./dist/index.js",
|
|
184
|
+
types: "./dist/index.d.ts",
|
|
185
|
+
exports: FACADE_EXPORTS,
|
|
186
|
+
scripts: blockScripts(v.npmOrg, ctx.isSdkInternal),
|
|
187
|
+
// Slim invariant: zero runtime deps reach the consumer.
|
|
188
|
+
dependencies: {},
|
|
189
|
+
devDependencies: devDeps,
|
|
109
190
|
block,
|
|
110
191
|
};
|
|
111
192
|
}
|
|
112
193
|
|
|
113
194
|
export function blockPackageJsonRules(ctx: RunContext): void {
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
ensureField("files", ["
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
"block-tools mark-stable -r 's3://milab-euce1-prod-pkgs-s3-block-registry/pub/releases/?region=eu-central-1'",
|
|
123
|
-
);
|
|
124
|
-
ensureScript(
|
|
125
|
-
"prepublishOnly",
|
|
126
|
-
"block-tools pack && block-tools publish -r 's3://milab-euce1-prod-pkgs-s3-block-registry/pub/releases/?region=eu-central-1'",
|
|
127
|
-
);
|
|
128
|
-
ensureScript(
|
|
129
|
-
"do-pack",
|
|
130
|
-
"shx rm -f *.tgz && block-tools pack && pnpm pack && shx mv *.tgz package.tgz",
|
|
131
|
-
);
|
|
132
|
-
|
|
133
|
-
// One workspace dep per discovered module in the facade's scopes. The
|
|
134
|
-
// facade depends on model / ui / workflow — not software (the workflow
|
|
135
|
-
// owns it) and not test (a reciprocal dep would be a pnpm/turbo cycle).
|
|
136
|
-
ensureWorkspaceScopeDeps("model");
|
|
137
|
-
ensureWorkspaceScopeDeps("ui");
|
|
138
|
-
ensureWorkspaceScopeDeps("workflow");
|
|
195
|
+
const v = ctx.blockVars;
|
|
196
|
+
|
|
197
|
+
ensureField("type", "module");
|
|
198
|
+
ensureField("files", ["dist", "block-pack"]);
|
|
199
|
+
ensureField("main", "./dist/index.js");
|
|
200
|
+
ensureField("module", "./dist/index.js");
|
|
201
|
+
ensureField("types", "./dist/index.d.ts");
|
|
202
|
+
ensureField("exports", FACADE_EXPORTS);
|
|
139
203
|
|
|
204
|
+
const scripts = blockScripts(v.npmOrg, ctx.isSdkInternal);
|
|
205
|
+
for (const [name, command] of Object.entries(scripts)) ensureScript(name, command);
|
|
206
|
+
removeScript("mark-stable");
|
|
207
|
+
|
|
208
|
+
// Slim invariant: the facade carries ZERO runtime dependencies. The siblings
|
|
209
|
+
// and the SDK build/publish deps are all devDeps, so `dependencies` ends
|
|
210
|
+
// empty. Software/test are excluded (the workflow owns software; a
|
|
211
|
+
// test→facade dep would be a cycle).
|
|
212
|
+
ensureWorkspaceScopeDevDeps("model");
|
|
213
|
+
ensureWorkspaceScopeDevDeps("ui");
|
|
214
|
+
ensureWorkspaceScopeDevDeps("workflow");
|
|
215
|
+
ensureDevDep("@milaboratories/ts-builder", "sdk:");
|
|
216
|
+
ensureDevDep("@milaboratories/ts-configs", "sdk:");
|
|
140
217
|
ensureDevDep("@platforma-sdk/block-tools", "sdk:");
|
|
141
|
-
|
|
218
|
+
ensureDevDep("@platforma-sdk/model", "sdk:");
|
|
142
219
|
ensureDevDep("shx", "catalog:");
|
|
220
|
+
ensureDevDep("typescript", "catalog:");
|
|
143
221
|
|
|
144
|
-
// `block.components` is fully determined by the discovered modules — keep
|
|
145
|
-
//
|
|
146
|
-
//
|
|
147
|
-
//
|
|
222
|
+
// `block.components` is fully determined by the discovered modules — keep it
|
|
223
|
+
// in sync on refresh. `block.meta` is deliberately NOT touched: it is an
|
|
224
|
+
// author-owned seed (set once in the init package.json), so refresh must
|
|
225
|
+
// never overwrite the author's title / description / logo.
|
|
148
226
|
ensureField("block.components", blockComponents(ctx));
|
|
149
227
|
|
|
228
|
+
// The author owns `name` and `version`; `version` MUST be present (the
|
|
229
|
+
// facade publishes).
|
|
230
|
+
requireField("version", "facade package.json must carry a 'version' (the facade publishes)");
|
|
231
|
+
|
|
150
232
|
enforceAlphabeticalOrder("dependencies");
|
|
151
233
|
enforceAlphabeticalOrder("devDependencies");
|
|
152
234
|
enforceAlphabeticalOrder("peerDependencies");
|
|
@@ -1,13 +1,48 @@
|
|
|
1
|
-
// Block-scope rules — the
|
|
2
|
-
//
|
|
1
|
+
// Block-scope rules — the facade package at `block/`. The facade is the
|
|
2
|
+
// only sibling of a block that publishes: a slim 4-file `src/` surface
|
|
3
|
+
// (engine-owned `index.ts` + `AGENTS.ts`, author-owned `block-extra.ts` +
|
|
4
|
+
// `agents-extra.ts`), a facade `tsconfig.json`, and a slim publishable
|
|
5
|
+
// `package.json`. Workspace-scope deps in the body resolve from ctx.modules.
|
|
3
6
|
|
|
4
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
scope,
|
|
9
|
+
fixed,
|
|
10
|
+
scaffold,
|
|
11
|
+
managed,
|
|
12
|
+
seed,
|
|
13
|
+
remove,
|
|
14
|
+
file,
|
|
15
|
+
tpl,
|
|
16
|
+
binaryFile,
|
|
17
|
+
generate,
|
|
18
|
+
} from "../engine/api";
|
|
5
19
|
import { blockPackageJsonInitial, blockPackageJsonRules } from "./block-package-json";
|
|
20
|
+
import { pascalCase } from "./shared/pascal-case";
|
|
6
21
|
|
|
7
22
|
export function blockRules(): void {
|
|
8
23
|
scope("block", () => {
|
|
9
|
-
|
|
10
|
-
|
|
24
|
+
// `remove` is idempotent (absent file → no-op), so this is safe on a block
|
|
25
|
+
// that has no such entry files.
|
|
26
|
+
remove("index.js");
|
|
27
|
+
remove("index.d.ts");
|
|
28
|
+
|
|
29
|
+
// Four-file source surface. `index.ts` is engine-owned and per-block
|
|
30
|
+
// (model import path + `<PascalName>` aliases) → text-templated. `AGENTS.ts`
|
|
31
|
+
// is engine-owned and identical for every block → static. The two `*-extra`
|
|
32
|
+
// files are author scaffolds (`scaffold`: create-if-missing on every refresh,
|
|
33
|
+
// never overwritten).
|
|
34
|
+
fixed(
|
|
35
|
+
"src/index.ts",
|
|
36
|
+
tpl("block/src/index.tpl.ts", (ctx) => ({
|
|
37
|
+
facadeName: ctx.blockVars.facadeName,
|
|
38
|
+
pascalName: pascalCase(ctx.blockVars.shortName),
|
|
39
|
+
})),
|
|
40
|
+
);
|
|
41
|
+
fixed("src/AGENTS.ts", file("block/src/AGENTS.ts"));
|
|
42
|
+
scaffold("src/block-extra.ts", file("block/src/block-extra.ts"));
|
|
43
|
+
scaffold("src/agents-extra.ts", file("block/src/agents-extra.ts"));
|
|
44
|
+
|
|
45
|
+
fixed("tsconfig.json", file("block/tsconfig.json"));
|
|
11
46
|
|
|
12
47
|
// Placeholder logos referenced by `block.meta` (logo + organization.logo).
|
|
13
48
|
// Binary seeds: written once at init, author-owned thereafter — refresh
|
|
@@ -33,7 +33,7 @@ export function modelPackageJsonInitial(ctx: RunContext): Record<string, unknown
|
|
|
33
33
|
const v = ctx.blockVars;
|
|
34
34
|
return {
|
|
35
35
|
name: `${v.facadeName}.model`,
|
|
36
|
-
|
|
36
|
+
private: true,
|
|
37
37
|
type: "module",
|
|
38
38
|
// The block-model build emits both index.cjs and index.js. `main` is
|
|
39
39
|
// the CommonJS entry (require fallback); `module` the ESM entry.
|
|
@@ -70,6 +70,11 @@ export function modelPackageJsonInitial(ctx: RunContext): Record<string, unknown
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
export function modelPackageJsonRules(): void {
|
|
73
|
+
// Controlled sibling — workspace-only, never published. `private: true` makes
|
|
74
|
+
// npm refuse to publish it; the `version` is kept (changesets-owned) so the
|
|
75
|
+
// packed template's lib carries a version.
|
|
76
|
+
ensureField("private", true);
|
|
77
|
+
|
|
73
78
|
ensureField("type", "module");
|
|
74
79
|
// build emits both; main = CJS entry, module = ESM entry (prod convention).
|
|
75
80
|
ensureField("main", "dist/index.cjs");
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// `pascalCase(shortName)` → the block-named alias prefix the facade entry
|
|
2
|
+
// template emits (`<PascalName>BlockContract`, …). Splits on any run of
|
|
3
|
+
// non-alphanumeric characters and capitalises each segment's first char:
|
|
4
|
+
// test-sum-numbers-v3 → TestSumNumbersV3
|
|
5
|
+
// mixcr-clonotyping-2 → MixcrClonotyping2
|
|
6
|
+
// samples-and-data → SamplesAndData
|
|
7
|
+
export function pascalCase(s: string): string {
|
|
8
|
+
const joined = s
|
|
9
|
+
.split(/[^A-Za-z0-9]+/)
|
|
10
|
+
.filter((seg) => seg.length > 0)
|
|
11
|
+
.map((seg) => seg.charAt(0).toUpperCase() + seg.slice(1))
|
|
12
|
+
.join("");
|
|
13
|
+
// A leading digit (e.g. `3d-viewer` → `3dViewer`) is not a valid identifier
|
|
14
|
+
// start — the prefix becomes `const 3dViewerBlockPointer = …`. Prepend `_`.
|
|
15
|
+
return /^[0-9]/.test(joined) ? `_${joined}` : joined;
|
|
16
|
+
}
|
|
@@ -46,7 +46,7 @@ export function softwarePackageJsonInitial(ctx: RunContext): Record<string, unkn
|
|
|
46
46
|
const v = ctx.blockVars;
|
|
47
47
|
return {
|
|
48
48
|
name: `${v.facadeName}.software`,
|
|
49
|
-
|
|
49
|
+
private: true,
|
|
50
50
|
type: "module",
|
|
51
51
|
description: "Block Software",
|
|
52
52
|
files: ["./dist/**/*"],
|
|
@@ -65,6 +65,11 @@ export function softwarePackageJsonInitial(ctx: RunContext): Record<string, unkn
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
export function softwarePackageJsonRules(): void {
|
|
68
|
+
// Controlled sibling — workspace-only, never npm-published. (Software still
|
|
69
|
+
// publishes runenv artifacts via `pl-pkg`, which is unaffected by `private`.)
|
|
70
|
+
// The `version` is kept (changesets-owned) so the packed template carries it.
|
|
71
|
+
ensureField("private", true);
|
|
72
|
+
|
|
68
73
|
ensureField("type", "module");
|
|
69
74
|
ensureField("files", ["./dist/**/*"]);
|
|
70
75
|
|
|
@@ -19,7 +19,6 @@ export function testPackageJsonInitial(ctx: RunContext): Record<string, unknown>
|
|
|
19
19
|
const v = ctx.blockVars;
|
|
20
20
|
return {
|
|
21
21
|
name: `${v.facadeName}.test`,
|
|
22
|
-
version: "1.0.0",
|
|
23
22
|
private: true,
|
|
24
23
|
type: "module",
|
|
25
24
|
scripts: {
|
|
@@ -41,6 +40,11 @@ export function testPackageJsonInitial(ctx: RunContext): Record<string, unknown>
|
|
|
41
40
|
}
|
|
42
41
|
|
|
43
42
|
export function testPackageJsonRules(): void {
|
|
43
|
+
// Controlled sibling — workspace-only, never published. (The initial already
|
|
44
|
+
// seeds `private: true`; the body re-asserts it. The `version` is kept —
|
|
45
|
+
// changesets-owned — so the packed template's lib carries a version.)
|
|
46
|
+
ensureField("private", true);
|
|
47
|
+
|
|
44
48
|
ensureField("type", "module");
|
|
45
49
|
|
|
46
50
|
ensureScript("fmt", "ts-builder format");
|
|
@@ -32,7 +32,7 @@ export function uiPackageJsonInitial(ctx: RunContext): Record<string, unknown> {
|
|
|
32
32
|
const v = ctx.blockVars;
|
|
33
33
|
return {
|
|
34
34
|
name: `${v.facadeName}.ui`,
|
|
35
|
-
|
|
35
|
+
private: true,
|
|
36
36
|
type: "module",
|
|
37
37
|
scripts: {
|
|
38
38
|
fmt: "ts-builder format",
|
|
@@ -60,6 +60,10 @@ export function uiPackageJsonInitial(ctx: RunContext): Record<string, unknown> {
|
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
export function uiPackageJsonRules(): void {
|
|
63
|
+
// Controlled sibling — workspace-only, never published, but kept versioned
|
|
64
|
+
// (changesets-owned) so the packed template's lib carries a version.
|
|
65
|
+
ensureField("private", true);
|
|
66
|
+
|
|
63
67
|
ensureField("type", "module");
|
|
64
68
|
|
|
65
69
|
ensureScript("fmt", "ts-builder format");
|
|
@@ -25,7 +25,7 @@ export function workflowPackageJsonInitial(ctx: RunContext): Record<string, unkn
|
|
|
25
25
|
const v = ctx.blockVars;
|
|
26
26
|
return {
|
|
27
27
|
name: `${v.facadeName}.workflow`,
|
|
28
|
-
|
|
28
|
+
private: true,
|
|
29
29
|
type: "module",
|
|
30
30
|
scripts: {
|
|
31
31
|
// No `fmt`: the workflow is Tengo, not TS — nothing for oxlint/oxfmt
|
|
@@ -54,6 +54,10 @@ export function workflowPackageJsonInitial(ctx: RunContext): Record<string, unkn
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
export function workflowPackageJsonRules(): void {
|
|
57
|
+
// Controlled sibling — workspace-only, never published, but kept versioned
|
|
58
|
+
// (changesets-owned) so the packed template's lib carries a version.
|
|
59
|
+
ensureField("private", true);
|
|
60
|
+
|
|
57
61
|
ensureField("type", "module");
|
|
58
62
|
|
|
59
63
|
// No `fmt` script: the workflow is Tengo, not TS — build + check run via
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Author-owned. `block-tools structure` does not modify this file.
|
|
2
|
+
// MCP / AI extension surface. Add types and functions the agent
|
|
3
|
+
// surface should expose.
|
|
4
|
+
//
|
|
5
|
+
// In the future this file will host JS functions the MCP runtime
|
|
6
|
+
// can execute. The `.d.ts` declarations stay visible to the agent;
|
|
7
|
+
// the JS bodies execute in the MCP code-execution context (the
|
|
8
|
+
// agent sees the types but not the implementation).
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Author-owned. `block-tools structure` does not modify this file.
|
|
2
|
+
// Add block-specific helper types or values the consumer surface
|
|
3
|
+
// should expose. Anything you `export` here flows out via the
|
|
4
|
+
// main entry (./index re-exports this file).
|
|
5
|
+
//
|
|
6
|
+
// Do NOT redefine: BlockContract, BlockOutputs, BlockData,
|
|
7
|
+
// BlockPointer, platforma, or the block-named <PascalName>Block*
|
|
8
|
+
// aliases — those names come from ./index and `export *` from this
|
|
9
|
+
// file would shadow them.
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// This file is managed by `block-tools structure`. Do not edit by hand.
|
|
2
|
+
// Author content lives in ./block-extra.ts.
|
|
3
|
+
|
|
4
|
+
import { platforma } from "${facadeName}.model";
|
|
5
|
+
import {
|
|
6
|
+
InferOutputsType,
|
|
7
|
+
InferDataType,
|
|
8
|
+
InferHrefType,
|
|
9
|
+
} from "@platforma-sdk/model";
|
|
10
|
+
|
|
11
|
+
export { platforma };
|
|
12
|
+
|
|
13
|
+
export type BlockContract = {
|
|
14
|
+
outputs: InferOutputsType<typeof platforma>;
|
|
15
|
+
data: InferDataType<typeof platforma>;
|
|
16
|
+
href: InferHrefType<typeof platforma>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export type BlockOutputs = BlockContract["outputs"];
|
|
20
|
+
export type BlockData = BlockContract["data"];
|
|
21
|
+
|
|
22
|
+
// import.meta.url is a file: URL (always forward-slash, even on Windows:
|
|
23
|
+
// file:///C:/…). We expose URLs, NOT paths — the facade stays dependency-free
|
|
24
|
+
// and loadable in minimal engines (e.g. QuickJS), and each consumer converts
|
|
25
|
+
// at its own edge with the right tool (fileURLToPath in Node), where Windows
|
|
26
|
+
// drive letters / %-encoding / UNC are handled correctly. The bundled entry
|
|
27
|
+
// sits one dir under the package root (dist/index.js, or src/index.ts in dev),
|
|
28
|
+
// so the root is two URL segments up. The structurer owns this layout —
|
|
29
|
+
// consumers read these URLs, they never reconstruct <root>/block-pack.
|
|
30
|
+
//
|
|
31
|
+
// TypeScript ships `ImportMeta.url` only in the `dom`/`webworker` libs; the
|
|
32
|
+
// facade tsconfig is lib-minimal (no `dom`, no `@types/node`) by design. We
|
|
33
|
+
// type the one ESM-standard member we use with a local cast rather than a
|
|
34
|
+
// `declare global` — a global augmentation would leak into the published
|
|
35
|
+
// `dist/index.d.ts` and clash with `@types/node`'s `ImportMeta` in full-Node
|
|
36
|
+
// consumers (test packages, the Middle Layer).
|
|
37
|
+
const selfUrl = (import.meta as ImportMeta & { url: string }).url;
|
|
38
|
+
const dirUrl = selfUrl.slice(0, selfUrl.lastIndexOf("/"));
|
|
39
|
+
const rootUrl = dirUrl.slice(0, dirUrl.lastIndexOf("/"));
|
|
40
|
+
|
|
41
|
+
export const BlockPointer = {
|
|
42
|
+
type: "from-pack-v2" as const,
|
|
43
|
+
packUrl: rootUrl + "/block-pack",
|
|
44
|
+
rootUrl,
|
|
45
|
+
} as const;
|
|
46
|
+
|
|
47
|
+
// Block-named aliases for readable cross-block imports in tests and
|
|
48
|
+
// consumer code. Same types / same runtime value as the universal
|
|
49
|
+
// names above; the aliases avoid `as`-renames at the import site.
|
|
50
|
+
export type ${pascalName}BlockContract = BlockContract;
|
|
51
|
+
export type ${pascalName}BlockOutputs = BlockOutputs;
|
|
52
|
+
export type ${pascalName}BlockData = BlockData;
|
|
53
|
+
export const ${pascalName}BlockPointer = BlockPointer;
|
|
54
|
+
|
|
55
|
+
export * from "./block-extra";
|