<commit_before>/* eslint-disable no-param-reassign */
/* @flow */

const stylis = require('stylis');
const { isValidElementType } = require('react-is');
const Module = require('./module');
const evaluate = require('./evaluate');
const slugify = require('../slugify');
const { units, unitless } = require('./units');

const hyphenate = s =>
  s.replace(/([A-Z])/g, g => `-${g[0].toLowerCase()}`).replace(/^ms-/, '-ms-');

const isPlainObject = o =>
  typeof o === 'object' && o != null && o.constructor.name === 'Object';

const toCSS = o =>
  Object.entries(o)
    .filter(
      ([, value]) =>
        // Ignore all falsy values except numbers
        typeof value === 'number' || value
    )
    .map(([key, value]) => {
      if (isPlainObject(value)) {
        return `${hyphenate(key)} { ${toCSS(value)} }`;
      }

      return `${hyphenate(key)}: ${
        /* $FlowFixMe */
        typeof value === 'number' && value !== 0 && !unitless[key]
          ? `${value}px`
          : value
      };`;
    })
    .join(' ');

const unitRegex = new RegExp(`^(${units.join('|')})(;|,|\n| |\\))`);

/* ::
type State = {|
  rules: {
    [className: string]: {
      cssText: string,
      loc: { line: number, column: number },
    },
  },
  index: number,
  dependencies: string[],
  file: {
    opts: {
      filename: string,
    },
  },
|};
*/

module.exports = function extract(
  babel /* : any */,
  options /* : { evaluate?: boolean } */ = {}
) {
  const { types: t } = babel;

  return {
    visitor: {
      Program: {
        enter(path /* : any */, state /* : State */) {
          // Collect all the style rules from the styles we encounter
          state.rules = {};
          state.index = 0;
          state.dependencies = [];

          // Invalidate cache for module evaluation
          Module.invalidate();
        },
        exit(path /* : any */, state /* : State */) {
          if (Object.keys(state.rules).length) {
            const mappings = [];

            let cssText = '';

            Object.keys(state.rules).forEach((className, index) => {
              mappings.push({
                generated: {
                  line: index + 1,
                  column: 0,
                },
                original: state.rules[className].loc,
                name: className,
              });

              // Run each rule through stylis to support nesting
              cssText += `${stylis(
                `.${className}`,
                state.rules[className].cssText
              )}\n`;
            });

            // Add the collected styles as a comment to the end of file
            path.addComment(
              'trailing',
              `\nCSS OUTPUT TEXT START\n${cssText}\nCSS OUTPUT TEXT END\n` +
                `\nCSS OUTPUT MAPPINGS:${JSON.stringify(
                  mappings
                )}\nCSS OUTPUT DEPENDENCIES:${JSON.stringify(
                  // Remove duplicate dependencies
                  state.dependencies.filter(
                    (d, i, self) => self.indexOf(d) === i
                  )
                )}\n`
            );
          }
        },
      },
      TaggedTemplateExpression(path /* : any */, state /* : State */) {
        const { quasi, tag } = path.node;

        let styled;

        if (
          t.isCallExpression(tag) &&
          t.isIdentifier(tag.callee) &&
          tag.arguments.length === 1 &&
          tag.callee.name === 'styled'
        ) {
          styled = { component: tag.arguments[0] };
        } else if (
          t.isMemberExpression(tag) &&
          t.isIdentifier(tag.object) &&
          t.isIdentifier(tag.property) &&
          tag.object.name === 'styled'
        ) {
          styled = { component: t.stringLiteral(tag.property.name) };
        }

        if (styled || (t.isIdentifier(tag) && tag.name === 'css')) {
          const interpolations = [];
<commit_msg>fix: clear modules cache after babel plugin is done<commit_after>/* eslint-disable no-param-reassign */
/* @flow */

const stylis = require('stylis');
const { isValidElementType } = require('react-is');
const Module = require('./module');
const evaluate = require('./evaluate');
const slugify = require('../slugify');
const { units, unitless } = require('./units');

const hyphenate = s =>
  s.replace(/([A-Z])/g, g => `-${g[0].toLowerCase()}`).replace(/^ms-/, '-ms-');

const isPlainObject = o =>
  typeof o === 'object' && o != null && o.constructor.name === 'Object';

const toCSS = o =>
  Object.entries(o)
    .filter(
      ([, value]) =>
        // Ignore all falsy values except numbers
        typeof value === 'number' || value
    )
    .map(([key, value]) => {
      if (isPlainObject(value)) {
        return `${hyphenate(key)} { ${toCSS(value)} }`;
      }

      return `${hyphenate(key)}: ${
        /* $FlowFixMe */
        typeof value === 'number' && value !== 0 && !unitless[key]
          ? `${value}px`
          : value
      };`;
    })
    .join(' ');

const unitRegex = new RegExp(`^(${units.join('|')})(;|,|\n| |\\))`);

/* ::
type State = {|
  rules: {
    [className: string]: {
      cssText: string,
      loc: { line: number, column: number },
    },
  },
  index: number,
  dependencies: string[],
  file: {
    opts: {
      filename: string,
    },
  },
|};
*/

module.exports = function extract(
  babel /* : any */,
  options /* : { evaluate?: boolean } */ = {}
) {
  const { types: t } = babel;

  return {
    visitor: {
      Program: {
        enter(path /* : any */, state /* : State */) {
          // Collect all the style rules from the styles we encounter
          state.rules = {};
          state.index = 0;
          state.dependencies = [];

          // Invalidate cache for module evaluation to get fresh modules
          Module.invalidate();
        },
        exit(path /* : any */, state /* : State */) {
          if (Object.keys(state.rules).length) {
            const mappings = [];

            let cssText = '';

            Object.keys(state.rules).forEach((className, index) => {
              mappings.push({
                generated: {
                  line: index + 1,
                  column: 0,
                },
                original: state.rules[className].loc,
                name: className,
              });

              // Run each rule through stylis to support nesting
              cssText += `${stylis(
                `.${className}`,
                state.rules[className].cssText
              )}\n`;
            });

            // Add the collected styles as a comment to the end of file
            path.addComment(
              'trailing',
              `\nCSS OUTPUT TEXT START\n${cssText}\nCSS OUTPUT TEXT END\n` +
                `\nCSS OUTPUT MAPPINGS:${JSON.stringify(
                  mappings
                )}\nCSS OUTPUT DEPENDENCIES:${JSON.stringify(
                  // Remove duplicate dependencies
                  state.dependencies.filter(
                    (d, i, self) => self.indexOf(d) === i
                  )
                )}\n`
            );
          }

          // Invalidate cache for module evaluation when we're done
          Module.invalidate();
        },
      },
      TaggedTemplateExpression(path /* : any */, state /* : State */) {
        const { quasi, tag } = path.node;

        let styled;

        if (
          t.isCallExpression(tag) &&
          t.isIdentifier(tag.callee) &&
          tag.arguments.length === 1 &&
          tag.callee.name === 'styled'
        ) {
          styled = { component: tag.arguments[0] };
        } else if (
          t.isMemberExpression(tag) &&
          t.isIdentifier(tag.object) &&
          t.isIdentifier(tag.property) &&
          tag.object.name === 'styled'
        ) {
          styled = { component: t.stringLiteral(tag.property.name) };
        }

        if (styled || (t.isIdentifier(tag) && tag.name === 'css')) {
          const interpolations = [];

{'fraction_non_alphanumeric': 0.1648420787718636, 'fraction_numerical': 0.0017616710708443439, 'mean_word_length': 1.6222368855163312, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1835808', 'n_tokens_mistral': 2343, 'n_tokens_neox': 2268, 'n_words': 519}