webfont 12.0.0 → 12.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (57) hide show
  1. package/NOTICE.md +14 -2
  2. package/README.md +176 -15
  3. package/dist/browser.js +4 -0
  4. package/dist/cli.mjs +518 -253
  5. package/dist/index.js +1 -1
  6. package/dist/parseTemplateOption-5T7rSw5J.mjs +20 -0
  7. package/dist/parseTemplateOption-BmH_pcQh.js +1 -0
  8. package/dist/renderTemplates-DvRlS58E.mjs +93 -0
  9. package/dist/renderTemplates-zCYCzeOt.js +1 -0
  10. package/dist/src/browser.d.ts +2 -0
  11. package/dist/src/index.d.ts +2 -0
  12. package/dist/src/lib/applyOptimizeSvgToGlyphs.d.ts +3 -0
  13. package/dist/src/lib/evenoddFillRule.d.ts +2 -0
  14. package/dist/src/lib/inputSource.d.ts +1 -4
  15. package/dist/src/lib/inputSourceUtils.d.ts +4 -0
  16. package/dist/src/lib/largeFontLigatures.d.ts +4 -0
  17. package/dist/src/lib/optimizeSvgGlyphs.d.ts +4 -0
  18. package/dist/src/lib/parseFormats.d.ts +4 -0
  19. package/dist/src/lib/parseTemplateOption.d.ts +2 -0
  20. package/dist/src/lib/runtimeEnvironment.d.ts +4 -0
  21. package/dist/src/lib/svgDiagnostics/diagnoseSvgContents.d.ts +12 -0
  22. package/dist/src/lib/svgFontOutput/emptyGlyphPaths.d.ts +3 -0
  23. package/dist/src/lib/svgTools/applySvgDiagnostics.d.ts +13 -0
  24. package/dist/src/lib/svgTools/applySvgTools.d.ts +14 -0
  25. package/dist/src/lib/svgTools/normalizeSvgToolsOptions.d.ts +2 -0
  26. package/dist/src/lib/svgicons2svgfont/index.d.ts +5 -0
  27. package/dist/src/lib/svgicons2svgfont/metadataFromSrcPath.d.ts +11 -0
  28. package/dist/src/lib/templateUnicodeRange.d.ts +4 -0
  29. package/dist/src/lib/ttfEncode.d.ts +5 -0
  30. package/dist/src/standalone/convertTtfInput.d.ts +3 -0
  31. package/dist/src/standalone/defaultOptions.d.ts +3 -0
  32. package/dist/src/standalone/generateSvgFont.d.ts +2 -0
  33. package/dist/src/standalone/getGlyphsDataFromInputs.d.ts +3 -0
  34. package/dist/src/standalone/glyphsData.d.ts +1 -1
  35. package/dist/src/standalone/index.d.ts +5 -0
  36. package/dist/src/standalone/inputMode.d.ts +3 -1
  37. package/dist/src/standalone/optionsFromGlyphs.d.ts +3 -0
  38. package/dist/src/standalone/renderTemplates.d.ts +10 -0
  39. package/dist/src/standalone/runSvgPipeline.d.ts +3 -0
  40. package/dist/src/standalone/validateWebfontOptions.d.ts +6 -0
  41. package/dist/src/standalone/webfontFromGlyphs.d.ts +3 -0
  42. package/dist/src/types/GlyphContentTransformFn.d.ts +2 -0
  43. package/dist/src/types/GlyphInput.d.ts +6 -0
  44. package/dist/src/types/InitialOptions.d.ts +2 -0
  45. package/dist/src/types/OptionsBase.d.ts +9 -1
  46. package/dist/src/types/RenderedTemplate.d.ts +7 -0
  47. package/dist/src/types/Result.d.ts +8 -0
  48. package/dist/src/types/SvgToolsOptions.d.ts +13 -0
  49. package/dist/src/types/TranscodedFont.d.ts +7 -0
  50. package/dist/src/types/WebfontFromGlyphsOptions.d.ts +11 -0
  51. package/dist/src/types/WebfontOptions.d.ts +12 -2
  52. package/dist/src/types/index.d.ts +2 -1
  53. package/package.json +16 -3
  54. package/templates/template.css.njk +6 -3
  55. package/templates/template.html.njk +15 -4
  56. package/templates/template.scss.njk +6 -3
  57. package/templates/template.styl.njk +6 -3
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,a)=>(a=n==null?{}:e(i(n)),s(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let l=require("cosmiconfig"),u=require("crypto");u=c(u);let d=require("deepmerge");d=c(d);let f=require("nunjucks");f=c(f);let p=require("path");p=c(p);let m=require("stream"),h=require("ttf2woff");h=c(h);let g=require("wawoff2");g=c(g);let _=require("globby"),v=require("svgicons2svgfont"),y=require("ttf2eot");y=c(y);let b=require("fontverter");b=c(b);let x=require("fs/promises");x=c(x);let S=require("fs"),C=require("xml2js");C=c(C);let w=require("p-limit");w=c(w);let T=require("svg2ttf");T=c(T);var E=()=>p.default.resolve(__dirname,`../templates`),D=e=>`${E()}/template.${e}.njk`,O=()=>{let e=E();return{css:{path:p.default.join(e,`template.css.njk`)},html:{path:p.default.join(e,`template.html.njk`)},json:{path:p.default.join(e,`template.json.njk`)},scss:{path:p.default.join(e,`template.scss.njk`)},styl:{path:p.default.join(e,`template.styl.njk`)}}},k=/^https?:\/\//iu,A=e=>k.test(e),j=e=>{if(A(e))try{return p.default.extname(new URL(e).pathname).toLowerCase()}catch{return``}return p.default.extname(e).toLowerCase()},M=async e=>(await Promise.all(e.map(e=>A(e)?Promise.resolve([e]):(0,_.globby)(e)))).flat(),ee=e=>({prependUnicode:!!e.prependUnicode,startUnicode:Number(e.startUnicode)}),te=e=>({ascent:e.ascent,centerHorizontally:e.centerHorizontally,descent:e.descent,fixedWidth:e.fixedWidth,fontHeight:e.fontHeight,fontId:e.fontId,fontName:e.fontName,fontStyle:e.fontStyle,fontWeight:e.fontWeight,metadata:e.metadata,normalize:e.normalize,round:e.round}),ne=e=>Buffer.from((0,y.default)(e)),N=1330926671,P=1953658213,F=65536,I=e=>{if(e.length<4)throw Error(`SFNT buffer is too short to read flavor`);let t=e.readUInt32BE(0);if(t===N)return`otf`;if(t===P||t===F)return`ttf`;throw Error(`Unsupported SFNT flavor 0x${t.toString(16)}`)},L=o(((e,t)=>{t.exports=function(e){return!e||e.length<8?!1:e[0]===119&&e[1]===79&&e[2]===70&&e[3]===70&&e[4]===0&&e[5]===1&&e[6]===0&&e[7]===0||e[4]===79&&e[5]===84&&e[6]===84&&e[7]===79}})),R=o(((e,t)=>{t.exports=function(e){return!e||e.length<8?!1:e[0]===119&&e[1]===79&&e[2]===70&&e[3]===50&&e[4]===0&&e[5]===1&&e[6]===0&&e[7]===0}})),z=c(L()),B=c(R()),V=(e,t)=>{let n=j(t);if(n===`.woff2`&&!(0,B.default)(e))throw Error(`URL did not return a valid WOFF2 font: ${t}`);if(n===`.woff`&&!(0,z.default)(e))throw Error(`URL did not return a valid WOFF font: ${t}`);if(e.length===0)throw Error(`URL returned an empty response: ${t}`)},H=async e=>{let t;try{t=await fetch(e)}catch(t){let n=String(t);throw t instanceof Error&&(n=t.message),Error(`Failed to fetch font URL ${e}: ${n}`)}if(!t.ok)throw Error(`Failed to fetch font URL ${e}: HTTP ${t.status} ${t.statusText}`);let n=await t.arrayBuffer(),r=Buffer.from(n);return V(r,e),r},U=new Set([`.woff`,`.woff2`]),W=`.svg`,G=[`svg`,`ttf`,`eot`,`woff`,`woff2`],K=e=>e===W,q=e=>U.has(e),J=e=>K(e)||q(e),Y=e=>{if(e.length===0)return`empty`;let t=e.map(e=>j(e));if(!t.every(J))return`empty`;let n=t.some(K),r=t.some(q);return n&&r?`mixed`:r?`webfont`:n?`svg`:`empty`},X=e=>{if(e.includes(`otf`))throw Error(`OTF output is only supported when converting WOFF/WOFF2 input. Request "ttf" for SVG icons, or pass a .woff/.woff2 file.`)},Z=(e,t)=>t===`svg`?e.filter(e=>j(e)===W):t===`webfont`?e.filter(e=>U.has(j(e))):[],re=e=>{let t=e.filter(e=>e===`ttf`||e===`otf`);if(e.length===G.length&&G.every(t=>e.includes(t)))return[`ttf`];if(t.length===0)throw Error(`formats must include "ttf" and/or "otf" when converting WOFF/WOFF2 input`);return[...new Set(t)]},ie=e=>{if(e.length===0)throw Error(`No WOFF or WOFF2 files matched`)},ae=e=>{if(e.template)throw Error(`Templates are not supported when converting WOFF/WOFF2 input`);if(e.glyphTransformFn)throw Error(`glyphTransformFn is not supported when converting WOFF/WOFF2 input`)},oe=e=>{let{decompressed:t,sfnt:n,format:r,flavor:i,source:a}=e;if(r===`ttf`&&i!==`ttf`)throw Error(`Input decompresses to OpenType (OTF). Request "otf" format instead of "ttf" for ${a}.`);if(r===`otf`&&i!==`otf`)throw Error(`Input decompresses to TrueType (TTF). Request "ttf" format instead of "otf" for ${a}.`);if(r===`ttf`){t.ttf=n;return}t.otf=n},se=e=>A(e)?H(e):x.readFile(e),ce=async(e,t,n)=>{n&&console.log(`Decompressing ${e}...`);let r=await se(e),i=Buffer.from(await b.default.convert(r,`sfnt`)),a=I(i),o={source:e};for(let n of t)oe({decompressed:o,sfnt:i,format:n,flavor:a,source:e});return o},le=async(e,t)=>{ae(t),ie(e);let n=re(t.formats),r=await Promise.all(e.map(e=>ce(e,n,t.verbose))),i={config:{...t},decompressedFonts:r};return r.length===1&&(i.ttf=r[0].ttf,i.otf=r[0].otf),i},ue=w.default,de=e=>e===void 0?[]:Array.isArray(e)?e:[e],fe=e=>({name:e.name,unicode:de(e.unicode)}),pe=(e,t)=>{let n=t.metadataProvider||(0,v.getMetadataService)(ee(t)),r=new C.default.Parser,i=ue(t.maxConcurrency);return Promise.all(e.map(e=>i(()=>new Promise((t,n)=>{let i=(0,S.createReadStream)(e),a=``;i.on(`error`,e=>n(e)).on(`data`,e=>{a+=e.toString()}).on(`end`,()=>a.length===0?n(Error(`Empty file ${e}`)):r.parseString(a,r=>r?n(r):t({contents:a,srcPath:e})))})))).then(e=>{let r=e;t.sort&&(r=e.sort((e,t)=>(0,v.fileSorter)(e.srcPath,t.srcPath)));let{ligatures:i}=t;return Promise.all(r.map(e=>new Promise((t,r)=>{n(e.srcPath,(n,a)=>{if(n)return r(n);if(!a)return r(Error(`Missing metadata for ${e.srcPath}`));let o=fe(a);return i&&o.unicode.push(a.name.replace(/-/gu,`_`)),e.metadata=o,t(e)})})))})},me=e=>{if(!e?.files)throw Error("You must pass webfont a `files` glob");return{centerHorizontally:!1,descent:0,fixedWidth:!1,fontHeight:void 0,fontId:void 0,fontName:`webfont`,fontStyle:``,fontWeight:``,formats:[`svg`,`ttf`,`eot`,`woff`,`woff2`],formatsOptions:{ttf:{copyright:null,ts:null,version:null}},ligatures:!0,maxConcurrency:100,metadata:void 0,normalize:!1,prependUnicode:!1,round:0x9184e72a000,sort:!0,startUnicode:59905,templateFontPath:`./`,verbose:!1,...e}},Q=(e,t)=>{if(e===`woff2`){if(!t.woff2)throw Error(`Missing woff2 buffer for template rendering`);return Buffer.from(t.woff2).toString(`base64`)}let n=t[e];if(!n)throw Error(`Missing ${e} buffer for template rendering`);return n.toString(`base64`)},he=(e,t={})=>Buffer.from((0,T.default)(e,t).buffer),ge=e=>`filepath`in e,_e=async e=>{let t=(0,l.cosmiconfig)(`webfont`,{searchStrategy:`global`});if(e.configFile){let n=p.default.resolve(process.cwd(),e.configFile);return await t.load(n)??{}}return await t.search(process.cwd())??{}},ve=(e,t)=>{let n=``;return new Promise((r,i)=>{t.verbose&&console.log(`Generating SVG font...`);let a=new v.SVGIcons2SVGFontStream(te(t)).on(`finish`,()=>r(n)).on(`data`,e=>{n+=e}).on(`error`,e=>i(e));e.forEach(e=>{let t=new m.Readable;t.push(e.contents),t.push(null),t.metadata=e.metadata??{name:``,unicode:[]},a.write(t)}),a.end()})},ye=e=>ne(e),be=(e,t)=>Buffer.from((0,h.default)(e,t).buffer),xe=e=>g.default.compress(e),$=async e=>{let t=me(e);delete t.filePath;let n=await _e({configFile:t.configFile}),r;ge(n)&&(t=(0,d.default)(t,n.config,{arrayMerge:(e,t)=>t}),r=n.filepath);let i;i=Array.isArray(t.files)?t.files:[t.files];let a=await M(i),o=Y(a);if(o===`mixed`)throw Error(`Cannot mix SVG icons with WOFF/WOFF2 font files in the same run`);if(o===`empty`)throw Error(`Files glob patterns specified did not match any supported files`);if(o===`webfont`){let e=await le(Z(a,o),t);return r&&(e.config={...t,filePath:r}),e}X(t.formats);let s=await pe(Z(a,`svg`),t);if(t.glyphTransformFn){let e=t.glyphTransformFn,n=s.map(async t=>{let n=await e(t.metadata??{name:``,unicode:[]});return{...t,metadata:n}});s=await Promise.all(n)}let c={};t.formatsOptions?.ttf&&(c=t.formatsOptions.ttf);let l=await ve(s,t),m=he(l,c),h={glyphsData:s,hash:u.default.createHash(`md5`).update(l).digest(`hex`),svg:l,ttf:m},{formats:g}=t;if(g.includes(`eot`)&&(h.eot=ye(m)),g.includes(`woff`)){let e;typeof t.metadata==`string`&&(e=t.metadata),h.woff=be(m,{metadata:e})}if(g.includes(`woff2`)&&(h.woff2=Buffer.from(await xe(m))),t.template){let e=O(),n;if(Object.keys(e).includes(t.template)){h.usedBuildInTemplate=!0;let e=p.default.resolve(__dirname,`../..`);f.default.configure(e),n=D(t.template)}else{let e=p.default.resolve(t.template);f.default.configure(p.default.dirname(e)),n=p.default.resolve(e)}let r={};t.addHashInFontUrl&&(r={hash:h.hash});let i=d.default.all([{glyphs:h.glyphsData?.map(e=>e.metadata)??[]},t,{cacheString:t.templateCacheString||Date.now(),className:t.templateClassName||t.fontName,fontName:t.templateFontName||t.fontName,fontPath:t.templateFontPath.replace(/\/?$/u,`/`)},r,{fonts:Object.fromEntries(new Map(g.map(e=>[e,()=>Q(e,h)])))}]);h.template=f.default.render(n,i)}return g.includes(`svg`)||delete h.svg,g.includes(`ttf`)||delete h.ttf,g.includes(`otf`)||delete h.otf,r?h.config={...t,filePath:r}:h.config=t,h},Se=$;exports.default=Se,exports.webfont=$;
1
+ Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});const e=require("./parseTemplateOption-BmH_pcQh.js");let t=require("cosmiconfig"),n=require("deepmerge");n=e.r(n);let r=require("path");r=e.r(r);let i=require("globby"),a=require("fs/promises");a=e.r(a);let o=require("ttf2woff");o=e.r(o);let s=require("wawoff2");s=e.r(s);let c=require("ttf2eot");c=e.r(c);let l=require("fontverter");l=e.r(l);let u=require("fs"),d=require("xml2js");d=e.r(d);let f=require("p-limit");f=e.r(f);let p=require("svgicons2svgfont"),m=require("crypto");m=e.r(m);let ee=require("svgo"),te=require("stream"),h=require("svg2ttf");h=e.r(h);var ne=/^https?:\/\//iu,g=e=>ne.test(e),_=e=>{if(g(e))try{return r.default.extname(new URL(e).pathname).toLowerCase()}catch{return``}return r.default.extname(e).toLowerCase()},v=async e=>(await Promise.all(e.map(e=>g(e)?Promise.resolve([e]):(0,i.globby)(e)))).flat(),re=1330926671,ie=1953658213,ae=65536,y=e=>{if(e.length<4)throw Error(`SFNT buffer is too short to read flavor`);let t=e.readUInt32BE(0);if(t===re)return`otf`;if(t===ie||t===ae)return`ttf`;throw Error(`Unsupported SFNT flavor 0x${t.toString(16)}`)},oe=e=>Buffer.from((0,c.default)(e)),b=e=>oe(e),x=(e,t={})=>Buffer.from((0,o.default)(e,t).buffer),S=async e=>Buffer.from(await s.default.compress(e)),C=new Set([`.woff`,`.woff2`]),w=`.svg`,T=`.ttf`,E=[`svg`,`ttf`,`eot`,`woff`,`woff2`],D=e=>e===w,O=e=>e===T,k=e=>C.has(e),se=e=>D(e)||k(e)||O(e),ce=e=>{if(e.length===0)return`empty`;let t=e.map(e=>_(e));if(!t.every(se))return`empty`;let n=t.some(D),r=t.some(k),i=t.some(O);return[n,r,i].filter(Boolean).length>1?`mixed`:r?`webfont`:i?`ttf`:n?`svg`:`empty`},A=e=>{if(e.includes(`otf`))throw Error(`OTF output is only supported when converting WOFF/WOFF2 input. Request "ttf" for SVG icons, or pass a .woff/.woff2 file.`)},j=(e,t)=>t===`svg`?e.filter(e=>_(e)===w):t===`webfont`?e.filter(e=>C.has(_(e))):t===`ttf`?e.filter(e=>_(e)===T):[],M=new Set([`ttf`,`eot`,`woff`,`woff2`]),N=e=>{let t=e.filter(e=>M.has(e));if(e.length===E.length&&E.every(t=>e.includes(t)))return[`woff`,`woff2`];if(t.length===0)throw Error(`formats must include at least one of "ttf", "eot", "woff", or "woff2" when converting TTF input`);return[...new Set(t)]},P=e=>{let t=e.filter(e=>e===`ttf`||e===`otf`);if(e.length===E.length&&E.every(t=>e.includes(t)))return[`ttf`];if(t.length===0)throw Error(`formats must include "ttf" and/or "otf" when converting WOFF/WOFF2 input`);return[...new Set(t)]},F=e=>{if(e.length===0)throw Error(`No TTF files matched`)},I=e=>{if(e.template)throw Error(`Templates are not supported when converting TTF input`);if(e.glyphTransformFn)throw Error(`glyphTransformFn is not supported when converting TTF input`);if(e.glyphContentTransformFn)throw Error(`glyphContentTransformFn is not supported when converting TTF input`)},L=(e,t)=>{let n;try{n=y(e)}catch{throw Error(`Input is not a valid TrueType font: ${t}`)}if(n!==`ttf`)throw Error(`OpenType (OTF) input is not supported for webfont encoding. Use a .ttf file for ${t}.`)},R=async(e,t,n,r)=>{if(n===`ttf`){e.ttf=t;return}if(n===`eot`){e.eot=b(t);return}if(n===`woff`){let n;typeof r.metadata==`string`&&(n=r.metadata),e.woff=x(t,{metadata:n});return}e.woff2=await S(t)},z=async(e,t,n,r)=>{if(g(e))throw Error(`Remote TTF URLs are not supported. Download the file first: ${e}`);r&&console.log(`Encoding ${e}...`);let i=await a.readFile(e);L(i,e);let o={source:e};return await Promise.all(t.map(e=>R(o,i,e,n))),o},B=async(e,t)=>{I(t),F(e);let n=N(t.formats),r=await Promise.all(e.map(e=>z(e,n,t,t.verbose))),i={config:{...t},transcodedFonts:r};if(r.length===1){let[e]=r;i.ttf=e.ttf,i.eot=e.eot,i.woff=e.woff,i.woff2=e.woff2}return i},V=e.n(((e,t)=>{t.exports=function(e){return!e||e.length<8?!1:e[0]===119&&e[1]===79&&e[2]===70&&e[3]===70&&e[4]===0&&e[5]===1&&e[6]===0&&e[7]===0||e[4]===79&&e[5]===84&&e[6]===84&&e[7]===79}})),H=e.n(((e,t)=>{t.exports=function(e){return!e||e.length<8?!1:e[0]===119&&e[1]===79&&e[2]===70&&e[3]===50&&e[4]===0&&e[5]===1&&e[6]===0&&e[7]===0}})),U=e.r(V()),W=e.r(H()),G=(e,t)=>{let n=_(t);if(n===`.woff2`&&!(0,W.default)(e))throw Error(`URL did not return a valid WOFF2 font: ${t}`);if(n===`.woff`&&!(0,U.default)(e))throw Error(`URL did not return a valid WOFF font: ${t}`);if(e.length===0)throw Error(`URL returned an empty response: ${t}`)},le=async e=>{let t;try{t=await fetch(e)}catch(t){let n=String(t);throw t instanceof Error&&(n=t.message),Error(`Failed to fetch font URL ${e}: ${n}`)}if(!t.ok)throw Error(`Failed to fetch font URL ${e}: HTTP ${t.status} ${t.statusText}`);let n=await t.arrayBuffer(),r=Buffer.from(n);return G(r,e),r},ue=e=>{if(e.length===0)throw Error(`No WOFF or WOFF2 files matched`)},de=e=>{if(e.template)throw Error(`Templates are not supported when converting WOFF/WOFF2 input`);if(e.glyphTransformFn)throw Error(`glyphTransformFn is not supported when converting WOFF/WOFF2 input`);if(e.glyphContentTransformFn)throw Error(`glyphContentTransformFn is not supported when converting WOFF/WOFF2 input`)},fe=e=>{let{decompressed:t,sfnt:n,format:r,flavor:i,source:a}=e;if(r===`ttf`&&i!==`ttf`)throw Error(`Input decompresses to OpenType (OTF). Request "otf" format instead of "ttf" for ${a}.`);if(r===`otf`&&i!==`otf`)throw Error(`Input decompresses to TrueType (TTF). Request "ttf" format instead of "otf" for ${a}.`);if(r===`ttf`){t.ttf=n;return}t.otf=n},pe=e=>g(e)?le(e):a.readFile(e),me=async(e,t,n)=>{n&&console.log(`Decompressing ${e}...`);let r=await pe(e),i=Buffer.from(await l.default.convert(r,`sfnt`)),a=y(i),o={source:e};for(let n of t)fe({decompressed:o,sfnt:i,format:n,flavor:a,source:e});return o},he=async(e,t)=>{de(t),ue(e);let n=P(t.formats),r=await Promise.all(e.map(e=>me(e,n,t.verbose))),i={config:{...t},decompressedFonts:r};return r.length===1&&(i.ttf=r[0].ttf,i.otf=r[0].otf),i},ge=f.default,_e=e=>({prependUnicode:!!e.prependUnicode,startUnicode:Number(e.startUnicode)}),ve=e=>{if(e==null)return;if(typeof e==`number`)return Number.isFinite(e)?e:void 0;let t=e.trim();if(t.length===0)return;let n=Number(t);if(Number.isFinite(n))return n},ye=e=>({ascent:e.ascent,centerHorizontally:e.centerHorizontally,descent:e.descent,fixedWidth:e.fixedWidth,fontHeight:e.fontHeight,fontId:e.fontId,fontName:e.fontName,fontStyle:e.fontStyle,fontWeight:e.fontWeight,metadata:e.metadata,normalize:e.normalize,round:ve(e.round)}),be=e=>e===void 0?[]:Array.isArray(e)?e:[e],xe=e=>({name:e.name,unicode:be(e.unicode)}),Se=(e,t)=>{let n=t.metadataProvider||(0,p.getMetadataService)(_e(t)),r=new d.default.Parser,i=ge(t.maxConcurrency);return Promise.all(e.map(e=>i(()=>new Promise((t,n)=>{let i=(0,u.createReadStream)(e),a=``;i.on(`error`,e=>n(e)).on(`data`,e=>{a+=e.toString()}).on(`end`,()=>a.length===0?n(Error(`Empty file ${e}`)):r.parseString(a,r=>r?n(r):t({contents:a,srcPath:e})))})))).then(e=>{let r=e;t.sort&&(r=e.sort((e,t)=>(0,p.fileSorter)(e.srcPath,t.srcPath)));let{ligatures:i}=t;return Promise.all(r.map(e=>new Promise((t,r)=>{n(e.srcPath,(n,a)=>{if(n)return r(n);if(!a)return r(Error(`Missing metadata for ${e.srcPath}`));let o=xe(a);return i&&o.unicode.push(a.name.replace(/-/gu,`_`)),e.metadata=o,t(e)})})))})},Ce=()=>({centerHorizontally:!1,descent:0,fixedWidth:!1,fontHeight:void 0,fontId:void 0,fontName:`webfont`,fontStyle:``,fontWeight:``,formats:[`svg`,`ttf`,`eot`,`woff`,`woff2`],formatsOptions:{ttf:{copyright:null,ts:null,version:null}},ligatures:!1,maxConcurrency:100,metadata:void 0,normalize:!1,prependUnicode:!1,round:0x9184e72a000,sort:!0,startUnicode:59905,templateFontPath:`./`,unicodeRange:!1,verbose:!1}),we=e=>{if(!e?.files)throw Error("You must pass webfont a `files` glob");return{...Ce(),...e}},Te=()=>({multipass:!1,plugins:[`removeDoctype`,`removeXMLProcInst`,`removeComments`,`removeMetadata`,`removeEditorsNSData`,`removeDesc`,`cleanupAttrs`,`removeUnusedNS`]}),Ee=e=>{let t=Te();return e?{...t,...e,plugins:e.plugins??t.plugins}:t},De=(e,t,n)=>(0,ee.optimize)(e,{...Ee(n),path:t}).data,Oe=(e,t)=>e.map(e=>({...e,contents:De(e.contents,e.srcPath,t)})),ke=(e,t)=>t&&e>2e3,Ae=e=>`Warning: ${e} glyphs with ligatures enabled may cause severe browser slowdown or hangs (especially Firefox on Windows). Ligatures are off by default; enable only if needed: --ligatures or ligatures: true. See TROUBLESHOOTING.md and https://github.com/itgalaxy/webfont/issues/558`,je=/<glyph\b([^>/]*)(?:\/>|>)/giu,Me=/\bglyph-name=["']([^"']+)["']/iu,Ne=/\bd=["']([^"']*)["']/iu,Pe=e=>{let t=[];for(let n of e.matchAll(je)){let e=n[1]??``,r=Me.exec(e);r&&(Ne.exec(e)?.[1]??``).trim().length===0&&t.push(r[1])}return t},Fe=(e,t)=>{for(let n of t){let t=n.metadata?.name;if(t&&(e===t||e.startsWith(`${t}-`)))return n.srcPath}},Ie=(e,t)=>{let n=new Set,r=[];for(let i of e){let e=Fe(i,t),a=e??i;n.has(a)||(n.add(a),e?r.push(`${i} (${e})`):r.push(i))}return r.join(`; `)},Le=(e,t)=>{let n=Pe(e);if(n.length===0)return;let r=Ie(n,t);throw Error(`Empty glyph path(s) in SVG font output for: ${r}. Stroke-only SVGs (fill="none" with stroke) often produce empty glyphs because svgicons2svgfont does not convert strokes. Convert strokes to filled paths in your design tool, preprocess with glyphContentTransformFn (for example svg-outline-stroke), or run with --svg-diagnose for compatibility warnings. See TROUBLESHOOTING.md ("Stroke-only SVGs produce blank icons").`)},Re=/fill-rule\s*:\s*evenodd|fill-rule\s*=\s*["']evenodd["']/iu,ze=e=>Re.test(e),Be=/\bstroke\s*=|\bstroke\s*:/iu,Ve=/fill\s*=\s*["']none["']|fill\s*:\s*none/iu,He=/<(line|polyline|clipPath)\b/iu,Ue=e=>Be.test(e)?Ve.test(e):!1,We=e=>He.test(e),K=(e,t)=>{switch(e){case`evenodd-fill-rule`:return`[webfont:diagnose] ${t} uses fill-rule: evenodd. Icon fonts render glyphs with the nonzero fill rule, so holes and counter-shapes can disappear. See TROUBLESHOOTING.md ("Icon details missing after export").`;case`stroke-only`:return`[webfont:diagnose] ${t} uses stroke-based paths (fill="none"). svgicons2svgfont ignores stroke; outlines may render as solid shapes or lose detail. Preprocess with glyphContentTransformFn (for example svg-outline-stroke) before conversion. See TROUBLESHOOTING.md ("Icon details missing after export").`;case`unsupported-element`:return`[webfont:diagnose] ${t} contains <line>, <polyline>, or <clipPath>. These elements are poorly supported in icon fonts; results may differ from the browser preview. Convert to filled paths or preprocess with glyphContentTransformFn.`;default:return e}},q=(e,t)=>{let n=[];return ze(t)&&n.push({code:`evenodd-fill-rule`,message:K(`evenodd-fill-rule`,e),srcPath:e}),Ue(t)&&n.push({code:`stroke-only`,message:K(`stroke-only`,e),srcPath:e}),We(t)&&n.push({code:`unsupported-element`,message:K(`unsupported-element`,e),srcPath:e}),n},J=e=>e.flatMap(e=>q(e.srcPath,e.contents)),Ge=(e,t)=>t.diagnose?!0:!!(t.verbose&&e.code===`evenodd-fill-rule`),Ke=e=>{if(!e||!e.diagnose)return;let t={diagnose:!0};return e.onMessage&&(t.onMessage=e.onMessage),t},qe=(e,t,n={})=>{let r=Ke(t),i=J(e),{reporter:a,verbose:o=!1}=n;for(let e of i)Ge(e,{diagnose:r?.diagnose,verbose:o})&&a?.(e.message);let s=[];return r?.diagnose&&(s=i),{diagnostics:s,glyphs:e}},Je=(e,t,n={})=>{let{diagnostics:r,glyphs:i}=qe(e,t,n);return{diagnostics:r,glyphs:i}},Ye=(e,t)=>{let n=``;return new Promise((r,i)=>{t.verbose&&console.log(`Generating SVG font...`);let a=new p.SVGIcons2SVGFontStream(ye(t)).on(`finish`,()=>r(n)).on(`data`,e=>{n+=e}).on(`error`,e=>i(e));e.forEach(e=>{let t=new te.Readable;t.push(e.contents),t.push(null),t.metadata=e.metadata??{name:``,unicode:[]},a.write(t)}),a.end()})},Xe=(e,t={})=>Buffer.from((0,h.default)(e,t).buffer),Ze=e=>b(e),Qe=(e,t)=>x(e,t),Y=e=>S(e),$e=async(e,t)=>{let n=e=>{if(t.svgTools?.onMessage){t.svgTools.onMessage(e);return}(t.svgTools?.diagnose||t.verbose)&&console.log(e)},r=!!(t.svgTools?.onMessage||t.svgTools?.diagnose||t.verbose),i;r&&(i=n);let{diagnostics:a,glyphs:o}=Je(e,t.svgTools,{reporter:i,verbose:t.verbose}),s=o;if(t.optimizeSvg&&(s=Oe(s,t.svgoConfig)),t.glyphContentTransformFn){let e=t.glyphContentTransformFn;s=await Promise.all(s.map(async t=>{let n=await e(t);return{...t,contents:n}}))}if(t.glyphTransformFn){let e=t.glyphTransformFn;s=await Promise.all(s.map(async t=>{let n=await e(t.metadata??{name:``,unicode:[]});return{...t,metadata:n}}))}ke(s.length,t.ligatures)&&console.log(Ae(s.length));let c={};t.formatsOptions?.ttf&&(c=t.formatsOptions.ttf);let l=await Ye(s,t);Le(l,s);let u=Xe(l,c),d={config:t,glyphsData:s,hash:m.default.createHash(`md5`).update(l).digest(`hex`),svg:l,ttf:u};a.length>0&&(d.svgDiagnostics=a);let{formats:f}=t;if(f.includes(`eot`)&&(d.eot=Ze(u)),f.includes(`woff`)){let e;typeof t.metadata==`string`&&(e=t.metadata),d.woff=Qe(u,{metadata:e})}if(f.includes(`woff2`)&&(d.woff2=Buffer.from(await Y(u))),t.template){let{renderTemplates:e}=await Promise.resolve().then(()=>require("./renderTemplates-zCYCzeOt.js")),{templates:n,usedBuildInTemplate:r}=e(t,d,f);n.length>0&&(d.templates=n,d.template=n[0]?.content,d.usedBuildInTemplate=r)}return f.includes(`svg`)||delete d.svg,f.includes(`ttf`)||delete d.ttf,f.includes(`otf`)||delete d.otf,d},X=new Set([`eot`,`otf`,`svg`,`ttf`,`woff`,`woff2`]),et=[...X].join(`, `),tt=e=>{if(typeof e!=`string`||!X.has(e))throw Error(`Invalid format "${String(e)}". Expected one of: ${et}`);return e},nt=e=>{if(e.length===0)throw Error(`formats must not be empty`);return e.map(tt)},rt=e=>{if(!Array.isArray(e))throw Error(`formats must be an array of format names (e.g. ["woff2", "svg"])`);return nt(e)},Z=(e,t)=>{if(t!==void 0&&typeof t!=`string`)throw Error(`${e} must be a string`)},it=(e,t)=>{if(t!==void 0&&typeof t!=`boolean`&&typeof t!=`string`)throw Error(`${e} must be a boolean or string`)},Q=(e,t)=>{if(t!==void 0&&typeof t!=`boolean`)throw Error(`${e} must be a boolean`)},at=(e,t)=>{if(t!==void 0&&(typeof t!=`object`||!t||Array.isArray(t)))throw Error(`${e} must be an object`)},ot=e=>{if(typeof e==`string`){if(e.length===0)throw Error(`files must not be empty`);return}if(Array.isArray(e)){if(e.length===0)throw Error(`files must not be empty`);if(!e.every(e=>typeof e==`string`))throw Error(`files must be a string or an array of strings`);return}throw Error(`files must be a string or an array of strings`)},st=t=>(ot(t.files),t.formats=rt(t.formats),Z(`fontName`,t.fontName),it(`unicodeRange`,t.unicodeRange),Q(`optimizeSvg`,t.optimizeSvg),at(`svgoConfig`,t.svgoConfig),Q(`templateFontLigatures`,t.templateFontLigatures),t.template!==void 0&&e.t(t.template),Z(`templateFontPath`,t.templateFontPath),t),ct=e=>`filepath`in e,lt=async e=>{let n=(0,t.cosmiconfig)(`webfont`,{searchStrategy:`global`});if(e.configFile){let t=r.default.resolve(process.cwd(),e.configFile);return await n.load(t)??{}}return await n.search(process.cwd())??{}},$=async e=>{let t=we(e);delete t.filePath;let r=await lt({configFile:t.configFile}),i;ct(r)&&(t=(0,n.default)(t,r.config,{arrayMerge:(e,t)=>t}),i=r.filepath),t=st(t);let a;a=Array.isArray(t.files)?t.files:[t.files];let o=await v(a),s=ce(o);if(s===`mixed`)throw Error(`Cannot mix SVG icons, TTF fonts, and WOFF/WOFF2 files in the same run`);if(s===`empty`)throw Error(`Files glob patterns specified did not match any supported files`);if(s===`webfont`){let e=await he(j(o,s),t);return i&&(e.config={...t,filePath:i}),e}if(s===`ttf`){let e=await B(j(o,s),t);return i&&(e.config={...t,filePath:i}),e}A(t.formats);let c=await $e(await Se(j(o,`svg`),t),t);return i?c.config={...t,filePath:i}:c.config=t,c},ut=$;exports.default=ut,exports.diagnoseGlyphsData=J,exports.diagnoseSvgContents=q,exports.webfont=$;
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env node
2
+ import { fileURLToPath as e } from "node:url";
3
+ e(import.meta.url), e(new URL(".", import.meta.url));
4
+ //#region src/lib/parseTemplateOption.ts
5
+ var t = (e) => {
6
+ if (e == null) return [];
7
+ if (typeof e == "string") {
8
+ let t = e.trim();
9
+ if (t.length === 0) throw Error("template must not be empty");
10
+ return [t];
11
+ }
12
+ if (Array.isArray(e)) {
13
+ if (e.length === 0) throw Error("template must not be empty");
14
+ if (!e.every((e) => typeof e == "string" && e.trim().length > 0)) throw Error("template must be a string or an array of non-empty strings");
15
+ return e.map((e) => e.trim());
16
+ }
17
+ throw Error("template must be a string or an array of strings");
18
+ };
19
+ //#endregion
20
+ export { t };
@@ -0,0 +1 @@
1
+ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,t)=>()=>(t||(e((t={exports:{}}).exports,t),e=null),t.exports),s=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},c=(n,r,a)=>(a=n==null?{}:e(i(n)),s(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n)),l=e=>{if(e==null)return[];if(typeof e==`string`){let t=e.trim();if(t.length===0)throw Error(`template must not be empty`);return[t]}if(Array.isArray(e)){if(e.length===0)throw Error(`template must not be empty`);if(!e.every(e=>typeof e==`string`&&e.trim().length>0))throw Error(`template must be a string or an array of non-empty strings`);return e.map(e=>e.trim())}throw Error(`template must be a string or an array of strings`)};Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return c}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return l}});
@@ -0,0 +1,93 @@
1
+ #!/usr/bin/env node
2
+ import { fileURLToPath as e } from "node:url";
3
+ e(import.meta.url);
4
+ const t = e(new URL(".", import.meta.url));
5
+ import { t as n } from "./parseTemplateOption-5T7rSw5J.mjs";
6
+ import r from "path";
7
+ import i from "deepmerge";
8
+ import a from "nunjucks";
9
+ //#region templates/index.ts
10
+ var o = () => r.resolve(t, "../templates"), s = (e) => `${o()}/template.${e}.njk`, c = () => {
11
+ let e = o();
12
+ return {
13
+ css: { path: r.join(e, "template.css.njk") },
14
+ html: { path: r.join(e, "template.html.njk") },
15
+ json: { path: r.join(e, "template.json.njk") },
16
+ scss: { path: r.join(e, "template.scss.njk") },
17
+ styl: { path: r.join(e, "template.styl.njk") }
18
+ };
19
+ }, l = (e) => {
20
+ let t = 4;
21
+ return e > 65535 && (t = 6), e.toString(16).toUpperCase().padStart(t, "0");
22
+ }, u = (e) => {
23
+ if (e.length === 0 || e.length > 2) return;
24
+ let t = e.codePointAt(0);
25
+ if (t !== void 0 && !(e.length > 1 && t < 128)) return t;
26
+ }, d = (e) => {
27
+ let t = [];
28
+ for (let n of e) for (let e of n.unicode ?? []) {
29
+ let n = u(e);
30
+ n !== void 0 && t.push(n);
31
+ }
32
+ return t;
33
+ }, f = (e) => {
34
+ let t = d(e);
35
+ if (t.length === 0) return;
36
+ let n = Math.min(...t), r = Math.max(...t);
37
+ return n === r ? `U+${l(n)}` : `U+${l(n)}-${l(r)}`;
38
+ }, p = (e, t) => {
39
+ if (!(e === !1 || e === void 0)) return typeof e == "string" ? e : f(t);
40
+ }, m = (e, t) => {
41
+ if (e === "woff2") {
42
+ if (!t.woff2) throw Error("Missing woff2 buffer for template rendering");
43
+ return Buffer.from(t.woff2).toString("base64");
44
+ }
45
+ let n = t[e];
46
+ if (!n) throw Error(`Missing ${e} buffer for template rendering`);
47
+ return n.toString("base64");
48
+ }, h = (e, o, l) => {
49
+ let u = n(e.template);
50
+ if (u.length === 0) return {
51
+ templates: [],
52
+ usedBuildInTemplate: !1
53
+ };
54
+ let d = c(), f = [], h = !1, g = {};
55
+ e.addHashInFontUrl && (g = { hash: o.hash });
56
+ let _ = o.glyphsData?.map((e) => e.metadata).filter((e) => e !== void 0) ?? [], v = i.all([
57
+ { glyphs: _ },
58
+ e,
59
+ {
60
+ cacheString: e.templateCacheString || Date.now(),
61
+ className: e.templateClassName || e.fontName,
62
+ fontFamily: e.templateFontName || e.fontName,
63
+ fontPath: e.templateFontPath.replace(/\/?$/u, "/"),
64
+ svgFontId: e.fontId || e.fontName
65
+ },
66
+ g,
67
+ { fonts: Object.fromEntries(new Map(l.map((e) => [e, () => m(e, o)]))) },
68
+ { unicodeRange: p(e.unicodeRange, _) },
69
+ { templateFontLigatures: e.templateFontLigatures !== !1 }
70
+ ]);
71
+ for (let e of u) {
72
+ let n, i;
73
+ if (Object.keys(d).includes(e)) {
74
+ h = !0, i = e;
75
+ let o = r.resolve(t, "../..");
76
+ a.configure(o), n = s(e);
77
+ } else {
78
+ let t = r.resolve(e);
79
+ a.configure(r.dirname(t)), n = r.resolve(t);
80
+ }
81
+ f.push({
82
+ template: e,
83
+ content: a.render(n, v),
84
+ builtIn: i
85
+ });
86
+ }
87
+ return {
88
+ templates: f,
89
+ usedBuildInTemplate: h
90
+ };
91
+ };
92
+ //#endregion
93
+ export { h as renderTemplates };
@@ -0,0 +1 @@
1
+ const e=require("./parseTemplateOption-BmH_pcQh.js");let t=require("deepmerge");t=e.r(t);let n=require("path");n=e.r(n);let r=require("nunjucks");r=e.r(r);var i=()=>n.default.resolve(__dirname,`../templates`),a=e=>`${i()}/template.${e}.njk`,o=()=>{let e=i();return{css:{path:n.default.join(e,`template.css.njk`)},html:{path:n.default.join(e,`template.html.njk`)},json:{path:n.default.join(e,`template.json.njk`)},scss:{path:n.default.join(e,`template.scss.njk`)},styl:{path:n.default.join(e,`template.styl.njk`)}}},s=e=>{let t=4;return e>65535&&(t=6),e.toString(16).toUpperCase().padStart(t,`0`)},c=e=>{if(e.length===0||e.length>2)return;let t=e.codePointAt(0);if(t!==void 0&&!(e.length>1&&t<128))return t},l=e=>{let t=[];for(let n of e)for(let e of n.unicode??[]){let n=c(e);n!==void 0&&t.push(n)}return t},u=e=>{let t=l(e);if(t.length===0)return;let n=Math.min(...t),r=Math.max(...t);return n===r?`U+${s(n)}`:`U+${s(n)}-${s(r)}`},d=(e,t)=>{if(!(e===!1||e===void 0))return typeof e==`string`?e:u(t)},f=(e,t)=>{if(e===`woff2`){if(!t.woff2)throw Error(`Missing woff2 buffer for template rendering`);return Buffer.from(t.woff2).toString(`base64`)}let n=t[e];if(!n)throw Error(`Missing ${e} buffer for template rendering`);return n.toString(`base64`)},p=(i,s,c)=>{let l=e.t(i.template);if(l.length===0)return{templates:[],usedBuildInTemplate:!1};let u=o(),p=[],m=!1,h={};i.addHashInFontUrl&&(h={hash:s.hash});let g=s.glyphsData?.map(e=>e.metadata).filter(e=>e!==void 0)??[],_=t.default.all([{glyphs:g},i,{cacheString:i.templateCacheString||Date.now(),className:i.templateClassName||i.fontName,fontFamily:i.templateFontName||i.fontName,fontPath:i.templateFontPath.replace(/\/?$/u,`/`),svgFontId:i.fontId||i.fontName},h,{fonts:Object.fromEntries(new Map(c.map(e=>[e,()=>f(e,s)])))},{unicodeRange:d(i.unicodeRange,g)},{templateFontLigatures:i.templateFontLigatures!==!1}]);for(let e of l){let t,i;if(Object.keys(u).includes(e)){m=!0,i=e;let o=n.default.resolve(__dirname,`../..`);r.default.configure(o),t=a(e)}else{let i=n.default.resolve(e);r.default.configure(n.default.dirname(i)),t=n.default.resolve(i)}p.push({template:e,content:r.default.render(t,_),builtIn:i})}return{templates:p,usedBuildInTemplate:m}};exports.renderTemplates=p;
@@ -0,0 +1,2 @@
1
+ export declare const webfont: () => Promise<never>;
2
+ export default webfont;
@@ -1,3 +1,5 @@
1
1
  import { webfont } from './standalone';
2
+ export { diagnoseGlyphsData, diagnoseSvgContents } from './lib/svgDiagnostics/diagnoseSvgContents';
2
3
  export { webfont } from './standalone';
4
+ export type { SvgDiagnosticCode, SvgGlyphDiagnostic, SvgToolsOptions } from './types/SvgToolsOptions';
3
5
  export default webfont;
@@ -0,0 +1,3 @@
1
+ import { Config } from 'svgo';
2
+ import { GlyphData } from '../types/GlyphData';
3
+ export declare const applyOptimizeSvgToGlyphs: (glyphs: GlyphData[], svgoConfig?: Config) => GlyphData[];
@@ -0,0 +1,2 @@
1
+ export declare const hasEvenoddFillRule: (svgContents: string) => boolean;
2
+ export declare const evenoddFillRuleWarning: (srcPath: string) => string;
@@ -1,5 +1,2 @@
1
- export declare const isHttpUrl: (value: string) => boolean;
2
- export declare const getInputExtension: (source: string) => string;
1
+ export { getInputExtension, getWebfontSourceBasename, isHttpUrl, resolveDecompressedFontBasenames, } from './inputSourceUtils';
3
2
  export declare const resolveInputSources: (patterns: readonly string[]) => Promise<string[]>;
4
- export declare const getWebfontSourceBasename: (source: string) => string;
5
- export declare const resolveDecompressedFontBasenames: (sources: readonly string[]) => string[];
@@ -0,0 +1,4 @@
1
+ export declare const isHttpUrl: (value: string) => boolean;
2
+ export declare const getInputExtension: (source: string) => string;
3
+ export declare const getWebfontSourceBasename: (source: string) => string;
4
+ export declare const resolveDecompressedFontBasenames: (sources: readonly string[]) => string[];
@@ -0,0 +1,4 @@
1
+ /** Glyph count above which OpenType ligatures often hurt browser layout (Firefox / DirectWrite). */
2
+ export declare const LARGE_FONT_LIGATURE_GLYPH_THRESHOLD = 2000;
3
+ export declare const shouldWarnLargeFontLigatures: (glyphCount: number, ligaturesEnabled: boolean) => boolean;
4
+ export declare const formatLargeFontLigatureWarning: (glyphCount: number) => string;
@@ -0,0 +1,4 @@
1
+ import { Config } from 'svgo';
2
+ /** Conservative SVGO preset: cleanup cruft without rewriting paths or removing viewBox. */
3
+ export declare const defaultWebfontSvgoConfig: () => Config;
4
+ export declare const optimizeSvgContents: (contents: string, srcPath: string, config?: Config) => string;
@@ -0,0 +1,4 @@
1
+ import { Format, Formats } from '../types/Format';
2
+ export declare const assertValidFormat: (value: unknown) => Format;
3
+ export declare const parseFormatsList: (values: readonly unknown[]) => Formats;
4
+ export declare const assertFormatsOption: (formats: unknown) => Formats;
@@ -0,0 +1,2 @@
1
+ export type TemplateOption = string | string[];
2
+ export declare const normalizeTemplateOption: (template: unknown) => string[];
@@ -0,0 +1,4 @@
1
+ /** True in browser tabs and Web Workers (including Vite `process` polyfills). */
2
+ export declare const isBrowserOrWorkerRuntime: () => boolean;
3
+ /** True only in real Node.js — not in browser tabs or Web Workers. */
4
+ export declare const isNodeRuntime: () => boolean;
@@ -0,0 +1,12 @@
1
+ import { SvgGlyphDiagnostic } from '../../types/SvgToolsOptions';
2
+ export declare const hasStrokeOnlySvg: (svgContents: string) => boolean;
3
+ export declare const hasUnsupportedSvgElements: (svgContents: string) => boolean;
4
+ export declare const diagnoseSvgContents: (srcPath: string, svgContents: string) => SvgGlyphDiagnostic[];
5
+ export declare const diagnoseGlyphsData: (glyphs: ReadonlyArray<{
6
+ contents: string;
7
+ srcPath: string;
8
+ }>) => SvgGlyphDiagnostic[];
9
+ export declare const shouldLogDiagnostic: (diagnostic: SvgGlyphDiagnostic, options: {
10
+ diagnose?: boolean;
11
+ verbose?: boolean;
12
+ }) => boolean;
@@ -0,0 +1,3 @@
1
+ import { GlyphData } from '../../types/GlyphData';
2
+ export declare const findEmptySvgFontGlyphNames: (svgFont: string) => string[];
3
+ export declare const assertNonEmptySvgFontGlyphs: (svgFont: string, glyphsData: ReadonlyArray<Pick<GlyphData, "metadata" | "srcPath">>) => void;
@@ -0,0 +1,13 @@
1
+ import { GlyphData } from '../../types/GlyphData';
2
+ import { SvgGlyphDiagnostic } from '../../types/SvgToolsOptions';
3
+ export type SvgToolsReporter = (message: string) => void;
4
+ export type ApplySvgDiagnosticsResult = {
5
+ diagnostics: SvgGlyphDiagnostic[];
6
+ glyphs: GlyphData[];
7
+ };
8
+ export declare const applySvgDiagnosticsToGlyphs: (glyphsData: GlyphData[], svgToolsInput: {
9
+ diagnose?: boolean;
10
+ } | undefined, runtime?: {
11
+ reporter?: SvgToolsReporter;
12
+ verbose?: boolean;
13
+ }) => ApplySvgDiagnosticsResult;
@@ -0,0 +1,14 @@
1
+ import { GlyphData } from '../../types/GlyphData';
2
+ import { SvgGlyphDiagnostic, SvgToolsOptions } from '../../types/SvgToolsOptions';
3
+ import { SvgToolsReporter } from './applySvgDiagnostics';
4
+ export type { SvgToolsReporter } from './applySvgDiagnostics';
5
+ export type ApplySvgToolsResult = {
6
+ diagnostics: SvgGlyphDiagnostic[];
7
+ glyphs: GlyphData[];
8
+ };
9
+ export type ApplySvgToolsRuntime = {
10
+ reporter?: SvgToolsReporter;
11
+ /** When true, logs evenodd diagnostics even if svgTools.diagnose is off (backward compatible with --verbose). */
12
+ verbose?: boolean;
13
+ };
14
+ export declare const applySvgToolsToGlyphs: (glyphsData: GlyphData[], svgToolsInput: SvgToolsOptions | undefined, runtime?: ApplySvgToolsRuntime) => ApplySvgToolsResult;
@@ -0,0 +1,2 @@
1
+ import { SvgToolsOptions } from '../../types/SvgToolsOptions';
2
+ export declare const normalizeSvgToolsOptions: (svgTools?: SvgToolsOptions) => SvgToolsOptions | undefined;
@@ -6,4 +6,9 @@ type MetadataServiceOptions = {
6
6
  startUnicode: number;
7
7
  };
8
8
  export declare const getMetadataServiceOptions: (options: WebfontOptions) => MetadataServiceOptions;
9
+ /**
10
+ * Coerce `round` for svgicons2svgfont; accepts number or numeric string (CLI/config).
11
+ * Returns undefined for undefined/null/empty/non-numeric/non-finite inputs.
12
+ */
13
+ export declare const normalizeRoundOption: (round: string | number | null | undefined) => number | undefined;
9
14
  export declare const getFontStreamOptions: (options: WebfontOptions) => Partial<SVGIcons2SVGFontStreamOptions>;
@@ -0,0 +1,11 @@
1
+ import { MetadataProvider } from '../../types/MetadataProvider';
2
+ type MetadataServiceOptions = {
3
+ prependUnicode: boolean;
4
+ startUnicode: number;
5
+ };
6
+ /**
7
+ * Browser-safe metadata lookup from a virtual `srcPath` (no `fs`, no file rename).
8
+ * Mirrors {@link https://github.com/nfroidure/svgicons2svgfont | svgicons2svgfont} filename rules.
9
+ */
10
+ export declare const createMetadataFromSrcPathService: (options?: Partial<MetadataServiceOptions>) => MetadataProvider;
11
+ export {};
@@ -0,0 +1,4 @@
1
+ import { GlyphMetadata } from '../types/GlyphMetadata';
2
+ export declare const collectCodePointsFromGlyphs: (glyphs: readonly Pick<GlyphMetadata, "unicode">[]) => number[];
3
+ export declare const computeUnicodeRangeFromGlyphs: (glyphs: readonly Pick<GlyphMetadata, "unicode">[]) => string | undefined;
4
+ export declare const resolveTemplateUnicodeRange: (unicodeRange: boolean | string | undefined, glyphs: readonly Pick<GlyphMetadata, "unicode">[]) => string | undefined;
@@ -0,0 +1,5 @@
1
+ export declare const encodeTtfToEot: (buffer: Buffer) => Buffer;
2
+ export declare const encodeTtfToWoff: (buffer: Buffer, options?: {
3
+ metadata?: string;
4
+ }) => Buffer;
5
+ export declare const encodeTtfToWoff2: (buffer: Buffer) => Promise<Buffer>;
@@ -0,0 +1,3 @@
1
+ import { Result } from '../types/Result';
2
+ import { WebfontOptions } from '../types/WebfontOptions';
3
+ export declare const convertTtfInput: (fontFiles: readonly string[], options: WebfontOptions) => Promise<Result>;
@@ -0,0 +1,3 @@
1
+ import { WebfontOptions } from '../types/WebfontOptions';
2
+ /** Shared defaults for Node (`files`) and in-memory (`glyphs`) entry points. */
3
+ export declare const defaultWebfontOptions: () => Omit<WebfontOptions, "files">;
@@ -0,0 +1,2 @@
1
+ import { GlyphData, WebfontOptions } from '../types';
2
+ export declare const generateSvgFont: (glyphsData: GlyphData[], options: WebfontOptions) => Promise<string>;
@@ -0,0 +1,3 @@
1
+ import { GlyphData, WebfontOptions } from '../types';
2
+ import { GlyphInput } from '../types/GlyphInput';
3
+ export declare const getGlyphsDataFromInputs: (inputs: readonly GlyphInput[], options: WebfontOptions) => Promise<GlyphData[]>;
@@ -1,4 +1,4 @@
1
1
  import { GlyphData, WebfontOptions } from '../types';
2
- type GlyphsDataGetter = (_files: Array<GlyphData["srcPath"]>, _options: WebfontOptions) => unknown;
2
+ type GlyphsDataGetter = (_files: Array<GlyphData["srcPath"]>, _options: WebfontOptions) => Promise<GlyphData[]>;
3
3
  export declare const getGlyphsData: GlyphsDataGetter;
4
4
  export {};
@@ -1,5 +1,10 @@
1
+ import { cosmiconfig } from 'cosmiconfig';
1
2
  import { InitialOptions } from '../types';
2
3
  import { Result } from '../types/Result';
4
+ type CosmiconfigLoaded = NonNullable<Awaited<ReturnType<ReturnType<typeof cosmiconfig>["search"]>>>;
5
+ export declare const loadWebfontConfig: (options: {
6
+ configFile?: string;
7
+ }) => Promise<CosmiconfigLoaded | Record<string, never>>;
3
8
  type Webfont = (_initialOptions?: InitialOptions) => Promise<Result>;
4
9
  export declare const webfont: Webfont;
5
10
  export default webfont;
@@ -1,7 +1,9 @@
1
1
  import { Format } from '../types/Format';
2
- export type InputMode = "empty" | "mixed" | "svg" | "webfont";
2
+ export type InputMode = "empty" | "mixed" | "svg" | "ttf" | "webfont";
3
3
  export declare const classifyInputFiles: (filePaths: readonly string[]) => InputMode;
4
4
  export declare const assertSvgPipelineFormats: (formats: readonly Format[]) => void;
5
5
  export declare const filterInputFilesByMode: (filePaths: readonly string[], mode: InputMode) => string[];
6
6
  export type ConversionFormat = "otf" | "ttf";
7
+ export type TtfEncodeFormat = "eot" | "ttf" | "woff" | "woff2";
8
+ export declare const resolveTtfConversionFormats: (formats: readonly Format[]) => TtfEncodeFormat[];
7
9
  export declare const resolveWebfontConversionFormats: (formats: readonly Format[]) => ConversionFormat[];
@@ -0,0 +1,3 @@
1
+ import { WebfontFromGlyphsOptions } from '../types/WebfontFromGlyphsOptions';
2
+ import { WebfontOptions } from '../types/WebfontOptions';
3
+ export declare const getOptionsFromGlyphs: (initialOptions: WebfontFromGlyphsOptions) => WebfontOptions;
@@ -0,0 +1,10 @@
1
+ import { Format } from '../types/Format';
2
+ import { RenderedTemplate } from '../types/RenderedTemplate';
3
+ import { Result } from '../types/Result';
4
+ import { WebfontOptions } from '../types/WebfontOptions';
5
+ type RenderTemplatesResult = {
6
+ templates: RenderedTemplate[];
7
+ usedBuildInTemplate: boolean;
8
+ };
9
+ export declare const renderTemplates: (options: WebfontOptions, result: Pick<Result, "glyphsData" | "hash"> & Partial<Result>, formats: readonly Format[]) => RenderTemplatesResult;
10
+ export {};
@@ -0,0 +1,3 @@
1
+ import { GlyphData, WebfontOptions } from '../types';
2
+ import { Result } from '../types/Result';
3
+ export declare const runSvgPipeline: (glyphsData: GlyphData[], options: WebfontOptions) => Promise<Result>;
@@ -0,0 +1,6 @@
1
+ import { WebfontOptions } from '../types/WebfontOptions';
2
+ /**
3
+ * Runtime validation for merged webfont options (API, cosmiconfig, CLI).
4
+ * Rejects mis-typed or unknown format names before running a pipeline (#133).
5
+ */
6
+ export declare const validateWebfontOptions: (options: WebfontOptions) => WebfontOptions;
@@ -0,0 +1,3 @@
1
+ import { Result } from '../types/Result';
2
+ import { WebfontFromGlyphsOptions } from '../types/WebfontFromGlyphsOptions';
3
+ export declare const webfontFromGlyphs: (initialOptions: WebfontFromGlyphsOptions) => Promise<Result>;
@@ -0,0 +1,2 @@
1
+ import { GlyphData } from './GlyphData';
2
+ export type GlyphContentTransformFn = (_glyph: GlyphData) => string | Promise<string>;
@@ -0,0 +1,6 @@
1
+ export type GlyphInput = {
2
+ /** SVG source text. */
3
+ contents: string;
4
+ /** Logical path or filename used for metadata (defaults to `icon.svg`). */
5
+ srcPath?: string;
6
+ };
@@ -1,8 +1,10 @@
1
+ import { GlyphContentTransformFn } from './GlyphContentTransformFn';
1
2
  import { GlyphTransformFn } from './GlyphTransformFn';
2
3
  import { MetadataProvider } from './MetadataProvider';
3
4
  import { OptionsBase } from './OptionsBase';
4
5
  export type InitialOptions = OptionsBase & {
5
6
  files: string | Array<string>;
7
+ glyphContentTransformFn?: GlyphContentTransformFn;
6
8
  glyphTransformFn?: GlyphTransformFn;
7
9
  metadataProvider?: MetadataProvider;
8
10
  };
@@ -1,11 +1,13 @@
1
+ import { TemplateOption } from '../lib/parseTemplateOption';
1
2
  import { Formats } from './Format';
3
+ import { SvgToolsOptions } from './SvgToolsOptions';
2
4
  export type OptionsBase = {
3
5
  configFile?: string;
4
6
  dest?: string;
5
7
  destCreate?: boolean;
6
8
  fontName?: string | unknown;
7
9
  formats?: Formats;
8
- template?: "css" | string;
10
+ template?: TemplateOption;
9
11
  templateClassName?: string | unknown;
10
12
  templateFontPath?: string;
11
13
  templateFontName?: string | unknown;
@@ -28,4 +30,10 @@ export type OptionsBase = {
28
30
  sort?: boolean;
29
31
  ligatures?: boolean;
30
32
  addHashInFontUrl?: boolean | unknown;
33
+ unicodeRange?: boolean | string | unknown;
34
+ optimizeSvg?: boolean | unknown;
35
+ svgoConfig?: unknown;
36
+ templateFontLigatures?: boolean | unknown;
37
+ /** Alpha. SVG diagnostics and optional pre-conversion fixes. */
38
+ svgTools?: SvgToolsOptions;
31
39
  };
@@ -0,0 +1,7 @@
1
+ export type RenderedTemplate = {
2
+ /** Original template option (built-in name or custom path). */
3
+ template: string;
4
+ content: string;
5
+ /** Built-in template id when applicable (css, html, scss, …). */
6
+ builtIn?: string;
7
+ };
@@ -1,18 +1,26 @@
1
1
  import { DecompressedFont } from './DecompressedFont';
2
2
  import { GlyphData } from './GlyphData';
3
+ import { RenderedTemplate } from './RenderedTemplate';
3
4
  import { ResultConfig } from './ResultConfig';
5
+ import { SvgGlyphDiagnostic } from './SvgToolsOptions';
6
+ import { TranscodedFont } from './TranscodedFont';
4
7
  export type { DecompressedFont } from './DecompressedFont';
8
+ export type { TranscodedFont } from './TranscodedFont';
5
9
  export type Result = {
6
10
  config?: ResultConfig;
7
11
  decompressedFonts?: DecompressedFont[];
12
+ transcodedFonts?: TranscodedFont[];
8
13
  eot?: Buffer;
9
14
  glyphsData?: Array<GlyphData>;
10
15
  hash?: string;
11
16
  otf?: Buffer;
12
17
  svg?: string | Buffer;
13
18
  template?: string;
19
+ templates?: RenderedTemplate[];
14
20
  ttf?: Buffer;
15
21
  usedBuildInTemplate?: boolean;
16
22
  woff?: Buffer;
17
23
  woff2?: Buffer;
24
+ /** Alpha. Populated when `svgTools.diagnose` is enabled. */
25
+ svgDiagnostics?: SvgGlyphDiagnostic[];
18
26
  };
@@ -0,0 +1,13 @@
1
+ export type SvgDiagnosticCode = "evenodd-fill-rule" | "stroke-only" | "unsupported-element";
2
+ export type SvgGlyphDiagnostic = {
3
+ code: SvgDiagnosticCode;
4
+ message: string;
5
+ srcPath: string;
6
+ };
7
+ /** Alpha. SVG diagnostics for the icon-font pipeline (see ADR 0011 — no bundled stroke-to-fill fixes). */
8
+ export type SvgToolsOptions = {
9
+ /** Scan source SVGs for known icon-font incompatibilities and report warnings. */
10
+ diagnose?: boolean;
11
+ /** Optional sink for diagnostic log lines (for example a web worker or test spy). */
12
+ onMessage?: (message: string) => void;
13
+ };
@@ -0,0 +1,7 @@
1
+ export type TranscodedFont = {
2
+ source: string;
3
+ eot?: Buffer;
4
+ ttf?: Buffer;
5
+ woff?: Buffer;
6
+ woff2?: Buffer;
7
+ };
@@ -0,0 +1,11 @@
1
+ import { GlyphContentTransformFn } from './GlyphContentTransformFn';
2
+ import { GlyphInput } from './GlyphInput';
3
+ import { GlyphTransformFn } from './GlyphTransformFn';
4
+ import { MetadataProvider } from './MetadataProvider';
5
+ import { OptionsBase } from './OptionsBase';
6
+ export type WebfontFromGlyphsOptions = OptionsBase & {
7
+ glyphs: GlyphInput[];
8
+ glyphContentTransformFn?: GlyphContentTransformFn;
9
+ glyphTransformFn?: GlyphTransformFn;
10
+ metadataProvider?: MetadataProvider;
11
+ };
@@ -1,7 +1,11 @@
1
+ import { Config as SvgoConfig } from 'svgo';
2
+ import { TemplateOption } from '../lib/parseTemplateOption';
1
3
  import { Formats, FormatsOptions } from './Format';
4
+ import { GlyphContentTransformFn } from './GlyphContentTransformFn';
2
5
  import { GlyphTransformFn } from './GlyphTransformFn';
3
6
  import { InitialOptions } from './InitialOptions';
4
7
  import { MetadataProvider } from './MetadataProvider';
8
+ import { SvgToolsOptions } from './SvgToolsOptions';
5
9
  export interface WebfontOptions extends InitialOptions {
6
10
  centerHorizontally: boolean;
7
11
  descent: number;
@@ -14,20 +18,26 @@ export interface WebfontOptions extends InitialOptions {
14
18
  formats: Formats;
15
19
  formatsOptions: FormatsOptions;
16
20
  glyphTransformFn?: GlyphTransformFn;
21
+ glyphContentTransformFn?: GlyphContentTransformFn;
17
22
  ligatures: boolean;
18
23
  maxConcurrency: number;
19
24
  metadata: unknown;
20
25
  metadataProvider?: MetadataProvider;
21
26
  normalize: boolean;
22
27
  prependUnicode: boolean;
23
- round: number;
28
+ round: string | number;
24
29
  sort: boolean;
25
30
  startUnicode: number;
26
- template?: string;
31
+ template?: TemplateOption;
27
32
  templateCacheString?: unknown;
28
33
  templateClassName?: unknown;
29
34
  templateFontName?: unknown;
30
35
  templateFontPath: string;
31
36
  verbose: boolean;
32
37
  addHashInFontUrl?: boolean;
38
+ unicodeRange?: boolean | string;
39
+ optimizeSvg?: boolean;
40
+ svgoConfig?: SvgoConfig;
41
+ templateFontLigatures?: boolean;
42
+ svgTools?: SvgToolsOptions;
33
43
  }
@@ -1,4 +1,5 @@
1
- export type { Format } from '../types/Format';
1
+ export type { Format, FormatsOptions } from '../types/Format';
2
+ export type { GlyphContentTransformFn } from './GlyphContentTransformFn';
2
3
  export type { GlyphData } from './GlyphData';
3
4
  export type { GlyphMetadata } from './GlyphMetadata';
4
5
  export type { GlyphTransformFn } from './GlyphTransformFn';