svgo-node.js 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. 'use strict';
  2. const os = require('os');
  3. const fs = require('fs');
  4. const { pathToFileURL } = require('url');
  5. const path = require('path');
  6. const {
  7. extendDefaultPlugins,
  8. optimize: optimizeAgnostic,
  9. createContentItem,
  10. } = require('./svgo.js');
  11. exports.extendDefaultPlugins = extendDefaultPlugins;
  12. exports.createContentItem = createContentItem;
  13. const importConfig = async (configFile) => {
  14. let config;
  15. // at the moment dynamic import may randomly fail with segfault
  16. // to workaround this for some users .cjs extension is loaded
  17. // exclusively with require
  18. if (configFile.endsWith('.cjs')) {
  19. config = require(configFile);
  20. } else {
  21. try {
  22. // dynamic import expects file url instead of path and may fail
  23. // when windows path is provided
  24. const { default: imported } = await import(pathToFileURL(configFile));
  25. config = imported;
  26. } catch (importError) {
  27. // TODO remove require in v3
  28. try {
  29. config = require(configFile);
  30. } catch (requireError) {
  31. // throw original error if es module is detected
  32. if (requireError.code === 'ERR_REQUIRE_ESM') {
  33. throw importError;
  34. } else {
  35. throw requireError;
  36. }
  37. }
  38. }
  39. }
  40. if (config == null || typeof config !== 'object' || Array.isArray(config)) {
  41. throw Error(`Invalid config file "${configFile}"`);
  42. }
  43. return config;
  44. };
  45. const isFile = async (file) => {
  46. try {
  47. const stats = await fs.promises.stat(file);
  48. return stats.isFile();
  49. } catch {
  50. return false;
  51. }
  52. };
  53. const loadConfig = async (configFile, cwd = process.cwd()) => {
  54. if (configFile != null) {
  55. if (path.isAbsolute(configFile)) {
  56. return await importConfig(configFile);
  57. } else {
  58. return await importConfig(path.join(cwd, configFile));
  59. }
  60. }
  61. let dir = cwd;
  62. // eslint-disable-next-line no-constant-condition
  63. while (true) {
  64. const js = path.join(dir, 'svgo.config.js');
  65. if (await isFile(js)) {
  66. return await importConfig(js);
  67. }
  68. const mjs = path.join(dir, 'svgo.config.mjs');
  69. if (await isFile(mjs)) {
  70. return await importConfig(mjs);
  71. }
  72. const cjs = path.join(dir, 'svgo.config.cjs');
  73. if (await isFile(cjs)) {
  74. return await importConfig(cjs);
  75. }
  76. const parent = path.dirname(dir);
  77. if (dir === parent) {
  78. return null;
  79. }
  80. dir = parent;
  81. }
  82. };
  83. exports.loadConfig = loadConfig;
  84. const optimize = (input, config) => {
  85. if (config == null) {
  86. config = {};
  87. }
  88. if (typeof config !== 'object') {
  89. throw Error('Config should be an object');
  90. }
  91. return optimizeAgnostic(input, {
  92. ...config,
  93. js2svg: {
  94. // platform specific default for end of line
  95. eol: os.EOL === '\r\n' ? 'crlf' : 'lf',
  96. ...config.js2svg,
  97. },
  98. });
  99. };
  100. exports.optimize = optimize;