@atlaskit/eslint-plugin-platform 2.1.2 → 2.2.1
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 +17 -0
- package/dist/cjs/index.js +105 -63
- package/dist/cjs/rules/compiled/expand-spacing-shorthand/index.js +85 -40
- package/dist/es2019/index.js +116 -74
- package/dist/es2019/rules/compiled/expand-spacing-shorthand/index.js +69 -33
- package/dist/esm/index.js +106 -64
- package/dist/esm/rules/compiled/expand-spacing-shorthand/index.js +85 -40
- package/dist/types/index.d.ts +233 -35
- package/dist/types-ts4.5/index.d.ts +276 -42
- package/package.json +1 -1
- package/src/index.tsx +120 -79
- package/src/rules/compiled/expand-spacing-shorthand/__tests__/rule.test.ts +31 -1
- package/src/rules/compiled/expand-spacing-shorthand/index.ts +56 -28
package/src/index.tsx
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
2
|
-
import
|
|
2
|
+
import compiledPlugin from '@compiled/eslint-plugin';
|
|
3
|
+
import type { ESLint, Linter } from 'eslint';
|
|
3
4
|
import ensureFeatureFlagRegistration from './rules/ensure-feature-flag-registration';
|
|
4
5
|
import noPreAndPostInstallScripts from './rules/no-pre-post-installs';
|
|
5
6
|
import ensureTestRunnerArguments from './rules/ensure-test-runner-arguments';
|
|
@@ -27,7 +28,13 @@ import useRecommendedUtils from './rules/feature-gating/use-recommended-utils';
|
|
|
27
28
|
import expandBackgroundShorthand from './rules/compiled/expand-background-shorthand';
|
|
28
29
|
import expandSpacingShorthand from './rules/compiled/expand-spacing-shorthand';
|
|
29
30
|
|
|
30
|
-
|
|
31
|
+
const packageJson: {
|
|
32
|
+
name: string;
|
|
33
|
+
version: string;
|
|
34
|
+
// eslint-disable-next-line import/no-extraneous-dependencies
|
|
35
|
+
} = require('@atlaskit/eslint-plugin-platform/package.json');
|
|
36
|
+
|
|
37
|
+
const rules = {
|
|
31
38
|
'ensure-feature-flag-registration': ensureFeatureFlagRegistration,
|
|
32
39
|
'ensure-feature-flag-prefix': ensureFeatureFlagPrefix,
|
|
33
40
|
'ensure-test-runner-arguments': ensureTestRunnerArguments,
|
|
@@ -75,36 +82,27 @@ const commonConfig = {
|
|
|
75
82
|
runtime: 'classic',
|
|
76
83
|
},
|
|
77
84
|
],
|
|
78
|
-
};
|
|
85
|
+
} satisfies Linter.RulesRecord;
|
|
79
86
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
},
|
|
100
|
-
},
|
|
101
|
-
jira: {
|
|
102
|
-
plugins: ['@atlaskit/platform', '@compiled'],
|
|
103
|
-
rules: {
|
|
104
|
-
...commonConfig,
|
|
105
|
-
},
|
|
106
|
-
},
|
|
107
|
-
};
|
|
87
|
+
const recommendedRules = {
|
|
88
|
+
...commonConfig,
|
|
89
|
+
// See platform/packages/platform/eslint-plugin/src/rules/feature-gating/README.md
|
|
90
|
+
// These rules are specific to `platform` and seem a WIP; jira and confluence currently have their own rules
|
|
91
|
+
'@atlaskit/platform/no-module-level-eval': 'error',
|
|
92
|
+
'@atlaskit/platform/static-feature-flags': 'error',
|
|
93
|
+
'@atlaskit/platform/no-preconditioning': 'error',
|
|
94
|
+
'@atlaskit/platform/inline-usage': 'error',
|
|
95
|
+
'@atlaskit/platform/prefer-fg': 'error',
|
|
96
|
+
'@atlaskit/platform/no-alias': 'error',
|
|
97
|
+
// end: feature-gating rules
|
|
98
|
+
'@atlaskit/platform/ensure-feature-flag-registration': 'error',
|
|
99
|
+
'@atlaskit/platform/ensure-feature-flag-prefix': [
|
|
100
|
+
'warn',
|
|
101
|
+
{ allowedPrefixes: ['platform.', 'platform_'] },
|
|
102
|
+
],
|
|
103
|
+
} satisfies Linter.RulesRecord;
|
|
104
|
+
|
|
105
|
+
const jiraRules = commonConfig;
|
|
108
106
|
|
|
109
107
|
const jsonPrefix =
|
|
110
108
|
'/* eslint-disable quote-props, comma-dangle, quotes, semi, eol-last, @typescript-eslint/semi, no-template-curly-in-string */ module.exports = ';
|
|
@@ -112,55 +110,98 @@ const jsonPrefix =
|
|
|
112
110
|
const jsonPrefixForFlatConfig =
|
|
113
111
|
'/* eslint-disable quote-props, comma-dangle, quotes, semi, eol-last, no-template-curly-in-string */ module.exports = ';
|
|
114
112
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
113
|
+
const { name, version } = packageJson;
|
|
114
|
+
const plugin = {
|
|
115
|
+
meta: {
|
|
116
|
+
name,
|
|
117
|
+
version,
|
|
118
|
+
},
|
|
119
|
+
rules,
|
|
120
|
+
configs: {
|
|
121
|
+
recommended: {
|
|
122
|
+
plugins: ['@atlaskit/platform', '@compiled'],
|
|
123
|
+
rules: recommendedRules,
|
|
120
124
|
},
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
...message,
|
|
131
|
-
fix: {
|
|
132
|
-
...fix,
|
|
133
|
-
range: [fix.range[0] - offset, fix.range[1] - offset],
|
|
134
|
-
},
|
|
135
|
-
};
|
|
136
|
-
});
|
|
125
|
+
'recommended/flat': {
|
|
126
|
+
plugins: {
|
|
127
|
+
get '@atlaskit/platform'(): ESLint.Plugin {
|
|
128
|
+
return plugin;
|
|
129
|
+
},
|
|
130
|
+
// @ts-expect-error there's an issue with the types for @compiled/eslint-plugin ('no-css-prop-without-css-function' specifically)
|
|
131
|
+
'@compiled': { meta: compiledPlugin.meta, rules: compiledPlugin.rules } as ESLint.Plugin,
|
|
132
|
+
},
|
|
133
|
+
rules: recommendedRules,
|
|
137
134
|
},
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
// once we roll out FlatConfig, we can remove the above processor
|
|
142
|
-
'package-json-processor-for-flat-config': {
|
|
143
|
-
preprocess: (source: string) => {
|
|
144
|
-
// augment the json into a js file
|
|
145
|
-
return [jsonPrefixForFlatConfig + source.trim()];
|
|
135
|
+
jira: {
|
|
136
|
+
plugins: ['@atlaskit/platform', '@compiled'],
|
|
137
|
+
rules: jiraRules,
|
|
146
138
|
},
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
...message,
|
|
157
|
-
fix: {
|
|
158
|
-
...fix,
|
|
159
|
-
range: [fix.range[0] - offset, fix.range[1] - offset],
|
|
160
|
-
},
|
|
161
|
-
};
|
|
162
|
-
});
|
|
139
|
+
'jira/flat': {
|
|
140
|
+
plugins: {
|
|
141
|
+
get '@atlaskit/platform'(): ESLint.Plugin {
|
|
142
|
+
return plugin;
|
|
143
|
+
},
|
|
144
|
+
// @ts-expect-error there's an issue with the types for @compiled/eslint-plugin ('no-css-prop-without-css-function' specifically)
|
|
145
|
+
'@compiled': { meta: compiledPlugin.meta, rules: compiledPlugin.rules } as ESLint.Plugin,
|
|
146
|
+
},
|
|
147
|
+
rules: jiraRules,
|
|
163
148
|
},
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
149
|
+
},
|
|
150
|
+
processors: {
|
|
151
|
+
'package-json-processor': {
|
|
152
|
+
preprocess: (source: string) => {
|
|
153
|
+
// augment the json into a js file
|
|
154
|
+
return [jsonPrefix + source.trim()];
|
|
155
|
+
},
|
|
156
|
+
postprocess: (messages) => {
|
|
157
|
+
return messages[0].map((message) => {
|
|
158
|
+
const { fix } = message;
|
|
159
|
+
if (!fix) {
|
|
160
|
+
return message;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const offset = jsonPrefix.length;
|
|
164
|
+
return {
|
|
165
|
+
...message,
|
|
166
|
+
fix: {
|
|
167
|
+
...fix,
|
|
168
|
+
range: [fix.range[0] - offset, fix.range[1] - offset],
|
|
169
|
+
},
|
|
170
|
+
};
|
|
171
|
+
});
|
|
172
|
+
},
|
|
173
|
+
supportsAutofix: true,
|
|
174
|
+
} as Linter.Processor,
|
|
175
|
+
// This processor is used for ESLint FlatConfig,
|
|
176
|
+
// once we roll out FlatConfig, we can remove the above processor
|
|
177
|
+
'package-json-processor-for-flat-config': {
|
|
178
|
+
preprocess: (source: string) => {
|
|
179
|
+
// augment the json into a js file
|
|
180
|
+
return [jsonPrefixForFlatConfig + source.trim()];
|
|
181
|
+
},
|
|
182
|
+
postprocess: (messages) => {
|
|
183
|
+
return messages[0].map((message) => {
|
|
184
|
+
const { fix } = message;
|
|
185
|
+
if (!fix) {
|
|
186
|
+
return message;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const offset = jsonPrefixForFlatConfig.length;
|
|
190
|
+
return {
|
|
191
|
+
...message,
|
|
192
|
+
fix: {
|
|
193
|
+
...fix,
|
|
194
|
+
range: [fix.range[0] - offset, fix.range[1] - offset],
|
|
195
|
+
},
|
|
196
|
+
};
|
|
197
|
+
});
|
|
198
|
+
},
|
|
199
|
+
supportsAutofix: true,
|
|
200
|
+
} as Linter.Processor,
|
|
201
|
+
},
|
|
202
|
+
} satisfies ESLint.Plugin;
|
|
203
|
+
const configs = plugin.configs;
|
|
204
|
+
const processors = plugin.processors;
|
|
205
|
+
|
|
206
|
+
export { configs, plugin, processors, rules };
|
|
207
|
+
export default plugin;
|
|
@@ -272,6 +272,36 @@ const invalidTestCases = (property: string) => {
|
|
|
272
272
|
`,
|
|
273
273
|
errors: Array.from(Array(3), () => ({ messageId: 'expandSpacingShorthand' })),
|
|
274
274
|
},
|
|
275
|
+
// Strings that are not valid property values should not be autofixed (e.g. !important)
|
|
276
|
+
{
|
|
277
|
+
name: `${property}: Don't autofix if not able to handle all the string values, e.g !important`,
|
|
278
|
+
code: outdent`
|
|
279
|
+
import {css} from '@compiled/react';
|
|
280
|
+
const styles = css({
|
|
281
|
+
${property}: \`0 \${token('space.200', '16px')} !important\`,
|
|
282
|
+
});
|
|
283
|
+
`,
|
|
284
|
+
errors: [{ messageId: 'expandSpacingShorthand' }],
|
|
285
|
+
},
|
|
286
|
+
{
|
|
287
|
+
name: `${property}: Autofix if able to handle all string values`,
|
|
288
|
+
code: outdent`
|
|
289
|
+
import {css} from '@compiled/react';
|
|
290
|
+
const styles = css({
|
|
291
|
+
${property}: \`0 auto \${token('space.300', '24px')}\`,
|
|
292
|
+
});
|
|
293
|
+
`,
|
|
294
|
+
output: outdent`
|
|
295
|
+
import {css} from '@compiled/react';
|
|
296
|
+
const styles = css({
|
|
297
|
+
${property}Top: 0,
|
|
298
|
+
${property}Right: 'auto',
|
|
299
|
+
${property}Bottom: token('space.300', '24px'),
|
|
300
|
+
${property}Left: 'auto',
|
|
301
|
+
});
|
|
302
|
+
`,
|
|
303
|
+
errors: [{ messageId: 'expandSpacingShorthand' }],
|
|
304
|
+
},
|
|
275
305
|
// Miscellaneous
|
|
276
306
|
{
|
|
277
307
|
name: `${property}: new property should not be created if existing property already exists`,
|
|
@@ -383,7 +413,7 @@ const invalidTestCases = (property: string) => {
|
|
|
383
413
|
`,
|
|
384
414
|
errors: Array.from(Array(2), () => ({ messageId: 'expandSpacingShorthand' })),
|
|
385
415
|
},
|
|
386
|
-
// TODO (AFB-1022): Resolve this failing test
|
|
416
|
+
// // TODO (AFB-1022): Resolve this failing test
|
|
387
417
|
// {
|
|
388
418
|
// name: `${property}: styled components with prop input`,
|
|
389
419
|
// code: outdent`
|
|
@@ -34,7 +34,7 @@ const parseTemplateLiteral = (templateLiteral: TemplateLiteral, context: Rule.Ru
|
|
|
34
34
|
if (cookedQuasi) {
|
|
35
35
|
const splitQuasis = cookedQuasi.split(' ');
|
|
36
36
|
splitQuasis.forEach((str) => {
|
|
37
|
-
str = str.trim().replace("
|
|
37
|
+
str = str.trim().replace("'", '');
|
|
38
38
|
if (str.length > 0) {
|
|
39
39
|
propertyValues.push(isNaN(Number(str)) ? `'${str}'` : str);
|
|
40
40
|
}
|
|
@@ -49,26 +49,52 @@ const parseTemplateLiteral = (templateLiteral: TemplateLiteral, context: Rule.Ru
|
|
|
49
49
|
return propertyValues;
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Checks if the parsed property values are valid (i.e. no rule violation will be thrown). Cases are, the property values:
|
|
54
|
+
* 1. Do not contain a token
|
|
55
|
+
* 2. Have length that are not in the range [1, 4]
|
|
56
|
+
* 3. Includes `calc(...)`
|
|
57
|
+
* Then, the rule will return with no error
|
|
58
|
+
* @param propertyValues property values parsed as list of strings
|
|
59
|
+
* @returns boolean
|
|
60
|
+
*/
|
|
61
|
+
const isPropertyValueExempted = (propertyValues: string[]) => {
|
|
53
62
|
if (!propertyValues.some((str) => str.includes('token('))) {
|
|
54
|
-
return
|
|
63
|
+
return true;
|
|
55
64
|
}
|
|
56
65
|
if (propertyValues.length < 1 || propertyValues.length > 4) {
|
|
57
|
-
return
|
|
66
|
+
return true;
|
|
58
67
|
}
|
|
59
68
|
if (propertyValues.some((str) => str.includes('calc('))) {
|
|
60
|
-
return
|
|
69
|
+
return true;
|
|
61
70
|
}
|
|
62
|
-
return
|
|
71
|
+
return false;
|
|
63
72
|
};
|
|
64
73
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
74
|
+
/**
|
|
75
|
+
* Checks if the parsed property values are invalid (i.e. rule violation thrown) and autofix required. Cases are when:
|
|
76
|
+
* 1. All expressions in TemplateLiteral are token expressions
|
|
77
|
+
* 2. Property values must have a format which includes -> e.g. 2, '2(rem|em|px)', auto, initial, inherit, token(...)
|
|
78
|
+
* The rule will return with error and provide a fix
|
|
79
|
+
* @param templateLiteral TemplateLiteral AST Node
|
|
80
|
+
* @param propertyValues property values parsed as list of strings
|
|
81
|
+
* @returns boolean
|
|
82
|
+
*/
|
|
83
|
+
const isPropertyValuesInvalidFix = (templateLiteral: TemplateLiteral, propertyValues: string[]) => {
|
|
69
84
|
const expressions = templateLiteral.expressions;
|
|
70
|
-
|
|
71
|
-
|
|
85
|
+
if (!expressions.every((expr) => expr.type === 'CallExpression' && isTokenCallExpression(expr))) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
for (const propValue of propertyValues) {
|
|
90
|
+
if (propValue === '0') { continue; }
|
|
91
|
+
if (['auto', 'initial', 'inherit'].includes(propValue.slice(1, -1))) { continue; }
|
|
92
|
+
if ((/^token\(.*\)$/).test(propValue)) { continue; }
|
|
93
|
+
if ((/^['"]\d+(\.\d+)?((rem)|(em)|(px))['"]$/).test(propValue)) { continue; }
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
72
98
|
|
|
73
99
|
// To fix spacing shorthands, given a list of spacing property values, expands the spacing property and adds autofix fixes
|
|
74
100
|
const expandSpacingProperties = ({
|
|
@@ -130,8 +156,24 @@ const executeExpandSpacingRule = (
|
|
|
130
156
|
return;
|
|
131
157
|
}
|
|
132
158
|
if (node.value.type === 'TemplateLiteral') {
|
|
133
|
-
|
|
134
|
-
if (
|
|
159
|
+
const propertyValues = parseTemplateLiteral(node.value, context);
|
|
160
|
+
if (isPropertyValueExempted(propertyValues)) {
|
|
161
|
+
// Valid, so no error should be thrown
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (isPropertyValuesInvalidFix(node.value, propertyValues)) {
|
|
165
|
+
// Invalid, so error should be thrown and fix provided
|
|
166
|
+
context.report({
|
|
167
|
+
node,
|
|
168
|
+
messageId: 'expandSpacingShorthand',
|
|
169
|
+
data: {
|
|
170
|
+
property: propertyShorthand,
|
|
171
|
+
},
|
|
172
|
+
fix(fixer) {
|
|
173
|
+
return expandSpacingProperties({ context, node, propertyValues, fixer, propertyShorthand });
|
|
174
|
+
},
|
|
175
|
+
});
|
|
176
|
+
} else {
|
|
135
177
|
context.report({
|
|
136
178
|
node,
|
|
137
179
|
messageId: 'expandSpacingShorthand',
|
|
@@ -141,20 +183,6 @@ const executeExpandSpacingRule = (
|
|
|
141
183
|
});
|
|
142
184
|
return;
|
|
143
185
|
}
|
|
144
|
-
const propertyValues = parseTemplateLiteral(node.value, context);
|
|
145
|
-
if (!checkValidPropertyValues(propertyValues)) {
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
context.report({
|
|
149
|
-
node,
|
|
150
|
-
messageId: 'expandSpacingShorthand',
|
|
151
|
-
data: {
|
|
152
|
-
property: propertyShorthand,
|
|
153
|
-
},
|
|
154
|
-
fix(fixer) {
|
|
155
|
-
return expandSpacingProperties({ context, node, propertyValues, fixer, propertyShorthand });
|
|
156
|
-
},
|
|
157
|
-
});
|
|
158
186
|
} else if (node.value.type === 'CallExpression' && isTokenCallExpression(node.value)) {
|
|
159
187
|
// Value of spacing property is a token CallExpression type, e.g. margin: token('space.100', '8px')
|
|
160
188
|
const propertyValues = [getSourceCode(context).getText(node.value)];
|