1"use strict"; 2 3Object.defineProperty(exports, "__esModule", { 4 value: true 5}); 6exports.getPostcssConfigHash = getPostcssConfigHash; 7exports.pluginFactory = pluginFactory; 8exports.resolvePostcssConfig = resolvePostcssConfig; 9exports.transformPostCssModule = transformPostCssModule; 10function _jsonFile() { 11 const data = _interopRequireDefault(require("@expo/json-file")); 12 _jsonFile = function () { 13 return data; 14 }; 15 return data; 16} 17function _fs() { 18 const data = _interopRequireDefault(require("fs")); 19 _fs = function () { 20 return data; 21 }; 22 return data; 23} 24function _path() { 25 const data = _interopRequireDefault(require("path")); 26 _path = function () { 27 return data; 28 }; 29 return data; 30} 31function _resolveFrom() { 32 const data = _interopRequireDefault(require("resolve-from")); 33 _resolveFrom = function () { 34 return data; 35 }; 36 return data; 37} 38function _require() { 39 const data = require("./utils/require"); 40 _require = function () { 41 return data; 42 }; 43 return data; 44} 45function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 46function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } 47function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } 48const CONFIG_FILE_NAME = 'postcss.config'; 49const debug = require('debug')('expo:metro:transformer:postcss'); 50async function transformPostCssModule(projectRoot, { 51 src, 52 filename 53}) { 54 const inputConfig = resolvePostcssConfig(projectRoot); 55 if (!inputConfig) { 56 return src; 57 } 58 return await processWithPostcssInputConfigAsync(projectRoot, { 59 inputConfig, 60 src, 61 filename 62 }); 63} 64async function processWithPostcssInputConfigAsync(projectRoot, { 65 src, 66 filename, 67 inputConfig 68}) { 69 const { 70 plugins, 71 processOptions 72 } = await parsePostcssConfigAsync(projectRoot, { 73 config: inputConfig, 74 resourcePath: filename 75 }); 76 debug('options:', processOptions); 77 debug('plugins:', plugins); 78 79 // TODO: Surely this can be cached... 80 const postcss = await Promise.resolve().then(() => _interopRequireWildcard(require('postcss'))); 81 const processor = postcss.default(plugins); 82 const { 83 content 84 } = await processor.process(src, processOptions); 85 return content; 86} 87async function parsePostcssConfigAsync(projectRoot, { 88 resourcePath: file, 89 config: { 90 plugins: inputPlugins, 91 map, 92 parser, 93 stringifier, 94 syntax, 95 ...config 96 } = {} 97}) { 98 const factory = pluginFactory(); 99 factory(inputPlugins); 100 // delete config.plugins; 101 102 const plugins = [...factory()].map(item => { 103 const [plugin, options] = item; 104 if (typeof plugin === 'string') { 105 return loadPlugin(projectRoot, plugin, options, file); 106 } 107 return plugin; 108 }); 109 if (config.from) { 110 config.from = _path().default.resolve(projectRoot, config.from); 111 } 112 if (config.to) { 113 config.to = _path().default.resolve(projectRoot, config.to); 114 } 115 const processOptions = { 116 from: file, 117 to: file, 118 map: false 119 }; 120 if (typeof parser === 'string') { 121 try { 122 var _resolveFrom$silent; 123 processOptions.parser = await (0, _require().tryRequireThenImport)((_resolveFrom$silent = _resolveFrom().default.silent(projectRoot, parser)) !== null && _resolveFrom$silent !== void 0 ? _resolveFrom$silent : parser); 124 } catch (error) { 125 if (error instanceof Error) { 126 throw new Error(`Loading PostCSS "${parser}" parser failed: ${error.message}\n\n(@${file})`); 127 } 128 throw error; 129 } 130 } 131 if (typeof stringifier === 'string') { 132 try { 133 var _resolveFrom$silent2; 134 processOptions.stringifier = await (0, _require().tryRequireThenImport)((_resolveFrom$silent2 = _resolveFrom().default.silent(projectRoot, stringifier)) !== null && _resolveFrom$silent2 !== void 0 ? _resolveFrom$silent2 : stringifier); 135 } catch (error) { 136 if (error instanceof Error) { 137 throw new Error(`Loading PostCSS "${stringifier}" stringifier failed: ${error.message}\n\n(@${file})`); 138 } 139 throw error; 140 } 141 } 142 if (typeof syntax === 'string') { 143 try { 144 var _resolveFrom$silent3; 145 processOptions.syntax = await (0, _require().tryRequireThenImport)((_resolveFrom$silent3 = _resolveFrom().default.silent(projectRoot, syntax)) !== null && _resolveFrom$silent3 !== void 0 ? _resolveFrom$silent3 : syntax); 146 } catch (error) { 147 throw new Error(`Loading PostCSS "${syntax}" syntax failed: ${error.message}\n\n(@${file})`); 148 } 149 } 150 if (map === true) { 151 // https://github.com/postcss/postcss/blob/master/docs/source-maps.md 152 processOptions.map = { 153 inline: true 154 }; 155 } 156 return { 157 plugins, 158 processOptions 159 }; 160} 161function loadPlugin(projectRoot, plugin, options, file) { 162 try { 163 debug('load plugin:', plugin); 164 165 // e.g. `tailwindcss` 166 let loadedPlugin = require((0, _resolveFrom().default)(projectRoot, plugin)); 167 if (loadedPlugin.default) { 168 loadedPlugin = loadedPlugin.default; 169 } 170 if (!options || !Object.keys(options).length) { 171 return loadedPlugin; 172 } 173 return loadedPlugin(options); 174 } catch (error) { 175 if (error instanceof Error) { 176 throw new Error(`Loading PostCSS "${plugin}" plugin failed: ${error.message}\n\n(@${file})`); 177 } 178 throw error; 179 } 180} 181function pluginFactory() { 182 const listOfPlugins = new Map(); 183 return plugins => { 184 if (typeof plugins === 'undefined') { 185 return listOfPlugins; 186 } 187 if (Array.isArray(plugins)) { 188 for (const plugin of plugins) { 189 if (Array.isArray(plugin)) { 190 const [name, options] = plugin; 191 if (typeof name !== 'string') { 192 throw new Error(`PostCSS plugin must be a string, but "${name}" was found. Please check your configuration.`); 193 } 194 listOfPlugins.set(name, options); 195 } else if (plugin && typeof plugin === 'function') { 196 listOfPlugins.set(plugin, undefined); 197 } else if (plugin && Object.keys(plugin).length === 1 && (typeof plugin[Object.keys(plugin)[0]] === 'object' || typeof plugin[Object.keys(plugin)[0]] === 'boolean') && plugin[Object.keys(plugin)[0]] !== null) { 198 const [name] = Object.keys(plugin); 199 const options = plugin[name]; 200 if (options === false) { 201 listOfPlugins.delete(name); 202 } else { 203 listOfPlugins.set(name, options); 204 } 205 } else if (plugin) { 206 listOfPlugins.set(plugin, undefined); 207 } 208 } 209 } else { 210 const objectPlugins = Object.entries(plugins); 211 for (const [name, options] of objectPlugins) { 212 if (options === false) { 213 listOfPlugins.delete(name); 214 } else { 215 listOfPlugins.set(name, options); 216 } 217 } 218 } 219 return listOfPlugins; 220 }; 221} 222function resolvePostcssConfig(projectRoot) { 223 // TODO: Maybe support platform-specific postcss config files in the future. 224 const jsConfigPath = _path().default.join(projectRoot, CONFIG_FILE_NAME + '.js'); 225 if (_fs().default.existsSync(jsConfigPath)) { 226 debug('load file:', jsConfigPath); 227 return (0, _require().requireUncachedFile)(jsConfigPath); 228 } 229 const jsonConfigPath = _path().default.join(projectRoot, CONFIG_FILE_NAME + '.json'); 230 if (_fs().default.existsSync(jsonConfigPath)) { 231 debug('load file:', jsonConfigPath); 232 return _jsonFile().default.read(jsonConfigPath, { 233 json5: true 234 }); 235 } 236 return null; 237} 238function getPostcssConfigHash(projectRoot) { 239 // TODO: Maybe recurse plugins and add versions to the hash in the future. 240 const { 241 stableHash 242 } = require('metro-cache'); 243 const jsConfigPath = _path().default.join(projectRoot, CONFIG_FILE_NAME + '.js'); 244 if (_fs().default.existsSync(jsConfigPath)) { 245 return stableHash(_fs().default.readFileSync(jsConfigPath, 'utf8')).toString('hex'); 246 } 247 const jsonConfigPath = _path().default.join(projectRoot, CONFIG_FILE_NAME + '.json'); 248 if (_fs().default.existsSync(jsonConfigPath)) { 249 return stableHash(_fs().default.readFileSync(jsonConfigPath, 'utf8')).toString('hex'); 250 } 251 return null; 252} 253//# sourceMappingURL=postcss.js.map