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 }; } 46/** 47 * Copyright © 2023 650 Industries. 48 * Copyright JS Foundation and other contributors 49 * 50 * https://github.com/webpack-contrib/postcss-loader/ 51 */ 52 53const CONFIG_FILE_NAME = 'postcss.config'; 54const debug = require('debug')('expo:metro:transformer:postcss'); 55async function transformPostCssModule(projectRoot, { 56 src, 57 filename 58}) { 59 const inputConfig = resolvePostcssConfig(projectRoot); 60 if (!inputConfig) { 61 return src; 62 } 63 return await processWithPostcssInputConfigAsync(projectRoot, { 64 inputConfig, 65 src, 66 filename 67 }); 68} 69async function processWithPostcssInputConfigAsync(projectRoot, { 70 src, 71 filename, 72 inputConfig 73}) { 74 const { 75 plugins, 76 processOptions 77 } = await parsePostcssConfigAsync(projectRoot, { 78 config: inputConfig, 79 resourcePath: filename 80 }); 81 debug('options:', processOptions); 82 debug('plugins:', plugins); 83 84 // TODO: Surely this can be cached... 85 const postcss = require('postcss'); 86 const processor = postcss.default(plugins); 87 const { 88 content 89 } = await processor.process(src, processOptions); 90 return content; 91} 92async function parsePostcssConfigAsync(projectRoot, { 93 resourcePath: file, 94 config: { 95 plugins: inputPlugins, 96 map, 97 parser, 98 stringifier, 99 syntax, 100 ...config 101 } = {} 102}) { 103 const factory = pluginFactory(); 104 factory(inputPlugins); 105 // delete config.plugins; 106 107 const plugins = [...factory()].map(item => { 108 const [plugin, options] = item; 109 if (typeof plugin === 'string') { 110 return loadPlugin(projectRoot, plugin, options, file); 111 } 112 return plugin; 113 }); 114 if (config.from) { 115 config.from = _path().default.resolve(projectRoot, config.from); 116 } 117 if (config.to) { 118 config.to = _path().default.resolve(projectRoot, config.to); 119 } 120 const processOptions = { 121 from: file, 122 to: file, 123 map: false 124 }; 125 if (typeof parser === 'string') { 126 try { 127 var _resolveFrom$silent; 128 processOptions.parser = await (0, _require().tryRequireThenImport)((_resolveFrom$silent = _resolveFrom().default.silent(projectRoot, parser)) !== null && _resolveFrom$silent !== void 0 ? _resolveFrom$silent : parser); 129 } catch (error) { 130 if (error instanceof Error) { 131 throw new Error(`Loading PostCSS "${parser}" parser failed: ${error.message}\n\n(@${file})`); 132 } 133 throw error; 134 } 135 } 136 if (typeof stringifier === 'string') { 137 try { 138 var _resolveFrom$silent2; 139 processOptions.stringifier = await (0, _require().tryRequireThenImport)((_resolveFrom$silent2 = _resolveFrom().default.silent(projectRoot, stringifier)) !== null && _resolveFrom$silent2 !== void 0 ? _resolveFrom$silent2 : stringifier); 140 } catch (error) { 141 if (error instanceof Error) { 142 throw new Error(`Loading PostCSS "${stringifier}" stringifier failed: ${error.message}\n\n(@${file})`); 143 } 144 throw error; 145 } 146 } 147 if (typeof syntax === 'string') { 148 try { 149 var _resolveFrom$silent3; 150 processOptions.syntax = await (0, _require().tryRequireThenImport)((_resolveFrom$silent3 = _resolveFrom().default.silent(projectRoot, syntax)) !== null && _resolveFrom$silent3 !== void 0 ? _resolveFrom$silent3 : syntax); 151 } catch (error) { 152 throw new Error(`Loading PostCSS "${syntax}" syntax failed: ${error.message}\n\n(@${file})`); 153 } 154 } 155 if (map === true) { 156 // https://github.com/postcss/postcss/blob/master/docs/source-maps.md 157 processOptions.map = { 158 inline: true 159 }; 160 } 161 return { 162 plugins, 163 processOptions 164 }; 165} 166function loadPlugin(projectRoot, plugin, options, file) { 167 try { 168 debug('load plugin:', plugin); 169 170 // e.g. `tailwindcss` 171 let loadedPlugin = require((0, _resolveFrom().default)(projectRoot, plugin)); 172 if (loadedPlugin.default) { 173 loadedPlugin = loadedPlugin.default; 174 } 175 if (!options || !Object.keys(options).length) { 176 return loadedPlugin; 177 } 178 return loadedPlugin(options); 179 } catch (error) { 180 if (error instanceof Error) { 181 throw new Error(`Loading PostCSS "${plugin}" plugin failed: ${error.message}\n\n(@${file})`); 182 } 183 throw error; 184 } 185} 186function pluginFactory() { 187 const listOfPlugins = new Map(); 188 return plugins => { 189 if (typeof plugins === 'undefined') { 190 return listOfPlugins; 191 } 192 if (Array.isArray(plugins)) { 193 for (const plugin of plugins) { 194 if (Array.isArray(plugin)) { 195 const [name, options] = plugin; 196 if (typeof name !== 'string') { 197 throw new Error(`PostCSS plugin must be a string, but "${name}" was found. Please check your configuration.`); 198 } 199 listOfPlugins.set(name, options); 200 } else if (plugin && typeof plugin === 'function') { 201 listOfPlugins.set(plugin, undefined); 202 } 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) { 203 const [name] = Object.keys(plugin); 204 const options = plugin[name]; 205 if (options === false) { 206 listOfPlugins.delete(name); 207 } else { 208 listOfPlugins.set(name, options); 209 } 210 } else if (plugin) { 211 listOfPlugins.set(plugin, undefined); 212 } 213 } 214 } else { 215 const objectPlugins = Object.entries(plugins); 216 for (const [name, options] of objectPlugins) { 217 if (options === false) { 218 listOfPlugins.delete(name); 219 } else { 220 listOfPlugins.set(name, options); 221 } 222 } 223 } 224 return listOfPlugins; 225 }; 226} 227function resolvePostcssConfig(projectRoot) { 228 // TODO: Maybe support platform-specific postcss config files in the future. 229 const jsConfigPath = _path().default.join(projectRoot, CONFIG_FILE_NAME + '.js'); 230 if (_fs().default.existsSync(jsConfigPath)) { 231 debug('load file:', jsConfigPath); 232 return (0, _require().requireUncachedFile)(jsConfigPath); 233 } 234 const jsonConfigPath = _path().default.join(projectRoot, CONFIG_FILE_NAME + '.json'); 235 if (_fs().default.existsSync(jsonConfigPath)) { 236 debug('load file:', jsonConfigPath); 237 return _jsonFile().default.read(jsonConfigPath, { 238 json5: true 239 }); 240 } 241 return null; 242} 243function getPostcssConfigHash(projectRoot) { 244 // TODO: Maybe recurse plugins and add versions to the hash in the future. 245 const { 246 stableHash 247 } = require('metro-cache'); 248 const jsConfigPath = _path().default.join(projectRoot, CONFIG_FILE_NAME + '.js'); 249 if (_fs().default.existsSync(jsConfigPath)) { 250 return stableHash(_fs().default.readFileSync(jsConfigPath, 'utf8')).toString('hex'); 251 } 252 const jsonConfigPath = _path().default.join(projectRoot, CONFIG_FILE_NAME + '.json'); 253 if (_fs().default.existsSync(jsonConfigPath)) { 254 return stableHash(_fs().default.readFileSync(jsonConfigPath, 'utf8')).toString('hex'); 255 } 256 return null; 257} 258//# sourceMappingURL=postcss.js.map