ember-codemod-css-modules
Version:
Codemod to replace ember-component-css with ember-css-modules (compatible with embroider-css-modules)
69 lines (68 loc) • 2.36 kB
JavaScript
import { readFileSync, writeFileSync } from 'node:fs';
import { moveFiles, } from '@codemod-utils/files';
import postcss from 'postcss';
import syntax from 'postcss-scss';
const localSelector = ':local(.component)';
const transformPlugin = {
postcssPlugin: 'Transform Plugin',
Once(root) {
let localRule;
let nodesBeforeLocal = [];
root.walk(node => {
if (node.type === 'rule' && node.selector === '&') {
localRule = node;
}
if (!localRule) {
nodesBeforeLocal.push(node);
}
});
if (localRule) {
localRule.selector = localSelector;
}
else {
root.append({ selector: localSelector });
localRule = root.nodes[root.nodes.length - 1];
nodesBeforeLocal = [];
}
root.walk(node => {
if (node === localRule)
return;
if (node.parent === localRule)
return;
if (node.parent?.type !== 'root')
return;
if (nodesBeforeLocal.includes(node))
return;
if (node.type === 'atrule' && node.name !== 'media')
return;
if (node.type === 'decl')
return;
if (node.type === 'comment' && node.text.startsWith('stylelint'))
return;
if (!node.raws.before)
node.raws.before = '\n';
localRule?.append(node);
});
},
};
const plugins = [transformPlugin];
const processor = postcss(plugins);
function moveComponentCssStylesheets(context, options) {
const pathMapping = new Map(context.map(entry => [entry.oldPath, entry.newPath]));
moveFiles(pathMapping, options);
}
async function transformCssSyntax(filePath) {
const contents = readFileSync(filePath).toString();
try {
const result = await processor.process(contents, { from: '', syntax });
writeFileSync(filePath, result.css);
}
catch (err) {
console.error(`PostCSS error in ${filePath}`);
throw err;
}
}
export async function moveStylesheets(context, options) {
moveComponentCssStylesheets(context, options);
await Promise.all(context.map(entry => transformCssSyntax(`${options.projectRoot}/${entry.newPath}`)));
}