import { createCompoundExpression, createSimpleExpression, NodeTransform, NodeTypes, SimpleExpressionNode } from '@vue/compiler-core' import { parseUrl } from './templateUtils' const srcsetTags = ['img', 'source'] interface ImageCandidate { url: string descriptor: string } // http://w3c.github.io/html/semantics-embedded-content.html#ref-for-image-candidate-string-5 const escapedSpaceCharacters = /( |\\t|\\n|\\f|\\r)+/g export const transformSrcset: NodeTransform = (node, context) => { if (node.type === NodeTypes.ELEMENT) { if (srcsetTags.includes(node.tag) && node.props.length) { node.props.forEach((attr, index) => { if (attr.name === 'srcset' && attr.type === NodeTypes.ATTRIBUTE) { if (!attr.value) return // same logic as in transform-require.js const value = attr.value.content const imageCandidates: ImageCandidate[] = value.split(',').map(s => { // The attribute value arrives here with all whitespace, except // normal spaces, represented by escape sequences const [url, descriptor] = s .replace(escapedSpaceCharacters, ' ') .trim() .split(' ', 2) return { url, descriptor } }) const compoundExpression = createCompoundExpression([], attr.loc) imageCandidates.forEach(({ url, descriptor }, index) => { const { path } = parseUrl(url) let exp: SimpleExpressionNode if (path) { const importsArray = Array.from(context.imports) const existingImportsIndex = importsArray.findIndex( i => i.path === path ) if (existingImportsIndex > -1) { exp = createSimpleExpression( `_imports_${existingImportsIndex}`, false, attr.loc, true ) } else { exp = createSimpleExpression( `_imports_${importsArray.length}`, false, attr.loc, true ) context.imports.add({ exp, path }) } compoundExpression.children.push(exp) } const isNotLast = imageCandidates.length - 1 > index if (descriptor && isNotLast) { compoundExpression.children.push(` + '${descriptor}, ' + `) } else if (descriptor) { compoundExpression.children.push(` + '${descriptor}'`) } else if (isNotLast) { compoundExpression.children.push(` + ', ' + `) } }) node.props[index] = { type: NodeTypes.DIRECTIVE, name: 'bind', arg: createSimpleExpression('srcset', true, attr.loc), exp: context.hoist(compoundExpression), modifiers: [], loc: attr.loc } } }) } } }