'use strict'; const path = require('path'); const fs = require('fs'); const css = require('css'); const camel = require('to-camel-case'); const autogenMessage = '//\n// This file has been auto-generated by the `npm run build-styles-prism` task\n//\n\n'; let directories = [ '../node_modules/prismjs/themes', '../node_modules/prism-themes/themes' ]; directories.map(directory => { fs.readdir(path.join(__dirname, directory), (err, files) => { files.forEach(file => { if (file.includes('.css') && !file.includes('.min')) { createJavascriptStyleSheet(file, directory); } }); updateDocs(files); }); }); function getSimpleFilename(filename) { let nameWithoutExtension = filename.split('.css')[0].split('prism-')[1]; if (filename === 'prism.css') nameWithoutExtension = 'prism'; if (filename === 'prism.min.css') nameWithoutExtension = 'prism.min'; return nameWithoutExtension; } let allFiles = []; let callCount = 0; function updateDocs(files) { allFiles = allFiles.concat(files); callCount += 1; if (callCount != directories.length) { return; } const onlyCSSFiles = allFiles.filter(file => file.includes('.css')); const onlyNonMinifiedCSS = onlyCSSFiles.filter( file => !file.includes('.min') ); const availableStyleNames = onlyNonMinifiedCSS.map(file => getSimpleFilename(file) ); const styles = availableStyleNames.map(name => `\n* ${camel(name)}`); const defaultExports = availableStyleNames.map( name => `export { default as ${camel(name)} } from './${name}';\n` ); const styleMD = `## Available \`stylesheet\` props ${styles.join('')}`; fs.writeFile( path.join(__dirname, '../AVAILABLE_STYLES_PRISM.MD'), styleMD, () => {} ); fs.writeFile( path.join(__dirname, '../src/styles/prism/index.js'), defaultExports.join(''), () => {} ); const demoStylesArray = `${autogenMessage}export default [${availableStyleNames .sort() .map(style => `\n '${style}'`)}\n];`; fs.writeFile( path.join(__dirname, '../demo/styles/prism.js'), demoStylesArray, err => { if (err) { throw err; } } ); } function createJavascriptStyleSheet(file, directory) { let fileWithoutCSS = getSimpleFilename(file); console.log(fileWithoutCSS); fs.readFile( path.join(__dirname, `${directory}/${file}`), 'utf-8', (err, data) => { const javacriptStylesheet = css .parse(data) .stylesheet.rules.reduce((sheet, rule) => { if (rule.type === 'rule') { const style = rule.selectors.reduce((selectors, selector) => { const selectorObject = rule.declarations.reduce( (declarations, declaration) => { if ( declaration.type === 'declaration' && declaration.property ) { const camelCaseDeclarationProp = camel( declaration.property ); const key = camelCaseDeclarationProp.includes('moz') || camelCaseDeclarationProp.includes('webkit') || (camelCaseDeclarationProp[0] === 'o' && !camelCaseDeclarationProp.includes('overflow')) ? `${camelCaseDeclarationProp .substring(0, 1) .toUpperCase()}${camelCaseDeclarationProp.substring( 1 )}` : camelCaseDeclarationProp; declarations[key] = declaration.value; } return declarations; }, {} ); if (selector.substring(0, 6) === '.token') { selector = selector.substring(7); // Regex to fix Prism theme selectors // - Remove further `.token` classes // - Remove the space (descendant combinator) // to allow for styling multiple classes // Ref: https://github.com/react-syntax-highlighter/react-syntax-highlighter/pull/305 selector = selector.replace(/(?<=\w) (\.token)?(?=\.)/g, ''); } selectors[selector] = selectorObject; return selectors; }, {}); sheet = Object.keys(style).reduce((stylesheet, selector) => { if (stylesheet[selector]) { stylesheet[selector] = Object.assign( {}, stylesheet[selector], style[selector] ); } else { stylesheet[selector] = style[selector]; } return stylesheet; }, sheet); } return sheet; }, {}); fs.writeFile( path.join(__dirname, `../src/styles/prism/${fileWithoutCSS}.js`), `export default ${JSON.stringify(javacriptStylesheet, null, 4)}`, () => {} ); } ); }