@thelabnyc/typed-scss-modules
Version:
TypeScript type definition generator for SCSS CSS Modules
65 lines (64 loc) • 2.8 kB
JavaScript
import os from "node:os";
import reserved from "reserved-words";
import { alerts } from "../core/index.js";
import { applyPrettier } from "../prettier/index.js";
export const EXPORT_TYPES = ["named", "default"];
export const QUOTE_TYPES = ["single", "double"];
export const exportTypeDefault = "named";
export const exportTypeNameDefault = "ClassNames";
export const exportTypeInterfaceDefault = "Styles";
export const quoteTypeDefault = "single";
export const bannerTypeDefault = "";
const classNameToNamedTypeDefinition = (className) => `export declare const ${className}: string;`;
const classNameToType = (className, quoteType) => {
const quote = quoteType === "single" ? "'" : '"';
return ` ${quote}${className}${quote}: string;`;
};
const isReservedKeyword = (className) => reserved.check(className, "es5", true) ||
reserved.check(className, "es6", true);
const isValidName = (className) => {
if (isReservedKeyword(className)) {
alerts.warn(`[SKIPPING] '${className}' is a reserved keyword (consider renaming or using --exportType default).`);
return false;
}
else if (/-/.test(className)) {
alerts.warn(`[SKIPPING] '${className}' contains dashes (consider using 'camelCase' or 'dashes' for --nameFormat or using --exportType default).`);
return false;
}
return true;
};
export const classNamesToTypeDefinitions = async (options) => {
if (options.classNames.length) {
const lines = [];
const { exportTypeName: ClassNames = exportTypeNameDefault, exportTypeInterface: Styles = exportTypeInterfaceDefault, } = options;
switch (options.exportType) {
case "default":
if (options.banner)
lines.push(options.banner);
lines.push(`export type ${Styles} = {`);
lines.push(...options.classNames.map((className) => classNameToType(className, options.quoteType || quoteTypeDefault)));
lines.push(`};${os.EOL}`);
lines.push(`export type ${ClassNames} = keyof ${Styles};${os.EOL}`);
lines.push(`declare const styles: ${Styles};${os.EOL}`);
lines.push(`export default styles;`);
break;
case "named":
if (options.banner)
lines.push(options.banner);
lines.push(...options.classNames
.filter(isValidName)
.map(classNameToNamedTypeDefinition));
break;
}
if (lines.length) {
const typeDefinition = lines.join(`${os.EOL}`) + `${os.EOL}`;
return await applyPrettier(options.file, typeDefinition);
}
else {
return null;
}
}
else {
return null;
}
};