Skip to content

Commit 398e2ca

Browse files
committed
upd dependencies and fixed refs to files from all parts of document: '' and 'with'
1 parent 9bd65b3 commit 398e2ca

7 files changed

+231
-113
lines changed

clone.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
module.exports = function (obj) {
2+
switch (typeof obj) {
3+
case 'undefined':
4+
case 'string':
5+
case 'boolean':
6+
case 'number':
7+
case 'function':
8+
return obj;
9+
}
10+
11+
if (obj == null) {
12+
return null;
13+
}
14+
15+
if (obj instanceof Date) {
16+
return new Date(obj);
17+
}
18+
19+
if (obj instanceof RegExp) {
20+
throw new Error('dunno how to clone', obj);
21+
//console.error('clone RegExp is unsafe');
22+
//return RegExp(obj);
23+
}
24+
25+
if (typeof obj != 'object' && !Array.isArray(obj)) {
26+
throw new Error('dunno how to clone', obj);
27+
}
28+
const newObj = (Array.isArray(obj)) ? [] : {};
29+
for (const i in obj) {
30+
newObj[i] = module.exports(obj[i]);
31+
}
32+
return newObj;
33+
};

index.js

+50-13
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ const fs = require('fs');
44
const jsonPatch = require('rfc6902');
55
const refParser = require('./patched-json-schema-ref-parser');
66
const jps = require('./json-pointer-selectors');
7+
const jsonPtr = require('json-ptr');
8+
const clone = require('./clone');
79

810
/**
911
@param {object} doc
@@ -13,37 +15,70 @@ const jps = require('./json-pointer-selectors');
1315
1416
@return {object} doc - modified source
1517
*/
16-
const inherit = function (doc, options) {
18+
const applyInherit = function (doc, options, rootDoc, inWith) {
1719
if (typeof doc != 'object' || doc == null) return doc;
18-
20+
21+
rootDoc = rootDoc || doc;
1922
options = options || {};
2023
if (options.inherit == null) {
2124
return doc;
2225
}
2326
if (options.inherit === true) {
2427
options.inherit = '$inherit';
2528
}
29+
30+
const $inherit = options.inherit;
31+
const _inherit = encodeURIComponent($inherit);
32+
const re_inherit = new RegExp(`\/${_inherit}\/source`, 'g');
33+
const _source = `${_inherit}\/source`;
34+
const re_source = new RegExp(`^(.*\/)${_source}\/?(.*)`);
35+
const _with = `${_inherit}\/with`;
36+
const re_with = new RegExp(`^(.*\/)${_with}\/?(.*)`);
37+
2638
if (Array.isArray(doc)) {
2739
for (let i = 0; i < doc.length; i++) {
28-
doc[i] = inherit(doc[i], options);
40+
doc[i] = applyInherit(doc[i], options, rootDoc, inWith);
2941
}
3042
} else {
3143
for (const key in doc) {
3244
if (key == '$ref') {
3345
if (!doc.$ref.match(/^#/)) {
3446
throw new Error('inherit: all outer references \'$ref\' must be resolved!');
3547
} else {
36-
// fix internal references, if they have '/$inherit/source', it is correct for bundling
37-
// but we are going to move object 2 levels up, so it won't be correct
38-
doc.$ref = doc.$ref.replace(new RegExp(`\/${encodeURIComponent(options.inherit)}\/source`, 'g'), '');
48+
// if internal references are like '/$inherit/source*' we just bring the document
49+
// because after applying json-patch these references will be invalid
50+
const re = doc.$ref.match(re_source);
51+
if (re) {
52+
//console.error('found source ref', doc)
53+
// pointer to whole document under key 'source'
54+
if (inWith || !re[2]) {
55+
//console.error('cloning document', doc.$ref, re, re_source)
56+
return clone(jsonPtr.get(rootDoc, doc.$ref));
57+
} else {
58+
//console.error('replacing $ref', doc.$ref, re, re_source)
59+
doc.$ref = doc.$ref.replace(re_inherit, '');
60+
}
61+
} else {
62+
// if internal references are like '/$inherit/with*' we just bring the document
63+
// because after applying json-patch these references will be invalid
64+
const re = doc.$ref.match(re_with);
65+
if (re) {
66+
//console.error('found with ref', doc)
67+
// pointer to whole document under key 'source'
68+
//console.error('cloning document', doc.$ref, re, re_with)
69+
return clone(jsonPtr.get(rootDoc, doc.$ref));
70+
}
71+
}
3972
}
4073
}
41-
doc[key] = inherit(doc[key], options);
74+
if (key in doc) {
75+
doc[key] = applyInherit(doc[key], options, rootDoc, key == 'with' || inWith);
76+
}
4277
}
43-
if (options.inherit && doc[options.inherit]) {
44-
const inh = doc[options.inherit];
78+
if (doc[$inherit]) {
79+
const inh = doc[$inherit];
4580
if (inh.source == null) {
46-
throw new Error(`inherit: ${options.inherit}.source is null!`);
81+
throw new Error(`inherit: ${$inherit}.source is null!`);
4782
}
4883
if (!(inh.with == null || Array.isArray(inh.with) && inh.with.length == 0)) {
4984
const patch = (options.compileJsonPatch || jps.compileJsonPatch)(inh.source, inh.with)
@@ -67,6 +102,7 @@ const inherit = function (doc, options) {
67102
@return {Promise.<object>}
68103
*/
69104
const bundle = function (filepath, options) {
105+
//console.error('Bundle()')
70106
if (!fs.existsSync(filepath)) {
71107
return new Promise((res, rej) => rej(new Error(`invalid argument: file "${filepath}" not exists`)));
72108
}
@@ -78,9 +114,9 @@ const bundle = function (filepath, options) {
78114
return parser.bundle(filepath)
79115
.then((doc) => {
80116
try {
81-
doc = inherit(doc, options);
117+
doc = applyInherit(doc, options);
82118
} catch (e) {
83-
console.error('inherit', 'doc:', doc, 'error:', e);
119+
console.error('inherit', 'doc:', JSON.stringify(doc, null, ' '), 'error:', e);
84120
throw e;
85121
}
86122
return doc;
@@ -100,14 +136,15 @@ const bundle = function (filepath, options) {
100136
@return {Promise.<object>}
101137
*/
102138
const dereference = function (doc, options) {
139+
//console.error('Dereference()')
103140
if (typeof doc == 'string') {
104141
return bundle(doc, options)
105142
.then((doc) => {
106143
return dereference(doc);
107144
});
108145
}
109146
try {
110-
doc = inherit(doc, options);
147+
doc = applyInherit(doc, options);
111148
} catch (e) {
112149
console.error('inherit', 'doc:', doc, 'error:', e);
113150
return new Promise(function(resolve, reject) {

json-pointer-selectors.js

+58-41
Original file line numberDiff line numberDiff line change
@@ -201,6 +201,59 @@ const objectMatchesSelector = (obj, selector) => {
201201
return true;
202202
};
203203

204+
const compileOperation = (source, op) => {
205+
const re = parseJsonPointer(op.path);
206+
207+
if (re.selector) {
208+
const arr = jsonPtr.get(source, re.prefix);
209+
210+
// if object is not array check deeper
211+
if (!Array.isArray(arr)) {
212+
// if there is something to check deeper
213+
if (arr[re.infix] != undefined && re.suffix != '') {
214+
// relative pathes
215+
op = compileOperation(arr[re.infix], Object.assign({}, op, {path: re.suffix}));
216+
// relative pathes back to absolute
217+
op.path = re.prefix + re.infix + op.path;
218+
}
219+
return op;
220+
}
221+
222+
// if found array check conditions
223+
let found;
224+
for (let j = 0; j < arr.length; j++) {
225+
if (objectMatchesSelector(arr[j], re.selector)) {
226+
if (found) {
227+
//console.error(re.selector)
228+
//console.error('first match:', found)
229+
//console.error('new match:', j, arr[j])
230+
throw new Error(`path ${op.path} compiles to selector that has multiple matches, it is forbidden`);
231+
}
232+
const tmp = Object.assign({}, op, {path: re.suffix});
233+
if (compileOperation(arr[j], tmp)) {
234+
// changing path to JSON-Pointer with number
235+
found = Object.assign({}, op, {path: re.prefix + '/' + j + re.suffix});
236+
}
237+
}
238+
}
239+
if (found) {
240+
// checking new pathes deeper
241+
return compileOperation(source, found);
242+
}
243+
return null;
244+
//throw new Error(`path ${op.path} compiles to selector that has no matches`);
245+
}
246+
247+
// all path exists or "op" is adding a new leaf
248+
if (jsonPtr.get(source, op.path)
249+
|| op.op == 'add' && jsonPtr.get(source, op.path.match(/(^.*)\/[^\/]*/)[1])
250+
) {
251+
return op;
252+
}
253+
254+
return null;
255+
};
256+
204257
/**
205258
@param {object} source - object to which patch will be applied
206259
@param {Array} patchOperations
@@ -210,48 +263,12 @@ const objectMatchesSelector = (obj, selector) => {
210263
const compileJsonPatch = (source, patchOperations) => {
211264
const res = [];
212265
for (let i = 0; i < patchOperations.length; i++) {
213-
if (!patchOperations[i].path) continue;
266+
const op = patchOperations[i];
267+
if (!op.path) continue;
214268

215-
const re = parseJsonPointer(patchOperations[i].path);
216-
if (re.selector) {
217-
const arr = jsonPtr.get(source, re.prefix);
218-
let tmp = [];
219-
// if object is not array check deeper
220-
if (!Array.isArray(arr)) {
221-
if (arr[re.infix] != undefined && re.suffix != '') {
222-
// relative pathes
223-
tmp = compileJsonPatch(arr[re.infix], [Object.assign({}, patchOperations[i], {path: re.suffix})]);
224-
for (let j = 0;j < tmp.length; j++) {
225-
// relative pathes back to absolute
226-
tmp[j].path = re.prefix + re.infix + tmp[j].path;
227-
res.push(tmp[j]);
228-
}
229-
} else {
230-
res.push(patchOperations[i]);
231-
}
232-
continue;
233-
}
234-
// if found array check conditions
235-
let found = false;
236-
for (let j = 0; j < arr.length; j++) {
237-
if (objectMatchesSelector(arr[j], re.selector)) {
238-
if (found) {
239-
throw new Error(`path ${patchOperations[i].path} compiles to selector that has multiple matches, it is forbidden`);
240-
}
241-
// changing path to JSON-Pointer with number
242-
tmp.push(Object.assign({}, patchOperations[i], {path: re.prefix + '/' + j + re.suffix}));
243-
found = true;
244-
}
245-
}
246-
if (tmp.length) {
247-
// checking new pathes deeper
248-
tmp = compileJsonPatch(source, tmp);
249-
}
250-
if (tmp.length) {
251-
res.push(...tmp);
252-
}
253-
} else {
254-
res.push(patchOperations[i]);
269+
const compiled = compileOperation(source, op);
270+
if (compiled) {
271+
res.push(compiled);
255272
}
256273
}
257274
return res;

package-lock.json

+11-11
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
{
22
"name": "jybid",
3-
"version": "1.0.3",
3+
"version": "1.1.0",
44
"description": "json yaml bundle inherit dereference",
55
"main": "index.js",
66
"directories": {
77
"test": "test"
88
},
99
"dependencies": {
10-
"json-ptr": "^1.1.2",
10+
"json-ptr": "^1.2.0",
1111
"json-schema-ref-parser": "^6.1.0",
12-
"rfc6902": "^3.0.2"
12+
"rfc6902": "^3.0.4"
1313
},
1414
"devDependencies": {},
1515
"scripts": {

0 commit comments

Comments
 (0)