提交 5ed424a7 编写于 作者: fxy060608's avatar fxy060608

wip(app): nvue styler

上级 dd99273b
......@@ -107,7 +107,6 @@ export function uniAppNVuePlugin({
const { code, messages } = await parse(source, {
filename,
logLevel: 'WARNING',
combinators: false,
})
messages.forEach((message) => {
if (message.type === 'warning') {
......
......@@ -2,7 +2,6 @@ import { parse } from '../src'
async function objectifierRule(input: string) {
const { code, messages } = await parse(input, {
combinators: true,
logLevel: 'NOTE',
})
return {
......@@ -18,9 +17,9 @@ describe('nvue-styler: combinators', () => {
)
expect(json).toEqual({
bar: {
'!left': 5,
},
'.bar': {
'': {
'!left': 5,
},
'.foo': {
'!left': 0,
'!right': 10,
......@@ -29,7 +28,7 @@ describe('nvue-styler: combinators', () => {
left: 2,
},
},
'.foobar': { '.foo .bar': { left: 1 } },
foobar: { '.foo .bar': { left: 1 } },
})
expect(messages.length).toBe(0)
})
......@@ -41,9 +40,9 @@ describe('nvue-styler: combinators', () => {
)
expect(json).toEqual({
bar: {
left: 5,
},
'.bar': {
'': {
left: 5,
},
[`.foo${type}`]: {
left: 5,
right: 10,
......@@ -52,7 +51,7 @@ describe('nvue-styler: combinators', () => {
left: 2,
},
},
'.foobar': { [`.foo${type}.bar${type}`]: { left: 1 } },
foobar: { [`.foo${type}.bar${type}`]: { left: 1 } },
})
expect(messages.length).toBe(0)
}
......
......@@ -18,10 +18,12 @@ zIndex: 4;
}`)
expect(json).toEqual({
foo: {
color: '#FF0000',
width: 200,
position: 'sticky',
zIndex: 4,
'': {
color: '#FF0000',
width: 200,
position: 'sticky',
zIndex: 4,
},
},
})
expect(messages.length).toBe(0)
......@@ -39,13 +41,15 @@ zIndex: 4;
}`)
expect(json).toEqual({
foo: {
width: '200px',
paddingLeft: 300,
borderWidth: '1pt',
left: 0,
right: '0px',
height: '10rpx',
paddingTop: '11upx',
'': {
width: '200px',
paddingLeft: 300,
borderWidth: '1pt',
left: 0,
right: '0px',
height: '10rpx',
paddingTop: '11upx',
},
},
})
expect(messages[0]).toEqual(
......@@ -75,15 +79,19 @@ zIndex: 4;
`)
expect(json).toEqual({
foo: {
opacity: 1,
'': {
opacity: 1,
},
},
bar: {
opacity: 0.5,
'': {
opacity: 0.5,
},
},
baz: {},
boo: {},
zero: {
opacity: 0,
'': {
opacity: 0,
},
},
})
expect(messages[0]).toEqual(
......@@ -117,13 +125,14 @@ zIndex: 4;
`)
expect(json).toEqual({
foo: {
zIndex: 1,
'': {
zIndex: 1,
},
},
bar: {},
baz: {},
boo: {},
zero: {
zIndex: 0,
'': {
zIndex: 0,
},
},
})
expect(messages[0]).toEqual(
......@@ -171,25 +180,34 @@ zIndex: 4;
`)
expect(json).toEqual({
foo: {
color: '#FF0000',
backgroundColor: '#ff0000',
'': {
color: '#FF0000',
backgroundColor: '#ff0000',
},
},
bar: {
color: '#FF0000',
backgroundColor: '#ff0000',
'': {
color: '#FF0000',
backgroundColor: '#ff0000',
},
},
baz: {
color: '#FF0000',
backgroundColor: '#FFB6C1',
'': {
color: '#FF0000',
backgroundColor: '#FFB6C1',
},
},
rgba: {
color: 'rgb(23,0,255)',
backgroundColor: 'rgba(234,45,99,0.4)',
'': {
color: 'rgb(23,0,255)',
backgroundColor: 'rgba(234,45,99,0.4)',
},
},
transparent: {
color: 'rgba(0,0,0,0)',
'': {
color: 'rgba(0,0,0,0)',
},
},
errRgba: {},
})
expect(messages[0]).toEqual(
expect.objectContaining({
......@@ -233,8 +251,8 @@ zIndex: 4;
.bar { flex-wrap: wrap }
`)
expect(json).toEqual({
foo: { flexWrap: 'nowrap' },
bar: { flexWrap: 'wrap' },
foo: { '': { flexWrap: 'nowrap' } },
bar: { '': { flexWrap: 'wrap' } },
})
expect(messages[0]).toEqual(
expect.objectContaining({
......@@ -275,15 +293,20 @@ zIndex: 4;
},
},
foo: {
transitionProperty: 'marginTop',
'': {
transitionProperty: 'marginTop',
},
},
bar: {
transitionProperty: 'height',
'': {
transitionProperty: 'height',
},
},
foobar: {
transitionProperty: 'marginTop,height',
'': {
transitionProperty: 'marginTop,height',
},
},
baz: {},
})
expect(messages[0]).toEqual(
expect.objectContaining({
......@@ -313,11 +336,15 @@ zIndex: 4;
},
},
foo: {
transitionDuration: 200,
transitionDelay: 500,
'': {
transitionDuration: 200,
transitionDelay: 500,
},
},
bar: {
transitionDuration: 200,
'': {
transitionDuration: 200,
},
},
})
expect(messages[0]).toEqual(
......@@ -358,12 +385,15 @@ zIndex: 4;
},
},
foo: {
transitionTimingFunction: 'ease-in-out',
'': {
transitionTimingFunction: 'ease-in-out',
},
},
bar: {
transitionTimingFunction: 'cubic-bezier(0.88,1,-0.67,1.37)',
'': {
transitionTimingFunction: 'cubic-bezier(0.88,1,-0.67,1.37)',
},
},
baz: {},
})
expect(messages[0]).toEqual(
expect.objectContaining({
......@@ -384,12 +414,14 @@ zIndex: 4;
`)
expect(json).toEqual({
foo: {
backgroundColor: '#ff0000',
abc: 123,
def: '456px',
ghi: '789pt',
AbcDef: 456,
abcDef: 'abc',
'': {
backgroundColor: '#ff0000',
abc: 123,
def: '456px',
ghi: '789pt',
AbcDef: 456,
abcDef: 'abc',
},
},
})
expect(messages[0]).toEqual(
......@@ -428,9 +460,11 @@ zIndex: 4;
`)
expect(json).toEqual({
foo: {
color: '#FF0000',
WebkitTransform: 'rotate(90deg)',
width: '200px',
'': {
color: '#FF0000',
WebkitTransform: 'rotate(90deg)',
width: '200px',
},
},
})
expect(messages[0]).toEqual(
......
......@@ -15,16 +15,18 @@ describe('nvue-styler: parse', () => {
const { json, messages } = await objectifierRoot(code)
expect(json).toEqual({
foo: {
color: '#FF0000',
backgroundColor: 'rgba(255,255,255,0.6)',
WebkitTransform: 'rotate(90deg)',
width: '200px',
left: 0,
right: '0px',
borderWidth: '1pt',
fontWeight: '100',
'': {
color: '#FF0000',
backgroundColor: 'rgba(255,255,255,0.6)',
WebkitTransform: 'rotate(90deg)',
width: '200px',
left: 0,
right: '0px',
borderWidth: '1pt',
fontWeight: '100',
},
},
bar: { backgroundColor: '#FF0000' },
bar: { '': { backgroundColor: '#FF0000' } },
})
expect(messages[0]).toEqual(
expect.objectContaining({
......@@ -54,15 +56,15 @@ describe('nvue-styler: parse', () => {
test('fix prop value', async () => {
const code = '.foo {font-size: 200px;}'
const { json, messages } = await objectifierRoot(code)
expect(json).toEqual({ foo: { fontSize: '200px' } })
expect(json).toEqual({ foo: { '': { fontSize: '200px' } } })
expect(messages.length).toBe(0)
})
test('ensure number type value', async () => {
const code = '.foo {line-height: 40;}\n\n .bar {line-height: 20px;}'
const { json, messages } = await objectifierRoot(code)
expect(json).toEqual({
foo: { lineHeight: 40 },
bar: { lineHeight: '20px' },
foo: { '': { lineHeight: 40 } },
bar: { '': { lineHeight: '20px' } },
})
expect(messages.length).toBe(0)
})
......@@ -71,8 +73,8 @@ describe('nvue-styler: parse', () => {
'.foo, .bar {font-size: 20;}\n\n .foo {color: #ff5000;}\n\n .bar {color: #000000;}'
const { json, messages } = await objectifierRoot(code)
expect(json).toEqual({
foo: { fontSize: 20, color: '#ff5000' },
bar: { fontSize: 20, color: '#000000' },
foo: { '': { fontSize: 20, color: '#ff5000' } },
bar: { '': { fontSize: 20, color: '#000000' } },
})
expect(messages.length).toBe(0)
})
......@@ -81,9 +83,9 @@ describe('nvue-styler: parse', () => {
'.foo, .bar {font-size: 20; color: #000000}\n\n .foo, .bar, .baz {color: #ff5000; height: 30;}'
const { json, messages } = await objectifierRoot(code)
expect(json).toEqual({
foo: { fontSize: 20, color: '#ff5000', height: 30 },
bar: { fontSize: 20, color: '#ff5000', height: 30 },
baz: { color: '#ff5000', height: 30 },
foo: { '': { fontSize: 20, color: '#ff5000', height: 30 } },
bar: { '': { fontSize: 20, color: '#ff5000', height: 30 } },
baz: { '': { color: '#ff5000', height: 30 } },
})
expect(messages.length).toBe(0)
})
......@@ -101,10 +103,12 @@ describe('nvue-styler: parse', () => {
},
},
foo: {
transitionDelay: 200,
transitionDuration: 300,
transitionProperty: 'marginTop',
transitionTimingFunction: 'ease-in',
'': {
transitionDelay: 200,
transitionDuration: 300,
transitionProperty: 'marginTop',
transitionTimingFunction: 'ease-in',
},
},
})
expect(messages[0]).toEqual(
......@@ -134,10 +138,12 @@ describe('nvue-styler: parse', () => {
},
},
foo: {
transitionDelay: 200,
transitionDuration: 300,
transitionProperty: 'transform',
transitionTimingFunction: 'ease-in-out',
'': {
transitionDelay: 200,
transitionDuration: 300,
transitionProperty: 'transform',
transitionTimingFunction: 'ease-in-out',
},
},
})
expect(messages[0]).toEqual(
......@@ -167,10 +173,12 @@ describe('nvue-styler: parse', () => {
},
},
foo: {
transitionDelay: 200,
transitionDuration: 300,
transitionProperty: 'marginTop,height',
transitionTimingFunction: 'ease-in-out',
'': {
transitionDelay: 200,
transitionDuration: 300,
transitionProperty: 'marginTop,height',
transitionTimingFunction: 'ease-in-out',
},
},
})
expect(messages[0]).toEqual(
......@@ -206,21 +214,25 @@ describe('nvue-styler: parse', () => {
},
},
foo: {
fontSize: 20,
color: '#ff5000',
height: 30,
transitionDelay: 200,
transitionDuration: 300,
transitionProperty: 'marginTop',
transitionTimingFunction: 'ease-in',
'': {
fontSize: 20,
color: '#ff5000',
height: 30,
transitionDelay: 200,
transitionDuration: 300,
transitionProperty: 'marginTop',
transitionTimingFunction: 'ease-in',
},
},
bar: {
color: '#ff5000',
height: 30,
transitionDelay: 200,
transitionDuration: 300,
transitionProperty: 'marginTop',
transitionTimingFunction: 'ease-in',
'': {
color: '#ff5000',
height: 30,
transitionDelay: 200,
transitionDuration: 300,
transitionProperty: 'marginTop',
transitionTimingFunction: 'ease-in',
},
},
})
expect(messages[0]).toEqual(
......@@ -250,11 +262,13 @@ describe('nvue-styler: parse', () => {
},
},
foo: {
fontSize: 20,
transitionDelay: 1000,
transitionDuration: 500,
transitionProperty: 'marginTop',
transitionTimingFunction: 'ease-in-out',
'': {
fontSize: 20,
transitionDelay: 1000,
transitionDuration: 500,
transitionProperty: 'marginTop',
transitionTimingFunction: 'ease-in-out',
},
},
})
expect(messages[0]).toEqual(
......@@ -276,24 +290,28 @@ describe('nvue-styler: parse', () => {
const { json } = await objectifierRoot(code)
expect(json).toEqual({
foo: {
paddingTop: '20px',
paddingRight: '20px',
paddingBottom: '20px',
paddingLeft: '20px',
marginTop: '30px',
marginRight: 40,
marginBottom: '30px',
marginLeft: 40,
'': {
paddingTop: '20px',
paddingRight: '20px',
paddingBottom: '20px',
paddingLeft: '20px',
marginTop: '30px',
marginRight: 40,
marginBottom: '30px',
marginLeft: 40,
},
},
bar: {
paddingTop: 10,
paddingRight: '20px',
paddingBottom: '30px',
paddingLeft: 40,
marginTop: '10px',
marginRight: 20,
marginBottom: 30,
marginLeft: 20,
'': {
paddingTop: 10,
paddingRight: '20px',
paddingBottom: '30px',
paddingLeft: 40,
marginTop: '10px',
marginRight: 20,
marginBottom: 30,
marginLeft: 20,
},
},
})
})
......@@ -303,16 +321,20 @@ describe('nvue-styler: parse', () => {
const { json } = await objectifierRoot(code)
expect(json).toEqual({
foo: {
paddingTop: '20px',
paddingRight: '20px',
paddingBottom: '20px',
paddingLeft: '30px',
'': {
paddingTop: '20px',
paddingRight: '20px',
paddingBottom: '20px',
paddingLeft: '30px',
},
},
bar: {
marginTop: '10px',
marginRight: 20,
marginBottom: '30px',
marginLeft: 20,
'': {
marginTop: '10px',
marginRight: 20,
marginBottom: '30px',
marginLeft: 20,
},
},
})
})
......@@ -322,8 +344,10 @@ describe('nvue-styler: parse', () => {
const { json } = await objectifierRoot(code)
expect(json).toEqual({
'class-a': {
color: '#0000ff',
'color:last-child:focus': '#ff0000',
'': {
color: '#0000ff',
'color:last-child:focus': '#ff0000',
},
},
})
})
......
......@@ -5,20 +5,17 @@ import {
SUPPORT_CSS_UNIT,
hyphenateStyleProperty,
isNumber,
COMBINATORS_RE,
} from '../utils'
import { normalizeMap } from './map'
const normalized = Symbol('normalized')
export interface NormalizeOptions {
combinators?: boolean
logLevel?: 'NOTE' | 'WARNING' | 'ERROR'
}
export function normalize(opts: NormalizeOptions = {}): Plugin {
if (!hasOwn(opts, 'combinators')) {
opts.combinators = false
}
if (!hasOwn(opts, 'logLevel')) {
opts.logLevel = 'WARNING'
}
......@@ -27,26 +24,22 @@ export function normalize(opts: NormalizeOptions = {}): Plugin {
Declaration: createDeclarationProcessor(opts),
}
if (__NODE_JS__) {
plugin.Rule = createRuleProcessor(opts)
plugin.Rule = createRuleProcessor()
}
return plugin
}
function createRuleProcessor({ combinators }: NormalizeOptions) {
function createRuleProcessor() {
return (rule: Rule, helper: Helpers) => {
if ((rule as any)[normalized]) {
return
}
const regx = combinators
? /^((?:(?:\.[A-Za-z0-9_\-]+)+[\+\~\> ])*)((?:\.[A-Za-z0-9_\-\:]+)+)$/
: /^(\.)([A-Za-z0-9_\-:]+)$/
rule.selector = rule.selectors
.map((selector) => {
selector = selector
.replace(/\s*([\+\~\>])\s*/g, '$1')
.replace(/\s+/, ' ')
if (regx.test(selector)) {
if (COMBINATORS_RE.test(selector)) {
return selector
}
rule.warn(
......
import { Container, Root, Document } from 'postcss'
import { extend, hasOwn } from '@vue/shared'
import { COMBINATORS_RE } from './utils'
interface ObjectifierContext {
'FONT-FACE': Record<string, unknown>[]
......@@ -63,34 +64,38 @@ function transformSelector(
result: Record<string, unknown | Record<string, unknown>>,
context: ObjectifierContext
) {
let className = selector.slice(1)
const lastDotIndex = className.lastIndexOf('.')
if (lastDotIndex > 0) {
className = className.substring(lastDotIndex + 1)
const res = selector.match(COMBINATORS_RE)
if (!res) {
return
}
const pseudoIndex = className.indexOf(':')
let parentSelector = res[1].trim()
let curSelector = res[2].trim().substring(1)
const pseudoIndex = curSelector.indexOf(':')
if (pseudoIndex > -1) {
const pseudoClass = className.slice(pseudoIndex)
className = className.slice(0, pseudoIndex)
const pseudoClass = curSelector.slice(pseudoIndex)
curSelector = curSelector.slice(0, pseudoIndex)
Object.keys(body).forEach(function (name) {
body[name + pseudoClass] = body[name]
delete body[name]
})
}
transition(className, body, context)
if (lastDotIndex > 0) {
className = '.' + className
result = (result[className] || (result[className] = {})) as Record<
string,
unknown
>
className = selector.substring(0, lastDotIndex + 1).trim()
transition(curSelector, body, context)
if (!Object.keys(body).length) {
return
}
if (result[className]) {
result = (result[curSelector] || (result[curSelector] = {})) as Record<
string,
unknown
>
if (result[parentSelector]) {
// clone
result[className] = processImportant(extend({}, result[className], body))
result[parentSelector] = processImportant(
extend({}, result[parentSelector], body)
)
} else {
result[className] = body
result[parentSelector] = body
}
}
......
import type { Declaration, Source } from 'postcss'
export const COMBINATORS_RE =
/^((?:(?:\.[A-Za-z0-9_\-]+)+[\+\~\> ])*)((?:\.[A-Za-z0-9_\-\:]+)+)$/
export type TransformDecl = (decl: Declaration) => Declaration[]
export type Normalize = (v: string | number) => {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册