build-syntax-resolver.js 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. "use strict";
  2. const path = require("path");
  3. const postcssSafeParser = require("postcss-safe-parser");
  4. const { cssSyntax, cssSafeSyntax } = require("./syntaxes");
  5. const { loadModule, isModuleNotFoundError } = require("../shared/load-module");
  6. const defaultRules = [
  7. {
  8. test: /^sass$/i,
  9. lang: "sass",
  10. },
  11. {
  12. test: /^scss$/i,
  13. lang: "scss",
  14. },
  15. {
  16. test: /^less$/i,
  17. lang: "less",
  18. },
  19. {
  20. test: /^s(?:ugar)?ss$/i,
  21. lang: "sugarss",
  22. },
  23. {
  24. test: /^styl(?:us)?$/i,
  25. lang: "stylus",
  26. },
  27. {
  28. test: /^postcss$/i,
  29. lang: "css",
  30. },
  31. ];
  32. const defaultSyntaxes = {
  33. sass: "postcss-sass",
  34. scss: "postcss-scss",
  35. less: "postcss-less",
  36. sugarss: "sugarss",
  37. stylus: "postcss-styl",
  38. };
  39. module.exports = function buildSyntaxResolver(config) {
  40. const { rules = [], ...syntaxes } = config || {};
  41. const allRules = [...rules, ...defaultRules];
  42. const definedLangs = new Set([
  43. "css",
  44. ...rules.map((rule) => rule.lang),
  45. ...Object.keys(syntaxes),
  46. ]);
  47. return function resolve(baseLang) {
  48. let lang = baseLang || "css";
  49. const cwd = process.cwd();
  50. const placeholderFilePath = path.join(cwd, `__placeholder__.${lang}`);
  51. for (const rule of allRules) {
  52. const regex = new RegExp(rule.test);
  53. if (regex.test(lang) || regex.test(placeholderFilePath)) {
  54. lang = rule.lang;
  55. break;
  56. }
  57. }
  58. lang = lang.toLowerCase();
  59. const syntax = syntaxes[lang] || defaultSyntaxes[lang];
  60. if (syntax) {
  61. if (typeof syntax === "string") {
  62. const syntaxModule = loadFromString(syntax);
  63. if (syntaxModule) {
  64. return syntaxModule;
  65. }
  66. if (definedLangs.has(lang)) {
  67. throw new Error(
  68. `Cannot resolve module "${syntax}". It's likely that the module isn't installed correctly. Try reinstalling by running the \`npm install ${syntax}@latest --save-dev\``
  69. );
  70. }
  71. }
  72. if (syntax === postcssSafeParser) {
  73. return cssSafeSyntax;
  74. }
  75. if (typeof syntax.parse === "function") {
  76. return syntax;
  77. }
  78. }
  79. if (!definedLangs.has(lang)) {
  80. return null;
  81. }
  82. return cssSyntax;
  83. };
  84. };
  85. const standardModuleResolvers = {
  86. // eslint-disable-next-line node/no-missing-require -- ignore
  87. "postcss-sass": () => require("postcss-sass"),
  88. // eslint-disable-next-line node/no-unpublished-require -- ignore
  89. "postcss-scss": () => require("postcss-scss"),
  90. // eslint-disable-next-line node/no-unpublished-require -- ignore
  91. "postcss-less": () => require("postcss-less"),
  92. // eslint-disable-next-line node/no-unpublished-require -- ignore
  93. sugarss: () => require("sugarss"),
  94. // eslint-disable-next-line node/no-unpublished-require -- ignore
  95. "postcss-styl": () => require("postcss-styl"),
  96. };
  97. function loadFromString(syntax) {
  98. if (syntax === "postcss") {
  99. return cssSyntax;
  100. }
  101. if (syntax === "postcss-safe-parser") {
  102. return cssSafeSyntax;
  103. }
  104. const loadedModule = loadModule(syntax);
  105. if (loadedModule) {
  106. return loadedModule;
  107. }
  108. /* istanbul ignore if */
  109. if (standardModuleResolvers[syntax]) {
  110. try {
  111. return standardModuleResolvers[syntax]();
  112. } catch (error) {
  113. if (!isModuleNotFoundError(error)) {
  114. throw error;
  115. }
  116. // ignore
  117. }
  118. }
  119. return null;
  120. }