From fe2a60976d9832adbd2ff2d03b2bf4818684b692 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Wed, 19 Feb 2020 17:06:26 -0800 Subject: [PATCH 01/20] Remove new-embed tests, which are redundant and wrong. --- tests/new-embed-api/frame-0001-frame.jsonld | 20 ----- tests/new-embed-api/frame-0001-in.jsonld | 29 ------- tests/new-embed-api/frame-0001-out.jsonld | 28 ------ tests/new-embed-api/frame-0002-frame.jsonld | 20 ----- tests/new-embed-api/frame-0002-in.jsonld | 29 ------- tests/new-embed-api/frame-0002-out.jsonld | 25 ------ tests/new-embed-api/frame-0003-frame.jsonld | 20 ----- tests/new-embed-api/frame-0003-in.jsonld | 29 ------- tests/new-embed-api/frame-0003-out.jsonld | 25 ------ tests/new-embed-api/frame-0004-frame.jsonld | 21 ----- tests/new-embed-api/frame-0004-in.jsonld | 40 --------- tests/new-embed-api/frame-0004-out.jsonld | 38 --------- tests/new-embed-api/frame-0005-frame.jsonld | 24 ------ tests/new-embed-api/frame-0005-in.jsonld | 50 ----------- tests/new-embed-api/frame-0005-out.jsonld | 48 ----------- tests/new-embed-api/frame-0006-frame.jsonld | 24 ------ tests/new-embed-api/frame-0006-in.jsonld | 73 ---------------- tests/new-embed-api/frame-0006-out.jsonld | 89 ------------------- tests/new-embed-api/frame-0007-frame.jsonld | 35 -------- tests/new-embed-api/frame-0007-in.jsonld | 77 ----------------- tests/new-embed-api/frame-0007-out.jsonld | 95 --------------------- tests/new-embed-api/frame-0008-frame.jsonld | 15 ---- tests/new-embed-api/frame-0008-in.jsonld | 52 ----------- tests/new-embed-api/frame-0008-out.jsonld | 40 --------- tests/new-embed-api/manifest.jsonld | 65 -------------- tests/test.js | 1 - 26 files changed, 1012 deletions(-) delete mode 100644 tests/new-embed-api/frame-0001-frame.jsonld delete mode 100644 tests/new-embed-api/frame-0001-in.jsonld delete mode 100644 tests/new-embed-api/frame-0001-out.jsonld delete mode 100644 tests/new-embed-api/frame-0002-frame.jsonld delete mode 100644 tests/new-embed-api/frame-0002-in.jsonld delete mode 100644 tests/new-embed-api/frame-0002-out.jsonld delete mode 100644 tests/new-embed-api/frame-0003-frame.jsonld delete mode 100644 tests/new-embed-api/frame-0003-in.jsonld delete mode 100644 tests/new-embed-api/frame-0003-out.jsonld delete mode 100644 tests/new-embed-api/frame-0004-frame.jsonld delete mode 100644 tests/new-embed-api/frame-0004-in.jsonld delete mode 100644 tests/new-embed-api/frame-0004-out.jsonld delete mode 100644 tests/new-embed-api/frame-0005-frame.jsonld delete mode 100644 tests/new-embed-api/frame-0005-in.jsonld delete mode 100644 tests/new-embed-api/frame-0005-out.jsonld delete mode 100644 tests/new-embed-api/frame-0006-frame.jsonld delete mode 100644 tests/new-embed-api/frame-0006-in.jsonld delete mode 100644 tests/new-embed-api/frame-0006-out.jsonld delete mode 100644 tests/new-embed-api/frame-0007-frame.jsonld delete mode 100644 tests/new-embed-api/frame-0007-in.jsonld delete mode 100644 tests/new-embed-api/frame-0007-out.jsonld delete mode 100644 tests/new-embed-api/frame-0008-frame.jsonld delete mode 100644 tests/new-embed-api/frame-0008-in.jsonld delete mode 100644 tests/new-embed-api/frame-0008-out.jsonld delete mode 100644 tests/new-embed-api/manifest.jsonld diff --git a/tests/new-embed-api/frame-0001-frame.jsonld b/tests/new-embed-api/frame-0001-frame.jsonld deleted file mode 100644 index 5864ae8f..00000000 --- a/tests/new-embed-api/frame-0001-frame.jsonld +++ /dev/null @@ -1,20 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#" - }, - "@type": "ex:Library", - "@embed": "@always", - "ex:contains": { - "@type": "ex:Book", - "@embed": "@always", - "ex:contains": { - "@type": "ex:Chapter", - "@embed": "@always" - }, - "ex:bookmark": { - "@type": "ex:Chapter", - "@embed": "@always" - } - } -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0001-in.jsonld b/tests/new-embed-api/frame-0001-in.jsonld deleted file mode 100644 index 342c560b..00000000 --- a/tests/new-embed-api/frame-0001-in.jsonld +++ /dev/null @@ -1,29 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#", - "ex:contains": {"@type": "@id"}, - "ex:bookmark": {"@type": "@id"} - }, - "@graph": [ - { - "@id": "http://example.org/test/#library", - "@type": "ex:Library", - "ex:contains": "http://example.org/test#book" - }, - { - "@id": "http://example.org/test#book", - "@type": "ex:Book", - "dc:contributor": "Writer", - "dc:title": "My Book", - "ex:contains": "http://example.org/test#chapter", - "ex:bookmark": "http://example.org/test#chapter" - }, - { - "@id": "http://example.org/test#chapter", - "@type": "ex:Chapter", - "dc:description": "Fun", - "dc:title": "Chapter One" - } - ] -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0001-out.jsonld b/tests/new-embed-api/frame-0001-out.jsonld deleted file mode 100644 index 071b66e6..00000000 --- a/tests/new-embed-api/frame-0001-out.jsonld +++ /dev/null @@ -1,28 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#" - }, - "@graph": [{ - "@id": "http://example.org/test/#library", - "@type": "ex:Library", - "ex:contains": { - "@id": "http://example.org/test#book", - "@type": "ex:Book", - "dc:contributor": "Writer", - "dc:title": "My Book", - "ex:contains": { - "@id": "http://example.org/test#chapter", - "@type": "ex:Chapter", - "dc:description": "Fun", - "dc:title": "Chapter One" - }, - "ex:bookmark": { - "@id": "http://example.org/test#chapter", - "@type": "ex:Chapter", - "dc:description": "Fun", - "dc:title": "Chapter One" - } - } - }] -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0002-frame.jsonld b/tests/new-embed-api/frame-0002-frame.jsonld deleted file mode 100644 index 8043b5b7..00000000 --- a/tests/new-embed-api/frame-0002-frame.jsonld +++ /dev/null @@ -1,20 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#" - }, - "@type": "ex:Library", - "@embed": "@always", - "ex:contains": { - "@type": "ex:Book", - "@embed": "@always", - "ex:contains": { - "@type": "ex:Chapter", - "@embed": "@always" - }, - "ex:topic": { - "@type": "ex:Library", - "@embed": "@always" - } - } -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0002-in.jsonld b/tests/new-embed-api/frame-0002-in.jsonld deleted file mode 100644 index f2179644..00000000 --- a/tests/new-embed-api/frame-0002-in.jsonld +++ /dev/null @@ -1,29 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#", - "ex:contains": {"@type": "@id"}, - "ex:topic": {"@type": "@id"} - }, - "@graph": [ - { - "@id": "http://example.org/test/#library", - "@type": "ex:Library", - "ex:contains": "http://example.org/test#book" - }, - { - "@id": "http://example.org/test#book", - "@type": "ex:Book", - "dc:contributor": "Writer", - "dc:title": "My Book about a library", - "ex:contains": "http://example.org/test#chapter", - "ex:topic": "http://example.org/test/#library" - }, - { - "@id": "http://example.org/test#chapter", - "@type": "ex:Chapter", - "dc:description": "Fun", - "dc:title": "Chapter One" - } - ] -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0002-out.jsonld b/tests/new-embed-api/frame-0002-out.jsonld deleted file mode 100644 index 635eeb41..00000000 --- a/tests/new-embed-api/frame-0002-out.jsonld +++ /dev/null @@ -1,25 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#" - }, - "@graph": [{ - "@id": "http://example.org/test/#library", - "@type": "ex:Library", - "ex:contains": { - "@id": "http://example.org/test#book", - "@type": "ex:Book", - "dc:contributor": "Writer", - "dc:title": "My Book about a library", - "ex:contains": { - "@id": "http://example.org/test#chapter", - "@type": "ex:Chapter", - "dc:description": "Fun", - "dc:title": "Chapter One" - }, - "ex:topic": { - "@id": "http://example.org/test/#library" - } - } - }] -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0003-frame.jsonld b/tests/new-embed-api/frame-0003-frame.jsonld deleted file mode 100644 index 44c813e2..00000000 --- a/tests/new-embed-api/frame-0003-frame.jsonld +++ /dev/null @@ -1,20 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#" - }, - "@type": "ex:Library", - "@embed": "@always", - "ex:contains": { - "@type": "ex:Book", - "@embed": "@always", - "ex:contains": { - "@type": "ex:Chapter", - "@embed": "@always", - "ex:topic": { - "@type": "ex:Library", - "@embed": "@always" - } - } - } -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0003-in.jsonld b/tests/new-embed-api/frame-0003-in.jsonld deleted file mode 100644 index 3ca2b8b6..00000000 --- a/tests/new-embed-api/frame-0003-in.jsonld +++ /dev/null @@ -1,29 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#", - "ex:contains": {"@type": "@id"}, - "ex:topic": {"@type": "@id"} - }, - "@graph": [ - { - "@id": "http://example.org/test/#library", - "@type": "ex:Library", - "ex:contains": "http://example.org/test#book" - }, - { - "@id": "http://example.org/test#book", - "@type": "ex:Book", - "dc:contributor": "Writer", - "dc:title": "My Book about a library", - "ex:contains": "http://example.org/test#chapter" - }, - { - "@id": "http://example.org/test#chapter", - "@type": "ex:Chapter", - "dc:description": "Fun", - "dc:title": "Chapter One", - "ex:topic": "http://example.org/test/#library" - } - ] -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0003-out.jsonld b/tests/new-embed-api/frame-0003-out.jsonld deleted file mode 100644 index 34c91f8d..00000000 --- a/tests/new-embed-api/frame-0003-out.jsonld +++ /dev/null @@ -1,25 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#" - }, - "@graph": [{ - "@id": "http://example.org/test/#library", - "@type": "ex:Library", - "ex:contains": { - "@id": "http://example.org/test#book", - "@type": "ex:Book", - "dc:contributor": "Writer", - "dc:title": "My Book about a library", - "ex:contains": { - "@id": "http://example.org/test#chapter", - "@type": "ex:Chapter", - "dc:description": "Fun", - "dc:title": "Chapter One", - "ex:topic": { - "@id": "http://example.org/test/#library" - } - } - } - }] -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0004-frame.jsonld b/tests/new-embed-api/frame-0004-frame.jsonld deleted file mode 100644 index 7e588379..00000000 --- a/tests/new-embed-api/frame-0004-frame.jsonld +++ /dev/null @@ -1,21 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#" - }, - "@type": "ex:Library", - "@embed": "@always", - "ex:contains": { - "@type": "ex:Book", - "@omitDefault": "true", - "@embed": "@always", - "ex:contains": { - "@type": "ex:Chapter", - "@embed": "@always", - "ex:topic": { - "@type": "ex:Library", - "@embed": "@always" - } - } - } -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0004-in.jsonld b/tests/new-embed-api/frame-0004-in.jsonld deleted file mode 100644 index 46274748..00000000 --- a/tests/new-embed-api/frame-0004-in.jsonld +++ /dev/null @@ -1,40 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#", - "ex:contains": {"@type": "@id"}, - "ex:topic": {"@type": "@id"} - }, - "@graph": [ - { - "@id": "http://example.org/test/#library", - "@type": "ex:Library", - "ex:name": "My local library", - "ex:contains": "http://example.org/test#book" - }, - { - "@id": "http://example.org/test/#library2", - "@type": "ex:Library", - "ex:name": "Another library" - }, - { - "@id": "http://example.org/test#book", - "@type": "ex:Book", - "dc:contributor": "Writer", - "dc:title": "My Book about a library", - "ex:contains": "http://example.org/test#chapter" - }, - { - "@id": "http://example.org/test#chapter", - "@type": "ex:Chapter", - "dc:description": "Fun", - "dc:title": "Chapter One", - "ex:topic": { - "@set": [ - "http://example.org/test/#library", - "http://example.org/test/#library2" - ] - } - } - ] -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0004-out.jsonld b/tests/new-embed-api/frame-0004-out.jsonld deleted file mode 100644 index e37cb1f2..00000000 --- a/tests/new-embed-api/frame-0004-out.jsonld +++ /dev/null @@ -1,38 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#" - }, - "@graph": [{ - "@id": "http://example.org/test/#library", - "@type": "ex:Library", - "ex:name": "My local library", - "ex:contains": { - "@id": "http://example.org/test#book", - "@type": "ex:Book", - "dc:contributor": "Writer", - "dc:title": "My Book about a library", - "ex:contains": { - "@id": "http://example.org/test#chapter", - "@type": "ex:Chapter", - "dc:description": "Fun", - "dc:title": "Chapter One", - "ex:topic": [ - { - "@id": "http://example.org/test/#library" - }, - { - "@id": "http://example.org/test/#library2", - "@type": "ex:Library", - "ex:name": "Another library" - } - ] - } - } - }, - { - "@id": "http://example.org/test/#library2", - "@type": "ex:Library", - "ex:name": "Another library" - }] -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0005-frame.jsonld b/tests/new-embed-api/frame-0005-frame.jsonld deleted file mode 100644 index 91c19b44..00000000 --- a/tests/new-embed-api/frame-0005-frame.jsonld +++ /dev/null @@ -1,24 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#" - }, - "@type": "ex:Town", - "@embed": "@always", - "ex:hasLibrary": { - "@type": "ex:Library", - "@embed": "@always", - "ex:contains": { - "@type": "ex:Book", - "@embed": "@always", - "ex:contains": { - "@type": "ex:Chapter", - "@embed": "@always", - "ex:topic": { - "@type": "ex:Library", - "@embed": "@always" - } - } - } - } -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0005-in.jsonld b/tests/new-embed-api/frame-0005-in.jsonld deleted file mode 100644 index 6e8f9863..00000000 --- a/tests/new-embed-api/frame-0005-in.jsonld +++ /dev/null @@ -1,50 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#", - "ex:contains": {"@type": "@id"}, - "ex:topic": {"@type": "@id"}, - "ex:hasLibrary": {"@type": "@id"} - }, - "@graph": [ - { - "@id": "http://example.org/town/#123", - "@type": "ex:Town", - "ex:name": "My town", - "ex:hasLibrary": [ - "http://example.org/test/#library", - "http://example.org/test/#library2" - ] - }, - { - "@id": "http://example.org/test/#library", - "@type": "ex:Library", - "ex:name": "My local library", - "ex:contains": "http://example.org/test#book" - }, - { - "@id": "http://example.org/test/#library2", - "@type": "ex:Library", - "ex:name": "Another library" - }, - { - "@id": "http://example.org/test#book", - "@type": "ex:Book", - "dc:contributor": "Writer", - "dc:title": "My Book about a library", - "ex:contains": "http://example.org/test#chapter" - }, - { - "@id": "http://example.org/test#chapter", - "@type": "ex:Chapter", - "dc:description": "Fun", - "dc:title": "Chapter One", - "ex:topic": { - "@set": [ - "http://example.org/test/#library", - "http://example.org/test/#library2" - ] - } - } - ] -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0005-out.jsonld b/tests/new-embed-api/frame-0005-out.jsonld deleted file mode 100644 index a3a45cc7..00000000 --- a/tests/new-embed-api/frame-0005-out.jsonld +++ /dev/null @@ -1,48 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#" - }, - "@graph": [ - { - "@id": "http://example.org/town/#123", - "@type": "ex:Town", - "ex:name": "My town", - "ex:hasLibrary": [ - { - "@id": "http://example.org/test/#library", - "@type": "ex:Library", - "ex:name": "My local library", - "ex:contains": { - "@id": "http://example.org/test#book", - "@type": "ex:Book", - "dc:contributor": "Writer", - "dc:title": "My Book about a library", - "ex:contains": { - "@id": "http://example.org/test#chapter", - "@type": "ex:Chapter", - "dc:description": "Fun", - "dc:title": "Chapter One", - "ex:topic": [ - { - "@id": "http://example.org/test/#library" - }, - { - "@id": "http://example.org/test/#library2", - "@type": "ex:Library", - "ex:name": "Another library" - } - ] - } - } - }, - { - "@id": "http://example.org/test/#library2", - "@type": "ex:Library", - "ex:contains": null, - "ex:name": "Another library" - } - ] - } - ] -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0006-frame.jsonld b/tests/new-embed-api/frame-0006-frame.jsonld deleted file mode 100644 index 56ece9bf..00000000 --- a/tests/new-embed-api/frame-0006-frame.jsonld +++ /dev/null @@ -1,24 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#" - }, - "@type": "ex:Library", - "@embed": "@always", - "ex:contains": { - "@type": "ex:Book", - "@embed": "@always", - "ex:bookmark": { - "@type": "ex:Chapter", - "@embed": "@always" - }, - "ex:contains": { - "@type": "ex:Chapter", - "@embed": "@always", - "ex:topic" : { - "@type": "ex:Topic", - "@embed": "@always" - } - } - } -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0006-in.jsonld b/tests/new-embed-api/frame-0006-in.jsonld deleted file mode 100644 index fc7a766b..00000000 --- a/tests/new-embed-api/frame-0006-in.jsonld +++ /dev/null @@ -1,73 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#", - "ex:contains": {"@type": "@id"}, - "ex:bookmark": {"@type": "@id"}, - "ex:topic": {"@type": "@id"} - }, - "@graph": [ - { - "@id": "http://example.org/test/#library", - "@type": "ex:Library", - "ex:contains": "http://example.org/test#book" - }, - { - "@id": "http://example.org/test#book", - "@type": "ex:Book", - "dc:contributor": "Writer", - "dc:title": "My Book", - "ex:contains": [ - "http://example.org/test#chapter", - "http://example.org/test#chapter2" - ], - "ex:bookmark": "http://example.org/test#chapter" - }, - { - "@id": "http://example.org/test#chapter", - "@type": "ex:Chapter", - "dc:description": "Fun", - "dc:title": "Chapter One", - "ex:topic": [ - "http://example.org/test#subject1", - "http://example.org/test#subject2", - "http://example.org/test#subject3" - ] - }, - { - "@id": "http://example.org/test#chapter2", - "@type": "ex:Chapter", - "dc:description": "More Fun", - "dc:title": "Chapter Two", - "ex:topic": [ - "http://example.org/test#subject1", - "http://example.org/test#subject4", - "http://example.org/test#subject5" - ] - }, - { - "@id": "http://example.org/test#subject1", - "@type": "ex:Topic", - "dc:description": "Topic 1" - }, - { - "@id": "http://example.org/test#subject2", - "@type": "ex:Topic", - "dc:description": "Topic 2" - }, - { - "@id": "http://example.org/test#subject3", - "@type": "ex:Topic", - "dc:description": "Topic 3" - }, - { - "@id": "http://example.org/test#subject4", - "@type": "ex:Topic", - "dc:description": "Topic 4" - }, - { - "@id": "http://example.org/test#subject5", - "@type": "ex:Topic", - "dc:description": "Topic 5" - }] -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0006-out.jsonld b/tests/new-embed-api/frame-0006-out.jsonld deleted file mode 100644 index 52d0cacc..00000000 --- a/tests/new-embed-api/frame-0006-out.jsonld +++ /dev/null @@ -1,89 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#" - }, - "@graph": [ - { - "@id": "http://example.org/test/#library", - "@type": "ex:Library", - "ex:contains": { - "@id": "http://example.org/test#book", - "@type": "ex:Book", - "dc:contributor": "Writer", - "dc:title": "My Book", - "ex:contains": [ - { - "@id": "http://example.org/test#chapter", - "@type": "ex:Chapter", - "dc:description": "Fun", - "dc:title": "Chapter One", - "ex:topic": [ - { - "@id": "http://example.org/test#subject1", - "@type": "ex:Topic", - "dc:description": "Topic 1" - }, - { - "@id": "http://example.org/test#subject2", - "@type": "ex:Topic", - "dc:description": "Topic 2" - }, - { - "@id": "http://example.org/test#subject3", - "@type": "ex:Topic", - "dc:description": "Topic 3" - } - ] - }, - { - "@id": "http://example.org/test#chapter2", - "@type": "ex:Chapter", - "dc:description": "More Fun", - "dc:title": "Chapter Two", - "ex:topic": [ - { - "@id": "http://example.org/test#subject1", - "@type": "ex:Topic", - "dc:description": "Topic 1" - }, - { - "@id": "http://example.org/test#subject4", - "@type": "ex:Topic", - "dc:description": "Topic 4" - }, - { - "@id": "http://example.org/test#subject5", - "@type": "ex:Topic", - "dc:description": "Topic 5" - } - ] - } - ], - "ex:bookmark": { - "@id": "http://example.org/test#chapter", - "@type": "ex:Chapter", - "dc:description": "Fun", - "dc:title": "Chapter One", - "ex:topic": [ - { - "@id": "http://example.org/test#subject1", - "@type": "ex:Topic", - "dc:description": "Topic 1" - }, - { - "@id": "http://example.org/test#subject2", - "@type": "ex:Topic", - "dc:description": "Topic 2" - }, - { - "@id": "http://example.org/test#subject3", - "@type": "ex:Topic", - "dc:description": "Topic 3" - } - ] - } - } - } - ] -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0007-frame.jsonld b/tests/new-embed-api/frame-0007-frame.jsonld deleted file mode 100644 index d1fa6658..00000000 --- a/tests/new-embed-api/frame-0007-frame.jsonld +++ /dev/null @@ -1,35 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#", - "ex:relatesTo": {"@type": "@id"} - }, - "@type": "ex:Library", - "@embed": "@always", - "ex:contains": { - "@type": "ex:Book", - "@embed": "@always", - "ex:bookmark": { - "@type": "ex:Chapter", - "@embed": "@always" - }, - "ex:contains": { - "@type": "ex:Chapter", - "@embed": "@always", - "dc:subject": { - "@omitDefault": "true", - "@embed": "@always", - "@type": "ex:Library" - }, - "ex:topic" : { - "@type": "ex:Topic", - "@embed": "@always", - "ex:relatesTo" : { - "@omitDefault": "true", - "@embed": "@always", - "@type": "ex:Library" - } - } - } - } -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0007-in.jsonld b/tests/new-embed-api/frame-0007-in.jsonld deleted file mode 100644 index 9d4cca97..00000000 --- a/tests/new-embed-api/frame-0007-in.jsonld +++ /dev/null @@ -1,77 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#", - "dc:subject": {"@type": "@id"}, - "ex:contains": {"@type": "@id"}, - "ex:bookmark": {"@type": "@id"}, - "ex:topic": {"@type": "@id"}, - "ex:relatesTo": {"@type": "@id"} - }, - "@graph": [ - { - "@id": "http://example.org/test/#library", - "@type": "ex:Library", - "ex:contains": "http://example.org/test#book" - }, - { - "@id": "http://example.org/test#book", - "@type": "ex:Book", - "dc:contributor": "Writer", - "dc:title": "My Book", - "ex:contains": [ - "http://example.org/test#chapter", - "http://example.org/test#chapter2" - ], - "ex:bookmark": "http://example.org/test#chapter" - }, - { - "@id": "http://example.org/test#chapter", - "@type": "ex:Chapter", - "dc:description": "Fun", - "dc:title": "Chapter One", - "dc:subject": "http://example.org/test/#library", - "ex:topic": [ - "http://example.org/test#subject1", - "http://example.org/test#subject2", - "http://example.org/test#subject3" - ] - }, - { - "@id": "http://example.org/test#chapter2", - "@type": "ex:Chapter", - "dc:description": "More Fun", - "dc:title": "Chapter Two", - "ex:topic": [ - "http://example.org/test#subject1", - "http://example.org/test#subject4", - "http://example.org/test#subject5" - ] - }, - { - "@id": "http://example.org/test#subject1", - "@type": "ex:Topic", - "dc:description": "Topic 1", - "ex:relatesTo": "http://example.org/test/#library" - }, - { - "@id": "http://example.org/test#subject2", - "@type": "ex:Topic", - "dc:description": "Topic 2" - }, - { - "@id": "http://example.org/test#subject3", - "@type": "ex:Topic", - "dc:description": "Topic 3" - }, - { - "@id": "http://example.org/test#subject4", - "@type": "ex:Topic", - "dc:description": "Topic 4" - }, - { - "@id": "http://example.org/test#subject5", - "@type": "ex:Topic", - "dc:description": "Topic 5" - }] -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0007-out.jsonld b/tests/new-embed-api/frame-0007-out.jsonld deleted file mode 100644 index 9cb477f3..00000000 --- a/tests/new-embed-api/frame-0007-out.jsonld +++ /dev/null @@ -1,95 +0,0 @@ -{ - "@context": { - "dc": "http://purl.org/dc/elements/1.1/", - "ex": "http://example.org/vocab#", - "ex:relatesTo": {"@type": "@id"} - }, - "@graph": [ - { - "@id": "http://example.org/test/#library", - "@type": "ex:Library", - "ex:contains": { - "@id": "http://example.org/test#book", - "@type": "ex:Book", - "dc:contributor": "Writer", - "dc:title": "My Book", - "ex:contains": [ - { - "@id": "http://example.org/test#chapter", - "@type": "ex:Chapter", - "dc:description": "Fun", - "dc:title": "Chapter One", - "dc:subject": {"@id": "http://example.org/test/#library"}, - "ex:topic": [ - { - "@id": "http://example.org/test#subject1", - "@type": "ex:Topic", - "dc:description": "Topic 1", - "ex:relatesTo": "http://example.org/test/#library" - }, - { - "@id": "http://example.org/test#subject2", - "@type": "ex:Topic", - "dc:description": "Topic 2" - }, - { - "@id": "http://example.org/test#subject3", - "@type": "ex:Topic", - "dc:description": "Topic 3" - } - ] - }, - { - "@id": "http://example.org/test#chapter2", - "@type": "ex:Chapter", - "dc:description": "More Fun", - "dc:title": "Chapter Two", - "ex:topic": [ - { - "@id": "http://example.org/test#subject1", - "@type": "ex:Topic", - "dc:description": "Topic 1", - "ex:relatesTo": "http://example.org/test/#library" - }, - { - "@id": "http://example.org/test#subject4", - "@type": "ex:Topic", - "dc:description": "Topic 4" - }, - { - "@id": "http://example.org/test#subject5", - "@type": "ex:Topic", - "dc:description": "Topic 5" - } - ] - } - ], - "ex:bookmark": { - "@id": "http://example.org/test#chapter", - "@type": "ex:Chapter", - "dc:description": "Fun", - "dc:title": "Chapter One", - "dc:subject": {"@id": "http://example.org/test/#library"}, - "ex:topic": [ - { - "@id": "http://example.org/test#subject1", - "@type": "ex:Topic", - "dc:description": "Topic 1", - "ex:relatesTo": "http://example.org/test/#library" - }, - { - "@id": "http://example.org/test#subject2", - "@type": "ex:Topic", - "dc:description": "Topic 2" - }, - { - "@id": "http://example.org/test#subject3", - "@type": "ex:Topic", - "dc:description": "Topic 3" - } - ] - } - } - } - ] -} \ No newline at end of file diff --git a/tests/new-embed-api/frame-0008-frame.jsonld b/tests/new-embed-api/frame-0008-frame.jsonld deleted file mode 100644 index dfc4fd62..00000000 --- a/tests/new-embed-api/frame-0008-frame.jsonld +++ /dev/null @@ -1,15 +0,0 @@ -{ - "@context": { - "ex": "http://example.com/", - "embed": { - "@id": "ex:embed", - "@container": "@set" - }, - "shouldExist": "ex:shouldExist" - }, - "@type": "http://example.com/TreeRoot", - "@embed": "@always", - "embed": { - "@embed": "@always" - } -} diff --git a/tests/new-embed-api/frame-0008-in.jsonld b/tests/new-embed-api/frame-0008-in.jsonld deleted file mode 100644 index 08d32aef..00000000 --- a/tests/new-embed-api/frame-0008-in.jsonld +++ /dev/null @@ -1,52 +0,0 @@ -{ - "@context": { - "ex": "http://example.com/", - "embed": { - "@id": "ex:embed", - "@container": "@set" - }, - "shouldExist": "ex:shouldExist" - }, - "@graph": [ - { - "@id": "ex:root", - "@type": "ex:TreeRoot", - "embed": [ - { - "@id": "ex:node-d1-with-leaf" - }, - { - "@id": "ex:node-d1-with-node" - } - ] - }, - { - "@id": "ex:node-d1-with-leaf", - "embed": [ - { - "@id": "ex:leaf" - } - ] - }, - { - "@id": "ex:node-d1-with-node", - "embed": [ - { - "@id": "ex:node-d2-with-leaf" - } - ] - }, - { - "@id": "ex:node-d2-with-leaf", - "embed": [ - { - "@id": "ex:leaf" - } - ] - }, - { - "@id": "ex:leaf", - "shouldExist": "shows when embedded" - } - ] -} diff --git a/tests/new-embed-api/frame-0008-out.jsonld b/tests/new-embed-api/frame-0008-out.jsonld deleted file mode 100644 index 5698740a..00000000 --- a/tests/new-embed-api/frame-0008-out.jsonld +++ /dev/null @@ -1,40 +0,0 @@ -{ - "@context": { - "ex": "http://example.com/", - "embed": { - "@id": "ex:embed", - "@container": "@set" - },"shouldExist": "ex:shouldExist" - }, - "@graph": [ - { - "@id": "ex:root", - "@type": "ex:TreeRoot", - "embed": [ - { - "@id": "ex:node-d1-with-leaf", - "embed": [ - { - "@id": "ex:leaf", - "shouldExist": "shows when embedded" - } - ] - }, - { - "@id": "ex:node-d1-with-node", - "embed": [ - { - "@id": "ex:node-d2-with-leaf", - "embed": [ - { - "@id": "ex:leaf", - "shouldExist": "shows when embedded" - } - ] - } - ] - } - ] - } - ] -} diff --git a/tests/new-embed-api/manifest.jsonld b/tests/new-embed-api/manifest.jsonld deleted file mode 100644 index 7b9dd043..00000000 --- a/tests/new-embed-api/manifest.jsonld +++ /dev/null @@ -1,65 +0,0 @@ -{ - "@context": "http://json-ld.org/test-suite/context.jsonld", - "@id": "", - "@type": "mf:Manifest", - "name": "New Embed API Framing", - "description": "JSON-LD framing tests use object comparison.", - "baseIri": "", - "sequence": [{ - "@id": "#t0001", - "@type": ["jld:PositiveEvaluationTest", "jld:FrameTest"], - "name": "Simple embed", - "input": "frame-0001-in.jsonld", - "frame": "frame-0001-frame.jsonld", - "expect": "frame-0001-out.jsonld" - }, { - "@id": "#t0002", - "@type": ["jld:PositiveEvaluationTest", "jld:FrameTest"], - "name": "Embed with direct circular reference", - "input": "frame-0002-in.jsonld", - "frame": "frame-0002-frame.jsonld", - "expect": "frame-0002-out.jsonld" - }, { - "@id": "#t0003", - "@type": ["jld:PositiveEvaluationTest", "jld:FrameTest"], - "name": "Embed with indirect circular reference", - "input": "frame-0003-in.jsonld", - "frame": "frame-0003-frame.jsonld", - "expect": "frame-0003-out.jsonld" - }, { - "@id": "#t0004", - "@type": ["jld:PositiveEvaluationTest", "jld:FrameTest"], - "name": "Embed with indirect circular reference via set", - "input": "frame-0004-in.jsonld", - "frame": "frame-0004-frame.jsonld", - "expect": "frame-0004-out.jsonld" - }, { - "@id": "#t0005", - "@type": ["jld:PositiveEvaluationTest", "jld:FrameTest"], - "name": "Embed with nested indirect circular reference via set", - "input": "frame-0005-in.jsonld", - "frame": "frame-0005-frame.jsonld", - "expect": "frame-0005-out.jsonld" - }, { - "@id": "#t0006", - "@type": ["jld:PositiveEvaluationTest", "jld:FrameTest"], - "name": "Multi-level simple embeds", - "input": "frame-0006-in.jsonld", - "frame": "frame-0006-frame.jsonld", - "expect": "frame-0006-out.jsonld" - }, { - "@id": "#t0007", - "@type": ["jld:PositiveEvaluationTest", "jld:FrameTest"], - "name": "A tangle of nastiness", - "input": "frame-0007-in.jsonld", - "frame": "frame-0007-frame.jsonld", - "expect": "frame-0007-out.jsonld" - },{ - "@id": "#t0008", - "@type": ["jld:PositiveEvaluationTest", "jld:FrameTest"], - "name": "Recursive property embed w/o circular reference", - "input": "frame-0008-in.jsonld", - "frame": "frame-0008-frame.jsonld", - "expect": "frame-0008-out.jsonld" - }] -} diff --git a/tests/test.js b/tests/test.js index 5214e28c..06bb336d 100644 --- a/tests/test.js +++ b/tests/test.js @@ -93,7 +93,6 @@ if(process.env.JSONLD_TESTS) { // other tests entries.push(path.resolve(_top, 'tests/misc.js')); entries.push(path.resolve(_top, 'tests/graph-container.js')); - entries.push(path.resolve(_top, 'tests/new-embed-api')); // TODO: avoid network traffic and re-enable //entries.push(path.resolve(_top, 'tests/node-document-loader-tests.js')); } From e73171b93197e14cd04c639d52aa8948694b39c4 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Wed, 19 Feb 2020 17:12:41 -0800 Subject: [PATCH 02/20] Changed framing defaults and handle omitGraph. - Changed framing defaults - `embed` to "@once" and warn on "@first" or "@last". - `pruneBlankNodeIdentifiers` based on processingMode. - `omitGraph` based on processingMode. - Top level `@graph` omitted if `omitGraph` is `true`. --- CHANGELOG.md | 5 +++++ lib/jsonld.js | 52 ++++++++++++++++++++++++++++---------------- tests/misc.js | 11 +++------- tests/test-common.js | 8 +------ 4 files changed, 42 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95c4fed8..b5be6113 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,10 @@ - **NOTE**: `LINK_HEADER_REL` in `lib/constants.js` has been deprecated and renamed to `LINK_HEADER_CONTEXT`. It remains for now but will be removed in a future release. +- Changed framing defaults + - `embed` to "@once" and warn on "@first" or "@last". + - `pruneBlankNodeIdentifiers` based on processingMode. + - `omitGraph` based on processingMode. ### Added - Support for `"@import"`. @@ -30,6 +34,7 @@ - Support for expansion and compaction of values container `"@direction"`. - Support for RDF transformation of `@direction` when `rdfDirection` is 'i18n-datatype'. +- Top level `@graph` omitted if `omitGraph` is `true`. ## 2.0.2 - 2020-01-17 diff --git a/lib/jsonld.js b/lib/jsonld.js index 718309d8..9dee5bf6 100644 --- a/lib/jsonld.js +++ b/lib/jsonld.js @@ -62,8 +62,10 @@ const { } = require('./graphTypes'); const { + expandIri: _expandIri, getInitialContext: _getInitialContext, - process: _processContext + process: _processContext, + processingMode: _processingMode } = require('./context'); const { @@ -223,6 +225,12 @@ jsonld.compact = async function(input, ctx, options) { ctx = ctx[0]; } + if(options.framing) { + // remove @preserve from results + options.link = {}; + compacted = _removePreserve(activeCtx, compacted, options); + } + // add context and/or @graph if(_isArray(compacted)) { // use '@graph' keyword @@ -244,16 +252,6 @@ jsonld.compact = async function(input, ctx, options) { } } - if(options.framing) { - // get graph alias - const graph = _compactIri({ - activeCtx, iri: '@graph', relativeTo: {vocab: true} - }); - // remove @preserve from results - options.link = {}; - compacted[graph] = _removePreserve(activeCtx, compacted[graph], options); - } - return compacted; }; @@ -435,11 +433,10 @@ jsonld.frame = async function(input, frame, options) { // set default options options = _setDefaults(options, { base: _isString(input) ? input : '', - embed: '@last', + embed: '@once', explicit: false, - requireAll: true, + requireAll: false, omitDefault: false, - pruneBlankNodeIdentifiers: true, bnodesToClear: [], contextResolver: new ContextResolver( {sharedCache: _resolvedContextCache}) @@ -467,6 +464,24 @@ jsonld.frame = async function(input, frame, options) { const frameContext = frame ? frame['@context'] || {} : {}; + // process context + const activeCtx = await jsonld.processContext( + _getInitialContext(options), frameContext, options); + + // mode specific defaults + if(!options.hasOwnProperty('omitGraph')) { + options.omitGraph = _processingMode(activeCtx, 1.1); + } + if(!options.hasOwnProperty('pruneBlankNodeIdentifiers')) { + options.pruneBlankNodeIdentifiers = _processingMode(activeCtx, 1.1); + } + if((options.embed === '@first' || options.embed === '@last') && + _processingMode(activeCtx, 1.1)) + { + console.warn(`WARNING: ${options.embed} is not a valid value ` + + `of @embed in 1.1 mode.`); + } + // expand input const expanded = await jsonld.expand(input, options); @@ -478,14 +493,13 @@ jsonld.frame = async function(input, frame, options) { // if the unexpanded frame includes a key expanding to @graph, frame the // default graph, otherwise, the merged graph - // FIXME should look for aliases of @graph - opts.merged = !('@graph' in frame); + const frameKeys = Object.keys(frame) + .map(key => _expandIri(activeCtx, key, {vocab: true})); + opts.merged = !frameKeys.includes('@graph'); // do framing const framed = _frameMergedOrDefault(expanded, expandedFrame, opts); - // compact result (force @graph option to true, skip expansion, - // check for linked embeds) - opts.graph = true; + opts.graph = !options.omitGraph; opts.skipExpansion = true; opts.link = {}; opts.framing = true; diff --git a/tests/misc.js b/tests/misc.js index 6c2758c7..1c3758e0 100644 --- a/tests/misc.js +++ b/tests/misc.js @@ -22,7 +22,6 @@ describe('link tests', () => { p.catch(e => { assert.ifError(e); }).then(output => { - output = output['@graph'][0]; assert.equal(output, output['a:foo']); done(); }); @@ -453,13 +452,9 @@ describe('js keywords', () => { "@context": { "@vocab": "http://example.org/" }, - "@graph": [ - { - "toString": { - "valueOf": "thing" - } - } - ] + "toString": { + "valueOf": "thing" + } } ; const e = await jsonld.frame(d, frame); diff --git a/tests/test-common.js b/tests/test-common.js index 6d34a3e5..960e24ef 100644 --- a/tests/test-common.js +++ b/tests/test-common.js @@ -126,8 +126,6 @@ const TEST_TYPES = { specVersion: ['json-ld-1.0'], // FIXME idRegex: [ - // ex - /frame-manifest.jsonld#tg001$/, // graphs /frame-manifest.jsonld#t0011$/, /frame-manifest.jsonld#t0010$/, @@ -177,12 +175,8 @@ const TEST_TYPES = { // lists /frame-manifest.jsonld#t0055$/, /frame-manifest.jsonld#t0058$/, - // misc - /frame-manifest.jsonld#tp010$/, - /frame-manifest.jsonld#tp050$/, - /frame-manifest.jsonld#teo01$/, + // @preserve and @container: @set /frame-manifest.jsonld#t0062$/, - /frame-manifest.jsonld#t0063$/, // @embed:@first /frame-manifest.jsonld#t0060$/, // requireAll From 3c71a7e568809ec39e69c529009f476c7b41c4c1 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Wed, 19 Feb 2020 17:36:16 -0800 Subject: [PATCH 03/20] Check for invalid values of `@embed`. --- CHANGELOG.md | 1 + lib/frame.js | 17 ++++++++++++++--- lib/jsonld.js | 8 ++------ tests/test-common.js | 2 -- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b5be6113..f60c04cb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ - Support for RDF transformation of `@direction` when `rdfDirection` is 'i18n-datatype'. - Top level `@graph` omitted if `omitGraph` is `true`. +- Check for invalid values of `@embed`. ## 2.0.2 - 2020-01-17 diff --git a/lib/frame.js b/lib/frame.js index c33ad57c..b1307a10 100644 --- a/lib/frame.js +++ b/lib/frame.js @@ -118,6 +118,13 @@ api.frame = (state, subjects, frame, parent, property = null) => { } state.link[id] = output; + // validate @embed + if((flags.embed === '@first' || flags.embed === '@last') && state.is11) { + throw new JsonLdError( + 'Invalid JSON-LD syntax; invalid value of @embed.', + 'jsonld.SyntaxError', {code: 'invalid @embed value', frame: frame}); + } + // if embed is @never or if a circular reference would be created by an // embed, the subject cannot be embedded, just add the reference; // note that a circular reference won't occur when the embed flag is @@ -346,11 +353,15 @@ function _getFrameFlag(frame, options, name) { // true => "@last" // false => "@never" if(rval === true) { - rval = '@last'; + rval = '@once'; } else if(rval === false) { rval = '@never'; - } else if(rval !== '@always' && rval !== '@never' && rval !== '@link') { - rval = '@last'; + } else if(rval !== '@always' && rval !== '@never' && rval !== '@link' && + rval !== '@first' && rval !== '@last' && rval !== '@once') + { + throw new JsonLdError( + 'Invalid JSON-LD syntax; invalid value of @embed.', + 'jsonld.SyntaxError', {code: 'invalid @embed value', frame: frame}); } } return rval; diff --git a/lib/jsonld.js b/lib/jsonld.js index 9dee5bf6..5b5be199 100644 --- a/lib/jsonld.js +++ b/lib/jsonld.js @@ -475,12 +475,6 @@ jsonld.frame = async function(input, frame, options) { if(!options.hasOwnProperty('pruneBlankNodeIdentifiers')) { options.pruneBlankNodeIdentifiers = _processingMode(activeCtx, 1.1); } - if((options.embed === '@first' || options.embed === '@last') && - _processingMode(activeCtx, 1.1)) - { - console.warn(`WARNING: ${options.embed} is not a valid value ` + - `of @embed in 1.1 mode.`); - } // expand input const expanded = await jsonld.expand(input, options); @@ -496,6 +490,8 @@ jsonld.frame = async function(input, frame, options) { const frameKeys = Object.keys(frame) .map(key => _expandIri(activeCtx, key, {vocab: true})); opts.merged = !frameKeys.includes('@graph'); + opts.is11 = _processingMode(activeCtx, 1.1); + // do framing const framed = _frameMergedOrDefault(expanded, expandedFrame, opts); diff --git a/tests/test-common.js b/tests/test-common.js index 960e24ef..1b770f0c 100644 --- a/tests/test-common.js +++ b/tests/test-common.js @@ -170,8 +170,6 @@ const TEST_TYPES = { // blank nodes /frame-manifest.jsonld#t0052$/, /frame-manifest.jsonld#t0053$/, - // embed - /frame-manifest.jsonld#t0054$/, // lists /frame-manifest.jsonld#t0055$/, /frame-manifest.jsonld#t0058$/, From bd9d4970d44a1b61d19ae9dd90825fe4c5be446d Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Thu, 20 Feb 2020 16:29:08 -0800 Subject: [PATCH 04/20] Fixes for object embedding and graph framing. - Changes in object embedding. - Better support for graph framing. --- CHANGELOG.md | 4 +- lib/frame.js | 128 +++++++++++++++++++++++++------------------ tests/test-common.js | 43 +-------------- 3 files changed, 80 insertions(+), 95 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f60c04cb..4ade0ad8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ - Keywords may not be used as prefixes. - Handle term definition on `@type` with empty map. - Handling of `@` values for `@reverse`. +- Changes in object embedding. +- Better support for graph framing. ### Changed - Keep term definitions mapping to null so they may be protected. @@ -34,7 +36,7 @@ - Support for expansion and compaction of values container `"@direction"`. - Support for RDF transformation of `@direction` when `rdfDirection` is 'i18n-datatype'. -- Top level `@graph` omitted if `omitGraph` is `true`. +- Top level `@graph` omitted if `omitGraph` is `true`. - Check for invalid values of `@embed`. ## 2.0.2 - 2020-01-17 diff --git a/lib/frame.js b/lib/frame.js index b1307a10..204b40eb 100644 --- a/lib/frame.js +++ b/lib/frame.js @@ -29,6 +29,7 @@ api.frameMergedOrDefault = (input, frame, options) => { // create framing state const state = { options, + embedded: false, graph: '@default', graphMap: {'@default': {}}, graphStack: [], @@ -83,6 +84,12 @@ api.frame = (state, subjects, frame, parent, property = null) => { requireAll: _getFrameFlag(frame, options, 'requireAll') }; + // get link for current graph + if(!state.link.hasOwnProperty(state.graph)) { + state.link[state.graph] = {}; + } + const link = state.link[state.graph]; + // filter out subjects that match the frame const matches = _filterSubjects(state, subjects, frame, flags); @@ -91,16 +98,6 @@ api.frame = (state, subjects, frame, parent, property = null) => { for(const id of ids) { const subject = matches[id]; - if(flags.embed === '@link' && id in state.link) { - // TODO: may want to also match an existing linked subject against - // the current frame ... so different frames could produce different - // subjects that are only shared in-memory when the frames are the same - - // add existing linked subject - _addFrameOutput(parent, property, state.link[id]); - continue; - } - /* Note: In order to treat each top-level match as a compartmentalized result, clear the unique embedded subjects map when the property is null, which only occurs at the top-level. */ @@ -110,27 +107,53 @@ api.frame = (state, subjects, frame, parent, property = null) => { state.uniqueEmbeds[state.graph] = state.uniqueEmbeds[state.graph] || {}; } + if(flags.embed === '@link' && id in link) { + // TODO: may want to also match an existing linked subject against + // the current frame ... so different frames could produce different + // subjects that are only shared in-memory when the frames are the same + + // add existing linked subject + _addFrameOutput(parent, property, link[id]); + continue; + } + // start output for subject - const output = {}; - output['@id'] = id; + const output = {'@id': id}; if(id.indexOf('_:') === 0) { util.addValue(state.bnodeMap, id, output, {propertyIsArray: true}); } - state.link[id] = output; + link[id] = output; // validate @embed if((flags.embed === '@first' || flags.embed === '@last') && state.is11) { throw new JsonLdError( 'Invalid JSON-LD syntax; invalid value of @embed.', - 'jsonld.SyntaxError', {code: 'invalid @embed value', frame: frame}); + 'jsonld.SyntaxError', {code: 'invalid @embed value', frame}); + } + + if(!state.embedded && state.uniqueEmbeds[state.graph].hasOwnProperty(id)) { + // skip adding this node object to the top level, as it was + // already included in another node object + continue; } // if embed is @never or if a circular reference would be created by an // embed, the subject cannot be embedded, just add the reference; // note that a circular reference won't occur when the embed flag is // `@link` as the above check will short-circuit before reaching this point - if(flags.embed === '@never' || - _createsCircularReference(subject, state.graph, state.subjectStack)) { + if(state.embedded && + (flags.embed === '@never' || + _createsCircularReference(subject, state.graph, state.subjectStack))) + { + _addFrameOutput(parent, property, output); + continue; + } + + // if only the first (or once) should be embedded + if(state.embedded && + (flags.embed == '@first' || flags.embed == '@once') && + state.uniqueEmbeds[state.graph].hasOwnProperty(id)) + { _addFrameOutput(parent, property, output); continue; } @@ -141,10 +164,10 @@ api.frame = (state, subjects, frame, parent, property = null) => { if(id in state.uniqueEmbeds[state.graph]) { _removeEmbed(state, id); } - state.uniqueEmbeds[state.graph][id] = - {parent, property}; } + state.uniqueEmbeds[state.graph][id] = {parent, property}; + // push matching subject onto stack to enable circular embed checks state.subjectStack.push({subject, graph: state.graph}); @@ -152,32 +175,31 @@ api.frame = (state, subjects, frame, parent, property = null) => { if(id in state.graphMap) { let recurse = false; let subframe = null; - if(!('@graph' in frame)) { + if(!frame.hasOwnProperty('@graph')) { recurse = state.graph !== '@merged'; subframe = {}; } else { subframe = frame['@graph'][0]; + recurse = !(id === '@merged' || id === '@default'); if(!types.isObject(subframe)) { subframe = {}; } - recurse = !(id === '@merged' || id === '@default'); } if(recurse) { state.graphStack.push(state.graph); - state.graph = id; // recurse into graph api.frame( - state, + Object.assign({}, state, {graph: id, embedded: false}), Object.keys(state.graphMap[id]).sort(), [subframe], output, '@graph'); - state.graph = state.graphStack.pop; + state.graphStack.pop; } } // if frame has @included, recurse over its sub-frame if('@included' in frame) { api.frame( - state, + Object.assign({}, state, {embedded: false}), subjects, frame['@included'], output, '@included'); } @@ -205,36 +227,37 @@ api.frame = (state, subjects, frame, parent, property = null) => { } // add objects - for(let o of subject[prop]) { + for(const o of subject[prop]) { const subframe = (prop in frame ? frame[prop] : _createImplicitFrame(flags)); // recurse into list if(graphTypes.isList(o)) { + const subframe = (frame[prop] && types.isObject(frame[prop][0]) ? + frame[prop][0]['@list'] : _createImplicitFrame(flags)); + // add empty list const list = {'@list': []}; _addFrameOutput(output, prop, list); // add list objects const src = o['@list']; - for(const n in src) { - o = src[n]; - if(graphTypes.isSubjectReference(o)) { - const subframe = (prop in frame ? - frame[prop][0]['@list'] : _createImplicitFrame(flags)); + for(const oo of src) { + if(graphTypes.isSubjectReference(oo)) { // recurse into subject reference - api.frame(state, [o['@id']], subframe, list, '@list'); + api.frame( + Object.assign({}, state, {embedded: true}), + [oo['@id']], subframe, list, '@list'); } else { // include other values automatically - _addFrameOutput(list, '@list', util.clone(o)); + _addFrameOutput(list, '@list', util.clone(oo)); } } - continue; - } - - if(graphTypes.isSubjectReference(o)) { + } else if(graphTypes.isSubjectReference(o)) { // recurse into subject reference - api.frame(state, [o['@id']], subframe, output, prop); + api.frame( + Object.assign({}, state, {embedded: true}), + [o['@id']], subframe, output, prop); } else if(_valueMatch(subframe[0], o)) { // include other values, if they match _addFrameOutput(output, prop, util.clone(o)); @@ -267,21 +290,20 @@ api.frame = (state, subjects, frame, parent, property = null) => { // if embed reverse values by finding nodes having this subject as a value // of the associated property - if('@reverse' in frame) { - for(const reverseProp of Object.keys(frame['@reverse']).sort()) { - const subframe = frame['@reverse'][reverseProp]; - for(const subject of Object.keys(state.subjects)) { - const nodeValues = - util.getValues(state.subjects[subject], reverseProp); - if(nodeValues.some(v => v['@id'] === id)) { - // node has property referencing this subject, recurse - output['@reverse'] = output['@reverse'] || {}; - util.addValue( - output['@reverse'], reverseProp, [], {propertyIsArray: true}); - api.frame( - state, [subject], subframe, output['@reverse'][reverseProp], - property); - } + for(const reverseProp of Object.keys(frame['@reverse'] || {}).sort()) { + const subframe = frame['@reverse'][reverseProp]; + for(const subject of Object.keys(state.subjects)) { + const nodeValues = + util.getValues(state.subjects[subject], reverseProp); + if(nodeValues.some(v => v['@id'] === id)) { + // node has property referencing this subject, recurse + output['@reverse'] = output['@reverse'] || {}; + util.addValue( + output['@reverse'], reverseProp, [], {propertyIsArray: true}); + api.frame( + Object.assign({}, state, {embedded: true}), + [subject], subframe, output['@reverse'][reverseProp], + property); } } } @@ -361,7 +383,7 @@ function _getFrameFlag(frame, options, name) { { throw new JsonLdError( 'Invalid JSON-LD syntax; invalid value of @embed.', - 'jsonld.SyntaxError', {code: 'invalid @embed value', frame: frame}); + 'jsonld.SyntaxError', {code: 'invalid @embed value', frame}); } } return rval; diff --git a/tests/test-common.js b/tests/test-common.js index 1b770f0c..acaf210f 100644 --- a/tests/test-common.js +++ b/tests/test-common.js @@ -126,47 +126,10 @@ const TEST_TYPES = { specVersion: ['json-ld-1.0'], // FIXME idRegex: [ - // graphs - /frame-manifest.jsonld#t0011$/, - /frame-manifest.jsonld#t0010$/, - /frame-manifest.jsonld#t0020$/, - /frame-manifest.jsonld#t0023$/, - /frame-manifest.jsonld#t0026$/, - /frame-manifest.jsonld#t0027$/, - /frame-manifest.jsonld#t0028$/, - /frame-manifest.jsonld#t0029$/, - /frame-manifest.jsonld#t0030$/, - /frame-manifest.jsonld#t0031$/, - /frame-manifest.jsonld#t0032$/, - /frame-manifest.jsonld#t0034$/, - /frame-manifest.jsonld#t0035$/, - /frame-manifest.jsonld#t0036$/, - /frame-manifest.jsonld#t0037$/, - /frame-manifest.jsonld#t0038$/, - /frame-manifest.jsonld#t0039$/, - /frame-manifest.jsonld#t0040$/, - /frame-manifest.jsonld#t0041$/, - /frame-manifest.jsonld#t0042$/, - /frame-manifest.jsonld#t0043$/, - /frame-manifest.jsonld#t0044$/, - /frame-manifest.jsonld#t0045$/, - /frame-manifest.jsonld#t0046$/, - /frame-manifest.jsonld#t0047$/, - /frame-manifest.jsonld#t0048$/, - /frame-manifest.jsonld#t0049$/, - /frame-manifest.jsonld#t0050$/, - /frame-manifest.jsonld#t0051$/, + // default value for @type /frame-manifest.jsonld#t0064$/, - /frame-manifest.jsonld#tg002$/, - /frame-manifest.jsonld#tg003$/, - /frame-manifest.jsonld#tg004$/, - /frame-manifest.jsonld#tg006$/, - /frame-manifest.jsonld#tg007$/, - /frame-manifest.jsonld#tg008$/, - /frame-manifest.jsonld#tg009$/, + // @container: @graph /frame-manifest.jsonld#tg010$/, - /frame-manifest.jsonld#tp046$/, - /frame-manifest.jsonld#tp049$/, // blank nodes /frame-manifest.jsonld#t0052$/, /frame-manifest.jsonld#t0053$/, @@ -175,8 +138,6 @@ const TEST_TYPES = { /frame-manifest.jsonld#t0058$/, // @preserve and @container: @set /frame-manifest.jsonld#t0062$/, - // @embed:@first - /frame-manifest.jsonld#t0060$/, // requireAll /frame-manifest.jsonld#tra01$/, /frame-manifest.jsonld#tra02$/, From 3365cf9693b02b3faff05942aca2945d2c60f84e Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Fri, 21 Feb 2020 16:39:23 -0800 Subject: [PATCH 05/20] Replace removePreserve. Replaced removePreserve with cleanupPreserve and cleanupNulls. --- CHANGELOG.md | 1 + lib/compact.js | 89 --------------------------------------- lib/frame.js | 110 ++++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 110 insertions(+), 90 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4ade0ad8..2cb56be9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ - `embed` to "@once" and warn on "@first" or "@last". - `pruneBlankNodeIdentifiers` based on processingMode. - `omitGraph` based on processingMode. +- replaced removePreserve with cleanupPreserve and cleanupNulls ### Added - Support for `"@import"`. diff --git a/lib/compact.js b/lib/compact.js index e0609a56..994a4ba5 100644 --- a/lib/compact.js +++ b/lib/compact.js @@ -1067,95 +1067,6 @@ api.compactValue = ({activeCtx, activeProperty, value, options}) => { }; }; -/** - * Removes the @preserve keywords as the last step of the compaction - * algorithm when it is running on framed output. - * - * @param ctx the active context used to compact the input. - * @param input the framed, compacted output. - * @param options the compaction options used. - * - * @return the resulting output. - */ -api.removePreserve = (ctx, input, options) => { - // recurse through arrays - if(_isArray(input)) { - const output = []; - for(let i = 0; i < input.length; ++i) { - const result = api.removePreserve(ctx, input[i], options); - // drop nulls from arrays - if(result !== null) { - output.push(result); - } - } - input = output; - } else if(_isObject(input)) { - // remove @preserve - if('@preserve' in input) { - if(input['@preserve'] === '@null') { - return null; - } - return input['@preserve']; - } - - // skip @values - if(_isValue(input)) { - return input; - } - - // recurse through @lists - if(_isList(input)) { - input['@list'] = api.removePreserve(ctx, input['@list'], options); - return input; - } - - // handle in-memory linked nodes - const idAlias = api.compactIri({ - activeCtx: ctx, - iri: '@id', - relativeTo: {vocab: true} - }); - if(input.hasOwnProperty(idAlias)) { - const id = input[idAlias]; - if(options.link.hasOwnProperty(id)) { - const idx = options.link[id].indexOf(input); - if(idx !== -1) { - // already visited - return options.link[id][idx]; - } - // prevent circular visitation - options.link[id].push(input); - } else { - // prevent circular visitation - options.link[id] = [input]; - } - } - - // recurse through properties - const graphAlias = api.compactIri({ - activeCtx: ctx, - iri: '@graph', - relativeTo: {vocab: true} - }); - for(const prop in input) { - // potentially remove the id, if it is an unreference bnode - if(prop === idAlias && options.bnodesToClear.includes(input[prop])) { - delete input[idAlias]; - continue; - } - - let result = api.removePreserve(ctx, input[prop], options); - const container = _getContextValue(ctx, prop, '@container') || []; - if(options.compactArrays && _isArray(result) && result.length === 1 && - container.length === 0 && prop !== graphAlias) { - result = result[0]; - } - input[prop] = result; - } - } - return input; -}; - /** * Picks the preferred compaction term from the given inverse context entry. * diff --git a/lib/frame.js b/lib/frame.js index 204b40eb..b3f5a7a3 100644 --- a/lib/frame.js +++ b/lib/frame.js @@ -59,7 +59,9 @@ api.frameMergedOrDefault = (input, frame, options) => { Object.keys(state.bnodeMap).filter(id => state.bnodeMap[id].length === 1); } - return framed; + // remove @preserve from results + options.link = {}; + return _cleanupPreserve(framed, options); }; /** @@ -316,6 +318,50 @@ api.frame = (state, subjects, frame, parent, property = null) => { } }; +/** + * Replace `@null` with `null`, removing it from arrays. + * + * @param input the framed, compacted output. + * @param options the framing options used. + * + * @return the resulting output. + */ +api.cleanupNull = (input, options) => { + // recurse through arrays + if(types.isArray(input)) { + const noNulls = input.map(v => api.cleanupNull(v, options)); + return noNulls.filter(v => v); // removes nulls from array + } + + if(input === '@null') { + return null; + } + + if(types.isObject(input)) { + // handle in-memory linked nodes + if(input.hasOwnProperty('@id')) { + const id = input['@id']; + if(options.link.hasOwnProperty(id)) { + const idx = options.link[id].indexOf(input); + if(idx !== -1) { + // already visited + return options.link[id][idx]; + } + // prevent circular visitation + options.link[id].push(input); + } else { + // prevent circular visitation + options.link[id] = [input]; + } + } + + for(const key in input) { + input[key] = api.cleanupNull(input[key], options); + } + } + return input; +}; + /** * Creates an implicit frame when recursing through subject matches. If * a frame doesn't have an explicit frame for a particular property, then @@ -614,6 +660,68 @@ function _removeEmbed(state, id) { removeDependents(id); } +/** + * Removes the @preserve keywords from expanded result of framing. + * + * @param input the framed, framed output. + * @param options the framing options used. + * + * @return the resulting output. + */ +function _cleanupPreserve(input, options) { + // recurse through arrays + if(types.isArray(input)) { + return input.map(value => _cleanupPreserve(value, options)); + } + + if(types.isObject(input)) { + // remove @preserve + if('@preserve' in input) { + return input['@preserve'][0]; + } + + // skip @values + if(graphTypes.isValue(input)) { + return input; + } + + // recurse through @lists + if(graphTypes.isList(input)) { + input['@list'] = _cleanupPreserve(input['@list'], options); + return input; + } + + // handle in-memory linked nodes + if(input.hasOwnProperty('@id')) { + const id = input['@id']; + if(options.link.hasOwnProperty(id)) { + const idx = options.link[id].indexOf(input); + if(idx !== -1) { + // already visited + return options.link[id][idx]; + } + // prevent circular visitation + options.link[id].push(input); + } else { + // prevent circular visitation + options.link[id] = [input]; + } + } + + // recurse through properties + for(const prop in input) { + // potentially remove the id, if it is an unreference bnode + if(prop === '@id' && options.bnodesToClear.includes(input[prop])) { + delete input['@id']; + continue; + } + + input[prop] = _cleanupPreserve(input[prop], options); + } + } + return input; +}; + /** * Adds framing output to the given parent. * From 85a8ee81c409b43fe9220d94830ecea8cfea6ae5 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Fri, 21 Feb 2020 16:47:38 -0800 Subject: [PATCH 06/20] Support default values for `@type` when framing. --- CHANGELOG.md | 1 + lib/expand.js | 15 ++++++++++++++- lib/frame.js | 23 ++++++++++++++++++----- lib/jsonld.js | 21 ++++++++++----------- lib/util.js | 40 +++++++++++++++++++++------------------- tests/test-common.js | 6 ------ 6 files changed, 64 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cb56be9..6377345b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -39,6 +39,7 @@ 'i18n-datatype'. - Top level `@graph` omitted if `omitGraph` is `true`. - Check for invalid values of `@embed`. +- Support default values for `@type` when framing. ## 2.0.2 - 2020-01-17 diff --git a/lib/expand.js b/lib/expand.js index b20f1bde..f502b8b8 100644 --- a/lib/expand.js +++ b/lib/expand.js @@ -515,7 +515,20 @@ async function _expandObject({ } if(expandedProperty === '@type') { - _validateTypeValue(value); + // if framing, can be a default object, but need to expand + // key to determine that + if(_isObject(value)) { + const expandedValue = {}; + for(const [k, v] of Object.entries(value)) { + const kk = _expandIri(typeScopedContext, k, {vocab: true}); + const vv = _asArray(v).map(vvv => + _expandIri(typeScopedContext, vvv, {base: true, vocab: true}) + ); + expandedValue[kk] = vv; + } + value = expandedValue; + } + _validateTypeValue(value, options.isFrame); _addValue( expandedParent, '@type', _asArray(value).map(v => diff --git a/lib/frame.js b/lib/frame.js index b3f5a7a3..336d519e 100644 --- a/lib/frame.js +++ b/lib/frame.js @@ -270,7 +270,14 @@ api.frame = (state, subjects, frame, parent, property = null) => { // handle defaults for(const prop of Object.keys(frame).sort()) { // skip keywords - if(isKeyword(prop)) { + if(prop === '@type') { + if(!types.isObject(frame[prop][0]) || + !frame[prop][0].hasOwnProperty('@default')) + { + continue; + } + // allow through default types + } else if(isKeyword(prop)) { continue; } @@ -526,18 +533,24 @@ function _filterSubject(state, subject, frame, flags) { matchThis = true; } else if(frame['@type'].length === 1 && types.isEmptyObject(frame['@type'][0])) { - // match on wildcard @type + // match on wildcard @type if there is a type matchThis = nodeValues.length > 0; } else { // match on a specific @type for(const type of frame['@type']) { - if(nodeValues.some(tt => tt === type)) { - return true; + if(types.isObject(type) && '@default' in type) { + // match on default object + matchThis = true; + } else { + matchThis = matchThis || nodeValues.some(tt => tt === type); } } - return false; + } + if(!flags.requireAll) { + return matchThis; } } + continue; } // Forc a copy of this frame entry so it can be manipulated diff --git a/lib/jsonld.js b/lib/jsonld.js index 5b5be199..c5e718fc 100644 --- a/lib/jsonld.js +++ b/lib/jsonld.js @@ -48,7 +48,9 @@ const {fromRDF: _fromRDF} = require('./fromRdf'); const {toRDF: _toRDF} = require('./toRdf'); const { - frameMergedOrDefault: _frameMergedOrDefault + frameMergedOrDefault: _frameMergedOrDefault, + cleanupNull: _cleanupNull, + cleanupPreserve: _cleanupPreserve } = require('./frame'); const { @@ -70,8 +72,7 @@ const { const { compact: _compact, - compactIri: _compactIri, - removePreserve: _removePreserve + compactIri: _compactIri } = require('./compact'); const { @@ -225,12 +226,6 @@ jsonld.compact = async function(input, ctx, options) { ctx = ctx[0]; } - if(options.framing) { - // remove @preserve from results - options.link = {}; - compacted = _removePreserve(activeCtx, compacted, options); - } - // add context and/or @graph if(_isArray(compacted)) { // use '@graph' keyword @@ -493,13 +488,17 @@ jsonld.frame = async function(input, frame, options) { opts.is11 = _processingMode(activeCtx, 1.1); // do framing - const framed = _frameMergedOrDefault(expanded, expandedFrame, opts); + let framed = _frameMergedOrDefault(expanded, expandedFrame, opts); opts.graph = !options.omitGraph; opts.skipExpansion = true; opts.link = {}; opts.framing = true; - const compacted = await jsonld.compact(framed, frameContext, opts); + let compacted = await jsonld.compact(framed, frameContext, opts); + + // replace @null with null, compacting arrays + opts.link = {}; + compacted = _cleanupNull(compacted, opts); return compacted; }; diff --git a/lib/util.js b/lib/util.js index b250d51d..b9cef080 100644 --- a/lib/util.js +++ b/lib/util.js @@ -147,31 +147,33 @@ api.parseLinkHeader = header => { * * @param v the value to check. */ -api.validateTypeValue = v => { - // can be a string or an empty object - if(types.isString(v) || types.isEmptyObject(v)) { +api.validateTypeValue = (v, isFrame) => { + if(types.isString(v)) { return; } - // must be an array - let isValid = false; - if(types.isArray(v)) { - // must contain only strings - isValid = true; - for(let i = 0; i < v.length; ++i) { - if(!(types.isString(v[i]))) { - isValid = false; - break; - } + if(types.isArray(v) && v.every(vv => types.isString(vv))) { + return; + } else if(isFrame && types.isObject(v)) { + switch(Object.keys(v).length) { + case 0: + // empty object is wildcard + return; + case 1: + // default entry is all strings + if('@default' in v && + api.asArray(v['@default']).every(vv => types.isString(vv))) + { + return; + } } } - if(!isValid) { - throw new JsonLdError( - 'Invalid JSON-LD syntax; "@type" value must a string, an array of ' + - 'strings, or an empty object.', 'jsonld.SyntaxError', - {code: 'invalid type value', value: v}); - } + throw new JsonLdError( + 'Invalid JSON-LD syntax; "@type" value must a string, an array of ' + + 'strings, an empty object, ' + + 'or a default object.', 'jsonld.SyntaxError', + {code: 'invalid type value', value: v}); }; /** diff --git a/tests/test-common.js b/tests/test-common.js index acaf210f..49fd4c19 100644 --- a/tests/test-common.js +++ b/tests/test-common.js @@ -126,18 +126,12 @@ const TEST_TYPES = { specVersion: ['json-ld-1.0'], // FIXME idRegex: [ - // default value for @type - /frame-manifest.jsonld#t0064$/, - // @container: @graph - /frame-manifest.jsonld#tg010$/, // blank nodes /frame-manifest.jsonld#t0052$/, /frame-manifest.jsonld#t0053$/, // lists /frame-manifest.jsonld#t0055$/, /frame-manifest.jsonld#t0058$/, - // @preserve and @container: @set - /frame-manifest.jsonld#t0062$/, // requireAll /frame-manifest.jsonld#tra01$/, /frame-manifest.jsonld#tra02$/, From f6fea3522bb47a5f80fbc269ea887545dd9db0c1 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Fri, 21 Feb 2020 17:23:36 -0800 Subject: [PATCH 07/20] Better frame validation. --- CHANGELOG.md | 1 + lib/frame.js | 29 ++++++++++++++++++++++++++++- lib/jsonld.js | 5 ++--- tests/test-common.js | 3 --- 4 files changed, 31 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6377345b..b82cc881 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Handling of `@` values for `@reverse`. - Changes in object embedding. - Better support for graph framing. +- Better frame validation. ### Changed - Keep term definitions mapping to null so they may be protected. diff --git a/lib/frame.js b/lib/frame.js index 336d519e..da44b781 100644 --- a/lib/frame.js +++ b/lib/frame.js @@ -7,6 +7,7 @@ const {isKeyword} = require('./context'); const graphTypes = require('./graphTypes'); const types = require('./types'); const util = require('./util'); +const url = require('./url'); const JsonLdError = require('./JsonLdError'); const { createNodeMap: _createNodeMap, @@ -453,6 +454,32 @@ function _validateFrame(frame) { 'Invalid JSON-LD syntax; a JSON-LD frame must be a single object.', 'jsonld.SyntaxError', {frame}); } + + if(frame[0].hasOwnProperty('@id')) { + for(const id of util.asArray(frame[0]['@id'])) { + // @id must be wildcard or an IRI + if(!(types.isObject(id) || url.isAbsolute(id)) || + (types.isString(id) && id.indexOf('_:') === 0)) + { + throw new JsonLdError( + 'Invalid JSON-LD syntax; invalid @id in frame.', + 'jsonld.SyntaxError', {code: 'invalid frame', frame}); + } + } + } + + if(frame[0].hasOwnProperty('@type')) { + for(const type of util.asArray(frame[0]['@type'])) { + // @id must be wildcard or an IRI + if(!(types.isObject(type) || url.isAbsolute(type)) || + (types.isString(type) && type.indexOf('_:') === 0)) + { + throw new JsonLdError( + 'Invalid JSON-LD syntax; invalid @type in frame.', + 'jsonld.SyntaxError', {code: 'invalid frame', frame}); + } + } + } } /** @@ -733,7 +760,7 @@ function _cleanupPreserve(input, options) { } } return input; -}; +} /** * Adds framing output to the given parent. diff --git a/lib/jsonld.js b/lib/jsonld.js index c5e718fc..ebd91bf5 100644 --- a/lib/jsonld.js +++ b/lib/jsonld.js @@ -49,8 +49,7 @@ const {toRDF: _toRDF} = require('./toRdf'); const { frameMergedOrDefault: _frameMergedOrDefault, - cleanupNull: _cleanupNull, - cleanupPreserve: _cleanupPreserve + cleanupNull: _cleanupNull } = require('./frame'); const { @@ -488,7 +487,7 @@ jsonld.frame = async function(input, frame, options) { opts.is11 = _processingMode(activeCtx, 1.1); // do framing - let framed = _frameMergedOrDefault(expanded, expandedFrame, opts); + const framed = _frameMergedOrDefault(expanded, expandedFrame, opts); opts.graph = !options.omitGraph; opts.skipExpansion = true; diff --git a/tests/test-common.js b/tests/test-common.js index 49fd4c19..257cafad 100644 --- a/tests/test-common.js +++ b/tests/test-common.js @@ -126,9 +126,6 @@ const TEST_TYPES = { specVersion: ['json-ld-1.0'], // FIXME idRegex: [ - // blank nodes - /frame-manifest.jsonld#t0052$/, - /frame-manifest.jsonld#t0053$/, // lists /frame-manifest.jsonld#t0055$/, /frame-manifest.jsonld#t0058$/, From 5b8588fb1f85a833d0609b6c2400c598dbcddf55 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Sun, 23 Feb 2020 15:09:43 -0800 Subject: [PATCH 08/20] Apply suggestion from @davidlehn on use of `Object.fromEntries`. --- lib/expand.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/expand.js b/lib/expand.js index f502b8b8..a867f719 100644 --- a/lib/expand.js +++ b/lib/expand.js @@ -518,15 +518,12 @@ async function _expandObject({ // if framing, can be a default object, but need to expand // key to determine that if(_isObject(value)) { - const expandedValue = {}; - for(const [k, v] of Object.entries(value)) { - const kk = _expandIri(typeScopedContext, k, {vocab: true}); - const vv = _asArray(v).map(vvv => - _expandIri(typeScopedContext, vvv, {base: true, vocab: true}) - ); - expandedValue[kk] = vv; - } - value = expandedValue; + value = Object.fromEntries(Object.entries(value).map(([k, v]) => [ + _expandIri(typeScopedContext, k, {vocab: true}), + _asArray(v).map(vv => + _expandIri(typeScopedContext, vv, {base: true, vocab: true}) + ) + ])); } _validateTypeValue(value, options.isFrame); _addValue( From fab9a1a042a48e15836a840bf5e1825a71528428 Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Sun, 23 Feb 2020 17:32:08 -0500 Subject: [PATCH 09/20] Add Object.entries polyfill. --- tests/test-karma.js | 1 + webpack.config.js | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/test-karma.js b/tests/test-karma.js index c8f0923a..8f4b8ce1 100644 --- a/tests/test-karma.js +++ b/tests/test-karma.js @@ -35,6 +35,7 @@ require('core-js/fn/array/from'); require('core-js/fn/array/includes'); require('core-js/fn/map'); require('core-js/fn/object/assign'); +require('core-js/fn/object/entries'); require('core-js/fn/promise'); require('core-js/fn/set'); require('core-js/fn/symbol'); diff --git a/webpack.config.js b/webpack.config.js index d70598ad..feda9b84 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -22,6 +22,7 @@ const outputs = [ 'core-js/fn/array/includes', 'core-js/fn/map', 'core-js/fn/object/assign', + 'core-js/fn/object/entries', 'core-js/fn/promise', 'core-js/fn/set', 'core-js/fn/string/starts-with', From 7ee698cb040a34dc89ff2359f96766741ff3719b Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Sun, 23 Feb 2020 19:02:34 -0500 Subject: [PATCH 10/20] Add Object.entries/fromEntries node6 support. --- lib/index.js | 7 +++++++ package.json | 1 + 2 files changed, 8 insertions(+) diff --git a/lib/index.js b/lib/index.js index c91a88ae..ffa4c3e4 100644 --- a/lib/index.js +++ b/lib/index.js @@ -5,8 +5,15 @@ * * Copyright 2010-2017 Digital Bazaar, Inc. */ +// FIXME: remove after change to core-js 3 and dropping node6 support +const fromEntries = require('object.fromentries'); +if(!Object.fromEntries) { + fromEntries.shim(); +} + if(require('semver').gte(process.version, '8.6.0')) { module.exports = require('./jsonld'); } else { + require('core-js/fn/object/entries'); module.exports = require('../dist/node6/lib/jsonld'); } diff --git a/package.json b/package.json index 20bf730e..0ceb436e 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "dependencies": { "canonicalize": "^1.0.1", "lru-cache": "^5.1.1", + "object.fromentries": "^2.0.2", "rdf-canonize": "^1.0.2", "request": "^2.88.0", "semver": "^6.3.0", From 97314aee27170d93e42025c43caf81c8398814cd Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Sun, 23 Feb 2020 16:14:33 -0800 Subject: [PATCH 11/20] Wildcard matching on `@id` and other requireAll semantics --- CHANGELOG.md | 1 + lib/frame.js | 177 +++++++++++++++++++++---------------------- tests/test-common.js | 6 -- 3 files changed, 87 insertions(+), 97 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b82cc881..ded4fc2a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ - Changes in object embedding. - Better support for graph framing. - Better frame validation. +- Wildcard matching on `@id` and other requireAll semantics. ### Changed - Keep term definitions mapping to null so they may be protected. diff --git a/lib/frame.js b/lib/frame.js index da44b781..3f8f49c9 100644 --- a/lib/frame.js +++ b/lib/frame.js @@ -532,111 +532,106 @@ function _filterSubject(state, subject, frame, flags) { const nodeValues = util.getValues(subject, key); const isEmpty = util.getValues(frame, key).length === 0; - if(isKeyword(key)) { - // skip non-@id and non-@type - if(key !== '@id' && key !== '@type') { - continue; + if(key === '@id') { + // match on no @id or any matching @id, including wildcard + if(types.isEmptyObject(frame['@id'][0] || {})) { + matchThis = true; + } else if(frame['@id'].length >= 0) { + matchThis = frame['@id'].includes(nodeValues[0]); + } + if(!flags.requireAll) { + return matchThis; } + } else if(key === '@type') { + // check @type (object value means 'any' type, + // fall through to ducktyping) wildcard = false; - - // check @id for a specific @id value - if(key === '@id') { - // if @id is not a wildcard and is not empty, then match or not on - // specific value - if(frame['@id'].length >= 0 && !types.isEmptyObject(frame['@id'][0])) { - return frame['@id'].includes(nodeValues[0]); + if(isEmpty) { + if(nodeValues.length > 0) { + // don't match on no @type + return false; } matchThis = true; - continue; - } - - // check @type (object value means 'any' type, fall through to ducktyping) - if('@type' in frame) { - if(isEmpty) { - if(nodeValues.length > 0) { - // don't match on no @type - return false; - } - matchThis = true; - } else if(frame['@type'].length === 1 && - types.isEmptyObject(frame['@type'][0])) { - // match on wildcard @type if there is a type - matchThis = nodeValues.length > 0; - } else { - // match on a specific @type - for(const type of frame['@type']) { - if(types.isObject(type) && '@default' in type) { - // match on default object - matchThis = true; - } else { - matchThis = matchThis || nodeValues.some(tt => tt === type); - } + } else if(frame['@type'].length === 1 && + types.isEmptyObject(frame['@type'][0])) { + // match on wildcard @type if there is a type + matchThis = nodeValues.length > 0; + } else { + // match on a specific @type + for(const type of frame['@type']) { + if(types.isObject(type) && '@default' in type) { + // match on default object + matchThis = true; + } else { + matchThis = matchThis || nodeValues.some(tt => tt === type); } } - if(!flags.requireAll) { - return matchThis; - } } + if(!flags.requireAll) { + return matchThis; + } + } else if(isKeyword(key)) { continue; - } - - // Forc a copy of this frame entry so it can be manipulated - const thisFrame = util.getValues(frame, key)[0]; - let hasDefault = false; - if(thisFrame) { - _validateFrame([thisFrame]); - hasDefault = '@default' in thisFrame; - } - - // no longer a wildcard pattern if frame has any non-keyword properties - wildcard = false; + } else { + // Force a copy of this frame entry so it can be manipulated + const thisFrame = util.getValues(frame, key)[0]; + let hasDefault = false; + if(thisFrame) { + _validateFrame([thisFrame]); + hasDefault = '@default' in thisFrame; + } - // skip, but allow match if node has no value for property, and frame has a - // default value - if(nodeValues.length === 0 && hasDefault) { - continue; - } + // no longer a wildcard pattern if frame has any non-keyword properties + wildcard = false; - // if frame value is empty, don't match if subject has any value - if(nodeValues.length > 0 && isEmpty) { - return false; - } + // skip, but allow match if node has no value for property, and frame has a + // default value + if(nodeValues.length === 0 && hasDefault) { + continue; + } - if(thisFrame === undefined) { - // node does not match if values is not empty and the value of property - // in frame is match none. - if(nodeValues.length > 0) { + // if frame value is empty, don't match if subject has any value + if(nodeValues.length > 0 && isEmpty) { return false; } - matchThis = true; - } else if(types.isObject(thisFrame)) { - // node matches if values is not empty and the value of property in frame - // is wildcard - matchThis = nodeValues.length > 0; - } else { - if(graphTypes.isValue(thisFrame)) { - // match on any matching value - matchThis = nodeValues.some(nv => _valueMatch(thisFrame, nv)); - } else if(graphTypes.isSubject(thisFrame) || - graphTypes.isSubjectReference(thisFrame)) { - matchThis = - nodeValues.some(nv => _nodeMatch(state, thisFrame, nv, flags)); - } else if(graphTypes.isList(thisFrame)) { - const listValue = thisFrame['@list'][0]; - if(graphTypes.isList(nodeValues[0])) { - const nodeListValues = nodeValues[0]['@list']; - - if(graphTypes.isValue(listValue)) { - // match on any matching value - matchThis = nodeListValues.some(lv => _valueMatch(listValue, lv)); - } else if(graphTypes.isSubject(listValue) || - graphTypes.isSubjectReference(listValue)) { - matchThis = nodeListValues.some(lv => _nodeMatch( - state, listValue, lv, flags)); + + if(thisFrame === undefined) { + // node does not match if values is not empty and the value of property + // in frame is match none. + if(nodeValues.length > 0) { + return false; + } + matchThis = true; + } else if(types.isObject(thisFrame)) { // XXX only framing keywords + // node matches if values is not empty and the value of property in frame + // is wildcard + matchThis = nodeValues.length > 0; + } else { + if(graphTypes.isValue(thisFrame)) { + // match on any matching value + matchThis = nodeValues.some(nv => _valueMatch(thisFrame, nv)); + } else if(graphTypes.isSubject(thisFrame) || + graphTypes.isSubjectReference(thisFrame)) + { + matchThis = + nodeValues.some(nv => _nodeMatch(state, thisFrame, nv, flags)); + } else if(graphTypes.isList(thisFrame)) { + const listValue = thisFrame['@list'][0]; + if(graphTypes.isList(nodeValues[0])) { + const nodeListValues = nodeValues[0]['@list']; + + if(graphTypes.isValue(listValue)) { + // match on any matching value + matchThis = nodeListValues.some(lv => _valueMatch(listValue, lv)); + } else if(graphTypes.isSubject(listValue) || + graphTypes.isSubjectReference(listValue)) { + matchThis = nodeListValues.some(lv => _nodeMatch( + state, listValue, lv, flags)); + } + } else { + // value must be a list to match + matchThis = false; } - } else { - // value must be a list to match - matchThis = false; } } } diff --git a/tests/test-common.js b/tests/test-common.js index 257cafad..b449739a 100644 --- a/tests/test-common.js +++ b/tests/test-common.js @@ -129,12 +129,6 @@ const TEST_TYPES = { // lists /frame-manifest.jsonld#t0055$/, /frame-manifest.jsonld#t0058$/, - // requireAll - /frame-manifest.jsonld#tra01$/, - /frame-manifest.jsonld#tra02$/, - /frame-manifest.jsonld#tra03$/, - // wildcard - /frame-manifest.jsonld#t0061$/, // included /frame-manifest.jsonld#tin01$/, /frame-manifest.jsonld#tin02$/, From e56f14b9f9c3ec47909e0637366c8c0e8a9b3d91 Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Mon, 24 Feb 2020 14:10:54 -0500 Subject: [PATCH 12/20] Fix brace style. Co-Authored-By: Dave Longley --- lib/frame.js | 21 +++++++-------------- lib/util.js | 3 +-- 2 files changed, 8 insertions(+), 16 deletions(-) diff --git a/lib/frame.js b/lib/frame.js index 3f8f49c9..5256accf 100644 --- a/lib/frame.js +++ b/lib/frame.js @@ -146,8 +146,7 @@ api.frame = (state, subjects, frame, parent, property = null) => { // `@link` as the above check will short-circuit before reaching this point if(state.embedded && (flags.embed === '@never' || - _createsCircularReference(subject, state.graph, state.subjectStack))) - { + _createsCircularReference(subject, state.graph, state.subjectStack))) { _addFrameOutput(parent, property, output); continue; } @@ -155,8 +154,7 @@ api.frame = (state, subjects, frame, parent, property = null) => { // if only the first (or once) should be embedded if(state.embedded && (flags.embed == '@first' || flags.embed == '@once') && - state.uniqueEmbeds[state.graph].hasOwnProperty(id)) - { + state.uniqueEmbeds[state.graph].hasOwnProperty(id)) { _addFrameOutput(parent, property, output); continue; } @@ -273,8 +271,7 @@ api.frame = (state, subjects, frame, parent, property = null) => { // skip keywords if(prop === '@type') { if(!types.isObject(frame[prop][0]) || - !frame[prop][0].hasOwnProperty('@default')) - { + !frame[prop][0].hasOwnProperty('@default')) { continue; } // allow through default types @@ -433,8 +430,7 @@ function _getFrameFlag(frame, options, name) { } else if(rval === false) { rval = '@never'; } else if(rval !== '@always' && rval !== '@never' && rval !== '@link' && - rval !== '@first' && rval !== '@last' && rval !== '@once') - { + rval !== '@first' && rval !== '@last' && rval !== '@once') { throw new JsonLdError( 'Invalid JSON-LD syntax; invalid value of @embed.', 'jsonld.SyntaxError', {code: 'invalid @embed value', frame}); @@ -459,8 +455,7 @@ function _validateFrame(frame) { for(const id of util.asArray(frame[0]['@id'])) { // @id must be wildcard or an IRI if(!(types.isObject(id) || url.isAbsolute(id)) || - (types.isString(id) && id.indexOf('_:') === 0)) - { + (types.isString(id) && id.indexOf('_:') === 0)) { throw new JsonLdError( 'Invalid JSON-LD syntax; invalid @id in frame.', 'jsonld.SyntaxError', {code: 'invalid frame', frame}); @@ -472,8 +467,7 @@ function _validateFrame(frame) { for(const type of util.asArray(frame[0]['@type'])) { // @id must be wildcard or an IRI if(!(types.isObject(type) || url.isAbsolute(type)) || - (types.isString(type) && type.indexOf('_:') === 0)) - { + (types.isString(type) && type.indexOf('_:') === 0)) { throw new JsonLdError( 'Invalid JSON-LD syntax; invalid @type in frame.', 'jsonld.SyntaxError', {code: 'invalid frame', frame}); @@ -611,8 +605,7 @@ function _filterSubject(state, subject, frame, flags) { // match on any matching value matchThis = nodeValues.some(nv => _valueMatch(thisFrame, nv)); } else if(graphTypes.isSubject(thisFrame) || - graphTypes.isSubjectReference(thisFrame)) - { + graphTypes.isSubjectReference(thisFrame)) { matchThis = nodeValues.some(nv => _nodeMatch(state, thisFrame, nv, flags)); } else if(graphTypes.isList(thisFrame)) { diff --git a/lib/util.js b/lib/util.js index b9cef080..896060cf 100644 --- a/lib/util.js +++ b/lib/util.js @@ -162,8 +162,7 @@ api.validateTypeValue = (v, isFrame) => { case 1: // default entry is all strings if('@default' in v && - api.asArray(v['@default']).every(vv => types.isString(vv))) - { + api.asArray(v['@default']).every(vv => types.isString(vv))) { return; } } From 6860bc9ab62b67c8a4a9fc6aff34191cddfb3b50 Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Mon, 24 Feb 2020 14:13:57 -0500 Subject: [PATCH 13/20] Fix style. --- lib/expand.js | 3 +-- lib/frame.js | 12 ++++++------ lib/fromRdf.js | 3 +-- lib/toRdf.js | 3 +-- 4 files changed, 9 insertions(+), 12 deletions(-) diff --git a/lib/expand.js b/lib/expand.js index a867f719..44c5102f 100644 --- a/lib/expand.js +++ b/lib/expand.js @@ -466,8 +466,7 @@ async function _expandObject({ } if(expandedProperty in expandedParent && expandedProperty !== '@included' && - expandedProperty !== '@type') - { + expandedProperty !== '@type') { throw new JsonLdError( 'Invalid JSON-LD syntax; colliding keywords detected.', 'jsonld.SyntaxError', diff --git a/lib/frame.js b/lib/frame.js index 5256accf..5511648a 100644 --- a/lib/frame.js +++ b/lib/frame.js @@ -455,7 +455,7 @@ function _validateFrame(frame) { for(const id of util.asArray(frame[0]['@id'])) { // @id must be wildcard or an IRI if(!(types.isObject(id) || url.isAbsolute(id)) || - (types.isString(id) && id.indexOf('_:') === 0)) { + (types.isString(id) && id.indexOf('_:') === 0)) { throw new JsonLdError( 'Invalid JSON-LD syntax; invalid @id in frame.', 'jsonld.SyntaxError', {code: 'invalid frame', frame}); @@ -467,7 +467,7 @@ function _validateFrame(frame) { for(const type of util.asArray(frame[0]['@type'])) { // @id must be wildcard or an IRI if(!(types.isObject(type) || url.isAbsolute(type)) || - (types.isString(type) && type.indexOf('_:') === 0)) { + (types.isString(type) && type.indexOf('_:') === 0)) { throw new JsonLdError( 'Invalid JSON-LD syntax; invalid @type in frame.', 'jsonld.SyntaxError', {code: 'invalid frame', frame}); @@ -578,8 +578,8 @@ function _filterSubject(state, subject, frame, flags) { // no longer a wildcard pattern if frame has any non-keyword properties wildcard = false; - // skip, but allow match if node has no value for property, and frame has a - // default value + // skip, but allow match if node has no value for property, and frame has + // a default value if(nodeValues.length === 0 && hasDefault) { continue; } @@ -597,8 +597,8 @@ function _filterSubject(state, subject, frame, flags) { } matchThis = true; } else if(types.isObject(thisFrame)) { // XXX only framing keywords - // node matches if values is not empty and the value of property in frame - // is wildcard + // node matches if values is not empty and the value of property in + // frame is wildcard matchThis = nodeValues.length > 0; } else { if(graphTypes.isValue(thisFrame)) { diff --git a/lib/fromRdf.js b/lib/fromRdf.js index 84986bae..fb3567c8 100644 --- a/lib/fromRdf.js +++ b/lib/fromRdf.js @@ -329,8 +329,7 @@ function _RDFToObject(o, useNativeTypes, rdfDirection) { rval['@type'] = type; } } else if(rdfDirection === 'i18n-datatype' && - type.startsWith('https://www.w3.org/ns/i18n#')) - { + type.startsWith('https://www.w3.org/ns/i18n#')) { const [, language, direction] = type.split(/[#_]/); if(language.length > 0) { rval['@language'] = language; diff --git a/lib/toRdf.js b/lib/toRdf.js index 61a056df..d19980c1 100644 --- a/lib/toRdf.js +++ b/lib/toRdf.js @@ -245,8 +245,7 @@ function _objectToRDF(item, issuer, dataset, graphTerm, rdfDirection) { object.value = value.toFixed(0); object.datatype.value = datatype || XSD_INTEGER; } else if(rdfDirection === 'i18n-datatype' && - '@direction' in item) - { + '@direction' in item) { const datatype = 'https://www.w3.org/ns/i18n#' + (item['@language'] || '') + `_${item['@direction']}`; From 4e4743ac0c05d0771ece499fc698974f2de7614f Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Mon, 24 Feb 2020 14:20:17 -0500 Subject: [PATCH 14/20] Use object rest spread. Co-Authored-By: Dave Longley --- lib/frame.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/frame.js b/lib/frame.js index 5511648a..df736b98 100644 --- a/lib/frame.js +++ b/lib/frame.js @@ -191,7 +191,7 @@ api.frame = (state, subjects, frame, parent, property = null) => { state.graphStack.push(state.graph); // recurse into graph api.frame( - Object.assign({}, state, {graph: id, embedded: false}), + {...state, graph: id, embedded: false}, Object.keys(state.graphMap[id]).sort(), [subframe], output, '@graph'); state.graphStack.pop; } @@ -200,7 +200,7 @@ api.frame = (state, subjects, frame, parent, property = null) => { // if frame has @included, recurse over its sub-frame if('@included' in frame) { api.frame( - Object.assign({}, state, {embedded: false}), + {...state, embedded: false}, subjects, frame['@included'], output, '@included'); } @@ -247,7 +247,7 @@ api.frame = (state, subjects, frame, parent, property = null) => { if(graphTypes.isSubjectReference(oo)) { // recurse into subject reference api.frame( - Object.assign({}, state, {embedded: true}), + {...state, embedded: true}, [oo['@id']], subframe, list, '@list'); } else { // include other values automatically @@ -257,7 +257,7 @@ api.frame = (state, subjects, frame, parent, property = null) => { } else if(graphTypes.isSubjectReference(o)) { // recurse into subject reference api.frame( - Object.assign({}, state, {embedded: true}), + {...state, embedded: true}, [o['@id']], subframe, output, prop); } else if(_valueMatch(subframe[0], o)) { // include other values, if they match @@ -308,7 +308,7 @@ api.frame = (state, subjects, frame, parent, property = null) => { util.addValue( output['@reverse'], reverseProp, [], {propertyIsArray: true}); api.frame( - Object.assign({}, state, {embedded: true}), + {...state, embedded: true}, [subject], subframe, output['@reverse'][reverseProp], property); } From e1217fc9b0678209627d6122a46b60fc496e4143 Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Mon, 24 Feb 2020 14:28:59 -0500 Subject: [PATCH 15/20] Improve conditional. --- lib/util.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/util.js b/lib/util.js index 896060cf..77da8f61 100644 --- a/lib/util.js +++ b/lib/util.js @@ -154,7 +154,8 @@ api.validateTypeValue = (v, isFrame) => { if(types.isArray(v) && v.every(vv => types.isString(vv))) { return; - } else if(isFrame && types.isObject(v)) { + } + if(isFrame && types.isObject(v)) { switch(Object.keys(v).length) { case 0: // empty object is wildcard @@ -162,7 +163,7 @@ api.validateTypeValue = (v, isFrame) => { case 1: // default entry is all strings if('@default' in v && - api.asArray(v['@default']).every(vv => types.isString(vv))) { + api.asArray(v['@default']).every(vv => types.isString(vv))) { return; } } From 93871558bcb6cfb9f13c40578513a9f4fb00e59b Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Mon, 24 Feb 2020 14:30:42 -0500 Subject: [PATCH 16/20] Update changelog. --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ded4fc2a..2f0c2a4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,7 +19,7 @@ - Changes in object embedding. - Better support for graph framing. - Better frame validation. -- Wildcard matching on `@id` and other requireAll semantics. +- Wildcard matching on `@id` and other `requireAll` semantics. ### Changed - Keep term definitions mapping to null so they may be protected. @@ -30,7 +30,7 @@ - `embed` to "@once" and warn on "@first" or "@last". - `pruneBlankNodeIdentifiers` based on processingMode. - `omitGraph` based on processingMode. -- replaced removePreserve with cleanupPreserve and cleanupNulls +- Replaced `removePreserve` with `cleanupPreserve` and `cleanupNulls`. ### Added - Support for `"@import"`. From bb4b89cb87ca9d31e0f7d412429e7d9062b4a9e7 Mon Sep 17 00:00:00 2001 From: Gregg Kellogg Date: Mon, 24 Feb 2020 17:15:07 -0700 Subject: [PATCH 17/20] Go back to @graph in frame usage. --- lib/frame.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/frame.js b/lib/frame.js index df736b98..9d9a35ed 100644 --- a/lib/frame.js +++ b/lib/frame.js @@ -176,7 +176,7 @@ api.frame = (state, subjects, frame, parent, property = null) => { if(id in state.graphMap) { let recurse = false; let subframe = null; - if(!frame.hasOwnProperty('@graph')) { + if(!('@graph' in frame)) { recurse = state.graph !== '@merged'; subframe = {}; } else { From 1a37e0c41ea5344a1c94906e2eab62e28097a23b Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Tue, 25 Feb 2020 20:52:02 -0500 Subject: [PATCH 18/20] Prefer 'in' over 'hasOwnProperty' when safe. - Static '@' keywords should be safe to use with 'in'. --- lib/context.js | 4 ++-- lib/frame.js | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/context.js b/lib/context.js index b5b1dcd6..8d983d19 100644 --- a/lib/context.js +++ b/lib/context.js @@ -1284,12 +1284,12 @@ api.getContextValue = (ctx, key, type) => { } // get default language - if(type === '@language' && ctx.hasOwnProperty(type)) { + if(type === '@language' && type in ctx) { return ctx[type]; } // get default direction - if(type === '@direction' && ctx.hasOwnProperty(type)) { + if(type === '@direction' && type in ctx) { return ctx[type]; } diff --git a/lib/frame.js b/lib/frame.js index 9d9a35ed..76dabd45 100644 --- a/lib/frame.js +++ b/lib/frame.js @@ -271,7 +271,7 @@ api.frame = (state, subjects, frame, parent, property = null) => { // skip keywords if(prop === '@type') { if(!types.isObject(frame[prop][0]) || - !frame[prop][0].hasOwnProperty('@default')) { + !('@default' in frame[prop][0])) { continue; } // allow through default types @@ -344,7 +344,7 @@ api.cleanupNull = (input, options) => { if(types.isObject(input)) { // handle in-memory linked nodes - if(input.hasOwnProperty('@id')) { + if('@id' in input) { const id = input['@id']; if(options.link.hasOwnProperty(id)) { const idx = options.link[id].indexOf(input); @@ -451,7 +451,7 @@ function _validateFrame(frame) { 'jsonld.SyntaxError', {frame}); } - if(frame[0].hasOwnProperty('@id')) { + if('@id' in frame[0]) { for(const id of util.asArray(frame[0]['@id'])) { // @id must be wildcard or an IRI if(!(types.isObject(id) || url.isAbsolute(id)) || @@ -463,7 +463,7 @@ function _validateFrame(frame) { } } - if(frame[0].hasOwnProperty('@type')) { + if('@type' in frame[0]) { for(const type of util.asArray(frame[0]['@type'])) { // @id must be wildcard or an IRI if(!(types.isObject(type) || url.isAbsolute(type)) || @@ -720,7 +720,7 @@ function _cleanupPreserve(input, options) { } // handle in-memory linked nodes - if(input.hasOwnProperty('@id')) { + if('@id' in input) { const id = input['@id']; if(options.link.hasOwnProperty(id)) { const idx = options.link[id].indexOf(input); From 8b6ef530d3440bc1396e0378be57ddb3736d168b Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Wed, 26 Feb 2020 19:20:38 -0500 Subject: [PATCH 19/20] Update eslint dependencies. --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 0ceb436e..06886dcd 100644 --- a/package.json +++ b/package.json @@ -55,8 +55,8 @@ "core-js": "^2.6.5", "cors": "^2.7.1", "cross-env": "^5.2.0", - "eslint": "^6.7.2", - "eslint-config-digitalbazaar": "^2.0.1", + "eslint": "^6.8.0", + "eslint-config-digitalbazaar": "^2.3.0", "express": "^4.16.4", "fs-extra": "^8.1.0", "join-path-js": "0.0.0", From 077fa402fa0f386b471ab313616596b8d4ef8bc5 Mon Sep 17 00:00:00 2001 From: "David I. Lehn" Date: Thu, 27 Feb 2020 21:58:52 -0500 Subject: [PATCH 20/20] Fix typo. --- lib/frame.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/frame.js b/lib/frame.js index 76dabd45..9726f071 100644 --- a/lib/frame.js +++ b/lib/frame.js @@ -193,7 +193,7 @@ api.frame = (state, subjects, frame, parent, property = null) => { api.frame( {...state, graph: id, embedded: false}, Object.keys(state.graphMap[id]).sort(), [subframe], output, '@graph'); - state.graphStack.pop; + state.graphStack.pop(); } }