Skip to content
Merged

3.1.0 #504

Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 34 additions & 1 deletion rules/file-name.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,38 @@ var path = require('path');

var utils = require('./utils/utils');

/**
* The filename is the one for the import statement if we are in a module
*
* @param {any} node The current node being linted
* @param {any} context The context
* @param {any} defaultFilename The previous filename
* @returns
*/
function handleModuleCase(node, context, defaultFilename) {
if (context.parserOptions.sourceType !== 'module') {
return defaultFilename;
}

// Handle the module case.
var name = node.arguments[1].name;
var globalScope = context.getScope();

// Retrieve the import instruction.
var variable = globalScope.variables.find(function(v) {
return v.name === name;
});

// Check that the definition is an import declaration.
if (variable.defs[0].parent.type !== 'ImportDeclaration') {
return defaultFilename;
}

// Thanks to the chrome devtools to find the path of the filename. :-)
var filename = path.basename(variable.defs[0].parent.source.value);
return filename;
}

module.exports = {
meta: {
schema: [{
Expand Down Expand Up @@ -117,7 +149,6 @@ module.exports = {

return function(context) {
var options = context.options[0] || {};
var filename = path.basename(context.getFilename());
var componentTypeMappings = createComponentTypeMappings(options);

return {
Expand All @@ -135,6 +166,8 @@ module.exports = {
return;
}
expectedName = filenameUtil.createExpectedName(name, type, options);
var filename = path.basename(context.getFilename());
filename = handleModuleCase(node, context, filename);

if (expectedName !== filename) {
context.report(node, 'Filename must be "{{expectedName}}"', {
Expand Down
97 changes: 80 additions & 17 deletions test/file-name.js
Original file line number Diff line number Diff line change
Expand Up @@ -259,42 +259,68 @@ angular.module(mod, [mod + '.core.angular', mod + '.thirdparty']);
options: [{
casing: 'pascal'
}]
}, {
// import case
filename: 'src/app/SomeOtherController.js',
code: `
var MyCtrl4 = function() {};
import {MyCtrl1} from 'src/app/SomeController.js';
import {MyCtrl2} from 'src/app/SomeDirective.js';
import {MyCtrl3} from 'src/app/SomeService.js';
app.controller("SomeController", MyCtrl1);
app.directive("SomeDirective", MyCtrl2);
app.service("SomeService", MyCtrl3);
app.controller("SomeOtherController", MyCtrl4);`,
parserOptions: {
ecmaVersion: 6,
sourceType: 'module'
}
}].concat(commonFalsePositives),
invalid: [{
filename: 'src/app/filters.js',
code: 'app.filter("myFilter", function() {});',
errors: [{message: 'Filename must be "myFilter.js"'}]
errors: [{
message: 'Filename must be "myFilter.js"'
}]
}, {
filename: 'src/app/myFilter.js',
code: 'app.filter("myFilter", function() {});',
options: [{
typeSeparator: 'dot'
}],
errors: [{message: 'Filename must be "myFilter.filter.js"'}]
errors: [{
message: 'Filename must be "myFilter.filter.js"'
}]
}, {
// typeSeparator underscore with service
filename: 'src/someService_controller.js',
code: 'app.factory("someService", function() {});',
options: [{
typeSeparator: 'underscore'
}],
errors: [{message: 'Filename must be "someService_service.js"'}]
errors: [{
message: 'Filename must be "someService_service.js"'
}]
}, {
// typeSeparator dot with controller, but no ignored type suffix
filename: 'src/app/Avengers.controller.js',
code: 'app.controller("AvengersController", function() {});',
options: [{
typeSeparator: 'dot'
}],
errors: [{message: 'Filename must be "AvengersController.controller.js"'}]
errors: [{
message: 'Filename must be "AvengersController.controller.js"'
}]
}, {
// typeSeparator dot with component, but no ignored type suffix
filename: 'src/app/Avengers.component.js',
code: 'app.component("AvengersComponent", {});',
options: [{
typeSeparator: 'dot'
}],
errors: [{message: 'Filename must be "AvengersComponent.component.js"'}]
errors: [{
message: 'Filename must be "AvengersComponent.component.js"'
}]
}, {
// typeSeparator dot with controller and ignored type suffix
filename: 'src/app/AvengersController.controller.js',
Expand All @@ -303,7 +329,9 @@ angular.module(mod, [mod + '.core.angular', mod + '.thirdparty']);
typeSeparator: 'dot',
ignoreTypeSuffix: true
}],
errors: [{message: 'Filename must be "Avengers.controller.js"'}]
errors: [{
message: 'Filename must be "Avengers.controller.js"'
}]
}, {
// typeSeparator dot with component and ignored type suffix
filename: 'src/app/AvengersComponent.component.js',
Expand All @@ -312,7 +340,9 @@ angular.module(mod, [mod + '.core.angular', mod + '.thirdparty']);
typeSeparator: 'dot',
ignoreTypeSuffix: true
}],
errors: [{message: 'Filename must be "Avengers.component.js"'}]
errors: [{
message: 'Filename must be "Avengers.component.js"'
}]
}, {
// nameStyle dash and typeSeparator dot with directive
filename: 'src/app/avangerProfile.directive.js',
Expand All @@ -321,7 +351,9 @@ angular.module(mod, [mod + '.core.angular', mod + '.thirdparty']);
typeSeparator: 'dot',
nameStyle: 'dash'
}],
errors: [{message: 'Filename must be "avanger-profile.directive.js"'}]
errors: [{
message: 'Filename must be "avanger-profile.directive.js"'
}]
}, {
// ignorePrefix xp
filename: 'src/app/xpAsset.service.js',
Expand All @@ -331,7 +363,9 @@ angular.module(mod, [mod + '.core.angular', mod + '.thirdparty']);
ignoreTypeSuffix: true,
ignorePrefix: 'xp'
}],
errors: [{message: 'Filename must be "asset.service.js"'}]
errors: [{
message: 'Filename must be "asset.service.js"'
}]
}, {
// ignorePrefix xp.
filename: 'src/app/xpAsset.service.js',
Expand All @@ -341,7 +375,9 @@ angular.module(mod, [mod + '.core.angular', mod + '.thirdparty']);
ignoreTypeSuffix: true,
ignorePrefix: 'xp.'
}],
errors: [{message: 'Filename must be "asset.service.js"'}]
errors: [{
message: 'Filename must be "asset.service.js"'
}]
}, {
// alphanumeric nameStyle dash and typeSeparator dash with service
filename: 'src/app/app2utils-service.js',
Expand All @@ -350,7 +386,9 @@ angular.module(mod, [mod + '.core.angular', mod + '.thirdparty']);
typeSeparator: 'dash',
nameStyle: 'dash'
}],
errors: [{message: 'Filename must be "app2-utils-service.js"'}]
errors: [{
message: 'Filename must be "app2-utils-service.js"'
}]
}, {
// alphanumeric nameStyle underscore and typeSeparator dot with directive
filename: 'src/app/my2tab.directive.js',
Expand All @@ -359,7 +397,9 @@ angular.module(mod, [mod + '.core.angular', mod + '.thirdparty']);
typeSeparator: 'dot',
nameStyle: 'underscore'
}],
errors: [{message: 'Filename must be "my2_tab.directive.js"'}]
errors: [{
message: 'Filename must be "my2_tab.directive.js"'
}]
}, {
// custom componentTypeMappings for provider
filename: 'src/app/users.service.js',
Expand All @@ -370,7 +410,9 @@ angular.module(mod, [mod + '.core.angular', mod + '.thirdparty']);
},
typeSeparator: 'dot'
}],
errors: [{message: 'Filename must be "users.provider.js"'}]
errors: [{
message: 'Filename must be "users.provider.js"'
}]
}, {
// camel casing, dot typeSeparator, ignoreTypeSuffix of true
filename: 'src/app/SomeController.js',
Expand All @@ -380,15 +422,19 @@ angular.module(mod, [mod + '.core.angular', mod + '.thirdparty']);
typeSeparator: 'dot',
ignoreTypeSuffix: true
}],
errors: [{message: 'Filename must be "some.controller.js"'}]
errors: [{
message: 'Filename must be "some.controller.js"'
}]
}, {
// camel casing
filename: 'src/app/SomeController.js',
code: 'app.controller("SomeController", function() {});',
options: [{
casing: 'camel'
}],
errors: [{message: 'Filename must be "someController.js"'}]
errors: [{
message: 'Filename must be "someController.js"'
}]
}, {
// pascal casing, dot typeSeparator, ignoreTypeSuffix of true
filename: 'src/app/someController.js',
Expand All @@ -398,14 +444,31 @@ angular.module(mod, [mod + '.core.angular', mod + '.thirdparty']);
typeSeparator: 'dot',
ignoreTypeSuffix: true
}],
errors: [{message: 'Filename must be "Some.controller.js"'}]
errors: [{
message: 'Filename must be "Some.controller.js"'
}]
}, {
// pascal casing
filename: 'src/app/someController.js',
code: 'app.controller("SomeController", function() {});',
options: [{
casing: 'pascal'
}],
errors: [{message: 'Filename must be "SomeController.js"'}]
errors: [{
message: 'Filename must be "SomeController.js"'
}]
}, {
// import case
filename: 'src/app/SomeController.js',
code: `
import {MyCtrl} from 'src/app/main.js'
app.controller("SomeController", MyCtrl);`,
parserOptions: {
ecmaVersion: 6,
sourceType: 'module'
},
errors: [{
message: 'Filename must be "SomeController.js"'
}]
}]
});