forked from marko-js-archive/marko-magic
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlasso-attribute-transformer.js
94 lines (78 loc) · 2.85 KB
/
lasso-attribute-transformer.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
"use strict";
const VAR_NODE_NAME = 'asset-var';
const resolve = require('lasso-resolve-from');
module.exports = function transform(el, context) {
var parentNode = el.parentNode;
var alreadyWrapped = parentNode.tagName === VAR_NODE_NAME;
var varNode = alreadyWrapped ? parentNode : context.createNodeForEl(VAR_NODE_NAME);
if(tagAttrs[el.tagName]) el.attributes.forEach(attr => {
if(!tagAttrs[el.tagName+':'+attr.name]) return;
var ids = 0;
var idGen = () => ids++;
var walker = context.createWalker({
enter:(node) => {
let nodeHandler = nodeHandlers[node.type];
if(!nodeHandler) return walker.skip();
if(nodeHandler === true) return;
var value = nodeHandler(node, walker, context, attr, varNode, idGen);
if(value) {
el.setAttributeValue(attr.name, value);
}
}
});
walker.walk(attr.value);
});
if(!alreadyWrapped && varNode.attributes.length) el.wrapWith(varNode);
}
const attrTags = {
src:[ 'audio', 'embed', 'iframe', 'img', 'input', 'script', 'source', 'track', 'video' ],
href:[ 'a', 'area', 'link' ],
data:[ 'object' ],
poster:[ 'video' ],
srcset:[ 'img' ], //something else needs to happen here
background:[ 'body' ]
};
const tagAttrs = Object.keys(attrTags).reduce((tagAttrs, attrName) => {
attrTags[attrName].forEach(tagName => {
tagAttrs[tagName] = true;
tagAttrs[tagName+':'+attrName] = true;
})
return tagAttrs;
}, {});
const nodeHandlers = {
ArrayExpression:true,
ObjectExpression:true,
Property:true,
LogicalExpression:true,
ConditionalExpression:(node, walker) => {
node.consequent = walker.walk(node.consequent);
node.alternate = walker.walk(node.alternate);
walker.skip()
},
Literal:(node, walker, context, attr, varNode, id) => {
var builder = context.builder;
var requireResolve = builder.requireResolve;
var literal = builder.literal;
var memberExpression = builder.memberExpression;
if(isFileSystemPath(node.value, context.dirname)) {
let varName = toVarName(attr.name, id());
varNode.setAttributeValue(varName, literal(node.value));
return memberExpression(varName, 'url');
}
}
}
const protocolPattern = /^[a-z]{2,}\:/i;
function isFileSystemPath(path, dirname) {
if(!path) return false;
if(typeof path !== 'string') return false;
if(protocolPattern.test(path)) return false;
return !!tryResolve(path, dirname);
}
function tryResolve(path, dirname) {
try {
return resolve(dirname, path).path;
} catch(error) {}
}
function toVarName(name, id) {
return '__'+name.replace(/-([a-z])/g, s => s[1].toUpperCase()).replace(/[^0-9a-z]/gi, '')+(id || '');
}