Skip to content

Commit

Permalink
Update tests
Browse files Browse the repository at this point in the history
  • Loading branch information
1aron committed Oct 26, 2023
1 parent d0c4c98 commit 434253d
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 66 deletions.
28 changes: 16 additions & 12 deletions packages/css/src/rule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export class Rule {
readonly natives: RuleNative[] = []
readonly order: number = 0
readonly stateToken: string
readonly declarations: CSSDeclarations

animationNames: string[]

Expand All @@ -35,7 +36,7 @@ export class Rule {
declarations?: CSSDeclarations
resolvedPropName?: string
layer?: Layer | CoreLayer,
analyze?(this: Rule, className: string): [valueToken: string, prefixToken?: string]
analyze?: (this: Rule, className: string) => [valueToken: string, prefixToken?: string]
transform?(this: Rule, value: string): string
declare?(this: Rule, value: string, unit: string): CSSDeclarations
delete?(this: Rule, className: string): void
Expand All @@ -44,18 +45,19 @@ export class Rule {
} = {},
public css: MasterCSS
) {
const { layer, unit, colored: configColored, resolvedPropName, analyze, transform, declare, create, order, id } = this.options
const { layer, unit, colored: configColored, resolvedPropName, analyze, transform, declare, create, order, id } = options
this.order = order
if (!this.options.unit) this.options.unit = ''
if (!this.options.separators) this.options.separators = [',']
if (!options.unit) options.unit = ''
if (!options.separators) options.separators = [',']
const { scope, important, functions, themeDriver } = css.config
const { themeNames, colorNames, colors, selectors, mediaQueries, stylesBy, animations } = css
const classNames = stylesBy[className]

if (create) create.call(this, className)

// 1. value / selectorToken
let declarations: CSSDeclarations = this.options.declarations
this.declarations = options.declarations

let hasMultipleThemes: boolean
let prefixToken: string
let stateToken: string
Expand All @@ -77,10 +79,10 @@ export class Rule {

// eslint-disable-next-line @typescript-eslint/no-this-alias
const instance = this
const variables = this.options.resolvedVariables
const variables = options.resolvedVariables
const separators = [',']
if (this.options.separators.length) {
separators.push(...this.options.separators)
if (options.separators.length) {
separators.push(...options.separators)
}
let currentValueToken = ''
let i = 0;
Expand Down Expand Up @@ -667,16 +669,18 @@ export class Rule {
unit = firstValueSplit.unit
}
}
declarations = declare.call(this, unit ? value : newValue, unit || '')
// @ts-ignore
this.declarations = declare.call(this, unit ? value : newValue, unit || '')
} else if (resolvedPropName) {
declarations = {
// @ts-ignore
this.declarations = {
[resolvedPropName as string]: newValue
}
}
}

const propertiesTextByTheme: Record<string, string[]> = {}
for (const eachPropName in declarations) {
for (const eachPropName in this.declarations) {
const push = (theme: string, propertyText: string) => {
// animations
if (
Expand Down Expand Up @@ -707,7 +711,7 @@ export class Rule {
}

const prefix = eachPropName + ':'
const declation = declarations[eachPropName]
const declation = this.declarations[eachPropName]
if (typeof declation === 'object') {
if (Array.isArray(declation)) {
for (const value of declation) {
Expand Down
6 changes: 6 additions & 0 deletions packages/css/tests/rule.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import MasterCSS from '../src'

test('states', () => {
const css = new MasterCSS()
expect(css.create('font:12:hover[disabled]@sm')[0].stateToken).toBe(':hover[disabled]@sm')
})
86 changes: 33 additions & 53 deletions packages/eslint-plugin/lib/rules/class-collision.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@

const areDeclarationsEqual = require('../utils/are-declarations-equal')
const astUtil = require('../utils/ast')
const defineVisitors = require('../utils/define-visitors')
const resolveContext = require('../utils/resolve-context')
const { createValidRules } = require('@master/css-validator')
const CssTree = require('css-tree')

module.exports = {
meta: {
Expand All @@ -18,7 +17,7 @@ module.exports = {
},
fixable: 'code'
},
create: function (context) {
create(context) {
const { options, settings, config } = resolveContext(context)
const visitNode = (node, arg = null) => {
astUtil.parseNodeRecursive(
Expand All @@ -29,69 +28,50 @@ module.exports = {
const sourceCodeLines = sourceCode.lines
const nodeStartLine = node.loc.start.line
const nodeEndLine = node.loc.end.line
const ruleOfClass = {}

const parsedRules = classNames
.map(x => createValidRules(x, { config }))
.map(rules => {
if (rules.length) {
const ruleAst = CssTree.parse(rules[0].text, { parseValue: false })
const ruleStyles = []
CssTree.walk(ruleAst, (cssNode) => {
if (cssNode.type === "Declaration") {
ruleStyles.push({
key: cssNode.property,
value: cssNode.value.value
})
}
})

return {
selector: Object.values(rules[0].vendorSuffixSelectors ?? {})?.[0]?.[0],
mediaToken: rules[0].media?.token,
styles: ruleStyles
}
}
return null
classNames
.forEach(eachClassName => {
ruleOfClass[eachClassName] = createValidRules(eachClassName, { config })[0]
})

for (let i = 0; i < classNames.length ; i++) {
for (let i = 0; i < classNames.length; i++) {
const className = classNames[i]
const parsedRule = parsedRules[i]
const rule = ruleOfClass[className]
const conflicts = []

if (parsedRule && parsedRule.styles.length === 1) {
if (rule) {
for (let j = 0; j < classNames.length; j++) {
const compareClassName = classNames[j]
const compareRule = parsedRules[j]
if (i !== j && compareRule && compareRule.styles.length === 1
&& parsedRule.selector == compareRule.selector
&& parsedRule.mediaToken == compareRule.mediaToken
&& parsedRule.styles[0].key == compareRule.styles[0].key
) {
const compareRule = ruleOfClass[compareClassName]
if (i !== j && compareRule
// 比對兩個 rule 是否具有相同數量及相同屬性的 declarations
&& areDeclarationsEqual(rule.declarations, compareRule.declarations)
&& rule.stateToken === compareRule.stateToken
) {
conflicts.push(compareClassName)
}
}
}

if (conflicts.length > 0) {
const conflictClassNamesMsg = conflicts.map(x => `\`${x}\``).join(' and ')
let fixClassNames = originalClassNamesValue
for (const conflictClassName of conflicts){
const regexSafe = conflictClassName.replace(/(\\|\.|\(|\)|\[|\]|\{|\}|\+|\*|\?|\^|\$|\||\/)/g, '\\$1')
fixClassNames = fixClassNames.replace(new RegExp(`\\s+${regexSafe}|${regexSafe}\\s+`), '')
}

context.report({
loc: astUtil.findLoc(className, sourceCodeLines, nodeStartLine, nodeEndLine),
messageId: 'collisionClass',
data: {
message: `\`${className}\` applies the same CSS declarations as ${conflictClassNamesMsg}.
`,
},
fix: function (fixer) {
return fixer.replaceTextRange([start, end], fixClassNames)
}
})
if (conflicts.length > 0) {
const conflictClassNamesMsg = conflicts.map(x => `\`${x}\``).join(' and ')
let fixClassNames = originalClassNamesValue
for (const conflictClassName of conflicts) {
const regexSafe = conflictClassName.replace(/(\\|\.|\(|\)|\[|\]|\{|\}|\+|\*|\?|\^|\$|\||\/)/g, '\\$1')
fixClassNames = fixClassNames.replace(new RegExp(`\\s+${regexSafe}|${regexSafe}\\s+`), '')
}
context.report({
loc: astUtil.findLoc(className, sourceCodeLines, nodeStartLine, nodeEndLine),
messageId: 'collisionClass',
data: {
message: `\`${className}\` applies the same CSS declarations as ${conflictClassNamesMsg}.
`,
},
fix: function (fixer) {
return fixer.replaceTextRange([start, end], fixClassNames)
}
})
}
}
},
Expand Down
22 changes: 22 additions & 0 deletions packages/eslint-plugin/lib/utils/are-declarations-equal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
function areDeclarationsEqual(aDeclarations, bDeclarations) {
// 获取对象A和B的所有属性名
const aKeys = Object.keys(aDeclarations);
const bKeys = Object.keys(bDeclarations);

// 如果属性数量不相等,返回false
if (aKeys.length !== bKeys.length) {
return false;
}

// 检查对象A的属性是否都存在于对象B中
for (const key of aKeys) {
if (!bDeclarations.hasOwnProperty(key)) {
return false;
}
}

// 如果所有属性都匹配,返回true
return true;
}

module.exports = areDeclarationsEqual
12 changes: 11 additions & 1 deletion packages/eslint-plugin/tests/collision.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,15 @@ new RuleTester({
{ messageId: 'collisionClass' }
]
},
],
{
code: `<div class="m:10@sm m:20@sm m:10@md m:20@md">collision</div>`,
output: `<div class="m:10@sm m:10@md">collision</div>`,
errors: [
{ messageId: 'collisionClass' },
{ messageId: 'collisionClass' },
{ messageId: 'collisionClass' },
{ messageId: 'collisionClass' }
]
}
]
})

0 comments on commit 434253d

Please sign in to comment.