import postcss from 'postcss'; import fs from 'fs'; import path from 'path'; function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } } function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; } function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _nonIterableRest(); } function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _iterableToArrayLimit(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"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } function parse(string, splitByAnd) { const array = []; let buffer = ''; let split = false; let func = 0; let i = -1; while (++i < string.length) { const char = string[i]; if (char === '(') { func += 1; } else if (char === ')') { if (func > 0) { func -= 1; } } else if (func === 0) { if (splitByAnd && andRegExp.test(buffer + char)) { split = true; } else if (!splitByAnd && char === ',') { split = true; } } if (split) { array.push(splitByAnd ? new MediaExpression(buffer + char) : new MediaQuery(buffer)); buffer = ''; split = false; } else { buffer += char; } } if (buffer !== '') { array.push(splitByAnd ? new MediaExpression(buffer) : new MediaQuery(buffer)); } return array; } class MediaQueryList { constructor(string) { this.nodes = parse(string); } invert() { this.nodes.forEach(node => { node.invert(); }); return this; } clone() { return new MediaQueryList(String(this)); } toString() { return this.nodes.join(','); } } class MediaQuery { constructor(string) { const _string$match = string.match(spaceWrapRegExp), _string$match2 = _slicedToArray(_string$match, 4), before = _string$match2[1], media = _string$match2[2], after = _string$match2[3]; const _ref = media.match(mediaRegExp) || [], _ref2 = _slicedToArray(_ref, 9), _ref2$ = _ref2[1], modifier = _ref2$ === void 0 ? '' : _ref2$, _ref2$2 = _ref2[2], afterModifier = _ref2$2 === void 0 ? ' ' : _ref2$2, _ref2$3 = _ref2[3], type = _ref2$3 === void 0 ? '' : _ref2$3, _ref2$4 = _ref2[4], beforeAnd = _ref2$4 === void 0 ? '' : _ref2$4, _ref2$5 = _ref2[5], and = _ref2$5 === void 0 ? '' : _ref2$5, _ref2$6 = _ref2[6], beforeExpression = _ref2$6 === void 0 ? '' : _ref2$6, _ref2$7 = _ref2[7], expression1 = _ref2$7 === void 0 ? '' : _ref2$7, _ref2$8 = _ref2[8], expression2 = _ref2$8 === void 0 ? '' : _ref2$8; const raws = { before, after, afterModifier, originalModifier: modifier || '', beforeAnd, and, beforeExpression }; const nodes = parse(expression1 || expression2, true); Object.assign(this, { modifier, type, raws, nodes }); } clone(overrides) { const instance = new MediaQuery(String(this)); Object.assign(instance, overrides); return instance; } invert() { this.modifier = this.modifier ? '' : this.raws.originalModifier; return this; } toString() { const raws = this.raws; return `${raws.before}${this.modifier}${this.modifier ? `${raws.afterModifier}` : ''}${this.type}${raws.beforeAnd}${raws.and}${raws.beforeExpression}${this.nodes.join('')}${this.raws.after}`; } } class MediaExpression { constructor(string) { const _ref3 = string.match(andRegExp) || [null, string], _ref4 = _slicedToArray(_ref3, 5), value = _ref4[1], _ref4$ = _ref4[2], after = _ref4$ === void 0 ? '' : _ref4$, _ref4$2 = _ref4[3], and = _ref4$2 === void 0 ? '' : _ref4$2, _ref4$3 = _ref4[4], afterAnd = _ref4$3 === void 0 ? '' : _ref4$3; const raws = { after, and, afterAnd }; Object.assign(this, { value, raws }); } clone(overrides) { const instance = new MediaExpression(String(this)); Object.assign(instance, overrides); return instance; } toString() { const raws = this.raws; return `${this.value}${raws.after}${raws.and}${raws.afterAnd}`; } } const modifierRE = '(not|only)'; const typeRE = '(all|print|screen|speech)'; const noExpressionRE = '([\\W\\w]*)'; const expressionRE = '([\\W\\w]+)'; const noSpaceRE = '(\\s*)'; const spaceRE = '(\\s+)'; const andRE = '(?:(\\s+)(and))'; const andRegExp = new RegExp(`^${expressionRE}(?:${andRE}${spaceRE})$`, 'i'); const spaceWrapRegExp = new RegExp(`^${noSpaceRE}${noExpressionRE}${noSpaceRE}$`); const mediaRegExp = new RegExp(`^(?:${modifierRE}${spaceRE})?(?:${typeRE}(?:${andRE}${spaceRE}${expressionRE})?|${expressionRE})$`, 'i'); var mediaASTFromString = (string => new MediaQueryList(string)); var getCustomMediaFromRoot = ((root, opts) => { // initialize custom selectors const customMedias = {}; // for each custom selector atrule that is a child of the css root root.nodes.slice().forEach(node => { if (isCustomMedia(node)) { // extract the name and selectors from the params of the custom selector const _node$params$match = node.params.match(customMediaParamsRegExp), _node$params$match2 = _slicedToArray(_node$params$match, 3), name = _node$params$match2[1], selectors = _node$params$match2[2]; // write the parsed selectors to the custom selector customMedias[name] = mediaASTFromString(selectors); // conditionally remove the custom selector atrule if (!Object(opts).preserve) { node.remove(); } } }); return customMedias; }); // match the custom selector name const customMediaNameRegExp = /^custom-media$/i; // match the custom selector params const customMediaParamsRegExp = /^(--[A-z][\w-]*)\s+([\W\w]+)\s*$/; // whether the atrule is a custom selector const isCustomMedia = node => node.type === 'atrule' && customMediaNameRegExp.test(node.name) && customMediaParamsRegExp.test(node.params); /* Get Custom Media from CSS File /* ========================================================================== */ function getCustomMediaFromCSSFile(_x) { return _getCustomMediaFromCSSFile.apply(this, arguments); } /* Get Custom Media from Object /* ========================================================================== */ function _getCustomMediaFromCSSFile() { _getCustomMediaFromCSSFile = _asyncToGenerator(function* (from) { const css = yield readFile(from); const root = postcss.parse(css, { from }); return getCustomMediaFromRoot(root, { preserve: true }); }); return _getCustomMediaFromCSSFile.apply(this, arguments); } function getCustomMediaFromObject(object) { const customMedia = Object.assign({}, Object(object).customMedia, Object(object)['custom-media']); for (const key in customMedia) { customMedia[key] = mediaASTFromString(customMedia[key]); } return customMedia; } /* Get Custom Media from JSON file /* ========================================================================== */ function getCustomMediaFromJSONFile(_x2) { return _getCustomMediaFromJSONFile.apply(this, arguments); } /* Get Custom Media from JS file /* ========================================================================== */ function _getCustomMediaFromJSONFile() { _getCustomMediaFromJSONFile = _asyncToGenerator(function* (from) { const object = yield readJSON(from); return getCustomMediaFromObject(object); }); return _getCustomMediaFromJSONFile.apply(this, arguments); } function getCustomMediaFromJSFile(_x3) { return _getCustomMediaFromJSFile.apply(this, arguments); } /* Get Custom Media from Sources /* ========================================================================== */ function _getCustomMediaFromJSFile() { _getCustomMediaFromJSFile = _asyncToGenerator(function* (from) { const object = yield import(from); return getCustomMediaFromObject(object); }); return _getCustomMediaFromJSFile.apply(this, arguments); } function getCustomMediaFromSources(sources) { return sources.map(source => { if (source instanceof Promise) { return source; } else if (source instanceof Function) { return source(); } // read the source as an object const opts = source === Object(source) ? source : { from: String(source) }; // skip objects with custom media if (Object(opts).customMedia || Object(opts)['custom-media']) { return opts; } // source pathname const from = path.resolve(String(opts.from || '')); // type of file being read from const type = (opts.type || path.extname(from).slice(1)).toLowerCase(); return { type, from }; }).reduce( /*#__PURE__*/ function () { var _ref = _asyncToGenerator(function* (customMedia, source) { const _ref2 = yield source, type = _ref2.type, from = _ref2.from; if (type === 'css' || type === 'pcss') { return Object.assign((yield customMedia), (yield getCustomMediaFromCSSFile(from))); } if (type === 'js') { return Object.assign((yield customMedia), (yield getCustomMediaFromJSFile(from))); } if (type === 'json') { return Object.assign((yield customMedia), (yield getCustomMediaFromJSONFile(from))); } return Object.assign((yield customMedia), getCustomMediaFromObject((yield source))); }); return function (_x4, _x5) { return _ref.apply(this, arguments); }; }(), {}); } /* Helper utilities /* ========================================================================== */ const readFile = from => new Promise((resolve, reject) => { fs.readFile(from, 'utf8', (error, result) => { if (error) { reject(error); } else { resolve(result); } }); }); const readJSON = /*#__PURE__*/ function () { var _ref3 = _asyncToGenerator(function* (from) { return JSON.parse((yield readFile(from))); }); return function readJSON(_x6) { return _ref3.apply(this, arguments); }; }(); // return transformed medias, replacing custom pseudo medias with custom medias function transformMediaList(mediaList, customMedias) { let index = mediaList.nodes.length - 1; while (index >= 0) { const transformedMedias = transformMedia(mediaList.nodes[index], customMedias); if (transformedMedias.length) { mediaList.nodes.splice(index, 1, ...transformedMedias); } --index; } return mediaList; } // return custom pseudo medias replaced with custom medias function transformMedia(media, customMedias) { const transpiledMedias = []; for (const index in media.nodes) { const _media$nodes$index = media.nodes[index], value = _media$nodes$index.value, nodes = _media$nodes$index.nodes; const key = value.replace(customPseudoRegExp, '$1'); if (key in customMedias) { var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = customMedias[key].nodes[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { const replacementMedia = _step.value; // use the first available modifier unless they cancel each other out const modifier = media.modifier !== replacementMedia.modifier ? media.modifier || replacementMedia.modifier : ''; const mediaClone = media.clone({ modifier, // conditionally use the raws from the first available modifier raws: !modifier || media.modifier ? _objectSpread({}, media.raws) : _objectSpread({}, replacementMedia.raws), type: media.type || replacementMedia.type }); // conditionally include more replacement raws when the type is present if (mediaClone.type === replacementMedia.type) { Object.assign(mediaClone.raws, { and: replacementMedia.raws.and, beforeAnd: replacementMedia.raws.beforeAnd, beforeExpression: replacementMedia.raws.beforeExpression }); } mediaClone.nodes.splice(index, 1, ...replacementMedia.clone().nodes.map(node => { // use raws and spacing from the current usage if (media.nodes[index].raws.and) { node.raws = _objectSpread({}, media.nodes[index].raws); } node.spaces = _objectSpread({}, media.nodes[index].spaces); return node; })); // remove the currently transformed key to prevent recursion const nextCustomMedia = getCustomMediasWithoutKey(customMedias, key); const retranspiledMedias = transformMedia(mediaClone, nextCustomMedia); if (retranspiledMedias.length) { transpiledMedias.push(...retranspiledMedias); } else { transpiledMedias.push(mediaClone); } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator.return != null) { _iterator.return(); } } finally { if (_didIteratorError) { throw _iteratorError; } } } return transpiledMedias; } else if (nodes && nodes.length) { transformMediaList(media.nodes[index], customMedias); } } return transpiledMedias; } const customPseudoRegExp = /\((--[A-z][\w-]*)\)/; const getCustomMediasWithoutKey = (customMedias, key) => { const nextCustomMedias = Object.assign({}, customMedias); delete nextCustomMedias[key]; return nextCustomMedias; }; var transformAtrules = ((root, customMedia, opts) => { root.walkAtRules(mediaAtRuleRegExp, atrule => { if (customPseudoRegExp$1.test(atrule.params)) { const mediaAST = mediaASTFromString(atrule.params); const params = String(transformMediaList(mediaAST, customMedia)); if (opts.preserve) { atrule.cloneBefore({ params }); } else { atrule.params = params; } } }); }); const mediaAtRuleRegExp = /^media$/i; const customPseudoRegExp$1 = /\(--[A-z][\w-]*\)/; /* Write Custom Media from CSS File /* ========================================================================== */ function writeCustomMediaToCssFile(_x, _x2) { return _writeCustomMediaToCssFile.apply(this, arguments); } /* Write Custom Media from JSON file /* ========================================================================== */ function _writeCustomMediaToCssFile() { _writeCustomMediaToCssFile = _asyncToGenerator(function* (to, customMedia) { const cssContent = Object.keys(customMedia).reduce((cssLines, name) => { cssLines.push(`@custom-media ${name} ${customMedia[name]};`); return cssLines; }, []).join('\n'); const css = `${cssContent}\n`; yield writeFile(to, css); }); return _writeCustomMediaToCssFile.apply(this, arguments); } function writeCustomMediaToJsonFile(_x3, _x4) { return _writeCustomMediaToJsonFile.apply(this, arguments); } /* Write Custom Media from Common JS file /* ========================================================================== */ function _writeCustomMediaToJsonFile() { _writeCustomMediaToJsonFile = _asyncToGenerator(function* (to, customMedia) { const jsonContent = JSON.stringify({ 'custom-media': customMedia }, null, ' '); const json = `${jsonContent}\n`; yield writeFile(to, json); }); return _writeCustomMediaToJsonFile.apply(this, arguments); } function writeCustomMediaToCjsFile(_x5, _x6) { return _writeCustomMediaToCjsFile.apply(this, arguments); } /* Write Custom Media from Module JS file /* ========================================================================== */ function _writeCustomMediaToCjsFile() { _writeCustomMediaToCjsFile = _asyncToGenerator(function* (to, customMedia) { const jsContents = Object.keys(customMedia).reduce((jsLines, name) => { jsLines.push(`\t\t'${escapeForJS(name)}': '${escapeForJS(customMedia[name])}'`); return jsLines; }, []).join(',\n'); const js = `module.exports = {\n\tcustomMedia: {\n${jsContents}\n\t}\n};\n`; yield writeFile(to, js); }); return _writeCustomMediaToCjsFile.apply(this, arguments); } function writeCustomMediaToMjsFile(_x7, _x8) { return _writeCustomMediaToMjsFile.apply(this, arguments); } /* Write Custom Media to Exports /* ========================================================================== */ function _writeCustomMediaToMjsFile() { _writeCustomMediaToMjsFile = _asyncToGenerator(function* (to, customMedia) { const mjsContents = Object.keys(customMedia).reduce((mjsLines, name) => { mjsLines.push(`\t'${escapeForJS(name)}': '${escapeForJS(customMedia[name])}'`); return mjsLines; }, []).join(',\n'); const mjs = `export const customMedia = {\n${mjsContents}\n};\n`; yield writeFile(to, mjs); }); return _writeCustomMediaToMjsFile.apply(this, arguments); } function writeCustomMediaToExports(customMedia, destinations) { return Promise.all(destinations.map( /*#__PURE__*/ function () { var _ref = _asyncToGenerator(function* (destination) { if (destination instanceof Function) { yield destination(defaultCustomMediaToJSON(customMedia)); } else { // read the destination as an object const opts = destination === Object(destination) ? destination : { to: String(destination) }; // transformer for custom media into a JSON-compatible object const toJSON = opts.toJSON || defaultCustomMediaToJSON; if ('customMedia' in opts) { // write directly to an object as customMedia opts.customMedia = toJSON(customMedia); } else if ('custom-media' in opts) { // write directly to an object as custom-media opts['custom-media'] = toJSON(customMedia); } else { // destination pathname const to = String(opts.to || ''); // type of file being written to const type = (opts.type || path.extname(to).slice(1)).toLowerCase(); // transformed custom media const customMediaJSON = toJSON(customMedia); if (type === 'css') { yield writeCustomMediaToCssFile(to, customMediaJSON); } if (type === 'js') { yield writeCustomMediaToCjsFile(to, customMediaJSON); } if (type === 'json') { yield writeCustomMediaToJsonFile(to, customMediaJSON); } if (type === 'mjs') { yield writeCustomMediaToMjsFile(to, customMediaJSON); } } } }); return function (_x9) { return _ref.apply(this, arguments); }; }())); } /* Helper utilities /* ========================================================================== */ const defaultCustomMediaToJSON = customMedia => { return Object.keys(customMedia).reduce((customMediaJSON, key) => { customMediaJSON[key] = String(customMedia[key]); return customMediaJSON; }, {}); }; const writeFile = (to, text) => new Promise((resolve, reject) => { fs.writeFile(to, text, error => { if (error) { reject(error); } else { resolve(); } }); }); const escapeForJS = string => string.replace(/\\([\s\S])|(')/g, '\\$1$2').replace(/\n/g, '\\n').replace(/\r/g, '\\r'); var index = postcss.plugin('postcss-custom-media', opts => { // whether to preserve custom media and at-rules using them const preserve = 'preserve' in Object(opts) ? Boolean(opts.preserve) : false; // sources to import custom media from const importFrom = [].concat(Object(opts).importFrom || []); // destinations to export custom media to const exportTo = [].concat(Object(opts).exportTo || []); // promise any custom media are imported const customMediaPromise = getCustomMediaFromSources(importFrom); return ( /*#__PURE__*/ function () { var _ref = _asyncToGenerator(function* (root) { const customMedia = Object.assign((yield customMediaPromise), getCustomMediaFromRoot(root, { preserve })); yield writeCustomMediaToExports(customMedia, exportTo); transformAtrules(root, customMedia, { preserve }); }); return function (_x) { return _ref.apply(this, arguments); }; }() ); }); export default index; //# sourceMappingURL=index.es.mjs.map