You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

211 lines
11 KiB

  1. 'use strict';
  2. function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
  3. var postcss = _interopDefault(require('postcss'));
  4. var postcssAttributeCaseInsensitive = _interopDefault(require('postcss-attribute-case-insensitive'));
  5. var postcssColorFunctionalNotation = _interopDefault(require('postcss-color-functional-notation'));
  6. var postcssColorHexAlpha = _interopDefault(require('postcss-color-hex-alpha'));
  7. var postcssColorModFunction = _interopDefault(require('postcss-color-mod-function'));
  8. var postcssColorRebeccapurple = _interopDefault(require('postcss-color-rebeccapurple'));
  9. var postcssCustomMedia = _interopDefault(require('postcss-custom-media'));
  10. var postcssCustomProperties = _interopDefault(require('postcss-custom-properties'));
  11. var postcssCustomSelectors = _interopDefault(require('postcss-custom-selectors'));
  12. var postcssDirPseudoClass = _interopDefault(require('postcss-dir-pseudo-class'));
  13. var postcssEnvFunction = _interopDefault(require('postcss-env-function'));
  14. var postcssFocusVisible = _interopDefault(require('postcss-focus-visible'));
  15. var postcssFocusWithin = _interopDefault(require('postcss-focus-within'));
  16. var postcssFontVariant = _interopDefault(require('postcss-font-variant'));
  17. var postcssGapProperties = _interopDefault(require('postcss-gap-properties'));
  18. var postcssImageSetPolyfill = _interopDefault(require('postcss-image-set-function'));
  19. var postcssInitial = _interopDefault(require('postcss-initial'));
  20. var postcssLabFunction = _interopDefault(require('postcss-lab-function'));
  21. var postcssLogical = _interopDefault(require('postcss-logical'));
  22. var postcssMediaMinmax = _interopDefault(require('postcss-media-minmax'));
  23. var postcssNesting = _interopDefault(require('postcss-nesting'));
  24. var postcssOverflowShorthand = _interopDefault(require('postcss-overflow-shorthand'));
  25. var postcssPageBreak = _interopDefault(require('postcss-page-break'));
  26. var postcssPlace = _interopDefault(require('postcss-place'));
  27. var postcssPseudoClassAnyLink = _interopDefault(require('postcss-pseudo-class-any-link'));
  28. var postcssReplaceOverflowWrap = _interopDefault(require('postcss-replace-overflow-wrap'));
  29. var postcssSelectorMatches = _interopDefault(require('postcss-selector-matches'));
  30. var postcssSelectorNot = _interopDefault(require('postcss-selector-not'));
  31. var caniuse = require('caniuse-lite');
  32. var autoprefixer = _interopDefault(require('autoprefixer'));
  33. var browserslist = _interopDefault(require('browserslist'));
  34. var cssdb = _interopDefault(require('cssdb'));
  35. var postcssFontFamilySystemUi = postcss.plugin('postcss-system-ui-font', () => root => {
  36. root.walkDecls(propertyRegExp, decl => {
  37. decl.value = decl.value.replace(systemUiMatch, systemUiReplace);
  38. });
  39. });
  40. const propertyRegExp = /(?:^(?:-|\\002d){2})|(?:^font(?:-family)?$)/i;
  41. const whitespace = '[\\f\\n\\r\\x09\\x20]';
  42. const systemUiFamily = ['system-ui',
  43. /* macOS 10.11-10.12 */
  44. '-apple-system',
  45. /* Windows 6+ */
  46. 'Segoe UI',
  47. /* Android 4+ */
  48. 'Roboto',
  49. /* Ubuntu 10.10+ */
  50. 'Ubuntu',
  51. /* Gnome 3+ */
  52. 'Cantarell',
  53. /* KDE Plasma 5+ */
  54. 'Noto Sans',
  55. /* fallback */
  56. 'sans-serif'];
  57. const systemUiMatch = new RegExp(`(^|,|${whitespace}+)(?:system-ui${whitespace}*)(?:,${whitespace}*(?:${systemUiFamily.join('|')})${whitespace}*)?(,|$)`, 'i');
  58. const systemUiReplace = `$1${systemUiFamily.join(', ')}$2`;
  59. var plugins = {
  60. 'all-property': postcssInitial,
  61. 'any-link-pseudo-class': postcssPseudoClassAnyLink,
  62. 'break-properties': postcssPageBreak,
  63. 'case-insensitive-attributes': postcssAttributeCaseInsensitive,
  64. 'color-functional-notation': postcssColorFunctionalNotation,
  65. 'color-mod-function': postcssColorModFunction,
  66. 'custom-media-queries': postcssCustomMedia,
  67. 'custom-properties': postcssCustomProperties,
  68. 'custom-selectors': postcssCustomSelectors,
  69. 'dir-pseudo-class': postcssDirPseudoClass,
  70. 'environment-variables': postcssEnvFunction,
  71. 'focus-visible-pseudo-class': postcssFocusVisible,
  72. 'focus-within-pseudo-class': postcssFocusWithin,
  73. 'font-variant-property': postcssFontVariant,
  74. 'gap-properties': postcssGapProperties,
  75. 'hexadecimal-alpha-notation': postcssColorHexAlpha,
  76. 'image-set-function': postcssImageSetPolyfill,
  77. 'lab-function': postcssLabFunction,
  78. 'logical-properties-and-values': postcssLogical,
  79. 'matches-pseudo-class': postcssSelectorMatches,
  80. 'media-query-ranges': postcssMediaMinmax,
  81. 'nesting-rules': postcssNesting,
  82. 'not-pseudo-class': postcssSelectorNot,
  83. 'overflow-property': postcssOverflowShorthand,
  84. 'overflow-wrap-property': postcssReplaceOverflowWrap,
  85. 'place-properties': postcssPlace,
  86. 'rebeccapurple-color': postcssColorRebeccapurple,
  87. 'system-ui-font-family': postcssFontFamilySystemUi
  88. };
  89. // return a list of features to be inserted before or after cssdb features
  90. function getTransformedInsertions(insertions, placement) {
  91. return Object.keys(insertions).map(id => [].concat(insertions[id]).map(plugin => ({
  92. [placement]: true,
  93. plugin,
  94. id
  95. }))).reduce((array, feature) => array.concat(feature), []);
  96. }
  97. function getUnsupportedBrowsersByFeature(feature) {
  98. const caniuseFeature = caniuse.features[feature]; // if feature support can be determined
  99. if (caniuseFeature) {
  100. const stats = caniuse.feature(caniuseFeature).stats; // return an array of browsers and versions that do not support the feature
  101. const results = Object.keys(stats).reduce((browsers, browser) => browsers.concat(Object.keys(stats[browser]).filter(version => stats[browser][version].indexOf('y') !== 0).map(version => `${browser} ${version}`)), []);
  102. return results;
  103. } else {
  104. // otherwise, return that the feature does not work in any browser
  105. return ['> 0%'];
  106. }
  107. }
  108. // ids ordered by required execution, then alphabetically
  109. var idsByExecutionOrder = ['custom-media-queries', 'custom-properties', 'environment-variables', // run environment-variables here to access transpiled custom media params and properties
  110. 'image-set-function', // run images-set-function before nesting-rules so that it may fix nested media
  111. 'media-query-ranges', // run media-query-range here to prevent duplicate transpilation after nesting-rules
  112. 'nesting-rules', 'custom-selectors', // run custom-selectors after nesting-rules to correctly transpile &:--custom-selector
  113. 'any-link-pseudo-class', 'case-insensitive-attributes', 'focus-visible-pseudo-class', 'focus-within-pseudo-class', 'matches-pseudo-class', 'not-pseudo-class', // run matches-pseudo-class and bit-pseudo-class after other selectors have been transpiled
  114. 'logical-properties-and-values', // run logical-properties-and-values before dir-pseudo-class
  115. 'dir-pseudo-class', 'all-property', // run all-property before other property polyfills
  116. 'color-functional-notation', 'hexadecimal-alpha-notation', 'lab-function', 'rebeccapurple-color', 'color-mod-function', // run color-mod after other color modifications have finished
  117. 'break-properties', 'font-variant-property', 'gap-properties', 'overflow-property', 'overflow-wrap-property', 'place-properties', 'system-ui-font-family'];
  118. var index = postcss.plugin('postcss-preset-env', opts => {
  119. // initialize options
  120. const features = Object(Object(opts).features);
  121. const insertBefore = Object(Object(opts).insertBefore);
  122. const insertAfter = Object(Object(opts).insertAfter);
  123. const browsers = Object(opts).browsers;
  124. const stage = 'stage' in Object(opts) ? opts.stage === false ? 5 : parseInt(opts.stage) || 0 : 2;
  125. const autoprefixerOptions = Object(opts).autoprefixer;
  126. const sharedOpts = initializeSharedOpts(Object(opts));
  127. const stagedAutoprefixer = autoprefixer(Object.assign({
  128. browsers
  129. }, autoprefixerOptions)); // polyfillable features (those with an available postcss plugin)
  130. const polyfillableFeatures = cssdb.concat( // additional features to be inserted before cssdb features
  131. getTransformedInsertions(insertBefore, 'insertBefore'), // additional features to be inserted after cssdb features
  132. getTransformedInsertions(insertAfter, 'insertAfter')).filter( // inserted features or features with an available postcss plugin
  133. feature => feature.insertBefore || feature.id in plugins).sort( // features sorted by execution order and then insertion order
  134. (a, b) => idsByExecutionOrder.indexOf(a.id) - idsByExecutionOrder.indexOf(b.id) || (a.insertBefore ? -1 : b.insertBefore ? 1 : 0) || (a.insertAfter ? 1 : b.insertAfter ? -1 : 0)).map( // polyfillable features as an object
  135. feature => {
  136. // target browsers for the polyfill
  137. const unsupportedBrowsers = getUnsupportedBrowsersByFeature(feature.caniuse);
  138. return feature.insertBefore || feature.insertAfter ? {
  139. browsers: unsupportedBrowsers,
  140. plugin: feature.plugin,
  141. id: `${feature.insertBefore ? 'before' : 'after'}-${feature.id}`,
  142. stage: 6
  143. } : {
  144. browsers: unsupportedBrowsers,
  145. plugin: plugins[feature.id],
  146. id: feature.id,
  147. stage: feature.stage
  148. };
  149. }); // staged features (those at or above the selected stage)
  150. const stagedFeatures = polyfillableFeatures.filter(feature => feature.id in features ? features[feature.id] : feature.stage >= stage).map(feature => ({
  151. browsers: feature.browsers,
  152. plugin: typeof feature.plugin.process === 'function' ? features[feature.id] === true ? sharedOpts // if the plugin is enabled and has shared options
  153. ? feature.plugin(Object.assign({}, sharedOpts)) // otherwise, if the plugin is enabled
  154. : feature.plugin() : sharedOpts // if the plugin has shared options and individual options
  155. ? feature.plugin(Object.assign({}, sharedOpts, features[feature.id])) // if the plugin has individual options
  156. : feature.plugin(Object.assign({}, features[feature.id])) // if the plugin is already initialized
  157. : feature.plugin,
  158. id: feature.id
  159. }));
  160. return (root, result) => {
  161. // browsers supported by the configuration
  162. const supportedBrowsers = browserslist(browsers, {
  163. path: result.root.source && result.root.source.input && result.root.source.input.file,
  164. ignoreUnknownVersions: true
  165. }); // features supported by the stage and browsers
  166. const supportedFeatures = stagedFeatures.filter(feature => supportedBrowsers.some(supportedBrowser => browserslist(feature.browsers, {
  167. ignoreUnknownVersions: true
  168. }).some(polyfillBrowser => polyfillBrowser === supportedBrowser))); // polyfills run in execution order
  169. const polyfills = supportedFeatures.reduce((promise, feature) => promise.then(() => feature.plugin(result.root, result)), Promise.resolve()).then(() => stagedAutoprefixer(result.root, result));
  170. return polyfills;
  171. };
  172. });
  173. const initializeSharedOpts = opts => {
  174. if ('importFrom' in opts || 'exportTo' in opts || 'preserve' in opts) {
  175. const sharedOpts = {};
  176. if ('importFrom' in opts) {
  177. sharedOpts.importFrom = opts.importFrom;
  178. }
  179. if ('exportTo' in opts) {
  180. sharedOpts.exportTo = opts.exportTo;
  181. }
  182. if ('preserve' in opts) {
  183. sharedOpts.preserve = opts.preserve;
  184. }
  185. return sharedOpts;
  186. }
  187. return false;
  188. };
  189. module.exports = index;