"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = collectDependencies; exports.parseFuncIRI = parseFuncIRI; function _posthtml() { const data = _interopRequireDefault(require("posthtml")); _posthtml = function () { return data; }; return data; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // A list of all attributes that may produce a dependency // Based on https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute // See also https://www.w3.org/TR/SVG/attindex.html and https://www.w3.org/TR/SVG11/attindex.html // SVG animation elements are excluded because they may only reference elements in the same document: https://www.w3.org/TR/SVG/linking.html#processingURL-fetch const HREF_ATTRS = ['a', 'use', 'feImage', 'image', 'linearGradient', 'radialGradient', 'pattern', 'mpath', 'textPath', 'script']; const ATTRS = { href: HREF_ATTRS, 'xlink:href': [...HREF_ATTRS, 'altGlyph', 'cursor', 'filter', 'font-face-uri', 'glyphRef', 'tref', 'color-profile'] }; // Attributes that allow url() to reference another element, either in the same document or a different one. // https://www.w3.org/TR/SVG11/linking.html#processingIRI const FUNC_IRI_ATTRS = new Set(['fill', 'stroke', 'clip-path', 'color-profile', 'cursor', 'filter', 'marker', 'marker-start', 'marker-mid', 'marker-end', 'mask', // SVG2 - https://www.w3.org/TR/SVG/linking.html#processingURL-validity 'shape-inside', 'shape-subtract', 'mask-image']); // https://www.w3.org/TR/css3-values/#urls const FUNC_IRI_RE = /^url\((?:((['"])(.*?)\2(\s+.*)?)|((?:\\[\s'"]|[^\s'"])+))\)$/; const ESCAPE_RE = /\\(.|\n|\r|\u2028|\u2029)/; function parseFuncIRI(value) { let m = value.match(FUNC_IRI_RE); if (m) { var _m$; let url = (m[3] || m[5]).replace(ESCAPE_RE, '$1'); let modifier = (_m$ = m[4]) !== null && _m$ !== void 0 ? _m$ : ''; return [url, modifier]; } } // Options to be passed to `addDependency` for certain tags + attributes const OPTIONS = { a: { href: { needsStableName: true }, 'xlink:href': { needsStableName: true } } }; function collectDependencies(asset, ast) { let isDirty = false; const errors = []; (0, _posthtml().default)().walk.call(ast.program, node => { // Ideally we'd have location information for specific attributes... let getLoc = () => node.location ? { filePath: asset.filePath, start: node.location.start, end: node.location.end } : undefined; if (typeof node === 'string' && node.startsWith(' { isDirty = true; return asset.addURLDependency(href, { priority: 'parallel' }); }); } const { tag, attrs } = node; if (!attrs) { return node; } for (const attr in attrs) { // Check for id references if (attrs[attr][0] === '#') { continue; } const elements = ATTRS[attr]; if (elements && elements.includes(node.tag)) { var _OPTIONS$tag; // Check for empty string if (attrs[attr].length === 0) { errors.push({ message: `'${attr}' should not be empty string`, filePath: asset.filePath, loc: node.location }); } let options = (_OPTIONS$tag = OPTIONS[tag]) === null || _OPTIONS$tag === void 0 ? void 0 : _OPTIONS$tag[attr]; if (node.tag === 'script') { options = { priority: 'parallel', env: { sourceType: attrs.type === 'module' ? 'module' : 'script', // SVG script elements do not support type="module" natively yet. outputFormat: 'global', loc: getLoc() } }; delete attrs.type; } attrs[attr] = asset.addURLDependency(attrs[attr], { ...options, loc: getLoc() }); isDirty = true; } if (FUNC_IRI_ATTRS.has(attr)) { let parsed = parseFuncIRI(attrs[attr]); if (parsed) { let depId = asset.addURLDependency(parsed[0], { loc: getLoc() }); attrs[attr] = `url('${depId}'${parsed[1]})`; isDirty = true; } } } return node; }); if (errors.length > 0) { throw errors; } if (isDirty) { asset.setAST(ast); } }