Skip to content

Commit cf1b87e

Browse files
Add module-configuration-file rule for Y128 guideline
Implement new ESLint rule to enforce John Papa's Y128 style guideline for AngularJS module configuration files. This rule ensures that module configuration (.config() calls) are placed in separate files with a .config.js suffix, following the naming pattern: - app.config.js for the main app module - admin.config.js for an admin module - Or simply config.js The rule automatically skips test files (.spec.js and .test.js). Files added: - rules/module-configuration-file.js - test/module-configuration-file.js - examples/module-configuration-file.js - Updated index.js to include rule in johnpapa config Closes #52 🤖 Generated with [Claude Code](https://claude.ai/code) Co-authored-by: Emmanuel DEMEY <EmmanuelDemey@users.noreply.github.com>
1 parent f6b90c7 commit cf1b87e

4 files changed

Lines changed: 191 additions & 0 deletions

File tree

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
2+
// example - valid: true, filename: "app.config.js"
3+
angular.module('app').config(function($httpProvider) {
4+
$httpProvider.interceptors.push('authInterceptor');
5+
});
6+
7+
// example - valid: true, filename: "admin.config.js"
8+
angular.module('admin').config(function($routeProvider) {
9+
$routeProvider.when('/admin', {
10+
templateUrl: 'admin.html'
11+
});
12+
});
13+
14+
// example - valid: true, filename: "config.js"
15+
angular.module('myApp').config(function($logProvider) {
16+
$logProvider.debugEnabled(true);
17+
});
18+
19+
// example - valid: true, filename: "src/modules/users/users.config.js"
20+
angular.module('users').config(function($stateProvider) {
21+
$stateProvider.state('users', {
22+
url: '/users',
23+
templateUrl: 'users.html'
24+
});
25+
});
26+
27+
// example - valid: false, filename: "app.js", errorMessage: "Module configuration should be in a separate file with a .config.js suffix"
28+
angular.module('app').config(function($httpProvider) {
29+
$httpProvider.interceptors.push('authInterceptor');
30+
});
31+
32+
// example - valid: false, filename: "app.module.js", errorMessage: "Module configuration should be in a separate file with a .config.js suffix"
33+
angular.module('app').config(function($routeProvider) {
34+
$routeProvider.otherwise('/home');
35+
});
36+
37+
// example - valid: false, filename: "admin.js", errorMessage: "Module configuration should be in a separate file with a .config.js suffix"
38+
angular.module('admin').config(configFunction);

index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ module.exports = {
3838
'angular/filter-name': 2,
3939
'angular/function-type': 2,
4040
'angular/interval-service': 2,
41+
'angular/module-configuration-file': 2,
4142
'angular/module-getter': 2,
4243
'angular/module-name': 2,
4344
'angular/module-setter': 2,

rules/module-configuration-file.js

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/**
2+
* require module configuration to be in separate files
3+
*
4+
* Separate configuration for a module into its own file named after the module.
5+
* A configuration file for the main `app` module is named `app.config.js` (or simply `config.js`).
6+
* A configuration for a module named `admin.module.js` is named `admin.config.js`.
7+
*
8+
* @styleguideReference {johnpapa} `y128` Modules - Configuration
9+
* @version 0.16.0
10+
* @category conventions
11+
* @sinceAngularVersion 1.x
12+
*/
13+
'use strict';
14+
15+
var path = require('path');
16+
var utils = require('./utils/utils');
17+
18+
module.exports = {
19+
meta: {
20+
docs: {
21+
url: 'https://github.com/Gillespie59/eslint-plugin-angular/blob/master/docs/rules/module-configuration-file.md'
22+
},
23+
schema: []
24+
},
25+
create: function(context) {
26+
return {
27+
CallExpression: function(node) {
28+
// Check if this is a .config() call on an Angular module
29+
if (!utils.isMemberExpression(node.callee)) {
30+
return;
31+
}
32+
33+
if (node.callee.property.name !== 'config') {
34+
return;
35+
}
36+
37+
// Check if this is called on an angular.module() getter
38+
var callee = node.callee.object;
39+
if (!utils.isAngularModuleGetter(callee) && !utils.isMemberExpression(callee)) {
40+
return;
41+
}
42+
43+
// Get the filename
44+
var filename = path.basename(context.getFilename());
45+
46+
// Skip if this is a test file
47+
if (filename.indexOf('.spec.') !== -1 || filename.indexOf('.test.') !== -1) {
48+
return;
49+
}
50+
51+
// Check if the filename follows the .config.js pattern
52+
if (!filename.endsWith('.config.js')) {
53+
context.report(node, 'Module configuration should be in a separate file with a .config.js suffix');
54+
}
55+
}
56+
};
57+
}
58+
};

test/module-configuration-file.js

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
'use strict';
2+
3+
// ------------------------------------------------------------------------------
4+
// Requirements
5+
// ------------------------------------------------------------------------------
6+
7+
var rule = require('../rules/module-configuration-file');
8+
var RuleTester = require('eslint').RuleTester;
9+
var commonFalsePositives = require('./utils/commonFalsePositives');
10+
11+
// ------------------------------------------------------------------------------
12+
// Tests
13+
// ------------------------------------------------------------------------------
14+
15+
var eslintTester = new RuleTester();
16+
eslintTester.run('module-configuration-file', rule, {
17+
valid: [
18+
{
19+
// config in a .config.js file
20+
filename: 'app.config.js',
21+
code: 'angular.module("app").config(function() {});'
22+
},
23+
{
24+
// config in a .config.js file with module getter
25+
filename: 'admin.config.js',
26+
code: 'angular.module("admin").config(function($httpProvider) { $httpProvider.interceptors.push("authInterceptor"); });'
27+
},
28+
{
29+
// simple config.js filename
30+
filename: 'config.js',
31+
code: 'angular.module("app").config(function() {});'
32+
},
33+
{
34+
// config in a subdirectory
35+
filename: 'src/app/modules/admin.config.js',
36+
code: 'angular.module("admin").config(function() {});'
37+
},
38+
{
39+
// module declaration without config
40+
filename: 'app.module.js',
41+
code: 'angular.module("app", []);'
42+
},
43+
{
44+
// controller in non-config file
45+
filename: 'home.controller.js',
46+
code: 'angular.module("app").controller("HomeController", function() {});'
47+
},
48+
{
49+
// service in non-config file
50+
filename: 'user.service.js',
51+
code: 'angular.module("app").factory("userService", function() {});'
52+
},
53+
{
54+
// test file should be ignored
55+
filename: 'app.spec.js',
56+
code: 'angular.module("app").config(function() {});'
57+
},
58+
{
59+
// test file should be ignored
60+
filename: 'app.test.js',
61+
code: 'angular.module("app").config(function() {});'
62+
}
63+
].concat(commonFalsePositives),
64+
invalid: [
65+
{
66+
filename: 'app.js',
67+
code: 'angular.module("app").config(function() {});',
68+
errors: [{
69+
message: 'Module configuration should be in a separate file with a .config.js suffix'
70+
}]
71+
},
72+
{
73+
filename: 'app.module.js',
74+
code: 'angular.module("app").config(function($httpProvider) { $httpProvider.interceptors.push("authInterceptor"); });',
75+
errors: [{
76+
message: 'Module configuration should be in a separate file with a .config.js suffix'
77+
}]
78+
},
79+
{
80+
filename: 'admin.js',
81+
code: 'angular.module("admin").config(function() {});',
82+
errors: [{
83+
message: 'Module configuration should be in a separate file with a .config.js suffix'
84+
}]
85+
},
86+
{
87+
filename: 'src/app/admin.module.js',
88+
code: 'angular.module("admin").config(configFunction);',
89+
errors: [{
90+
message: 'Module configuration should be in a separate file with a .config.js suffix'
91+
}]
92+
}
93+
]
94+
});

0 commit comments

Comments
 (0)