import { StyleSheet } from '@emotion/sheet'; import Stylis from '@emotion/stylis'; import weakMemoize from '@emotion/weak-memoize'; // https://github.com/thysultan/stylis.js/tree/master/plugins/rule-sheet // inlined to avoid umd wrapper and peerDep warnings/installing stylis // since we use stylis after closure compiler var delimiter = '/*|*/'; var needle = delimiter + '}'; function toSheet(block) { if (block) { Sheet.current.insert(block + '}'); } } var Sheet = { current: null }; var ruleSheet = function ruleSheet(context, content, selectors, parents, line, column, length, ns, depth, at) { switch (context) { // property case 1: { switch (content.charCodeAt(0)) { case 64: { // @import Sheet.current.insert(content + ';'); return ''; } // charcode for l case 108: { // charcode for b // this ignores label if (content.charCodeAt(2) === 98) { return ''; } } } break; } // selector case 2: { if (ns === 0) return content + delimiter; break; } // at-rule case 3: { switch (ns) { // @font-face, @page case 102: case 112: { Sheet.current.insert(selectors[0] + content); return ''; } default: { return content + (at === 0 ? delimiter : ''); } } } case -2: { content.split(needle).forEach(toSheet); } } }; var removeLabel = function removeLabel(context, content) { if (context === 1 && // charcode for l content.charCodeAt(0) === 108 && // charcode for b content.charCodeAt(2) === 98 // this ignores label ) { return ''; } }; var isBrowser = typeof document !== 'undefined'; var rootServerStylisCache = {}; var getServerStylisCache = isBrowser ? undefined : weakMemoize(function () { var getCache = weakMemoize(function () { return {}; }); var prefixTrueCache = {}; var prefixFalseCache = {}; return function (prefix) { if (prefix === undefined || prefix === true) { return prefixTrueCache; } if (prefix === false) { return prefixFalseCache; } return getCache(prefix); }; }); var createCache = function createCache(options) { if (options === undefined) options = {}; var key = options.key || 'css'; var stylisOptions; if (options.prefix !== undefined) { stylisOptions = { prefix: options.prefix }; } var stylis = new Stylis(stylisOptions); if (process.env.NODE_ENV !== 'production') { // $FlowFixMe if (/[^a-z-]/.test(key)) { throw new Error("Emotion key must only contain lower case alphabetical characters and - but \"" + key + "\" was passed"); } } var inserted = {}; // $FlowFixMe var container; if (isBrowser) { container = options.container || document.head; var nodes = document.querySelectorAll("style[data-emotion-" + key + "]"); Array.prototype.forEach.call(nodes, function (node) { var attrib = node.getAttribute("data-emotion-" + key); // $FlowFixMe attrib.split(' ').forEach(function (id) { inserted[id] = true; }); if (node.parentNode !== container) { container.appendChild(node); } }); } var _insert; if (isBrowser) { stylis.use(options.stylisPlugins)(ruleSheet); _insert = function insert(selector, serialized, sheet, shouldCache) { var name = serialized.name; Sheet.current = sheet; if (process.env.NODE_ENV !== 'production' && serialized.map !== undefined) { var map = serialized.map; Sheet.current = { insert: function insert(rule) { sheet.insert(rule + map); } }; } stylis(selector, serialized.styles); if (shouldCache) { cache.inserted[name] = true; } }; } else { stylis.use(removeLabel); var serverStylisCache = rootServerStylisCache; if (options.stylisPlugins || options.prefix !== undefined) { stylis.use(options.stylisPlugins); // $FlowFixMe serverStylisCache = getServerStylisCache(options.stylisPlugins || rootServerStylisCache)(options.prefix); } var getRules = function getRules(selector, serialized) { var name = serialized.name; if (serverStylisCache[name] === undefined) { serverStylisCache[name] = stylis(selector, serialized.styles); } return serverStylisCache[name]; }; _insert = function _insert(selector, serialized, sheet, shouldCache) { var name = serialized.name; var rules = getRules(selector, serialized); if (cache.compat === undefined) { // in regular mode, we don't set the styles on the inserted cache // since we don't need to and that would be wasting memory // we return them so that they are rendered in a style tag if (shouldCache) { cache.inserted[name] = true; } if ( // using === development instead of !== production // because if people do ssr in tests, the source maps showing up would be annoying process.env.NODE_ENV === 'development' && serialized.map !== undefined) { return rules + serialized.map; } return rules; } else { // in compat mode, we put the styles on the inserted cache so // that emotion-server can pull out the styles // except when we don't want to cache it which was in Global but now // is nowhere but we don't want to do a major right now // and just in case we're going to leave the case here // it's also not affecting client side bundle size // so it's really not a big deal if (shouldCache) { cache.inserted[name] = rules; } else { return rules; } } }; } if (process.env.NODE_ENV !== 'production') { // https://esbench.com/bench/5bf7371a4cd7e6009ef61d0a var commentStart = /\/\*/g; var commentEnd = /\*\//g; stylis.use(function (context, content) { switch (context) { case -1: { while (commentStart.test(content)) { commentEnd.lastIndex = commentStart.lastIndex; if (commentEnd.test(content)) { commentStart.lastIndex = commentEnd.lastIndex; continue; } throw new Error('Your styles have an unterminated comment ("/*" without corresponding "*/").'); } commentStart.lastIndex = 0; break; } } }); stylis.use(function (context, content, selectors) { switch (context) { case -1: { var flag = 'emotion-disable-server-rendering-unsafe-selector-warning-please-do-not-use-this-the-warning-exists-for-a-reason'; var unsafePseudoClasses = content.match(/(:first|:nth|:nth-last)-child/g); if (unsafePseudoClasses && cache.compat !== true) { unsafePseudoClasses.forEach(function (unsafePseudoClass) { var ignoreRegExp = new RegExp(unsafePseudoClass + ".*\\/\\* " + flag + " \\*\\/"); var ignore = ignoreRegExp.test(content); if (unsafePseudoClass && !ignore) { console.error("The pseudo class \"" + unsafePseudoClass + "\" is potentially unsafe when doing server-side rendering. Try changing it to \"" + unsafePseudoClass.split('-child')[0] + "-of-type\"."); } }); } break; } } }); } var cache = { key: key, sheet: new StyleSheet({ key: key, container: container, nonce: options.nonce, speedy: options.speedy }), nonce: options.nonce, inserted: inserted, registered: {}, insert: _insert }; return cache; }; export default createCache;