wip: drop class opt for now + move lazy requires to utils

This commit is contained in:
Evan You 2019-09-30 13:13:32 -04:00
parent 46bd9dbab0
commit 7ee07447c5
3 changed files with 46 additions and 39 deletions

View File

@ -268,10 +268,8 @@ function dedupeProperties(properties: Property[]): Property[] {
const name = prop.key.content const name = prop.key.content
const existing = knownProps[name] const existing = knownProps[name]
if (existing) { if (existing) {
if (name.startsWith('on') || name === 'style') { if (name.startsWith('on') || name === 'style' || name === 'class') {
mergeAsArray(existing, prop) mergeAsArray(existing, prop)
} else if (name === 'class') {
mergeClasses(existing, prop)
} }
// unexpected duplicate, should have emitted error during parse // unexpected duplicate, should have emitted error during parse
} else { } else {
@ -293,13 +291,6 @@ function mergeAsArray(existing: Property, incoming: Property) {
} }
} }
// Merge dynamic and static class into a single prop
// :class="expression" class="string"
// -> class: expression + "string"
function mergeClasses(existing: Property, incoming: Property) {
// TODO
}
function createDirectiveArgs( function createDirectiveArgs(
dir: DirectiveNode, dir: DirectiveNode,
context: TransformContext context: TransformContext

View File

@ -7,9 +7,6 @@
// - This transform is only applied in non-browser builds because it relies on // - This transform is only applied in non-browser builds because it relies on
// an additional JavaScript parser. In the browser, there is no source-map // an additional JavaScript parser. In the browser, there is no source-map
// support and the code is wrapped in `with (this) { ... }`. // support and the code is wrapped in `with (this) { ... }`.
import { parseScript } from 'meriyah'
import { walk } from 'estree-walker'
import { NodeTransform, TransformContext } from '../transform' import { NodeTransform, TransformContext } from '../transform'
import { import {
NodeTypes, NodeTypes,
@ -20,7 +17,12 @@ import {
createCompoundExpression createCompoundExpression
} from '../ast' } from '../ast'
import { Node, Function, Identifier, Property } from 'estree' import { Node, Function, Identifier, Property } from 'estree'
import { advancePositionWithClone, isSimpleIdentifier } from '../utils' import {
advancePositionWithClone,
isSimpleIdentifier,
parseJS,
walkJS
} from '../utils'
export const transformExpression: NodeTransform = (node, context) => { export const transformExpression: NodeTransform = (node, context) => {
if (node.type === NodeTypes.INTERPOLATION) { if (node.type === NodeTypes.INTERPOLATION) {
@ -39,22 +41,13 @@ export const transformExpression: NodeTransform = (node, context) => {
dir.exp = processExpression(exp, context, dir.name === 'slot') dir.exp = processExpression(exp, context, dir.name === 'slot')
} }
if (arg && !arg.isStatic) { if (arg && !arg.isStatic) {
if (dir.name === 'class') { dir.arg = processExpression(arg, context)
// TODO special expression optimization for classes
dir.arg = processExpression(arg, context)
} else {
dir.arg = processExpression(arg, context)
}
} }
} }
} }
} }
} }
// cache node requires
let _parseScript: typeof parseScript
let _walk: typeof walk
interface PrefixMeta { interface PrefixMeta {
prefix?: string prefix?: string
start: number start: number
@ -83,18 +76,12 @@ export function processExpression(
return node return node
} }
// lazy require dependencies so that they don't end up in rollup's dep graph
// and thus can be tree-shaken in browser builds.
const parseScript =
_parseScript || (_parseScript = require('meriyah').parseScript)
const walk = _walk || (_walk = require('estree-walker').walk)
let ast: any let ast: any
// if the expression is supposed to be used in a function params position // if the expression is supposed to be used in a function params position
// we need to parse it differently. // we need to parse it differently.
const source = `(${node.content})${asParams ? `=>{}` : ``}` const source = `(${node.content})${asParams ? `=>{}` : ``}`
try { try {
ast = parseScript(source, { ranges: true }) ast = parseJS(source, { ranges: true })
} catch (e) { } catch (e) {
context.onError(e) context.onError(e)
return node return node
@ -104,7 +91,7 @@ export function processExpression(
const knownIds = Object.create(context.identifiers) const knownIds = Object.create(context.identifiers)
// walk the AST and look for identifiers that need to be prefixed with `_ctx.`. // walk the AST and look for identifiers that need to be prefixed with `_ctx.`.
walk(ast, { walkJS(ast, {
enter(node: Node & PrefixMeta, parent) { enter(node: Node & PrefixMeta, parent) {
if (node.type === 'Identifier') { if (node.type === 'Identifier') {
if (!ids.includes(node)) { if (!ids.includes(node)) {
@ -126,7 +113,7 @@ export function processExpression(
// walk function expressions and add its arguments to known identifiers // walk function expressions and add its arguments to known identifiers
// so that we don't prefix them // so that we don't prefix them
node.params.forEach(p => node.params.forEach(p =>
walk(p, { walkJS(p, {
enter(child, parent) { enter(child, parent) {
if ( if (
child.type === 'Identifier' && child.type === 'Identifier' &&
@ -182,21 +169,24 @@ export function processExpression(
const children: CompoundExpressionNode['children'] = [] const children: CompoundExpressionNode['children'] = []
ids.sort((a, b) => a.start - b.start) ids.sort((a, b) => a.start - b.start)
ids.forEach((id, i) => { ids.forEach((id, i) => {
// range is offset by -1 due to the wrapping parens when parsed
const start = id.start - 1
const end = id.end - 1
const last = ids[i - 1] as any const last = ids[i - 1] as any
const leadingText = full.slice(last ? last.end - 1 : 0, id.start - 1) const leadingText = full.slice(last ? last.end - 1 : 0, start)
if (leadingText.length || id.prefix) { if (leadingText.length || id.prefix) {
children.push(leadingText + (id.prefix || ``)) children.push(leadingText + (id.prefix || ``))
} }
const source = full.slice(id.start - 1, id.end - 1) const source = full.slice(start, end)
children.push( children.push(
createSimpleExpression(id.name, false, { createSimpleExpression(id.name, false, {
source, source,
start: advancePositionWithClone(node.loc.start, source, id.start - 1), start: advancePositionWithClone(node.loc.start, source, start),
end: advancePositionWithClone(node.loc.start, source, id.end - 1) end: advancePositionWithClone(node.loc.start, source, end)
}) })
) )
if (i === ids.length - 1 && id.end - 1 < full.length) { if (i === ids.length - 1 && end < full.length) {
children.push(full.slice(id.end - 1)) children.push(full.slice(end))
} }
}) })

View File

@ -1,4 +1,30 @@
import { SourceLocation, Position } from './ast' import { SourceLocation, Position } from './ast'
import { parseScript } from 'meriyah'
import { walk } from 'estree-walker'
// cache node requires
// lazy require dependencies so that they don't end up in rollup's dep graph
// and thus can be tree-shaken in browser builds.
let _parseScript: typeof parseScript
let _walk: typeof walk
export const parseJS: typeof parseScript = (code: string, options: any) => {
assert(
!__BROWSER__,
`Expression AST analysis can only be performed in non-browser builds.`
)
const parse = _parseScript || (_parseScript = require('meriyah').parseScript)
return parse(code, options)
}
export const walkJS: typeof walk = (ast, walker) => {
assert(
!__BROWSER__,
`Expression AST analysis can only be performed in non-browser builds.`
)
const walk = _walk || (_walk = require('estree-walker').walk)
return walk(ast, walker)
}
export const isSimpleIdentifier = (name: string): boolean => export const isSimpleIdentifier = (name: string): boolean =>
!/^\d|[^\w]/.test(name) !/^\d|[^\w]/.test(name)