Skip to content

Commit a5d4fb3

Browse files
gkelloggdavidlehn
authored andcommitted
Wildcard matching on @id and other requireAll semantics
1 parent 73e798e commit a5d4fb3

File tree

3 files changed

+87
-97
lines changed

3 files changed

+87
-97
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
- Changes in object embedding.
2020
- Better support for graph framing.
2121
- Better frame validation.
22+
- Wildcard matching on `@id` and other requireAll semantics.
2223

2324
### Changed
2425
- Keep term definitions mapping to null so they may be protected.

lib/frame.js

Lines changed: 86 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -532,111 +532,106 @@ function _filterSubject(state, subject, frame, flags) {
532532
const nodeValues = util.getValues(subject, key);
533533
const isEmpty = util.getValues(frame, key).length === 0;
534534

535-
if(isKeyword(key)) {
536-
// skip non-@id and non-@type
537-
if(key !== '@id' && key !== '@type') {
538-
continue;
535+
if(key === '@id') {
536+
// match on no @id or any matching @id, including wildcard
537+
if(types.isEmptyObject(frame['@id'][0] || {})) {
538+
matchThis = true;
539+
} else if(frame['@id'].length >= 0) {
540+
matchThis = frame['@id'].includes(nodeValues[0]);
541+
}
542+
if(!flags.requireAll) {
543+
return matchThis;
539544
}
545+
} else if(key === '@type') {
546+
// check @type (object value means 'any' type,
547+
// fall through to ducktyping)
540548
wildcard = false;
541-
542-
// check @id for a specific @id value
543-
if(key === '@id') {
544-
// if @id is not a wildcard and is not empty, then match or not on
545-
// specific value
546-
if(frame['@id'].length >= 0 && !types.isEmptyObject(frame['@id'][0])) {
547-
return frame['@id'].includes(nodeValues[0]);
549+
if(isEmpty) {
550+
if(nodeValues.length > 0) {
551+
// don't match on no @type
552+
return false;
548553
}
549554
matchThis = true;
550-
continue;
551-
}
552-
553-
// check @type (object value means 'any' type, fall through to ducktyping)
554-
if('@type' in frame) {
555-
if(isEmpty) {
556-
if(nodeValues.length > 0) {
557-
// don't match on no @type
558-
return false;
559-
}
560-
matchThis = true;
561-
} else if(frame['@type'].length === 1 &&
562-
types.isEmptyObject(frame['@type'][0])) {
563-
// match on wildcard @type if there is a type
564-
matchThis = nodeValues.length > 0;
565-
} else {
566-
// match on a specific @type
567-
for(const type of frame['@type']) {
568-
if(types.isObject(type) && '@default' in type) {
569-
// match on default object
570-
matchThis = true;
571-
} else {
572-
matchThis = matchThis || nodeValues.some(tt => tt === type);
573-
}
555+
} else if(frame['@type'].length === 1 &&
556+
types.isEmptyObject(frame['@type'][0])) {
557+
// match on wildcard @type if there is a type
558+
matchThis = nodeValues.length > 0;
559+
} else {
560+
// match on a specific @type
561+
for(const type of frame['@type']) {
562+
if(types.isObject(type) && '@default' in type) {
563+
// match on default object
564+
matchThis = true;
565+
} else {
566+
matchThis = matchThis || nodeValues.some(tt => tt === type);
574567
}
575568
}
576-
if(!flags.requireAll) {
577-
return matchThis;
578-
}
579569
}
570+
if(!flags.requireAll) {
571+
return matchThis;
572+
}
573+
} else if(isKeyword(key)) {
580574
continue;
581-
}
582-
583-
// Forc a copy of this frame entry so it can be manipulated
584-
const thisFrame = util.getValues(frame, key)[0];
585-
let hasDefault = false;
586-
if(thisFrame) {
587-
_validateFrame([thisFrame]);
588-
hasDefault = '@default' in thisFrame;
589-
}
590-
591-
// no longer a wildcard pattern if frame has any non-keyword properties
592-
wildcard = false;
575+
} else {
576+
// Force a copy of this frame entry so it can be manipulated
577+
const thisFrame = util.getValues(frame, key)[0];
578+
let hasDefault = false;
579+
if(thisFrame) {
580+
_validateFrame([thisFrame]);
581+
hasDefault = '@default' in thisFrame;
582+
}
593583

594-
// skip, but allow match if node has no value for property, and frame has a
595-
// default value
596-
if(nodeValues.length === 0 && hasDefault) {
597-
continue;
598-
}
584+
// no longer a wildcard pattern if frame has any non-keyword properties
585+
wildcard = false;
599586

600-
// if frame value is empty, don't match if subject has any value
601-
if(nodeValues.length > 0 && isEmpty) {
602-
return false;
603-
}
587+
// skip, but allow match if node has no value for property, and frame has a
588+
// default value
589+
if(nodeValues.length === 0 && hasDefault) {
590+
continue;
591+
}
604592

605-
if(thisFrame === undefined) {
606-
// node does not match if values is not empty and the value of property
607-
// in frame is match none.
608-
if(nodeValues.length > 0) {
593+
// if frame value is empty, don't match if subject has any value
594+
if(nodeValues.length > 0 && isEmpty) {
609595
return false;
610596
}
611-
matchThis = true;
612-
} else if(types.isObject(thisFrame)) {
613-
// node matches if values is not empty and the value of property in frame
614-
// is wildcard
615-
matchThis = nodeValues.length > 0;
616-
} else {
617-
if(graphTypes.isValue(thisFrame)) {
618-
// match on any matching value
619-
matchThis = nodeValues.some(nv => _valueMatch(thisFrame, nv));
620-
} else if(graphTypes.isSubject(thisFrame) ||
621-
graphTypes.isSubjectReference(thisFrame)) {
622-
matchThis =
623-
nodeValues.some(nv => _nodeMatch(state, thisFrame, nv, flags));
624-
} else if(graphTypes.isList(thisFrame)) {
625-
const listValue = thisFrame['@list'][0];
626-
if(graphTypes.isList(nodeValues[0])) {
627-
const nodeListValues = nodeValues[0]['@list'];
628-
629-
if(graphTypes.isValue(listValue)) {
630-
// match on any matching value
631-
matchThis = nodeListValues.some(lv => _valueMatch(listValue, lv));
632-
} else if(graphTypes.isSubject(listValue) ||
633-
graphTypes.isSubjectReference(listValue)) {
634-
matchThis = nodeListValues.some(lv => _nodeMatch(
635-
state, listValue, lv, flags));
597+
598+
if(thisFrame === undefined) {
599+
// node does not match if values is not empty and the value of property
600+
// in frame is match none.
601+
if(nodeValues.length > 0) {
602+
return false;
603+
}
604+
matchThis = true;
605+
} else if(types.isObject(thisFrame)) { // XXX only framing keywords
606+
// node matches if values is not empty and the value of property in frame
607+
// is wildcard
608+
matchThis = nodeValues.length > 0;
609+
} else {
610+
if(graphTypes.isValue(thisFrame)) {
611+
// match on any matching value
612+
matchThis = nodeValues.some(nv => _valueMatch(thisFrame, nv));
613+
} else if(graphTypes.isSubject(thisFrame) ||
614+
graphTypes.isSubjectReference(thisFrame))
615+
{
616+
matchThis =
617+
nodeValues.some(nv => _nodeMatch(state, thisFrame, nv, flags));
618+
} else if(graphTypes.isList(thisFrame)) {
619+
const listValue = thisFrame['@list'][0];
620+
if(graphTypes.isList(nodeValues[0])) {
621+
const nodeListValues = nodeValues[0]['@list'];
622+
623+
if(graphTypes.isValue(listValue)) {
624+
// match on any matching value
625+
matchThis = nodeListValues.some(lv => _valueMatch(listValue, lv));
626+
} else if(graphTypes.isSubject(listValue) ||
627+
graphTypes.isSubjectReference(listValue)) {
628+
matchThis = nodeListValues.some(lv => _nodeMatch(
629+
state, listValue, lv, flags));
630+
}
631+
} else {
632+
// value must be a list to match
633+
matchThis = false;
636634
}
637-
} else {
638-
// value must be a list to match
639-
matchThis = false;
640635
}
641636
}
642637
}

tests/test-common.js

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -129,12 +129,6 @@ const TEST_TYPES = {
129129
// lists
130130
/frame-manifest.jsonld#t0055$/,
131131
/frame-manifest.jsonld#t0058$/,
132-
// requireAll
133-
/frame-manifest.jsonld#tra01$/,
134-
/frame-manifest.jsonld#tra02$/,
135-
/frame-manifest.jsonld#tra03$/,
136-
// wildcard
137-
/frame-manifest.jsonld#t0061$/,
138132
// included
139133
/frame-manifest.jsonld#tin01$/,
140134
/frame-manifest.jsonld#tin02$/,

0 commit comments

Comments
 (0)