---
to: scripts/compileCoreDependencies.mjs
---
import css from 'css';
import { isEqual } from 'lodash-es';
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
import { resolve } from 'node:path';

const initialIndexContent = `
// This file is automatically generated, do not edit it directly.
/* eslint-disable import-x/export */`;

const cwd = process.cwd();
const dirents = readdirSync(resolve(cwd, '..'), { withFileTypes: true });

const directories = dirents
  .filter(dirent => dirent.isDirectory() && !cwd.endsWith(dirent.name))
  .map(dirent => dirent.name);

const packageJson = JSON.parse(readFileSync(resolve(cwd, 'package.json'), { encoding: 'utf8' }));
const tsconfig = JSON.parse(readFileSync(resolve(cwd, 'tsconfig.json'), { encoding: 'utf8' }));

packageJson.dependencies = {};

let cssContent = [];
let exportStatements = [];

for (const name of directories) {
  const packageName = `@<%= name %>/${name}`;

  if (!(packageName in packageJson.dependencies)) {
    packageJson.dependencies[packageName] = 'workspace:*';
  }

  if (!tsconfig.references.some(reference => reference.path.endsWith(name))) {
    tsconfig.references.push({ path: `../../<%= packagesDirName %>/${name}` });
  }

  exportStatements = [...exportStatements, `export * from '${packageName}';`];
  const dependencyCssPath = resolve(cwd, 'node_modules', packageName, 'dist', 'styles', 'index.css');

  if (existsSync(dependencyCssPath)) {
    cssContent = [...cssContent, readFileSync(dependencyCssPath, { encoding: 'utf8' })];
  }
}

const indexFilePath = resolve(cwd, 'src', 'index.ts');
const indexFileContent = [initialIndexContent, ...exportStatements].join('\n').trim() + '\n';
writeFileSync(indexFilePath, indexFileContent, { encoding: 'utf8' });

writeFileSync(resolve(cwd, 'tsconfig.json'), JSON.stringify(tsconfig, undefined, 2) + '\n', {
  encoding: 'utf8',
});

writeFileSync(resolve(cwd, 'package.json'), JSON.stringify(packageJson, undefined, 2) + '\n', {
  encoding: 'utf8',
});

const [firstCssContent, ...otherCssContent] = cssContent;
const parsed = css.parse(firstCssContent);
const mediaRules = {};

const setUniqueRules = (uniqueRules, newRules) => {
  for (const rule of newRules) {
    if (!uniqueRules.some(uniqueRule => isEqual(uniqueRule.selectors, rule.selectors))) {
      uniqueRules = [...uniqueRules, rule];
    }
  }

  return uniqueRules;
};

parsed.stylesheet.rules = otherCssContent.reduce((uniqueRules, entry, _index) => {
  const { rules: nodes = [] } = css.parse(entry).stylesheet ?? {};

  for (const node of nodes) {
    switch (node.type) {
      case 'media': {
        if (mediaRules[node.media]) {
          mediaRules[node.media].rules = setUniqueRules(mediaRules[node.media].rules, node.rules);
        } else {
          mediaRules[node.media] = node;
        }

        break;
      }

      case 'rule': {
        if (!uniqueRules.some(uniqueRule => isEqual(uniqueRule.selectors, node.selectors))) {
          uniqueRules = [...uniqueRules, node];
        }

        break;
      }

      default: {
        uniqueRules = [...uniqueRules, node];
      }
    }
  }

  return uniqueRules;
}, parsed.stylesheet.rules);

parsed.stylesheet.rules = [...parsed.stylesheet.rules, ...Object.values(mediaRules)];

const stylesPath = resolve(cwd, 'dist', 'styles');

if (!existsSync(stylesPath)) {
  mkdirSync(stylesPath, { recursive: true });
}

writeFileSync(resolve(stylesPath, 'index.css'), css.stringify(parsed) + '\n', {
  encoding: 'utf8',
});
