Skip to content

Commit ca2810b

Browse files
gkelloggdavidlehn
authored andcommitted
Work in Progress
1 parent 88a911a commit ca2810b

File tree

3 files changed

+94
-35
lines changed

3 files changed

+94
-35
lines changed

lib/frame.js

Lines changed: 73 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -28,16 +28,50 @@ api.frameMerged = (input, frame, options) => {
2828
// create framing state
2929
const state = {
3030
options: options,
31-
graphs: {'@default': {}, '@merged': {}},
31+
graph: '@merged',
32+
graphMap: {'@default': {}, '@merged': {}},
33+
graphStack: [],
3234
subjectStack: [],
3335
link: {}
3436
};
3537

3638
// produce a map of all graphs and name each bnode
3739
// FIXME: currently uses subjects from @merged graph only
3840
const issuer = new util.IdentifierIssuer('_:b');
39-
_createNodeMap(input, state.graphs, '@merged', issuer);
40-
state.subjects = state.graphs['@merged'];
41+
_createNodeMap(input, state.graphMap, '@merged', issuer);
42+
state.subjects = state.graphMap['@merged'];
43+
44+
// frame the subjects
45+
const framed = [];
46+
api.frame(state, Object.keys(state.subjects).sort(), frame, framed);
47+
return framed;
48+
};
49+
50+
/**
51+
* Performs JSON-LD `default` framing.
52+
*
53+
* @param input the expanded JSON-LD to frame.
54+
* @param frame the expanded JSON-LD frame to use.
55+
* @param options the framing options.
56+
*
57+
* @return the framed output.
58+
*/
59+
api.frameDefault = (input, frame, options) => {
60+
// create framing state
61+
const state = {
62+
options: options,
63+
graph: '@default',
64+
graphMap: {'@default': {}},
65+
graphStack: [],
66+
subjectStack: [],
67+
link: {}
68+
};
69+
70+
// produce a map of all graphs and name each bnode
71+
// FIXME: currently uses subjects from @merged graph only
72+
const issuer = new util.IdentifierIssuer('_:b');
73+
_createNodeMap(input, state.graphMap, '@default', issuer);
74+
state.subjects = state.graphMap['@default'];
4175

4276
// frame the subjects
4377
const framed = [];
@@ -72,8 +106,7 @@ api.frame = (state, subjects, frame, parent, property = null) => {
72106

73107
// add matches to output
74108
const ids = Object.keys(matches).sort();
75-
for(let idx = 0; idx < ids.length; ++idx) {
76-
const id = ids[idx];
109+
for(const id of ids) {
77110
const subject = matches[id];
78111

79112
if(flags.embed === '@link' && id in state.link) {
@@ -120,11 +153,33 @@ api.frame = (state, subjects, frame, parent, property = null) => {
120153
// push matching subject onto stack to enable circular embed checks
121154
state.subjectStack.push(subject);
122155

123-
// iterate over subject properties
124-
let props = Object.keys(subject).sort();
125-
for(let i = 0; i < props.length; i++) {
126-
const prop = props[i];
156+
// subject is also the name of a graph
157+
if(id in state.graphMap) {
158+
let recurse = false;
159+
let subframe = null;
160+
if(!('@graph' in frame)) {
161+
recurse = state.graph !== '@merged';
162+
subframe = {};
163+
} else {
164+
subframe = frame['@graph'][0];
165+
if(!types.isObject(subframe)) {
166+
subframe == {};
167+
}
168+
recurse = !(id === '@merged' || id === '@default');
169+
}
170+
171+
if(recurse) {
172+
state.graphStack << state.graph;
173+
state.graph = id;
174+
// recurse into graph
175+
debugger
176+
api.frame(state, Object.keys(state.graphMap[id]).sort, [subframe], output, '@graph');
177+
state.graph = state.graphStack.pop;
178+
}
179+
}
127180

181+
// iterate over subject properties
182+
for(const prop of Object.keys(subject).sort()) {
128183
// copy keywords to output
129184
if(isKeyword(prop)) {
130185
output[prop] = util.clone(subject[prop]);
@@ -137,10 +192,7 @@ api.frame = (state, subjects, frame, parent, property = null) => {
137192
}
138193

139194
// add objects
140-
const objects = subject[prop];
141-
for(var oi = 0; oi < objects.length; ++oi) {
142-
let o = objects[oi];
143-
195+
for(let o of subject[prop]) {
144196
// recurse into list
145197
if(graphTypes.isList(o)) {
146198
// add empty list
@@ -149,7 +201,7 @@ api.frame = (state, subjects, frame, parent, property = null) => {
149201

150202
// add list objects
151203
const src = o['@list'];
152-
for(let n in src) {
204+
for(const n in src) {
153205
o = src[n];
154206
if(graphTypes.isSubjectReference(o)) {
155207
const subframe = (prop in frame ?
@@ -177,18 +229,15 @@ api.frame = (state, subjects, frame, parent, property = null) => {
177229
}
178230

179231
// handle defaults
180-
props = Object.keys(frame).sort();
181-
for(let i = 0; i < props.length; ++i) {
182-
const prop = props[i];
183-
232+
for(const prop of Object.keys(frame).sort()) {
184233
// skip keywords
185234
if(isKeyword(prop)) {
186235
continue;
187236
}
188237

189238
// if omit default is off, then include default values for properties
190239
// that appear in the next frame but are not in the matching subject
191-
const next = frame[prop][0];
240+
const next = frame[prop][0] || {};
192241
const omitDefaultOn = _getFrameFlag(next, options, 'omitDefault');
193242
if(!omitDefaultOn && !(prop in output)) {
194243
let preserve = '@null';
@@ -302,8 +351,7 @@ function _validateFrame(frame) {
302351
function _filterSubjects(state, subjects, frame, flags) {
303352
// filter subjects in @id order
304353
const rval = {};
305-
for(let i = 0; i < subjects.length; ++i) {
306-
const id = subjects[i];
354+
for(const id of subjects) {
307355
const subject = state.subjects[id];
308356
if(_filterSubject(subject, frame, flags)) {
309357
rval[id] = subject;
@@ -325,10 +373,9 @@ function _filterSubject(subject, frame, flags) {
325373
// check @type (object value means 'any' type, fall through to ducktyping)
326374
if('@type' in frame &&
327375
!(frame['@type'].length === 1 && types.isObject(frame['@type'][0]))) {
328-
const nodeTypes = frame['@type'];
329-
for(let i = 0; i < nodeTypes.length; ++i) {
376+
for(const nodeType of frame['@type']) {
330377
// any matching @type is a match
331-
if(util.hasValue(subject, '@type', nodeTypes[i])) {
378+
if(util.hasValue(subject, '@type', nodeType)) {
332379
return true;
333380
}
334381
}
@@ -338,7 +385,7 @@ function _filterSubject(subject, frame, flags) {
338385
// check ducktype
339386
let wildcard = true;
340387
let matchesSome = false;
341-
for(let key in frame) {
388+
for(const key in frame) {
342389
if(isKeyword(key)) {
343390
// skip non-@id and non-@type
344391
if(key !== '@id' && key !== '@type') {
@@ -417,8 +464,7 @@ function _removeEmbed(state, id) {
417464
const removeDependents = id => {
418465
// get embed keys as a separate array to enable deleting keys in map
419466
const ids = Object.keys(embeds);
420-
for(let i = 0; i < ids.length; ++i) {
421-
const next = ids[i];
467+
for(const next of ids) {
422468
if(next in embeds && types.isObject(embeds[next].parent) &&
423469
embeds[next].parent['@id'] === id) {
424470
delete embeds[next];

lib/jsonld.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,14 @@ const Rdfa = require('./Rdfa');
4444

4545
const {expand: _expand} = require('./expand');
4646
const {flatten: _flatten} = require('./flatten');
47-
const {frameMerged: _frameMerged} = require('./frame');
4847
const {fromRDF: _fromRDF} = require('./fromRdf');
4948
const {toRDF: _toRDF} = require('./toRdf');
5049

50+
const {
51+
frameMerged: _frameMerged,
52+
frameDefault: _frameDefault
53+
} = require('./frame');
54+
5155
const {
5256
isArray: _isArray,
5357
isObject: _isObject,
@@ -61,7 +65,8 @@ const {
6165
const {
6266
getInitialContext: _getInitialContext,
6367
process: _processContext,
64-
getAllContexts: _getAllContexts
68+
getAllContexts: _getAllContexts,
69+
expandIri: _expandIri
6570
} = require('./context');
6671

6772
const {
@@ -420,7 +425,8 @@ jsonld.frame = util.callbackify(async function(input, frame, options) {
420425
embed: '@last',
421426
explicit: false,
422427
requireAll: true,
423-
omitDefault: false
428+
omitDefault: false,
429+
pruneBlankNodeIdentifiers: true
424430
});
425431

426432
// if frame is a string, attempt to dereference remote document
@@ -454,8 +460,16 @@ jsonld.frame = util.callbackify(async function(input, frame, options) {
454460
opts.keepFreeFloatingNodes = true;
455461
const expandedFrame = await jsonld.expand(frame, opts);
456462

457-
// do merged framing
458-
const framed = _frameMerged(expanded, expandedFrame, opts);
463+
// if the unexpanded frame includes a key expanding to @graph, frame the default graph, otherwise, the merged graph
464+
let framed;
465+
// FIXME should look for aliases of @graph
466+
if('@graph' in frame) {
467+
// do default framing
468+
framed = _frameDefault(expanded, expandedFrame, opts);
469+
} else {
470+
// do merged framing
471+
framed = _frameMerged(expanded, expandedFrame, opts);
472+
}
459473

460474
// compact result (force @graph option to true, skip expansion,
461475
// check for linked embeds)

tests/test-common.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,7 @@ const TEST_TYPES = {
4949
compare: compareExpectedJson
5050
},
5151
'jld:FlattenTest': {
52-
skip: {
53-
},
52+
skip: {},
5453
fn: 'flatten',
5554
params: [
5655
readTestUrl('input'),
@@ -61,7 +60,7 @@ const TEST_TYPES = {
6160
},
6261
'jld:FrameTest': {
6362
skip: {
64-
specVersion: ['json-ld-1.1']
63+
//specVersion: ['json-ld-1.1']
6564
},
6665
fn: 'frame',
6766
params: [

0 commit comments

Comments
 (0)