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