stylelint-taro 4.0.0-alpha.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.
@@ -0,0 +1,98 @@
1
+ import stylelint from 'stylelint'
2
+ import declarationValueIndex from 'stylelint/lib/utils/declarationValueIndex'
3
+ import matchesStringOrRegExp from 'stylelint/lib/utils/matchesStringOrRegExp'
4
+ import optionsMatches from 'stylelint/lib/utils/optionsMatches'
5
+ import validateObjectWithArrayProps from 'stylelint/lib/utils/validateObjectWithArrayProps'
6
+ import validateOptions from 'stylelint/lib/utils/validateOptions'
7
+ import { isBoolean, isRegExp, isString } from 'stylelint/lib/utils/validateTypes'
8
+ import vendor from 'stylelint/lib/utils/vendor'
9
+
10
+ import { findIntersection, log, nameSpace, report, taroDocsUrl } from '../../utils'
11
+
12
+ import type { Rule } from 'stylelint'
13
+
14
+ export const ruleName = nameSpace('declaration-property-value-allowed-list')
15
+
16
+ export const messages = stylelint.utils.ruleMessages(ruleName, {
17
+ rejected: (property, value, platfrom) => log(`"${property}" 暂不支持值 "${value}",受限端: "${platfrom}"`)
18
+ })
19
+
20
+ const meta = {
21
+ // TODO: 使用Taro文档的规则
22
+ url: taroDocsUrl('declaration-property-value-allowed-list'),
23
+ }
24
+
25
+ const rule: Rule = (primary) => {
26
+
27
+ return (root, result) => {
28
+
29
+ const validOptions = Object.keys(primary).every((key) => {
30
+ if (primary[key]) {
31
+ return validateOptions(result, ruleName, {
32
+ actual: primary[key],
33
+ possible: [validateObjectWithArrayProps(isString, isRegExp, isBoolean)],
34
+ })
35
+ }
36
+ return true
37
+ })
38
+
39
+ if (!validOptions) {
40
+ return
41
+ }
42
+
43
+ const { intersection } = findIntersection(primary)
44
+
45
+ Object.keys(intersection).forEach(key => {
46
+ if (intersection[key] === true) {
47
+ delete intersection[key]
48
+ }
49
+ })
50
+ const propKeys = Object.keys(intersection)
51
+
52
+ // 在这里可以添加额外的逻辑
53
+ root.walkDecls(decl => {
54
+ const { prop, value } = decl
55
+
56
+ const unprefixedProp = vendor.unprefixed(prop)
57
+ const propPatterns = propKeys.filter((key) => matchesStringOrRegExp(unprefixedProp, key))
58
+
59
+ if (propPatterns.length === 0) {
60
+ return
61
+ }
62
+
63
+ if (propPatterns.some((pattern) => optionsMatches(intersection, pattern, value))) {
64
+ return
65
+ }
66
+
67
+ const platforms = []
68
+ Object.keys(primary).forEach((platform) => {
69
+ if (primary[platform]) {
70
+ if (propPatterns.some((pattern) => {
71
+ return optionsMatches(primary[platform], pattern, value) || primary[platform][pattern] === true
72
+ })) {
73
+ return
74
+ }
75
+ platforms.push(platform)
76
+ }
77
+ })
78
+
79
+ const index = declarationValueIndex(decl)
80
+ const endIndex = index + decl.value.length
81
+
82
+ report({
83
+ message: messages.rejected(prop, value, platforms.join(', ')),
84
+ node: decl,
85
+ index,
86
+ endIndex,
87
+ result,
88
+ ruleName,
89
+ })
90
+ })
91
+ }
92
+ }
93
+
94
+ rule.ruleName = ruleName
95
+ rule.messages = messages
96
+ rule.meta = meta
97
+
98
+ export default rule
@@ -0,0 +1,11 @@
1
+ import declarationPropertyValueAllowedList from './declaration-property-value-allowed-list'
2
+ import noNestedSelectors from './no-nested-selectors'
3
+ import propertyAllowedList from './property-allowed-list'
4
+
5
+ const rules = {
6
+ 'no-nested-selectors': noNestedSelectors,
7
+ 'property-allowed-list': propertyAllowedList,
8
+ 'declaration-property-value-allowed-list': declarationPropertyValueAllowedList,
9
+ }
10
+
11
+ export default rules
@@ -0,0 +1,46 @@
1
+ import stylelint, { utils } from 'stylelint'
2
+
3
+ import { log, nameSpace, report, taroDocsUrl } from '../../utils'
4
+
5
+ import type { Rule } from 'stylelint'
6
+
7
+ export const ruleName = nameSpace('no-nested-selectors')
8
+
9
+ export const messages = stylelint.utils.ruleMessages(ruleName, {
10
+ rejected: (selector, platfrom) => log(`"${selector}" 仅能使用单个class选择器,受限端 "${platfrom}"`)
11
+ })
12
+
13
+ const meta = {
14
+ // TODO: 使用Taro文档的规则
15
+ url: taroDocsUrl('no-nested-selectors'),
16
+ }
17
+
18
+ const rule: Rule = (primary) => {
19
+ return (root, result) => {
20
+ const validOptions = utils.validateOptions(result, ruleName, {
21
+ actual: primary
22
+ })
23
+ if (!validOptions)
24
+ return
25
+ const platform = ['harmony', 'rn']
26
+
27
+ root.walkRules(ruleNode => {
28
+ const selector = ruleNode.selector
29
+ if (!/^[.#]?[a-zA-Z0-9_-]+$/.test(selector)) {
30
+ report({
31
+ ruleName,
32
+ result,
33
+ node: ruleNode,
34
+ message: messages.rejected(selector, platform.join(', ')),
35
+ })
36
+ }
37
+
38
+ })
39
+ }
40
+ }
41
+
42
+ rule.ruleName = ruleName
43
+ rule.messages = messages
44
+ rule.meta = meta
45
+
46
+ export default rule
@@ -0,0 +1,94 @@
1
+ import _ from 'lodash'
2
+ import stylelint from 'stylelint'
3
+ import isCustomProperty from 'stylelint/lib/utils/isCustomProperty'
4
+ import isStandardSyntaxProperty from 'stylelint/lib/utils/isStandardSyntaxProperty'
5
+ import matchesStringOrRegExp from 'stylelint/lib/utils/matchesStringOrRegExp'
6
+ import validateObjectWithArrayProps from 'stylelint/lib/utils/validateObjectWithArrayProps'
7
+ import validateOptions from 'stylelint/lib/utils/validateOptions'
8
+ import { isBoolean, isRegExp, isString } from 'stylelint/lib/utils/validateTypes'
9
+ import vendor from 'stylelint/lib/utils/vendor'
10
+
11
+ import { log, nameSpace, report, taroDocsUrl } from '../../utils'
12
+
13
+ import type { Rule } from 'stylelint'
14
+
15
+
16
+ export const ruleName = nameSpace('property-allowed-list')
17
+
18
+ export const messages = stylelint.utils.ruleMessages(ruleName, {
19
+ rejected: (property, platfrom) => log(`"${property}" 暂不支持该属性,受限端 "${platfrom}"`)
20
+ })
21
+
22
+ const meta = {
23
+ // TODO: 使用Taro文档的规则
24
+ url: taroDocsUrl('property-allowed-list'),
25
+ }
26
+
27
+ const rule: Rule = (primary) => {
28
+
29
+ return (root, result) => {
30
+ const validOptions = Object.keys(primary).every((key) => {
31
+ if (primary[key]) {
32
+ return validateOptions(result, ruleName, {
33
+ actual: primary[key],
34
+ possible: [validateObjectWithArrayProps(isString, isRegExp, isBoolean)],
35
+ })
36
+ }
37
+ return true
38
+ })
39
+
40
+ if (!validOptions) {
41
+ return
42
+ }
43
+
44
+ const _arr = []
45
+ Object.keys(primary).forEach(key => {
46
+ _arr.push(...Object.keys(primary[key]))
47
+ })
48
+ const intersectionKeys = _.intersection(_arr)
49
+
50
+ // 在这里可以添加额外的逻辑
51
+ root.walkDecls(decl => {
52
+ const prop = decl.prop
53
+
54
+ if (!isStandardSyntaxProperty(prop)) {
55
+ return
56
+ }
57
+
58
+ if (isCustomProperty(prop)) {
59
+ return
60
+ }
61
+
62
+ // either the prefix or unprefixed version is in the list
63
+ if (matchesStringOrRegExp([prop, vendor.unprefixed(prop)], intersectionKeys)) {
64
+ return
65
+ }
66
+
67
+ const platform = []
68
+ Object.keys(primary).forEach(key => {
69
+ if (primary[key]) {
70
+ const platformKeys = Object.keys(primary[key])
71
+ if (platformKeys.length > 0) {
72
+ if (!platformKeys.includes(prop)) {
73
+ platform.push(key)
74
+ }
75
+ }
76
+ }
77
+ })
78
+
79
+ report({
80
+ message: messages.rejected(prop, platform.join(', ')),
81
+ word: prop,
82
+ node: decl,
83
+ result,
84
+ ruleName,
85
+ })
86
+ })
87
+ }
88
+ }
89
+
90
+ rule.ruleName = ruleName
91
+ rule.messages = messages
92
+ rule.meta = meta
93
+
94
+ export default rule
@@ -0,0 +1,69 @@
1
+ import { utils } from 'stylelint'
2
+
3
+ import type { Problem } from 'stylelint'
4
+
5
+ export function taroDocsUrl(_: string) {
6
+ return `https://taro-docs.jd.com/docs/`
7
+ }
8
+
9
+ export function nameSpace(ruleName: string) {
10
+ // 前缀视个人情况而定
11
+ return `taro/${ruleName}`
12
+ }
13
+ export function newMessage(ruleName: string, options) {
14
+ return utils.ruleMessages(ruleName, options)
15
+ }
16
+
17
+ export function report(problem: Problem) {
18
+ return utils.report(problem)
19
+ }
20
+
21
+ export function log(text: string) {
22
+ // vscode下不添加颜色
23
+ if (!process.env.TARO_ENV) {
24
+ return text
25
+ }
26
+ return text
27
+ // return highlightQuotaValue(text)
28
+ }
29
+
30
+ export function findIntersection(data) {
31
+ const keys = Object.keys(data)
32
+ let intersection = {}
33
+
34
+ if (keys.length > 1) {
35
+ const firstKey = keys[0]
36
+ const firstProps = data[firstKey]
37
+
38
+ for (const prop in firstProps) {
39
+ const firstValues = firstProps[prop]
40
+ let commonValues = firstValues || []
41
+
42
+ for (let i = 1; i < keys.length; i++) {
43
+ const currentKey = keys[i]
44
+ const currentProps = data[currentKey]
45
+ const currentValues = currentProps[prop]
46
+
47
+ if (Array.isArray(commonValues)) {
48
+ if (Array.isArray(currentValues)) {
49
+ commonValues = commonValues.filter(value => currentValues.includes(value))
50
+ } else if (currentValues){
51
+ commonValues = commonValues.filter(value => currentValues === true || currentValues.includes(value))
52
+ }
53
+ } else if (commonValues === true) {
54
+ commonValues = currentValues || []
55
+ } else {
56
+ commonValues = []
57
+ }
58
+ }
59
+
60
+ if (commonValues.length > 0) {
61
+ intersection[prop] = commonValues
62
+ }
63
+ }
64
+ } else {
65
+ intersection = data[keys[0]]
66
+ }
67
+
68
+ return { intersection }
69
+ }