@atlaskit/eslint-plugin-platform 2.9.3 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @atlaskit/eslint-plugin-platform
2
2
 
3
+ ## 2.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ - [`ed426d1a0955c`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/ed426d1a0955c) -
8
+ Add `one-value-export-per-file` ESLint rule for reporting files with multiple local value exports.
9
+
3
10
  ## 2.9.3
4
11
 
5
12
  ### Patch Changes
package/dist/cjs/index.js CHANGED
@@ -45,6 +45,7 @@ var _noBarrelEntryJestMock = _interopRequireDefault(require("./rules/import/no-b
45
45
  var _noJestMockBarrelFiles = _interopRequireDefault(require("./rules/import/no-jest-mock-barrel-files"));
46
46
  var _noRelativeBarrelFileImports = _interopRequireDefault(require("./rules/import/no-relative-barrel-file-imports"));
47
47
  var _noConversationAssistantBarrelImports = _interopRequireDefault(require("./rules/import/no-conversation-assistant-barrel-imports"));
48
+ var _oneValueExportPerFile = _interopRequireDefault(require("./rules/import/one-value-export-per-file"));
48
49
  var _visitExampleTypeImportRequired = _interopRequireDefault(require("./rules/visit-example-type-import-required"));
49
50
  var _editorExampleTypeImportRequired = _interopRequireDefault(require("./rules/editor-example-type-import-required"));
50
51
  var _ensureUseSyncExternalStoreServerSnapshot = _interopRequireDefault(require("./rules/ensure-use-sync-external-store-server-snapshot"));
@@ -107,6 +108,7 @@ var rules = exports.rules = {
107
108
  'no-jest-mock-barrel-files': _noJestMockBarrelFiles.default,
108
109
  'no-relative-barrel-file-imports': _noRelativeBarrelFileImports.default,
109
110
  'no-conversation-assistant-barrel-imports': _noConversationAssistantBarrelImports.default,
111
+ 'one-value-export-per-file': _oneValueExportPerFile.default,
110
112
  'visit-example-type-import-required': _visitExampleTypeImportRequired.default,
111
113
  'no-xcss-in-cx': _noXcssInCx.default,
112
114
  'editor-example-type-import-required': _editorExampleTypeImportRequired.default,
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.default = void 0;
8
+ var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
9
+ function getPropertyName(node) {
10
+ if (!node) {
11
+ return null;
12
+ }
13
+ if (node.type === 'Identifier') {
14
+ return node.name;
15
+ }
16
+ if (node.type === 'Literal') {
17
+ return String(node.value);
18
+ }
19
+ return null;
20
+ }
21
+ function isPrimitiveLiteral(declarator) {
22
+ function isPrimitiveExpression(node) {
23
+ if (!node) {
24
+ return false;
25
+ }
26
+ switch (node.type) {
27
+ case 'Literal':
28
+ return typeof node.value === 'string' || typeof node.value === 'number' || typeof node.value === 'boolean' || node.value === null;
29
+ case 'TemplateLiteral':
30
+ return node.expressions.length === 0;
31
+ case 'Identifier':
32
+ return node.name === 'undefined';
33
+ case 'UnaryExpression':
34
+ return ['+', '-', '~', '!'].includes(node.operator) && isPrimitiveExpression(node.argument);
35
+ case 'BinaryExpression':
36
+ return isPrimitiveExpression(node.left) && isPrimitiveExpression(node.right);
37
+ case 'TSAsExpression':
38
+ case 'TSTypeAssertion':
39
+ case 'TSNonNullExpression':
40
+ return isPrimitiveExpression(node.expression);
41
+ default:
42
+ return false;
43
+ }
44
+ }
45
+ return isPrimitiveExpression(declarator.init);
46
+ }
47
+ function collectBindingExports(node) {
48
+ if (!node) {
49
+ return [];
50
+ }
51
+ switch (node.type) {
52
+ case 'Identifier':
53
+ return [{
54
+ name: node.name,
55
+ loc: node.loc
56
+ }];
57
+ case 'ObjectPattern':
58
+ return node.properties.flatMap(function (property) {
59
+ if (property.type === 'RestElement') {
60
+ return collectBindingExports(property.argument);
61
+ }
62
+ return collectBindingExports(property.value);
63
+ });
64
+ case 'ArrayPattern':
65
+ return node.elements.flatMap(function (element) {
66
+ return collectBindingExports(element);
67
+ });
68
+ case 'AssignmentPattern':
69
+ return collectBindingExports(node.left);
70
+ case 'RestElement':
71
+ return collectBindingExports(node.argument);
72
+ default:
73
+ return [];
74
+ }
75
+ }
76
+ function getDefaultExportName(node) {
77
+ var declaration = node.declaration;
78
+ if ((declaration.type === 'FunctionDeclaration' || declaration.type === 'ClassDeclaration') && declaration.id) {
79
+ return declaration.id.name;
80
+ }
81
+ return 'default';
82
+ }
83
+ function getDefaultExportLoc(node) {
84
+ var declaration = node.declaration;
85
+ if ((declaration.type === 'FunctionDeclaration' || declaration.type === 'ClassDeclaration') && declaration.id) {
86
+ return declaration.id.loc;
87
+ }
88
+ return node.loc;
89
+ }
90
+ function collectDeclarationExports(declaration, allowPrimitiveExports) {
91
+ if (!declaration) {
92
+ return [];
93
+ }
94
+ switch (declaration.type) {
95
+ case 'VariableDeclaration':
96
+ return declaration.declarations.flatMap(function (declarator) {
97
+ if (allowPrimitiveExports && isPrimitiveLiteral(declarator)) {
98
+ return [];
99
+ }
100
+ return collectBindingExports(declarator.id);
101
+ });
102
+ case 'FunctionDeclaration':
103
+ case 'ClassDeclaration':
104
+ return declaration.id ? [{
105
+ name: declaration.id.name,
106
+ loc: declaration.id.loc
107
+ }] : [];
108
+ case 'TSEnumDeclaration':
109
+ return [{
110
+ name: declaration.id.name,
111
+ loc: declaration.id.loc
112
+ }];
113
+ case 'TSInterfaceDeclaration':
114
+ case 'TSTypeAliasDeclaration':
115
+ return [];
116
+ default:
117
+ return [];
118
+ }
119
+ }
120
+ function collectNamedSpecifierExports(node) {
121
+ if (node.exportKind === 'type') {
122
+ return [];
123
+ }
124
+ return node.specifiers.flatMap(function (specifier) {
125
+ if (specifier.type !== 'ExportSpecifier' || specifier.exportKind === 'type') {
126
+ return [];
127
+ }
128
+ var exportedName = getPropertyName(specifier.exported);
129
+ return exportedName ? [{
130
+ name: exportedName,
131
+ loc: specifier.exported.loc
132
+ }] : [];
133
+ });
134
+ }
135
+ var rule = {
136
+ meta: {
137
+ type: 'suggestion',
138
+ docs: {
139
+ description: 'Disallow more than one local value export per file.',
140
+ category: 'Best Practices',
141
+ recommended: false
142
+ },
143
+ schema: [{
144
+ type: 'object',
145
+ properties: {
146
+ allowPrimitiveExports: {
147
+ type: 'boolean',
148
+ description: 'When true, primitive value exports (strings, numbers, booleans, null, undefined, and template literals) are ignored when counting local value exports.'
149
+ }
150
+ },
151
+ additionalProperties: false
152
+ }],
153
+ messages: {
154
+ multipleValueExports: 'This file exports {{count}} local values ({{names}}). Keep one value export per file https://hello.atlassian.net/wiki/spaces/DevInfra/pages/6809881812/One+Export+Per+File'
155
+ }
156
+ },
157
+ create: function create(context) {
158
+ var _, _options$allowPrimiti;
159
+ var options = (_ = context.options[0]) !== null && _ !== void 0 ? _ : {};
160
+ var allowPrimitiveExports = (_options$allowPrimiti = options.allowPrimitiveExports) !== null && _options$allowPrimiti !== void 0 ? _options$allowPrimiti : false;
161
+ var valueExports = [];
162
+ return {
163
+ ExportDefaultDeclaration: function ExportDefaultDeclaration(node) {
164
+ var exportNode = node;
165
+ valueExports.push({
166
+ name: getDefaultExportName(exportNode),
167
+ loc: getDefaultExportLoc(exportNode)
168
+ });
169
+ },
170
+ ExportNamedDeclaration: function ExportNamedDeclaration(node) {
171
+ var exportNode = node;
172
+
173
+ // Re-export-only barrel syntax is intentionally ignored.
174
+ if (exportNode.source) {
175
+ return;
176
+ }
177
+ valueExports.push.apply(valueExports, (0, _toConsumableArray2.default)(collectDeclarationExports(exportNode.declaration, allowPrimitiveExports)));
178
+ valueExports.push.apply(valueExports, (0, _toConsumableArray2.default)(collectNamedSpecifierExports(exportNode)));
179
+ },
180
+ 'Program:exit': function ProgramExit(node) {
181
+ if (valueExports.length <= 1) {
182
+ return;
183
+ }
184
+ var sampleNames = valueExports.slice(0, 5).map(function (valueExport) {
185
+ return valueExport.name;
186
+ }).join(', ');
187
+ var names = valueExports.length > 5 ? "".concat(sampleNames, ", and ").concat(valueExports.length - 5, " more") : sampleNames;
188
+ valueExports.forEach(function (valueExport) {
189
+ context.report({
190
+ node: node,
191
+ loc: valueExport.loc,
192
+ messageId: 'multipleValueExports',
193
+ data: {
194
+ count: String(valueExports.length),
195
+ names: names
196
+ }
197
+ });
198
+ });
199
+ }
200
+ };
201
+ }
202
+ };
203
+ var _default = exports.default = rule;
@@ -38,6 +38,7 @@ import noBarrelEntryJestMock from './rules/import/no-barrel-entry-jest-mock';
38
38
  import noJestMockBarrelFiles from './rules/import/no-jest-mock-barrel-files';
39
39
  import noRelativeBarrelFileImports from './rules/import/no-relative-barrel-file-imports';
40
40
  import noConversationAssistantBarrelImports from './rules/import/no-conversation-assistant-barrel-imports';
41
+ import oneValueExportPerFile from './rules/import/one-value-export-per-file';
41
42
  import visitExampleTypeImportRequired from './rules/visit-example-type-import-required';
42
43
  import editorExampleTypeImportRequired from './rules/editor-example-type-import-required';
43
44
  import ensureUseSyncExternalStoreServerSnapshot from './rules/ensure-use-sync-external-store-server-snapshot';
@@ -98,6 +99,7 @@ const rules = {
98
99
  'no-jest-mock-barrel-files': noJestMockBarrelFiles,
99
100
  'no-relative-barrel-file-imports': noRelativeBarrelFileImports,
100
101
  'no-conversation-assistant-barrel-imports': noConversationAssistantBarrelImports,
102
+ 'one-value-export-per-file': oneValueExportPerFile,
101
103
  'visit-example-type-import-required': visitExampleTypeImportRequired,
102
104
  'no-xcss-in-cx': noXcssInCx,
103
105
  'editor-example-type-import-required': editorExampleTypeImportRequired,
@@ -0,0 +1,191 @@
1
+ function getPropertyName(node) {
2
+ if (!node) {
3
+ return null;
4
+ }
5
+ if (node.type === 'Identifier') {
6
+ return node.name;
7
+ }
8
+ if (node.type === 'Literal') {
9
+ return String(node.value);
10
+ }
11
+ return null;
12
+ }
13
+ function isPrimitiveLiteral(declarator) {
14
+ function isPrimitiveExpression(node) {
15
+ if (!node) {
16
+ return false;
17
+ }
18
+ switch (node.type) {
19
+ case 'Literal':
20
+ return typeof node.value === 'string' || typeof node.value === 'number' || typeof node.value === 'boolean' || node.value === null;
21
+ case 'TemplateLiteral':
22
+ return node.expressions.length === 0;
23
+ case 'Identifier':
24
+ return node.name === 'undefined';
25
+ case 'UnaryExpression':
26
+ return ['+', '-', '~', '!'].includes(node.operator) && isPrimitiveExpression(node.argument);
27
+ case 'BinaryExpression':
28
+ return isPrimitiveExpression(node.left) && isPrimitiveExpression(node.right);
29
+ case 'TSAsExpression':
30
+ case 'TSTypeAssertion':
31
+ case 'TSNonNullExpression':
32
+ return isPrimitiveExpression(node.expression);
33
+ default:
34
+ return false;
35
+ }
36
+ }
37
+ return isPrimitiveExpression(declarator.init);
38
+ }
39
+ function collectBindingExports(node) {
40
+ if (!node) {
41
+ return [];
42
+ }
43
+ switch (node.type) {
44
+ case 'Identifier':
45
+ return [{
46
+ name: node.name,
47
+ loc: node.loc
48
+ }];
49
+ case 'ObjectPattern':
50
+ return node.properties.flatMap(property => {
51
+ if (property.type === 'RestElement') {
52
+ return collectBindingExports(property.argument);
53
+ }
54
+ return collectBindingExports(property.value);
55
+ });
56
+ case 'ArrayPattern':
57
+ return node.elements.flatMap(element => collectBindingExports(element));
58
+ case 'AssignmentPattern':
59
+ return collectBindingExports(node.left);
60
+ case 'RestElement':
61
+ return collectBindingExports(node.argument);
62
+ default:
63
+ return [];
64
+ }
65
+ }
66
+ function getDefaultExportName(node) {
67
+ const declaration = node.declaration;
68
+ if ((declaration.type === 'FunctionDeclaration' || declaration.type === 'ClassDeclaration') && declaration.id) {
69
+ return declaration.id.name;
70
+ }
71
+ return 'default';
72
+ }
73
+ function getDefaultExportLoc(node) {
74
+ const declaration = node.declaration;
75
+ if ((declaration.type === 'FunctionDeclaration' || declaration.type === 'ClassDeclaration') && declaration.id) {
76
+ return declaration.id.loc;
77
+ }
78
+ return node.loc;
79
+ }
80
+ function collectDeclarationExports(declaration, allowPrimitiveExports) {
81
+ if (!declaration) {
82
+ return [];
83
+ }
84
+ switch (declaration.type) {
85
+ case 'VariableDeclaration':
86
+ return declaration.declarations.flatMap(declarator => {
87
+ if (allowPrimitiveExports && isPrimitiveLiteral(declarator)) {
88
+ return [];
89
+ }
90
+ return collectBindingExports(declarator.id);
91
+ });
92
+ case 'FunctionDeclaration':
93
+ case 'ClassDeclaration':
94
+ return declaration.id ? [{
95
+ name: declaration.id.name,
96
+ loc: declaration.id.loc
97
+ }] : [];
98
+ case 'TSEnumDeclaration':
99
+ return [{
100
+ name: declaration.id.name,
101
+ loc: declaration.id.loc
102
+ }];
103
+ case 'TSInterfaceDeclaration':
104
+ case 'TSTypeAliasDeclaration':
105
+ return [];
106
+ default:
107
+ return [];
108
+ }
109
+ }
110
+ function collectNamedSpecifierExports(node) {
111
+ if (node.exportKind === 'type') {
112
+ return [];
113
+ }
114
+ return node.specifiers.flatMap(specifier => {
115
+ if (specifier.type !== 'ExportSpecifier' || specifier.exportKind === 'type') {
116
+ return [];
117
+ }
118
+ const exportedName = getPropertyName(specifier.exported);
119
+ return exportedName ? [{
120
+ name: exportedName,
121
+ loc: specifier.exported.loc
122
+ }] : [];
123
+ });
124
+ }
125
+ const rule = {
126
+ meta: {
127
+ type: 'suggestion',
128
+ docs: {
129
+ description: 'Disallow more than one local value export per file.',
130
+ category: 'Best Practices',
131
+ recommended: false
132
+ },
133
+ schema: [{
134
+ type: 'object',
135
+ properties: {
136
+ allowPrimitiveExports: {
137
+ type: 'boolean',
138
+ description: 'When true, primitive value exports (strings, numbers, booleans, null, undefined, and template literals) are ignored when counting local value exports.'
139
+ }
140
+ },
141
+ additionalProperties: false
142
+ }],
143
+ messages: {
144
+ multipleValueExports: 'This file exports {{count}} local values ({{names}}). Keep one value export per file https://hello.atlassian.net/wiki/spaces/DevInfra/pages/6809881812/One+Export+Per+File'
145
+ }
146
+ },
147
+ create(context) {
148
+ var _, _options$allowPrimiti;
149
+ const options = (_ = context.options[0]) !== null && _ !== void 0 ? _ : {};
150
+ const allowPrimitiveExports = (_options$allowPrimiti = options.allowPrimitiveExports) !== null && _options$allowPrimiti !== void 0 ? _options$allowPrimiti : false;
151
+ const valueExports = [];
152
+ return {
153
+ ExportDefaultDeclaration(node) {
154
+ const exportNode = node;
155
+ valueExports.push({
156
+ name: getDefaultExportName(exportNode),
157
+ loc: getDefaultExportLoc(exportNode)
158
+ });
159
+ },
160
+ ExportNamedDeclaration(node) {
161
+ const exportNode = node;
162
+
163
+ // Re-export-only barrel syntax is intentionally ignored.
164
+ if (exportNode.source) {
165
+ return;
166
+ }
167
+ valueExports.push(...collectDeclarationExports(exportNode.declaration, allowPrimitiveExports));
168
+ valueExports.push(...collectNamedSpecifierExports(exportNode));
169
+ },
170
+ 'Program:exit'(node) {
171
+ if (valueExports.length <= 1) {
172
+ return;
173
+ }
174
+ const sampleNames = valueExports.slice(0, 5).map(valueExport => valueExport.name).join(', ');
175
+ const names = valueExports.length > 5 ? `${sampleNames}, and ${valueExports.length - 5} more` : sampleNames;
176
+ valueExports.forEach(valueExport => {
177
+ context.report({
178
+ node,
179
+ loc: valueExport.loc,
180
+ messageId: 'multipleValueExports',
181
+ data: {
182
+ count: String(valueExports.length),
183
+ names
184
+ }
185
+ });
186
+ });
187
+ }
188
+ };
189
+ }
190
+ };
191
+ export default rule;
package/dist/esm/index.js CHANGED
@@ -41,6 +41,7 @@ import noBarrelEntryJestMock from './rules/import/no-barrel-entry-jest-mock';
41
41
  import noJestMockBarrelFiles from './rules/import/no-jest-mock-barrel-files';
42
42
  import noRelativeBarrelFileImports from './rules/import/no-relative-barrel-file-imports';
43
43
  import noConversationAssistantBarrelImports from './rules/import/no-conversation-assistant-barrel-imports';
44
+ import oneValueExportPerFile from './rules/import/one-value-export-per-file';
44
45
  import visitExampleTypeImportRequired from './rules/visit-example-type-import-required';
45
46
  import editorExampleTypeImportRequired from './rules/editor-example-type-import-required';
46
47
  import ensureUseSyncExternalStoreServerSnapshot from './rules/ensure-use-sync-external-store-server-snapshot';
@@ -101,6 +102,7 @@ var rules = {
101
102
  'no-jest-mock-barrel-files': noJestMockBarrelFiles,
102
103
  'no-relative-barrel-file-imports': noRelativeBarrelFileImports,
103
104
  'no-conversation-assistant-barrel-imports': noConversationAssistantBarrelImports,
105
+ 'one-value-export-per-file': oneValueExportPerFile,
104
106
  'visit-example-type-import-required': visitExampleTypeImportRequired,
105
107
  'no-xcss-in-cx': noXcssInCx,
106
108
  'editor-example-type-import-required': editorExampleTypeImportRequired,
@@ -0,0 +1,196 @@
1
+ import _toConsumableArray from "@babel/runtime/helpers/toConsumableArray";
2
+ function getPropertyName(node) {
3
+ if (!node) {
4
+ return null;
5
+ }
6
+ if (node.type === 'Identifier') {
7
+ return node.name;
8
+ }
9
+ if (node.type === 'Literal') {
10
+ return String(node.value);
11
+ }
12
+ return null;
13
+ }
14
+ function isPrimitiveLiteral(declarator) {
15
+ function isPrimitiveExpression(node) {
16
+ if (!node) {
17
+ return false;
18
+ }
19
+ switch (node.type) {
20
+ case 'Literal':
21
+ return typeof node.value === 'string' || typeof node.value === 'number' || typeof node.value === 'boolean' || node.value === null;
22
+ case 'TemplateLiteral':
23
+ return node.expressions.length === 0;
24
+ case 'Identifier':
25
+ return node.name === 'undefined';
26
+ case 'UnaryExpression':
27
+ return ['+', '-', '~', '!'].includes(node.operator) && isPrimitiveExpression(node.argument);
28
+ case 'BinaryExpression':
29
+ return isPrimitiveExpression(node.left) && isPrimitiveExpression(node.right);
30
+ case 'TSAsExpression':
31
+ case 'TSTypeAssertion':
32
+ case 'TSNonNullExpression':
33
+ return isPrimitiveExpression(node.expression);
34
+ default:
35
+ return false;
36
+ }
37
+ }
38
+ return isPrimitiveExpression(declarator.init);
39
+ }
40
+ function collectBindingExports(node) {
41
+ if (!node) {
42
+ return [];
43
+ }
44
+ switch (node.type) {
45
+ case 'Identifier':
46
+ return [{
47
+ name: node.name,
48
+ loc: node.loc
49
+ }];
50
+ case 'ObjectPattern':
51
+ return node.properties.flatMap(function (property) {
52
+ if (property.type === 'RestElement') {
53
+ return collectBindingExports(property.argument);
54
+ }
55
+ return collectBindingExports(property.value);
56
+ });
57
+ case 'ArrayPattern':
58
+ return node.elements.flatMap(function (element) {
59
+ return collectBindingExports(element);
60
+ });
61
+ case 'AssignmentPattern':
62
+ return collectBindingExports(node.left);
63
+ case 'RestElement':
64
+ return collectBindingExports(node.argument);
65
+ default:
66
+ return [];
67
+ }
68
+ }
69
+ function getDefaultExportName(node) {
70
+ var declaration = node.declaration;
71
+ if ((declaration.type === 'FunctionDeclaration' || declaration.type === 'ClassDeclaration') && declaration.id) {
72
+ return declaration.id.name;
73
+ }
74
+ return 'default';
75
+ }
76
+ function getDefaultExportLoc(node) {
77
+ var declaration = node.declaration;
78
+ if ((declaration.type === 'FunctionDeclaration' || declaration.type === 'ClassDeclaration') && declaration.id) {
79
+ return declaration.id.loc;
80
+ }
81
+ return node.loc;
82
+ }
83
+ function collectDeclarationExports(declaration, allowPrimitiveExports) {
84
+ if (!declaration) {
85
+ return [];
86
+ }
87
+ switch (declaration.type) {
88
+ case 'VariableDeclaration':
89
+ return declaration.declarations.flatMap(function (declarator) {
90
+ if (allowPrimitiveExports && isPrimitiveLiteral(declarator)) {
91
+ return [];
92
+ }
93
+ return collectBindingExports(declarator.id);
94
+ });
95
+ case 'FunctionDeclaration':
96
+ case 'ClassDeclaration':
97
+ return declaration.id ? [{
98
+ name: declaration.id.name,
99
+ loc: declaration.id.loc
100
+ }] : [];
101
+ case 'TSEnumDeclaration':
102
+ return [{
103
+ name: declaration.id.name,
104
+ loc: declaration.id.loc
105
+ }];
106
+ case 'TSInterfaceDeclaration':
107
+ case 'TSTypeAliasDeclaration':
108
+ return [];
109
+ default:
110
+ return [];
111
+ }
112
+ }
113
+ function collectNamedSpecifierExports(node) {
114
+ if (node.exportKind === 'type') {
115
+ return [];
116
+ }
117
+ return node.specifiers.flatMap(function (specifier) {
118
+ if (specifier.type !== 'ExportSpecifier' || specifier.exportKind === 'type') {
119
+ return [];
120
+ }
121
+ var exportedName = getPropertyName(specifier.exported);
122
+ return exportedName ? [{
123
+ name: exportedName,
124
+ loc: specifier.exported.loc
125
+ }] : [];
126
+ });
127
+ }
128
+ var rule = {
129
+ meta: {
130
+ type: 'suggestion',
131
+ docs: {
132
+ description: 'Disallow more than one local value export per file.',
133
+ category: 'Best Practices',
134
+ recommended: false
135
+ },
136
+ schema: [{
137
+ type: 'object',
138
+ properties: {
139
+ allowPrimitiveExports: {
140
+ type: 'boolean',
141
+ description: 'When true, primitive value exports (strings, numbers, booleans, null, undefined, and template literals) are ignored when counting local value exports.'
142
+ }
143
+ },
144
+ additionalProperties: false
145
+ }],
146
+ messages: {
147
+ multipleValueExports: 'This file exports {{count}} local values ({{names}}). Keep one value export per file https://hello.atlassian.net/wiki/spaces/DevInfra/pages/6809881812/One+Export+Per+File'
148
+ }
149
+ },
150
+ create: function create(context) {
151
+ var _, _options$allowPrimiti;
152
+ var options = (_ = context.options[0]) !== null && _ !== void 0 ? _ : {};
153
+ var allowPrimitiveExports = (_options$allowPrimiti = options.allowPrimitiveExports) !== null && _options$allowPrimiti !== void 0 ? _options$allowPrimiti : false;
154
+ var valueExports = [];
155
+ return {
156
+ ExportDefaultDeclaration: function ExportDefaultDeclaration(node) {
157
+ var exportNode = node;
158
+ valueExports.push({
159
+ name: getDefaultExportName(exportNode),
160
+ loc: getDefaultExportLoc(exportNode)
161
+ });
162
+ },
163
+ ExportNamedDeclaration: function ExportNamedDeclaration(node) {
164
+ var exportNode = node;
165
+
166
+ // Re-export-only barrel syntax is intentionally ignored.
167
+ if (exportNode.source) {
168
+ return;
169
+ }
170
+ valueExports.push.apply(valueExports, _toConsumableArray(collectDeclarationExports(exportNode.declaration, allowPrimitiveExports)));
171
+ valueExports.push.apply(valueExports, _toConsumableArray(collectNamedSpecifierExports(exportNode)));
172
+ },
173
+ 'Program:exit': function ProgramExit(node) {
174
+ if (valueExports.length <= 1) {
175
+ return;
176
+ }
177
+ var sampleNames = valueExports.slice(0, 5).map(function (valueExport) {
178
+ return valueExport.name;
179
+ }).join(', ');
180
+ var names = valueExports.length > 5 ? "".concat(sampleNames, ", and ").concat(valueExports.length - 5, " more") : sampleNames;
181
+ valueExports.forEach(function (valueExport) {
182
+ context.report({
183
+ node: node,
184
+ loc: valueExport.loc,
185
+ messageId: 'multipleValueExports',
186
+ data: {
187
+ count: String(valueExports.length),
188
+ names: names
189
+ }
190
+ });
191
+ });
192
+ }
193
+ };
194
+ }
195
+ };
196
+ export default rule;
@@ -36,6 +36,7 @@ declare const rules: {
36
36
  'no-jest-mock-barrel-files': Rule.RuleModule;
37
37
  'no-relative-barrel-file-imports': Rule.RuleModule;
38
38
  'no-conversation-assistant-barrel-imports': Rule.RuleModule;
39
+ 'one-value-export-per-file': Rule.RuleModule;
39
40
  'visit-example-type-import-required': Rule.RuleModule;
40
41
  'no-xcss-in-cx': Rule.RuleModule;
41
42
  'editor-example-type-import-required': Rule.RuleModule;
@@ -85,6 +86,7 @@ declare const plugin: {
85
86
  'no-jest-mock-barrel-files': Rule.RuleModule;
86
87
  'no-relative-barrel-file-imports': Rule.RuleModule;
87
88
  'no-conversation-assistant-barrel-imports': Rule.RuleModule;
89
+ 'one-value-export-per-file': Rule.RuleModule;
88
90
  'visit-example-type-import-required': Rule.RuleModule;
89
91
  'editor-example-type-import-required': Rule.RuleModule;
90
92
  'ensure-use-sync-external-store-server-snapshot': Rule.RuleModule;
@@ -0,0 +1,3 @@
1
+ import type { Rule } from 'eslint';
2
+ declare const rule: Rule.RuleModule;
3
+ export default rule;
@@ -36,6 +36,7 @@ declare const rules: {
36
36
  'no-jest-mock-barrel-files': Rule.RuleModule;
37
37
  'no-relative-barrel-file-imports': Rule.RuleModule;
38
38
  'no-conversation-assistant-barrel-imports': Rule.RuleModule;
39
+ 'one-value-export-per-file': Rule.RuleModule;
39
40
  'visit-example-type-import-required': Rule.RuleModule;
40
41
  'no-xcss-in-cx': Rule.RuleModule;
41
42
  'editor-example-type-import-required': Rule.RuleModule;
@@ -85,6 +86,7 @@ declare const plugin: {
85
86
  'no-jest-mock-barrel-files': Rule.RuleModule;
86
87
  'no-relative-barrel-file-imports': Rule.RuleModule;
87
88
  'no-conversation-assistant-barrel-imports': Rule.RuleModule;
89
+ 'one-value-export-per-file': Rule.RuleModule;
88
90
  'visit-example-type-import-required': Rule.RuleModule;
89
91
  'editor-example-type-import-required': Rule.RuleModule;
90
92
  'ensure-use-sync-external-store-server-snapshot': Rule.RuleModule;
@@ -0,0 +1,3 @@
1
+ import type { Rule } from 'eslint';
2
+ declare const rule: Rule.RuleModule;
3
+ export default rule;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@atlaskit/eslint-plugin-platform",
3
3
  "description": "The essential plugin for use with Atlassian frontend platform tools",
4
- "version": "2.9.3",
4
+ "version": "2.10.0",
5
5
  "author": "Atlassian Pty Ltd",
6
6
  "atlassian": {
7
7
  "team": "Build Infra",