UNPKG

@lipemat/js-boilerplate

Version:

Dependencies and scripts for a no config JavaScript app

121 lines (105 loc) 3.25 kB
import {getPackageConfig} from './package-config'; import type {GetLocalIdent} from '../types/css-loader'; import type {AtLeast} from '../types/utility'; export const SHORT_ALPHABET = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; export const ALPHABET = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'; const classes: { [ filename: string ]: { [ className: string ]: string } } = {}; let counters = [ -1 ]; /** * Check if short CSS classes are enabled. * * Using a helper function to allow for future enhancements. * * @since 4.6.0 */ export function usingShortCssClasses(): boolean { return Boolean( getPackageConfig().shortCssClasses ); } /** * Reset all counters. * * @notice Mostly here for unit tests. */ export function resetCounters(): void { counters = [ -1 ]; } /** * Get the next class is sequence based on: * 1. Single character from SHORT_ALPHABET (prevent conflicts with JS boilerplate). * 2. Incremented character from the `ALPHABET`. * 1. Used once require 2+ characters. * 2. Grows to 3+ characters as needed. * * @return {string} */ export function getNextClass(): string { const last = counters.length - 1; let totalLetters = ALPHABET.length - 1; // First level uses the SHORT_ALPHABET. if ( 0 === last ) { totalLetters = SHORT_ALPHABET.length - 1; } if ( counters[ last ] < totalLetters ) { counters[ last ]++; } else { incrementParent(); } return counters.map( ( counter, i ) => { return 0 === i ? SHORT_ALPHABET[ counter ] : ALPHABET[ counter ]; } ).join( '' ); } /** * When we run out of characters on the current level: * 1. Increment the parent level. * 2. Reset current level and all child levels back to 0. * * If we are out of characters on the parent level or have * no parent level: * 1. Add a new child level. * 2. Reset all levels back to 0. * */ function incrementParent() { let parent = counters.length - 2; let totalLetters = ALPHABET.length - 1; while ( counters[ parent ] !== undefined ) { // First level uses the SHORT_ALPHABET. if ( 0 === parent ) { totalLetters = SHORT_ALPHABET.length - 1; } if ( counters[ parent ] < totalLetters ) { counters[ parent ]++; // Reset all child levels to 0. while ( counters[ parent + 1 ] !== undefined ) { counters[ parent + 1 ] = 0; parent++; } return; } parent--; } // Add a new level and reset all existing levels. counters.forEach( ( _, i ) => counters[ i ] = 0 ); counters.push( 0 ); } type LocalIdentParams = Parameters<GetLocalIdent>; /** * Return a single character unique CSS class name based on WebPack * css-loader's `getLocalIdentName` callback. * * Tracks CSS classes per each file so duplicate uses of the * same class in a file receive the same result. * * @notice Only enabled if the `package.json` has `shortCssClasses` set to true. * * @link https://webpack.js.org/loaders/css-loader/#getlocalident */ export const getLocalIdent = ( {resourcePath}: AtLeast<LocalIdentParams[0], 'resourcePath'>, _: LocalIdentParams[1], localName: LocalIdentParams[2] ): ReturnType<GetLocalIdent> => { classes[ resourcePath ] ||= {}; classes[ resourcePath ][ localName ] ||= getNextClass(); return classes[ resourcePath ][ localName ]; };