@atlaskit/eslint-plugin-design-system 13.8.0 → 13.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 +16 -0
- package/README.md +2 -0
- package/dist/cjs/presets/all-flat.codegen.js +3 -1
- package/dist/cjs/presets/all.codegen.js +3 -1
- package/dist/cjs/presets/recommended-flat.codegen.js +3 -1
- package/dist/cjs/presets/recommended.codegen.js +3 -1
- package/dist/cjs/rules/index.codegen.js +5 -1
- package/dist/cjs/rules/no-html-heading/index.js +40 -0
- package/dist/cjs/rules/no-html-heading/node-types/index.js +19 -0
- package/dist/cjs/rules/no-html-heading/node-types/jsx-element/index.js +136 -0
- package/dist/cjs/rules/no-html-heading/node-types/styled-component/index.js +42 -0
- package/dist/cjs/rules/no-html-heading/node-types/supported.js +82 -0
- package/dist/cjs/rules/no-html-select/index.js +40 -0
- package/dist/cjs/rules/no-html-select/node-types/index.js +19 -0
- package/dist/cjs/rules/no-html-select/node-types/jsx-element/index.js +27 -0
- package/dist/cjs/rules/no-html-select/node-types/styled-component/index.js +42 -0
- package/dist/cjs/rules/no-html-select/node-types/supported.js +66 -0
- package/dist/es2019/presets/all-flat.codegen.js +3 -1
- package/dist/es2019/presets/all.codegen.js +3 -1
- package/dist/es2019/presets/recommended-flat.codegen.js +3 -1
- package/dist/es2019/presets/recommended.codegen.js +3 -1
- package/dist/es2019/rules/index.codegen.js +5 -1
- package/dist/es2019/rules/no-html-heading/index.js +34 -0
- package/dist/es2019/rules/no-html-heading/node-types/index.js +2 -0
- package/dist/es2019/rules/no-html-heading/node-types/jsx-element/index.js +99 -0
- package/dist/es2019/rules/no-html-heading/node-types/styled-component/index.js +37 -0
- package/dist/es2019/rules/no-html-heading/node-types/supported.js +72 -0
- package/dist/es2019/rules/no-html-select/index.js +34 -0
- package/dist/es2019/rules/no-html-select/node-types/index.js +2 -0
- package/dist/es2019/rules/no-html-select/node-types/jsx-element/index.js +19 -0
- package/dist/es2019/rules/no-html-select/node-types/styled-component/index.js +37 -0
- package/dist/es2019/rules/no-html-select/node-types/supported.js +56 -0
- package/dist/esm/presets/all-flat.codegen.js +3 -1
- package/dist/esm/presets/all.codegen.js +3 -1
- package/dist/esm/presets/recommended-flat.codegen.js +3 -1
- package/dist/esm/presets/recommended.codegen.js +3 -1
- package/dist/esm/rules/index.codegen.js +5 -1
- package/dist/esm/rules/no-html-heading/index.js +34 -0
- package/dist/esm/rules/no-html-heading/node-types/index.js +2 -0
- package/dist/esm/rules/no-html-heading/node-types/jsx-element/index.js +127 -0
- package/dist/esm/rules/no-html-heading/node-types/styled-component/index.js +36 -0
- package/dist/esm/rules/no-html-heading/node-types/supported.js +73 -0
- package/dist/esm/rules/no-html-select/index.js +34 -0
- package/dist/esm/rules/no-html-select/node-types/index.js +2 -0
- package/dist/esm/rules/no-html-select/node-types/jsx-element/index.js +18 -0
- package/dist/esm/rules/no-html-select/node-types/styled-component/index.js +36 -0
- package/dist/esm/rules/no-html-select/node-types/supported.js +57 -0
- package/dist/types/index.codegen.d.ts +18 -0
- package/dist/types/presets/all-flat.codegen.d.ts +2 -0
- package/dist/types/presets/all.codegen.d.ts +2 -0
- package/dist/types/presets/recommended-flat.codegen.d.ts +2 -0
- package/dist/types/presets/recommended.codegen.d.ts +2 -0
- package/dist/types/rules/index.codegen.d.ts +2 -0
- package/dist/types/rules/no-html-heading/index.d.ts +3 -0
- package/dist/types/rules/no-html-heading/node-types/index.d.ts +2 -0
- package/dist/types/rules/no-html-heading/node-types/jsx-element/index.d.ts +8 -0
- package/dist/types/rules/no-html-heading/node-types/styled-component/index.d.ts +8 -0
- package/dist/types/rules/no-html-heading/node-types/supported.d.ts +7 -0
- package/dist/types/rules/no-html-select/index.d.ts +3 -0
- package/dist/types/rules/no-html-select/node-types/index.d.ts +2 -0
- package/dist/types/rules/no-html-select/node-types/jsx-element/index.d.ts +8 -0
- package/dist/types/rules/no-html-select/node-types/styled-component/index.d.ts +8 -0
- package/dist/types/rules/no-html-select/node-types/supported.d.ts +7 -0
- package/dist/types-ts4.5/index.codegen.d.ts +18 -0
- package/dist/types-ts4.5/presets/all-flat.codegen.d.ts +2 -0
- package/dist/types-ts4.5/presets/all.codegen.d.ts +2 -0
- package/dist/types-ts4.5/presets/recommended-flat.codegen.d.ts +2 -0
- package/dist/types-ts4.5/presets/recommended.codegen.d.ts +2 -0
- package/dist/types-ts4.5/rules/index.codegen.d.ts +2 -0
- package/dist/types-ts4.5/rules/no-html-heading/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/no-html-heading/node-types/index.d.ts +2 -0
- package/dist/types-ts4.5/rules/no-html-heading/node-types/jsx-element/index.d.ts +8 -0
- package/dist/types-ts4.5/rules/no-html-heading/node-types/styled-component/index.d.ts +8 -0
- package/dist/types-ts4.5/rules/no-html-heading/node-types/supported.d.ts +7 -0
- package/dist/types-ts4.5/rules/no-html-select/index.d.ts +3 -0
- package/dist/types-ts4.5/rules/no-html-select/node-types/index.d.ts +2 -0
- package/dist/types-ts4.5/rules/no-html-select/node-types/jsx-element/index.d.ts +8 -0
- package/dist/types-ts4.5/rules/no-html-select/node-types/styled-component/index.d.ts +8 -0
- package/dist/types-ts4.5/rules/no-html-select/node-types/supported.d.ts +7 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# @atlaskit/eslint-plugin-design-system
|
|
2
2
|
|
|
3
|
+
## 13.10.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#145568](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/145568)
|
|
8
|
+
[`43180d95604d6`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/43180d95604d6) -
|
|
9
|
+
Add rule to encourage use of the DS heading component over native HTML headings.
|
|
10
|
+
|
|
11
|
+
## 13.9.0
|
|
12
|
+
|
|
13
|
+
### Minor Changes
|
|
14
|
+
|
|
15
|
+
- [#145662](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/pull-requests/145662)
|
|
16
|
+
[`acf5f6979c85f`](https://bitbucket.org/atlassian/atlassian-frontend-monorepo/commits/acf5f6979c85f) -
|
|
17
|
+
Add rule to encourage use of the DS select component over native HTML selects.
|
|
18
|
+
|
|
3
19
|
## 13.8.0
|
|
4
20
|
|
|
5
21
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -69,8 +69,10 @@ module.exports = {
|
|
|
69
69
|
| <a href="./src/rules/no-html-anchor/README.md">no-html-anchor</a> | Discourage direct usage of HTML anchor elements in favor of Atlassian Design System link components. | Yes | | Yes |
|
|
70
70
|
| <a href="./src/rules/no-html-button/README.md">no-html-button</a> | Discourage direct usage of HTML button elements in favor of Atlassian Design System button components. | Yes | | |
|
|
71
71
|
| <a href="./src/rules/no-html-checkbox/README.md">no-html-checkbox</a> | Discourage direct usage of HTML checkbox elements in favor of the Atlassian Design System checkbox component. | Yes | | Yes |
|
|
72
|
+
| <a href="./src/rules/no-html-heading/README.md">no-html-heading</a> | Discourage direct usage of HTML heading elements in favor of Atlassian Design System heading components. | Yes | | Yes |
|
|
72
73
|
| <a href="./src/rules/no-html-image/README.md">no-html-image</a> | Discourage direct usage of HTML image elements in favor of the Atlassian Design System image component. | Yes | | Yes |
|
|
73
74
|
| <a href="./src/rules/no-html-range/README.md">no-html-range</a> | Discourage direct usage of HTML range elements in favor of the Atlassian Design System range component. | Yes | | Yes |
|
|
75
|
+
| <a href="./src/rules/no-html-select/README.md">no-html-select</a> | Discourage direct usage of HTML select elements in favor of the Atlassian Design System select component. | Yes | | Yes |
|
|
74
76
|
| <a href="./src/rules/no-invalid-css-map/README.md">no-invalid-css-map</a> | Checks the validity of a CSS map created through cssMap. This is intended to be used alongside TypeScript's type-checking. | Yes | | |
|
|
75
77
|
| <a href="./src/rules/no-keyframes-tagged-template-expression/README.md">no-keyframes-tagged-template-expression</a> | Disallows any `keyframe` tagged template expressions that originate from Emotion, Styled Components or Compiled | | Yes | |
|
|
76
78
|
| <a href="./src/rules/no-legacy-icons/README.md">no-legacy-icons</a> | Enforces no legacy icons are used. | | Yes | Yes |
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
/**
|
|
8
8
|
* THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
|
|
9
|
-
* @codegen <<SignedSource::
|
|
9
|
+
* @codegen <<SignedSource::aa1526cdf8f7bbdd8e89e584da433397>>
|
|
10
10
|
* @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
|
|
11
11
|
*/
|
|
12
12
|
var _default = exports.default = {
|
|
@@ -30,8 +30,10 @@ var _default = exports.default = {
|
|
|
30
30
|
'@atlaskit/design-system/no-html-anchor': 'warn',
|
|
31
31
|
'@atlaskit/design-system/no-html-button': 'warn',
|
|
32
32
|
'@atlaskit/design-system/no-html-checkbox': 'warn',
|
|
33
|
+
'@atlaskit/design-system/no-html-heading': 'warn',
|
|
33
34
|
'@atlaskit/design-system/no-html-image': 'warn',
|
|
34
35
|
'@atlaskit/design-system/no-html-range': 'warn',
|
|
36
|
+
'@atlaskit/design-system/no-html-select': 'warn',
|
|
35
37
|
'@atlaskit/design-system/no-invalid-css-map': ['error', {
|
|
36
38
|
allowedFunctionCalls: [['@atlaskit/tokens', 'token']]
|
|
37
39
|
}],
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
/**
|
|
8
8
|
* THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
|
|
9
|
-
* @codegen <<SignedSource::
|
|
9
|
+
* @codegen <<SignedSource::ec47b97e20d77ba1f43c2211aeeed2f6>>
|
|
10
10
|
* @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
|
|
11
11
|
*/
|
|
12
12
|
var _default = exports.default = {
|
|
@@ -29,8 +29,10 @@ var _default = exports.default = {
|
|
|
29
29
|
'@atlaskit/design-system/no-html-anchor': 'warn',
|
|
30
30
|
'@atlaskit/design-system/no-html-button': 'warn',
|
|
31
31
|
'@atlaskit/design-system/no-html-checkbox': 'warn',
|
|
32
|
+
'@atlaskit/design-system/no-html-heading': 'warn',
|
|
32
33
|
'@atlaskit/design-system/no-html-image': 'warn',
|
|
33
34
|
'@atlaskit/design-system/no-html-range': 'warn',
|
|
35
|
+
'@atlaskit/design-system/no-html-select': 'warn',
|
|
34
36
|
'@atlaskit/design-system/no-invalid-css-map': ['error', {
|
|
35
37
|
allowedFunctionCalls: [['@atlaskit/tokens', 'token']]
|
|
36
38
|
}],
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
/**
|
|
8
8
|
* THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
|
|
9
|
-
* @codegen <<SignedSource::
|
|
9
|
+
* @codegen <<SignedSource::4ad986601bfd6f0081e3bc6909694979>>
|
|
10
10
|
* @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
|
|
11
11
|
*/
|
|
12
12
|
var _default = exports.default = {
|
|
@@ -25,8 +25,10 @@ var _default = exports.default = {
|
|
|
25
25
|
'@atlaskit/design-system/no-html-anchor': 'warn',
|
|
26
26
|
'@atlaskit/design-system/no-html-button': 'warn',
|
|
27
27
|
'@atlaskit/design-system/no-html-checkbox': 'warn',
|
|
28
|
+
'@atlaskit/design-system/no-html-heading': 'warn',
|
|
28
29
|
'@atlaskit/design-system/no-html-image': 'warn',
|
|
29
30
|
'@atlaskit/design-system/no-html-range': 'warn',
|
|
31
|
+
'@atlaskit/design-system/no-html-select': 'warn',
|
|
30
32
|
'@atlaskit/design-system/no-invalid-css-map': ['error', {
|
|
31
33
|
allowedFunctionCalls: [['@atlaskit/tokens', 'token']]
|
|
32
34
|
}],
|
|
@@ -6,7 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.default = void 0;
|
|
7
7
|
/**
|
|
8
8
|
* THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
|
|
9
|
-
* @codegen <<SignedSource::
|
|
9
|
+
* @codegen <<SignedSource::18dcf6fce30892e43fb5fb76339c261e>>
|
|
10
10
|
* @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
|
|
11
11
|
*/
|
|
12
12
|
var _default = exports.default = {
|
|
@@ -24,8 +24,10 @@ var _default = exports.default = {
|
|
|
24
24
|
'@atlaskit/design-system/no-html-anchor': 'warn',
|
|
25
25
|
'@atlaskit/design-system/no-html-button': 'warn',
|
|
26
26
|
'@atlaskit/design-system/no-html-checkbox': 'warn',
|
|
27
|
+
'@atlaskit/design-system/no-html-heading': 'warn',
|
|
27
28
|
'@atlaskit/design-system/no-html-image': 'warn',
|
|
28
29
|
'@atlaskit/design-system/no-html-range': 'warn',
|
|
30
|
+
'@atlaskit/design-system/no-html-select': 'warn',
|
|
29
31
|
'@atlaskit/design-system/no-invalid-css-map': ['error', {
|
|
30
32
|
allowedFunctionCalls: [['@atlaskit/tokens', 'token']]
|
|
31
33
|
}],
|
|
@@ -25,8 +25,10 @@ var _noExportedKeyframes = _interopRequireDefault(require("./no-exported-keyfram
|
|
|
25
25
|
var _noHtmlAnchor = _interopRequireDefault(require("./no-html-anchor"));
|
|
26
26
|
var _noHtmlButton = _interopRequireDefault(require("./no-html-button"));
|
|
27
27
|
var _noHtmlCheckbox = _interopRequireDefault(require("./no-html-checkbox"));
|
|
28
|
+
var _noHtmlHeading = _interopRequireDefault(require("./no-html-heading"));
|
|
28
29
|
var _noHtmlImage = _interopRequireDefault(require("./no-html-image"));
|
|
29
30
|
var _noHtmlRange = _interopRequireDefault(require("./no-html-range"));
|
|
31
|
+
var _noHtmlSelect = _interopRequireDefault(require("./no-html-select"));
|
|
30
32
|
var _noInvalidCssMap = _interopRequireDefault(require("./no-invalid-css-map"));
|
|
31
33
|
var _noKeyframesTaggedTemplateExpression = _interopRequireDefault(require("./no-keyframes-tagged-template-expression"));
|
|
32
34
|
var _noLegacyIcons = _interopRequireDefault(require("./no-legacy-icons"));
|
|
@@ -61,7 +63,7 @@ var _useTokensTypography = _interopRequireDefault(require("./use-tokens-typograp
|
|
|
61
63
|
var _useVisuallyHidden = _interopRequireDefault(require("./use-visually-hidden"));
|
|
62
64
|
/**
|
|
63
65
|
* THIS FILE WAS CREATED VIA CODEGEN DO NOT MODIFY {@see http://go/af-codegen}
|
|
64
|
-
* @codegen <<SignedSource::
|
|
66
|
+
* @codegen <<SignedSource::19fc297469c40b1fa9fd64c9f9313ba7>>
|
|
65
67
|
* @codegenCommand yarn workspace @atlaskit/eslint-plugin-design-system codegen
|
|
66
68
|
*/
|
|
67
69
|
|
|
@@ -86,8 +88,10 @@ var rules = exports.rules = {
|
|
|
86
88
|
'no-html-anchor': _noHtmlAnchor.default,
|
|
87
89
|
'no-html-button': _noHtmlButton.default,
|
|
88
90
|
'no-html-checkbox': _noHtmlCheckbox.default,
|
|
91
|
+
'no-html-heading': _noHtmlHeading.default,
|
|
89
92
|
'no-html-image': _noHtmlImage.default,
|
|
90
93
|
'no-html-range': _noHtmlRange.default,
|
|
94
|
+
'no-html-select': _noHtmlSelect.default,
|
|
91
95
|
'no-invalid-css-map': _noInvalidCssMap.default,
|
|
92
96
|
'no-keyframes-tagged-template-expression': _noKeyframesTaggedTemplateExpression.default,
|
|
93
97
|
'no-legacy-icons': _noLegacyIcons.default,
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _createRule = require("../utils/create-rule");
|
|
8
|
+
var _nodeTypes = require("./node-types");
|
|
9
|
+
var rule = (0, _createRule.createLintRule)({
|
|
10
|
+
meta: {
|
|
11
|
+
name: 'no-html-heading',
|
|
12
|
+
type: 'suggestion',
|
|
13
|
+
hasSuggestions: true,
|
|
14
|
+
docs: {
|
|
15
|
+
description: 'Discourage direct usage of HTML heading elements in favor of Atlassian Design System heading components.',
|
|
16
|
+
recommended: true,
|
|
17
|
+
severity: 'warn'
|
|
18
|
+
},
|
|
19
|
+
messages: {
|
|
20
|
+
noHtmlHeading: "This <{{ name }}> should be replaced with a heading component from the Atlassian Design System. ADS headings include ensure accessible implementations and provide access to ADS styling features like design tokens."
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
create: function create(context) {
|
|
24
|
+
return {
|
|
25
|
+
// transforms styled.<heading>(...) usages
|
|
26
|
+
CallExpression: function CallExpression(node) {
|
|
27
|
+
_nodeTypes.StyledComponent.lint(node, {
|
|
28
|
+
context: context
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
// transforms <heading css={...}> usages
|
|
32
|
+
JSXElement: function JSXElement(node) {
|
|
33
|
+
_nodeTypes.JSXElement.lint(node, {
|
|
34
|
+
context: context
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
var _default = exports.default = rule;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "JSXElement", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function get() {
|
|
9
|
+
return _jsxElement.JSXElement;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "StyledComponent", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function get() {
|
|
15
|
+
return _styledComponent.StyledComponent;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
var _styledComponent = require("./styled-component");
|
|
19
|
+
var _jsxElement = require("./jsx-element");
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.JSXElement = void 0;
|
|
8
|
+
var _eslintCodemodUtils = require("eslint-codemod-utils");
|
|
9
|
+
var _contextCompat = require("@atlaskit/eslint-utils/context-compat");
|
|
10
|
+
var ast = _interopRequireWildcard(require("../../../../ast-nodes"));
|
|
11
|
+
var _supported = require("../supported");
|
|
12
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
|
|
13
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
14
|
+
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (!t) { if (Array.isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
|
|
15
|
+
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
16
|
+
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
17
|
+
function isImportDeclaration(node) {
|
|
18
|
+
return node.type === 'ImportDeclaration';
|
|
19
|
+
}
|
|
20
|
+
var JSXElement = exports.JSXElement = {
|
|
21
|
+
lint: function lint(node, _ref) {
|
|
22
|
+
var context = _ref.context;
|
|
23
|
+
if (!(0, _supported.isSupportedForLint)(node)) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
var nodeName = ast.JSXElement.getName(node);
|
|
27
|
+
var sourceCode = (0, _contextCompat.getSourceCode)(context);
|
|
28
|
+
var importDeclarations = sourceCode.ast.body.filter(isImportDeclaration);
|
|
29
|
+
var existingHeadingName = null;
|
|
30
|
+
var usedNames = new Set();
|
|
31
|
+
|
|
32
|
+
// Check for existing imports
|
|
33
|
+
var _iterator = _createForOfIteratorHelper(importDeclarations),
|
|
34
|
+
_step;
|
|
35
|
+
try {
|
|
36
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
37
|
+
var declaration = _step.value;
|
|
38
|
+
var _iterator2 = _createForOfIteratorHelper(declaration.specifiers),
|
|
39
|
+
_step2;
|
|
40
|
+
try {
|
|
41
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
42
|
+
var specifier = _step2.value;
|
|
43
|
+
usedNames.add(specifier.local.name);
|
|
44
|
+
}
|
|
45
|
+
} catch (err) {
|
|
46
|
+
_iterator2.e(err);
|
|
47
|
+
} finally {
|
|
48
|
+
_iterator2.f();
|
|
49
|
+
}
|
|
50
|
+
if (declaration.source.value === '@atlaskit/heading') {
|
|
51
|
+
var defaultSpecifier = declaration.specifiers.find(function (specifier) {
|
|
52
|
+
return specifier.type === 'ImportDefaultSpecifier';
|
|
53
|
+
});
|
|
54
|
+
if (defaultSpecifier) {
|
|
55
|
+
existingHeadingName = defaultSpecifier.local.name;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
} catch (err) {
|
|
60
|
+
_iterator.e(err);
|
|
61
|
+
} finally {
|
|
62
|
+
_iterator.f();
|
|
63
|
+
}
|
|
64
|
+
var generateUniqueName = function generateUniqueName(baseName) {
|
|
65
|
+
var index = 1;
|
|
66
|
+
var newName = baseName;
|
|
67
|
+
while (usedNames.has(newName)) {
|
|
68
|
+
newName = "".concat(baseName).concat(index);
|
|
69
|
+
index++;
|
|
70
|
+
}
|
|
71
|
+
return newName;
|
|
72
|
+
};
|
|
73
|
+
var headingName = existingHeadingName || generateUniqueName('Heading');
|
|
74
|
+
context.report({
|
|
75
|
+
node: node.openingElement,
|
|
76
|
+
messageId: 'noHtmlHeading',
|
|
77
|
+
data: {
|
|
78
|
+
name: nodeName
|
|
79
|
+
},
|
|
80
|
+
suggest: [{
|
|
81
|
+
desc: 'Replace with Heading component from @atlaskit/heading',
|
|
82
|
+
fix: function fix(fixer) {
|
|
83
|
+
var _node$closingElement;
|
|
84
|
+
var openingTagRange = node.openingElement.range;
|
|
85
|
+
var closingTagRange = (_node$closingElement = node.closingElement) === null || _node$closingElement === void 0 ? void 0 : _node$closingElement.range;
|
|
86
|
+
var elementName = (0, _eslintCodemodUtils.isNodeOfType)(node.openingElement.name, 'JSXIdentifier') ? node.openingElement.name.name : '';
|
|
87
|
+
var attributesText = node.openingElement.attributes
|
|
88
|
+
// Don't bring in the "role" or the "aria-level" because it's not needed
|
|
89
|
+
.filter(function (attr) {
|
|
90
|
+
return !(0, _eslintCodemodUtils.isNodeOfType)(attr, 'JSXAttribute') || typeof attr.name.name === 'string' && !['role', 'aria-level'].includes(attr.name.name);
|
|
91
|
+
}).map(function (attr) {
|
|
92
|
+
return sourceCode.getText(attr);
|
|
93
|
+
}).join(' ');
|
|
94
|
+
|
|
95
|
+
// Get the heading level
|
|
96
|
+
var headingLevel = '';
|
|
97
|
+
var ariaLevel = node.openingElement.attributes.find(function (attr) {
|
|
98
|
+
return (0, _eslintCodemodUtils.isNodeOfType)(attr, 'JSXAttribute') && attr.name.name === 'aria-level';
|
|
99
|
+
});
|
|
100
|
+
if (ariaLevel && (0, _eslintCodemodUtils.isNodeOfType)(ariaLevel, 'JSXAttribute')) {
|
|
101
|
+
var _ariaLevel$value, _ariaLevel$value2;
|
|
102
|
+
// If it's a string
|
|
103
|
+
if (((_ariaLevel$value = ariaLevel.value) === null || _ariaLevel$value === void 0 ? void 0 : _ariaLevel$value.type) === 'Literal' && ariaLevel.value.value) {
|
|
104
|
+
headingLevel = "h".concat(ariaLevel.value.value);
|
|
105
|
+
// If it's a number or some other literal in an expression container
|
|
106
|
+
} else if (((_ariaLevel$value2 = ariaLevel.value) === null || _ariaLevel$value2 === void 0 ? void 0 : _ariaLevel$value2.type) === 'JSXExpressionContainer' && ariaLevel.value.expression.type === 'Literal' && ariaLevel.value.expression.value) {
|
|
107
|
+
headingLevel = "h".concat(ariaLevel.value.expression.value);
|
|
108
|
+
}
|
|
109
|
+
} else if (elementName.match(/h[1-6]/)) {
|
|
110
|
+
headingLevel = elementName;
|
|
111
|
+
}
|
|
112
|
+
var fixers = [];
|
|
113
|
+
|
|
114
|
+
// Replace <a> with <Heading> and retain attributes
|
|
115
|
+
if (openingTagRange) {
|
|
116
|
+
if (node.openingElement.selfClosing) {
|
|
117
|
+
fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], "".concat(headingName).concat(headingLevel ? " as=\"".concat(headingLevel, "\"") : '').concat(attributesText ? " ".concat(attributesText) : '', " /")));
|
|
118
|
+
} else {
|
|
119
|
+
fixers.push(fixer.replaceTextRange([openingTagRange[0] + 1, openingTagRange[1] - 1], "".concat(headingName).concat(headingLevel ? " as=\"".concat(headingLevel, "\"") : '').concat(attributesText ? " ".concat(attributesText) : '')));
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (closingTagRange && !node.openingElement.selfClosing) {
|
|
123
|
+
fixers.push(fixer.replaceTextRange([closingTagRange[0] + 2, closingTagRange[1] - 1], headingName));
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Add import if not present
|
|
127
|
+
if (!existingHeadingName) {
|
|
128
|
+
var importStatement = "import ".concat(headingName, " from '@atlaskit/heading';\n");
|
|
129
|
+
fixers.push(fixer.insertTextBefore(sourceCode.ast, importStatement));
|
|
130
|
+
}
|
|
131
|
+
return fixers;
|
|
132
|
+
}
|
|
133
|
+
}]
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.StyledComponent = void 0;
|
|
7
|
+
var _eslintCodemodUtils = require("eslint-codemod-utils");
|
|
8
|
+
var _contextCompat = require("@atlaskit/eslint-utils/context-compat");
|
|
9
|
+
var _getJsxElementByName2 = require("../../../utils/get-jsx-element-by-name");
|
|
10
|
+
var _getStyledComponentCall = require("../../../utils/get-styled-component-call");
|
|
11
|
+
var _supported = require("../supported");
|
|
12
|
+
/* eslint-disable @repo/internal/react/require-jsdoc */
|
|
13
|
+
|
|
14
|
+
var StyledComponent = exports.StyledComponent = {
|
|
15
|
+
lint: function lint(node, _ref) {
|
|
16
|
+
var _getJsxElementByName;
|
|
17
|
+
var context = _ref.context;
|
|
18
|
+
if (!(0, _eslintCodemodUtils.isNodeOfType)(node, 'CallExpression') || !(0, _eslintCodemodUtils.isNodeOfType)(node.callee, 'MemberExpression') || !(0, _eslintCodemodUtils.isNodeOfType)(node.callee.object, 'Identifier') || !(0, _eslintCodemodUtils.isNodeOfType)(node.callee.property, 'Identifier')) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
var styles = (0, _getStyledComponentCall.getStyledComponentCall)(node);
|
|
22
|
+
var elementName = node.callee.property.name;
|
|
23
|
+
if (!styles || !(0, _eslintCodemodUtils.isNodeOfType)(styles.id, 'Identifier')) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
var jsxElement = (_getJsxElementByName = (0, _getJsxElementByName2.getJsxElementByName)(styles.id.name, (0, _contextCompat.getScope)(context, node))) === null || _getJsxElementByName === void 0 ? void 0 : _getJsxElementByName.parent;
|
|
27
|
+
if (!jsxElement) {
|
|
28
|
+
// If there's no JSX element, we can't determine if it's being used as an heading or not
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (jsxElement && !(0, _supported.isSupportedForLint)(jsxElement, elementName)) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
context.report({
|
|
35
|
+
node: styles,
|
|
36
|
+
messageId: 'noHtmlHeading',
|
|
37
|
+
data: {
|
|
38
|
+
name: node.callee.property.name
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
};
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.isSupportedForLint = isSupportedForLint;
|
|
8
|
+
var _eslintCodemodUtils = require("eslint-codemod-utils");
|
|
9
|
+
var ast = _interopRequireWildcard(require("../../../ast-nodes"));
|
|
10
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
|
|
11
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
12
|
+
var supportedElements = [{
|
|
13
|
+
name: 'h1'
|
|
14
|
+
}, {
|
|
15
|
+
name: 'h2'
|
|
16
|
+
}, {
|
|
17
|
+
name: 'h3'
|
|
18
|
+
}, {
|
|
19
|
+
name: 'h4'
|
|
20
|
+
}, {
|
|
21
|
+
name: 'h5'
|
|
22
|
+
}, {
|
|
23
|
+
name: 'h6'
|
|
24
|
+
}, {
|
|
25
|
+
name: '*',
|
|
26
|
+
attributes: [{
|
|
27
|
+
name: 'role',
|
|
28
|
+
values: ['heading']
|
|
29
|
+
}]
|
|
30
|
+
}];
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Determines if the given JSX element is a supported element to lint with this rule.
|
|
34
|
+
*/
|
|
35
|
+
function isSupportedForLint(jsxNode, elementName) {
|
|
36
|
+
if (!(0, _eslintCodemodUtils.isNodeOfType)(jsxNode, 'JSXElement')) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Allow passing in the element name because the jsxNode doesn't
|
|
41
|
+
// represent the element name with styled components
|
|
42
|
+
var elName = elementName || ast.JSXElement.getName(jsxNode);
|
|
43
|
+
if (!elName) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Only check native HTML elements, not components
|
|
48
|
+
if (elName[0] !== elName[0].toLowerCase()) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
var supportedElement = supportedElements.find(function (_ref) {
|
|
52
|
+
var name = _ref.name;
|
|
53
|
+
return name === elName;
|
|
54
|
+
});
|
|
55
|
+
if (!supportedElement) {
|
|
56
|
+
supportedElement = supportedElements.find(function (_ref2) {
|
|
57
|
+
var name = _ref2.name;
|
|
58
|
+
return name === '*';
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
if (!supportedElement) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
// Check if the element has any attributes that are not supported
|
|
66
|
+
var attributes = ast.JSXElement.getAttributes(jsxNode);
|
|
67
|
+
if (supportedElement.attributes && !supportedElement.attributes.every(function (_ref3) {
|
|
68
|
+
var name = _ref3.name,
|
|
69
|
+
values = _ref3.values;
|
|
70
|
+
return attributes.some(function (attribute) {
|
|
71
|
+
if (attribute.type === 'JSXSpreadAttribute') {
|
|
72
|
+
return false;
|
|
73
|
+
}
|
|
74
|
+
var isMatchingName = attribute.name.name === name;
|
|
75
|
+
var isMatchingValues = values && attribute.value && attribute.value.type === 'Literal' && typeof attribute.value.value === 'string' && (values === null || values === void 0 ? void 0 : values.includes(attribute.value.value));
|
|
76
|
+
return isMatchingName && isMatchingValues;
|
|
77
|
+
});
|
|
78
|
+
})) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _createRule = require("../utils/create-rule");
|
|
8
|
+
var _nodeTypes = require("./node-types");
|
|
9
|
+
var rule = (0, _createRule.createLintRule)({
|
|
10
|
+
meta: {
|
|
11
|
+
name: 'no-html-select',
|
|
12
|
+
type: 'suggestion',
|
|
13
|
+
hasSuggestions: true,
|
|
14
|
+
docs: {
|
|
15
|
+
description: 'Discourage direct usage of HTML select elements in favor of the Atlassian Design System select component.',
|
|
16
|
+
recommended: true,
|
|
17
|
+
severity: 'warn'
|
|
18
|
+
},
|
|
19
|
+
messages: {
|
|
20
|
+
noHtmlSelect: "This <{{ name }}> should be replaced with the select component from the Atlassian Design System. ADS select components have event tracking, ensure accessible implementations, and provide access to ADS styling features like design tokens."
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
create: function create(context) {
|
|
24
|
+
return {
|
|
25
|
+
// transforms styled.<anchor>(...) usages
|
|
26
|
+
CallExpression: function CallExpression(node) {
|
|
27
|
+
_nodeTypes.StyledComponent.lint(node, {
|
|
28
|
+
context: context
|
|
29
|
+
});
|
|
30
|
+
},
|
|
31
|
+
// transforms <anchor css={...}> usages
|
|
32
|
+
JSXElement: function JSXElement(node) {
|
|
33
|
+
_nodeTypes.JSXElement.lint(node, {
|
|
34
|
+
context: context
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
var _default = exports.default = rule;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
Object.defineProperty(exports, "JSXElement", {
|
|
7
|
+
enumerable: true,
|
|
8
|
+
get: function get() {
|
|
9
|
+
return _jsxElement.JSXElement;
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
Object.defineProperty(exports, "StyledComponent", {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function get() {
|
|
15
|
+
return _styledComponent.StyledComponent;
|
|
16
|
+
}
|
|
17
|
+
});
|
|
18
|
+
var _styledComponent = require("./styled-component");
|
|
19
|
+
var _jsxElement = require("./jsx-element");
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
var _typeof = require("@babel/runtime/helpers/typeof");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.JSXElement = void 0;
|
|
8
|
+
var ast = _interopRequireWildcard(require("../../../../ast-nodes"));
|
|
9
|
+
var _supported = require("../supported");
|
|
10
|
+
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); }
|
|
11
|
+
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
12
|
+
var JSXElement = exports.JSXElement = {
|
|
13
|
+
lint: function lint(node, _ref) {
|
|
14
|
+
var context = _ref.context;
|
|
15
|
+
if (!(0, _supported.isSupportedForLint)(node)) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
var nodeName = ast.JSXElement.getName(node);
|
|
19
|
+
context.report({
|
|
20
|
+
node: node.openingElement,
|
|
21
|
+
messageId: 'noHtmlSelect',
|
|
22
|
+
data: {
|
|
23
|
+
name: nodeName
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.StyledComponent = void 0;
|
|
7
|
+
var _eslintCodemodUtils = require("eslint-codemod-utils");
|
|
8
|
+
var _contextCompat = require("@atlaskit/eslint-utils/context-compat");
|
|
9
|
+
var _getJsxElementByName2 = require("../../../utils/get-jsx-element-by-name");
|
|
10
|
+
var _getStyledComponentCall = require("../../../utils/get-styled-component-call");
|
|
11
|
+
var _supported = require("../supported");
|
|
12
|
+
/* eslint-disable @repo/internal/react/require-jsdoc */
|
|
13
|
+
|
|
14
|
+
var StyledComponent = exports.StyledComponent = {
|
|
15
|
+
lint: function lint(node, _ref) {
|
|
16
|
+
var _getJsxElementByName;
|
|
17
|
+
var context = _ref.context;
|
|
18
|
+
if (!(0, _eslintCodemodUtils.isNodeOfType)(node, 'CallExpression') || !(0, _eslintCodemodUtils.isNodeOfType)(node.callee, 'MemberExpression') || !(0, _eslintCodemodUtils.isNodeOfType)(node.callee.object, 'Identifier') || !(0, _eslintCodemodUtils.isNodeOfType)(node.callee.property, 'Identifier')) {
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
var styles = (0, _getStyledComponentCall.getStyledComponentCall)(node);
|
|
22
|
+
var elementName = node.callee.property.name;
|
|
23
|
+
if (!styles || !(0, _eslintCodemodUtils.isNodeOfType)(styles.id, 'Identifier')) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
var jsxElement = (_getJsxElementByName = (0, _getJsxElementByName2.getJsxElementByName)(styles.id.name, (0, _contextCompat.getScope)(context, node))) === null || _getJsxElementByName === void 0 ? void 0 : _getJsxElementByName.parent;
|
|
27
|
+
if (!jsxElement) {
|
|
28
|
+
// If there's no JSX element, we can't determine if it's being used as an select or not
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (jsxElement && !(0, _supported.isSupportedForLint)(jsxElement, elementName)) {
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
context.report({
|
|
35
|
+
node: styles,
|
|
36
|
+
messageId: 'noHtmlSelect',
|
|
37
|
+
data: {
|
|
38
|
+
name: node.callee.property.name
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
};
|