UNPKG

4.24 kBJavaScriptView Raw
1/**
2 * @fileoverview Restrict usage of duplicate imports.
3 * @author Simen Bekkhus
4 */
5"use strict";
6
7//------------------------------------------------------------------------------
8// Rule Definition
9//------------------------------------------------------------------------------
10
11/**
12 * Returns the name of the module imported or re-exported.
13 *
14 * @param {ASTNode} node - A node to get.
15 * @returns {string} the name of the module, or empty string if no name.
16 */
17function getValue(node) {
18 if (node && node.source && node.source.value) {
19 return node.source.value.trim();
20 }
21
22 return "";
23}
24
25/**
26 * Checks if the name of the import or export exists in the given array, and reports if so.
27 *
28 * @param {RuleContext} context - The ESLint rule context object.
29 * @param {ASTNode} node - A node to get.
30 * @param {string} value - The name of the imported or exported module.
31 * @param {string[]} array - The array containing other imports or exports in the file.
32 * @param {string} message - A message to be reported after the name of the module
33 *
34 * @returns {void} No return value
35 */
36function checkAndReport(context, node, value, array, message) {
37 if (array.indexOf(value) !== -1) {
38 context.report({
39 node,
40 message: "'{{module}}' {{message}}",
41 data: {
42 module: value,
43 message
44 }
45 });
46 }
47}
48
49/**
50 * @callback nodeCallback
51 * @param {ASTNode} node - A node to handle.
52 */
53
54/**
55 * Returns a function handling the imports of a given file
56 *
57 * @param {RuleContext} context - The ESLint rule context object.
58 * @param {boolean} includeExports - Whether or not to check for exports in addition to imports.
59 * @param {string[]} importsInFile - The array containing other imports in the file.
60 * @param {string[]} exportsInFile - The array containing other exports in the file.
61 *
62 * @returns {nodeCallback} A function passed to ESLint to handle the statement.
63 */
64function handleImports(context, includeExports, importsInFile, exportsInFile) {
65 return function(node) {
66 const value = getValue(node);
67
68 if (value) {
69 checkAndReport(context, node, value, importsInFile, "import is duplicated.");
70
71 if (includeExports) {
72 checkAndReport(context, node, value, exportsInFile, "import is duplicated as export.");
73 }
74
75 importsInFile.push(value);
76 }
77 };
78}
79
80/**
81 * Returns a function handling the exports of a given file
82 *
83 * @param {RuleContext} context - The ESLint rule context object.
84 * @param {string[]} importsInFile - The array containing other imports in the file.
85 * @param {string[]} exportsInFile - The array containing other exports in the file.
86 *
87 * @returns {nodeCallback} A function passed to ESLint to handle the statement.
88 */
89function handleExports(context, importsInFile, exportsInFile) {
90 return function(node) {
91 const value = getValue(node);
92
93 if (value) {
94 checkAndReport(context, node, value, exportsInFile, "export is duplicated.");
95 checkAndReport(context, node, value, importsInFile, "export is duplicated as import.");
96
97 exportsInFile.push(value);
98 }
99 };
100}
101
102module.exports = {
103 meta: {
104 docs: {
105 description: "disallow duplicate module imports",
106 category: "ECMAScript 6",
107 recommended: false
108 },
109
110 schema: [{
111 type: "object",
112 properties: {
113 includeExports: {
114 type: "boolean"
115 }
116 },
117 additionalProperties: false
118 }]
119 },
120
121 create(context) {
122 const includeExports = (context.options[0] || {}).includeExports,
123 importsInFile = [],
124 exportsInFile = [];
125
126 const handlers = {
127 ImportDeclaration: handleImports(context, includeExports, importsInFile, exportsInFile)
128 };
129
130 if (includeExports) {
131 handlers.ExportNamedDeclaration = handleExports(context, importsInFile, exportsInFile);
132 handlers.ExportAllDeclaration = handleExports(context, importsInFile, exportsInFile);
133 }
134
135 return handlers;
136 }
137};