Merge pull request #3 from shelbys/PLATAPI-1912

add $ref and remove type for models
This commit is contained in:
y-tang 2015-04-13 09:42:31 -07:00
commit 2158af9c82
8 changed files with 156 additions and 15 deletions

View File

@ -41,9 +41,10 @@ var classHelper = module.exports = {
* @return {Object} API declaration reference. * @return {Object} API declaration reference.
*/ */
generateResourceDocAPIEntry: function(aClass) { generateResourceDocAPIEntry: function(aClass) {
var description = aClass.ctor.settings.description || aClass.ctor.sharedCtor && aClass.ctor.sharedCtor.description;
return { return {
path: aClass.http.path, path: aClass.http.path,
description: aClass.ctor.settings.description || aClass.ctor.sharedCtor && aClass.ctor.sharedCtor.description description: Array.isArray(description) ? description.join('') : description
}; };
} }
}; };

View File

@ -5,6 +5,7 @@
*/ */
var _cloneDeep = require('lodash.clonedeep'); var _cloneDeep = require('lodash.clonedeep');
var translateDataTypeKeys = require('./translate-data-type-keys'); var translateDataTypeKeys = require('./translate-data-type-keys');
var TYPES_PRIMITIVE = ['array', 'boolean', 'integer', 'number', 'null', 'object', 'string', 'any'];
/** /**
* Export the modelHelper singleton. * Export the modelHelper singleton.
@ -28,7 +29,14 @@ var modelHelper = module.exports = {
referencedModels.push(model); referencedModels.push(model);
} }
} }
} };
var convertTypeTo$Ref = function convertTypeTo$Ref(prop){
if (prop.type && TYPES_PRIMITIVE.indexOf(prop.type) === -1 ){
prop.$ref = prop.type;
delete prop.type;
}
};
var def = modelClass.definition; var def = modelClass.definition;
var name = def.name; var name = def.name;
@ -73,6 +81,7 @@ var modelHelper = module.exports = {
processType(modelClass.app, prop.type, referencedModels); processType(modelClass.app, prop.type, referencedModels);
if (prop.items) { if (prop.items) {
processType(modelClass.app, prop.items.type, referencedModels); processType(modelClass.app, prop.items.type, referencedModels);
convertTypeTo$Ref(prop.items);
} }
// Required props sit in a per-model array. // Required props sit in a per-model array.
@ -83,6 +92,15 @@ var modelHelper = module.exports = {
// Change mismatched keys. // Change mismatched keys.
prop = translateDataTypeKeys(prop); prop = translateDataTypeKeys(prop);
convertTypeTo$Ref(prop);
delete prop.required;
delete prop.id;
if (prop.description){
prop.description = Array.isArray(prop.description) ? prop.description.join('') : prop.description;
}
// Assign this back to the properties object. // Assign this back to the properties object.
properties[key] = prop; properties[key] = prop;
@ -102,13 +120,25 @@ var modelHelper = module.exports = {
} }
}); });
var additionalProperties = undefined;
if (def.settings){
var strict = def.settings.strict;
additionalProperties = def.settings.additionalProperties;
var notAllowAdditionalProperties = strict || (additionalProperties !== true);
if (notAllowAdditionalProperties){
additionalProperties = false;
}
}
out[name] = { out[name] = {
id: name, id: name,
additionalProperties: additionalProperties,
properties: properties, properties: properties,
required: required required: required
}; };
if (def.settings && typeof def.settings.additionalProperties != 'undefined') {
out[name].additionalProperties = def.settings.additionalProperties; if (def.description){
out[name].description = Array.isArray(def.description) ? def.description.join('') : def.description;
} }
// Generate model definitions for related models // Generate model definitions for related models
@ -215,7 +245,4 @@ var modelHelper = module.exports = {
} }
return out; return out;
} }
}; };

View File

@ -191,8 +191,8 @@ var routeHelper = module.exports = {
nickname: route.method.replace(/\./g, '_'), nickname: route.method.replace(/\./g, '_'),
deprecated: route.deprecated, deprecated: route.deprecated,
type: returns.model || returns.type || 'void', type: returns.model || returns.type || 'void',
summary: route.description, // TODO(schoon) - Excerpt? summary: Array.isArray(route.description) ? route.description.join('') : route.description, // TODO(schoon) - Excerpt?
notes: route.notes, // TODO(schoon) - `description` metadata? notes: Array.isArray(route.notes) ? route.notes.join('') : route.notes, // TODO(schoon) - `description` metadata?
consumes: ['application/json', 'application/xml', 'text/xml'], consumes: ['application/json', 'application/xml', 'text/xml'],
produces: ['application/json', 'application/javascript', 'application/xml', 'text/javascript', 'text/xml'], produces: ['application/json', 'application/javascript', 'application/xml', 'text/javascript', 'text/xml'],
parameters: accepts, parameters: accepts,
@ -264,7 +264,7 @@ var routeHelper = module.exports = {
minimum: accepts.minimum, minimum: accepts.minimum,
maximum: accepts.maximum, maximum: accepts.maximum,
allowMultiple: accepts.allowMultiple, allowMultiple: accepts.allowMultiple,
description: accepts.description description: Array.isArray(accepts.description) ? accepts.description.join('') : accepts.description
}; };
out = routeHelper.extendWithType(out); out = routeHelper.extendWithType(out);

View File

@ -12,6 +12,7 @@ var urlJoin = require('./url-join');
var _defaults = require('lodash.defaults'); var _defaults = require('lodash.defaults');
var classHelper = require('./class-helper'); var classHelper = require('./class-helper');
var routeHelper = require('./route-helper'); var routeHelper = require('./route-helper');
var _cloneDeep = require('lodash.clonedeep');
/** /**
* Create a remotable Swagger module for plugging into `RemoteObjects`. * Create a remotable Swagger module for plugging into `RemoteObjects`.
@ -129,11 +130,17 @@ function addRoute(app, uri, doc, opts) {
* @return {Object} Resource doc. * @return {Object} Resource doc.
*/ */
function generateResourceDoc(opts) { function generateResourceDoc(opts) {
var apiInfo = _cloneDeep(opts.apiInfo);
for (var propertyName in apiInfo) {
var property = apiInfo[propertyName];
apiInfo[propertyName] = Array.isArray(property) ? property.join('') : property;
}
return { return {
swaggerVersion: opts.swaggerVersion, swaggerVersion: opts.swaggerVersion,
apiVersion: opts.version, apiVersion: opts.version,
// See https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md#513-info-object // See https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md#513-info-object
info: opts.apiInfo, info: apiInfo,
// TODO Authorizations // TODO Authorizations
// https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md#514-authorizations-object // https://github.com/wordnik/swagger-spec/blob/master/versions/1.2.md#514-authorizations-object
consumes: ['application/json', 'application/xml', 'text/xml'], consumes: ['application/json', 'application/xml', 'text/xml'],

View File

@ -1,6 +1,6 @@
{ {
"name": "loopback-explorer", "name": "loopback-explorer",
"version": "1.2.12", "version": "1.2.13",
"description": "Browse and test your LoopBack app's APIs", "description": "Browse and test your LoopBack app's APIs",
"main": "index.js", "main": "index.js",
"scripts": { "scripts": {

47
test/class-helper.test.js Normal file
View File

@ -0,0 +1,47 @@
/**
* Created by ytang on 4/7/15.
*/
var classHelper = require('../lib/class-helper');
var loopback = require('loopback');
var expect = require('chai').expect;
describe('class-helper', function() {
describe('#generateResourceDocAPIEntry', function() {
describe('when ctor.settings.description is an array of string', function() {
it('should return description as a string', function() {
var aClass = {
ctor: {
settings: {
description: ['1','2','3']
}
},
http:{
path: 'path'
}
};
var result = classHelper.generateResourceDocAPIEntry(aClass);
expect(result.description).to.eql('123');
});
});
describe('when ctor.sharedCtor.description is an array of string', function() {
it('should return description as a string', function() {
var aClass = {
ctor: {
settings: {},
sharedCtor: {
description: ['1','2','3']
}
},
http:{
path: 'path'
}
};
var result = classHelper.generateResourceDocAPIEntry(aClass);
expect(result.description).to.eql('123');
});
});
});
});

View File

@ -111,14 +111,14 @@ describe('model-helper', function() {
expect(prop).to.eql({ type: 'array', items: { type: 'any' } }); expect(prop).to.eql({ type: 'array', items: { type: 'any' } });
}); });
it('converts Model type', function() { it('converts Model type to $ref', function() {
var Address = loopback.createModel('Address', {street: String}); var Address = loopback.createModel('Address', {street: String});
var def = buildSwaggerModels({ var def = buildSwaggerModels({
str: String, str: String,
address: Address address: Address
}); });
var prop = def.properties.address; var prop = def.properties.address;
expect(prop).to.eql({ type: 'Address' }); expect(prop).to.eql({ $ref: 'Address' });
}); });
}); });
@ -192,6 +192,36 @@ describe('model-helper', function() {
expect(def.properties).to.have.property('visibleProperty'); expect(def.properties).to.have.property('visibleProperty');
}); });
}); });
describe('#generateModelDefinition', function(){
it('should convert top level array description to string', function(){
var model = {};
model.definition = {
name: 'test',
description: ['1','2','3'],
properties: {}
};
var models = {};
modelHelper.generateModelDefinition(model, models);
expect(models.test.description).to.equal('123');
});
it('should convert property level array description to string', function(){
var model = {};
model.definition = {
name: 'test',
properties: {
prop1: {
type: 'string',
description: ['1','2','3']
}
}
};
var models = {};
modelHelper.generateModelDefinition(model, models);
expect(models.test.properties.prop1.description).to.equal('123');
});
});
}); });
// Simulates the format of a remoting class. // Simulates the format of a remoting class.

View File

@ -73,6 +73,35 @@ describe('route-helper', function() {
expect(opDoc.responseMessages[0].responseModel).to.equal('string'); expect(opDoc.responseMessages[0].responseModel).to.equal('string');
}); });
describe('#acceptToParameter', function(){
it('should return function that converts accepts.description from array of string to string', function(){
var f = routeHelper.acceptToParameter({verb: 'get', path: 'path'});
var result = f({description: ['1','2','3']});
expect(result.description).to.eql('123');
});
});
describe('#routeToAPIDoc', function(){
it('should convert route.description from array fo string to string', function(){
var result = routeHelper.routeToAPIDoc({
method: 'someMethod',
verb: 'get',
path: 'path',
description:['1','2','3']
});
expect(result.operations[0].summary).to.eql('123');
});
it('should convert route.notes from array fo string to string', function(){
var result = routeHelper.routeToAPIDoc({
method: 'someMethod',
verb: 'get',
path: 'path',
notes:['1','2','3']
});
expect(result.operations[0].notes).to.eql('123');
});
});
}); });
// Easy wrapper around createRoute // Easy wrapper around createRoute