mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-20 22:42:53 -05:00
✨ Add ?formats param to Posts API (#8305)
refs #8275 - Adds support for `formats` param - Returns `html` by default - Can optionally return other formats by providing a comma-separated list
This commit is contained in:
parent
25c4e5025a
commit
3e60941054
7 changed files with 235 additions and 17 deletions
|
@ -37,7 +37,7 @@ posts = {
|
||||||
* @returns {Promise<Posts>} Posts Collection with Meta
|
* @returns {Promise<Posts>} Posts Collection with Meta
|
||||||
*/
|
*/
|
||||||
browse: function browse(options) {
|
browse: function browse(options) {
|
||||||
var extraOptions = ['status'],
|
var extraOptions = ['status', 'formats'],
|
||||||
permittedOptions,
|
permittedOptions,
|
||||||
tasks;
|
tasks;
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ posts = {
|
||||||
tasks = [
|
tasks = [
|
||||||
utils.validate(docName, {opts: permittedOptions}),
|
utils.validate(docName, {opts: permittedOptions}),
|
||||||
utils.handlePublicPermissions(docName, 'browse'),
|
utils.handlePublicPermissions(docName, 'browse'),
|
||||||
utils.convertOptions(allowedIncludes),
|
utils.convertOptions(allowedIncludes, dataProvider.Post.allowedFormats),
|
||||||
modelQuery
|
modelQuery
|
||||||
];
|
];
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ posts = {
|
||||||
* @return {Promise<Post>} Post
|
* @return {Promise<Post>} Post
|
||||||
*/
|
*/
|
||||||
read: function read(options) {
|
read: function read(options) {
|
||||||
var attrs = ['id', 'slug', 'status', 'uuid'],
|
var attrs = ['id', 'slug', 'status', 'uuid', 'formats'],
|
||||||
tasks;
|
tasks;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,7 +96,7 @@ posts = {
|
||||||
tasks = [
|
tasks = [
|
||||||
utils.validate(docName, {attrs: attrs, opts: options.opts || []}),
|
utils.validate(docName, {attrs: attrs, opts: options.opts || []}),
|
||||||
utils.handlePublicPermissions(docName, 'read'),
|
utils.handlePublicPermissions(docName, 'read'),
|
||||||
utils.convertOptions(allowedIncludes),
|
utils.convertOptions(allowedIncludes, dataProvider.Post.allowedFormats),
|
||||||
modelQuery
|
modelQuery
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
@ -122,7 +122,7 @@ utils = {
|
||||||
name: {}
|
name: {}
|
||||||
},
|
},
|
||||||
// these values are sanitised/validated separately
|
// these values are sanitised/validated separately
|
||||||
noValidation = ['data', 'context', 'include', 'filter', 'forUpdate', 'transacting'],
|
noValidation = ['data', 'context', 'include', 'filter', 'forUpdate', 'transacting', 'formats'],
|
||||||
errors = [];
|
errors = [];
|
||||||
|
|
||||||
_.each(options, function (value, key) {
|
_.each(options, function (value, key) {
|
||||||
|
@ -243,12 +243,16 @@ utils = {
|
||||||
return this.trimAndLowerCase(fields);
|
return this.trimAndLowerCase(fields);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
prepareFormats: function prepareFormats(formats, allowedFormats) {
|
||||||
|
return _.intersection(this.trimAndLowerCase(formats), allowedFormats);
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ## Convert Options
|
* ## Convert Options
|
||||||
* @param {Array} allowedIncludes
|
* @param {Array} allowedIncludes
|
||||||
* @returns {Function} doConversion
|
* @returns {Function} doConversion
|
||||||
*/
|
*/
|
||||||
convertOptions: function convertOptions(allowedIncludes) {
|
convertOptions: function convertOptions(allowedIncludes, allowedFormats) {
|
||||||
/**
|
/**
|
||||||
* Convert our options from API-style to Model-style
|
* Convert our options from API-style to Model-style
|
||||||
* @param {Object} options
|
* @param {Object} options
|
||||||
|
@ -258,11 +262,20 @@ utils = {
|
||||||
if (options.include) {
|
if (options.include) {
|
||||||
options.include = utils.prepareInclude(options.include, allowedIncludes);
|
options.include = utils.prepareInclude(options.include, allowedIncludes);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.fields) {
|
if (options.fields) {
|
||||||
options.columns = utils.prepareFields(options.fields);
|
options.columns = utils.prepareFields(options.fields);
|
||||||
delete options.fields;
|
delete options.fields;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.formats) {
|
||||||
|
options.formats = utils.prepareFormats(options.formats, allowedFormats);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.formats && options.columns) {
|
||||||
|
options.columns = options.columns.concat(options.formats);
|
||||||
|
}
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
@ -274,7 +287,7 @@ utils = {
|
||||||
* @param {String} docName
|
* @param {String} docName
|
||||||
* @returns {Promise(Object)} resolves to the original object if it checks out
|
* @returns {Promise(Object)} resolves to the original object if it checks out
|
||||||
*/
|
*/
|
||||||
checkObject: function (object, docName, editId) {
|
checkObject: function checkObject(object, docName, editId) {
|
||||||
if (_.isEmpty(object) || _.isEmpty(object[docName]) || _.isEmpty(object[docName][0])) {
|
if (_.isEmpty(object) || _.isEmpty(object[docName]) || _.isEmpty(object[docName][0])) {
|
||||||
return Promise.reject(new errors.BadRequestError({
|
return Promise.reject(new errors.BadRequestError({
|
||||||
message: i18n.t('errors.api.utils.noRootKeyProvided', {docName: docName})
|
message: i18n.t('errors.api.utils.noRootKeyProvided', {docName: docName})
|
||||||
|
@ -306,10 +319,10 @@ utils = {
|
||||||
|
|
||||||
return Promise.resolve(object);
|
return Promise.resolve(object);
|
||||||
},
|
},
|
||||||
checkFileExists: function (fileData) {
|
checkFileExists: function checkFileExists(fileData) {
|
||||||
return !!(fileData.mimetype && fileData.path);
|
return !!(fileData.mimetype && fileData.path);
|
||||||
},
|
},
|
||||||
checkFileIsValid: function (fileData, types, extensions) {
|
checkFileIsValid: function checkFileIsValid(fileData, types, extensions) {
|
||||||
var type = fileData.mimetype,
|
var type = fileData.mimetype,
|
||||||
ext = path.extname(fileData.name).toLowerCase();
|
ext = path.extname(fileData.name).toLowerCase();
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
function isPost(jsonData) {
|
function isPost(jsonData) {
|
||||||
return jsonData.hasOwnProperty('html') && jsonData.hasOwnProperty('markdown') &&
|
return jsonData.hasOwnProperty('html') &&
|
||||||
jsonData.hasOwnProperty('title') && jsonData.hasOwnProperty('slug');
|
jsonData.hasOwnProperty('title') && jsonData.hasOwnProperty('slug');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -477,12 +477,31 @@ Post = ghostBookshelf.Model.extend({
|
||||||
defaultColumnsToFetch: function defaultColumnsToFetch() {
|
defaultColumnsToFetch: function defaultColumnsToFetch() {
|
||||||
return ['id', 'published_at', 'slug', 'author_id'];
|
return ['id', 'published_at', 'slug', 'author_id'];
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* If the `formats` option is not used, we return `html` be default.
|
||||||
|
* Otherwise we return what is requested e.g. `?formats=mobiledoc,plaintext`
|
||||||
|
*/
|
||||||
|
formatsToJSON: function formatsToJSON(attrs, options) {
|
||||||
|
var defaultFormats = ['html'],
|
||||||
|
formatsToKeep = options.formats || defaultFormats;
|
||||||
|
|
||||||
|
// Iterate over all known formats, and if they are not in the keep list, remove them
|
||||||
|
_.each(Post.allowedFormats, function (format) {
|
||||||
|
if (formatsToKeep.indexOf(format) === -1) {
|
||||||
|
delete attrs[format];
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return attrs;
|
||||||
|
},
|
||||||
|
|
||||||
toJSON: function toJSON(options) {
|
toJSON: function toJSON(options) {
|
||||||
options = options || {};
|
options = options || {};
|
||||||
|
|
||||||
var attrs = ghostBookshelf.Model.prototype.toJSON.call(this, options);
|
var attrs = ghostBookshelf.Model.prototype.toJSON.call(this, options);
|
||||||
|
|
||||||
|
attrs = this.formatsToJSON(attrs, options);
|
||||||
|
|
||||||
if (!options.columns || (options.columns && options.columns.indexOf('author') > -1)) {
|
if (!options.columns || (options.columns && options.columns.indexOf('author') > -1)) {
|
||||||
attrs.author = attrs.author || attrs.author_id;
|
attrs.author = attrs.author || attrs.author_id;
|
||||||
delete attrs.author_id;
|
delete attrs.author_id;
|
||||||
|
@ -505,6 +524,8 @@ Post = ghostBookshelf.Model.extend({
|
||||||
return this.isPublicContext() ? 'page:false' : 'page:false+status:published';
|
return this.isPublicContext() ? 'page:false' : 'page:false+status:published';
|
||||||
}
|
}
|
||||||
}, {
|
}, {
|
||||||
|
allowedFormats: ['markdown', 'mobiledoc', 'html', 'plaintext', 'amp'],
|
||||||
|
|
||||||
orderDefaultOptions: function orderDefaultOptions() {
|
orderDefaultOptions: function orderDefaultOptions() {
|
||||||
return {
|
return {
|
||||||
status: 'ASC',
|
status: 'ASC',
|
||||||
|
@ -580,6 +601,9 @@ Post = ghostBookshelf.Model.extend({
|
||||||
edit: ['forUpdate']
|
edit: ['forUpdate']
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The post model additionally supports having a formats option
|
||||||
|
options.push('formats');
|
||||||
|
|
||||||
if (validOptions[methodName]) {
|
if (validOptions[methodName]) {
|
||||||
options = options.concat(validOptions[methodName]);
|
options = options.concat(validOptions[methodName]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,6 +54,138 @@ describe('Post API', function () {
|
||||||
testUtils.API.checkResponse(jsonResponse.meta.pagination, 'pagination');
|
testUtils.API.checkResponse(jsonResponse.meta.pagination, 'pagination');
|
||||||
_.isBoolean(jsonResponse.posts[0].featured).should.eql(true);
|
_.isBoolean(jsonResponse.posts[0].featured).should.eql(true);
|
||||||
_.isBoolean(jsonResponse.posts[0].page).should.eql(true);
|
_.isBoolean(jsonResponse.posts[0].page).should.eql(true);
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can retrieve a single post format', function (done) {
|
||||||
|
request.get(testUtils.API.getApiQuery('posts/?formats=mobiledoc'))
|
||||||
|
.set('Authorization', 'Bearer ' + accesstoken)
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(200)
|
||||||
|
.end(function (err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
should.not.exist(res.headers['x-cache-invalidate']);
|
||||||
|
var jsonResponse = res.body;
|
||||||
|
should.exist(jsonResponse.posts);
|
||||||
|
testUtils.API.checkResponse(jsonResponse, 'posts');
|
||||||
|
jsonResponse.posts.should.have.length(5);
|
||||||
|
testUtils.API.checkResponse(jsonResponse.posts[0], 'post', ['mobiledoc'], ['html']);
|
||||||
|
testUtils.API.checkResponse(jsonResponse.meta.pagination, 'pagination');
|
||||||
|
_.isBoolean(jsonResponse.posts[0].featured).should.eql(true);
|
||||||
|
_.isBoolean(jsonResponse.posts[0].page).should.eql(true);
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can retrieve multiple post formats', function (done) {
|
||||||
|
request.get(testUtils.API.getApiQuery('posts/?formats=plaintext,mobiledoc,amp'))
|
||||||
|
.set('Authorization', 'Bearer ' + accesstoken)
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(200)
|
||||||
|
.end(function (err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
should.not.exist(res.headers['x-cache-invalidate']);
|
||||||
|
var jsonResponse = res.body;
|
||||||
|
should.exist(jsonResponse.posts);
|
||||||
|
testUtils.API.checkResponse(jsonResponse, 'posts');
|
||||||
|
jsonResponse.posts.should.have.length(5);
|
||||||
|
testUtils.API.checkResponse(jsonResponse.posts[0], 'post', ['mobiledoc', 'plaintext', 'amp'], ['html']);
|
||||||
|
testUtils.API.checkResponse(jsonResponse.meta.pagination, 'pagination');
|
||||||
|
_.isBoolean(jsonResponse.posts[0].featured).should.eql(true);
|
||||||
|
_.isBoolean(jsonResponse.posts[0].page).should.eql(true);
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can handle unknown post formats', function (done) {
|
||||||
|
request.get(testUtils.API.getApiQuery('posts/?formats=plaintext,mobiledo'))
|
||||||
|
.set('Authorization', 'Bearer ' + accesstoken)
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(200)
|
||||||
|
.end(function (err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
should.not.exist(res.headers['x-cache-invalidate']);
|
||||||
|
var jsonResponse = res.body;
|
||||||
|
should.exist(jsonResponse.posts);
|
||||||
|
testUtils.API.checkResponse(jsonResponse, 'posts');
|
||||||
|
jsonResponse.posts.should.have.length(5);
|
||||||
|
testUtils.API.checkResponse(jsonResponse.posts[0], 'post', ['plaintext'], ['html']);
|
||||||
|
testUtils.API.checkResponse(jsonResponse.meta.pagination, 'pagination');
|
||||||
|
_.isBoolean(jsonResponse.posts[0].featured).should.eql(true);
|
||||||
|
_.isBoolean(jsonResponse.posts[0].page).should.eql(true);
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can handle empty formats (default html is expected)', function (done) {
|
||||||
|
request.get(testUtils.API.getApiQuery('posts/?formats='))
|
||||||
|
.set('Authorization', 'Bearer ' + accesstoken)
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(200)
|
||||||
|
.end(function (err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
should.not.exist(res.headers['x-cache-invalidate']);
|
||||||
|
var jsonResponse = res.body;
|
||||||
|
should.exist(jsonResponse.posts);
|
||||||
|
testUtils.API.checkResponse(jsonResponse, 'posts');
|
||||||
|
jsonResponse.posts.should.have.length(5);
|
||||||
|
testUtils.API.checkResponse(jsonResponse.posts[0], 'post');
|
||||||
|
testUtils.API.checkResponse(jsonResponse.meta.pagination, 'pagination');
|
||||||
|
_.isBoolean(jsonResponse.posts[0].featured).should.eql(true);
|
||||||
|
_.isBoolean(jsonResponse.posts[0].page).should.eql(true);
|
||||||
|
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('fields and formats', function (done) {
|
||||||
|
request.get(testUtils.API.getApiQuery('posts/?formats=mobiledoc,html&fields=id,title'))
|
||||||
|
.set('Authorization', 'Bearer ' + accesstoken)
|
||||||
|
.expect('Content-Type', /json/)
|
||||||
|
.expect('Cache-Control', testUtils.cacheRules.private)
|
||||||
|
.expect(200)
|
||||||
|
.end(function (err, res) {
|
||||||
|
if (err) {
|
||||||
|
return done(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
should.not.exist(res.headers['x-cache-invalidate']);
|
||||||
|
var jsonResponse = res.body;
|
||||||
|
should.exist(jsonResponse.posts);
|
||||||
|
testUtils.API.checkResponse(jsonResponse, 'posts');
|
||||||
|
jsonResponse.posts.should.have.length(5);
|
||||||
|
|
||||||
|
testUtils.API.checkResponse(
|
||||||
|
jsonResponse.posts[0],
|
||||||
|
'post',
|
||||||
|
null,
|
||||||
|
null,
|
||||||
|
['mobiledoc', 'id', 'title', 'html']
|
||||||
|
);
|
||||||
|
|
||||||
|
testUtils.API.checkResponse(jsonResponse.meta.pagination, 'pagination');
|
||||||
|
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -43,7 +43,9 @@ describe('Post Model', function () {
|
||||||
|
|
||||||
beforeEach(testUtils.setup('owner', 'posts', 'apps'));
|
beforeEach(testUtils.setup('owner', 'posts', 'apps'));
|
||||||
|
|
||||||
function checkFirstPostData(firstPost) {
|
function checkFirstPostData(firstPost, options) {
|
||||||
|
options = options || {};
|
||||||
|
|
||||||
should.not.exist(firstPost.author_id);
|
should.not.exist(firstPost.author_id);
|
||||||
firstPost.author.should.be.an.Object();
|
firstPost.author.should.be.an.Object();
|
||||||
firstPost.url.should.equal('/html-ipsum/');
|
firstPost.url.should.equal('/html-ipsum/');
|
||||||
|
@ -60,10 +62,29 @@ describe('Post Model', function () {
|
||||||
firstPost.published_by.name.should.equal(DataGenerator.Content.users[0].name);
|
firstPost.published_by.name.should.equal(DataGenerator.Content.users[0].name);
|
||||||
firstPost.tags[0].name.should.equal(DataGenerator.Content.tags[0].name);
|
firstPost.tags[0].name.should.equal(DataGenerator.Content.tags[0].name);
|
||||||
|
|
||||||
// Formats
|
|
||||||
// @TODO change / update this for mobiledoc in
|
// @TODO change / update this for mobiledoc in
|
||||||
firstPost.markdown.should.match(/HTML Ipsum Presents/);
|
if (options.formats) {
|
||||||
firstPost.html.should.match(/HTML Ipsum Presents/);
|
if (options.formats.indexOf('markdown') !== -1) {
|
||||||
|
firstPost.markdown.should.match(/HTML Ipsum Presents/);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.formats.indexOf('html') !== -1) {
|
||||||
|
firstPost.html.should.match(/HTML Ipsum Presents/);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.formats.indexOf('plaintext') !== -1) {
|
||||||
|
/**
|
||||||
|
* NOTE: this is null, not undefined, so it was returned
|
||||||
|
* The plaintext value is generated.
|
||||||
|
*/
|
||||||
|
should.equal(firstPost.plaintext, null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
firstPost.html.should.match(/HTML Ipsum Presents/);
|
||||||
|
should.equal(firstPost.plaintext, undefined);
|
||||||
|
should.equal(firstPost.markdown, undefined);
|
||||||
|
should.equal(firstPost.amp, undefined);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('findAll', function () {
|
describe('findAll', function () {
|
||||||
|
@ -98,6 +119,27 @@ describe('Post Model', function () {
|
||||||
done();
|
done();
|
||||||
}).catch(done);
|
}).catch(done);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('can findAll, use formats option', function (done) {
|
||||||
|
var options = {
|
||||||
|
formats: ['markdown', 'plaintext'],
|
||||||
|
include: ['author', 'fields', 'tags', 'created_by', 'updated_by', 'published_by']
|
||||||
|
};
|
||||||
|
|
||||||
|
PostModel.findAll(options)
|
||||||
|
.then(function (results) {
|
||||||
|
should.exist(results);
|
||||||
|
results.length.should.be.above(0);
|
||||||
|
|
||||||
|
var posts = results.models.map(function (model) {
|
||||||
|
return model.toJSON(options);
|
||||||
|
}), firstPost = _.find(posts, {title: testUtils.DataGenerator.Content.posts[0].title});
|
||||||
|
|
||||||
|
checkFirstPostData(firstPost, options);
|
||||||
|
|
||||||
|
done();
|
||||||
|
}).catch(done);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('findPage', function () {
|
describe('findPage', function () {
|
||||||
|
|
|
@ -19,8 +19,13 @@ var _ = require('lodash'),
|
||||||
slugs: ['slugs'],
|
slugs: ['slugs'],
|
||||||
slug: ['slug'],
|
slug: ['slug'],
|
||||||
// object / model level
|
// object / model level
|
||||||
// Post API swaps author_id to author, and always returns a computed 'url' property
|
// Post API
|
||||||
post: _(schema.posts).keys().without('author_id').concat('author', 'url').value(),
|
post: _(schema.posts).keys()
|
||||||
|
// does not return all formats by default
|
||||||
|
.without('markdown', 'mobiledoc', 'amp', 'plaintext')
|
||||||
|
// swaps author_id to author, and always returns a computed 'url' property
|
||||||
|
.without('author_id').concat('author', 'url')
|
||||||
|
.value(),
|
||||||
// User API always removes the password field
|
// User API always removes the password field
|
||||||
user: _(schema.users).keys().without('password').without('ghost_auth_access_token').value(),
|
user: _(schema.users).keys().without('password').without('ghost_auth_access_token').value(),
|
||||||
// Tag API swaps parent_id to parent
|
// Tag API swaps parent_id to parent
|
||||||
|
@ -78,8 +83,10 @@ function checkResponseValue(jsonResponse, expectedProperties) {
|
||||||
providedProperties.length.should.eql(expectedProperties.length);
|
providedProperties.length.should.eql(expectedProperties.length);
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkResponse(jsonResponse, objectType, additionalProperties, missingProperties) {
|
function checkResponse(jsonResponse, objectType, additionalProperties, missingProperties, onlyProperties) {
|
||||||
var checkProperties = expectedProperties[objectType];
|
var checkProperties = expectedProperties[objectType];
|
||||||
|
|
||||||
|
checkProperties = onlyProperties ? onlyProperties : checkProperties;
|
||||||
checkProperties = additionalProperties ? checkProperties.concat(additionalProperties) : checkProperties;
|
checkProperties = additionalProperties ? checkProperties.concat(additionalProperties) : checkProperties;
|
||||||
checkProperties = missingProperties ? _.xor(checkProperties, missingProperties) : checkProperties;
|
checkProperties = missingProperties ? _.xor(checkProperties, missingProperties) : checkProperties;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue