@descix/frqtl-node 0.6.0-p0.2 → 0.6.0-p1.1
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/CLAUDE.md +2 -2
- package/README.md +7 -3
- package/dist/dist-manifest.json +54 -48
- package/dist/frqtl/assets/vendor/acorn.LICENSE +21 -0
- package/dist/frqtl/assets/vendor/acorn.PINNED.json +9 -0
- package/dist/frqtl/assets/vendor/acorn.mjs +6266 -0
- package/dist/frqtl/compat/renderer/lo-drawn-center.js +41 -0
- package/dist/frqtl/experiments/_shared/boot-failure.js +60 -0
- package/dist/frqtl/objects/FrqtlApp.js +109 -30
- package/dist/frqtl/objects/ObjectFactory.js +4 -5
- package/dist/frqtl/objects/RecipeContext.js +451 -9
- package/dist/frqtl/objects/instruments/hosted-eyes.js +68 -28
- package/dist/frqtl/objects/objects/QuantumEmitter.js +1 -1
- package/dist/frqtl/objects/schema/index.js +72 -0
- package/dist/frqtl/parts/DetectorWall.js +1 -1
- package/dist/frqtl/parts/FrqtlControlsPanel.js +4 -2
- package/dist/frqtl/parts/Wall.js +2 -0
- package/dist/frqtl/scenes/absorbing-wall-3d.js +18 -14
- package/dist/frqtl/scenes/absorbing-wall.js +18 -14
- package/dist/frqtl/scenes/atomic-model.js +3 -0
- package/dist/frqtl/scenes/big-bang.js +3 -0
- package/dist/frqtl/scenes/blackbody.js +14 -11
- package/dist/frqtl/scenes/circuit-sat.js +7 -4
- package/dist/frqtl/scenes/collision-matrix-3d.js +3 -0
- package/dist/frqtl/scenes/counting-wall-3d.js +19 -15
- package/dist/frqtl/scenes/counting-wall.js +19 -15
- package/dist/frqtl/scenes/double-slit.js +3 -0
- package/dist/frqtl/scenes/dse-one-emitter.js +64 -58
- package/dist/frqtl/scenes/dse-one-slit.js +59 -55
- package/dist/frqtl/scenes/dse-photoelectric.js +28 -24
- package/dist/frqtl/scenes/dse-tunnel-rebuild.js +124 -99
- package/dist/frqtl/scenes/dse-two-emitters.js +64 -58
- package/dist/frqtl/scenes/dse-two-slits.js +69 -65
- package/dist/frqtl/scenes/empty.js +3 -0
- package/dist/frqtl/scenes/laser-buildup.js +23 -16
- package/dist/frqtl/scenes/mirror-3d.js +31 -27
- package/dist/frqtl/scenes/mirror-route.js +4 -1
- package/dist/frqtl/scenes/mirror.js +24 -20
- package/dist/frqtl/scenes/omni-3d.js +7 -4
- package/dist/frqtl/scenes/omni-source.js +7 -4
- package/dist/frqtl/scenes/self-interference.js +13 -10
- package/dist/frqtl/scenes/smoking-gun.js +15 -11
- package/dist/frqtl/scenes/straight-walk.js +7 -4
- package/dist/frqtl/scenes/sun.js +11 -8
- package/dist/frqtl/scenes/two-source.js +22 -17
- package/dist/frqtl/scenes/wave.js +10 -7
- package/dist/shim/bundle/manifest.js +1 -1
- package/dist/shim/engine/router.js +2 -2
- package/dist/shim/page-params/index.js +2 -2
- package/dist/shim/project/index.js +7 -5
- package/dist/shim/project/link.js +12 -5
- package/dist/shim/project/parts-module.js +67 -0
- package/dist/shim/project/parts-writer.js +453 -0
- package/dist/shim/project/specifiers.js +41 -13
- package/dist/shim/registry/walkthrough.js +9 -9
- package/dist/shim/render-state/apply.js +11 -14
- package/llms.txt +2 -2
- package/package.json +1 -1
package/dist/frqtl/scenes/sun.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* A sketch file: the WHOLE scene as one ES module, `export default function buildExperiment(exp)`. The world
|
|
7
7
|
* (its co-init call, `exp.createCanvas` / `exp.createScene` — the one place its size is written),
|
|
8
|
-
* the parts (`exp.addObject`) and the render intent are all here; the sugar
|
|
8
|
+
* the parts (`export const parts` + `exp.declare`, or `exp.addObject`) and the render intent are all here; the sugar
|
|
9
9
|
* objects, renderer and engine are imports. Registered by lib/shim/registry/walkthrough.js
|
|
10
10
|
* (rung r8-sun).
|
|
11
11
|
*/
|
|
@@ -21,18 +21,21 @@
|
|
|
21
21
|
|
|
22
22
|
import { CameraControls, SphereEmitter } from '@descix/frqtl-web/parts';
|
|
23
23
|
|
|
24
|
+
export const parts = {
|
|
25
|
+
source: [SphereEmitter, {
|
|
26
|
+
preset: 'spherical', emissionBoxSide: 0, is2D: false,
|
|
27
|
+
chargeMode: 'random', fundamentalDimension: 2,
|
|
28
|
+
wavelength: 1, fundamentalWaveLength: 64, emitEveryTicks: 1
|
|
29
|
+
}],
|
|
30
|
+
};
|
|
31
|
+
|
|
24
32
|
export default function buildExperiment(exp) {
|
|
25
33
|
// Rung 8 (Sun) — the sun.png panel regime: a 3D omni POINT source, virtual mass 16
|
|
26
34
|
// (fullness 1) via wavelength:1, λ scale 16 via fundamentalWaveLength:64, emit every 1.
|
|
27
35
|
// The sphere shape + god-rays + glow FX ride the renderState (three-only capabilities).
|
|
28
36
|
// The sun's yellow is the NATURAL fullness->color (mass=capacity, fullness 1); no forced color.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
chargeMode: 'random', fundamentalDimension: 2,
|
|
32
|
-
wavelength: 1, fundamentalWaveLength: 64, emitEveryTicks: 1
|
|
33
|
-
};
|
|
34
|
-
exp.createScene(600, 400, 600, SphereEmitter.worldCfg(SRC)); // THE WORLD: a 3D scene + universe, 600x400x600 — first, then parts
|
|
35
|
-
exp.addObject('SphereEmitter', SRC);
|
|
37
|
+
exp.createScene(600, 400, 600, SphereEmitter.worldCfg(parts.source[1])); // THE WORLD: a 3D scene + universe, 600x400x600 — first, then parts
|
|
38
|
+
exp.declare(parts);
|
|
36
39
|
if (typeof document !== 'undefined' && exp.runner) {
|
|
37
40
|
if (exp.runner.controlHost) { CameraControls.attach(exp.runner, exp.runner.controlHost); }
|
|
38
41
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* A sketch file: the WHOLE scene as one ES module, `export default function buildExperiment(exp)`. The world
|
|
7
7
|
* (its co-init call, `exp.createCanvas` / `exp.createScene` — the one place its size is written),
|
|
8
|
-
* the parts (`exp.addObject`) and the render intent are all here; the sugar
|
|
8
|
+
* the parts (`export const parts` + `exp.declare`, or `exp.addObject`) and the render intent are all here; the sugar
|
|
9
9
|
* objects, renderer and engine are imports. Registered by lib/shim/registry/walkthrough.js
|
|
10
10
|
* (rungs r6a-two-source, r6b-two-fountains, r6c-plasma-fusion).
|
|
11
11
|
*/
|
|
@@ -16,22 +16,27 @@
|
|
|
16
16
|
|
|
17
17
|
import { SphereEmitter } from '@descix/frqtl-web/parts';
|
|
18
18
|
|
|
19
|
+
// The classic self-interference config called TWICE, centered ±32px from canvas
|
|
20
|
+
// center (64px apart = 1×fundamentalWaveLength, i.e. λ_eff/4 since λ_eff = 4×fWL).
|
|
21
|
+
// The world is init'd ONCE, then TWO parts are constructed on it — no flag, no
|
|
22
|
+
// re-init, no stacking. The
|
|
23
|
+
// lattice BETWEEN the two visible sources is EMERGENT density superposition (SU1).
|
|
24
|
+
const W = 600, H = 400; // THE WORLD this scene states (its co-init call below)
|
|
25
|
+
const cx = Math.floor(W / 2), cy = Math.floor(H / 2);
|
|
26
|
+
const CFG = {
|
|
27
|
+
is2D: true, preset: 'spherical',
|
|
28
|
+
emissionShell: 'surface', innerR: 16,
|
|
29
|
+
fundamentalDimension: 2, wavelength: 32,
|
|
30
|
+
chargeMode: 'random', fundamentalWaveLength: 64,
|
|
31
|
+
burstSize: 72, emitEveryTicks: 1
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
export const parts = {
|
|
35
|
+
left: [SphereEmitter, { ...CFG, center: [cx - 32, cy] }],
|
|
36
|
+
right: [SphereEmitter, { ...CFG, center: [cx + 32, cy] }],
|
|
37
|
+
};
|
|
38
|
+
|
|
19
39
|
export default function buildExperiment(exp) {
|
|
20
|
-
// The classic self-interference config called TWICE, centered ±32px from canvas
|
|
21
|
-
// center (64px apart = 1×fundamentalWaveLength, i.e. λ_eff/4 since λ_eff = 4×fWL).
|
|
22
|
-
// The world is init'd ONCE, then TWO parts are constructed on it — no flag, no
|
|
23
|
-
// re-init, no stacking. The
|
|
24
|
-
// lattice BETWEEN the two visible sources is EMERGENT density superposition (SU1).
|
|
25
|
-
var W = 600, H = 400; // THE WORLD this scene states (its co-init call below)
|
|
26
|
-
var cx = Math.floor(W / 2), cy = Math.floor(H / 2);
|
|
27
|
-
var CFG = {
|
|
28
|
-
is2D: true, preset: 'spherical',
|
|
29
|
-
emissionShell: 'surface', innerR: 16,
|
|
30
|
-
fundamentalDimension: 2, wavelength: 32,
|
|
31
|
-
chargeMode: 'random', fundamentalWaveLength: 64,
|
|
32
|
-
burstSize: 72, emitEveryTicks: 1
|
|
33
|
-
};
|
|
34
40
|
exp.createCanvas(W, H, SphereEmitter.worldCfg(CFG)); // THE WORLD: a 2D canvas + universe — first, then parts
|
|
35
|
-
exp.
|
|
36
|
-
exp.addObject('SphereEmitter', Object.assign({}, CFG, { center: [cx + 32, cy] }));
|
|
41
|
+
exp.declare(parts);
|
|
37
42
|
}
|
|
@@ -5,22 +5,25 @@
|
|
|
5
5
|
*
|
|
6
6
|
* A sketch file: the WHOLE scene as one ES module, `export default function buildExperiment(exp)`. The world
|
|
7
7
|
* (its co-init call, `exp.createCanvas` / `exp.createScene` — the one place its size is written),
|
|
8
|
-
* the parts (`exp.addObject`) and the render intent are all here; the sugar
|
|
8
|
+
* the parts (`export const parts` + `exp.declare`, or `exp.addObject`) and the render intent are all here; the sugar
|
|
9
9
|
* objects, renderer and engine are imports. Registered by lib/shim/registry/walkthrough.js
|
|
10
10
|
* (rung r2-wave).
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import { SphereEmitter } from '@descix/frqtl-web/parts';
|
|
14
14
|
|
|
15
|
+
export const parts = {
|
|
16
|
+
source: [SphereEmitter, {
|
|
17
|
+
preset: 'particle-walk', is2D: true,
|
|
18
|
+
fundamentalDimension: 2, wavelength: 8
|
|
19
|
+
}],
|
|
20
|
+
};
|
|
21
|
+
|
|
15
22
|
export default function buildExperiment(exp) {
|
|
16
23
|
// Rung 2 — Rung 1 + raise the leaf dimension to 2 (WAVELENGTH_DEMO_DIMENSION):
|
|
17
24
|
// wavelength is a NO-OP at dim 0 (capacity=1 saturates mass), so raising the
|
|
18
25
|
// fundamental gives the wavelength arg leverage. wavelength:8 -> mass 2 ->
|
|
19
26
|
// transverse period grows from ~16px (Rung 1) to a visible ~128px snake.
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
fundamentalDimension: 2, wavelength: 8
|
|
23
|
-
};
|
|
24
|
-
exp.createCanvas(600, 400, SphereEmitter.worldCfg(SRC)); // THE WORLD: a 2D canvas + universe — first, then parts
|
|
25
|
-
exp.addObject('SphereEmitter', SRC);
|
|
27
|
+
exp.createCanvas(600, 400, SphereEmitter.worldCfg(parts.source[1])); // THE WORLD: a 2D canvas + universe — first, then parts
|
|
28
|
+
exp.declare(parts);
|
|
26
29
|
}
|
|
@@ -44,7 +44,7 @@ export var BUNDLE_ONLY_KEYS = ['sdkVersion', 'preview', 'descix'];
|
|
|
44
44
|
* @param {object} envelope — a `lib/shim/storage/modules.js` Module envelope
|
|
45
45
|
* (MUST carry `source`; every other field is ferried verbatim).
|
|
46
46
|
* @param {object} opts
|
|
47
|
-
* @param {string} opts.sdkVersion — REQUIRED; the CDN pin (e.g. '0.6.0-
|
|
47
|
+
* @param {string} opts.sdkVersion — REQUIRED; the CDN pin (e.g. '0.6.0-p1.1').
|
|
48
48
|
* @param {string|null} [opts.preview] — preview filename ref, or null/omitted.
|
|
49
49
|
* @returns {object} the manifest (JSON-serializable).
|
|
50
50
|
*/
|
|
@@ -148,7 +148,7 @@ var DIST_PROFILE = buildDistProfile('../..');
|
|
|
148
148
|
// lib/shim/engine/test/router.test.mjs asserts them against the two
|
|
149
149
|
// package.json#version fields so a forgotten bump fails `make verify`, not a
|
|
150
150
|
// silent stale-CDN-URL bug.
|
|
151
|
-
var CDN_SDK_VERSION = '0.6.0-
|
|
151
|
+
var CDN_SDK_VERSION = '0.6.0-p1.1'; // sdk/frqtl-web/package.json#version (the ONE version owner) — bound by router.test.mjs
|
|
152
152
|
var CDN_MATH_SDK_VERSION = '0.3.2'; // sdk/egpt-math-sdk/package.json#version — bound by router.test.mjs; bumped with each npm publish
|
|
153
153
|
|
|
154
154
|
/**
|
|
@@ -507,7 +507,7 @@ var _assertProfileParity = (function () {
|
|
|
507
507
|
* // CDN mode (static hosting — the artifact host shell has no server, no page anchor):
|
|
508
508
|
* const cdnRouter = engineRouter({ mode: 'cdn', engine: 'wasm' });
|
|
509
509
|
* console.log(cdnRouter.resolve('compat/engine.js'));
|
|
510
|
-
* // 'https://cdn.jsdelivr.net/npm/@descix/frqtl-web@0.6.0-
|
|
510
|
+
* // 'https://cdn.jsdelivr.net/npm/@descix/frqtl-web@0.6.0-p1.1/dist/frqtl/compat/engine.js'
|
|
511
511
|
*
|
|
512
512
|
* // CDN mode, self-hosted: a copy of dist/ served from the consumer's own origin:
|
|
513
513
|
* const selfHosted = engineRouter({ mode: 'cdn', engine: 'wasm', base: 'https://example.org/vendor/frqtl-web/dist' });
|
|
@@ -185,8 +185,8 @@ var HOST_TOKENS = Object.freeze([
|
|
|
185
185
|
why: 'chrome is a HOST-COMPOSITION decision (whether the experiment\'s own ' +
|
|
186
186
|
'control chrome DOM renders), never a per-experiment physics/render ' +
|
|
187
187
|
'parameter; forwarding it from an outer host URL into an embedded ' +
|
|
188
|
-
'iframe would reintroduce the hidden-experiment-chrome bug
|
|
189
|
-
'
|
|
188
|
+
'iframe would reintroduce the hidden-experiment-chrome bug (the GYM ' +
|
|
189
|
+
'must always show the ' +
|
|
190
190
|
'experiment\'s own full chrome, never chrome=canvas — see the ' +
|
|
191
191
|
'"WHEN should a host set chrome=canvas" doc above for the general ' +
|
|
192
192
|
'criterion, not just the GYM\'s specific answer to it)'
|
|
@@ -4,16 +4,18 @@
|
|
|
4
4
|
* project/index.js — the `./project` entry of BOTH packages: the specifier table, the link site and the
|
|
5
5
|
* project identity, re-exported from their owners (this file owns nothing).
|
|
6
6
|
*
|
|
7
|
-
* FRQTL_WEB_SPECIFIERS, libPathOf, importMapFor
|
|
8
|
-
*
|
|
7
|
+
* FRQTL_WEB_SPECIFIERS, libPathOf, importMapFor,
|
|
8
|
+
* pageImportMapFor specifiers.js
|
|
9
|
+
* linkProject, sketchProject, SKETCH_ENTRY link.js
|
|
9
10
|
* projectIdentity identity.js
|
|
10
11
|
*
|
|
11
12
|
* PROJECT_EXPORTS is this entry's export list; a conformance test holds the module's exports equal to
|
|
12
13
|
* it, and the package gate holds it equal across @descix/frqtl-web and @descix/frqtl-node.
|
|
13
14
|
*/
|
|
14
15
|
|
|
15
|
-
export const PROJECT_EXPORTS = Object.freeze(['FRQTL_WEB_SPECIFIERS', 'libPathOf', 'importMapFor', '
|
|
16
|
+
export const PROJECT_EXPORTS = Object.freeze(['FRQTL_WEB_SPECIFIERS', 'libPathOf', 'importMapFor', 'pageImportMapFor',
|
|
17
|
+
'linkProject', 'sketchProject', 'SKETCH_ENTRY', 'projectIdentity']);
|
|
16
18
|
|
|
17
|
-
export { FRQTL_WEB_SPECIFIERS, libPathOf, importMapFor } from './specifiers.js';
|
|
18
|
-
export { linkProject } from './link.js';
|
|
19
|
+
export { FRQTL_WEB_SPECIFIERS, libPathOf, importMapFor, pageImportMapFor } from './specifiers.js';
|
|
20
|
+
export { linkProject, sketchProject, SKETCH_ENTRY } from './link.js';
|
|
19
21
|
export { projectIdentity } from './identity.js';
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* link.js — THE link site: a project (one or more ES module files held as text, or a served folder)
|
|
5
5
|
* becomes imported modules, and its entry's default export is the scene.
|
|
6
6
|
*
|
|
7
|
-
* linkProject(project) → Promise<{ buildExperiment, files }> files: { path: Uint8Array } — the bytes linked
|
|
7
|
+
* linkProject(project) → Promise<{ buildExperiment, files, urls, project }> files: { path: Uint8Array } — the bytes linked
|
|
8
8
|
* project = { files: { 'sketch.js': text, 'parts/X.js': text, … }, entry, mint, bare? }
|
|
9
9
|
* | { url: '<served folder>/', entry, mint?, bare? }
|
|
10
10
|
* url absolute, or relative to the document's base URL in a page ('./'); ends in "/"
|
|
@@ -18,8 +18,12 @@
|
|
|
18
18
|
* lib-identity path (specifiers.js libPathOf) under THIS copy's package root
|
|
19
19
|
* (compat/package-root.js), so a project links against the very modules its boot loaded.
|
|
20
20
|
* A host whose modules are not served one file per URL (frqtl-web.min.js) passes its own.
|
|
21
|
-
* resolves { buildExperiment, files } — files is the project's BYTES by path (fetched, for a
|
|
22
|
-
* folder; the UTF-8 encoding of each text, for a file map), the input of projectIdentity
|
|
21
|
+
* resolves { buildExperiment, files, urls, project } — files is the project's BYTES by path (fetched, for a
|
|
22
|
+
* served folder; the UTF-8 encoding of each text, for a file map), the input of projectIdentity
|
|
23
|
+
* (identity.js); urls is each file's minted URL by path (a forked part registers its kind `from` that
|
|
24
|
+
* URL — lib/shim/project/parts-module.js maps it back to the path); project is the linked project as
|
|
25
|
+
* TEXT — { files: { path: text }, entry, mint, bare? } — what a facade holds and re-links
|
|
26
|
+
* (RecipeContext.build(linked)). A served folder's project is its decoded files.
|
|
23
27
|
*
|
|
24
28
|
* In a project, a file imports another project file by a RELATIVE specifier, and the package by
|
|
25
29
|
* `@descix/frqtl-web/...`; nothing else. Relative specifiers are rewritten to the minted URLs of the files
|
|
@@ -242,7 +246,8 @@ function _entryFunction(ns, entry) {
|
|
|
242
246
|
|
|
243
247
|
/**
|
|
244
248
|
* @param {object} project — see the file header
|
|
245
|
-
* @returns {Promise<{buildExperiment: function, files: Object<string, string
|
|
249
|
+
* @returns {Promise<{buildExperiment: function, files: Object<string, Uint8Array>, urls: Object<string, string>,
|
|
250
|
+
* project: {files: Object<string, string>, entry: string, mint: function, bare?: function}}>}
|
|
246
251
|
*/
|
|
247
252
|
export async function linkProject(project) {
|
|
248
253
|
if (!project || typeof project !== 'object') {
|
|
@@ -334,7 +339,9 @@ export async function linkProject(project) {
|
|
|
334
339
|
urls[p] = m.url;
|
|
335
340
|
}
|
|
336
341
|
const ns = await import(urls[entry]);
|
|
337
|
-
|
|
342
|
+
const held = { files: g.files, entry: entry, mint: mint };
|
|
343
|
+
if (project.bare !== undefined) { held.bare = project.bare; }
|
|
344
|
+
return { buildExperiment: _entryFunction(ns, entry), files: g.bytes, urls: Object.assign({}, urls), project: held };
|
|
338
345
|
} finally {
|
|
339
346
|
for (const m of minted) { if (typeof m.release === 'function') { m.release(); } }
|
|
340
347
|
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/* Copyright 2023-2026 by Essam Abadir */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* parts-module.js — THE mapping from a kind's defining module to the specifier a sketch imports it by.
|
|
5
|
+
*
|
|
6
|
+
* moduleOfKind(from, urls) → '@descix/frqtl-web/parts' | '<project path>' | null
|
|
7
|
+
* from the kind row's `from` (objects/kinds.js registerKind: the defining module's own URL)
|
|
8
|
+
* urls the minted URL of every project file, by path ({ 'parts/MyEmitter.js': 'blob:…' }) — what
|
|
9
|
+
* the last linkProject returned (link.js), or null when no project is linked
|
|
10
|
+
* A part file of THIS copy of the package (packageRoot() + 'frqtl/parts/<File>.js') is a package part:
|
|
11
|
+
* the barrel's specifier. A project file's minted URL is that file's project path. Anything else (an
|
|
12
|
+
* internal kind under frqtl/objects/, a module outside the package) has no importable specifier: null.
|
|
13
|
+
*
|
|
14
|
+
* importSpecifierOf(module, entry) → the specifier `entry` writes in an import line for `module`
|
|
15
|
+
* a package specifier as it is; a project path relative to the entry's own folder ('./parts/X.js').
|
|
16
|
+
*
|
|
17
|
+
* Consumers: the declared census (FrqtlApp: each runner.declared row's `module`) and the parts writer's
|
|
18
|
+
* one added import line (parts-writer.js, through RecipeContext.toSketch). Nobody else maps a `from`.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
import { packageRoot } from '../../frqtl/compat/package-root.js';
|
|
22
|
+
import { FRQTL_WEB_SPECIFIERS } from './specifiers.js';
|
|
23
|
+
|
|
24
|
+
const _BARREL = FRQTL_WEB_SPECIFIERS.find(function (r) { return r.libPath === 'frqtl/parts/index.js'; });
|
|
25
|
+
if (!_BARREL) {
|
|
26
|
+
throw new Error('[parts-module] FRQTL_WEB_SPECIFIERS has no row for the parts barrel (frqtl/parts/index.js). (FAIL-LOUD.)');
|
|
27
|
+
}
|
|
28
|
+
/** The specifier a package part is imported by: the parts barrel's row. */
|
|
29
|
+
export const PARTS_SPECIFIER = _BARREL.specifier;
|
|
30
|
+
|
|
31
|
+
const _PART_FILE = /^frqtl\/parts\/[A-Za-z_$][\w$]*\.js$/;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {string} from — a kind row's `from` URL
|
|
35
|
+
* @param {Object<string,string>|null} urls — project path → minted URL, from the last link
|
|
36
|
+
* @returns {string|null}
|
|
37
|
+
*/
|
|
38
|
+
export function moduleOfKind(from, urls) {
|
|
39
|
+
if (typeof from !== 'string' || !from) {
|
|
40
|
+
throw new TypeError('[parts-module] moduleOfKind(from, urls): from is the kind row\'s module URL (got ' +
|
|
41
|
+
JSON.stringify(from) + '). (FAIL-LOUD.)');
|
|
42
|
+
}
|
|
43
|
+
const root = packageRoot();
|
|
44
|
+
if (from.startsWith(root) && _PART_FILE.test(from.slice(root.length))) { return PARTS_SPECIFIER; }
|
|
45
|
+
if (urls) {
|
|
46
|
+
for (const p of Object.keys(urls)) { if (urls[p] === from) { return p; } }
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @param {string} module — moduleOfKind's answer (never null here)
|
|
53
|
+
* @param {string} entry — the importing file's project path (the sketch, 'sketch.js')
|
|
54
|
+
* @returns {string}
|
|
55
|
+
*/
|
|
56
|
+
export function importSpecifierOf(module, entry) {
|
|
57
|
+
if (typeof module !== 'string' || !module) {
|
|
58
|
+
throw new TypeError('[parts-module] importSpecifierOf(module, entry): a module specifier or project path. (FAIL-LOUD.)');
|
|
59
|
+
}
|
|
60
|
+
if (module.startsWith('@')) { return module; }
|
|
61
|
+
const from = entry.split('/');
|
|
62
|
+
from.pop();
|
|
63
|
+
const to = module.split('/');
|
|
64
|
+
while (from.length && to.length > 1 && from[0] === to[0]) { from.shift(); to.shift(); }
|
|
65
|
+
const up = from.map(function () { return '..'; });
|
|
66
|
+
return (up.length ? up.join('/') + '/' : './') + to.join('/');
|
|
67
|
+
}
|