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.
- package/LICENSE +160 -0
- package/README.md +114 -0
- package/lib/config.js +121 -0
- package/lib/index.js +12 -0
- package/lib/platform/constrant.js +7 -0
- package/lib/platform/h5.js +4 -0
- package/lib/platform/harmony.js +107 -0
- package/lib/platform/miniprogram.js +4 -0
- package/lib/platform/rn.js +29 -0
- package/lib/platform/type.js +2 -0
- package/lib/rules/declaration-property-value-allowed-list/index.js +83 -0
- package/lib/rules/index.js +14 -0
- package/lib/rules/no-nested-selectors/index.js +61 -0
- package/lib/rules/property-allowed-list/index.js +81 -0
- package/lib/utils/index.js +69 -0
- package/package.json +66 -0
- package/src/config.ts +136 -0
- package/src/index.ts +10 -0
- package/src/platform/constrant.ts +4 -0
- package/src/platform/h5.ts +7 -0
- package/src/platform/harmony.ts +108 -0
- package/src/platform/miniprogram.ts +7 -0
- package/src/platform/rn.ts +31 -0
- package/src/platform/type.ts +9 -0
- package/src/rules/declaration-property-value-allowed-list/index.ts +98 -0
- package/src/rules/index.ts +11 -0
- package/src/rules/no-nested-selectors/index.ts +46 -0
- package/src/rules/property-allowed-list/index.ts +94 -0
- package/src/utils/index.ts +69 -0
|
@@ -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
|
+
}
|