Skip to content

Commit 4a70425

Browse files
committed
Merge pull request #173 from strongloop/update_remote_method
Allow defining remote method without isStatic flag
2 parents 97c75b5 + 6959163 commit 4a70425

File tree

4 files changed

+93
-8
lines changed

4 files changed

+93
-8
lines changed

lib/helpers.js

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,24 @@ exports.checkPropertyName = function(name) {
6565
return true;
6666
};
6767

68+
/**
69+
* Validate remote method name. Allows `.` in method name for prototype
70+
* @param {String} name The user input
71+
* @returns {String|Boolean}
72+
*/
73+
exports.validateRemoteMethodName = function(name) {
74+
if (name.match(/\./) && !name.match(/^prototype\.([^.]*)$/)) {
75+
return 'Name cannot contain "." characters except' +
76+
' the dot in "prototype." prefix';
77+
}
78+
var result = exports.validateOptionalName(name, /[\/@\s\+%:]/);
79+
if (result !== true) return result;
80+
if (RESERVED_PROPERTY_NAMES.indexOf(name) !== -1) {
81+
return name + ' is a reserved keyword. Please use another name';
82+
}
83+
return true;
84+
};
85+
6886
/**
6987
* Validate required name for properties, data sources, or connectors
7088
* Empty name could not pass
@@ -84,9 +102,13 @@ exports.validateRequiredName = function (name) {
84102
* @param {String} name The user input
85103
* @returns {String|Boolean}
86104
*/
87-
exports.validateOptionalName = function (name) {
88-
if (name.match(/[\/@\s\+%:\.]/)) {
89-
return 'Name cannot contain special characters (/@+%:. ): ' + name;
105+
exports.validateOptionalName = function (name, unallowedCharacters) {
106+
if (!unallowedCharacters) {
107+
unallowedCharacters = /[\/@\s\+%:\.]/;
108+
}
109+
if (name.match(unallowedCharacters)) {
110+
return 'Name cannot contain special characters ' + unallowedCharacters +
111+
name;
90112
}
91113
if (name !== encodeURIComponent(name)) {
92114
return 'Name cannot contain special characters escaped by ' +

remote-method/index.js

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ var actions = require('../lib/actions');
1313
var helpers = require('../lib/helpers');
1414
var validateRequiredName = helpers.validateRequiredName;
1515
var validateOptionalName = helpers.validateOptionalName;
16-
var checkPropertyName = helpers.checkPropertyName;
16+
var validateRemoteMethodName = helpers.validateRemoteMethodName;
1717
var typeChoices = helpers.getTypeChoices();
1818
var ModelDefinition = require('loopback-workspace').models.ModelDefinition;
1919

@@ -96,22 +96,27 @@ module.exports = yeoman.generators.Base.extend({
9696
message: 'Enter the remote method name:',
9797
required: true,
9898
default: name,
99-
validate: checkPropertyName
99+
validate: validateRemoteMethodName
100100
},
101101
{
102102
name: 'isStatic',
103103
message: 'Is Static?',
104-
required:true,
104+
required: false,
105105
type: 'confirm',
106-
default: true
106+
default: function(answers) {
107+
return !answers.methodName.match(/^prototype\.(.*)$/);
108+
}
107109
},
108110
{
109111
name: 'description',
110112
message: 'Description for method:'
111113
}
112114
];
113115
this.prompt(prompts, function(answers) {
114-
this.methodName = answers.methodName;
116+
var m = answers.methodName.match(/^prototype\.(.*)$/);
117+
var isStatic = !m;
118+
var baseName = isStatic ? answers.methodName : m[1];
119+
this.methodName = baseName;
115120
this.isStatic = answers.isStatic;
116121
this.description = answers.description;
117122
done();

test/helpers.test.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ var validateAppName = helpers.validateAppName;
1010
var validateOptionalName = helpers.validateOptionalName;
1111
var validateRequiredName = helpers.validateRequiredName;
1212
var checkRelationName = helpers.checkRelationName;
13+
var validateRemoteMethodName = helpers.validateRemoteMethodName;
1314
require('chai').should();
1415
var expect = require('chai').expect;
1516
var promise = require('bluebird');
@@ -76,6 +77,36 @@ describe('helpers', function() {
7677
});
7778
});
7879

80+
// test validateRemoteMethodName()
81+
describe('validateRemoteMethodName()', function() {
82+
it('should accept good names', function() {
83+
testValidationAcceptsValue(validateRemoteMethodName, 'prop');
84+
testValidationAcceptsValue(validateRemoteMethodName, 'prop1');
85+
testValidationAcceptsValue(validateRemoteMethodName, 'my_prop');
86+
testValidationAcceptsValue(validateRemoteMethodName, 'my-prop');
87+
testValidationAcceptsValue(validateRemoteMethodName, 'prototype.method');
88+
});
89+
90+
it('should report errors for a name containing special chars', function() {
91+
testValidationRejectsValue(validateRemoteMethodName, 'my prop');
92+
testValidationRejectsValue(validateRemoteMethodName, 'my/prop');
93+
testValidationRejectsValue(validateRemoteMethodName, 'my@prop');
94+
testValidationRejectsValue(validateRemoteMethodName, 'my+prop');
95+
testValidationRejectsValue(validateRemoteMethodName, 'my%prop');
96+
testValidationRejectsValue(validateRemoteMethodName, 'my:prop');
97+
testValidationRejectsValue(validateRemoteMethodName, 'm.prop');
98+
});
99+
100+
it('should accept empty name', function() {
101+
testValidationAcceptsValue(validateOptionalName, '');
102+
});
103+
104+
it('should not accept name with . after `prototype.`', function() {
105+
testValidationRejectsValue(validateRemoteMethodName,
106+
'prototype.dotted.method');
107+
});
108+
});
109+
79110
// test checkRelationName()
80111
describe('checkRelationName()', function() {
81112
var sampleModelDefinition = new ModelDefinition([

test/remote-method.test.js

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,33 @@ describe('loopback:remote-method generator', function() {
6161
});
6262
});
6363

64+
it('method name with `prototype.` should be removed', function(done) {
65+
var methodGenerator = givenMethodGenerator();
66+
helpers.mockPrompt(methodGenerator, {
67+
model: 'Car',
68+
methodName: 'prototype.myRemote',
69+
isStatic: 'false',
70+
desription: 'This is my first remote method',
71+
httpPath: '',
72+
acceptsArg: '',
73+
returnsArg: ''
74+
});
75+
76+
methodGenerator.run(function() {
77+
var definition = common.readJsonSync('common/models/car.json');
78+
var methods = definition.methods || {};
79+
expect(methods).to.have.property('myRemote');
80+
expect(methods).to.not.have.property('prototype.myRemote');
81+
expect(methods.myRemote).to.eql({
82+
isStatic: false,
83+
accepts: [],
84+
returns: [],
85+
http: []
86+
});
87+
done();
88+
});
89+
});
90+
6491
function givenMethodGenerator() {
6592
var name = 'loopback:remote-method';
6693
var path = '../../remote-method';

0 commit comments

Comments
 (0)