@svgx/core
Version:
Transform SVG inputs into many outputs, especially "HAST" "JSX" and "JS".
233 lines (232 loc) • 10.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.toEstreeComponent = exports.toJsComponent = exports.toJsxComponent = exports.toJs = exports.toJsx = exports.toEstree = exports.toHast = void 0;
const svgo_1 = require("svgo");
const astring_1 = require("astring");
const estraverse_1 = require("estraverse");
// transform an svg string to HAST (Hypertext Abstract Syntax Tree)
const toHast = async (svg, options = {}) => {
const defaultOptions = {
optimize: true,
svgoConfig: {},
};
const mergedOptions = Object.assign({}, defaultOptions, options);
let optimized = svg;
if (mergedOptions.optimize) {
optimized = (0, svgo_1.optimize)(svg, mergedOptions.svgoConfig).data;
}
const { fromHtml } = await eval(`import('hast-util-from-html')`);
return fromHtml(optimized, {
space: "svg",
fragment: true,
});
};
exports.toHast = toHast;
// transform an svg into an estree
const toEstree = async (svg, options) => {
const hast = await (0, exports.toHast)(svg, options);
const { toEstree: getEstree } = await eval(`import('hast-util-to-estree')`);
return getEstree(hast, { space: "svg" });
};
exports.toEstree = toEstree;
// transform an svg into raw jsx syntax (just jsx, not a component)
const toJsx = async (svg, options) => {
const esTree = await (0, exports.toEstree)(svg, options);
const { toJs: getJs, jsx } = await eval(`import('estree-util-to-js')`);
const { value } = getJs(esTree, { handlers: jsx });
return value;
};
exports.toJsx = toJsx;
// transform an svg into javascript function calls (using pragmas)
const toJs = async (svg, options) => {
const defaultOptions = {
optimize: true,
svgoConfig: {},
runtime: "automatic",
importSource: "react",
pragma: (options === null || options === void 0 ? void 0 : options.runtime) === "classic" ? "createElement" : undefined,
pragmaFrag: (options === null || options === void 0 ? void 0 : options.runtime) === "classic" ? "Fragment" : undefined,
};
const mergedOptions = Object.assign({}, defaultOptions, options);
const esTree = await (0, exports.toEstree)(svg, mergedOptions);
const { buildJsx } = await eval(`import('estree-util-build-jsx')`);
const esAst = buildJsx(esTree, mergedOptions);
return (0, astring_1.generate)(esAst);
};
exports.toJs = toJs;
// transform an svg into a component with raw jsx return value
const toJsxComponent = async (svg, options) => {
const esTreeComponent = await (0, exports.toEstreeComponent)(svg, options);
const { toJs: getJs, jsx } = await eval(`import('estree-util-to-js')`);
const { value } = getJs(esTreeComponent, { handlers: jsx });
return value;
};
exports.toJsxComponent = toJsxComponent;
// transform an svg into a component with jsx runtime function calls return value
const toJsComponent = async (svg, options) => {
const defaultOptions = {
optimize: true,
svgoConfig: {},
componentName: "Component",
passProps: true,
defaultExport: true,
importSource: "react",
runtime: "automatic",
pragma: (options === null || options === void 0 ? void 0 : options.runtime) === "classic" ? "createElement" : undefined,
pragmaFrag: (options === null || options === void 0 ? void 0 : options.runtime) === "classic" ? "Fragment" : undefined,
};
const mergedOptions = Object.assign({}, defaultOptions, options);
const esTreeComponent = await (0, exports.toEstreeComponent)(svg, mergedOptions);
const { buildJsx } = await eval(`import('estree-util-build-jsx')`);
const esAst = buildJsx(esTreeComponent, mergedOptions);
return (0, astring_1.generate)(esAst);
};
exports.toJsComponent = toJsComponent;
// transform an svg into a component in estree format
const toEstreeComponent = async (svg, options = {}) => {
const defaultOptions = {
optimize: true,
svgoConfig: {},
componentName: "Component",
passProps: true,
defaultExport: true,
runtime: "automatic",
pragma: (options === null || options === void 0 ? void 0 : options.runtime) === "classic" ? "createElement" : undefined,
pragmaFrag: (options === null || options === void 0 ? void 0 : options.runtime) === "classic" ? "Fragment" : undefined,
importSource: "react",
};
const mergedOptions = Object.assign({}, defaultOptions, options);
const esTree = await (0, exports.toEstree)(svg, mergedOptions);
(0, estraverse_1.traverse)(esTree, {
enter: function (node) {
if (node.type === "Program" && node.body) {
const previousNodeBody = node.body[0];
// this is for importing pragma and pragmaFrag when using classic runtime
const importDeclaration = (mergedOptions === null || mergedOptions === void 0 ? void 0 : mergedOptions.runtime) === "classic"
? {
type: "ImportDeclaration",
specifiers: [
{
type: "ImportSpecifier",
imported: {
type: "Identifier",
name: mergedOptions.pragma || "createElement",
},
local: {
type: "Identifier",
name: mergedOptions.pragma || "createElement",
},
},
{
type: "ImportSpecifier",
imported: {
type: "Identifier",
name: mergedOptions.pragmaFrag || "Fragment",
},
local: {
type: "Identifier",
name: mergedOptions.pragmaFrag || "Fragment",
},
},
],
source: {
type: "Literal",
value: mergedOptions.importSource || "react",
raw: `"${mergedOptions.importSource}"` || '"react"',
},
}
: null;
const componentNode = {
type: "VariableDeclaration",
kind: "const",
declarations: [
{
type: "VariableDeclarator",
id: {
type: "Identifier",
name: mergedOptions.componentName,
},
init: {
type: "ArrowFunctionExpression",
expression: false,
generator: false,
async: false,
params: mergedOptions.passProps
? [
{
type: "Identifier",
name: "props",
},
]
: [],
body: {
type: "BlockStatement",
body: [
{
type: "ReturnStatement",
argument: previousNodeBody.expression,
},
],
},
},
},
],
};
const componentWithNamedExport = [
{
type: "ExportNamedDeclaration",
declaration: componentNode,
specifiers: [],
source: null,
},
];
const componentWithDefaultExport = [
componentNode,
{
type: "ExportDefaultDeclaration",
declaration: {
type: "Identifier",
name: mergedOptions.componentName,
},
},
];
if (importDeclaration) {
node.body = mergedOptions.defaultExport
? [importDeclaration, ...componentWithDefaultExport]
: [importDeclaration, ...componentWithNamedExport];
}
else {
node.body = mergedOptions.defaultExport
? componentWithDefaultExport
: componentWithNamedExport;
}
}
if (mergedOptions.passProps &&
node.type === "JSXOpeningElement" &&
node.name.type === "JSXIdentifier" &&
node.name.name === "svg") {
node.attributes.push({
type: "JSXSpreadAttribute",
argument: { type: "Identifier", name: "props" },
});
}
},
fallback: function (node) {
if (node.type === "JSXFragment")
return ["children"];
if (node.type === "JSXElement")
return ["openingElement"];
if (node.type === "JSXOpeningElement")
return ["attributes", "name", "selfClosing"];
if (node.type === "JSXAttribute")
return ["name", "value"];
if (node.type === "JSXIdentifier")
return ["name"];
if (node.type === "JSXSpreadAttribute")
return ["argument"];
throw new Error("unknown node: " + node.type);
},
});
return esTree;
};
exports.toEstreeComponent = toEstreeComponent;