@atlaskit/eslint-plugin-platform 0.14.0 → 1.1.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 +22 -0
- package/afm-jira/tsconfig.json +5 -1
- package/dist/cjs/index.js +1 -1
- package/dist/cjs/rules/compiled/expand-background-shorthand/index.js +5 -5
- package/dist/cjs/rules/compiled/expand-border-shorthand/index.js +6 -13
- package/dist/cjs/rules/feature-gating/inline-usage/index.js +1 -1
- package/dist/cjs/rules/feature-gating/no-alias/index.js +1 -1
- package/dist/cjs/rules/feature-gating/no-module-level-eval/index.js +4 -3
- package/dist/cjs/rules/feature-gating/no-module-level-eval-nav4/index.js +4 -3
- package/dist/cjs/rules/feature-gating/no-preconditioning/index.js +1 -1
- package/dist/cjs/rules/feature-gating/prefer-fg/index.js +7 -6
- package/dist/cjs/rules/feature-gating/static-feature-flags/index.js +2 -2
- package/dist/cjs/rules/feature-gating/use-recommended-utils/index.js +2 -2
- package/dist/cjs/rules/feature-gating/utils.js +10 -9
- package/dist/cjs/rules/util/context-compat.js +33 -0
- package/dist/es2019/index.js +1 -1
- package/dist/es2019/rules/compiled/expand-background-shorthand/index.js +4 -4
- package/dist/es2019/rules/compiled/expand-border-shorthand/index.js +6 -13
- package/dist/es2019/rules/feature-gating/inline-usage/index.js +1 -1
- package/dist/es2019/rules/feature-gating/no-alias/index.js +1 -1
- package/dist/es2019/rules/feature-gating/no-module-level-eval/index.js +4 -3
- package/dist/es2019/rules/feature-gating/no-module-level-eval-nav4/index.js +4 -3
- package/dist/es2019/rules/feature-gating/no-preconditioning/index.js +1 -1
- package/dist/es2019/rules/feature-gating/prefer-fg/index.js +5 -4
- package/dist/es2019/rules/feature-gating/static-feature-flags/index.js +2 -2
- package/dist/es2019/rules/feature-gating/use-recommended-utils/index.js +2 -2
- package/dist/es2019/rules/feature-gating/utils.js +9 -8
- package/dist/es2019/rules/util/context-compat.js +27 -0
- package/dist/esm/index.js +1 -1
- package/dist/esm/rules/compiled/expand-background-shorthand/index.js +5 -5
- package/dist/esm/rules/compiled/expand-border-shorthand/index.js +6 -13
- package/dist/esm/rules/feature-gating/inline-usage/index.js +1 -1
- package/dist/esm/rules/feature-gating/no-alias/index.js +1 -1
- package/dist/esm/rules/feature-gating/no-module-level-eval/index.js +4 -3
- package/dist/esm/rules/feature-gating/no-module-level-eval-nav4/index.js +4 -3
- package/dist/esm/rules/feature-gating/no-preconditioning/index.js +1 -1
- package/dist/esm/rules/feature-gating/prefer-fg/index.js +7 -6
- package/dist/esm/rules/feature-gating/static-feature-flags/index.js +2 -2
- package/dist/esm/rules/feature-gating/use-recommended-utils/index.js +2 -2
- package/dist/esm/rules/feature-gating/utils.js +10 -9
- package/dist/esm/rules/util/context-compat.js +27 -0
- package/dist/types/rules/feature-gating/utils.d.ts +4 -3
- package/dist/types/rules/util/context-compat.d.ts +10 -0
- package/dist/types-ts4.5/rules/feature-gating/utils.d.ts +4 -3
- package/dist/types-ts4.5/rules/util/context-compat.d.ts +10 -0
- package/package.json +2 -5
- package/src/index.tsx +1 -1
- package/src/rules/compiled/expand-background-shorthand/__tests__/rule.test.ts +1 -1
- package/src/rules/compiled/expand-background-shorthand/index.tsx +4 -4
- package/src/rules/compiled/expand-border-shorthand/README.md +1 -1
- package/src/rules/compiled/expand-border-shorthand/__tests__/rule.test.ts +47 -22
- package/src/rules/compiled/expand-border-shorthand/index.ts +7 -13
- package/src/rules/feature-gating/inline-usage/index.tsx +1 -1
- package/src/rules/feature-gating/no-alias/index.tsx +6 -1
- package/src/rules/feature-gating/no-module-level-eval/index.tsx +8 -6
- package/src/rules/feature-gating/no-module-level-eval-nav4/index.tsx +6 -5
- package/src/rules/feature-gating/no-preconditioning/index.tsx +1 -1
- package/src/rules/feature-gating/prefer-fg/index.tsx +8 -6
- package/src/rules/feature-gating/static-feature-flags/index.tsx +2 -2
- package/src/rules/feature-gating/use-recommended-utils/index.tsx +2 -2
- package/src/rules/feature-gating/utils.tsx +8 -6
- package/src/rules/util/context-compat.ts +28 -0
- package/tsconfig.app.json +3 -0
|
@@ -22,6 +22,9 @@ const separateBorderProperties = (
|
|
|
22
22
|
if (EXCLUDED_VALUES.includes(borderString)) {
|
|
23
23
|
return;
|
|
24
24
|
}
|
|
25
|
+
if (borderString.includes('var(--')) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
25
28
|
|
|
26
29
|
context.report({
|
|
27
30
|
node: property,
|
|
@@ -44,7 +47,7 @@ const isCompiledAPI = (importDeclaration: ImportDeclaration, callExpression: Cal
|
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
return importDeclaration.specifiers.some(
|
|
47
|
-
(specifier) => specifier.type === 'ImportSpecifier' && specifier.
|
|
50
|
+
(specifier) => specifier.type === 'ImportSpecifier' && specifier.local.name === functionName,
|
|
48
51
|
);
|
|
49
52
|
};
|
|
50
53
|
|
|
@@ -74,21 +77,12 @@ export const expandBorderShorthand: Rule.RuleModule = {
|
|
|
74
77
|
if (importDeclaration) {
|
|
75
78
|
if (isCompiledAPI(importDeclaration, callExpression)) {
|
|
76
79
|
if (node.value.type === 'Literal' && node.value.value !== null) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
} else if (node.value.raw) {
|
|
81
|
-
const borderString = node.value.raw;
|
|
80
|
+
const borderString =
|
|
81
|
+
typeof node.value.value === 'string' ? node.value.value : node.value.raw;
|
|
82
|
+
if (borderString) {
|
|
82
83
|
separateBorderProperties(borderString, node, context);
|
|
83
84
|
}
|
|
84
85
|
} else if (node.value.type === 'TemplateLiteral') {
|
|
85
|
-
if (node.value.quasis.length > 1 || node.value.expressions.length > 0) {
|
|
86
|
-
context.report({
|
|
87
|
-
node,
|
|
88
|
-
messageId: 'expandBorderShorthand',
|
|
89
|
-
});
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
86
|
if (node.value.quasis.length === 1 && node.value.quasis[0].value.cooked) {
|
|
93
87
|
const borderQuasis: string = node.value.quasis[0].value.cooked;
|
|
94
88
|
separateBorderProperties(borderQuasis, node, context);
|
|
@@ -27,7 +27,7 @@ const validateCallExpression = (
|
|
|
27
27
|
const shouldWarn =
|
|
28
28
|
callee.type === 'Identifier' &&
|
|
29
29
|
targetedFunctionsSwitch.has(callee.name) &&
|
|
30
|
-
isAPIimport(callee.name, context);
|
|
30
|
+
isAPIimport(callee.name, context, node);
|
|
31
31
|
|
|
32
32
|
if (shouldWarn) {
|
|
33
33
|
const defDeclaration = findDefinitionDeclaration(node.parent);
|
|
@@ -59,7 +59,12 @@ const rule: Rule.RuleModule = {
|
|
|
59
59
|
return;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
-
const isReassignment = isIdentifierImportedFrom(
|
|
62
|
+
const isReassignment = isIdentifierImportedFrom(
|
|
63
|
+
node.init.name,
|
|
64
|
+
IMPORT_SOURCES,
|
|
65
|
+
context,
|
|
66
|
+
node,
|
|
67
|
+
);
|
|
63
68
|
|
|
64
69
|
if (isReassignment) {
|
|
65
70
|
context.report({
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { Rule } from 'eslint';
|
|
2
|
-
import {
|
|
2
|
+
import type { Node } from 'estree';
|
|
3
|
+
import { isAPIimport } from '../utils';
|
|
4
|
+
import { getScope } from '../../util/context-compat';
|
|
3
5
|
|
|
4
|
-
const isInFunctionLevel = (context: Rule.RuleContext) => {
|
|
5
|
-
let scope: any =
|
|
6
|
+
const isInFunctionLevel = (context: Rule.RuleContext, node: Node) => {
|
|
7
|
+
let scope: any = getScope(context, node);
|
|
6
8
|
|
|
7
9
|
while (scope?.type !== 'module' && scope?.type !== 'global') {
|
|
8
10
|
if (scope.type === 'function') {
|
|
@@ -32,12 +34,12 @@ const rule: Rule.RuleModule = {
|
|
|
32
34
|
},
|
|
33
35
|
create(context) {
|
|
34
36
|
return {
|
|
35
|
-
'CallExpression[callee.type="Identifier"]': (node: Node
|
|
37
|
+
'CallExpression[callee.type="Identifier"]': (node: Node) => {
|
|
36
38
|
if (
|
|
37
39
|
node.type === 'CallExpression' &&
|
|
38
40
|
node.callee.type === 'Identifier' &&
|
|
39
|
-
isAPIimport(node.callee.name, context) &&
|
|
40
|
-
!isInFunctionLevel(context)
|
|
41
|
+
isAPIimport(node.callee.name, context, node) &&
|
|
42
|
+
!isInFunctionLevel(context, node)
|
|
41
43
|
) {
|
|
42
44
|
context.report({
|
|
43
45
|
messageId: 'noModuleLevelEval',
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Rule } from 'eslint';
|
|
2
|
-
import {
|
|
2
|
+
import type { Node } from 'estree';
|
|
3
|
+
import { getScope } from '../../util/context-compat';
|
|
3
4
|
|
|
4
5
|
const featureLibraryFunctions = new Set([
|
|
5
6
|
/*
|
|
@@ -21,8 +22,8 @@ const featureLibraryFunctions = new Set([
|
|
|
21
22
|
'getWillShowNav4UserOptOut',
|
|
22
23
|
]);
|
|
23
24
|
|
|
24
|
-
const isInFunctionLevel = (context: Rule.RuleContext) => {
|
|
25
|
-
let scope: any =
|
|
25
|
+
const isInFunctionLevel = (context: Rule.RuleContext, node: Node) => {
|
|
26
|
+
let scope: any = getScope(context, node);
|
|
26
27
|
|
|
27
28
|
while (scope?.type !== 'module' && scope?.type !== 'global') {
|
|
28
29
|
if (scope.type === 'function') {
|
|
@@ -52,12 +53,12 @@ const rule: Rule.RuleModule = {
|
|
|
52
53
|
},
|
|
53
54
|
create(context) {
|
|
54
55
|
return {
|
|
55
|
-
'CallExpression[callee.type="Identifier"]': (node: Node
|
|
56
|
+
'CallExpression[callee.type="Identifier"]': (node: Node) => {
|
|
56
57
|
if (
|
|
57
58
|
node.type === 'CallExpression' &&
|
|
58
59
|
node.callee.type === 'Identifier' &&
|
|
59
60
|
featureLibraryFunctions.has(node.callee.name) &&
|
|
60
|
-
!isInFunctionLevel(context)
|
|
61
|
+
!isInFunctionLevel(context, node)
|
|
61
62
|
) {
|
|
62
63
|
context.report({
|
|
63
64
|
messageId: 'noModuleLevelEval',
|
|
@@ -24,7 +24,7 @@ const getGateType = (node: Rule.Node, context: Rule.RuleContext): string => {
|
|
|
24
24
|
callee.type === 'Identifier' &&
|
|
25
25
|
// Experiments cannot have other experiments as preconditions, only gates
|
|
26
26
|
(callee.name === 'fg' || isExpUsage(callee.name)) &&
|
|
27
|
-
isAPIimport(callee.name, context);
|
|
27
|
+
isAPIimport(callee.name, context, node);
|
|
28
28
|
|
|
29
29
|
return isFeatureGate ? callee.name : '';
|
|
30
30
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { Rule } from 'eslint';
|
|
2
2
|
|
|
3
3
|
import { FEATURE_API_IMPORT_SOURCES } from '../../constants';
|
|
4
|
-
import {
|
|
4
|
+
import type { Node } from '../utils';
|
|
5
|
+
import type { Program } from 'estree';
|
|
6
|
+
import { getScope } from '../../util/context-compat';
|
|
5
7
|
|
|
6
8
|
const validateUsage = (
|
|
7
9
|
node: Node<'CallExpression'>,
|
|
@@ -9,9 +11,9 @@ const validateUsage = (
|
|
|
9
11
|
context: Rule.RuleContext,
|
|
10
12
|
changeMap: Map<any, any>,
|
|
11
13
|
) => {
|
|
12
|
-
const resolved = context
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
const resolved = getScope(context, node).references.find(
|
|
15
|
+
(ref) => ref.identifier.name === utilName,
|
|
16
|
+
)?.resolved;
|
|
15
17
|
|
|
16
18
|
const importSpecifierDefinition = resolved?.defs.find(
|
|
17
19
|
(def: any) =>
|
|
@@ -69,10 +71,10 @@ const rule: Rule.RuleModule = {
|
|
|
69
71
|
changeMap = changeMap || new Map();
|
|
70
72
|
validateUsage(node, 'getBooleanFF', context, changeMap);
|
|
71
73
|
},
|
|
72
|
-
'Program:exit': () => {
|
|
74
|
+
'Program:exit': (node: Program) => {
|
|
73
75
|
if (changeMap?.size) {
|
|
74
76
|
changeMap.forEach((changeCounts, importDeclaration) => {
|
|
75
|
-
const [moduleScope] =
|
|
77
|
+
const [moduleScope] = getScope(context, node).childScopes;
|
|
76
78
|
const importSpecifiers = new Set(
|
|
77
79
|
importDeclaration.specifiers.map(({ imported }: any) => imported.name),
|
|
78
80
|
);
|
|
@@ -70,14 +70,14 @@ const rule: Rule.RuleModule = {
|
|
|
70
70
|
if (
|
|
71
71
|
node.callee.type === 'Identifier' &&
|
|
72
72
|
(!targetedFunctionsSwitch.has(node.callee.name) ||
|
|
73
|
-
!isIdentifierImportedFrom(node.callee.name, IMPORT_SOURCES, context))
|
|
73
|
+
!isIdentifierImportedFrom(node.callee.name, IMPORT_SOURCES, context, node))
|
|
74
74
|
) {
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
const nameArgument = node.arguments[0];
|
|
79
79
|
if (nameArgument.type === 'Identifier') {
|
|
80
|
-
const def = getDef(nameArgument.name, context);
|
|
80
|
+
const def = getDef(nameArgument.name, context, node);
|
|
81
81
|
if (def != null && def.type === 'Variable') {
|
|
82
82
|
const { value } = def.node.init as any;
|
|
83
83
|
|
|
@@ -24,7 +24,7 @@ const rule: Rule.RuleModule = {
|
|
|
24
24
|
) => {
|
|
25
25
|
if (
|
|
26
26
|
node.object.type === 'Identifier' &&
|
|
27
|
-
isIdentifierImportedFrom(node.object.name, BANNED_IMPORTS_SET, context)
|
|
27
|
+
isIdentifierImportedFrom(node.object.name, BANNED_IMPORTS_SET, context, node)
|
|
28
28
|
) {
|
|
29
29
|
context.report({
|
|
30
30
|
messageId: 'useRecommended',
|
|
@@ -42,7 +42,7 @@ const rule: Rule.RuleModule = {
|
|
|
42
42
|
) => {
|
|
43
43
|
if (
|
|
44
44
|
node.object.type === 'Identifier' &&
|
|
45
|
-
isIdentifierImportedFrom(node.object.name, BANNED_IMPORTS_SET, context)
|
|
45
|
+
isIdentifierImportedFrom(node.object.name, BANNED_IMPORTS_SET, context, node)
|
|
46
46
|
) {
|
|
47
47
|
context.report({
|
|
48
48
|
messageId: 'notSupported',
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { FEATURE_API_IMPORT_SOURCES } from '../constants';
|
|
2
2
|
import type { Rule, Scope } from 'eslint';
|
|
3
|
+
import type { Node as EstreeNode } from 'estree';
|
|
4
|
+
import { getScope } from '../util/context-compat';
|
|
3
5
|
|
|
4
6
|
export function isIdentifierImportedFrom(
|
|
5
7
|
identifierName: string,
|
|
6
8
|
sources: Set<string>,
|
|
7
9
|
context: Rule.RuleContext,
|
|
10
|
+
node: EstreeNode,
|
|
8
11
|
) {
|
|
9
12
|
if (sources.size > 0) {
|
|
10
13
|
return (
|
|
11
|
-
context
|
|
12
|
-
.getScope()
|
|
14
|
+
getScope(context, node)
|
|
13
15
|
.references.find((ref) => ref.identifier.name === identifierName)
|
|
14
16
|
?.resolved?.defs.some(
|
|
15
17
|
(def) =>
|
|
@@ -21,13 +23,13 @@ export function isIdentifierImportedFrom(
|
|
|
21
23
|
return false;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
export function isAPIimport(functionName: string, context: Rule.RuleContext) {
|
|
25
|
-
return isIdentifierImportedFrom(functionName, FEATURE_API_IMPORT_SOURCES, context);
|
|
26
|
+
export function isAPIimport(functionName: string, context: Rule.RuleContext, node: EstreeNode) {
|
|
27
|
+
return isIdentifierImportedFrom(functionName, FEATURE_API_IMPORT_SOURCES, context, node);
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
// returns the definition node of a variable if it's declared within the scope of the file
|
|
29
|
-
export function getDef(name: string, context: Rule.RuleContext) {
|
|
30
|
-
let scope: Scope.Scope | null =
|
|
31
|
+
export function getDef(name: string, context: Rule.RuleContext, node: EstreeNode) {
|
|
32
|
+
let scope: Scope.Scope | null = getScope(context, node);
|
|
31
33
|
|
|
32
34
|
while (scope && scope.type !== 'global') {
|
|
33
35
|
for (const variable of scope.variables) {
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { Rule, Scope, SourceCode } from 'eslint';
|
|
2
|
+
import type { Node } from 'estree';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* TODO: Consider whether this should be replaced by ESLint's compat library.
|
|
6
|
+
* Either way, this should be removed once we no longer need to support ESLint versions less than 8.40.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A compatibility layer to support older versions of ESLint.
|
|
11
|
+
* `context.sourceCode` is the preferred way to access SourceCode, as
|
|
12
|
+
* `context.getSourceCode()` is deprecated in v8 and removed in v9.
|
|
13
|
+
* @param context - The ESLint rule context
|
|
14
|
+
*/
|
|
15
|
+
const getSourceCode = (context: Rule.RuleContext): SourceCode => {
|
|
16
|
+
return context.sourceCode ?? context.getSourceCode();
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* A compatibility layer to support older versions of ESLint.
|
|
21
|
+
* `context.sourceCode.getScope()` is the preferred way to access Scope, as
|
|
22
|
+
* `context.getScope()` was removed in v9.
|
|
23
|
+
* @param context - The ESLint rule context
|
|
24
|
+
* @param node - The node to get the scope for
|
|
25
|
+
*/
|
|
26
|
+
export const getScope = (context: Rule.RuleContext, node: Node): Scope.Scope => {
|
|
27
|
+
return getSourceCode(context)?.getScope(node) ?? context.getScope();
|
|
28
|
+
};
|
package/tsconfig.app.json
CHANGED