eyeling 1.24.30 → 1.24.31
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/browser/eyeling.browser.js +283 -4
- package/examples/input/rdf-message-flow.trig +56 -105
- package/examples/output/rdf-message-flow.md +3 -3
- package/examples/rdf-message-flow.n3 +70 -49
- package/eyeling.js +283 -4
- package/lib/lexer.js +283 -4
- package/package.json +1 -1
- package/test/api.test.js +58 -0
package/lib/lexer.js
CHANGED
|
@@ -356,6 +356,24 @@ function stripQuotes(lex) {
|
|
|
356
356
|
// This keeps all downstream parsing/reasoning N3-only.
|
|
357
357
|
const LOG_NAME_OF_IRI = '<http://www.w3.org/2000/10/swap/log#nameOf>';
|
|
358
358
|
const RDF_REIFIES_IRI = '<http://www.w3.org/1999/02/22-rdf-syntax-ns#reifies>';
|
|
359
|
+
const RDF_TYPE_IRI = '<http://www.w3.org/1999/02/22-rdf-syntax-ns#type>';
|
|
360
|
+
const XSD_INTEGER_IRI = '<http://www.w3.org/2001/XMLSchema#integer>';
|
|
361
|
+
const EYMSG_NS = 'https://eyereasoner.github.io/eyeling/vocab/message#';
|
|
362
|
+
const EYMSG = Object.freeze({
|
|
363
|
+
RDFMessageStream: `<${EYMSG_NS}RDFMessageStream>`,
|
|
364
|
+
MessageEnvelope: `<${EYMSG_NS}MessageEnvelope>`,
|
|
365
|
+
envelope: `<${EYMSG_NS}envelope>`,
|
|
366
|
+
firstEnvelope: `<${EYMSG_NS}firstEnvelope>`,
|
|
367
|
+
lastEnvelope: `<${EYMSG_NS}lastEnvelope>`,
|
|
368
|
+
orderedEnvelopes: `<${EYMSG_NS}orderedEnvelopes>`,
|
|
369
|
+
messageCount: `<${EYMSG_NS}messageCount>`,
|
|
370
|
+
offset: `<${EYMSG_NS}offset>`,
|
|
371
|
+
nextEnvelope: `<${EYMSG_NS}nextEnvelope>`,
|
|
372
|
+
payloadGraph: `<${EYMSG_NS}payloadGraph>`,
|
|
373
|
+
payloadKind: `<${EYMSG_NS}payloadKind>`,
|
|
374
|
+
empty: `<${EYMSG_NS}empty>`,
|
|
375
|
+
nonEmpty: `<${EYMSG_NS}nonEmpty>`,
|
|
376
|
+
});
|
|
359
377
|
|
|
360
378
|
function normalizeRdfCompatibility(inputText) {
|
|
361
379
|
let text = String(inputText ?? '');
|
|
@@ -366,10 +384,11 @@ function normalizeRdfCompatibility(inputText) {
|
|
|
366
384
|
// plausible top-level TriG named graph block.
|
|
367
385
|
const hasTripleTerms = text.includes('<<');
|
|
368
386
|
const hasVersionDirective = /^\s*(?:@version|VERSION)\s+(["'])1\.2\1\s*\.?\s*(?:#.*)?$/im.test(text);
|
|
387
|
+
const hasMessageVersionDirective = /^\s*(?:@version|VERSION)\s+(["'])(?:1\.1|1\.2|1\.2-basic)-messages\1\s*\.?\s*(?:#.*)?$/im.test(text);
|
|
369
388
|
const hasNamedGraphCandidate = /(?:^|[.\r\n])\s*(?:GRAPH\s+)?(?:<[^>\r\n]*>|_:[A-Za-z][A-Za-z0-9_-]*|[A-Za-z][A-Za-z0-9_-]*:[^\s{};,.()[\]]*)\s*\{/m.test(text);
|
|
370
389
|
const hasAnnotationSyntax = /(?:^|\s)~\s*(?:<|_:[A-Za-z]|[A-Za-z][A-Za-z0-9_-]*:|\{\|)|\{\|/.test(text);
|
|
371
390
|
|
|
372
|
-
if (!hasTripleTerms && !hasVersionDirective && !hasNamedGraphCandidate && !hasAnnotationSyntax) return text;
|
|
391
|
+
if (!hasTripleTerms && !hasVersionDirective && !hasMessageVersionDirective && !hasNamedGraphCandidate && !hasAnnotationSyntax) return text;
|
|
373
392
|
|
|
374
393
|
function isWordChar(ch) {
|
|
375
394
|
return ch != null && /[A-Za-z0-9_:-]/.test(ch);
|
|
@@ -723,7 +742,7 @@ function normalizeRdfCompatibility(inputText) {
|
|
|
723
742
|
}
|
|
724
743
|
|
|
725
744
|
function stripVersionDirectives(s) {
|
|
726
|
-
return s.replace(/^\s*(?:@version|VERSION)\s+(["'])1\.2
|
|
745
|
+
return s.replace(/^\s*(?:@version|VERSION)\s+(["'])(?:1\.1|1\.2|1\.2-basic)(?:-messages)?\1\s*\.?\s*(?:#.*)?$/gim, '');
|
|
727
746
|
}
|
|
728
747
|
|
|
729
748
|
function skipWsAndComments(s, at) {
|
|
@@ -877,10 +896,270 @@ function normalizeRdfCompatibility(inputText) {
|
|
|
877
896
|
return out;
|
|
878
897
|
}
|
|
879
898
|
|
|
899
|
+
|
|
900
|
+
function isOnlyWhitespaceAndComments(s) {
|
|
901
|
+
return skipWsAndComments(s, 0) >= s.length;
|
|
902
|
+
}
|
|
903
|
+
|
|
904
|
+
|
|
905
|
+
function skipOldStyleDirective(s, at) {
|
|
906
|
+
let i = at;
|
|
907
|
+
while (i < s.length) {
|
|
908
|
+
const ch = s[i];
|
|
909
|
+
if (ch === '"' || ch === "'") {
|
|
910
|
+
i = readStringAt(s, i).end;
|
|
911
|
+
continue;
|
|
912
|
+
}
|
|
913
|
+
if (ch === '<') {
|
|
914
|
+
i = readIriAt(s, i).end;
|
|
915
|
+
continue;
|
|
916
|
+
}
|
|
917
|
+
if (ch === '#') {
|
|
918
|
+
while (i < s.length && s[i] !== '\n' && s[i] !== '\r') i += 1;
|
|
919
|
+
continue;
|
|
920
|
+
}
|
|
921
|
+
i += 1;
|
|
922
|
+
if (ch === '.') return i;
|
|
923
|
+
}
|
|
924
|
+
return i;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
function stripDirectivesAndCommentsForEmptiness(s) {
|
|
928
|
+
let out = '';
|
|
929
|
+
let i = 0;
|
|
930
|
+
let statementStart = true;
|
|
931
|
+
while (i < s.length) {
|
|
932
|
+
const ch = s[i];
|
|
933
|
+
if (ch === '"' || ch === "'") {
|
|
934
|
+
const str = readStringAt(s, i);
|
|
935
|
+
out += str.text;
|
|
936
|
+
i = str.end;
|
|
937
|
+
statementStart = false;
|
|
938
|
+
continue;
|
|
939
|
+
}
|
|
940
|
+
if (ch === '<') {
|
|
941
|
+
const iri = readIriAt(s, i);
|
|
942
|
+
out += iri.text;
|
|
943
|
+
i = iri.end;
|
|
944
|
+
statementStart = false;
|
|
945
|
+
continue;
|
|
946
|
+
}
|
|
947
|
+
if (ch === '#') {
|
|
948
|
+
while (i < s.length && s[i] !== '\n' && s[i] !== '\r') i += 1;
|
|
949
|
+
statementStart = true;
|
|
950
|
+
continue;
|
|
951
|
+
}
|
|
952
|
+
if (statementStart) {
|
|
953
|
+
const start = skipWsAndComments(s, i);
|
|
954
|
+
out += s.slice(i, start);
|
|
955
|
+
i = start;
|
|
956
|
+
if (startsWordAt(s, 'PREFIX', i) || startsWordAt(s, 'BASE', i) || startsWordAt(s, 'VERSION', i)) {
|
|
957
|
+
while (i < s.length && s[i] !== '\n' && s[i] !== '\r') i += 1;
|
|
958
|
+
statementStart = true;
|
|
959
|
+
continue;
|
|
960
|
+
}
|
|
961
|
+
if (s[i] === '@') {
|
|
962
|
+
const lower = s.slice(i, i + 9).toLowerCase();
|
|
963
|
+
if (lower.startsWith('@prefix') || lower.startsWith('@base') || lower.startsWith('@version')) {
|
|
964
|
+
i = skipOldStyleDirective(s, i);
|
|
965
|
+
statementStart = true;
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
}
|
|
970
|
+
out += ch;
|
|
971
|
+
if (ch === '.' || ch === '}' || ch === '\n' || ch === '\r') statementStart = true;
|
|
972
|
+
else if (!/\s/.test(ch)) statementStart = false;
|
|
973
|
+
i += 1;
|
|
974
|
+
}
|
|
975
|
+
return out;
|
|
976
|
+
}
|
|
977
|
+
|
|
978
|
+
function simpleHashText(s) {
|
|
979
|
+
let h = 0x811c9dc5;
|
|
980
|
+
for (let i = 0; i < s.length; i += 1) {
|
|
981
|
+
h ^= s.charCodeAt(i);
|
|
982
|
+
h = Math.imul(h, 0x01000193) >>> 0;
|
|
983
|
+
}
|
|
984
|
+
return h.toString(16).padStart(8, '0');
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
function rewriteMessageBlankLabels(s, messageIndex) {
|
|
988
|
+
let out = '';
|
|
989
|
+
let i = 0;
|
|
990
|
+
const prefix = `_:eyeling_m${String(messageIndex).padStart(3, '0')}_`;
|
|
991
|
+
while (i < s.length) {
|
|
992
|
+
const ch = s[i];
|
|
993
|
+
if (ch === '"' || ch === "'") {
|
|
994
|
+
const str = readStringAt(s, i);
|
|
995
|
+
out += str.text;
|
|
996
|
+
i = str.end;
|
|
997
|
+
continue;
|
|
998
|
+
}
|
|
999
|
+
if (ch === '<' && !s.startsWith('<<', i)) {
|
|
1000
|
+
const iri = readIriAt(s, i);
|
|
1001
|
+
out += iri.text;
|
|
1002
|
+
i = iri.end;
|
|
1003
|
+
continue;
|
|
1004
|
+
}
|
|
1005
|
+
if (ch === '#') {
|
|
1006
|
+
while (i < s.length) {
|
|
1007
|
+
const c = s[i++];
|
|
1008
|
+
out += c;
|
|
1009
|
+
if (c === '\n' || c === '\r') break;
|
|
1010
|
+
}
|
|
1011
|
+
continue;
|
|
1012
|
+
}
|
|
1013
|
+
if (s.startsWith('_:', i)) {
|
|
1014
|
+
let j = i + 2;
|
|
1015
|
+
while (j < s.length && !/\s/.test(s[j]) && !'{}[](),;.'.includes(s[j])) j += 1;
|
|
1016
|
+
const label = s.slice(i + 2, j);
|
|
1017
|
+
if (label) {
|
|
1018
|
+
out += prefix + label.replace(/[^A-Za-z0-9_]/g, '_');
|
|
1019
|
+
i = j;
|
|
1020
|
+
continue;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
out += ch;
|
|
1024
|
+
i += 1;
|
|
1025
|
+
}
|
|
1026
|
+
return out;
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
function findMessageDirectiveAt(s, at) {
|
|
1030
|
+
if (startsWordAt(s, 'MESSAGE', at)) return { start: at, end: at + 'MESSAGE'.length };
|
|
1031
|
+
if (s.slice(at, at + 8).toLowerCase() === '@message' && !isWordChar(s[at + 8])) {
|
|
1032
|
+
let end = at + 8;
|
|
1033
|
+
end = skipWsAndComments(s, end);
|
|
1034
|
+
if (s[end] === '.') end += 1;
|
|
1035
|
+
return { start: at, end };
|
|
1036
|
+
}
|
|
1037
|
+
return null;
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
function splitRdfMessageLog(s) {
|
|
1041
|
+
const chunks = [];
|
|
1042
|
+
let i = 0;
|
|
1043
|
+
let start = 0;
|
|
1044
|
+
let braceDepth = 0;
|
|
1045
|
+
let bracketDepth = 0;
|
|
1046
|
+
let parenDepth = 0;
|
|
1047
|
+
let statementStart = true;
|
|
1048
|
+
let sawDelimiter = false;
|
|
1049
|
+
|
|
1050
|
+
while (i < s.length) {
|
|
1051
|
+
const ch = s[i];
|
|
1052
|
+
if (ch === '"' || ch === "'") {
|
|
1053
|
+
i = readStringAt(s, i).end;
|
|
1054
|
+
statementStart = false;
|
|
1055
|
+
continue;
|
|
1056
|
+
}
|
|
1057
|
+
if (ch === '<' && !s.startsWith('<<', i)) {
|
|
1058
|
+
i = readIriAt(s, i).end;
|
|
1059
|
+
statementStart = false;
|
|
1060
|
+
continue;
|
|
1061
|
+
}
|
|
1062
|
+
if (ch === '#') {
|
|
1063
|
+
while (i < s.length && s[i] !== '\n' && s[i] !== '\r') i += 1;
|
|
1064
|
+
statementStart = true;
|
|
1065
|
+
continue;
|
|
1066
|
+
}
|
|
1067
|
+
if (statementStart && braceDepth === 0 && bracketDepth === 0 && parenDepth === 0) {
|
|
1068
|
+
const termStart = skipWsAndComments(s, i);
|
|
1069
|
+
const msg = findMessageDirectiveAt(s, termStart);
|
|
1070
|
+
if (msg) {
|
|
1071
|
+
chunks.push(s.slice(start, termStart));
|
|
1072
|
+
start = msg.end;
|
|
1073
|
+
i = msg.end;
|
|
1074
|
+
statementStart = true;
|
|
1075
|
+
sawDelimiter = true;
|
|
1076
|
+
continue;
|
|
1077
|
+
}
|
|
1078
|
+
if (termStart !== i) {
|
|
1079
|
+
i = termStart;
|
|
1080
|
+
continue;
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
if (ch === '{') braceDepth += 1;
|
|
1084
|
+
else if (ch === '}' && braceDepth > 0) braceDepth -= 1;
|
|
1085
|
+
else if (ch === '[') bracketDepth += 1;
|
|
1086
|
+
else if (ch === ']' && bracketDepth > 0) bracketDepth -= 1;
|
|
1087
|
+
else if (ch === '(') parenDepth += 1;
|
|
1088
|
+
else if (ch === ')' && parenDepth > 0) parenDepth -= 1;
|
|
1089
|
+
|
|
1090
|
+
if (ch === '.' && braceDepth === 0 && bracketDepth === 0 && parenDepth === 0) statementStart = true;
|
|
1091
|
+
else if (ch === '\n' || ch === '\r') statementStart = true;
|
|
1092
|
+
else if (!/\s/.test(ch)) statementStart = false;
|
|
1093
|
+
i += 1;
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
const tail = s.slice(start);
|
|
1097
|
+
if (!sawDelimiter || !isOnlyWhitespaceAndComments(tail)) chunks.push(tail);
|
|
1098
|
+
return chunks;
|
|
1099
|
+
}
|
|
1100
|
+
|
|
1101
|
+
function normalizeMessageChunk(chunk, messageIndex) {
|
|
1102
|
+
let body = String(chunk || '');
|
|
1103
|
+
if (hasTripleTerms || body.includes('<<')) body = convertTripleTerms(body);
|
|
1104
|
+
if (hasAnnotationSyntax || /(?:^|\s)~\s*(?:<|_:[A-Za-z]|[A-Za-z][A-Za-z0-9_-]*:|\{\|)|\{\|/.test(body)) {
|
|
1105
|
+
body = convertAnnotations(body);
|
|
1106
|
+
}
|
|
1107
|
+
body = normalizeNamedGraphs(body);
|
|
1108
|
+
body = rewriteMessageBlankLabels(body, messageIndex);
|
|
1109
|
+
return body.trim();
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
function messageChunkHasRdf(body) {
|
|
1113
|
+
return !isOnlyWhitespaceAndComments(stripDirectivesAndCommentsForEmptiness(body));
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
function normalizeRdfMessageLog(s) {
|
|
1117
|
+
const withoutVersion = stripVersionDirectives(s);
|
|
1118
|
+
const chunks = splitRdfMessageLog(withoutVersion);
|
|
1119
|
+
const hash = simpleHashText(s);
|
|
1120
|
+
const base = `urn:eyeling:message-log:${hash}`;
|
|
1121
|
+
const stream = `<${base}#stream>`;
|
|
1122
|
+
const envelopeIris = chunks.map((unused, idx) => `<${base}#m${String(idx + 1).padStart(3, '0')}>`);
|
|
1123
|
+
const payloadIris = chunks.map((unused, idx) => `<${base}#m${String(idx + 1).padStart(3, '0')}/payload>`);
|
|
1124
|
+
const out = [];
|
|
1125
|
+
|
|
1126
|
+
out.push(`${stream} ${RDF_TYPE_IRI} ${EYMSG.RDFMessageStream} .`);
|
|
1127
|
+
out.push(`${stream} ${EYMSG.messageCount} "${chunks.length}"^^${XSD_INTEGER_IRI} .`);
|
|
1128
|
+
if (envelopeIris.length) {
|
|
1129
|
+
out.push(`${stream} ${EYMSG.orderedEnvelopes} (${envelopeIris.join(' ')}) .`);
|
|
1130
|
+
out.push(`${stream} ${EYMSG.firstEnvelope} ${envelopeIris[0]} .`);
|
|
1131
|
+
out.push(`${stream} ${EYMSG.lastEnvelope} ${envelopeIris[envelopeIris.length - 1]} .`);
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
for (let idx = 0; idx < chunks.length; idx += 1) {
|
|
1135
|
+
const n = idx + 1;
|
|
1136
|
+
const envelope = envelopeIris[idx];
|
|
1137
|
+
const payload = payloadIris[idx];
|
|
1138
|
+
const body = normalizeMessageChunk(chunks[idx], n);
|
|
1139
|
+
const hasBody = messageChunkHasRdf(body);
|
|
1140
|
+
|
|
1141
|
+
out.push(`${stream} ${EYMSG.envelope} ${envelope} .`);
|
|
1142
|
+
out.push(`${envelope} ${RDF_TYPE_IRI} ${EYMSG.MessageEnvelope} .`);
|
|
1143
|
+
out.push(`${envelope} ${EYMSG.offset} "${n}"^^${XSD_INTEGER_IRI} .`);
|
|
1144
|
+
out.push(`${envelope} ${EYMSG.payloadKind} ${hasBody ? EYMSG.nonEmpty : EYMSG.empty} .`);
|
|
1145
|
+
if (idx + 1 < envelopeIris.length) out.push(`${envelope} ${EYMSG.nextEnvelope} ${envelopeIris[idx + 1]} .`);
|
|
1146
|
+
if (hasBody) {
|
|
1147
|
+
out.push(`${envelope} ${EYMSG.payloadGraph} ${payload} .`);
|
|
1148
|
+
out.push(`${payload} ${LOG_NAME_OF_IRI} {`);
|
|
1149
|
+
out.push(body);
|
|
1150
|
+
out.push(`} .`);
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
return out.join('\n') + '\n';
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
if (hasMessageVersionDirective) return normalizeRdfMessageLog(text);
|
|
1158
|
+
|
|
880
1159
|
if (hasTripleTerms) text = convertTripleTerms(text);
|
|
881
1160
|
if (hasAnnotationSyntax) text = convertAnnotations(text);
|
|
882
|
-
if (hasVersionDirective) text = stripVersionDirectives(text);
|
|
883
|
-
if (hasVersionDirective || hasNamedGraphCandidate) text = normalizeNamedGraphs(text);
|
|
1161
|
+
if (hasVersionDirective || hasMessageVersionDirective) text = stripVersionDirectives(text);
|
|
1162
|
+
if (hasVersionDirective || hasMessageVersionDirective || hasNamedGraphCandidate) text = normalizeNamedGraphs(text);
|
|
884
1163
|
return text;
|
|
885
1164
|
}
|
|
886
1165
|
|
package/package.json
CHANGED
package/test/api.test.js
CHANGED
|
@@ -2864,6 +2864,64 @@ PREFIX xsd: <http://www.w3.org/2001/XMLSchema#>
|
|
|
2864
2864
|
/:audit\s+\{[\s\S]*:workOrder\s+:basedOn\s+:factoryDataset\s*\.[\s\S]*\}/m,
|
|
2865
2865
|
],
|
|
2866
2866
|
},
|
|
2867
|
+
{
|
|
2868
|
+
name: 'RDF mode replays RDF 1.2 message logs into eymsg envelopes',
|
|
2869
|
+
opt: { proofComments: false, rdf: true },
|
|
2870
|
+
input: {
|
|
2871
|
+
sources: [
|
|
2872
|
+
{
|
|
2873
|
+
label: 'rules.n3',
|
|
2874
|
+
text: `@prefix : <http://example.org/msgtest#>.
|
|
2875
|
+
@prefix eymsg: <https://eyereasoner.github.io/eyeling/vocab/message#>.
|
|
2876
|
+
@prefix log: <http://www.w3.org/2000/10/swap/log#>.
|
|
2877
|
+
@prefix list: <http://www.w3.org/2000/10/swap/list#>.
|
|
2878
|
+
|
|
2879
|
+
{
|
|
2880
|
+
?S a eymsg:RDFMessageStream;
|
|
2881
|
+
eymsg:messageCount ?Count;
|
|
2882
|
+
eymsg:orderedEnvelopes ?Envelopes;
|
|
2883
|
+
eymsg:firstEnvelope ?First.
|
|
2884
|
+
?Envelopes list:length ?Len.
|
|
2885
|
+
?First eymsg:nextEnvelope ?Second.
|
|
2886
|
+
?Second eymsg:nextEnvelope ?Third;
|
|
2887
|
+
eymsg:payloadKind eymsg:empty.
|
|
2888
|
+
?First eymsg:payloadGraph ?P1.
|
|
2889
|
+
?P1 log:nameOf ?G1.
|
|
2890
|
+
?G1 log:includes { ?B1 :value 1. }.
|
|
2891
|
+
?Third eymsg:payloadGraph ?P3.
|
|
2892
|
+
?P3 log:nameOf ?G3.
|
|
2893
|
+
?G3 log:includes { ?B3 :value 2. }.
|
|
2894
|
+
} log:query {
|
|
2895
|
+
:result :messageCount ?Count;
|
|
2896
|
+
:listLength ?Len;
|
|
2897
|
+
:empty ?Second;
|
|
2898
|
+
:firstBlank ?B1;
|
|
2899
|
+
:thirdBlank ?B3.
|
|
2900
|
+
}.
|
|
2901
|
+
`,
|
|
2902
|
+
},
|
|
2903
|
+
{
|
|
2904
|
+
label: 'message-log.trig',
|
|
2905
|
+
text: `VERSION "1.2-messages"
|
|
2906
|
+
@prefix : <http://example.org/msgtest#> .
|
|
2907
|
+
_:b :value 1 .
|
|
2908
|
+
MESSAGE
|
|
2909
|
+
# empty message
|
|
2910
|
+
MESSAGE
|
|
2911
|
+
_:b :value 2 .
|
|
2912
|
+
`,
|
|
2913
|
+
},
|
|
2914
|
+
],
|
|
2915
|
+
},
|
|
2916
|
+
expect: [
|
|
2917
|
+
/:result\s+:messageCount\s+"3"\^\^xsd:integer\s*\./m,
|
|
2918
|
+
/:result\s+:listLength\s+3\s*\./m,
|
|
2919
|
+
/:result\s+:empty\s+<urn:eyeling:message-log:[0-9a-f]+#m002>\s*\./m,
|
|
2920
|
+
/:result\s+:firstBlank\s+_:src2_eyeling_m001_b\s*\./m,
|
|
2921
|
+
/:result\s+:thirdBlank\s+_:src2_eyeling_m003_b\s*\./m,
|
|
2922
|
+
],
|
|
2923
|
+
},
|
|
2924
|
+
|
|
2867
2925
|
{
|
|
2868
2926
|
name: 'API empty input returns empty output',
|
|
2869
2927
|
opt: { proofComments: false },
|