svger-cli 3.1.1 → 4.0.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.
- package/CHANGELOG.md +332 -0
- package/README.md +432 -25
- package/SECURITY.md +3 -3
- package/assets/svges/500px.svg +3 -0
- package/assets/svges/adobe.svg +3 -0
- package/assets/svges/adonis.svg +3 -0
- package/assets/svges/aeroplane-1.svg +3 -0
- package/assets/svges/agenda.svg +3 -0
- package/assets/svges/airbnb.svg +3 -0
- package/assets/svges/airtable.svg +3 -0
- package/assets/svges/alarm-1.svg +7 -0
- package/assets/svges/align-text-center.svg +6 -0
- package/assets/svges/align-text-left.svg +6 -0
- package/assets/svges/align-text-right.svg +6 -0
- package/assets/svges/alpinejs.svg +4 -0
- package/assets/svges/amazon-original.svg +5 -0
- package/assets/svges/amazon-pay.svg +7 -0
- package/assets/svges/amazon.svg +10 -0
- package/assets/svges/ambulance-1.svg +4 -0
- package/assets/svges/amd.svg +3 -0
- package/assets/svges/amex.svg +4 -0
- package/assets/svges/anchor.svg +3 -0
- package/assets/svges/android-old.svg +3 -0
- package/assets/svges/android.svg +3 -0
- package/assets/svges/angellist.svg +3 -0
- package/assets/svges/angle-double-down.svg +4 -0
- package/assets/svges/angle-double-left.svg +4 -0
- package/assets/svges/angle-double-right.svg +4 -0
- package/assets/svges/angle-double-up.svg +4 -0
- package/assets/svges/angular.svg +3 -0
- package/assets/svges/app-store.svg +3 -0
- package/assets/svges/apple-brand.svg +3 -0
- package/assets/svges/apple-music-alt.svg +3 -0
- package/assets/svges/apple-music.svg +3 -0
- package/assets/svges/apple-pay.svg +3 -0
- package/assets/svges/arc-browser.svg +6 -0
- package/assets/svges/arrow-all-direction.svg +6 -0
- package/assets/svges/arrow-angular-top-left.svg +3 -0
- package/assets/svges/arrow-angular-top-right.svg +3 -0
- package/assets/svges/arrow-both-direction-horizontal-1.svg +3 -0
- package/assets/svges/arrow-both-direction-vertical-1.svg +3 -0
- package/assets/svges/arrow-downward.svg +3 -0
- package/assets/svges/arrow-left-circle.svg +4 -0
- package/assets/svges/arrow-left.svg +3 -0
- package/assets/svges/arrow-right-circle.svg +4 -0
- package/assets/svges/arrow-right.svg +3 -0
- package/assets/svges/arrow-upward.svg +3 -0
- package/assets/svges/asana.svg +3 -0
- package/assets/svges/astro.svg +4 -0
- package/assets/svges/atlassian.svg +3 -0
- package/assets/svges/audi-alt.svg +3 -0
- package/assets/svges/audi.svg +3 -0
- package/assets/svges/aws.svg +3 -0
- package/assets/svges/azure.svg +3 -0
- package/assets/svges/badge-decagram-percent.svg +6 -0
- package/assets/svges/balloons.svg +3 -0
- package/assets/svges/ban-2.svg +3 -0
- package/assets/svges/bar-chart-4.svg +6 -0
- package/assets/svges/bar-chart-dollar.svg +6 -0
- package/assets/svges/basket-shopping-3.svg +5 -0
- package/assets/svges/beat.svg +3 -0
- package/assets/svges/behance.svg +5 -0
- package/assets/svges/bell-1.svg +3 -0
- package/assets/svges/bike.svg +6 -0
- package/assets/svges/bing.svg +5 -0
- package/assets/svges/bitbucket.svg +5 -0
- package/assets/svges/bitcoin.svg +5 -0
- package/assets/svges/bittorrent.svg +6 -0
- package/assets/svges/blogger-alt.svg +3 -0
- package/assets/svges/blogger.svg +3 -0
- package/assets/svges/bluetooth-logo.svg +3 -0
- package/assets/svges/bluetooth.svg +3 -0
- package/assets/svges/bmw.svg +7 -0
- package/assets/svges/board-writing-3.svg +3 -0
- package/assets/svges/bold.svg +3 -0
- package/assets/svges/bolt-2.svg +3 -0
- package/assets/svges/bolt-3.svg +3 -0
- package/assets/svges/book-1.svg +4 -0
- package/assets/svges/bookmark-1.svg +3 -0
- package/assets/svges/bookmark-circle.svg +4 -0
- package/assets/svges/books-2.svg +3 -0
- package/assets/svges/bootstrap-5-square.svg +3 -0
- package/assets/svges/bootstrap-5.svg +3 -0
- package/assets/svges/box-archive-1.svg +4 -0
- package/assets/svges/box-closed.svg +3 -0
- package/assets/svges/box-gift-1.svg +3 -0
- package/assets/svges/brave.svg +3 -0
- package/assets/svges/bricks.svg +3 -0
- package/assets/svges/bridge-3.svg +3 -0
- package/assets/svges/briefcase-1.svg +3 -0
- package/assets/svges/briefcase-2.svg +3 -0
- package/assets/svges/briefcase-plus-1.svg +4 -0
- package/assets/svges/brush-1-rotated.svg +3 -0
- package/assets/svges/brush-2.svg +3 -0
- package/assets/svges/btc.svg +3 -0
- package/assets/svges/bug-1.svg +3 -0
- package/assets/svges/buildings-1.svg +5 -0
- package/assets/svges/bulb-2.svg +3 -0
- package/assets/svges/bulb-4.svg +9 -0
- package/assets/svges/burger-1.svg +3 -0
- package/assets/svges/burger-drink.svg +4 -0
- package/assets/svges/bus-1.svg +5 -0
- package/assets/svges/busket-ball.svg +3 -0
- package/assets/svges/cake-1.svg +3 -0
- package/assets/svges/calculator-1.svg +8 -0
- package/assets/svges/calculator-2.svg +13 -0
- package/assets/svges/calendar-days.svg +9 -0
- package/assets/svges/camera-1.svg +4 -0
- package/assets/svges/camera-movie-1.svg +3 -0
- package/assets/svges/candy-cane-2.svg +3 -0
- package/assets/svges/candy-round-1.svg +3 -0
- package/assets/svges/canva.svg +3 -0
- package/assets/svges/capsule-1.svg +3 -0
- package/assets/svges/car-2.svg +5 -0
- package/assets/svges/car-4.svg +3 -0
- package/assets/svges/car-6.svg +5 -0
- package/assets/svges/caravan-1.svg +3 -0
- package/assets/svges/cart-1.svg +5 -0
- package/assets/svges/cart-2.svg +5 -0
- package/assets/svges/cash-app.svg +3 -0
- package/assets/svges/certificate-badge-1.svg +6 -0
- package/assets/svges/chat-bubble-2.svg +5 -0
- package/assets/svges/check-circle-1.svg +4 -0
- package/assets/svges/check-square-2.svg +4 -0
- package/assets/svges/check.svg +3 -0
- package/assets/svges/chevron-down-circle.svg +4 -0
- package/assets/svges/chevron-down.svg +3 -0
- package/assets/svges/chevron-left-circle.svg +4 -0
- package/assets/svges/chevron-left.svg +3 -0
- package/assets/svges/chevron-right-circle.svg +4 -0
- package/assets/svges/chevron-up-circle.svg +4 -0
- package/assets/svges/chevron-up.svg +3 -0
- package/assets/svges/chrome.svg +6 -0
- package/assets/svges/chromecast.svg +3 -0
- package/assets/svges/cisco.svg +3 -0
- package/assets/svges/claude.svg +3 -0
- package/assets/svges/clickup.svg +4 -0
- package/assets/svges/clipboard.svg +3 -0
- package/assets/svges/cloud-2.svg +3 -0
- package/assets/svges/cloud-bolt-1.svg +4 -0
- package/assets/svges/cloud-bolt-2.svg +4 -0
- package/assets/svges/cloud-check-circle.svg +5 -0
- package/assets/svges/cloud-download.svg +5 -0
- package/assets/svges/cloud-iot-2.svg +3 -0
- package/assets/svges/cloud-rain.svg +6 -0
- package/assets/svges/cloud-refresh-clockwise.svg +5 -0
- package/assets/svges/cloud-sun.svg +9 -0
- package/assets/svges/cloud-upload.svg +5 -0
- package/assets/svges/cloudflare.svg +3 -0
- package/assets/svges/code-1.svg +5 -0
- package/assets/svges/code-s.svg +5 -0
- package/assets/svges/codepen.svg +3 -0
- package/assets/svges/coffee-cup-2.svg +6 -0
- package/assets/svges/coinbase.svg +10 -0
- package/assets/svges/colour-palette-3.svg +7 -0
- package/assets/svges/comment-1-share.svg +4 -0
- package/assets/svges/comment-1-text.svg +5 -0
- package/assets/svges/comment-1.svg +3 -0
- package/assets/svges/compass-drafting-2.svg +3 -0
- package/assets/svges/connectdevelop.svg +3 -0
- package/assets/svges/copilot.svg +8 -0
- package/assets/svges/coral.svg +3 -0
- package/assets/svges/cpanel.svg +3 -0
- package/assets/svges/crane-4.svg +3 -0
- package/assets/svges/creative-commons.svg +4 -0
- package/assets/svges/credit-card-multiple.svg +3 -0
- package/assets/svges/crop-2.svg +3 -0
- package/assets/svges/crown-3.svg +3 -0
- package/assets/svges/css3.svg +3 -0
- package/assets/svges/dashboard-square-1.svg +6 -0
- package/assets/svges/database-2.svg +3 -0
- package/assets/svges/deno.svg +4 -0
- package/assets/svges/dev.svg +3 -0
- package/assets/svges/dialogflow.svg +4 -0
- package/assets/svges/diamonds-1.svg +3 -0
- package/assets/svges/diamonds-2.svg +3 -0
- package/assets/svges/digitalocean.svg +3 -0
- package/assets/svges/diners-club.svg +38 -0
- package/assets/svges/direction-ltr.svg +4 -0
- package/assets/svges/direction-rtl.svg +4 -0
- package/assets/svges/discord-chat.svg +5 -0
- package/assets/svges/discord.svg +3 -0
- package/assets/svges/discover.svg +3 -0
- package/assets/svges/docker.svg +3 -0
- package/assets/svges/dollar-circle.svg +4 -0
- package/assets/svges/dollar.svg +3 -0
- package/assets/svges/double-quotes-end-1.svg +4 -0
- package/assets/svges/download-1.svg +4 -0
- package/assets/svges/download-circle-1.svg +4 -0
- package/assets/svges/dribbble-symbol.svg +3 -0
- package/assets/svges/dribbble.svg +3 -0
- package/assets/svges/drizzle.svg +6 -0
- package/assets/svges/dropbox.svg +7 -0
- package/assets/svges/drupal.svg +3 -0
- package/assets/svges/dumbbell-1.svg +3 -0
- package/assets/svges/edge.svg +3 -0
- package/assets/svges/emoji-expressionless-flat-eyes.svg +6 -0
- package/assets/svges/emoji-expressionless.svg +6 -0
- package/assets/svges/emoji-grin.svg +6 -0
- package/assets/svges/emoji-sad.svg +6 -0
- package/assets/svges/emoji-smile-side.svg +6 -0
- package/assets/svges/emoji-smile-sunglass.svg +5 -0
- package/assets/svges/emoji-smile-tongue.svg +3 -0
- package/assets/svges/emoji-smile.svg +6 -0
- package/assets/svges/enter-down.svg +4 -0
- package/assets/svges/enter.svg +4 -0
- package/assets/svges/envato.svg +4 -0
- package/assets/svges/envelope-1.svg +3 -0
- package/assets/svges/eraser-1.svg +4 -0
- package/assets/svges/ethereum-logo.svg +4 -0
- package/assets/svges/euro.svg +3 -0
- package/assets/svges/exit-up.svg +4 -0
- package/assets/svges/exit.svg +4 -0
- package/assets/svges/expand-arrow-1.svg +3 -0
- package/assets/svges/expand-square-4.svg +6 -0
- package/assets/svges/expressjs.svg +4 -0
- package/assets/svges/eye.svg +4 -0
- package/assets/svges/facebook-messenger.svg +3 -0
- package/assets/svges/facebook-rounded.svg +4 -0
- package/assets/svges/facebook-square.svg +3 -0
- package/assets/svges/facebook.svg +3 -0
- package/assets/svges/facetime.svg +3 -0
- package/assets/svges/figma.svg +3 -0
- package/assets/svges/file-format-zip.svg +4 -0
- package/assets/svges/file-multiple.svg +4 -0
- package/assets/svges/file-pencil.svg +4 -0
- package/assets/svges/file-plus-circle.svg +5 -0
- package/assets/svges/file-question.svg +5 -0
- package/assets/svges/file-xmark.svg +4 -0
- package/assets/svges/firebase.svg +3 -0
- package/assets/svges/firefox.svg +3 -0
- package/assets/svges/firework-rocket-4.svg +3 -0
- package/assets/svges/fitbit.svg +3 -0
- package/assets/svges/flag-1.svg +3 -0
- package/assets/svges/flag-2.svg +3 -0
- package/assets/svges/flickr.svg +4 -0
- package/assets/svges/floppy-disk-1.svg +3 -0
- package/assets/svges/flower-2.svg +3 -0
- package/assets/svges/flutter.svg +3 -0
- package/assets/svges/folder-1.svg +3 -0
- package/assets/svges/ford.svg +3 -0
- package/assets/svges/framer.svg +3 -0
- package/assets/svges/funnel-1.svg +3 -0
- package/assets/svges/gallery.svg +4 -0
- package/assets/svges/game-pad-modern-1.svg +6 -0
- package/assets/svges/gatsby.svg +3 -0
- package/assets/svges/gauge-1.svg +5 -0
- package/assets/svges/gear-1.svg +4 -0
- package/assets/svges/gears-3.svg +6 -0
- package/assets/svges/gemini.svg +3 -0
- package/assets/svges/git.svg +3 -0
- package/assets/svges/github.svg +3 -0
- package/assets/svges/glass-juice-1.svg +3 -0
- package/assets/svges/globe-1.svg +3 -0
- package/assets/svges/globe-stand.svg +4 -0
- package/assets/svges/go.svg +7 -0
- package/assets/svges/goodreads.svg +3 -0
- package/assets/svges/google-cloud.svg +3 -0
- package/assets/svges/google-drive.svg +3 -0
- package/assets/svges/google-meet.svg +3 -0
- package/assets/svges/google-pay.svg +3 -0
- package/assets/svges/google-wallet.svg +3 -0
- package/assets/svges/google.svg +3 -0
- package/assets/svges/graduation-cap-1.svg +3 -0
- package/assets/svges/grammarly.svg +3 -0
- package/assets/svges/hacker-news.svg +3 -0
- package/assets/svges/hammer-1.svg +3 -0
- package/assets/svges/hammer-2.svg +3 -0
- package/assets/svges/hand-mic.svg +3 -0
- package/assets/svges/hand-shake.svg +3 -0
- package/assets/svges/hand-stop.svg +3 -0
- package/assets/svges/hand-taking-dollar.svg +4 -0
- package/assets/svges/hand-taking-leaf-1.svg +5 -0
- package/assets/svges/hand-taking-user.svg +5 -0
- package/assets/svges/hashnode.svg +3 -0
- package/assets/svges/hat-chef-3.svg +3 -0
- package/assets/svges/headphone-1.svg +3 -0
- package/assets/svges/heart.svg +3 -0
- package/assets/svges/helicopter-2.svg +4 -0
- package/assets/svges/helmet-safety-1.svg +3 -0
- package/assets/svges/hierarchy-1.svg +9 -0
- package/assets/svges/highlighter-1.svg +3 -0
- package/assets/svges/highlighter-2.svg +3 -0
- package/assets/svges/home-2.svg +3 -0
- package/assets/svges/hospital-2.svg +4 -0
- package/assets/svges/hourglass.svg +3 -0
- package/assets/svges/html5.svg +4 -0
- package/assets/svges/ibm.svg +3 -0
- package/assets/svges/id-card.svg +7 -0
- package/assets/svges/imdb.svg +7 -0
- package/assets/svges/indent.svg +8 -0
- package/assets/svges/info.svg +4 -0
- package/assets/svges/injection-1.svg +3 -0
- package/assets/svges/instagram-logotype.svg +3 -0
- package/assets/svges/instagram.svg +4 -0
- package/assets/svges/intel.svg +4 -0
- package/assets/svges/ios.svg +3 -0
- package/assets/svges/island-2.svg +4 -0
- package/assets/svges/jaguar.svg +3 -0
- package/assets/svges/jamstack.svg +3 -0
- package/assets/svges/java.svg +3 -0
- package/assets/svges/javascript.svg +3 -0
- package/assets/svges/jcb.svg +3 -0
- package/assets/svges/joomla.svg +6 -0
- package/assets/svges/jsfiddle.svg +4 -0
- package/assets/svges/key-1.svg +3 -0
- package/assets/svges/keyboard.svg +12 -0
- package/assets/svges/knife-fork-1.svg +5 -0
- package/assets/svges/kubernetes.svg +11 -0
- package/assets/svges/label-dollar-2.svg +4 -0
- package/assets/svges/laptop-2.svg +3 -0
- package/assets/svges/laptop-phone.svg +5 -0
- package/assets/svges/laravel.svg +3 -0
- package/assets/svges/layers-1.svg +4 -0
- package/assets/svges/layout-26.svg +3 -0
- package/assets/svges/layout-9.svg +3 -0
- package/assets/svges/leaf-1.svg +3 -0
- package/assets/svges/leaf-6.svg +4 -0
- package/assets/svges/lemon-squeezy.svg +6 -0
- package/assets/svges/life-guard-tube-1.svg +3 -0
- package/assets/svges/line-dashed.svg +5 -0
- package/assets/svges/line-dotted.svg +8 -0
- package/assets/svges/line-height.svg +7 -0
- package/assets/svges/line.svg +3 -0
- package/assets/svges/lineicons.svg +6 -0
- package/assets/svges/link-2-angular-right.svg +3 -0
- package/assets/svges/linkedin.svg +3 -0
- package/assets/svges/location-arrow-right.svg +3 -0
- package/assets/svges/locked-1.svg +4 -0
- package/assets/svges/locked-2.svg +4 -0
- package/assets/svges/loom.svg +3 -0
- package/assets/svges/magento.svg +4 -0
- package/assets/svges/magnet.svg +3 -0
- package/assets/svges/mailchimp.svg +3 -0
- package/assets/svges/map-marker-1.svg +6 -0
- package/assets/svges/map-marker-5.svg +4 -0
- package/assets/svges/map-pin-5.svg +3 -0
- package/assets/svges/markdown.svg +5 -0
- package/assets/svges/mastercard.svg +7 -0
- package/assets/svges/medium-alt.svg +3 -0
- package/assets/svges/medium.svg +3 -0
- package/assets/svges/megaphone-1.svg +3 -0
- package/assets/svges/menu-cheesburger.svg +8 -0
- package/assets/svges/menu-hamburger-1.svg +5 -0
- package/assets/svges/menu-meatballs-1.svg +5 -0
- package/assets/svges/menu-meatballs-2.svg +5 -0
- package/assets/svges/mercedes.svg +3 -0
- package/assets/svges/message-2-question.svg +5 -0
- package/assets/svges/message-2.svg +3 -0
- package/assets/svges/message-3-text.svg +5 -0
- package/assets/svges/meta-alt.svg +3 -0
- package/assets/svges/meta.svg +7 -0
- package/assets/svges/microphone-1.svg +4 -0
- package/assets/svges/microscope.svg +3 -0
- package/assets/svges/microsoft-edge.svg +5 -0
- package/assets/svges/microsoft-teams.svg +6 -0
- package/assets/svges/microsoft.svg +6 -0
- package/assets/svges/minus-circle.svg +4 -0
- package/assets/svges/minus.svg +3 -0
- package/assets/svges/mongodb.svg +3 -0
- package/assets/svges/monitor-code.svg +5 -0
- package/assets/svges/monitor-mac.svg +3 -0
- package/assets/svges/monitor.svg +3 -0
- package/assets/svges/moon-half-right-5.svg +3 -0
- package/assets/svges/mountains-2.svg +3 -0
- package/assets/svges/mouse-2.svg +3 -0
- package/assets/svges/mushroom-1.svg +3 -0
- package/assets/svges/mushroom-5.svg +6 -0
- package/assets/svges/music.svg +3 -0
- package/assets/svges/mysql.svg +3 -0
- package/assets/svges/nasa.svg +3 -0
- package/assets/svges/netflix.svg +3 -0
- package/assets/svges/netlify.svg +3 -0
- package/assets/svges/next-step-2.svg +3 -0
- package/assets/svges/nextjs.svg +3 -0
- package/assets/svges/nike.svg +3 -0
- package/assets/svges/nissan.svg +3 -0
- package/assets/svges/nodejs-alt.svg +3 -0
- package/assets/svges/nodejs.svg +3 -0
- package/assets/svges/notebook-1.svg +3 -0
- package/assets/svges/notion.svg +3 -0
- package/assets/svges/npm.svg +3 -0
- package/assets/svges/nuxt.svg +3 -0
- package/assets/svges/nvidia.svg +3 -0
- package/assets/svges/oculus.svg +4 -0
- package/assets/svges/open-ai.svg +3 -0
- package/assets/svges/opera-mini.svg +3 -0
- package/assets/svges/oracle.svg +3 -0
- package/assets/svges/outdent.svg +8 -0
- package/assets/svges/paddle.svg +3 -0
- package/assets/svges/page-break-1.svg +7 -0
- package/assets/svges/pagination.svg +7 -0
- package/assets/svges/paint-bucket.svg +3 -0
- package/assets/svges/paint-roller-1.svg +3 -0
- package/assets/svges/paperclip-1.svg +3 -0
- package/assets/svges/party-flags.svg +3 -0
- package/assets/svges/party-spray.svg +3 -0
- package/assets/svges/patreon.svg +3 -0
- package/assets/svges/pause.svg +4 -0
- package/assets/svges/payoneer.svg +4 -0
- package/assets/svges/paypal.svg +4 -0
- package/assets/svges/pen-to-square.svg +4 -0
- package/assets/svges/pencil-1.svg +3 -0
- package/assets/svges/pepsi.svg +4 -0
- package/assets/svges/phone.svg +4 -0
- package/assets/svges/photos.svg +4 -0
- package/assets/svges/php.svg +3 -0
- package/assets/svges/pie-chart-2.svg +3 -0
- package/assets/svges/pilcrow.svg +3 -0
- package/assets/svges/pimjo-logo.svg +9 -0
- package/assets/svges/pimjo-symbol.svg +3 -0
- package/assets/svges/pinterest.svg +3 -0
- package/assets/svges/pizza-2.svg +6 -0
- package/assets/svges/placeholder-dollar.svg +4 -0
- package/assets/svges/plantscale.svg +3 -0
- package/assets/svges/play-store.svg +3 -0
- package/assets/svges/play.svg +3 -0
- package/assets/svges/playstation.svg +5 -0
- package/assets/svges/plug-1.svg +3 -0
- package/assets/svges/plus-circle.svg +4 -0
- package/assets/svges/plus.svg +3 -0
- package/assets/svges/pnpm.svg +10 -0
- package/assets/svges/postgresql.svg +3 -0
- package/assets/svges/postman.svg +3 -0
- package/assets/svges/pound.svg +3 -0
- package/assets/svges/power-button.svg +4 -0
- package/assets/svges/previous-step-2.svg +3 -0
- package/assets/svges/printer.svg +3 -0
- package/assets/svges/prisma.svg +3 -0
- package/assets/svges/producthunt.svg +4 -0
- package/assets/svges/proton-mail-logo.svg +3 -0
- package/assets/svges/proton-mail-symbol.svg +3 -0
- package/assets/svges/python.svg +3 -0
- package/assets/svges/question-mark-circle.svg +5 -0
- package/assets/svges/question-mark.svg +4 -0
- package/assets/svges/quora.svg +4 -0
- package/assets/svges/radis.svg +3 -0
- package/assets/svges/react.svg +3 -0
- package/assets/svges/reddit.svg +6 -0
- package/assets/svges/refresh-circle-1-clockwise.svg +4 -0
- package/assets/svges/refresh-dollar-1.svg +5 -0
- package/assets/svges/refresh-user-1.svg +6 -0
- package/assets/svges/remix-js.svg +4 -0
- package/assets/svges/road-1.svg +6 -0
- package/assets/svges/rocket-5.svg +5 -0
- package/assets/svges/route-1.svg +7 -0
- package/assets/svges/rss-right.svg +6 -0
- package/assets/svges/ruler-1.svg +3 -0
- package/assets/svges/ruler-pen.svg +4 -0
- package/assets/svges/rupee.svg +3 -0
- package/assets/svges/safari.svg +35 -0
- package/assets/svges/sanity.svg +20 -0
- package/assets/svges/school-bench-1.svg +4 -0
- package/assets/svges/school-bench-2.svg +4 -0
- package/assets/svges/scissors-1-vertical.svg +4 -0
- package/assets/svges/scoter.svg +8 -0
- package/assets/svges/scroll-down-2.svg +6 -0
- package/assets/svges/search-1.svg +3 -0
- package/assets/svges/search-2.svg +4 -0
- package/assets/svges/search-minus.svg +4 -0
- package/assets/svges/search-plus.svg +4 -0
- package/assets/svges/search-text.svg +5 -0
- package/assets/svges/select-cursor-1.svg +10 -0
- package/assets/svges/seo-monitor.svg +6 -0
- package/assets/svges/service-bell-1.svg +3 -0
- package/assets/svges/share-1-circle.svg +4 -0
- package/assets/svges/share-1.svg +3 -0
- package/assets/svges/share-2.svg +4 -0
- package/assets/svges/shield-2-check.svg +4 -0
- package/assets/svges/shield-2.svg +3 -0
- package/assets/svges/shield-dollar.svg +4 -0
- package/assets/svges/shift-left.svg +4 -0
- package/assets/svges/shift-right.svg +4 -0
- package/assets/svges/ship-1.svg +5 -0
- package/assets/svges/shirt-1.svg +3 -0
- package/assets/svges/shopify.svg +3 -0
- package/assets/svges/shovel.svg +3 -0
- package/assets/svges/shuffle.svg +3 -0
- package/assets/svges/sign-post-left.svg +3 -0
- package/assets/svges/signal-app.svg +3 -0
- package/assets/svges/signs-post-2.svg +3 -0
- package/assets/svges/sketch.svg +3 -0
- package/assets/svges/skype.svg +3 -0
- package/assets/svges/slack.svg +10 -0
- package/assets/svges/slice-2.svg +3 -0
- package/assets/svges/sliders-horizontal-square-2.svg +7 -0
- package/assets/svges/slideshare.svg +5 -0
- package/assets/svges/snapchat.svg +3 -0
- package/assets/svges/sort-alphabetical.svg +5 -0
- package/assets/svges/sort-high-to-low.svg +7 -0
- package/assets/svges/soundcloud.svg +3 -0
- package/assets/svges/spacex.svg +4 -0
- package/assets/svges/spellcheck.svg +4 -0
- package/assets/svges/spinner-2-sacle.svg +10 -0
- package/assets/svges/spinner-3.svg +3 -0
- package/assets/svges/sports.svg +3 -0
- package/assets/svges/spotify-alt.svg +6 -0
- package/assets/svges/spotify.svg +3 -0
- package/assets/svges/squarespace.svg +3 -0
- package/assets/svges/stackoverflow.svg +8 -0
- package/assets/svges/stamp.svg +3 -0
- package/assets/svges/star-fat-half-2.svg +4 -0
- package/assets/svges/star-fat.svg +3 -0
- package/assets/svges/star-sharp-disabled.svg +4 -0
- package/assets/svges/statista.svg +3 -0
- package/assets/svges/steam.svg +5 -0
- package/assets/svges/stethoscope-1.svg +3 -0
- package/assets/svges/stopwatch.svg +5 -0
- package/assets/svges/storage-hdd-2.svg +4 -0
- package/assets/svges/strikethrough-1.svg +5 -0
- package/assets/svges/stripe.svg +9 -0
- package/assets/svges/stumbleupon.svg +3 -0
- package/assets/svges/sun-1.svg +11 -0
- package/assets/svges/supabase.svg +5 -0
- package/assets/svges/surfboard-2.svg +3 -0
- package/assets/svges/svelte.svg +3 -0
- package/assets/svges/swift.svg +3 -0
- package/assets/svges/tab.svg +4 -0
- package/assets/svges/tailwindcss.svg +3 -0
- package/assets/svges/target-user.svg +5 -0
- package/assets/svges/telegram.svg +3 -0
- package/assets/svges/telephone-1.svg +4 -0
- package/assets/svges/telephone-3.svg +5 -0
- package/assets/svges/tesla.svg +3 -0
- package/assets/svges/text-format-remove.svg +5 -0
- package/assets/svges/text-format.svg +5 -0
- package/assets/svges/text-paragraph.svg +6 -0
- package/assets/svges/thumbs-down-3.svg +3 -0
- package/assets/svges/thumbs-up-3.svg +3 -0
- package/assets/svges/ticket-1.svg +3 -0
- package/assets/svges/tickets-3.svg +7 -0
- package/assets/svges/tiktok-alt.svg +3 -0
- package/assets/svges/tiktok.svg +3 -0
- package/assets/svges/tower-broadcast-1.svg +7 -0
- package/assets/svges/toyota.svg +4 -0
- package/assets/svges/train-1.svg +4 -0
- package/assets/svges/train-3.svg +5 -0
- package/assets/svges/trash-3.svg +5 -0
- package/assets/svges/tree-2.svg +3 -0
- package/assets/svges/trees-3.svg +3 -0
- package/assets/svges/trello.svg +3 -0
- package/assets/svges/trend-down-1.svg +3 -0
- package/assets/svges/trend-up-1.svg +3 -0
- package/assets/svges/trophy-1.svg +3 -0
- package/assets/svges/trowel-1.svg +3 -0
- package/assets/svges/truck-delivery-1.svg +3 -0
- package/assets/svges/tumblr.svg +3 -0
- package/assets/svges/turborepo.svg +4 -0
- package/assets/svges/twitch.svg +3 -0
- package/assets/svges/twitter-old.svg +3 -0
- package/assets/svges/typescript.svg +3 -0
- package/assets/svges/uber-symbol.svg +3 -0
- package/assets/svges/uber.svg +3 -0
- package/assets/svges/ubuntu.svg +3 -0
- package/assets/svges/underline.svg +4 -0
- package/assets/svges/unlink-2-angular-eft.svg +8 -0
- package/assets/svges/unlocked-2.svg +4 -0
- package/assets/svges/unsplash.svg +4 -0
- package/assets/svges/upload-1.svg +4 -0
- package/assets/svges/upload-circle-1.svg +4 -0
- package/assets/svges/user-4.svg +4 -0
- package/assets/svges/user-multiple-4.svg +6 -0
- package/assets/svges/vector-nodes-6.svg +3 -0
- package/assets/svges/vector-nodes-7.svg +3 -0
- package/assets/svges/vercel.svg +3 -0
- package/assets/svges/vimeo.svg +3 -0
- package/assets/svges/visa.svg +3 -0
- package/assets/svges/vite.svg +6 -0
- package/assets/svges/vk.svg +3 -0
- package/assets/svges/vmware.svg +4 -0
- package/assets/svges/volkswagen.svg +8 -0
- package/assets/svges/volume-1.svg +5 -0
- package/assets/svges/volume-high.svg +6 -0
- package/assets/svges/volume-low.svg +4 -0
- package/assets/svges/volume-mute.svg +6 -0
- package/assets/svges/volume-off.svg +3 -0
- package/assets/svges/vs-code.svg +3 -0
- package/assets/svges/vuejs.svg +3 -0
- package/assets/svges/wallet-1.svg +3 -0
- package/assets/svges/watch-beat-1.svg +4 -0
- package/assets/svges/water-drop-1.svg +4 -0
- package/assets/svges/webflow.svg +3 -0
- package/assets/svges/webhooks.svg +3 -0
- package/assets/svges/wechat.svg +4 -0
- package/assets/svges/weight-machine-1.svg +4 -0
- package/assets/svges/whatsapp.svg +3 -0
- package/assets/svges/wheelbarrow-empty.svg +3 -0
- package/assets/svges/wheelchair-1.svg +3 -0
- package/assets/svges/windows.svg +6 -0
- package/assets/svges/wise.svg +3 -0
- package/assets/svges/wordpress.svg +3 -0
- package/assets/svges/www-cursor.svg +5 -0
- package/assets/svges/www.svg +4 -0
- package/assets/svges/x.svg +3 -0
- package/assets/svges/xampp.svg +5 -0
- package/assets/svges/xbox.svg +6 -0
- package/assets/svges/xmark-circle.svg +4 -0
- package/assets/svges/xmark.svg +3 -0
- package/assets/svges/xrp.svg +3 -0
- package/assets/svges/yahoo.svg +3 -0
- package/assets/svges/yarn.svg +4 -0
- package/assets/svges/ycombinator.svg +3 -0
- package/assets/svges/yen.svg +3 -0
- package/assets/svges/youtube-kids.svg +3 -0
- package/assets/svges/youtube-music.svg +4 -0
- package/assets/svges/youtube.svg +3 -0
- package/assets/svges/zapier.svg +3 -0
- package/assets/svges/zero-size.svg +6 -0
- package/assets/svges/zoom.svg +4 -0
- package/bin/test-svger.js +163 -0
- package/dist/__tests__/__mocks__/visual-diff.d.ts +7 -0
- package/dist/__tests__/__mocks__/visual-diff.js +13 -0
- package/dist/__tests__/fixtures.js +18 -18
- package/dist/cli.js +148 -2
- package/dist/config.js +4 -1
- package/dist/core/enhanced-plugin-manager.d.ts +107 -0
- package/dist/core/enhanced-plugin-manager.js +315 -0
- package/dist/core/error-handler.d.ts +1 -1
- package/dist/core/error-handler.js +14 -17
- package/dist/core/framework-templates.js +37 -47
- package/dist/core/logger.js +0 -1
- package/dist/core/performance-engine.js +10 -15
- package/dist/core/plugin-manager.js +4 -4
- package/dist/core/style-compiler.d.ts +0 -1
- package/dist/core/style-compiler.js +3 -6
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/integrations/babel.d.ts +1 -1
- package/dist/integrations/babel.js +1 -1
- package/dist/integrations/jest-preset.js +1 -1
- package/dist/optimizers/advanced-stages.d.ts +40 -0
- package/dist/optimizers/advanced-stages.js +297 -0
- package/dist/optimizers/basic-cleaner.d.ts +68 -0
- package/dist/optimizers/basic-cleaner.js +198 -0
- package/dist/optimizers/collapse-useless-groups.d.ts +26 -0
- package/dist/optimizers/collapse-useless-groups.js +104 -0
- package/dist/optimizers/command-optimizer.d.ts +48 -0
- package/dist/optimizers/command-optimizer.js +299 -0
- package/dist/optimizers/index.d.ts +14 -0
- package/dist/optimizers/index.js +15 -0
- package/dist/optimizers/move-attrs-to-parent.d.ts +31 -0
- package/dist/optimizers/move-attrs-to-parent.js +115 -0
- package/dist/optimizers/numeric-optimizer.d.ts +43 -0
- package/dist/optimizers/numeric-optimizer.js +383 -0
- package/dist/optimizers/optimizer-pipeline.d.ts +39 -0
- package/dist/optimizers/optimizer-pipeline.js +81 -0
- package/dist/optimizers/path-deduplicator.d.ts +37 -0
- package/dist/optimizers/path-deduplicator.js +406 -0
- package/dist/optimizers/path-parser.d.ts +60 -0
- package/dist/optimizers/path-parser.js +428 -0
- package/dist/optimizers/path-shortener.d.ts +41 -0
- package/dist/optimizers/path-shortener.js +274 -0
- package/dist/optimizers/path-simplifier.d.ts +30 -0
- package/dist/optimizers/path-simplifier.js +326 -0
- package/dist/optimizers/remove-hidden-empty.d.ts +29 -0
- package/dist/optimizers/remove-hidden-empty.js +130 -0
- package/dist/optimizers/remove-unused-defs.d.ts +24 -0
- package/dist/optimizers/remove-unused-defs.js +132 -0
- package/dist/optimizers/shape-conversion.d.ts +74 -0
- package/dist/optimizers/shape-conversion.js +277 -0
- package/dist/optimizers/style-optimizer.d.ts +30 -0
- package/dist/optimizers/style-optimizer.js +324 -0
- package/dist/optimizers/svg-tree-parser.d.ts +55 -0
- package/dist/optimizers/svg-tree-parser.js +352 -0
- package/dist/optimizers/transform-collapsing.d.ts +38 -0
- package/dist/optimizers/transform-collapsing.js +444 -0
- package/dist/optimizers/transform-optimizer.d.ts +65 -0
- package/dist/optimizers/transform-optimizer.js +320 -0
- package/dist/optimizers/tree-serializer.d.ts +46 -0
- package/dist/optimizers/tree-serializer.js +190 -0
- package/dist/optimizers/tree-stages.d.ts +27 -0
- package/dist/optimizers/tree-stages.js +141 -0
- package/dist/optimizers/types.d.ts +207 -0
- package/dist/optimizers/types.js +122 -0
- package/dist/plugins/color-replacer.d.ts +39 -0
- package/dist/plugins/color-replacer.js +126 -0
- package/dist/plugins/gradient-optimizer.d.ts +33 -0
- package/dist/plugins/gradient-optimizer.js +197 -0
- package/dist/plugins/stroke-normalizer.d.ts +33 -0
- package/dist/plugins/stroke-normalizer.js +166 -0
- package/dist/plugins/watermark-remover.d.ts +32 -0
- package/dist/plugins/watermark-remover.js +133 -0
- package/dist/processors/svg-processor.d.ts +17 -2
- package/dist/processors/svg-processor.js +108 -32
- package/dist/services/config.d.ts +4 -0
- package/dist/services/config.js +62 -1
- package/dist/services/file-watcher.d.ts +1 -1
- package/dist/services/file-watcher.js +1 -1
- package/dist/services/svg-service.d.ts +4 -0
- package/dist/services/svg-service.js +41 -7
- package/dist/types/index.d.ts +1 -0
- package/dist/types/plugin-system.d.ts +153 -0
- package/dist/types/plugin-system.js +5 -0
- package/dist/utils/visual-diff.d.ts +150 -0
- package/dist/utils/visual-diff.js +247 -0
- package/dist/watch.js +0 -2
- package/docs/COMPLETE-ACHIEVEMENT-SUMMARY.md +401 -0
- package/docs/MIGRATION-4.0.0.md +271 -0
- package/docs/PIPELINE-INTEGRATION.md +406 -0
- package/docs/PLUGIN-DEVELOPMENT-GUIDE.md +807 -0
- package/docs/QUICK-REFERENCE.md +176 -0
- package/docs/SAMPLE-SVGS-TESTING.md +276 -0
- package/docs/archive/PHASE-1-ARCHITECTURE.md +345 -0
- package/docs/archive/PHASE-1-IMPLEMENTATION.md +307 -0
- package/docs/archive/PHASE-1-SUMMARY.md +298 -0
- package/docs/archive/PHASE-2-COMPLETE.md +207 -0
- package/docs/archive/PHASE-3-SUMMARY.md +149 -0
- package/docs/archive/PHASE-4.3-COMMAND-OPTIMIZER.md +323 -0
- package/docs/archive/PHASE-4.4-PATH-SIMPLIFICATION.md +81 -0
- package/docs/archive/PHASE-4.5-PATH-DEDUPLICATION.md +449 -0
- package/docs/archive/PHASE-5.1-SUCCESS-REPORT.md +207 -0
- package/docs/archive/PHASE-5.1-TRANSFORM-COLLAPSING.md +362 -0
- package/docs/archive/PHASE-6.1-SHAPE-CONVERSION-DESIGN.md +518 -0
- package/docs/archive/PHASE-6.2-PLUGIN-SYSTEM-STATUS.md +403 -0
- package/docs/archive/PHASE-6.3-FINAL-STATUS.md +193 -0
- package/docs/archive/PHASE-6.3-VALIDATION-PROGRESS.md +345 -0
- package/docs/archive/PHASE-6.3-VISUAL-DIFF-DESIGN.md +553 -0
- package/docs/archive/PHASE-6.3-VISUAL-DIFF-SUMMARY.md +367 -0
- package/docs/archive/PHASE-6.3-XML-SERIALIZATION-FIX.md +210 -0
- package/docs/archive/RELEASE-NOTES-3.2.0.md +344 -0
- package/docs/archive/RELEASE-PREP-3.2.0.md +376 -0
- package/docs/performance/PERFORMANCE-RESULTS.md +31 -0
- package/docs/performance/REAL-WORLD-BENCHMARKS.md +159 -0
- package/package.json +16 -6
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Basic SVG Cleaner
|
|
3
|
+
* Extracts basic cleaning logic from svg-processor for use in optimizer pipeline
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Remove XML declarations from SVG content
|
|
7
|
+
*/
|
|
8
|
+
export function removeXMLDeclaration(svg, config) {
|
|
9
|
+
if (!config.removeXMLProcInst)
|
|
10
|
+
return svg;
|
|
11
|
+
return svg.replace(/<\?xml.*?\?>/g, '');
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Remove DOCTYPE declarations from SVG content
|
|
15
|
+
*/
|
|
16
|
+
export function removeDoctype(svg, config) {
|
|
17
|
+
if (!config.removeDoctype)
|
|
18
|
+
return svg;
|
|
19
|
+
return svg.replace(/<!DOCTYPE.*?>/g, '');
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Remove comments from SVG content
|
|
23
|
+
*/
|
|
24
|
+
export function removeComments(svg, config) {
|
|
25
|
+
if (!config.removeComments)
|
|
26
|
+
return svg;
|
|
27
|
+
return svg.replace(/<!--[\s\S]*?-->/g, '');
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Normalize whitespace in SVG content
|
|
31
|
+
*/
|
|
32
|
+
export function normalizeWhitespace(svg, config) {
|
|
33
|
+
if (!config.normalizeWhitespace)
|
|
34
|
+
return svg;
|
|
35
|
+
return svg
|
|
36
|
+
.replace(/\r?\n|\r/g, '') // Remove line breaks
|
|
37
|
+
.replace(/\s{2,}/g, ' ') // Collapse multiple spaces
|
|
38
|
+
.trim();
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Remove metadata elements from SVG content
|
|
42
|
+
*/
|
|
43
|
+
export function removeMetadata(svg, config) {
|
|
44
|
+
if (!config.removeMetadata)
|
|
45
|
+
return svg;
|
|
46
|
+
return svg
|
|
47
|
+
.replace(/<metadata[\s\S]*?<\/metadata>/gi, '')
|
|
48
|
+
.replace(/<title[\s\S]*?<\/title>/gi, '')
|
|
49
|
+
.replace(/<desc[\s\S]*?<\/desc>/gi, '');
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Convert kebab-case attributes to camelCase for React compatibility
|
|
53
|
+
*/
|
|
54
|
+
export function convertToCamelCase(svg, config) {
|
|
55
|
+
if (!config.reactCompatibility)
|
|
56
|
+
return svg;
|
|
57
|
+
const attributeMap = {
|
|
58
|
+
'fill-rule': 'fillRule',
|
|
59
|
+
'clip-rule': 'clipRule',
|
|
60
|
+
'stroke-width': 'strokeWidth',
|
|
61
|
+
'stroke-linecap': 'strokeLinecap',
|
|
62
|
+
'stroke-linejoin': 'strokeLinejoin',
|
|
63
|
+
'stroke-miterlimit': 'strokeMiterlimit',
|
|
64
|
+
'stroke-dasharray': 'strokeDasharray',
|
|
65
|
+
'stroke-dashoffset': 'strokeDashoffset',
|
|
66
|
+
'font-family': 'fontFamily',
|
|
67
|
+
'font-size': 'fontSize',
|
|
68
|
+
'font-weight': 'fontWeight',
|
|
69
|
+
'text-anchor': 'textAnchor',
|
|
70
|
+
'stop-color': 'stopColor',
|
|
71
|
+
'stop-opacity': 'stopOpacity',
|
|
72
|
+
'fill-opacity': 'fillOpacity',
|
|
73
|
+
'stroke-opacity': 'strokeOpacity',
|
|
74
|
+
};
|
|
75
|
+
let result = svg;
|
|
76
|
+
for (const [kebab, camel] of Object.entries(attributeMap)) {
|
|
77
|
+
const regex = new RegExp(kebab, 'g');
|
|
78
|
+
result = result.replace(regex, camel);
|
|
79
|
+
}
|
|
80
|
+
return result;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Remove unnecessary XML namespace attributes
|
|
84
|
+
*/
|
|
85
|
+
export function removeXMLNamespaces(svg, config) {
|
|
86
|
+
if (!config.removeUnnecessaryAttrs)
|
|
87
|
+
return svg;
|
|
88
|
+
// Remove xmlns and xmlns:xlink (React handles these automatically)
|
|
89
|
+
return svg.replace(/\s+xmlns(:xlink)?="[^"]*"/g, '');
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Remove inline style attributes
|
|
93
|
+
* Note: This can be aggressive - use with caution
|
|
94
|
+
*/
|
|
95
|
+
export function removeInlineStyles(svg, config) {
|
|
96
|
+
if (!config.inlineStyles)
|
|
97
|
+
return svg;
|
|
98
|
+
// Remove style attributes
|
|
99
|
+
return svg.replace(/\s+style="[^"]*"/g, '');
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Shorten hex colors (#ffffff → #fff)
|
|
103
|
+
*/
|
|
104
|
+
export function shortenColors(svg, config) {
|
|
105
|
+
if (!config.shortenColors)
|
|
106
|
+
return svg;
|
|
107
|
+
// Match 6-digit hex colors that can be shortened
|
|
108
|
+
return svg.replace(/#([0-9a-f])\1([0-9a-f])\2([0-9a-f])\3/gi, '#$1$2$3');
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Remove empty containers (g, defs without children or with only whitespace)
|
|
112
|
+
*/
|
|
113
|
+
export function removeEmptyContainers(svg, config) {
|
|
114
|
+
if (!config.removeEmptyContainers)
|
|
115
|
+
return svg;
|
|
116
|
+
let result = svg;
|
|
117
|
+
let previousResult = '';
|
|
118
|
+
// Iteratively remove empty containers until no more are found
|
|
119
|
+
while (result !== previousResult) {
|
|
120
|
+
previousResult = result;
|
|
121
|
+
result = result
|
|
122
|
+
.replace(/<g\s*><\/g>/gi, '') // Empty g tags
|
|
123
|
+
.replace(/<g\s*>\s*<\/g>/gi, '') // g tags with only whitespace
|
|
124
|
+
.replace(/<defs\s*><\/defs>/gi, '') // Empty defs tags
|
|
125
|
+
.replace(/<defs\s*>\s*<\/defs>/gi, ''); // defs with only whitespace
|
|
126
|
+
}
|
|
127
|
+
return result;
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Remove hidden elements (display:none, opacity:0, visibility:hidden)
|
|
131
|
+
*/
|
|
132
|
+
/**
|
|
133
|
+
* Remove hidden elements (display:none, opacity:0, visibility:hidden)
|
|
134
|
+
* NOTE: Disabled because it's too aggressive with regex and breaks complex SVGs.
|
|
135
|
+
* Use tree-based optimization (remove-hidden-empty.ts) instead for safe removal.
|
|
136
|
+
*/
|
|
137
|
+
export function removeHiddenElements(svg) {
|
|
138
|
+
// DISABLED: Regex-based removal is too aggressive
|
|
139
|
+
// Tree-based optimizer handles this correctly
|
|
140
|
+
return svg;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Round float numbers to specified precision
|
|
144
|
+
*/
|
|
145
|
+
export function roundFloats(svg, config) {
|
|
146
|
+
const precision = config.floatPrecision;
|
|
147
|
+
// Match floating point numbers
|
|
148
|
+
return svg.replace(/(\d+\.\d+)/g, match => {
|
|
149
|
+
const num = parseFloat(match);
|
|
150
|
+
return num.toFixed(precision).replace(/\.?0+$/, ''); // Remove trailing zeros
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Sort attributes alphabetically
|
|
155
|
+
*/
|
|
156
|
+
export function sortAttributes(svg, config) {
|
|
157
|
+
if (!config.sortAttrs)
|
|
158
|
+
return svg;
|
|
159
|
+
// Match SVG tags with attributes (both self-closing and regular)
|
|
160
|
+
return svg.replace(/<([a-z][a-z0-9]*)\s+([^>]+?)(\/?)>/gi, (_match, tagName, attrs, selfClosing) => {
|
|
161
|
+
// Parse attributes
|
|
162
|
+
const attrPairs = [];
|
|
163
|
+
const attrRegex = /([a-zA-Z][a-zA-Z0-9-]*)="([^"]*)"/g;
|
|
164
|
+
let attrMatch;
|
|
165
|
+
while ((attrMatch = attrRegex.exec(attrs)) !== null) {
|
|
166
|
+
attrPairs.push([attrMatch[1], attrMatch[2]]);
|
|
167
|
+
}
|
|
168
|
+
// Sort alphabetically
|
|
169
|
+
attrPairs.sort((a, b) => a[0].localeCompare(b[0]));
|
|
170
|
+
// Reconstruct tag, preserving self-closing status
|
|
171
|
+
const sortedAttrs = attrPairs
|
|
172
|
+
.map(([key, val]) => `${key}="${val}"`)
|
|
173
|
+
.join(' ');
|
|
174
|
+
return `<${tagName} ${sortedAttrs}${selfClosing}>`;
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Basic cleaning stage - combines all basic cleaners
|
|
179
|
+
* This is the main entry point for the optimizer pipeline
|
|
180
|
+
*/
|
|
181
|
+
export async function basicCleaningStage(svg, config) {
|
|
182
|
+
let result = svg;
|
|
183
|
+
// Apply cleaners in sequence
|
|
184
|
+
result = removeXMLDeclaration(result, config);
|
|
185
|
+
result = removeDoctype(result, config);
|
|
186
|
+
result = removeComments(result, config);
|
|
187
|
+
result = removeMetadata(result, config);
|
|
188
|
+
result = normalizeWhitespace(result, config);
|
|
189
|
+
result = removeXMLNamespaces(result, config);
|
|
190
|
+
result = removeInlineStyles(result, config);
|
|
191
|
+
result = convertToCamelCase(result, config);
|
|
192
|
+
result = shortenColors(result, config);
|
|
193
|
+
result = roundFloats(result, config);
|
|
194
|
+
result = removeEmptyContainers(result, config);
|
|
195
|
+
result = removeHiddenElements(result);
|
|
196
|
+
result = sortAttributes(result, config);
|
|
197
|
+
return result;
|
|
198
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collapse Useless Groups
|
|
3
|
+
* Remove <g> with no attrs and single child
|
|
4
|
+
* Merge attrs upward if safe (no conflicts)
|
|
5
|
+
*/
|
|
6
|
+
import type { SVGNode } from './svg-tree-parser.js';
|
|
7
|
+
/**
|
|
8
|
+
* Collapse useless groups in the tree
|
|
9
|
+
* A group is useless if:
|
|
10
|
+
* 1. It has no attributes and exactly one child
|
|
11
|
+
* 2. It has attributes that don't conflict with its single child
|
|
12
|
+
*/
|
|
13
|
+
export declare function collapseUselessGroups(root: SVGNode): {
|
|
14
|
+
collapsedCount: number;
|
|
15
|
+
collapsedNodes: string[];
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Collapse useless groups stage
|
|
19
|
+
*/
|
|
20
|
+
export declare function collapseUselessGroupsStage(root: SVGNode): {
|
|
21
|
+
modified: boolean;
|
|
22
|
+
stats: {
|
|
23
|
+
collapsedCount: number;
|
|
24
|
+
collapsedNodes: string[];
|
|
25
|
+
};
|
|
26
|
+
};
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Collapse Useless Groups
|
|
3
|
+
* Remove <g> with no attrs and single child
|
|
4
|
+
* Merge attrs upward if safe (no conflicts)
|
|
5
|
+
*/
|
|
6
|
+
import { traverseTree, replaceNode } from './svg-tree-parser.js';
|
|
7
|
+
/**
|
|
8
|
+
* Check if a group is useless (no attributes and single child)
|
|
9
|
+
*/
|
|
10
|
+
function isUselessGroup(node) {
|
|
11
|
+
return (node.tag === 'g' &&
|
|
12
|
+
node.attrs.size === 0 &&
|
|
13
|
+
node.children.length === 1 &&
|
|
14
|
+
!node.content);
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Check if attributes can be safely merged from child to parent
|
|
18
|
+
* Returns true if no conflicts exist
|
|
19
|
+
*/
|
|
20
|
+
function canMergeAttributes(parent, child) {
|
|
21
|
+
// Check for attribute conflicts
|
|
22
|
+
for (const [key] of child.attrs.entries()) {
|
|
23
|
+
if (parent.attrs.has(key)) {
|
|
24
|
+
// Conflict: both have the same attribute
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return true;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Merge child attributes to parent
|
|
32
|
+
*/
|
|
33
|
+
function mergeAttributesToParent(parent, child) {
|
|
34
|
+
for (const [key, value] of child.attrs.entries()) {
|
|
35
|
+
if (!parent.attrs.has(key)) {
|
|
36
|
+
parent.attrs.set(key, value);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Collapse useless groups in the tree
|
|
42
|
+
* A group is useless if:
|
|
43
|
+
* 1. It has no attributes and exactly one child
|
|
44
|
+
* 2. It has attributes that don't conflict with its single child
|
|
45
|
+
*/
|
|
46
|
+
export function collapseUselessGroups(root) {
|
|
47
|
+
let collapsedCount = 0;
|
|
48
|
+
const collapsedNodes = [];
|
|
49
|
+
// We need to collect nodes to collapse first
|
|
50
|
+
// to avoid modifying tree during traversal
|
|
51
|
+
const nodesToCollapse = [];
|
|
52
|
+
traverseTree(root, node => {
|
|
53
|
+
if (node.tag === 'g') {
|
|
54
|
+
// Case 1: Group with no attributes and single child
|
|
55
|
+
if (isUselessGroup(node)) {
|
|
56
|
+
nodesToCollapse.push(node);
|
|
57
|
+
}
|
|
58
|
+
// Case 2: Group with single child and no attribute conflicts
|
|
59
|
+
else if (node.children.length === 1 && !node.content) {
|
|
60
|
+
const child = node.children[0];
|
|
61
|
+
if (canMergeAttributes(child, node)) {
|
|
62
|
+
nodesToCollapse.push(node);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
// Collapse collected nodes
|
|
68
|
+
for (const node of nodesToCollapse) {
|
|
69
|
+
if (!node.parent)
|
|
70
|
+
continue;
|
|
71
|
+
const child = node.children[0];
|
|
72
|
+
// For groups with no attrs, just replace group with child
|
|
73
|
+
if (node.attrs.size === 0) {
|
|
74
|
+
if (replaceNode(node, child)) {
|
|
75
|
+
const id = node.attrs.get('id') || 'anonymous';
|
|
76
|
+
collapsedNodes.push(id);
|
|
77
|
+
collapsedCount++;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
// For groups with attrs, merge them to child first
|
|
81
|
+
else if (canMergeAttributes(child, node)) {
|
|
82
|
+
mergeAttributesToParent(child, node);
|
|
83
|
+
if (replaceNode(node, child)) {
|
|
84
|
+
const id = node.attrs.get('id') || 'anonymous';
|
|
85
|
+
collapsedNodes.push(id);
|
|
86
|
+
collapsedCount++;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
collapsedCount,
|
|
92
|
+
collapsedNodes,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Collapse useless groups stage
|
|
97
|
+
*/
|
|
98
|
+
export function collapseUselessGroupsStage(root) {
|
|
99
|
+
const result = collapseUselessGroups(root);
|
|
100
|
+
return {
|
|
101
|
+
modified: result.collapsedCount > 0,
|
|
102
|
+
stats: result,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path Command Optimizer (Phase 4.3)
|
|
3
|
+
*
|
|
4
|
+
* Goal: Achieve 50-70% reduction on complex paths with smart curve transformation
|
|
5
|
+
*
|
|
6
|
+
* Main features:
|
|
7
|
+
* 1. Curve shortening (C→S, C→Q, Q→T)
|
|
8
|
+
* 2. Smart command substitution (C/Q→L when straight)
|
|
9
|
+
* 3. Relative/Absolute re-evaluation after changes
|
|
10
|
+
* 4. Configurable tolerance based on optimization level
|
|
11
|
+
*
|
|
12
|
+
* Expected improvement: 10-25% additional reduction on complex icons
|
|
13
|
+
*/
|
|
14
|
+
import type { PathCommand } from './path-parser.js';
|
|
15
|
+
/**
|
|
16
|
+
* Optimize path commands by transforming curves to simpler forms
|
|
17
|
+
*
|
|
18
|
+
* Priority:
|
|
19
|
+
* 1. C → S (smooth cubic)
|
|
20
|
+
* 2. C → Q (cubic to quadratic)
|
|
21
|
+
* 3. Q → T (smooth quadratic)
|
|
22
|
+
* 4. C/Q → L (curve to line when straight)
|
|
23
|
+
* 5. Re-evaluate absolute/relative after changes
|
|
24
|
+
*/
|
|
25
|
+
export declare function optimizeCommands(commands: PathCommand[], tolerance?: number, precision?: number): {
|
|
26
|
+
commands: PathCommand[];
|
|
27
|
+
stats: {
|
|
28
|
+
convertedCtoS: number;
|
|
29
|
+
convertedCtoQ: number;
|
|
30
|
+
convertedQtoT: number;
|
|
31
|
+
convertedCurveToLine: number;
|
|
32
|
+
reoptimizedAbsRel: number;
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* Command optimization stage for pipeline integration
|
|
37
|
+
* Applies curve shortening, smart substitution, and re-optimization
|
|
38
|
+
*/
|
|
39
|
+
export declare function commandOptimizationStage(commands: PathCommand[], tolerance?: number, precision?: number): {
|
|
40
|
+
commands: PathCommand[];
|
|
41
|
+
stats: {
|
|
42
|
+
convertedCtoS: number;
|
|
43
|
+
convertedCtoQ: number;
|
|
44
|
+
convertedQtoT: number;
|
|
45
|
+
convertedCurveToLine: number;
|
|
46
|
+
reoptimizedAbsRel: number;
|
|
47
|
+
};
|
|
48
|
+
};
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Path Command Optimizer (Phase 4.3)
|
|
3
|
+
*
|
|
4
|
+
* Goal: Achieve 50-70% reduction on complex paths with smart curve transformation
|
|
5
|
+
*
|
|
6
|
+
* Main features:
|
|
7
|
+
* 1. Curve shortening (C→S, C→Q, Q→T)
|
|
8
|
+
* 2. Smart command substitution (C/Q→L when straight)
|
|
9
|
+
* 3. Relative/Absolute re-evaluation after changes
|
|
10
|
+
* 4. Configurable tolerance based on optimization level
|
|
11
|
+
*
|
|
12
|
+
* Expected improvement: 10-25% additional reduction on complex icons
|
|
13
|
+
*/
|
|
14
|
+
import { toAbsolute, toRelative, compareAbsoluteRelativeSize, } from './path-parser.js';
|
|
15
|
+
/**
|
|
16
|
+
* Distance between two points
|
|
17
|
+
*/
|
|
18
|
+
function distance(x1, y1, x2, y2) {
|
|
19
|
+
const dx = x2 - x1;
|
|
20
|
+
const dy = y2 - y1;
|
|
21
|
+
return Math.sqrt(dx * dx + dy * dy);
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Check if three points are approximately collinear
|
|
25
|
+
* Returns true if the middle point is very close to the line connecting the first and third points
|
|
26
|
+
*/
|
|
27
|
+
function isCollinear(x1, y1, x2, y2, x3, y3, tolerance = 0.1) {
|
|
28
|
+
// Calculate the distance from point 2 to the line formed by points 1 and 3
|
|
29
|
+
// Using the formula: distance = |ax + by + c| / sqrt(a² + b²)
|
|
30
|
+
// Where line is: (y3-y1)x - (x3-x1)y + (x3-x1)y1 - (y3-y1)x1 = 0
|
|
31
|
+
const a = y3 - y1;
|
|
32
|
+
const b = -(x3 - x1);
|
|
33
|
+
const c = (x3 - x1) * y1 - (y3 - y1) * x1;
|
|
34
|
+
const denominator = Math.sqrt(a * a + b * b);
|
|
35
|
+
if (denominator < 1e-10) {
|
|
36
|
+
// Points 1 and 3 are the same, check if point 2 is also the same
|
|
37
|
+
return distance(x1, y1, x2, y2) < tolerance;
|
|
38
|
+
}
|
|
39
|
+
const dist = Math.abs(a * x2 + b * y2 + c) / denominator;
|
|
40
|
+
return dist < tolerance;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Check if a cubic bezier curve is approximately a quadratic bezier
|
|
44
|
+
* Returns the quadratic control point if true, null otherwise
|
|
45
|
+
*/
|
|
46
|
+
function cubicToQuadratic(x0, y0, x1, y1, x2, y2, x3, y3, tolerance = 1.0) {
|
|
47
|
+
// A cubic bezier C(x0,y0, x1,y1, x2,y2, x3,y3) can be approximated by
|
|
48
|
+
// quadratic Q(x0,y0, qx,qy, x3,y3) if the cubic control points are positioned correctly.
|
|
49
|
+
//
|
|
50
|
+
// For a perfect conversion: qx = (3*x1 - x0)/2, qy = (3*y1 - y0)/2 (from first control point)
|
|
51
|
+
// and also: qx = (3*x2 - x3)/2, qy = (3*y2 - y3)/2 (from second control point)
|
|
52
|
+
//
|
|
53
|
+
// These should give the same result for a true quadratic.
|
|
54
|
+
const qx1 = (3 * x1 - x0) / 2;
|
|
55
|
+
const qy1 = (3 * y1 - y0) / 2;
|
|
56
|
+
const qx2 = (3 * x2 - x3) / 2;
|
|
57
|
+
const qy2 = (3 * y2 - y3) / 2;
|
|
58
|
+
// Check if both calculations give approximately the same control point
|
|
59
|
+
const dist = distance(qx1, qy1, qx2, qy2);
|
|
60
|
+
if (dist < tolerance) {
|
|
61
|
+
// Use the average for better accuracy
|
|
62
|
+
return {
|
|
63
|
+
qx: (qx1 + qx2) / 2,
|
|
64
|
+
qy: (qy1 + qy2) / 2,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Check if a curve segment is approximately a straight line
|
|
71
|
+
*/
|
|
72
|
+
function isCurveApproximatelyStraight(x0, y0, controlPoints, xEnd, yEnd, tolerance = 1.0) {
|
|
73
|
+
// Check if all control points are close to the line from start to end
|
|
74
|
+
for (let i = 0; i < controlPoints.length; i += 2) {
|
|
75
|
+
const cx = controlPoints[i];
|
|
76
|
+
const cy = controlPoints[i + 1];
|
|
77
|
+
if (!isCollinear(x0, y0, cx, cy, xEnd, yEnd, tolerance)) {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return true;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Check if Q command can be converted to T (smooth quadratic)
|
|
85
|
+
* Q can become T if the current control point is the reflection of the previous one
|
|
86
|
+
*/
|
|
87
|
+
function canConvertQtoT(prevCmd, currentX, currentY, qx, qy, tolerance = 0.1) {
|
|
88
|
+
if (!prevCmd ||
|
|
89
|
+
(prevCmd.type !== 'Q' &&
|
|
90
|
+
prevCmd.type !== 'q' &&
|
|
91
|
+
prevCmd.type !== 'T' &&
|
|
92
|
+
prevCmd.type !== 't')) {
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
// Get the previous control point
|
|
96
|
+
let prevQx, prevQy;
|
|
97
|
+
if (prevCmd.type === 'Q' || prevCmd.type === 'q') {
|
|
98
|
+
if (prevCmd.type === 'Q') {
|
|
99
|
+
prevQx = prevCmd.values[0];
|
|
100
|
+
prevQy = prevCmd.values[1];
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
// Convert relative to absolute
|
|
104
|
+
const absX = prevCmd.absolutePosition?.x || 0;
|
|
105
|
+
const absY = prevCmd.absolutePosition?.y || 0;
|
|
106
|
+
prevQx = absX + prevCmd.values[0];
|
|
107
|
+
prevQy = absY + prevCmd.values[1];
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
else {
|
|
111
|
+
// T/t command - the control point is reflected from previous
|
|
112
|
+
return false; // Can't check, assume no
|
|
113
|
+
}
|
|
114
|
+
// Calculate expected reflected control point
|
|
115
|
+
const reflectedQx = 2 * currentX - prevQx;
|
|
116
|
+
const reflectedQy = 2 * currentY - prevQy;
|
|
117
|
+
// Check if current control point matches the reflection
|
|
118
|
+
const dist = distance(qx, qy, reflectedQx, reflectedQy);
|
|
119
|
+
return dist < tolerance;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Check if C command can be converted to S (smooth cubic)
|
|
123
|
+
* C can become S if the first control point is the reflection of the previous second control point
|
|
124
|
+
*/
|
|
125
|
+
function canConvertCtoS(prevCmd, currentX, currentY, x1, y1, tolerance = 0.1) {
|
|
126
|
+
if (!prevCmd ||
|
|
127
|
+
(prevCmd.type !== 'C' &&
|
|
128
|
+
prevCmd.type !== 'c' &&
|
|
129
|
+
prevCmd.type !== 'S' &&
|
|
130
|
+
prevCmd.type !== 's')) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
// Get the previous second control point
|
|
134
|
+
let prevX2, prevY2;
|
|
135
|
+
if (prevCmd.type === 'C' || prevCmd.type === 'c') {
|
|
136
|
+
if (prevCmd.type === 'C') {
|
|
137
|
+
prevX2 = prevCmd.values[2];
|
|
138
|
+
prevY2 = prevCmd.values[3];
|
|
139
|
+
}
|
|
140
|
+
else {
|
|
141
|
+
// Convert relative to absolute
|
|
142
|
+
const absX = prevCmd.absolutePosition?.x || 0;
|
|
143
|
+
const absY = prevCmd.absolutePosition?.y || 0;
|
|
144
|
+
prevX2 = absX + prevCmd.values[2];
|
|
145
|
+
prevY2 = absY + prevCmd.values[3];
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
else if (prevCmd.type === 'S' || prevCmd.type === 's') {
|
|
149
|
+
if (prevCmd.type === 'S') {
|
|
150
|
+
prevX2 = prevCmd.values[0];
|
|
151
|
+
prevY2 = prevCmd.values[1];
|
|
152
|
+
}
|
|
153
|
+
else {
|
|
154
|
+
const absX = prevCmd.absolutePosition?.x || 0;
|
|
155
|
+
const absY = prevCmd.absolutePosition?.y || 0;
|
|
156
|
+
prevX2 = absX + prevCmd.values[0];
|
|
157
|
+
prevY2 = absY + prevCmd.values[1];
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
return false;
|
|
162
|
+
}
|
|
163
|
+
// Calculate expected reflected control point
|
|
164
|
+
const reflectedX1 = 2 * currentX - prevX2;
|
|
165
|
+
const reflectedY1 = 2 * currentY - prevY2;
|
|
166
|
+
// Check if current first control point matches the reflection
|
|
167
|
+
const dist = distance(x1, y1, reflectedX1, reflectedY1);
|
|
168
|
+
return dist < tolerance;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Optimize path commands by transforming curves to simpler forms
|
|
172
|
+
*
|
|
173
|
+
* Priority:
|
|
174
|
+
* 1. C → S (smooth cubic)
|
|
175
|
+
* 2. C → Q (cubic to quadratic)
|
|
176
|
+
* 3. Q → T (smooth quadratic)
|
|
177
|
+
* 4. C/Q → L (curve to line when straight)
|
|
178
|
+
* 5. Re-evaluate absolute/relative after changes
|
|
179
|
+
*/
|
|
180
|
+
export function optimizeCommands(commands, tolerance = 1.0, precision = 3) {
|
|
181
|
+
const stats = {
|
|
182
|
+
convertedCtoS: 0,
|
|
183
|
+
convertedCtoQ: 0,
|
|
184
|
+
convertedQtoT: 0,
|
|
185
|
+
convertedCurveToLine: 0,
|
|
186
|
+
reoptimizedAbsRel: 0,
|
|
187
|
+
};
|
|
188
|
+
const optimized = [];
|
|
189
|
+
let currentX = 0;
|
|
190
|
+
let currentY = 0;
|
|
191
|
+
let prevCmd = null;
|
|
192
|
+
for (let i = 0; i < commands.length; i++) {
|
|
193
|
+
let cmd = commands[i];
|
|
194
|
+
let modified = false;
|
|
195
|
+
// Update current position for absolute commands
|
|
196
|
+
if (cmd.absolutePosition) {
|
|
197
|
+
currentX = cmd.absolutePosition.x;
|
|
198
|
+
currentY = cmd.absolutePosition.y;
|
|
199
|
+
}
|
|
200
|
+
// Get absolute coordinates for analysis
|
|
201
|
+
const absCmd = cmd.type === cmd.type.toLowerCase()
|
|
202
|
+
? toAbsolute(cmd, currentX, currentY)
|
|
203
|
+
: cmd;
|
|
204
|
+
// 1. Try C → S (smooth cubic bezier)
|
|
205
|
+
if (absCmd.type === 'C') {
|
|
206
|
+
const [x1, y1, x2, y2, x, y] = absCmd.values;
|
|
207
|
+
if (canConvertCtoS(prevCmd, currentX, currentY, x1, y1, tolerance)) {
|
|
208
|
+
// Convert to S command (only need second control point and end point)
|
|
209
|
+
cmd = {
|
|
210
|
+
type: 'S',
|
|
211
|
+
values: [x2, y2, x, y],
|
|
212
|
+
absolutePosition: { x, y },
|
|
213
|
+
};
|
|
214
|
+
stats.convertedCtoS++;
|
|
215
|
+
modified = true;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
// 2. Try C → Q (cubic to quadratic)
|
|
219
|
+
if (!modified && absCmd.type === 'C') {
|
|
220
|
+
const [x1, y1, x2, y2, x, y] = absCmd.values;
|
|
221
|
+
const quadratic = cubicToQuadratic(currentX, currentY, x1, y1, x2, y2, x, y, tolerance);
|
|
222
|
+
if (quadratic) {
|
|
223
|
+
// Convert to Q command
|
|
224
|
+
cmd = {
|
|
225
|
+
type: 'Q',
|
|
226
|
+
values: [quadratic.qx, quadratic.qy, x, y],
|
|
227
|
+
absolutePosition: { x, y },
|
|
228
|
+
};
|
|
229
|
+
stats.convertedCtoQ++;
|
|
230
|
+
modified = true;
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
// 3. Try Q → T (smooth quadratic)
|
|
234
|
+
if (!modified && absCmd.type === 'Q') {
|
|
235
|
+
const [qx, qy, x, y] = absCmd.values;
|
|
236
|
+
if (canConvertQtoT(prevCmd, currentX, currentY, qx, qy, tolerance)) {
|
|
237
|
+
// Convert to T command (only need end point)
|
|
238
|
+
cmd = {
|
|
239
|
+
type: 'T',
|
|
240
|
+
values: [x, y],
|
|
241
|
+
absolutePosition: { x, y },
|
|
242
|
+
};
|
|
243
|
+
stats.convertedQtoT++;
|
|
244
|
+
modified = true;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// 4. Try C/Q → L (curve to line when approximately straight)
|
|
248
|
+
if (!modified && (absCmd.type === 'C' || absCmd.type === 'Q')) {
|
|
249
|
+
const values = absCmd.values;
|
|
250
|
+
const endX = values[values.length - 2];
|
|
251
|
+
const endY = values[values.length - 1];
|
|
252
|
+
const controlPoints = values.slice(0, -2);
|
|
253
|
+
if (isCurveApproximatelyStraight(currentX, currentY, controlPoints, endX, endY, tolerance)) {
|
|
254
|
+
// Convert to L command
|
|
255
|
+
cmd = {
|
|
256
|
+
type: 'L',
|
|
257
|
+
values: [endX, endY],
|
|
258
|
+
absolutePosition: { x: endX, y: endY },
|
|
259
|
+
};
|
|
260
|
+
stats.convertedCurveToLine++;
|
|
261
|
+
modified = true;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
// 5. Re-evaluate absolute/relative after modifications
|
|
265
|
+
if (modified) {
|
|
266
|
+
// Try both absolute and relative, keep whichever is shorter
|
|
267
|
+
const absCmd = cmd.type === cmd.type.toLowerCase()
|
|
268
|
+
? toAbsolute(cmd, currentX, currentY)
|
|
269
|
+
: cmd;
|
|
270
|
+
const relCmd = toRelative(absCmd, currentX, currentY);
|
|
271
|
+
const sizeDiff = compareAbsoluteRelativeSize(absCmd, currentX, currentY, precision);
|
|
272
|
+
if (sizeDiff > 0) {
|
|
273
|
+
// Relative is shorter
|
|
274
|
+
cmd = relCmd;
|
|
275
|
+
stats.reoptimizedAbsRel++;
|
|
276
|
+
}
|
|
277
|
+
else if (sizeDiff < 0) {
|
|
278
|
+
// Absolute is shorter
|
|
279
|
+
cmd = absCmd;
|
|
280
|
+
stats.reoptimizedAbsRel++;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
optimized.push(cmd);
|
|
284
|
+
// Update position and previous command
|
|
285
|
+
if (cmd.absolutePosition) {
|
|
286
|
+
currentX = cmd.absolutePosition.x;
|
|
287
|
+
currentY = cmd.absolutePosition.y;
|
|
288
|
+
}
|
|
289
|
+
prevCmd = cmd;
|
|
290
|
+
}
|
|
291
|
+
return { commands: optimized, stats };
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Command optimization stage for pipeline integration
|
|
295
|
+
* Applies curve shortening, smart substitution, and re-optimization
|
|
296
|
+
*/
|
|
297
|
+
export function commandOptimizationStage(commands, tolerance = 1.0, precision = 3) {
|
|
298
|
+
return optimizeCommands(commands, tolerance, precision);
|
|
299
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SVG Optimizer Module
|
|
3
|
+
* Advanced SVG optimization system with pluggable pipeline architecture
|
|
4
|
+
*/
|
|
5
|
+
export { OptimizerPipeline, createOptimizerPipeline, } from './optimizer-pipeline.js';
|
|
6
|
+
export { OptLevel, type OptConfig, type OptimizationPlugin, type OptimizedNode, type OptimizedTree, type OptimizationStage, type OptimizationResult, getDefaultOptConfig, } from './types.js';
|
|
7
|
+
export { basicCleaningStage, removeXMLDeclaration, removeDoctype, removeComments, normalizeWhitespace, removeMetadata, convertToCamelCase, removeXMLNamespaces, removeInlineStyles, shortenColors, removeEmptyContainers, removeHiddenElements, roundFloats, sortAttributes, } from './basic-cleaner.js';
|
|
8
|
+
export { type SVGNode, parseSVG, traverseTree, findNodesByTag, findNodeById, getAllIds, removeNode, replaceNode, cloneNode, } from './svg-tree-parser.js';
|
|
9
|
+
export { type SerializerOptions, serializeNode, serializeSVG, serializeSVGPretty, serializeSVGMinified, calculateReduction, } from './tree-serializer.js';
|
|
10
|
+
export { treeOptimizationStage, treeRemoveUnusedDefsStage, treeCollapseGroupsStage, treeMoveAttributesToParentStage, treeRemoveHiddenEmptyStage, } from './tree-stages.js';
|
|
11
|
+
export { removeUnusedDefs, removeUnusedDefsStage, } from './remove-unused-defs.js';
|
|
12
|
+
export { collapseUselessGroups, collapseUselessGroupsStage, } from './collapse-useless-groups.js';
|
|
13
|
+
export { moveAttributesToParent, moveAttributesToParentStage, } from './move-attrs-to-parent.js';
|
|
14
|
+
export { removeHiddenAndEmptyElements, removeHiddenAndEmptyElementsStage, } from './remove-hidden-empty.js';
|