Skip to content

Commit a73fb83

Browse files
committed
Breaking: Support ESM rules
1 parent 30bb8e2 commit a73fb83

File tree

4 files changed

+89
-2
lines changed

4 files changed

+89
-2
lines changed

lib/utils.js

+16-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,20 @@ module.exports = {
9898
let exportsVarOverridden = false;
9999
let exportsIsFunction = false;
100100

101-
const exportNodes = ast.body
101+
// ESM
102+
const exportDefaultDeclaration = ast.body.find(statement => statement.type === 'ExportDefaultDeclaration');
103+
const exportNodesESM = exportDefaultDeclaration && exportDefaultDeclaration.declaration.type === 'ObjectExpression' ?
104+
exportDefaultDeclaration.declaration.properties.reduce((parsedProps, prop) => {
105+
const keyValue = module.exports.getKeyName(prop);
106+
if (INTERESTING_KEYS.has(keyValue)) {
107+
parsedProps[keyValue] = prop.value;
108+
}
109+
return parsedProps;
110+
}, {}) :
111+
undefined;
112+
113+
// CJS
114+
const exportNodesCJS = ast.body
102115
.filter(statement => statement.type === 'ExpressionStatement')
103116
.map(statement => statement.expression)
104117
.filter(expression => expression.type === 'AssignmentExpression')
@@ -150,6 +163,8 @@ module.exports = {
150163
return currentExports;
151164
}, {});
152165

166+
const exportNodes = exportNodesESM || exportNodesCJS;
167+
153168
const createExists = Object.prototype.hasOwnProperty.call(exportNodes, 'create');
154169
if (!createExists) {
155170
return null;

tests/lib/rules/prefer-message-ids.js

+23
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,17 @@ ruleTester.run('prefer-message-ids', rule, {
2929
}
3030
};
3131
`,
32+
{
33+
// ESM
34+
code: `
35+
export default {
36+
create(context) {
37+
context.report({ node, messageId: 'foo' });
38+
}
39+
};
40+
`,
41+
parserOptions: { sourceType: 'module' },
42+
},
3243
`
3344
module.exports = {
3445
create(context) {
@@ -91,6 +102,18 @@ ruleTester.run('prefer-message-ids', rule, {
91102
`,
92103
errors: [{ messageId: 'foundMessage', type: 'Property' }],
93104
},
105+
{
106+
// ESM
107+
code: `
108+
export default {
109+
create(context) {
110+
context.report({ node, message: 'foo' });
111+
}
112+
};
113+
`,
114+
parserOptions: { sourceType: 'module' },
115+
errors: [{ messageId: 'foundMessage', type: 'Property' }],
116+
},
94117
{
95118
// With message in variable.
96119
code: `

tests/lib/rules/require-meta-docs-description.js

+22
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,16 @@ ruleTester.run('require-meta-docs-description', rule, {
2121
create(context) {}
2222
};
2323
`,
24+
{
25+
// ESM
26+
code: `
27+
export default {
28+
meta: { docs: { description: 'disallow unused variables' } },
29+
create(context) {}
30+
};
31+
`,
32+
parserOptions: { sourceType: 'module' },
33+
},
2434
`
2535
module.exports = {
2636
meta: { docs: { description: 'enforce a maximum line length' } },
@@ -104,6 +114,18 @@ ruleTester.run('require-meta-docs-description', rule, {
104114
output: null,
105115
errors: [{ messageId: 'missing', type: 'ObjectExpression' }],
106116
},
117+
{
118+
// ESM
119+
code: `
120+
export default {
121+
meta: {},
122+
create(context) {}
123+
};
124+
`,
125+
output: null,
126+
parserOptions: { sourceType: 'module' },
127+
errors: [{ messageId: 'missing', type: 'ObjectExpression' }],
128+
},
107129
{
108130
code: `
109131
module.exports = {

tests/lib/utils.js

+28-1
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,23 @@ describe('utils', () => {
3333
});
3434
});
3535

36+
describe('the file does not have a valid rule (ESM)', () => {
37+
[
38+
'',
39+
'export const foo = { create() {} }',
40+
'export default { foo: {} }',
41+
'const foo = {}; export default foo',
42+
].forEach(noRuleCase => {
43+
it(`returns null for ${noRuleCase}`, () => {
44+
const ast = espree.parse(noRuleCase, { ecmaVersion: 8, range: true, sourceType: 'module' });
45+
assert.isNull(utils.getRuleInfo({ ast }), 'Expected no rule to be found');
46+
});
47+
});
48+
});
49+
3650
describe('the file has a valid rule', () => {
3751
const CASES = {
52+
// CJS
3853
'module.exports = { create: function foo() {} };': {
3954
create: { type: 'FunctionExpression', id: { name: 'foo' } }, // (This property will actually contain the AST node.)
4055
meta: null,
@@ -110,11 +125,23 @@ describe('utils', () => {
110125
meta: null,
111126
isNewStyle: false,
112127
},
128+
129+
// ESM
130+
'export default { create() {} }': {
131+
create: { type: 'FunctionExpression' },
132+
meta: null,
133+
isNewStyle: true,
134+
},
135+
'export default { create() {}, meta: {} }': {
136+
create: { type: 'FunctionExpression' },
137+
meta: { type: 'ObjectExpression' },
138+
isNewStyle: true,
139+
},
113140
};
114141

115142
Object.keys(CASES).forEach(ruleSource => {
116143
it(ruleSource, () => {
117-
const ast = espree.parse(ruleSource, { ecmaVersion: 6, range: true });
144+
const ast = espree.parse(ruleSource, { ecmaVersion: 6, range: true, sourceType: ruleSource.includes('export default') ? 'module' : 'script' });
118145
const ruleInfo = utils.getRuleInfo({ ast });
119146
assert(
120147
lodash.isMatch(ruleInfo, CASES[ruleSource]),

0 commit comments

Comments
 (0)