@ -2,7 +2,6 @@
const pirates = require ( "pirates" ) ;
const pirates = require ( "pirates" ) ;
const path = require ( "path" ) ;
const path = require ( "path" ) ;
const defaultValue = require ( "default-value" ) ;
const resolveFrom = require ( "resolve-from" ) ;
const resolveFrom = require ( "resolve-from" ) ;
const syncpipe = require ( "syncpipe" ) ;
const syncpipe = require ( "syncpipe" ) ;
const insertCSS = require ( "insert-css" ) ;
const insertCSS = require ( "insert-css" ) ;
@ -16,10 +15,32 @@ const postcssValues = require("postcss-modules-values");
const postcssICSSParser = require ( "postcss-icss-parser" ) ;
const postcssICSSParser = require ( "postcss-icss-parser" ) ;
const genericNames = require ( "generic-names" ) ;
const genericNames = require ( "generic-names" ) ;
module . exports = function registerICSS ( options = { } ) {
const { validateOptions } = require ( "@validatem/core" ) ;
const isArray = require ( "@validatem/is-array" ) ;
const isBoolean = require ( "@validatem/is-boolean" ) ;
const isFunction = require ( "@validatem/is-function" ) ;
const isString = require ( "@validatem/is-string" ) ;
const oneOf = require ( "@validatem/one-of" ) ;
const arrayOf = require ( "@validatem/array-of" ) ;
const defaultTo = require ( "@validatem/default-to" ) ;
let defaultNameGenerator = genericNames ( "[name]__[local]---[hash:base64:5]" ) ;
module . exports = function registerICSS ( _options ) {
let options = validateOptions ( arguments , [ defaultTo ( { } ) , {
generateScopedName : [ isFunction , defaultTo . literal ( defaultNameGenerator ) ] ,
mode : [ oneOf ( [ "local" , "global" ] ) , defaultTo ( "local" ) ] ,
autoExportImports : [ isBoolean , defaultTo ( true ) ] ,
// TODO: Actually validate that the array items are compatible PostCSS plugins, using array-of
before : [ isArray , defaultTo ( [ ] ) ] ,
after : [ isArray , defaultTo ( [ ] ) ] ,
extensions : [ arrayOf ( isString ) , defaultTo ( [ ".css" ] ) ] ,
postcssOptions : [ defaultTo ( { } ) ] // TODO: Validate for plain object, once is-plain-object works cross-realm
} ] ) ;
let processedFiles = new Map ( ) ;
let processedFiles = new Map ( ) ;
let generateScopedName = defaultValue ( options . generateScopedName , genericNames ( "[name]__[local]---[hash:base64:5]" ) ) ;
let generateScopedName = options. generateScopedName ;
function getExports ( fullPath ) {
function getExports ( fullPath ) {
if ( path . isAbsolute ( fullPath ) ) {
if ( path . isAbsolute ( fullPath ) ) {
@ -40,15 +61,15 @@ module.exports = function registerICSS(options = {}) {
// We cannot reuse the PostCSS instance across files here yet, because the keyReplacer fallback is dependent on the path of the file we're currently processing.
// We cannot reuse the PostCSS instance across files here yet, because the keyReplacer fallback is dependent on the path of the file we're currently processing.
// TODO: Figure out a sensible way to improve upon that.
// TODO: Figure out a sensible way to improve upon that.
let postcssInstance = postcss ( [
let postcssInstance = postcss ( [
... defaultValue( options. before , [ ] ) ,
... options. before ,
postcssValues ,
postcssValues ,
postcssLocalByDefault ( { mode : defaultValue( options. mode , "local" ) } ) ,
postcssLocalByDefault ( { mode : options. mode } ) ,
postcssExtractImports ( ) ,
postcssExtractImports ( ) ,
postcssScope ( {
postcssScope ( {
generateScopedName : generateScopedName
generateScopedName : generateScopedName
} ) ,
} ) ,
postcssICSSParser ( {
postcssICSSParser ( {
autoExportImports : defaultValue( options. autoExportImports , true ) ,
autoExportImports : options. autoExportImports ,
keyReplacer : ( { url , remoteKey } ) => {
keyReplacer : ( { url , remoteKey } ) => {
let resolvedSourcePath = resolveFrom ( path . dirname ( fullPath ) , url ) ;
let resolvedSourcePath = resolveFrom ( path . dirname ( fullPath ) , url ) ;
let htmlExports = getExports ( resolvedSourcePath ) ;
let htmlExports = getExports ( resolvedSourcePath ) ;
@ -63,12 +84,12 @@ module.exports = function registerICSS(options = {}) {
return mangledName . replace ( / /g , "." ) ;
return mangledName . replace ( / /g , "." ) ;
}
}
} ) ,
} ) ,
... defaultValue( options. after , [ ] )
... options. after
] ) ;
] ) ;
let result = postcssInstance . process ( code , {
let result = postcssInstance . process ( code , {
from : fullPath ,
from : fullPath ,
... defaultValue( options. postcssOptions , { } )
... options. postcssOptions
} ) ;
} ) ;
let icssExports = syncpipe ( result . messages , [
let icssExports = syncpipe ( result . messages , [
@ -82,7 +103,7 @@ module.exports = function registerICSS(options = {}) {
return ` module.exports = ${ JSON . stringify ( icssExports ) } ` ;
return ` module.exports = ${ JSON . stringify ( icssExports ) } ` ;
}
}
let extensions = defaultValue( options. extensions , [ ".css" ] ) ;
let extensions = options. extensions ;
let unhook = pirates . addHook (
let unhook = pirates . addHook (
( code , fullPath ) => process ( fullPath , code ) ,
( code , fullPath ) => process ( fullPath , code ) ,