提交 7edd390a 编写于 作者: fxy060608's avatar fxy060608

wip(app): nvue styler

上级 fd6cbab3
......@@ -13,6 +13,20 @@ export function render(_ctx, _cache) {
}"
`;
exports[`app-nvue: compiler <scroll-view data-id="id" scroll-x="true" :show-scrollbar="true"/> 1`] = `
"import { openBlock as _openBlock, createElementBlock as _createElementBlock } from \\"vue\\"
const _hoisted_1 = {
\\"data-id\\": \\"id\\",
scrollX: \\"true\\",
showScrollbar: true
}
export function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(\\"scroll-view\\", _hoisted_1))
}"
`;
exports[`app-nvue: compiler <slider/> 1`] = `
"import { resolveComponent as _resolveComponent, openBlock as _openBlock, createBlock as _createBlock } from \\"vue\\"
......@@ -62,45 +76,44 @@ export function render(_ctx, _cache) {
exports[`app-nvue: compiler <view><text>hello</text></view> 1`] = `
"import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from \\"vue\\"
const _hoisted_1 = [\\"appendAsTree\\"]
const _hoisted_1 = /*#__PURE__*/_createElementVNode(\\"u-text\\", null, \\"hello\\", -1 /* HOISTED */)
const _hoisted_2 = [
_hoisted_1
]
export function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(\\"view\\", null, [
_createElementVNode(\\"u-text\\", { appendAsTree: true }, \\"hello\\", 8 /* PROPS */, _hoisted_1)
]))
return (_openBlock(), _createElementBlock(\\"view\\", null, _hoisted_2))
}"
`;
exports[`app-nvue: compiler <view>hello</view> 1`] = `
"import { createElementVNode as _createElementVNode, openBlock as _openBlock, createElementBlock as _createElementBlock } from \\"vue\\"
const _hoisted_1 = [\\"appendAsTree\\"]
const _hoisted_1 = /*#__PURE__*/_createElementVNode(\\"u-text\\", null, \\"hello\\", -1 /* HOISTED */)
const _hoisted_2 = [
_hoisted_1
]
export function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(\\"view\\", null, [
_createElementVNode(\\"u-text\\", { appendAsTree: true }, \\"hello\\", 8 /* PROPS */, _hoisted_1)
]))
return (_openBlock(), _createElementBlock(\\"view\\", null, _hoisted_2))
}"
`;
exports[`app-nvue: compiler <view>hello{{a}}<view>aaa{{a}}</view>{{b}}</view> 1`] = `
"import { createElementVNode as _createElementVNode, toDisplayString as _toDisplayString, openBlock as _openBlock, createElementBlock as _createElementBlock } from \\"vue\\"
const _hoisted_1 = [\\"appendAsTree\\"]
const _hoisted_2 = [\\"appendAsTree\\"]
const _hoisted_3 = [\\"appendAsTree\\"]
const _hoisted_4 = [\\"appendAsTree\\"]
const _hoisted_5 = [\\"appendAsTree\\"]
const _hoisted_1 = /*#__PURE__*/_createElementVNode(\\"u-text\\", null, \\"hello\\", -1 /* HOISTED */)
const _hoisted_2 = /*#__PURE__*/_createElementVNode(\\"u-text\\", null, \\"aaa\\", -1 /* HOISTED */)
export function render(_ctx, _cache) {
return (_openBlock(), _createElementBlock(\\"view\\", null, [
_createElementVNode(\\"u-text\\", { appendAsTree: true }, \\"hello\\", 8 /* PROPS */, _hoisted_1),
_createElementVNode(\\"u-text\\", { appendAsTree: true }, _toDisplayString(_ctx.a), 9 /* TEXT, PROPS */, _hoisted_2),
_hoisted_1,
_createElementVNode(\\"u-text\\", null, _toDisplayString(_ctx.a), 1 /* TEXT */),
_createElementVNode(\\"view\\", null, [
_createElementVNode(\\"u-text\\", { appendAsTree: true }, \\"aaa\\", 8 /* PROPS */, _hoisted_3),
_createElementVNode(\\"u-text\\", { appendAsTree: true }, _toDisplayString(_ctx.a), 9 /* TEXT, PROPS */, _hoisted_4)
_hoisted_2,
_createElementVNode(\\"u-text\\", null, _toDisplayString(_ctx.a), 1 /* TEXT */)
]),
_createElementVNode(\\"u-text\\", { appendAsTree: true }, _toDisplayString(_ctx.b), 9 /* TEXT, PROPS */, _hoisted_5)
_createElementVNode(\\"u-text\\", null, _toDisplayString(_ctx.b), 1 /* TEXT */)
]))
}"
`;
import { NVUE_U_BUILT_IN_TAGS } from '@dcloudio/uni-shared'
import {
DirectiveNode,
ElementNode,
ElementTypes,
findDir,
findProp,
SimpleExpressionNode,
} from '@vue/compiler-core'
import { compileTemplate } from '@vue/compiler-sfc'
......@@ -41,6 +39,7 @@ const codes = [
`<input v-model="text"/>`,
`<textarea v-model="text"/>`,
`<slider/>`,
`<scroll-view data-id="id" scroll-x="true" :show-scrollbar="true"/>`,
]
describe('app-nvue: compiler', () => {
......@@ -58,25 +57,25 @@ describe('app-nvue: compiler', () => {
test('scroll-view', () => {
genAst(`<view></view>`)
})
test('render-whole', () => {
expect(
(
(
findProp(
genAst(`<view :render-whole="true">hello</view>`),
'appendAsTree',
true,
false
) as DirectiveNode
).arg as SimpleExpressionNode
).content
).toBe('appendAsTree')
})
test('unitary tag', () => {
expect(
findProp(genAst(`<text>hello</text>`), 'appendAsTree', true, false)
).toBeTruthy()
})
// test('render-whole', () => {
// expect(
// (
// (
// findProp(
// genAst(`<view :render-whole="true">hello</view>`),
// 'appendAsTree',
// true,
// false
// ) as DirectiveNode
// ).arg as SimpleExpressionNode
// ).content
// ).toBe('appendAsTree')
// })
// test('unitary tag', () => {
// expect(
// findProp(genAst(`<text>hello</text>`), 'appendAsTree', true, false)
// ).toBeTruthy()
// })
test('tap=>click', () => {
expect(
(
......
......@@ -2,6 +2,7 @@ import type { PreRenderedChunk } from 'rollup'
import type { Plugin } from 'vite'
import path from 'path'
import colors from 'picocolors'
import { defaultNVueRpx2Unit } from '@dcloudio/uni-shared'
import {
APP_SERVICE_FILENAME,
commonjsProxyRE,
......@@ -18,16 +19,16 @@ import {
} from '@dcloudio/uni-cli-shared'
import { parse } from '@dcloudio/uni-nvue-styler'
import { nvueOutDir } from '../../utils'
import { transformRenderWhole } from './transforms/transformRenderWhole'
import { transformAppendAsTree } from './transforms/transformAppendAsTree'
// import { transformRenderWhole } from './transforms/transformRenderWhole'
// import { transformAppendAsTree } from './transforms/transformAppendAsTree'
import { transformVideo } from './transforms/transformVideo'
import { transformText } from './transforms/transformText'
import { createConfigResolved } from '../../plugin/configResolved'
import { defaultNVueRpx2Unit } from '@dcloudio/uni-shared'
import { external, globals } from '../utils'
import { transformRootNode } from './transforms/transformRootNode'
import { transformModel } from './transforms/vModel'
import { transformShow } from './transforms/vShow'
import { transformAttrs } from './transforms/transformAttrs'
const uTags = {
text: 'u-text',
......@@ -44,10 +45,11 @@ export function initNVueNodeTransforms() {
return [
transformRootNode,
createTransformTag(uTags),
transformAttrs,
transformText,
transformVideo,
transformRenderWhole,
transformAppendAsTree,
// transformRenderWhole,
// transformAppendAsTree,
]
}
......
import {
isDirectiveNode,
isElementNode,
isSimpleExpressionNode,
} from '@dcloudio/uni-cli-shared'
import { isAppNVueNativeTag } from '@dcloudio/uni-shared'
import { NodeTransform } from '@vue/compiler-core'
import { camelize } from '@vue/shared'
/**
* 将内置组件属性调整为驼峰
* @param node
* @param context
* @returns
*/
export const transformAttrs: NodeTransform = (node, context) => {
if (!isElementNode(node)) {
return
}
if (!isAppNVueNativeTag(node.tag)) {
return
}
node.props.forEach((prop) => {
if (isDirectiveNode(prop)) {
const { arg } = prop
if (arg && isSimpleExpressionNode(arg)) {
arg.content = normalizePropName(arg.content)
}
} else {
prop.name = normalizePropName(prop.name)
}
})
}
function normalizePropName(name: string) {
if (name.startsWith('data-')) {
return name
}
return camelize(name)
}
......@@ -5587,7 +5587,8 @@ function baseCreateRenderer(options, createHydrationFns) {
if ('value' in props) {
hostPatchProp(el, 'value', null, props.value);
// fixed by xxxxxx
hostPatchProp(el, 'value', null, props.value, false, [], parentComponent);
}
if (vnodeHook = props.onVnodeBeforeMount) {
......@@ -5733,7 +5734,8 @@ function baseCreateRenderer(options, createHydrationFns) {
/* CLASS */
) {
if (oldProps.class !== newProps.class) {
hostPatchProp(el, 'class', null, newProps.class, isSVG);
// fixed by xxxxxx
hostPatchProp(el, 'class', null, newProps.class, isSVG, [], parentComponent);
}
} // style
// this flag is matched when the element has dynamic style bindings
......@@ -5742,7 +5744,8 @@ function baseCreateRenderer(options, createHydrationFns) {
if (patchFlag & 4
/* STYLE */
) {
hostPatchProp(el, 'style', oldProps.style, newProps.style, isSVG);
// fixed by xxxxxx
hostPatchProp(el, 'style', oldProps.style, newProps.style, isSVG, [], parentComponent);
} // props
// This flag is matched when the element has dynamic prop/attr bindings
// other than class and style. The keys of dynamic prop/attrs are saved for
......@@ -5839,7 +5842,8 @@ function baseCreateRenderer(options, createHydrationFns) {
}
if ('value' in newProps) {
hostPatchProp(el, 'value', oldProps.value, newProps.value);
// fixed by xxxxxx
hostPatchProp(el, 'value', oldProps.value, newProps.value, false, [], parentComponent);
}
}
};
......@@ -9329,19 +9333,10 @@ function isMatchParentSelector(parentSelector, el) {
var item = classArray[i];
var type = item[item.length - 1];
var className = item.replace(TYPE_RE, '');
var property = PROPERTY_PARENT_NODE;
var recurse = true;
if (type === '>') {
recurse = false;
} else if (type === '+') {
property = PROPERTY_PREVIOUS_SIBLING;
recurse = false;
} else if (type === '~') {
property = PROPERTY_PREVIOUS_SIBLING;
}
if (type === '~' || type === ' ') {
var property = type === '~' ? PROPERTY_PREVIOUS_SIBLING : PROPERTY_PARENT_NODE;
if (recurse) {
while (el) {
el = el[property];
......@@ -9354,7 +9349,11 @@ function isMatchParentSelector(parentSelector, el) {
return false;
}
} else {
el = el && el[property];
if (type === '>') {
el = el && el[PROPERTY_PARENT_NODE];
} else if (type === '+') {
el = el && el[PROPERTY_PREVIOUS_SIBLING];
}
if (!hasClass(className, el)) {
return false;
......
......@@ -4498,7 +4498,8 @@ function baseCreateRenderer(options, createHydrationFns) {
if ('value' in props) {
hostPatchProp(el, 'value', null, props.value);
// fixed by xxxxxx
hostPatchProp(el, 'value', null, props.value, false, [], parentComponent);
}
if (vnodeHook = props.onVnodeBeforeMount) {
......@@ -4616,7 +4617,8 @@ function baseCreateRenderer(options, createHydrationFns) {
/* CLASS */
) {
if (oldProps.class !== newProps.class) {
hostPatchProp(el, 'class', null, newProps.class, isSVG);
// fixed by xxxxxx
hostPatchProp(el, 'class', null, newProps.class, isSVG, [], parentComponent);
}
} // style
// this flag is matched when the element has dynamic style bindings
......@@ -4625,7 +4627,8 @@ function baseCreateRenderer(options, createHydrationFns) {
if (patchFlag & 4
/* STYLE */
) {
hostPatchProp(el, 'style', oldProps.style, newProps.style, isSVG);
// fixed by xxxxxx
hostPatchProp(el, 'style', oldProps.style, newProps.style, isSVG, [], parentComponent);
} // props
// This flag is matched when the element has dynamic prop/attr bindings
// other than class and style. The keys of dynamic prop/attrs are saved for
......@@ -4722,7 +4725,8 @@ function baseCreateRenderer(options, createHydrationFns) {
}
if ('value' in newProps) {
hostPatchProp(el, 'value', oldProps.value, newProps.value);
// fixed by xxxxxx
hostPatchProp(el, 'value', oldProps.value, newProps.value, false, [], parentComponent);
}
}
};
......@@ -7596,19 +7600,10 @@ function isMatchParentSelector(parentSelector, el) {
var item = classArray[i];
var type = item[item.length - 1];
var className = item.replace(TYPE_RE, '');
var property = PROPERTY_PARENT_NODE;
var recurse = true;
if (type === '>') {
recurse = false;
} else if (type === '+') {
property = PROPERTY_PREVIOUS_SIBLING;
recurse = false;
} else if (type === '~') {
property = PROPERTY_PREVIOUS_SIBLING;
}
if (type === '~' || type === ' ') {
var property = type === '~' ? PROPERTY_PREVIOUS_SIBLING : PROPERTY_PARENT_NODE;
if (recurse) {
while (el) {
el = el[property];
......@@ -7621,7 +7616,11 @@ function isMatchParentSelector(parentSelector, el) {
return false;
}
} else {
el = el && el[property];
if (type === '>') {
el = el && el[PROPERTY_PARENT_NODE];
} else if (type === '+') {
el = el && el[PROPERTY_PREVIOUS_SIBLING];
}
if (!hasClass(className, el)) {
return false;
......
......@@ -4622,7 +4622,8 @@ function baseCreateRenderer(options, createHydrationFns) {
* affect non-DOM renderers)
*/
if ('value' in props) {
hostPatchProp(el, 'value', null, props.value);
// fixed by xxxxxx
hostPatchProp(el, 'value', null, props.value, false, [], parentComponent);
}
if ((vnodeHook = props.onVnodeBeforeMount)) {
invokeVNodeHook(vnodeHook, parentComponent, vnode);
......@@ -4743,13 +4744,15 @@ function baseCreateRenderer(options, createHydrationFns) {
// this flag is matched when the element has dynamic class bindings.
if (patchFlag & 2 /* CLASS */) {
if (oldProps.class !== newProps.class) {
hostPatchProp(el, 'class', null, newProps.class, isSVG);
// fixed by xxxxxx
hostPatchProp(el, 'class', null, newProps.class, isSVG, [], parentComponent);
}
}
// style
// this flag is matched when the element has dynamic style bindings
if (patchFlag & 4 /* STYLE */) {
hostPatchProp(el, 'style', oldProps.style, newProps.style, isSVG);
// fixed by xxxxxx
hostPatchProp(el, 'style', oldProps.style, newProps.style, isSVG, [], parentComponent);
}
// props
// This flag is matched when the element has dynamic prop/attr bindings
......@@ -4841,7 +4844,8 @@ function baseCreateRenderer(options, createHydrationFns) {
}
}
if ('value' in newProps) {
hostPatchProp(el, 'value', oldProps.value, newProps.value);
// fixed by xxxxxx
hostPatchProp(el, 'value', oldProps.value, newProps.value, false, [], parentComponent);
}
}
};
......@@ -7813,19 +7817,8 @@ function isMatchParentSelector(parentSelector, el) {
const item = classArray[i];
const type = item[item.length - 1];
const className = item.replace(TYPE_RE, '');
let property = PROPERTY_PARENT_NODE;
let recurse = true;
if (type === '>') {
recurse = false;
}
else if (type === '+') {
property = PROPERTY_PREVIOUS_SIBLING;
recurse = false;
}
else if (type === '~') {
property = PROPERTY_PREVIOUS_SIBLING;
}
if (recurse) {
if (type === '~' || type === ' ') {
const property = type === '~' ? PROPERTY_PREVIOUS_SIBLING : PROPERTY_PARENT_NODE;
while (el) {
el = el[property];
if (hasClass(className, el)) {
......@@ -7837,7 +7830,12 @@ function isMatchParentSelector(parentSelector, el) {
}
}
else {
el = el && el[property];
if (type === '>') {
el = el && el[PROPERTY_PARENT_NODE];
}
else if (type === '+') {
el = el && el[PROPERTY_PREVIOUS_SIBLING];
}
if (!hasClass(className, el)) {
return false;
}
......
......@@ -11,24 +11,43 @@ async function objectifierRule(input: string) {
}
describe('nvue-styler: combinators', () => {
test('compound', async () => {
const { json, messages } = await objectifierRule(`.a.b{left:0}`)
expect(json).toEqual({ a: { '.b': { left: 0 } } })
expect(messages.length).toBe(0)
const res = await objectifierRule(`.a .b.c.d{left:0}`)
expect(res.json).toEqual({ b: { '.a .c.d': { left: 0 } } })
expect(res.messages.length).toBe(0)
const res1 = await objectifierRule(
`.a .b .c.d.e{left:0} .c{left:1} .a .c{left:2}`
)
expect(res1.json).toEqual({
c: { '.a .b .d.e': { left: 0 }, '': { left: 1 }, '.a ': { left: 2 } },
})
expect(res1.messages.length).toBe(0)
const res2 = await objectifierRule(`.a .b .c.d.e .f{left:0}`)
expect(res2.json).toEqual({ f: { '.a .b .c.d.e ': { left: 0 } } })
expect(res2.messages.length).toBe(0)
})
test('descendant', async () => {
const { json, messages } = await objectifierRule(
` .bar {left:5!important;}.foo .bar {left: 0!important;}.foo .bar{left:5;right:5;right:10!important}.bar .bar{left:2}.foo .bar .foobar{left:1}`
)
expect(json).toEqual({
bar: {
'': {
'!left': 5,
},
'.foo': {
'.foo ': {
'!left': 0,
'!right': 10,
},
'.bar': {
'.bar ': {
left: 2,
},
},
foobar: { '.foo .bar': { left: 1 } },
foobar: { '.foo .bar ': { left: 1 } },
})
expect(messages.length).toBe(0)
})
......
......@@ -8,7 +8,7 @@ async function objectifierRule(input: string) {
}
}
describe('nvue-styler: parse', () => {
describe('nvue-styler: normalize', () => {
test('basic', async () => {
const { json, messages } = await objectifierRule(`.foo{
color: #FF0000;
......@@ -42,11 +42,11 @@ zIndex: 4;
expect(json).toEqual({
foo: {
'': {
width: '200px',
width: 200,
paddingLeft: 300,
borderWidth: '1pt',
left: 0,
right: '0px',
right: 0,
height: '10rpx',
paddingTop: '11upx',
},
......@@ -463,7 +463,7 @@ zIndex: 4;
'': {
color: '#FF0000',
WebkitTransform: 'rotate(90deg)',
width: '200px',
width: 200,
},
},
})
......
......@@ -8,7 +8,7 @@ async function objectifierRoot(input: string) {
}
}
describe('nvue-styler: parse', () => {
describe('nvue-styler: objectifier', () => {
test('basic', async () => {
const code =
'html {color: #000000;}\n\n.foo {color: red; background-color: rgba(255,255,255,0.6); -webkit-transform: rotate(90deg); width: 200px; left: 0; right: 0px; border-width: 1pt; font-weight: 100}\n\n.bar {background: red}'
......@@ -19,9 +19,9 @@ describe('nvue-styler: parse', () => {
color: '#FF0000',
backgroundColor: 'rgba(255,255,255,0.6)',
WebkitTransform: 'rotate(90deg)',
width: '200px',
width: 200,
left: 0,
right: '0px',
right: 0,
borderWidth: '1pt',
fontWeight: '100',
},
......@@ -56,7 +56,7 @@ 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: 200 } } })
expect(messages.length).toBe(0)
})
test('ensure number type value', async () => {
......@@ -64,7 +64,7 @@ describe('nvue-styler: parse', () => {
const { json, messages } = await objectifierRoot(code)
expect(json).toEqual({
foo: { '': { lineHeight: 40 } },
bar: { '': { lineHeight: '20px' } },
bar: { '': { lineHeight: 20 } },
})
expect(messages.length).toBe(0)
})
......@@ -291,23 +291,23 @@ describe('nvue-styler: parse', () => {
expect(json).toEqual({
foo: {
'': {
paddingTop: '20px',
paddingRight: '20px',
paddingBottom: '20px',
paddingLeft: '20px',
marginTop: '30px',
paddingTop: 20,
paddingRight: 20,
paddingBottom: 20,
paddingLeft: 20,
marginTop: 30,
marginRight: 40,
marginBottom: '30px',
marginBottom: 30,
marginLeft: 40,
},
},
bar: {
'': {
paddingTop: 10,
paddingRight: '20px',
paddingBottom: '30px',
paddingRight: 20,
paddingBottom: 30,
paddingLeft: 40,
marginTop: '10px',
marginTop: 10,
marginRight: 20,
marginBottom: 30,
marginLeft: 20,
......@@ -322,17 +322,17 @@ describe('nvue-styler: parse', () => {
expect(json).toEqual({
foo: {
'': {
paddingTop: '20px',
paddingRight: '20px',
paddingBottom: '20px',
paddingLeft: '30px',
paddingTop: 20,
paddingRight: 20,
paddingBottom: 20,
paddingLeft: 30,
},
},
bar: {
'': {
marginTop: '10px',
marginTop: 10,
marginRight: 20,
marginBottom: '30px',
marginBottom: 30,
marginLeft: 20,
},
},
......
......@@ -12,7 +12,7 @@ export const normalizeLength: Normalize = (v: string | number) => {
if (match) {
var unit = match[1]
if (!unit) {
if (!unit || unit === 'px') {
return { value: parseFloat(v) }
} else if (SUPPORT_CSS_UNIT.indexOf(unit) > -1) {
return { value: v }
......
......@@ -68,8 +68,14 @@ function transformSelector(
if (!res) {
return
}
let parentSelector = res[1].trim()
let curSelector = res[2].trim().substring(1)
let parentSelector = res[1]
let curSelector = res[2].substring(1)
// .a.b => a.b
const dotIndex = curSelector.indexOf('.')
if (dotIndex > -1) {
parentSelector += curSelector.substring(dotIndex)
curSelector = curSelector.substring(0, dotIndex)
}
const pseudoIndex = curSelector.indexOf(':')
if (pseudoIndex > -1) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册