Skip to content

Commit

Permalink
Release 2.0.0-rc.7 🍻 👏
Browse files Browse the repository at this point in the history
- Enhance: #72
- Fix: #71
- Fix: #70
- Fix: #69
- Enhance: #59
- Enhance: #57
- Fix: #51
  • Loading branch information
Jonathan Casarrubias committed Aug 2, 2016
1 parent 4111086 commit dbc3526
Show file tree
Hide file tree
Showing 45 changed files with 1,701 additions and 418 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.md
Expand Up @@ -2,6 +2,16 @@

This file is created to keep history of the LoopBack SDK Builder, it does not consider or keeps any history of its parent module `loopback-sdk-angular`.

## Release 2.0.0-rc.7

- Enhance: https://github.com/jonathan-casarrubias/loopback-sdk-builder/issues/72
- Fix: https://github.com/jonathan-casarrubias/loopback-sdk-builder/issues/71
- Fix: https://github.com/jonathan-casarrubias/loopback-sdk-builder/issues/70
- Fix: https://github.com/jonathan-casarrubias/loopback-sdk-builder/issues/69
- Enhance: https://github.com/jonathan-casarrubias/loopback-sdk-builder/issues/59
- Enhance: https://github.com/jonathan-casarrubias/loopback-sdk-builder/issues/57
- Fix: https://github.com/jonathan-casarrubias/loopback-sdk-builder/issues/51

## Release 2.0.0-rc.6

- Fix: https://github.com/jonathan-casarrubias/loopback-sdk-builder/issues/68
Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -53,7 +53,7 @@ You don't have to manually write any static code.

````sh
$ cd to/api/project
$ npm install --save-dev loopback-sdk-builder@2.0.0-rc.6
$ npm install --save-dev loopback-sdk-builder@2.0.0-rc.7
````

# LoopBack SDK CLI Options
Expand Down
181 changes: 131 additions & 50 deletions lib/angular2/index.js
@@ -1,6 +1,7 @@
/**
* @module Angular 2 Generator for loopback-sdk-builder
* @author Jonathan Casarrubias <@johncasarrubias> <github:jonathan-casarrubias>
* @license MTI
* @description
* Defines a SDK Schema and builds according configuration
*/
Expand Down Expand Up @@ -163,11 +164,9 @@ module.exports = function generate(ctx) {
output: '/models/' + modelName + '.ts',
params: {
model: ctx.models[modelName],
models: ctx.models,
modelName: modelName,
getModelType: getModelType,
getPropertyType: getPropertyType,
getModelImports: getModelImports
buildModelImports: buildModelImports,
buildModelProperties: buildModelProperties
}
},
/**
Expand All @@ -184,6 +183,8 @@ module.exports = function generate(ctx) {
buildPostBody: buildPostBody,
buildUrlParams: buildUrlParams,
buildRouteParams: buildRouteParams,
buildMethodParams: buildMethodParams,
buildServiceImports: buildServiceImports,
normalizeMethodName: normalizeMethodName
}
}
Expand All @@ -207,44 +208,90 @@ module.exports = function generate(ctx) {
}
);
/**
* @method getPropertyType
* @method buildModelImports
* @description
* Define import statement for those model who are related to other scopes
*/
function buildModelImports(model) {
let relations = Object.keys(model.sharedClass.ctor.relations).filter(
relationName => model.sharedClass.ctor.relations[relationName].targetClass &&
model.sharedClass.ctor.relations[relationName].targetClass !== model.name
);
let loaded = {};
let output = [];
if (relations.length > 0) {
output.push('import {');
relations.forEach((relationName, i) => {
let targetClass = model.sharedClass.ctor.relations[relationName].targetClass;
if (!loaded[targetClass]) {
loaded[targetClass] = true;
output.push(` ${targetClass}${(i < relations.length - 1) ? ',' : ''}`);
}
});
output.push('} from \'../index\';\n');
}
return output.join('\n');
}
/**
* @method buildModelProperties
* @description
* Define properties for the given model
*/
function buildModelProperties(model, isInterface) {
let output = [];
// Add Model Properties
Object.keys(model.properties).forEach((property) => {
if (model.isUser && property === 'credentials') return;
let meta = model.properties[property];
let isRequired = '';
if (isInterface && meta.required)
isRequired = '?';
output.push(` ${property}${isRequired}: ${buildPropertyType(meta.type)};`);
});
// Add Model Relations
Object.keys(model.sharedClass.ctor.relations).forEach(relation => {
output.push(` ${relation}${isInterface ? '?' : ''}: ${buildRelationType(model, relation)};`);
});
return output.join('\n');
}
/**
* @method buildRelationType
* @description
* Discovers property type according related models that are public
*/
function getPropertyType(model, relationName) {
function buildRelationType(model, relationName) {
let relation = model.sharedClass.ctor.relations[relationName];
let targetClass = relation.targetClass;
let basicType = (ctx.models[targetClass]) ? targetClass : 'any';
let finalType = relation.type.match(/(^has$|belongsTo)/g)
let finalType = relation.type.match(/(hasOne|belongsTo)/g)
? basicType : `Array<${basicType}>`;
return finalType;
}
/**
* @method getModelImports
* @method buildServiceImports
* @description
* Define import statement for those model who are related to other scopes
*/
function getModelImports(model) {
let relations = Object.keys(model.sharedClass.ctor.relations).filter(
relationName => model.sharedClass.ctor.relations[relationName].targetClass &&
model.sharedClass.ctor.relations[relationName].targetClass !== model.name
);
let loaded = {};
let output = new String();
if (relations.length > 0) {
output = 'import {';
relations.forEach((relationName, i) => {
let targetClass = model.sharedClass.ctor.relations[relationName].targetClass;
if (!loaded[targetClass]) {
loaded[targetClass] = true;
output = `${output}\n ${targetClass}`;
output = (i < relations.length - 1) ? `${output},` : output
function buildServiceImports(modelName, methods) {
let output = [` ${modelName}`];
let namespaces = {}; namespaces[modelName] = true;
methods.forEach((action) => {
action.accepts.forEach((param, i, arr) => {
var type;
if (param.type === 'object') {
type = param.arg === 'filter' ? 'LoopBackFilter' : 'any';
} else {
type = param.type !== 'AccessToken' && param.type !== 'any'
? param.type : 'any';
}
let capitalized = capitalize(type);
if (typeof type === 'string' && !type.match(/(any|number|boolean|string|date|array|object)/) && !namespaces[capitalized]) {
namespaces[capitalized] = true;
output.push(` ${capitalized}`);
}
});
output = `${output}
} from '../index';`;
}
return output;
});
return output.join(',\n');
}
/**
* @method normalizeMethodName
Expand All @@ -256,63 +303,93 @@ module.exports = function generate(ctx) {
return (index < 2 && !capitalize) ? value : (value.charAt(0).toUpperCase() + value.slice(1));
}).join('');
}
/**
* @method buildMethodParams
* @description
* Set which params should be defined for the given remote method
*/
function buildMethodParams(methodName, params) {
let output = new Array();
if (methodName !== 'logout') {
params.forEach((param, i, arr) => {
let type;
if (param.type === 'object') {
type = param.arg === 'filter' ? 'LoopBackFilter' : 'any';
} else {
type = param.type !== 'AccessToken' && param.type !== 'any'
? capitalize(param.type) : 'any';
}
let value = '';
if (!param.required && methodName === 'login' && param.arg === 'include') {
type = 'any';
value = " = 'user'";
} else {
value = !param.required ? ' = undefined' : '';
}
output.push(`${param.arg}: ${type}${value}`);
});
}
return output.join(', ');
}
/**
* @method buildPostBody
* @description
* Define which properties should be passed while posting data (POST, PUT, PATCH)
*/
function buildPostBody(postData) {
let output = new String();
let output = [];
if (postData && postData.length > 0) {
output.push('');
let l = postData.length;
postData.forEach((property, i) => {
output = `${output}\n ${property.arg}: ${property.arg}`;
output = (i < postData.length - 1) ? `${output},` : `${output}\n `;
output.push(` ${property.arg}: ${property.arg}${(i < l - 1) ? ',' : ''}`);
});
output.push(' ');
}
return output;
return output.join('\n');
}
/**
* @method buildUrlParams
* @description
* Define which properties should be passed using query string
*/
function buildUrlParams(model, methodName, urlParams) {
let output = new String();
let output = [''];
// filter params that should not go over url query string
urlParams = urlParams.filter(param => !param.arg.match(/(id|fk|data|options|credentials)/g));
if (model.isUser && methodName === 'logout')
output = `${output}\n urlParams.access_token = this.auth.getAccessTokenId();`;
output.push(` urlParams.access_token = this.auth.getAccessTokenId();`);
if (urlParams && urlParams.length > 0) {
urlParams.forEach((param, i) => {
output = `${output}\n if (${param.arg}) urlParams.${param.arg} = ${param.arg};`;
output.push(` if (${param.arg}) urlParams.${param.arg} = ${param.arg};`);
});
}
return output;
return output.join('\n');
}
/**
* @method buildRouteParams TODO
* @method buildRouteParams
* @description
* Define which properties should be passed as route params
*/
function buildRouteParams(routeParams) {
let output = new String();
let output = [];
if (routeParams && routeParams.length > 0) {
output.push('');
routeParams.forEach((param, i) => {
output = `${output}\n ${param.arg}: ${param.arg}`;
output = (i < routeParams.length - 1) ? `${output},` : `${output}\n `;
output.push(` ${param.arg}: ${param.arg}${(i < routeParams.length - 1) ? ',' : ''}`);
});
output.push(' ');
}
return output;
return output.join('\n');
}
/*
<%
routeParams.forEach(function(param, i, arr) { %>
<%= param.arg %>: <%= param.arg %><%= i < arr.length -1 ? ',' : '' %><%
});%>
%>
*/
// TODO REVIEW TO SEE IF THIS IS CORRECT AND VALUABLE (JC)
function getModelType(type) {
/**
* @author João Ribeiro <jonnybgod@gmail.com, http://jonnybgod.ghost.io>,
* @license MTI
* @method buildPropertyType
* @description
* Define which properties should be passed as route params
*/
function buildPropertyType(type) {
switch (type.toString()) {
case 'boolean':
case 'function Boolean() { [native code] }':
Expand All @@ -330,4 +407,8 @@ module.exports = function generate(ctx) {
return 'any';
}
}
};
};

function capitalize(string) {
return string[0].toUpperCase() + string.slice(1);
}
3 changes: 1 addition & 2 deletions lib/angular2/shared/models/base.ejs
Expand Up @@ -8,7 +8,6 @@ export interface LoopBackFilter {
offset?: any;
where?: any;
}

<% if (!loadAccessToken) { %>
export interface AccessTokenInterface {
id?: string;
Expand All @@ -28,4 +27,4 @@ export class AccessToken implements AccessTokenInterface {
Object.assign(this, instance);
}
}
<% } %>
<% } %>
32 changes: 3 additions & 29 deletions lib/angular2/shared/models/model.ejs
@@ -1,37 +1,11 @@
/* tslint:disable */
<%- getModelImports(model) %>

<%- buildModelImports(model) %>
export interface <%- modelName %>Interface {
<% for (var property in model.properties) { var meta = model.properties[property]; -%>
<% if (meta.description) { %>
/**
* <%- meta.description %>
*/<% } %>
<%- property %><%= meta.required ? '' : '?' -%>: <%- getModelType(meta.type) %>;
<%
} // for property in model.properties -%>
<% Object.keys(model.sharedClass.ctor.relations).forEach(relation => {
%><%- relation %>?: <%- getPropertyType(model, relation) %>;
<%
}); // for property in model.relations -%>
<%- buildModelProperties(model, true) %>
}

export class <%- modelName %> implements <%- modelName %>Interface {
<% for (var property in model.properties) { var meta = model.properties[property]; -%>
<% if (meta.description) { %>
/**
* <%- meta.description %>
*/<% } %>
<%- property %>: <%- getModelType(meta.type) %>;<%
} // for property in model.properties -%>
<% Object.keys(model.sharedClass.ctor.relations).forEach(relation => {
%><%- relation %>: <%- getPropertyType(model, relation) %>;
<%
}); // for property in model.relations -%>
<%- buildModelProperties(model) %>
constructor(instance?: <%- modelName %>) {
Object.assign(this, instance);
}
Expand Down
5 changes: 0 additions & 5 deletions lib/angular2/shared/services/core/auth.ejs
Expand Up @@ -64,14 +64,9 @@ export class LoopBackAuth {
StorageDriver.remove(this.propsPrefix + 'rememberMe');
};

// Note: LocalStorage converts the value to string
// We are using empty string as a marker for null/undefined values.
protected saveThis(name: string, value: any) {
try {
var key = this.propsPrefix + name;
if (value == null) {
value = '';
}
StorageDriver.set(key, value);
}
catch(err) {
Expand Down

0 comments on commit dbc3526

Please sign in to comment.