19b2597baSEvan Baconimport { wrapDevelopmentCSS } from './css';
29b2597baSEvan Bacon
39b2597baSEvan Baconconst RNW_CSS_CLASS_ID = '_';
49b2597baSEvan Bacon
59b2597baSEvan Baconexport async function transformCssModuleWeb(props: {
69b2597baSEvan Bacon  filename: string;
79b2597baSEvan Bacon  src: string;
89b2597baSEvan Bacon  options: { projectRoot: string; minify: boolean; dev: boolean; sourceMap: boolean };
99b2597baSEvan Bacon}) {
10*1a3a1db5SEvan Bacon  const { transform } = require('lightningcss') as typeof import('lightningcss');
119b2597baSEvan Bacon
129b2597baSEvan Bacon  // TODO: Add bundling to resolve imports
139b2597baSEvan Bacon  // https://lightningcss.dev/bundling.html#bundling-order
149b2597baSEvan Bacon
159b2597baSEvan Bacon  const cssResults = transform({
169b2597baSEvan Bacon    filename: props.filename,
179b2597baSEvan Bacon    code: Buffer.from(props.src),
189b2597baSEvan Bacon    sourceMap: props.options.sourceMap,
199b2597baSEvan Bacon    cssModules: {
209b2597baSEvan Bacon      // Prevent renaming CSS variables to ensure
219b2597baSEvan Bacon      // variables created in global files are available.
229b2597baSEvan Bacon      dashedIdents: false,
239b2597baSEvan Bacon    },
249b2597baSEvan Bacon    // cssModules: true,
259b2597baSEvan Bacon    projectRoot: props.options.projectRoot,
269b2597baSEvan Bacon    minify: props.options.minify,
279b2597baSEvan Bacon  });
289b2597baSEvan Bacon  const codeAsString = cssResults.code.toString();
299b2597baSEvan Bacon
30e62df662SEvan Bacon  const { styles, reactNativeWeb, variables } = convertLightningCssToReactNativeWebStyleSheet(
31e62df662SEvan Bacon    cssResults.exports!
32e62df662SEvan Bacon  );
339b2597baSEvan Bacon
34e62df662SEvan Bacon  let outputModule = `module.exports=Object.assign(${JSON.stringify(
35e62df662SEvan Bacon    styles
36201c72c1SEvan Bacon  )},{unstable_styles:${JSON.stringify(reactNativeWeb)}},${JSON.stringify(variables)});`;
379b2597baSEvan Bacon
389b2597baSEvan Bacon  if (props.options.dev) {
399b2597baSEvan Bacon    const runtimeCss = wrapDevelopmentCSS({
409b2597baSEvan Bacon      ...props,
419b2597baSEvan Bacon      src: codeAsString,
429b2597baSEvan Bacon    });
439b2597baSEvan Bacon
449b2597baSEvan Bacon    outputModule += '\n' + runtimeCss;
459b2597baSEvan Bacon  }
469b2597baSEvan Bacon
479b2597baSEvan Bacon  return {
489b2597baSEvan Bacon    output: outputModule,
499b2597baSEvan Bacon    css: cssResults.code,
509b2597baSEvan Bacon    map: cssResults.map,
519b2597baSEvan Bacon  };
529b2597baSEvan Bacon}
539b2597baSEvan Bacon
549b2597baSEvan Baconexport function convertLightningCssToReactNativeWebStyleSheet(
559b2597baSEvan Bacon  input: import('lightningcss').CSSModuleExports
569b2597baSEvan Bacon) {
57e62df662SEvan Bacon  const styles: Record<string, string> = {};
58e62df662SEvan Bacon  const reactNativeWeb: Record<string, any> = {};
599b2597baSEvan Bacon  const variables: Record<string, string> = {};
609b2597baSEvan Bacon  // e.g. { container: { name: 'ahs8IW_container', composes: [], isReferenced: false }, }
619b2597baSEvan Bacon  Object.entries(input).map(([key, value]) => {
629b2597baSEvan Bacon    // order matters here
639b2597baSEvan Bacon    let className = value.name;
649b2597baSEvan Bacon
659b2597baSEvan Bacon    if (value.composes.length) {
669b2597baSEvan Bacon      className += ' ' + value.composes.map((value) => value.name).join(' ');
679b2597baSEvan Bacon    }
689b2597baSEvan Bacon
699b2597baSEvan Bacon    // CSS Variables will be `{string: string}`
709b2597baSEvan Bacon    if (key.startsWith('--')) {
719b2597baSEvan Bacon      variables[key] = className;
729b2597baSEvan Bacon    }
739b2597baSEvan Bacon
74e62df662SEvan Bacon    styles[key] = className;
75e62df662SEvan Bacon    reactNativeWeb[key] = { $$css: true, [RNW_CSS_CLASS_ID]: className };
769b2597baSEvan Bacon    return {
779b2597baSEvan Bacon      [key]: { $$css: true, [RNW_CSS_CLASS_ID]: className },
789b2597baSEvan Bacon    };
799b2597baSEvan Bacon  });
809b2597baSEvan Bacon
81e62df662SEvan Bacon  return { styles, reactNativeWeb, variables };
829b2597baSEvan Bacon}
839b2597baSEvan Bacon
849b2597baSEvan Baconexport function matchCssModule(filePath: string): boolean {
857cebda5aSEvan Bacon  return !!/\.module(\.(native|ios|android|web))?\.(css|s[ac]ss)$/.test(filePath);
869b2597baSEvan Bacon}
87