capdag 1.205.540 → 1.211.563
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/cap-fab-renderer.js +1 -1
- package/capdag.js +11 -0
- package/capdag.test.js +71 -71
- package/package.json +1 -1
package/cap-fab-renderer.js
CHANGED
|
@@ -2087,7 +2087,7 @@ function buildRunGraphData(data) {
|
|
|
2087
2087
|
// labels the anchor→entry edge on the first body.
|
|
2088
2088
|
//
|
|
2089
2089
|
// Without such a preceding sequence cap, the source itself is
|
|
2090
|
-
// already a list (e.g. `media:pdf;list` source_media_urn) and the
|
|
2090
|
+
// already a list (e.g. `media:ext=pdf;list` source_media_urn) and the
|
|
2091
2091
|
// ForEach iterates it directly.
|
|
2092
2092
|
let seqProducerStepIdx = -1;
|
|
2093
2093
|
let seqProducerStep = null;
|
package/capdag.js
CHANGED
|
@@ -6069,6 +6069,14 @@ function probeCartridgeCapGroups(entryPath) {
|
|
|
6069
6069
|
child.on('error', (e) => finish(new Error(`cartridge ${entryPath} spawn error: ${e.message}`)));
|
|
6070
6070
|
child.on('close', () => finish(new Error(`cartridge ${entryPath} HELLO failed: connection closed before receiving HELLO`)));
|
|
6071
6071
|
|
|
6072
|
+
// A cartridge that exits or closes its stdin before reading our HELLO
|
|
6073
|
+
// surfaces the broken pipe as an ASYNCHRONOUS 'error' event on the pipe
|
|
6074
|
+
// (EPIPE), not as a synchronous throw from write(). Without a listener,
|
|
6075
|
+
// Node treats that as an unhandled 'error' and aborts the whole host
|
|
6076
|
+
// process. Catch it here and route it through finish() so a single
|
|
6077
|
+
// misbehaving cartridge fails its own probe instead of killing discovery.
|
|
6078
|
+
child.stdin.on('error', (e) => finish(new Error(`cartridge ${entryPath} HELLO failed: ${e.message}`)));
|
|
6079
|
+
|
|
6072
6080
|
timer = setTimeout(() => finish(new Error(`cartridge ${entryPath} HELLO failed: timeout`)), 5000);
|
|
6073
6081
|
|
|
6074
6082
|
// Send our HELLO first (host side).
|
|
@@ -6120,6 +6128,9 @@ function probeCartridgeCapGroups(entryPath) {
|
|
|
6120
6128
|
buf = Buffer.concat([buf, chunk]);
|
|
6121
6129
|
tryParse();
|
|
6122
6130
|
});
|
|
6131
|
+
// Guard the read side too: an error on the child's stdout (e.g. the pipe
|
|
6132
|
+
// breaking mid-read) must not become an unhandled 'error' event.
|
|
6133
|
+
child.stdout.on('error', (e) => finish(new Error(`cartridge ${entryPath} HELLO failed: ${e.message}`)));
|
|
6123
6134
|
});
|
|
6124
6135
|
}
|
|
6125
6136
|
|
package/capdag.test.js
CHANGED
|
@@ -692,7 +692,7 @@ function test046_matchingSemanticsFallbackPattern() {
|
|
|
692
692
|
|
|
693
693
|
// TEST047: Matching semantics - thumbnail fallback with void input
|
|
694
694
|
function test047_matchingSemanticsThumbnailVoidInput() {
|
|
695
|
-
const cap = CapUrn.fromString('cap:in="media:void";generate-thumbnail;out="media:image;
|
|
695
|
+
const cap = CapUrn.fromString('cap:in="media:void";generate-thumbnail;out="media:ext=png;image;thumbnail"');
|
|
696
696
|
const request = CapUrn.fromString('cap:ext=pdf;in="media:void";generate-thumbnail;out="media:image"');
|
|
697
697
|
assert(cap.accepts(request), 'Void input cap should accept request; cap output conforms to less-specific request output');
|
|
698
698
|
}
|
|
@@ -727,25 +727,25 @@ function test050_matchingSemanticsDirectionMismatch() {
|
|
|
727
727
|
function test890_directionSemanticMatching() {
|
|
728
728
|
// Generic wildcard cap accepts specific pdf request
|
|
729
729
|
const genericCap = CapUrn.fromString(
|
|
730
|
-
'cap:in="media:";generate-thumbnail;out="media:image;
|
|
730
|
+
'cap:in="media:";generate-thumbnail;out="media:ext=png;image;thumbnail"'
|
|
731
731
|
);
|
|
732
732
|
const pdfRequest = CapUrn.fromString(
|
|
733
|
-
'cap:in="media:ext=pdf";generate-thumbnail;out="media:image;
|
|
733
|
+
'cap:in="media:ext=pdf";generate-thumbnail;out="media:ext=png;image;thumbnail"'
|
|
734
734
|
);
|
|
735
735
|
assert(genericCap.accepts(pdfRequest), 'Generic wildcard cap must accept pdf request');
|
|
736
736
|
|
|
737
737
|
// Also accepts epub
|
|
738
738
|
const epubRequest = CapUrn.fromString(
|
|
739
|
-
'cap:in="media:epub";generate-thumbnail;out="media:image;
|
|
739
|
+
'cap:in="media:ext=epub";generate-thumbnail;out="media:ext=png;image;thumbnail"'
|
|
740
740
|
);
|
|
741
741
|
assert(genericCap.accepts(epubRequest), 'Generic wildcard cap must accept epub request');
|
|
742
742
|
|
|
743
743
|
// Reverse: specific pdf cap does NOT accept generic bytes request
|
|
744
744
|
const pdfCap = CapUrn.fromString(
|
|
745
|
-
'cap:in="media:ext=pdf";generate-thumbnail;out="media:image;
|
|
745
|
+
'cap:in="media:ext=pdf";generate-thumbnail;out="media:ext=png;image;thumbnail"'
|
|
746
746
|
);
|
|
747
747
|
const genericRequest = CapUrn.fromString(
|
|
748
|
-
'cap:in="media:";generate-thumbnail;out="media:image;
|
|
748
|
+
'cap:in="media:";generate-thumbnail;out="media:ext=png;image;thumbnail"'
|
|
749
749
|
);
|
|
750
750
|
assert(!pdfCap.accepts(genericRequest), 'Specific pdf cap must NOT accept generic wildcard request');
|
|
751
751
|
|
|
@@ -754,7 +754,7 @@ function test890_directionSemanticMatching() {
|
|
|
754
754
|
|
|
755
755
|
// Output direction: cap producing more specific output satisfies less specific request
|
|
756
756
|
const specificOutCap = CapUrn.fromString(
|
|
757
|
-
'cap:in="media:";generate-thumbnail;out="media:image;
|
|
757
|
+
'cap:in="media:";generate-thumbnail;out="media:ext=png;image;thumbnail"'
|
|
758
758
|
);
|
|
759
759
|
const genericOutRequest = CapUrn.fromString(
|
|
760
760
|
'cap:in="media:";generate-thumbnail;out="media:image"'
|
|
@@ -767,7 +767,7 @@ function test890_directionSemanticMatching() {
|
|
|
767
767
|
'cap:in="media:";generate-thumbnail;out="media:image"'
|
|
768
768
|
);
|
|
769
769
|
const specificOutRequest = CapUrn.fromString(
|
|
770
|
-
'cap:in="media:";generate-thumbnail;out="media:image;
|
|
770
|
+
'cap:in="media:";generate-thumbnail;out="media:ext=png;image;thumbnail"'
|
|
771
771
|
);
|
|
772
772
|
assert(!genericOutCap.accepts(specificOutRequest),
|
|
773
773
|
'Generic output cap must NOT satisfy specific output request');
|
|
@@ -776,34 +776,34 @@ function test890_directionSemanticMatching() {
|
|
|
776
776
|
// TEST891: Semantic direction specificity — more constraints in
|
|
777
777
|
// either axis means a higher score under the truth-table-driven sum.
|
|
778
778
|
// media: (top, no tags) scores 0; each marker tag scores 2; each
|
|
779
|
-
// exact tag scores
|
|
779
|
+
// exact-value tag (e.g. ext=png) scores 4.
|
|
780
780
|
function test891_directionSemanticSpecificity() {
|
|
781
781
|
const genericCap = CapUrn.fromString(
|
|
782
|
-
'cap:in="media:";generate-thumbnail;out="media:image;
|
|
782
|
+
'cap:in="media:";generate-thumbnail;out="media:ext=png;image;thumbnail"'
|
|
783
783
|
);
|
|
784
784
|
const specificCap = CapUrn.fromString(
|
|
785
|
-
'cap:in="media:ext=pdf";generate-thumbnail;out="media:image;
|
|
785
|
+
'cap:in="media:ext=pdf";generate-thumbnail;out="media:ext=png;image;thumbnail"'
|
|
786
786
|
);
|
|
787
787
|
|
|
788
788
|
// generic:
|
|
789
|
-
// out=media:image;
|
|
789
|
+
// out=media:ext=png;image;thumbnail -> 4 (ext=png exact-value) + 2 + 2 = 8
|
|
790
790
|
// in=media: -> 0
|
|
791
791
|
// y: generate-thumbnail marker -> 2
|
|
792
|
-
// spec_C = 10000*
|
|
793
|
-
assertEqual(genericCap.specificity(), 10000*
|
|
794
|
-
'out=image
|
|
792
|
+
// spec_C = 10000*8 + 100*0 + 2 = 80002
|
|
793
|
+
assertEqual(genericCap.specificity(), 10000*8 + 100*0 + 2,
|
|
794
|
+
'out=ext=png(4)+image(2)+thumbnail(2)=8 + in=media:(0) + generate-thumbnail marker(2) = 80002');
|
|
795
795
|
// specific:
|
|
796
|
-
// out=media:image;
|
|
796
|
+
// out=media:ext=png;image;thumbnail -> 8
|
|
797
797
|
// in=media:ext=pdf -> 4 (ext=pdf is an exact-value tag, not a bare marker)
|
|
798
798
|
// y: generate-thumbnail marker -> 2
|
|
799
|
-
// spec_C = 10000*
|
|
800
|
-
assertEqual(specificCap.specificity(), 10000*
|
|
801
|
-
'out=image
|
|
799
|
+
// spec_C = 10000*8 + 100*4 + 2 = 80402
|
|
800
|
+
assertEqual(specificCap.specificity(), 10000*8 + 100*4 + 2,
|
|
801
|
+
'out=ext=png(4)+image(2)+thumbnail(2)=8 + in=ext=pdf(4) + generate-thumbnail marker(2) = 80402');
|
|
802
802
|
assert(specificCap.specificity() > genericCap.specificity(), 'pdf should be more specific');
|
|
803
803
|
|
|
804
804
|
// CapMatcher should prefer more specific
|
|
805
805
|
const pdfRequest = CapUrn.fromString(
|
|
806
|
-
'cap:in="media:ext=pdf";generate-thumbnail;out="media:image;
|
|
806
|
+
'cap:in="media:ext=pdf";generate-thumbnail;out="media:ext=png;image;thumbnail"'
|
|
807
807
|
);
|
|
808
808
|
const best = CapMatcher.findBestMatch([genericCap, specificCap], pdfRequest);
|
|
809
809
|
assert(best !== null, 'Should find a match');
|
|
@@ -1008,7 +1008,7 @@ function test075_accepts() {
|
|
|
1008
1008
|
function test076_specificity() {
|
|
1009
1009
|
const s1 = MediaUrn.fromString('media:');
|
|
1010
1010
|
const s2 = MediaUrn.fromString('media:ext=pdf');
|
|
1011
|
-
const s3 = MediaUrn.fromString('media:image;
|
|
1011
|
+
const s3 = MediaUrn.fromString('media:ext=png;image;thumbnail');
|
|
1012
1012
|
assert(s2.specificity() > s1.specificity(), 'pdf should be more specific than wildcard');
|
|
1013
1013
|
assert(s3.specificity() > s2.specificity(), 'image;png;thumbnail should be more specific than pdf');
|
|
1014
1014
|
}
|
|
@@ -1208,13 +1208,13 @@ function test109_extensionsWithMetadataAndValidation() {
|
|
|
1208
1208
|
function test110_multipleExtensions() {
|
|
1209
1209
|
const mediaDefs = [
|
|
1210
1210
|
{
|
|
1211
|
-
urn: 'media:image
|
|
1211
|
+
urn: 'media:ext=jpeg;image',
|
|
1212
1212
|
media_type: 'image/jpeg',
|
|
1213
1213
|
title: 'JPEG Image',
|
|
1214
1214
|
extensions: ['jpg', 'jpeg']
|
|
1215
1215
|
}
|
|
1216
1216
|
];
|
|
1217
|
-
const resolved = resolveMediaUrn('media:image
|
|
1217
|
+
const resolved = resolveMediaUrn('media:ext=jpeg;image', mediaDefs);
|
|
1218
1218
|
assertEqual(resolved.extensions.length, 2, 'Should have two extensions');
|
|
1219
1219
|
assertEqual(resolved.extensions[0], 'jpg', 'First extension should be jpg');
|
|
1220
1220
|
assertEqual(resolved.extensions[1], 'jpeg', 'Second extension should be jpeg');
|
|
@@ -1414,7 +1414,7 @@ function test0053_CapFabGetOutgoingConformsToMatching() {
|
|
|
1414
1414
|
assertEqual(outgoingFromBroad.length, 1, 'Exact URN must match');
|
|
1415
1415
|
|
|
1416
1416
|
// A totally unrelated URN must not match.
|
|
1417
|
-
const outgoingFromUnrelated = graph.getOutgoing('media:image
|
|
1417
|
+
const outgoingFromUnrelated = graph.getOutgoing('media:ext=png;image');
|
|
1418
1418
|
assertEqual(outgoingFromUnrelated.length, 0, 'Unrelated URN must not match');
|
|
1419
1419
|
}
|
|
1420
1420
|
|
|
@@ -1663,7 +1663,7 @@ function test312_allUrnBuildersProduceValidUrns() {
|
|
|
1663
1663
|
function test0059_JS_buildExtensionIndex() {
|
|
1664
1664
|
const mediaDefs = [
|
|
1665
1665
|
{ urn: 'media:ext=pdf', media_type: 'application/pdf', extensions: ['pdf'] },
|
|
1666
|
-
{ urn: 'media:image
|
|
1666
|
+
{ urn: 'media:ext=jpeg;image', media_type: 'image/jpeg', extensions: ['jpg', 'jpeg'] },
|
|
1667
1667
|
{ urn: 'media:fmt=json', media_type: 'application/json', extensions: ['json'] }
|
|
1668
1668
|
];
|
|
1669
1669
|
const index = buildExtensionIndex(mediaDefs);
|
|
@@ -1709,7 +1709,7 @@ function test0069_JS_mediaUrnsForExtension() {
|
|
|
1709
1709
|
function test0070_JS_getExtensionMappings() {
|
|
1710
1710
|
const mediaDefs = [
|
|
1711
1711
|
{ urn: 'media:ext=pdf', media_type: 'application/pdf', extensions: ['pdf'] },
|
|
1712
|
-
{ urn: 'media:image
|
|
1712
|
+
{ urn: 'media:ext=jpeg;image', media_type: 'image/jpeg', extensions: ['jpg', 'jpeg'] }
|
|
1713
1713
|
];
|
|
1714
1714
|
const mappings = getExtensionMappings(mediaDefs);
|
|
1715
1715
|
assert(Array.isArray(mappings), 'Should return an array');
|
|
@@ -2751,8 +2751,8 @@ async function test1878_bundledProviderWithoutBakedHashIsRejected() {
|
|
|
2751
2751
|
// TEST1312: is_image returns true only when image marker tag is present
|
|
2752
2752
|
function test1312_isImage() {
|
|
2753
2753
|
assert(MediaUrn.fromString(MEDIA_PNG).isImage(), 'MEDIA_PNG should be image');
|
|
2754
|
-
assert(MediaUrn.fromString('media:image;
|
|
2755
|
-
assert(MediaUrn.fromString('media:image
|
|
2754
|
+
assert(MediaUrn.fromString('media:ext=png;image;thumbnail').isImage(), 'media:ext=png;image;thumbnail should be image');
|
|
2755
|
+
assert(MediaUrn.fromString('media:ext=jpg;image').isImage(), 'media:ext=jpg;image should be image');
|
|
2756
2756
|
// Non-image types
|
|
2757
2757
|
assert(!MediaUrn.fromString(MEDIA_PDF).isImage(), 'MEDIA_PDF should not be image');
|
|
2758
2758
|
assert(!MediaUrn.fromString(MEDIA_STRING).isImage(), 'MEDIA_STRING should not be image');
|
|
@@ -2764,7 +2764,7 @@ function test1312_isImage() {
|
|
|
2764
2764
|
function test1313_isAudio() {
|
|
2765
2765
|
assert(MediaUrn.fromString(MEDIA_AUDIO).isAudio(), 'MEDIA_AUDIO should be audio');
|
|
2766
2766
|
assert(MediaUrn.fromString(MEDIA_AUDIO_SPEECH).isAudio(), 'MEDIA_AUDIO_SPEECH should be audio');
|
|
2767
|
-
assert(MediaUrn.fromString('media:audio;mp3').isAudio(), 'media:audio;mp3 should be audio');
|
|
2767
|
+
assert(MediaUrn.fromString('media:audio;ext=mp3').isAudio(), 'media:audio;ext=mp3 should be audio');
|
|
2768
2768
|
// Non-audio types
|
|
2769
2769
|
assert(!MediaUrn.fromString(MEDIA_VIDEO).isAudio(), 'MEDIA_VIDEO should not be audio');
|
|
2770
2770
|
assert(!MediaUrn.fromString(MEDIA_PNG).isAudio(), 'MEDIA_PNG should not be audio');
|
|
@@ -2774,7 +2774,7 @@ function test1313_isAudio() {
|
|
|
2774
2774
|
// TEST1314: is_video returns true only when video marker tag is present
|
|
2775
2775
|
function test1314_isVideo() {
|
|
2776
2776
|
assert(MediaUrn.fromString(MEDIA_VIDEO).isVideo(), 'MEDIA_VIDEO should be video');
|
|
2777
|
-
assert(MediaUrn.fromString('media:video
|
|
2777
|
+
assert(MediaUrn.fromString('media:ext=mp4;video').isVideo(), 'media:ext=mp4;video should be video');
|
|
2778
2778
|
// Non-video types
|
|
2779
2779
|
assert(!MediaUrn.fromString(MEDIA_AUDIO).isVideo(), 'MEDIA_AUDIO should not be video');
|
|
2780
2780
|
assert(!MediaUrn.fromString(MEDIA_PNG).isVideo(), 'MEDIA_PNG should not be video');
|
|
@@ -3197,7 +3197,7 @@ function test653_invalidEffectNoneDeclarationRejected() {
|
|
|
3197
3197
|
// TEST654: effect=none preserves runtime media identity.
|
|
3198
3198
|
function test654_effectNonePreservesRuntimeMedia() {
|
|
3199
3199
|
const decimate = CapUrn.fromString('cap:decimate-sequence;effect=none');
|
|
3200
|
-
const png = MediaUrn.fromString('media:image
|
|
3200
|
+
const png = MediaUrn.fromString('media:ext=png;image');
|
|
3201
3201
|
const pdf = MediaUrn.fromString('media:ext=pdf');
|
|
3202
3202
|
assertEqual(decimate.inferRuntimeOutputMedia(png).toString(), png.toString(), 'effect=none should preserve png');
|
|
3203
3203
|
assertEqual(decimate.inferRuntimeOutputMedia(pdf).toString(), pdf.toString(), 'effect=none should preserve pdf');
|
|
@@ -3206,7 +3206,7 @@ function test654_effectNonePreservesRuntimeMedia() {
|
|
|
3206
3206
|
// TEST655: default effect=declared does not preserve runtime refinements.
|
|
3207
3207
|
function test655_effectDeclaredUsesDeclaredOutput() {
|
|
3208
3208
|
const resize = CapUrn.fromString('cap:in=media:image;out=media:image;resize');
|
|
3209
|
-
const png = MediaUrn.fromString('media:image;
|
|
3209
|
+
const png = MediaUrn.fromString('media:ext=png;image;width=4000');
|
|
3210
3210
|
assertEqual(
|
|
3211
3211
|
resize.inferRuntimeOutputMedia(png).toString(),
|
|
3212
3212
|
'media:image',
|
|
@@ -3303,7 +3303,7 @@ function test0096_Machine_fanOut() {
|
|
|
3303
3303
|
const g = Machine.fromString(
|
|
3304
3304
|
'[meta cap:in="media:ext=pdf";extract-metadata;out="media:enc=utf-8;file-metadata;record"]' +
|
|
3305
3305
|
'[outline cap:in="media:ext=pdf";extract-outline;out="media:document-outline;enc=utf-8;record"]' +
|
|
3306
|
-
'[thumb cap:in="media:ext=pdf";generate-thumbnail;out="media:image;
|
|
3306
|
+
'[thumb cap:in="media:ext=pdf";generate-thumbnail;out="media:ext=png;image;thumbnail"]' +
|
|
3307
3307
|
'[doc -> meta -> metadata]' +
|
|
3308
3308
|
'[doc -> outline -> outline_data]' +
|
|
3309
3309
|
'[doc -> thumb -> thumbnail]'
|
|
@@ -3319,9 +3319,9 @@ function test0096_Machine_fanOut() {
|
|
|
3319
3319
|
// TEST0097: Machine fan in secondary assigned by prior wiring
|
|
3320
3320
|
function test0097_Machine_fanInSecondaryAssignedByPriorWiring() {
|
|
3321
3321
|
const g = Machine.fromString(
|
|
3322
|
-
'[thumb cap:in="media:ext=pdf";generate-thumbnail;out="media:image;
|
|
3322
|
+
'[thumb cap:in="media:ext=pdf";generate-thumbnail;out="media:ext=png;image;thumbnail"]' +
|
|
3323
3323
|
'[model_dl cap:in="media:enc=utf-8;model-spec";download;out="media:enc=utf-8;model-spec"]' +
|
|
3324
|
-
'[describe cap:in="media:image
|
|
3324
|
+
'[describe cap:in="media:ext=png;image";describe-image;out="media:enc=utf-8;image-description"]' +
|
|
3325
3325
|
'[doc -> thumb -> thumbnail]' +
|
|
3326
3326
|
'[spec_input -> model_dl -> model_spec]' +
|
|
3327
3327
|
'[(thumbnail, model_spec) -> describe -> description]'
|
|
@@ -3333,12 +3333,12 @@ function test0097_Machine_fanInSecondaryAssignedByPriorWiring() {
|
|
|
3333
3333
|
// TEST0098: Machine fan in secondary unassigned gets wildcard
|
|
3334
3334
|
function test0098_Machine_fanInSecondaryUnassignedGetsWildcard() {
|
|
3335
3335
|
const g = Machine.fromString(
|
|
3336
|
-
'[describe cap:in="media:image
|
|
3336
|
+
'[describe cap:in="media:ext=png;image";describe-image;out="media:enc=utf-8;image-description"]\n' +
|
|
3337
3337
|
'[(thumbnail, model_spec) -> describe -> description]'
|
|
3338
3338
|
);
|
|
3339
3339
|
assertEqual(g.edges().length, 1);
|
|
3340
3340
|
assertEqual(g.edges()[0].sources.length, 2);
|
|
3341
|
-
assertEqual(g.edges()[0].sources[0].toString(), 'media:image
|
|
3341
|
+
assertEqual(g.edges()[0].sources[0].toString(), 'media:ext=png;image');
|
|
3342
3342
|
assertEqual(g.edges()[0].sources[1].toString(), 'media:');
|
|
3343
3343
|
}
|
|
3344
3344
|
|
|
@@ -3376,7 +3376,7 @@ function test0114_Machine_conflictingMediaTypesFail() {
|
|
|
3376
3376
|
assertThrowsWithCode(
|
|
3377
3377
|
() => Machine.fromString(
|
|
3378
3378
|
'[cap1 cap:in="media:enc=utf-8;ext=txt";a;out="media:ext=pdf"]' +
|
|
3379
|
-
'[cap2 cap:in="media:audio;wav";b;out="media:enc=utf-8;ext=txt"]' +
|
|
3379
|
+
'[cap2 cap:in="media:audio;ext=wav";b;out="media:enc=utf-8;ext=txt"]' +
|
|
3380
3380
|
'[src -> cap1 -> mid]' +
|
|
3381
3381
|
'[mid -> cap2 -> dst]'
|
|
3382
3382
|
),
|
|
@@ -3463,9 +3463,9 @@ function test0123_Machine_lineBasedLoop() {
|
|
|
3463
3463
|
// TEST0124: Machine line based fan in
|
|
3464
3464
|
function test0124_Machine_lineBasedFanIn() {
|
|
3465
3465
|
const g = Machine.fromString(
|
|
3466
|
-
'thumb cap:in="media:ext=pdf";generate-thumbnail;out="media:image;
|
|
3466
|
+
'thumb cap:in="media:ext=pdf";generate-thumbnail;out="media:ext=png;image;thumbnail"\n' +
|
|
3467
3467
|
'model_dl cap:in="media:enc=utf-8;model-spec";download;out="media:enc=utf-8;model-spec"\n' +
|
|
3468
|
-
'describe cap:in="media:image
|
|
3468
|
+
'describe cap:in="media:ext=png;image";describe-image;out="media:enc=utf-8;image-description"\n' +
|
|
3469
3469
|
'doc -> thumb -> thumbnail\n' +
|
|
3470
3470
|
'spec_input -> model_dl -> model_spec\n' +
|
|
3471
3471
|
'(thumbnail, model_spec) -> describe -> description'
|
|
@@ -3861,7 +3861,7 @@ function test0152_Machine_roundtripFanOut() {
|
|
|
3861
3861
|
const original = new Machine([
|
|
3862
3862
|
mkEdge('media:ext=pdf', 'cap:in="media:ext=pdf";extract-metadata;out="media:enc=utf-8;file-metadata;record"', 'media:enc=utf-8;file-metadata;record'),
|
|
3863
3863
|
mkEdge('media:ext=pdf', 'cap:in="media:ext=pdf";extract-outline;out="media:document-outline;enc=utf-8;record"', 'media:document-outline;enc=utf-8;record'),
|
|
3864
|
-
mkEdge('media:ext=pdf', 'cap:in="media:ext=pdf";generate-thumbnail;out="media:image;
|
|
3864
|
+
mkEdge('media:ext=pdf', 'cap:in="media:ext=pdf";generate-thumbnail;out="media:ext=png;image;thumbnail"', 'media:ext=png;image;thumbnail'),
|
|
3865
3865
|
]);
|
|
3866
3866
|
const notation = original.toMachineNotation();
|
|
3867
3867
|
const reparsed = Machine.fromString(notation);
|
|
@@ -4137,7 +4137,7 @@ function test0177_Machine_parseMachineWithAST_multilinePositions() {
|
|
|
4137
4137
|
// TEST0178: Machine parse machine with a s t fan in source locations
|
|
4138
4138
|
function test0178_Machine_parseMachineWithAST_fanInSourceLocations() {
|
|
4139
4139
|
const input = [
|
|
4140
|
-
'[describe cap:in="media:image
|
|
4140
|
+
'[describe cap:in="media:ext=png;image";describe-image;out="media:enc=utf-8;image-description"]',
|
|
4141
4141
|
'[(thumbnail, model_spec) -> describe -> description]'
|
|
4142
4142
|
].join('\n');
|
|
4143
4143
|
const result = parseMachineWithAST(input);
|
|
@@ -4259,7 +4259,7 @@ function test0186_Machine_toMermaid_emptyGraph() {
|
|
|
4259
4259
|
// TEST0187: Machine to mermaid fan in
|
|
4260
4260
|
function test0187_Machine_toMermaid_fanIn() {
|
|
4261
4261
|
const machine = Machine.fromString(
|
|
4262
|
-
'[describe cap:in="media:image
|
|
4262
|
+
'[describe cap:in="media:ext=png;image";describe-image;out="media:enc=utf-8;image-description"]' +
|
|
4263
4263
|
'[(thumbnail, model_spec) -> describe -> description]'
|
|
4264
4264
|
);
|
|
4265
4265
|
const mermaid = machine.toMermaid();
|
|
@@ -4272,7 +4272,7 @@ function test0187_Machine_toMermaid_fanIn() {
|
|
|
4272
4272
|
function test0188_Machine_toMermaid_fanOut() {
|
|
4273
4273
|
const input = [
|
|
4274
4274
|
'[meta cap:in="media:ext=pdf";extract-metadata;out="media:enc=utf-8;file-metadata;record"]',
|
|
4275
|
-
'[thumb cap:in="media:ext=pdf";generate-thumbnail;out="media:image;
|
|
4275
|
+
'[thumb cap:in="media:ext=pdf";generate-thumbnail;out="media:ext=png;image;thumbnail"]',
|
|
4276
4276
|
'[doc -> meta -> metadata]',
|
|
4277
4277
|
'[doc -> thumb -> thumbnail]'
|
|
4278
4278
|
].join('');
|
|
@@ -4646,10 +4646,10 @@ function test0207_Renderer_classifyStrandCapSteps_capFlags() {
|
|
|
4646
4646
|
// prevForEach=true; cap3 should have nextCollect=true; cap2 should
|
|
4647
4647
|
// have neither.
|
|
4648
4648
|
const steps = [
|
|
4649
|
-
makeForEachStep('media:pdf;list'),
|
|
4650
|
-
makeCapStep('cap:in="media:ext=pdf";a;out="media:image
|
|
4651
|
-
makeCapStep('cap:in="media:image
|
|
4652
|
-
makeCapStep('cap:in="media:jpg";c;out="media:ext=txt"', 'c', 'media:jpg', 'media:ext=txt', false, false),
|
|
4649
|
+
makeForEachStep('media:ext=pdf;list'),
|
|
4650
|
+
makeCapStep('cap:in="media:ext=pdf";a;out="media:ext=png;image"', 'a', 'media:ext=pdf', 'media:ext=png;image', false, false),
|
|
4651
|
+
makeCapStep('cap:in="media:ext=png;image";b;out="media:ext=jpg"', 'b', 'media:ext=png;image', 'media:ext=jpg', false, false),
|
|
4652
|
+
makeCapStep('cap:in="media:ext=jpg";c;out="media:ext=txt"', 'c', 'media:ext=jpg', 'media:ext=txt', false, false),
|
|
4653
4653
|
makeCollectStep('media:ext=txt'),
|
|
4654
4654
|
];
|
|
4655
4655
|
const { capStepIndices, capFlags } = rendererClassifyStrandCapSteps(steps);
|
|
@@ -4757,15 +4757,15 @@ function test0211_Renderer_buildStrandGraphData_foreachCollectSpan() {
|
|
|
4757
4757
|
// labels on cap edges — they're distinct processing units in the
|
|
4758
4758
|
// plan. This mirrors capdag's plan_builder.rs exactly.
|
|
4759
4759
|
const payload = withMediaDisplayNames({
|
|
4760
|
-
source_media_urn: 'media:pdf;list',
|
|
4760
|
+
source_media_urn: 'media:ext=pdf;list',
|
|
4761
4761
|
target_media_urn: 'media:txt;list',
|
|
4762
4762
|
steps: [
|
|
4763
|
-
makeForEachStep('media:pdf;list'),
|
|
4763
|
+
makeForEachStep('media:ext=pdf;list'),
|
|
4764
4764
|
makeCapStep('cap:in="media:ext=pdf";extract;out="media:ext=txt"', 'extract', 'media:ext=pdf', 'media:ext=txt', false, false),
|
|
4765
4765
|
makeCollectStep('media:ext=txt'),
|
|
4766
4766
|
],
|
|
4767
4767
|
}, {
|
|
4768
|
-
'media:pdf;list': 'PDF List',
|
|
4768
|
+
'media:ext=pdf;list': 'PDF List',
|
|
4769
4769
|
'media:ext=txt': 'Plain Text',
|
|
4770
4770
|
'media:txt;list': 'Text List',
|
|
4771
4771
|
});
|
|
@@ -4905,15 +4905,15 @@ function test0215_Renderer_collapseStrand_singleCapBodyKeepsCapOwnLabel() {
|
|
|
4905
4905
|
// with the entry edge labeled "extract" and an unlabeled
|
|
4906
4906
|
// connector bridge to the output.
|
|
4907
4907
|
const payload = withMediaDisplayNames({
|
|
4908
|
-
source_media_urn: 'media:pdf;list',
|
|
4908
|
+
source_media_urn: 'media:ext=pdf;list',
|
|
4909
4909
|
target_media_urn: 'media:txt;list',
|
|
4910
4910
|
steps: [
|
|
4911
|
-
makeForEachStep('media:pdf;list'),
|
|
4911
|
+
makeForEachStep('media:ext=pdf;list'),
|
|
4912
4912
|
makeCapStep('cap:in="media:ext=pdf";extract;out="media:ext=txt"', 'extract', 'media:ext=pdf', 'media:ext=txt', false, false),
|
|
4913
4913
|
makeCollectStep('media:ext=txt'),
|
|
4914
4914
|
],
|
|
4915
4915
|
}, {
|
|
4916
|
-
'media:pdf;list': 'PDF List',
|
|
4916
|
+
'media:ext=pdf;list': 'PDF List',
|
|
4917
4917
|
'media:ext=txt': 'Plain Text',
|
|
4918
4918
|
'media:txt;list': 'Text List',
|
|
4919
4919
|
});
|
|
@@ -5209,12 +5209,12 @@ function test0223_Renderer_buildRunGraphData_pagesSuccessesAndFailures() {
|
|
|
5209
5209
|
// Show-more nodes: one for 3 hidden successes, one for 2 hidden
|
|
5210
5210
|
// failures.
|
|
5211
5211
|
const strand = {
|
|
5212
|
-
source_media_urn: 'media:pdf;list',
|
|
5212
|
+
source_media_urn: 'media:ext=pdf;list',
|
|
5213
5213
|
target_media_urn: 'media:ext=txt',
|
|
5214
5214
|
steps: [
|
|
5215
|
-
makeForEachStep('media:pdf;list'),
|
|
5216
|
-
makeCapStep('cap:in="media:ext=pdf";a;out="media:image
|
|
5217
|
-
makeCapStep('cap:in="media:image
|
|
5215
|
+
makeForEachStep('media:ext=pdf;list'),
|
|
5216
|
+
makeCapStep('cap:in="media:ext=pdf";a;out="media:ext=png;image"', 'a', 'media:ext=pdf', 'media:ext=png;image', false, false),
|
|
5217
|
+
makeCapStep('cap:in="media:ext=png;image";b;out="media:ext=txt"', 'b', 'media:ext=png;image', 'media:ext=txt', false, false),
|
|
5218
5218
|
makeCollectStep('media:ext=txt'),
|
|
5219
5219
|
],
|
|
5220
5220
|
};
|
|
@@ -5230,16 +5230,16 @@ function test0223_Renderer_buildRunGraphData_pagesSuccessesAndFailures() {
|
|
|
5230
5230
|
saved_paths: [],
|
|
5231
5231
|
total_bytes: 0,
|
|
5232
5232
|
duration_ms: 0,
|
|
5233
|
-
failed_cap: 'cap:in="media:image
|
|
5233
|
+
failed_cap: 'cap:in="media:ext=png;image";b;out="media:ext=txt"',
|
|
5234
5234
|
error: 'oom',
|
|
5235
5235
|
});
|
|
5236
5236
|
}
|
|
5237
5237
|
const payload = {
|
|
5238
5238
|
resolved_strand: strand,
|
|
5239
5239
|
media_display_names: {
|
|
5240
|
-
'media:pdf;list': 'PDF List',
|
|
5240
|
+
'media:ext=pdf;list': 'PDF List',
|
|
5241
5241
|
'media:ext=pdf': 'PDF',
|
|
5242
|
-
'media:image
|
|
5242
|
+
'media:ext=png;image': 'PNG',
|
|
5243
5243
|
'media:ext=txt': 'Text',
|
|
5244
5244
|
},
|
|
5245
5245
|
body_outcomes: outcomes,
|
|
@@ -5276,10 +5276,10 @@ function test0224_Renderer_buildRunGraphData_failureWithoutFailedCapRendersFullT
|
|
|
5276
5276
|
// Strand [ForEach, Cap, Collect] → body has 1 cap. Each body
|
|
5277
5277
|
// replica emits 1 entry node + 1 body cap node = 2 nodes.
|
|
5278
5278
|
const strand = {
|
|
5279
|
-
source_media_urn: 'media:pdf;list',
|
|
5279
|
+
source_media_urn: 'media:ext=pdf;list',
|
|
5280
5280
|
target_media_urn: 'media:ext=txt',
|
|
5281
5281
|
steps: [
|
|
5282
|
-
makeForEachStep('media:pdf;list'),
|
|
5282
|
+
makeForEachStep('media:ext=pdf;list'),
|
|
5283
5283
|
makeCapStep('cap:in="media:ext=pdf";a;out="media:ext=txt"', 'a', 'media:ext=pdf', 'media:ext=txt', false, false),
|
|
5284
5284
|
makeCollectStep('media:ext=txt'),
|
|
5285
5285
|
],
|
|
@@ -5287,7 +5287,7 @@ function test0224_Renderer_buildRunGraphData_failureWithoutFailedCapRendersFullT
|
|
|
5287
5287
|
const payload = {
|
|
5288
5288
|
resolved_strand: strand,
|
|
5289
5289
|
media_display_names: {
|
|
5290
|
-
'media:pdf;list': 'PDF List',
|
|
5290
|
+
'media:ext=pdf;list': 'PDF List',
|
|
5291
5291
|
'media:ext=pdf': 'PDF',
|
|
5292
5292
|
'media:ext=txt': 'Text',
|
|
5293
5293
|
},
|
|
@@ -5560,10 +5560,10 @@ function test0229_Renderer_buildRunGraphData_closedForeachSuccessMergesAtCollect
|
|
|
5560
5560
|
// Actually simpler: [ForEach, Cap_a, Collect] with source=list
|
|
5561
5561
|
// and target=list.
|
|
5562
5562
|
const strand = {
|
|
5563
|
-
source_media_urn: 'media:pdf;list',
|
|
5563
|
+
source_media_urn: 'media:ext=pdf;list',
|
|
5564
5564
|
target_media_urn: 'media:txt;list',
|
|
5565
5565
|
steps: [
|
|
5566
|
-
makeForEachStep('media:pdf;list'),
|
|
5566
|
+
makeForEachStep('media:ext=pdf;list'),
|
|
5567
5567
|
makeCapStep('cap:in="media:ext=pdf";extract;out="media:ext=txt"', 'extract', 'media:ext=pdf', 'media:ext=txt', false, false),
|
|
5568
5568
|
makeCollectStep('media:ext=txt'),
|
|
5569
5569
|
],
|
|
@@ -5571,7 +5571,7 @@ function test0229_Renderer_buildRunGraphData_closedForeachSuccessMergesAtCollect
|
|
|
5571
5571
|
const payload = {
|
|
5572
5572
|
resolved_strand: strand,
|
|
5573
5573
|
media_display_names: {
|
|
5574
|
-
'media:pdf;list': 'PDF List',
|
|
5574
|
+
'media:ext=pdf;list': 'PDF List',
|
|
5575
5575
|
'media:ext=pdf': 'PDF',
|
|
5576
5576
|
'media:ext=txt': 'Text',
|
|
5577
5577
|
'media:txt;list': 'Text List',
|
|
@@ -5835,18 +5835,18 @@ function test0238_Renderer_buildResolvedMachineGraphData_fanInProducesEdgePerAss
|
|
|
5835
5835
|
strands: [
|
|
5836
5836
|
{
|
|
5837
5837
|
nodes: [
|
|
5838
|
-
{ id: 'n0', urn: 'media:image
|
|
5838
|
+
{ id: 'n0', urn: 'media:ext=png;image', title: 'PNG Image' },
|
|
5839
5839
|
{ id: 'n1', urn: 'media:enc=utf-8;model-spec', title: 'Model Spec' },
|
|
5840
5840
|
{ id: 'n2', urn: 'media:enc=utf-8;image-description', title: 'Image Description' },
|
|
5841
5841
|
],
|
|
5842
5842
|
edges: [
|
|
5843
5843
|
{
|
|
5844
5844
|
alias: 'edge_0',
|
|
5845
|
-
cap_urn: 'cap:in=media:image;
|
|
5845
|
+
cap_urn: 'cap:in="media:ext=png;image";describe-image;out="media:enc=utf-8;image-description"',
|
|
5846
5846
|
title: 'Describe Image',
|
|
5847
5847
|
is_loop: false,
|
|
5848
5848
|
assignment: [
|
|
5849
|
-
{ cap_arg_media_urn: 'media:image
|
|
5849
|
+
{ cap_arg_media_urn: 'media:ext=png;image', source_node: 'n0' },
|
|
5850
5850
|
{ cap_arg_media_urn: 'media:enc=utf-8;model-spec', source_node: 'n1' },
|
|
5851
5851
|
],
|
|
5852
5852
|
target_node: 'n2',
|
|
@@ -5945,7 +5945,7 @@ function test0240_Renderer_buildResolvedMachineGraphData_duplicateNodeIdAcrossSt
|
|
|
5945
5945
|
output_anchor_nodes: ['n0'],
|
|
5946
5946
|
},
|
|
5947
5947
|
{
|
|
5948
|
-
nodes: [{ id: 'n0', urn: 'media:html', title: 'HTML' }],
|
|
5948
|
+
nodes: [{ id: 'n0', urn: 'media:ext=html', title: 'HTML' }],
|
|
5949
5949
|
edges: [],
|
|
5950
5950
|
input_anchor_nodes: ['n0'],
|
|
5951
5951
|
output_anchor_nodes: ['n0'],
|
package/package.json
CHANGED