|
import { promises as fs } from 'fs'; |
|
import { extname, join, resolve } from 'path'; |
|
|
|
const DEFAULT_ASSETS_DIR = 'assets'; |
|
const CSS_EXTENSION = '.css'; |
|
const DISCLAIMER = '/* CAUTION: Source document was rebased from 10px to 16px rem root */'; |
|
const DRY_RUN = process.env.DRY_RUN === 'true'; |
|
|
|
let processedFiles = 0; |
|
let skippedFiles = 0; |
|
|
|
const convertRem = (value) => { |
|
const converted = (parseFloat(value) * 10) / 16; |
|
return converted.toString().replace(/\.?0+$/, '') + 'rem'; |
|
}; |
|
|
|
const processCssContent = (css) => { |
|
if (css.startsWith(DISCLAIMER)) return null; |
|
|
|
const pattern = /(\d+(?:\.\d+)?)rem/g; |
|
const modifiedCss = css.replace(pattern, (_, value) => convertRem(value)); |
|
return modifiedCss === css ? null : DISCLAIMER + '\n\n' + modifiedCss; |
|
}; |
|
|
|
const processCssFile = async (filePath) => { |
|
try { |
|
const css = await fs.readFile(filePath, 'utf8'); |
|
const modifiedCss = processCssContent(css); |
|
if (modifiedCss === null) { |
|
console.log(`No changes needed for ${filePath} (already contains disclaimer or no rem units)`); |
|
skippedFiles++; |
|
return; |
|
} |
|
|
|
if (DRY_RUN) { |
|
console.log(`Would process ${filePath}`); |
|
processedFiles++; |
|
return; |
|
} |
|
|
|
await fs.writeFile(filePath, modifiedCss, 'utf8'); |
|
console.log(`Processed CSS saved to ${filePath}`); |
|
processedFiles++; |
|
} catch (err) { |
|
console.error(`Error processing file ${filePath}: ${err.message}`); |
|
} |
|
}; |
|
|
|
const shouldProcessFile = (fileName) => |
|
extname(fileName).toLowerCase() === CSS_EXTENSION && !fileName.startsWith('mx-'); |
|
|
|
const processDirectory = async (directory) => { |
|
try { |
|
const entries = await fs.readdir(directory, { withFileTypes: true }); |
|
await Promise.all( |
|
entries.map(async (entry) => { |
|
const fullPath = join(directory, entry.name); |
|
if (entry.isDirectory()) { |
|
await processDirectory(fullPath); |
|
} else if (entry.isFile() && shouldProcessFile(entry.name)) { |
|
await processCssFile(fullPath); |
|
} |
|
}), |
|
); |
|
} catch (err) { |
|
console.error(`Error processing directory ${directory}:`, err); |
|
} |
|
}; |
|
|
|
const printHelp = () => { |
|
console.log('Usage: node script.js [directory]'); |
|
console.log('If no directory is specified, "assets" in the current working directory will be used.'); |
|
console.log('Set DRY_RUN=true environment variable for a dry run.'); |
|
console.log('Options:'); |
|
console.log(' -h, --help Show this help message'); |
|
}; |
|
|
|
const main = async () => { |
|
const args = process.argv.slice(2); |
|
|
|
if (args.includes('-h') || args.includes('--help')) { |
|
printHelp(); |
|
process.exit(0); |
|
} |
|
|
|
const assetsDir = resolve(process.cwd(), args[0] || DEFAULT_ASSETS_DIR); |
|
|
|
try { |
|
await fs.access(assetsDir); |
|
await processDirectory(assetsDir); |
|
console.log(`\nSummary:\nProcessed files: ${processedFiles}\nSkipped files: ${skippedFiles}`); |
|
} catch (err) { |
|
console.error(`Error: ${err.message}`); |
|
process.exit(1); |
|
} |
|
}; |
|
|
|
main(); |