@@ -28,16 +28,50 @@ api.frameMerged = (input, frame, options) => {
28
28
// create framing state
29
29
const state = {
30
30
options : options ,
31
- graphs : { '@default' : { } , '@merged' : { } } ,
31
+ graph : '@merged' ,
32
+ graphMap : { '@default' : { } , '@merged' : { } } ,
33
+ graphStack : [ ] ,
32
34
subjectStack : [ ] ,
33
35
link : { }
34
36
} ;
35
37
36
38
// produce a map of all graphs and name each bnode
37
39
// FIXME: currently uses subjects from @merged graph only
38
40
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' ] ;
41
75
42
76
// frame the subjects
43
77
const framed = [ ] ;
@@ -72,8 +106,7 @@ api.frame = (state, subjects, frame, parent, property = null) => {
72
106
73
107
// add matches to output
74
108
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 ) {
77
110
const subject = matches [ id ] ;
78
111
79
112
if ( flags . embed === '@link' && id in state . link ) {
@@ -120,11 +153,33 @@ api.frame = (state, subjects, frame, parent, property = null) => {
120
153
// push matching subject onto stack to enable circular embed checks
121
154
state . subjectStack . push ( subject ) ;
122
155
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
+ }
127
180
181
+ // iterate over subject properties
182
+ for ( const prop of Object . keys ( subject ) . sort ( ) ) {
128
183
// copy keywords to output
129
184
if ( isKeyword ( prop ) ) {
130
185
output [ prop ] = util . clone ( subject [ prop ] ) ;
@@ -137,10 +192,7 @@ api.frame = (state, subjects, frame, parent, property = null) => {
137
192
}
138
193
139
194
// 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 ] ) {
144
196
// recurse into list
145
197
if ( graphTypes . isList ( o ) ) {
146
198
// add empty list
@@ -149,7 +201,7 @@ api.frame = (state, subjects, frame, parent, property = null) => {
149
201
150
202
// add list objects
151
203
const src = o [ '@list' ] ;
152
- for ( let n in src ) {
204
+ for ( const n in src ) {
153
205
o = src [ n ] ;
154
206
if ( graphTypes . isSubjectReference ( o ) ) {
155
207
const subframe = ( prop in frame ?
@@ -177,18 +229,15 @@ api.frame = (state, subjects, frame, parent, property = null) => {
177
229
}
178
230
179
231
// 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 ( ) ) {
184
233
// skip keywords
185
234
if ( isKeyword ( prop ) ) {
186
235
continue ;
187
236
}
188
237
189
238
// if omit default is off, then include default values for properties
190
239
// 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 ] || { } ;
192
241
const omitDefaultOn = _getFrameFlag ( next , options , 'omitDefault' ) ;
193
242
if ( ! omitDefaultOn && ! ( prop in output ) ) {
194
243
let preserve = '@null' ;
@@ -302,8 +351,7 @@ function _validateFrame(frame) {
302
351
function _filterSubjects ( state , subjects , frame , flags ) {
303
352
// filter subjects in @id order
304
353
const rval = { } ;
305
- for ( let i = 0 ; i < subjects . length ; ++ i ) {
306
- const id = subjects [ i ] ;
354
+ for ( const id of subjects ) {
307
355
const subject = state . subjects [ id ] ;
308
356
if ( _filterSubject ( subject , frame , flags ) ) {
309
357
rval [ id ] = subject ;
@@ -325,10 +373,9 @@ function _filterSubject(subject, frame, flags) {
325
373
// check @type (object value means 'any' type, fall through to ducktyping)
326
374
if ( '@type' in frame &&
327
375
! ( 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' ] ) {
330
377
// any matching @type is a match
331
- if ( util . hasValue ( subject , '@type' , nodeTypes [ i ] ) ) {
378
+ if ( util . hasValue ( subject , '@type' , nodeType ) ) {
332
379
return true ;
333
380
}
334
381
}
@@ -338,7 +385,7 @@ function _filterSubject(subject, frame, flags) {
338
385
// check ducktype
339
386
let wildcard = true ;
340
387
let matchesSome = false ;
341
- for ( let key in frame ) {
388
+ for ( const key in frame ) {
342
389
if ( isKeyword ( key ) ) {
343
390
// skip non-@id and non-@type
344
391
if ( key !== '@id' && key !== '@type' ) {
@@ -417,8 +464,7 @@ function _removeEmbed(state, id) {
417
464
const removeDependents = id => {
418
465
// get embed keys as a separate array to enable deleting keys in map
419
466
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 ) {
422
468
if ( next in embeds && types . isObject ( embeds [ next ] . parent ) &&
423
469
embeds [ next ] . parent [ '@id' ] === id ) {
424
470
delete embeds [ next ] ;
0 commit comments