postcss-modules
Version:
PostCSS plugin to use CSS Modules everywhere
160 lines (123 loc) • 5.19 kB
JavaScript
;
var _postcss = _interopRequireDefault(require("postcss"));
var _lodash = _interopRequireDefault(require("lodash.camelcase"));
var _genericNames = _interopRequireDefault(require("generic-names"));
var _unquote = _interopRequireDefault(require("./unquote"));
var _parser = _interopRequireDefault(require("./css-loader-core/parser"));
var _loader = _interopRequireDefault(require("./css-loader-core/loader"));
var _generateScopedName = _interopRequireDefault(require("./generateScopedName"));
var _saveJSON = _interopRequireDefault(require("./saveJSON"));
var _behaviours = require("./behaviours");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
const PLUGIN_NAME = "postcss-modules";
function getDefaultScopeBehaviour(opts) {
if (opts.scopeBehaviour && (0, _behaviours.isValidBehaviour)(opts.scopeBehaviour)) {
return opts.scopeBehaviour;
}
return _behaviours.behaviours.LOCAL;
}
function getScopedNameGenerator(opts) {
const scopedNameGenerator = opts.generateScopedName || _generateScopedName.default;
if (typeof scopedNameGenerator === "function") return scopedNameGenerator;
return (0, _genericNames.default)(scopedNameGenerator, {
context: process.cwd(),
hashPrefix: opts.hashPrefix
});
}
function getLoader(opts, plugins) {
const root = typeof opts.root === "undefined" ? "/" : opts.root;
return typeof opts.Loader === "function" ? new opts.Loader(root, plugins) : new _loader.default(root, plugins);
}
function isGlobalModule(globalModules, inputFile) {
return globalModules.some(regex => inputFile.match(regex));
}
function getDefaultPluginsList(opts, inputFile) {
const globalModulesList = opts.globalModulePaths || null;
const exportGlobals = opts.exportGlobals || false;
const defaultBehaviour = getDefaultScopeBehaviour(opts);
const generateScopedName = getScopedNameGenerator(opts);
if (globalModulesList && isGlobalModule(globalModulesList, inputFile)) {
return (0, _behaviours.getDefaultPlugins)({
behaviour: _behaviours.behaviours.GLOBAL,
generateScopedName,
exportGlobals
});
}
return (0, _behaviours.getDefaultPlugins)({
behaviour: defaultBehaviour,
generateScopedName,
exportGlobals
});
}
function isOurPlugin(plugin) {
return plugin.postcssPlugin === PLUGIN_NAME;
}
function dashesCamelCase(string) {
return string.replace(/-+(\w)/g, (_, firstLetter) => firstLetter.toUpperCase());
}
module.exports = (opts = {}) => {
return {
postcssPlugin: PLUGIN_NAME,
async OnceExit(css, {
result
}) {
const getJSON = opts.getJSON || _saveJSON.default;
const inputFile = css.source.input.file;
const pluginList = getDefaultPluginsList(opts, inputFile);
const resultPluginIndex = result.processor.plugins.findIndex(plugin => isOurPlugin(plugin));
if (resultPluginIndex === -1) {
throw new Error('Plugin missing from options.');
}
const earlierPlugins = result.processor.plugins.slice(0, resultPluginIndex);
const loaderPlugins = [...earlierPlugins, ...pluginList];
const loader = getLoader(opts, loaderPlugins);
const fetcher = (file, relativeTo, depTrace) => {
const unquoteFile = (0, _unquote.default)(file);
const resolvedResult = typeof opts.resolve === 'function' && opts.resolve(unquoteFile);
const resolvedFile = resolvedResult instanceof Promise ? resolvedResult : Promise.resolve(resolvedResult);
return resolvedFile.then(f => {
return loader.fetch.call(loader, `"${f || unquoteFile}"`, relativeTo, depTrace);
});
};
const parser = new _parser.default(fetcher);
await (0, _postcss.default)([...pluginList, parser.plugin()]).process(css, {
from: inputFile
});
const out = loader.finalSource;
if (out) css.prepend(out);
if (opts.localsConvention) {
const isFunc = typeof opts.localsConvention === "function";
parser.exportTokens = Object.entries(parser.exportTokens).reduce((tokens, [className, value]) => {
if (isFunc) {
tokens[opts.localsConvention(className, value, inputFile)] = value;
return tokens;
}
switch (opts.localsConvention) {
case "camelCase":
tokens[className] = value;
tokens[(0, _lodash.default)(className)] = value;
break;
case "camelCaseOnly":
tokens[(0, _lodash.default)(className)] = value;
break;
case "dashes":
tokens[className] = value;
tokens[dashesCamelCase(className)] = value;
break;
case "dashesOnly":
tokens[dashesCamelCase(className)] = value;
break;
}
return tokens;
}, {});
}
result.messages.push({
type: "export",
plugin: "postcss-modules",
exportTokens: parser.exportTokens
}); // getJSON may return a promise
return getJSON(css.source.input.file, parser.exportTokens, result.opts.to);
}
};
};
module.exports.postcss = true;