UNPKG

@svelte-put/preprocess-inline-svg

Version:
298 lines (292 loc) 10.3 kB
var __defProp = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); // src/vite/vite.internals.ts import fs2 from "fs"; import path2 from "path"; // src/preprocessor/preprocessor.internals.ts import fs from "fs"; import path from "path"; // ../preprocess-helpers/src/index.js function getAttribute(source, node, attributeName) { const attr = node.attributes.find( (attr2) => attr2.name === attributeName && attr2.type === "Attribute" ); if (attr) { let raw = source.slice(attr.start + attributeName.length + 1, attr.end); if (raw.startsWith('"') && raw.endsWith('"')) { raw = raw.slice(1, -1); } return raw; } } // src/preprocessor/preprocessor.internals.ts import { toHtml } from "hast-util-to-html"; import MagicString from "magic-string"; import { walk } from "svelte/compiler"; import { parse } from "svelte-parse-markup"; import { parse as parseSvg } from "svg-parser"; var DEFAULT_SOURCES_CONFIG = { directories: [], attributes: {} }; function resolveSourceOptions(options) { return { directories: (options == null ? void 0 : options.directories) ? Array.isArray(options.directories) ? options.directories : [options.directories] : DEFAULT_SOURCES_CONFIG.directories, attributes: (options == null ? void 0 : options.attributes) ? __spreadValues(__spreadValues({}, DEFAULT_SOURCES_CONFIG.attributes), options.attributes) : DEFAULT_SOURCES_CONFIG.attributes }; } function resolveSources(sources) { if (!sources) return { local: DEFAULT_SOURCES_CONFIG, dirs: [] }; if (!Array.isArray(sources)) { if (!sources.directories) { return { local: resolveSourceOptions(sources), dirs: [] }; } const dir = resolveSourceOptions(sources); const local = __spreadProps(__spreadValues({}, dir), { directories: [] }); return { local, dirs: [dir] }; } const inputsWithoutDirectories = sources.filter((i) => !i.directories); if (inputsWithoutDirectories.length > 1) { throw new Error( "\n@svelte-put/preprocess-inline-svg: only one default input (one without `directories` option) is allowed" ); } return { local: resolveSourceOptions(inputsWithoutDirectories[0]), dirs: sources.filter((i) => !!i.directories).map(resolveSourceOptions) }; } var DEFAULT_INLINE_SVG_CONFIG = { inlineSrcAttributeName: "data-inline-src", keepInlineSrcAttribute: false }; function resolveInlineSvgConfig(config = {}) { var _a, _b; return { inlineSrcAttributeName: (_a = config.inlineSrcAttributeName) != null ? _a : DEFAULT_INLINE_SVG_CONFIG.inlineSrcAttributeName, keepInlineSrcAttribute: (_b = config.keepInlineSrcAttribute) != null ? _b : DEFAULT_INLINE_SVG_CONFIG.keepInlineSrcAttribute }; } function findSvgSrc(filename, directories, inlineSrc) { let resolvedSrc = void 0; if (inlineSrc) { if (!inlineSrc.endsWith(".svg")) inlineSrc += ".svg"; if (directories.length === 0) { resolvedSrc = path.join(path.dirname(filename), inlineSrc); if (!fs.existsSync(resolvedSrc)) resolvedSrc = void 0; } else { for (const dir of directories) { resolvedSrc = path.join(dir, inlineSrc); if (!path.isAbsolute(resolvedSrc)) { resolvedSrc = path.join(process.cwd(), resolvedSrc); } if (fs.existsSync(resolvedSrc)) break; else resolvedSrc = void 0; } } } return resolvedSrc; } function transform(code, filename, sources, config) { const { local, dirs } = sources; const { inlineSrcAttributeName, keepInlineSrcAttribute } = config; const s = new MagicString(code); const ast = parse(code, { filename }); walk(ast.html, { enter(_node) { const node = _node; if (node.type !== "Element" || node.name !== "svg") return; let options = local; let inlineSrc = getAttribute(code, node, inlineSrcAttributeName); let svgSource = findSvgSrc(filename, options.directories, inlineSrc); if (!svgSource) { for (let i = 0; i < dirs.length; i++) { options = dirs[i]; inlineSrc = getAttribute(code, node, inlineSrcAttributeName); svgSource = findSvgSrc(filename, options.directories, inlineSrc); if (svgSource) break; } } if (!inlineSrc) return; if (!svgSource) { throw new Error( ` @svelte-put/preprocess-inline-svg: cannot find svg source for ${inlineSrc} at ${filename}` ); } const svgStr = fs.readFileSync(svgSource, "utf8").replace(/&amp;/g, "&"); const hast = parseSvg(svgStr); const svg = hast.children[0]; const attributes = __spreadValues(__spreadValues({}, svg.properties), options.attributes); node.attributes.map((attr) => { if (attr.type === "Attribute") { if (attr.name === inlineSrcAttributeName && !keepInlineSrcAttribute) { s.remove(attr.start, attr.end); } if (attributes[attr.name] && attr.value.length === 1) { delete attributes[attr.name]; } } }); for (const [name, value] of Object.entries(attributes)) { s.appendRight(node.start + "<svg".length, ` ${name}="${value}" `); } let insertIndex = node.end - "/>".length; if (s.slice(insertIndex, node.end) !== "/>") { insertIndex = node.end - "</svg>".length; } const content = toHtml(svg.children, { allowDangerousCharacters: true }); s.update(insertIndex, node.end, `>${content}</svg>`); } }); return { code: s.toString(), map: s.generateMap() }; } // src/vite/vite.internals.ts var DEFAULT_VITE_PLUGIN_CONFIG = __spreadProps(__spreadValues({}, DEFAULT_INLINE_SVG_CONFIG), { extension: [".svelte"], svgExtension: [".svg"], sourceTypingGeneration: true }); function resolveExtension(extension, fallback = []) { return (extension ? Array.isArray(extension) ? extension : [extension] : fallback).map( (ext) => ext.startsWith(".") ? ext : `.${ext}` ); } function resolveViteInlineSvgConfig(config = {}) { var _a; return __spreadProps(__spreadValues({}, resolveInlineSvgConfig(config)), { extension: resolveExtension(config.extension, DEFAULT_VITE_PLUGIN_CONFIG.extension), svgExtension: resolveExtension(config.svgExtension, DEFAULT_VITE_PLUGIN_CONFIG.svgExtension), sourceTypingGeneration: (_a = config.sourceTypingGeneration) != null ? _a : DEFAULT_VITE_PLUGIN_CONFIG.sourceTypingGeneration }); } function findSvgRecursively(dir) { const files = fs2.readdirSync(dir).map((f) => path2.join(dir, f)).filter((f) => { const stat = fs2.statSync(f); if (stat.isDirectory()) return true; if (stat.isFile()) return f.endsWith(".svg"); return false; }); const directories = files.filter((f) => fs2.statSync(f).isDirectory()); const subFiles = directories.flatMap(findSvgRecursively); return [...files, ...subFiles]; } function generateSourceTyping(sources) { try { const { local, dirs } = sources; const sourcePath = path2.join( process.cwd(), "node_modules/@svelte-put/preprocess-inline-svg/dist/sources.generated.d.ts" ); const directories = [...local.directories, ...dirs.flatMap((d) => d.directories)]; const svgs = /* @__PURE__ */ new Set(); for (const dir of directories) { const files = findSvgRecursively(dir); for (const file of files) { const svg = path2.relative(dir, file).replace(".svg", ""); svgs.add(`'${svg}'`); } } const nonTyped = ["`./${string}`", "`../${string}`"].join("\n | "); const typing = Array.from(svgs).join("\n | "); const source = `export type Source = ${nonTyped} | ${typing};`; fs2.writeFileSync(sourcePath, source); } catch (error) { console.error("[svelte-preprocess-inline-svg]", error); } } // src/vite/vite.ts import debounce from "lodash.debounce"; function hotReload(server) { server.ws.send({ type: "full-reload" }); } function matchFileExt(file, extensions) { return extensions.some((ext) => file.endsWith(ext)); } function inlineSvg(sources = [], config = {}) { const rSources = resolveSources(sources); const rConfig = resolveViteInlineSvgConfig(config); return { name: "svelte-preprocess-inline-svg", enforce: "pre", transform(code, id) { if (matchFileExt(id, rConfig.extension)) { return transform(code, id, rSources, rConfig); } }, configureServer(server) { if (rConfig.sourceTypingGeneration) { generateSourceTyping(rSources); } const updateSourceTyping = debounce(() => { if (rConfig.sourceTypingGeneration) { generateSourceTyping(rSources); } hotReload(server); }); server.watcher.add(rConfig.svgExtension.map((ext) => `**/*${ext}`)); server.watcher.on("add", (file) => { if (matchFileExt(file, rConfig.svgExtension)) { updateSourceTyping(); } }); server.watcher.on("unlink", (file) => { if (matchFileExt(file, rConfig.svgExtension)) { updateSourceTyping(); } }); server.watcher.on("change", (file) => { if (matchFileExt(file, rConfig.svgExtension)) { hotReload(server); } }); } }; } export { DEFAULT_VITE_PLUGIN_CONFIG, generateSourceTyping, inlineSvg, resolveExtension, resolveViteInlineSvgConfig }; //# sourceMappingURL=index.js.map