index.js 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', {
  3. value: true
  4. });
  5. var _slicedToArray = (function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i['return']) _i['return'](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError('Invalid attempt to destructure non-iterable instance'); } }; })();
  6. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  7. var _postcss = require('postcss');
  8. var _postcss2 = _interopRequireDefault(_postcss);
  9. var _topologicalSort = require('./topologicalSort');
  10. var _topologicalSort2 = _interopRequireDefault(_topologicalSort);
  11. var declWhitelist = ['composes'];
  12. var declFilter = new RegExp('^(' + declWhitelist.join('|') + ')$');
  13. var matchImports = /^(.+?)\s+from\s+(?:"([^"]+)"|'([^']+)'|(global))$/;
  14. var icssImport = /^:import\((?:"([^"]+)"|'([^']+)')\)/;
  15. var VISITED_MARKER = 1;
  16. function createParentName(rule, root) {
  17. return '__' + root.index(rule.parent) + '_' + rule.selector;
  18. }
  19. function serializeImports(imports) {
  20. return imports.map(function (importPath) {
  21. return '`' + importPath + '`';
  22. }).join(', ');
  23. }
  24. /**
  25. * :import('G') {}
  26. *
  27. * Rule
  28. * composes: ... from 'A'
  29. * composes: ... from 'B'
  30. * Rule
  31. * composes: ... from 'A'
  32. * composes: ... from 'A'
  33. * composes: ... from 'C'
  34. *
  35. * Results in:
  36. *
  37. * graph: {
  38. * G: [],
  39. * A: [],
  40. * B: ['A'],
  41. * C: ['A'],
  42. * }
  43. */
  44. function addImportToGraph(importId, parentId, graph, visited) {
  45. var siblingsId = parentId + '_' + 'siblings';
  46. var visitedId = parentId + '_' + importId;
  47. if (visited[visitedId] !== VISITED_MARKER) {
  48. if (!Array.isArray(visited[siblingsId])) visited[siblingsId] = [];
  49. var siblings = visited[siblingsId];
  50. if (Array.isArray(graph[importId])) graph[importId] = graph[importId].concat(siblings);else graph[importId] = siblings.slice();
  51. visited[visitedId] = VISITED_MARKER;
  52. siblings.push(importId);
  53. }
  54. }
  55. var processor = _postcss2['default'].plugin('modules-extract-imports', function () {
  56. var options = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
  57. var failOnWrongOrder = options.failOnWrongOrder;
  58. return function (css) {
  59. var graph = {};
  60. var visited = {};
  61. var existingImports = {};
  62. var importDecls = {};
  63. var imports = {};
  64. var importIndex = 0;
  65. var createImportedName = typeof options.createImportedName !== 'function' ? function (importName /*, path*/) {
  66. return 'i__imported_' + importName.replace(/\W/g, '_') + '_' + importIndex++;
  67. } : options.createImportedName;
  68. // Check the existing imports order and save refs
  69. css.walkRules(function (rule) {
  70. var matches = icssImport.exec(rule.selector);
  71. if (matches) {
  72. var _matches = _slicedToArray(matches, 3);
  73. var /*match*/doubleQuotePath = _matches[1];
  74. var singleQuotePath = _matches[2];
  75. var importPath = doubleQuotePath || singleQuotePath;
  76. addImportToGraph(importPath, 'root', graph, visited);
  77. existingImports[importPath] = rule;
  78. }
  79. });
  80. // Find any declaration that supports imports
  81. css.walkDecls(declFilter, function (decl) {
  82. var matches = decl.value.match(matchImports);
  83. var tmpSymbols = undefined;
  84. if (matches) {
  85. var _matches2 = _slicedToArray(matches, 5);
  86. var /*match*/symbols = _matches2[1];
  87. var doubleQuotePath = _matches2[2];
  88. var singleQuotePath = _matches2[3];
  89. var _global = _matches2[4];
  90. if (_global) {
  91. // Composing globals simply means changing these classes to wrap them in global(name)
  92. tmpSymbols = symbols.split(/\s+/).map(function (s) {
  93. return 'global(' + s + ')';
  94. });
  95. } else {
  96. (function () {
  97. var importPath = doubleQuotePath || singleQuotePath;
  98. var parentRule = createParentName(decl.parent, css);
  99. addImportToGraph(importPath, parentRule, graph, visited);
  100. importDecls[importPath] = decl;
  101. imports[importPath] = imports[importPath] || {};
  102. tmpSymbols = symbols.split(/\s+/).map(function (s) {
  103. if (!imports[importPath][s]) {
  104. imports[importPath][s] = createImportedName(s, importPath);
  105. }
  106. return imports[importPath][s];
  107. });
  108. })();
  109. }
  110. decl.value = tmpSymbols.join(' ');
  111. }
  112. });
  113. var importsOrder = (0, _topologicalSort2['default'])(graph, failOnWrongOrder);
  114. if (importsOrder instanceof Error) {
  115. var importPath = importsOrder.nodes.find(function (importPath) {
  116. return importDecls.hasOwnProperty(importPath);
  117. });
  118. var decl = importDecls[importPath];
  119. var errMsg = 'Failed to resolve order of composed modules ' + serializeImports(importsOrder.nodes) + '.';
  120. throw decl.error(errMsg, {
  121. plugin: 'modules-extract-imports',
  122. word: 'composes'
  123. });
  124. }
  125. var lastImportRule = undefined;
  126. importsOrder.forEach(function (path) {
  127. var importedSymbols = imports[path];
  128. var rule = existingImports[path];
  129. if (!rule && importedSymbols) {
  130. rule = _postcss2['default'].rule({
  131. selector: ':import("' + path + '")',
  132. raws: { after: '\n' }
  133. });
  134. if (lastImportRule) css.insertAfter(lastImportRule, rule);else css.prepend(rule);
  135. }
  136. lastImportRule = rule;
  137. if (!importedSymbols) return;
  138. Object.keys(importedSymbols).forEach(function (importedSymbol) {
  139. rule.append(_postcss2['default'].decl({
  140. value: importedSymbol,
  141. prop: importedSymbols[importedSymbol],
  142. raws: { before: '\n ' }
  143. }));
  144. });
  145. });
  146. };
  147. });
  148. exports['default'] = processor;
  149. module.exports = exports['default'];