diff --git a/README.md b/README.md index 3167258..50eb6f1 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ const output = { filename: '[name:toLower].css' // specify output file name; defaults to '[name].css' }; const options = { - implementation: 'sass-embedded', // defaults to 'node-sass', + compiler: 'sass-embedded', // defaults to 'node-sass', api: 'modern', // defaults to 'legacy' sassOptions: { minify: true // defaults to false @@ -109,9 +109,9 @@ module.exports = { // * caching 'sass-build:recommended' ], - files: [ + build: [ { - // use packages/default as the folder in which all lookup is based. default is the process.cwd() + // use packages/default as the folder in which all lookup is based. default is process.cwd() cwd: 'packages/default', // path to source file, relative to cwd file: 'scss/all.scss', @@ -123,7 +123,7 @@ module.exports = { file: 'scss/all.scss', outFile: 'dist/all.css', // use different sass implementation - implementation: 'sass-embedded', + compiler: 'sass-embedded', // use @use instead of @import syntax api: 'modern' } diff --git a/__tests__/sass-build/sass-build.test.ts b/__tests__/sass-build/sass-build.test.ts index 2cefd50..9fb75a9 100644 --- a/__tests__/sass-build/sass-build.test.ts +++ b/__tests__/sass-build/sass-build.test.ts @@ -23,7 +23,7 @@ const FIXTURES_PATH = path.resolve( __dirname, '../__fixtures__' ); fs.rmSync( `${FIXTURES_PATH}/dist`, { recursive: true, force: true } ); }); - const opts : Partial = { + const opts : Partial = { api: 'legacy' }; @@ -33,7 +33,7 @@ const FIXTURES_PATH = path.resolve( __dirname, '../__fixtures__' ); describe( 'sassBuild', () => { test('sassBuild compiles', () => { - sassBuild( file, outFile, opts ); + sassBuild( file, outFile, opts ); assert.equal( fileExists( outFile ), true ); }); diff --git a/__tests__/sass-compile/sass-compile.test.ts b/__tests__/sass-compile/sass-compile.test.ts index a30591c..bc067ff 100644 --- a/__tests__/sass-compile/sass-compile.test.ts +++ b/__tests__/sass-compile/sass-compile.test.ts @@ -15,7 +15,7 @@ const FIXTURES_PATH = path.resolve( __dirname, '../__fixtures__' ); logger.level = 'error'; }); - const opts : Partial = { + const opts : Partial = { api: 'legacy' }; @@ -25,7 +25,7 @@ const FIXTURES_PATH = path.resolve( __dirname, '../__fixtures__' ); describe( 'sassCompile', () => { test('sassCompile compiles', () => { - const fileContent = sassCompile( file, opts ); + const fileContent = sassCompile( file, opts ); assert.notEqual( fileContent, '' ); }); @@ -35,13 +35,13 @@ const FIXTURES_PATH = path.resolve( __dirname, '../__fixtures__' ); test('minify: true', () => { const sassOptions : Partial = { minify: true }; - const fileContent = sassCompile( file, { ...opts, sassOptions } ); + const fileContent = sassCompile( file, { ...opts, sassOptions } ); assert.equal( fileContent, 'body{color:red}\n' ); }); test('minify: false', () => { const sassOptions : Partial = { minify: false }; - const fileContent = sassCompile( file, { ...opts, sassOptions } ); + const fileContent = sassCompile( file, { ...opts, sassOptions } ); assert.equal( fileContent, 'body {\n color: red;\n}\n' ); }); @@ -52,7 +52,7 @@ const FIXTURES_PATH = path.resolve( __dirname, '../__fixtures__' ); test('correct path', () => { const sassOptions : Partial = { loadPaths: [ FIXTURES_PATH ] }; - const fileContent = sassCompile( nestedFile, { ...opts, sassOptions } ); + const fileContent = sassCompile( nestedFile, { ...opts, sassOptions } ); assert.notEqual( fileContent, '' ); }); diff --git a/__tests__/sass-compiler/wrap-compiler.test.ts b/__tests__/sass-compiler/wrap-compiler.test.ts index de665f0..4ca1dda 100644 --- a/__tests__/sass-compiler/wrap-compiler.test.ts +++ b/__tests__/sass-compiler/wrap-compiler.test.ts @@ -10,7 +10,7 @@ describe( 'sass-compiler', () => { const NODE_SASS = 'node-sass'; const DART_SASS = 'dart-sass'; const SASS_EMBEDDED = 'sass-embedded'; - const EMPTY_OPTS = {}; + const EMPTY_OPTS = {}; test('Default wrapper compiler is node-sass', () => { const compiler = wrapCompiler( EMPTY_OPTS ); @@ -20,42 +20,42 @@ describe( 'sass-compiler', () => { }); test(`Setting compiler name to 'node-sass' works correctly`, () => { - const compiler = wrapCompiler( { implementation: 'node-sass' } as CliOptions ); + const compiler = wrapCompiler( { compiler: 'node-sass' } as CliBuildOptions ); const compilerName = compiler.info.split('\t')[0]; assert.equal(compilerName, NODE_SASS); }); test(`Setting compiler name to 'sass' works correctly`, () => { - const compiler = wrapCompiler( { implementation: 'sass' } as CliOptions ); + const compiler = wrapCompiler( { compiler: 'sass' } as CliBuildOptions ); const compilerName = compiler.info.split('\t')[0]; assert.equal(compilerName, DART_SASS); }); test(`Setting compiler name to 'sass-embedded' works correctly`, () => { - const compiler = wrapCompiler( { implementation: 'sass-embedded' } as CliOptions ); + const compiler = wrapCompiler( { compiler: 'sass-embedded' } as CliBuildOptions ); const compilerName = compiler.info.split('\t')[0]; assert.equal(compilerName, SASS_EMBEDDED); }); test(`Setting compiler name to require('node-sass') works correctly`, () => { - const compiler = wrapCompiler( { implementation: require('node-sass') } as CliOptions ); + const compiler = wrapCompiler( { compiler: require('node-sass') } as CliBuildOptions ); const compilerName = compiler.info.split('\t')[0]; assert.equal(compilerName, NODE_SASS); }); test(`Setting compiler name to require('sass') works correctly`, () => { - const compiler = wrapCompiler( { implementation: require('sass') } as CliOptions ); + const compiler = wrapCompiler( { compiler: require('sass') } as CliBuildOptions ); const compilerName = compiler.info.split('\t')[0]; assert.equal(compilerName, DART_SASS); }); test(`Setting compiler name to require('sass-embedded') works correctly`, () => { - const compiler = wrapCompiler( { implementation: require('sass-embedded') } as CliOptions ); + const compiler = wrapCompiler( { compiler: require('sass-embedded') } as CliBuildOptions ); const compilerName = compiler.info.split('\t')[0]; assert.equal(compilerName, SASS_EMBEDDED); @@ -63,16 +63,16 @@ describe( 'sass-compiler', () => { test('Setting invalid compiler throws an error', () => { assert.throws( () => { - wrapCompiler( { implementation: '' } as CliOptions ); + wrapCompiler( { compiler: '' } as CliBuildOptions ); }); assert.throws( () => { - wrapCompiler( { implementation: 'glob' } as CliOptions ); + wrapCompiler( { compiler: 'glob' } as CliBuildOptions ); }); assert.throws( () => { - wrapCompiler( { implementation: 'no-such-compiler' } as CliOptions ); + wrapCompiler( { compiler: 'no-such-compiler' } as CliBuildOptions ); }); assert.throws( () => { - wrapCompiler( { implementation: require('glob') } as CliOptions ); + wrapCompiler( { compiler: require('glob') } as CliBuildOptions ); }); }); diff --git a/lib/sass-build-recommended.js b/lib/sass-build-recommended.js index 9ebe894..2489c46 100644 --- a/lib/sass-build-recommended.js +++ b/lib/sass-build-recommended.js @@ -4,23 +4,30 @@ const cwd = process.cwd(); const { sassCacheImporter } = require('../dist/importers/cache-importer'); const { sassPackageImporter } = require('../dist/importers/package-importer'); -/** @type {CliOptions} */ +/** @type {ConfigOptions} */ const config = { - cwd: cwd, - implementation: 'node-sass', - api: 'legacy', - sassOptions: { - minify: false, - functions: [], - importers: [ - sassCacheImporter(), - sassPackageImporter({ cwd: cwd }) - ] - }, - postcss: [ - calc({ precision: 10 }), - autoprefixer() - ] + defaults: { + transform: { + cwd: cwd + }, + build: { + cwd: cwd, + compiler: 'node-sass', + api: 'legacy', + sassOptions: { + minify: false, + functions: [], + importers: [ + sassCacheImporter(), + sassPackageImporter({ cwd: cwd }) + ] + }, + postcss: [ + calc({ precision: 10 }), + autoprefixer() + ] + } + } }; module.exports = config; diff --git a/package-lock.json b/package-lock.json index 3dbd859..59226d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,9 +6,10 @@ "packages": { "": { "name": "sass-build", - "version": "0.0.2", + "version": "1.0.0", "license": "MIT", "dependencies": { + "@joneff/baka": "^2.0.0", "glob": "^8.0.3", "lodash": "^4.17.21", "mime-types": "^2.1.35", @@ -1432,6 +1433,24 @@ "node": "^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0" } }, + "node_modules/@joneff/baka": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@joneff/baka/-/baka-2.0.0.tgz", + "integrity": "sha512-hfMQYpMMp2E6SP9+qAXpG1n9q+5ayyTWODlYS6aLTsO6hVDn/LCShM65a5THc+CCn1354Jv3G81NyiplgoSNiQ==", + "dependencies": { + "@joneff/sass-import-resolver": "^1.0.0", + "glob": "^8.0.3", + "lodash.merge": "^4.6.2" + } + }, + "node_modules/@joneff/sass-import-resolver": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@joneff/sass-import-resolver/-/sass-import-resolver-1.0.0.tgz", + "integrity": "sha512-OtXpn3NYZEoi/+9dXNItOWU9ky4vebX89neg78CVHrYRVXbEWuRfyVFfwH1dhbW9aMZS7CwIXH+1efIegiQ2yQ==", + "dependencies": { + "lodash.merge": "^4.6.2" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", @@ -6499,8 +6518,7 @@ "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, "node_modules/lodash.uniqby": { "version": "4.7.0", @@ -13624,6 +13642,24 @@ "chalk": "^4.0.0" } }, + "@joneff/baka": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@joneff/baka/-/baka-2.0.0.tgz", + "integrity": "sha512-hfMQYpMMp2E6SP9+qAXpG1n9q+5ayyTWODlYS6aLTsO6hVDn/LCShM65a5THc+CCn1354Jv3G81NyiplgoSNiQ==", + "requires": { + "@joneff/sass-import-resolver": "^1.0.0", + "glob": "^8.0.3", + "lodash.merge": "^4.6.2" + } + }, + "@joneff/sass-import-resolver": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@joneff/sass-import-resolver/-/sass-import-resolver-1.0.0.tgz", + "integrity": "sha512-OtXpn3NYZEoi/+9dXNItOWU9ky4vebX89neg78CVHrYRVXbEWuRfyVFfwH1dhbW9aMZS7CwIXH+1efIegiQ2yQ==", + "requires": { + "lodash.merge": "^4.6.2" + } + }, "@jridgewell/gen-mapping": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", @@ -17433,8 +17469,7 @@ "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, "lodash.uniqby": { "version": "4.7.0", diff --git a/package.json b/package.json index f7f6a37..81c0be6 100755 --- a/package.json +++ b/package.json @@ -35,6 +35,7 @@ "prepublishOnly": "npm run build" }, "dependencies": { + "@joneff/baka": "^2.0.0", "glob": "^8.0.3", "lodash": "^4.17.21", "mime-types": "^2.1.35", diff --git a/src/build/build-files.ts b/src/build/build-files.ts index c9ff27e..2554b39 100644 --- a/src/build/build-files.ts +++ b/src/build/build-files.ts @@ -1,7 +1,7 @@ -import { wrapImplementation } from '../compiler'; +import { wrapCompiler } from '../compiler'; -export function sassBuildFiles( file: string | string[], output: OutputOptions = {}, options?: CliOptions ) : void { - const compiler = wrapImplementation( options ); +export function sassBuildFiles( file: string | string[], output: OutputOptions = {}, options?: CliBuildOptions ) : void { + const compiler = wrapCompiler( options ); compiler.buildFiles( file, output, options?.sassOptions ); } diff --git a/src/build/build-string.ts b/src/build/build-string.ts index 06304f7..fdeebc0 100644 --- a/src/build/build-string.ts +++ b/src/build/build-string.ts @@ -1,7 +1,7 @@ -import { wrapImplementation } from '../compiler'; +import { wrapCompiler } from '../compiler'; -export function sassBuildString( source: string, outFile: string, options?: CliOptions ) : void { - const compiler = wrapImplementation( options ); +export function sassBuildString( source: string, outFile: string, options?: CliBuildOptions ) : void { + const compiler = wrapCompiler( options ); compiler.buildString( source, outFile, options?.sassOptions ); } diff --git a/src/build/build.ts b/src/build/build.ts index 8a2ec7b..b2a4041 100644 --- a/src/build/build.ts +++ b/src/build/build.ts @@ -1,7 +1,7 @@ -import { wrapImplementation } from '../compiler'; +import { wrapCompiler } from '../compiler'; -export function sassBuild( file: string, outFile: string, options?: CliOptions ) : void { - const compiler = wrapImplementation( options ); +export function sassBuild( file: string, outFile: string, options?: CliBuildOptions ) : void { + const compiler = wrapCompiler( options ); compiler.build( file, outFile, options?.sassOptions ); } diff --git a/src/cli/index.ts b/src/cli/index.ts index 46b98ab..512e7ce 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -1,7 +1,7 @@ import argsParser from 'yargs-parser'; import * as commands from './commands'; -import { processConfig } from './process-config'; +import { processConfigFile } from '../config'; import { exit, logger @@ -61,7 +61,7 @@ export function cli() { logger.silly('cli', 'No config passed.'); } - processConfig( config ); + processConfigFile( config ); exitSuccess(); } diff --git a/src/cli/process-config.ts b/src/cli/process-config.ts deleted file mode 100644 index e6fae42..0000000 --- a/src/cli/process-config.ts +++ /dev/null @@ -1,120 +0,0 @@ -import path from 'path'; -import _ from 'lodash'; - -import { - exit, - logger, - isString, - isArray, - objectType, - fileExists, - requireUserFile -} from '../utils'; -import { sassBuild, sassBuildFiles } from '../build'; - -function extendConfig(source: ConfigOptions) : ConfigOptions { - let baseConfigs = source.extends; - - if (source.extends === undefined) { - return source; - } - - if (isString(baseConfigs)) { - baseConfigs = [ baseConfigs ]; - } - - if (isArray(baseConfigs) === false) { - return source; - } - - ( baseConfigs).forEach(baseConfigName => { - let configPath = ''; - let configData: CliOptions = {}; - const [ provider, identifier ] = baseConfigName.split(':', 2); - - if (provider !== 'sass-build' && provider !== 'plugin') { - return; - } - - if (identifier === undefined || identifier === '') { - return; - } - - if (provider === 'plugin') { - configPath = identifier; - } else { - configPath = path.resolve(__dirname, '../../lib', `sass-build-${identifier}.js`); - } - - if (configPath !== '') { - configData = require(configPath); - } - - configData = _.pick(configData, 'cwd', 'implementation', 'api', 'postcss', 'sassOptions'); - - // eslint-disable-next-line no-param-reassign - source = _.defaultsDeep({}, source, configData); - }); - - return source; -} - - -export function processConfig( configPath: string ) { - - if (configPath) { - logger.silly('cli > process config', `Using config: ${configPath}`); - } else { - logger.silly('cli > process config', 'Using default config: sass.config.js'); - // eslint-disable-next-line no-param-reassign - configPath = 'sass.config.js'; - } - - if (!fileExists(configPath)) { - exit( 2, 'error', 'cli > process config', `Cannot file config file: ${configPath}` ); - } - - let configData : ConfigOptions = requireUserFile( configPath ); - configData = extendConfig( configData ); - const rootFiles = configData.files; - const rootOpts = _.pick(configData, 'cwd', 'implementation', 'api', 'postcss', 'sassOptions'); - - if (Array.isArray(rootFiles) === false) { - exit( 9, 'error', 'buildConfig', `Expected config.files to be array, but got ${objectType(rootFiles)}\n`); - } - - rootFiles.forEach(entry => { - - if (typeof entry === 'string') { - sassBuildFiles( [ entry ] ); - return; - } - - const options = _.pick(entry, 'cwd', 'implementation', 'api', 'postcss', 'sassOptions' ); - const opts = _.defaultsDeep({}, options, rootOpts ); - - const { file, outFile } = >entry; - - if (typeof file === 'string') { - - if (outFile === null || outFile === undefined) { - exit( 9, 'error', 'buildConfig', `Expected config.entry.outFile to be array, but got ${rootFiles}\n`); - } - - sassBuild( file, outFile, opts ); - return; - } - - const { files, output } = >entry; - - if ( typeof files === 'string' ) { - sassBuildFiles( [ files ], output, opts ); - return; - } - - if (Array.isArray(files)) { - sassBuildFiles( files, output, opts ); - return; - } - }); -} diff --git a/src/compile/compile-string.ts b/src/compile/compile-string.ts index 4a82f16..f841982 100644 --- a/src/compile/compile-string.ts +++ b/src/compile/compile-string.ts @@ -1,7 +1,7 @@ -import { wrapImplementation } from '../compiler'; +import { wrapCompiler } from '../compiler'; -export function sassCompileString( source: string, options?: CliOptions ) : string { - const compiler = wrapImplementation( options ); +export function sassCompileString( source: string, options?: CliBuildOptions ) : string { + const compiler = wrapCompiler( options ); return compiler.compileString( source, options?.sassOptions ); } diff --git a/src/compile/compile.ts b/src/compile/compile.ts index 27660a3..3807cec 100644 --- a/src/compile/compile.ts +++ b/src/compile/compile.ts @@ -1,7 +1,7 @@ -import { wrapImplementation } from '../compiler'; +import { wrapCompiler } from '../compiler'; -export function sassCompile( file: string, options?: CliOptions ) : string { - const compiler = wrapImplementation( options ); +export function sassCompile( file: string, options?: CliBuildOptions ) : string { + const compiler = wrapCompiler( options ); return compiler.compile( file, options?.sassOptions ); } diff --git a/src/compiler/base-sass-compiler.ts b/src/compiler/base-sass-compiler.ts index 067e670..bc85ecc 100644 --- a/src/compiler/base-sass-compiler.ts +++ b/src/compiler/base-sass-compiler.ts @@ -13,13 +13,13 @@ import { } from '../utils'; export abstract class BaseSassCompiler implements SassCompiler { - protected implementation: SassImplementation; + protected compiler: NativeSassCompiler; protected postcss: PostcssProcessor; - protected options: CliOptions; + protected options: CliBuildOptions; - constructor(options: CliOptions) { + constructor(options: CliBuildOptions) { this.options = options; - this.implementation = this.options.implementation; + this.compiler = this.options.compiler; this.postcss = this.options.postcss; } @@ -118,6 +118,6 @@ export abstract class BaseSassCompiler implements SassCompiler { } get info(): string { - return this.implementation.info; + return this.compiler.info; } } diff --git a/src/compiler/index.ts b/src/compiler/index.ts index 58de48b..c4d67d0 100644 --- a/src/compiler/index.ts +++ b/src/compiler/index.ts @@ -10,16 +10,16 @@ import { ModernSassCompiler } from './modern-sass-compiler'; import { LegacySassCompiler } from './legacy-sass-compiler'; -export function wrapImplementation( options?: CliOptions ) : SassCompiler { - const defaults = >{ +export function wrapCompiler( options?: CliBuildOptions ) : SassCompiler { + const defaults = >{ cwd: CWD }; const opts = _.defaultsDeep( {}, options, defaults ); - opts.implementation = getSassCompiler( opts.implementation ); + opts.compiler = getSassCompiler( opts.compiler ); opts.postcss = getPostcss( opts.postcss ); - const info = opts.implementation.info.split('\t')[0]; + const info = opts.compiler.info.split('\t')[0]; if (opts.api === 'modern') { if (info === 'node-sass') { diff --git a/src/compiler/legacy-sass-compiler.ts b/src/compiler/legacy-sass-compiler.ts index 3c3eaff..51ab76c 100644 --- a/src/compiler/legacy-sass-compiler.ts +++ b/src/compiler/legacy-sass-compiler.ts @@ -24,7 +24,7 @@ export class LegacySassCompiler extends BaseSassCompiler { ); this.before(); - const result = ( this.implementation).renderSync(opts).css.toString('utf-8'); + const result = ( this.compiler).renderSync(opts).css.toString('utf-8'); return this.postcss.process(result).css; } @@ -40,7 +40,7 @@ export class LegacySassCompiler extends BaseSassCompiler { ); this.before(); - const result = ( this.implementation).renderSync(opts).css.toString('utf-8'); + const result = ( this.compiler).renderSync(opts).css.toString('utf-8'); return this.postcss.process(result).css; } diff --git a/src/compiler/modern-sass-compiler.ts b/src/compiler/modern-sass-compiler.ts index 2d6f61e..0faac1e 100644 --- a/src/compiler/modern-sass-compiler.ts +++ b/src/compiler/modern-sass-compiler.ts @@ -21,7 +21,7 @@ export class ModernSassCompiler extends BaseSassCompiler { ); this.before(); - const result = ( this.implementation).compile( file, opts ).css; + const result = ( this.compiler).compile( file, opts ).css; return this.postcss.process(result).css; } @@ -36,7 +36,7 @@ export class ModernSassCompiler extends BaseSassCompiler { ); this.before(); - const result = ( this.implementation).compileString( source, opts ).css; + const result = ( this.compiler).compileString( source, opts ).css; return this.postcss.process(result).css; } diff --git a/src/config/index.ts b/src/config/index.ts new file mode 100644 index 0000000..4a66fc6 --- /dev/null +++ b/src/config/index.ts @@ -0,0 +1 @@ +export * from './process-config'; diff --git a/src/config/process-config.ts b/src/config/process-config.ts new file mode 100644 index 0000000..04ef4f1 --- /dev/null +++ b/src/config/process-config.ts @@ -0,0 +1,109 @@ +import path from 'path'; +import _ from 'lodash'; + +import { + exit, + logger, + isString, + isArray, + fileExists, + requireUserFile +} from '../utils'; + +import { stageBuild } from './stage-build'; +import { stageTransform } from './stage-transform'; + +const stageMap = { + build: stageBuild, + transform: stageTransform +}; + +const defaultStages = [ 'transform', 'build' ]; + +function getDefaults(source: ConfigOptions) : ConfigOptions['defaults'] { + let baseConfigs = source.extends; + + if (baseConfigs === undefined) { + return source.defaults || {}; + } + + if (isString(baseConfigs)) { + baseConfigs = [ baseConfigs ]; + } + + if (isArray(baseConfigs) === false) { + return source.defaults || {}; + } + + baseConfigs.forEach(baseConfigName => { + let configPath = ''; + let configData: ConfigOptions = {}; + const [ provider, identifier ] = baseConfigName.split(':', 2); + + if (provider !== 'sass-build' && provider !== 'plugin') { + return; + } + + if (identifier === undefined || identifier === '') { + return; + } + + if (provider === 'plugin') { + configPath = identifier; + } else { + configPath = path.resolve(__dirname, '../../lib', `sass-build-${identifier}.js`); + } + + if (configPath !== '') { + configData = require(configPath); + } + + source.defaults = _.defaultsDeep({}, source.defaults, configData.defaults); + }); + + return source.defaults; +} + +export function processConfigFile( configPath: string, stages: string[] = defaultStages ) { + + if (configPath) { + logger.silly('process config', `Using config: ${configPath}`); + } else { + logger.silly('process config', 'Using default config: sass.config.js'); + // eslint-disable-next-line no-param-reassign + configPath = 'sass.config.js'; + } + + if (!fileExists(configPath)) { + exit( 2, 'error', 'process config', `Cannot file config file: ${configPath}` ); + } + + const config : ConfigOptions = requireUserFile( configPath ); + + processConfig(config, stages); +} + +export function processConfig(config: ConfigOptions, stages: string[] = defaultStages) { + const configDefaults = getDefaults( config ); + + if (Array.isArray(config.files)) { + if (Array.isArray(config.build)) { + logger.warn('process config', `Found both config.build and config.files. Using config.build.`); + } else { + logger.warn('process config', `Prefer config.build instead of config.files.`); + config.build = Array.from(config.files); + } + delete config.files; + } + + stages.forEach(stage => { + const stageFn = stageMap[stage]; + const stageData = config[stage]; + const stageDefaults = configDefaults[stage] || {}; + + if (typeof stageFn === 'function') { + stageFn( stageData, stageDefaults ); + } + }); + +} diff --git a/src/config/stage-build.ts b/src/config/stage-build.ts new file mode 100644 index 0000000..5af8cdf --- /dev/null +++ b/src/config/stage-build.ts @@ -0,0 +1,69 @@ +import _ from 'lodash'; + +import { + exit, + logger, + objectType +} from '../utils'; + +import { sassBuild, sassBuildFiles } from '../build'; + +export function stageBuild(buildSection: BuildStageEntry[], defaults: CliBuildOptions) { + + if (buildSection === undefined) { + logger.silly('config > build', 'No build stage.'); + return; + } + + if (Array.isArray(buildSection) === false) { + exit( 9, 'error', 'config > build', `Expected config.build to be array, but got ${objectType(buildSection)}.\n`); + } + + if (buildSection.length === 0) { + logger.silly('config > build', 'Build stage is empty.'); + return; + } + + buildSection.forEach(buildEntry => { + + if (typeof buildEntry === 'string') { + sassBuildFiles( [ buildEntry ] ); + return; + } + + const options = { + cwd: buildEntry.cwd, + compiler: buildEntry.compiler, + api: buildEntry.api, + postcss: buildEntry.postcss, + sassOptions: buildEntry.sassOptions + }; + const opts = _.defaultsDeep( {}, options, defaults ); + + const { file, outFile } = buildEntry; + + if (typeof file === 'string') { + + if (typeof outFile !== 'string' ) { + exit( 9, 'error', 'config > build', `Expected outFile to be string, but got ${objectType(outFile)}.\n`); + } + + sassBuild( file, outFile, opts ); + return; + } + + const { entry, output } = buildEntry; + + if ( typeof entry === 'string' ) { + sassBuildFiles( [ entry ], output, opts ); + return; + } + + if (Array.isArray(entry)) { + sassBuildFiles( entry, output, opts ); + return; + } + + exit( 9, 'error', 'config > build', `Expected file and outFile or entry fields.\n`); + }); +} diff --git a/src/config/stage-transform.ts b/src/config/stage-transform.ts new file mode 100644 index 0000000..c18214e --- /dev/null +++ b/src/config/stage-transform.ts @@ -0,0 +1,77 @@ +import _ from 'lodash'; + +import { + exit, + logger, + objectType +} from '../utils'; + +export function stageTransform(transformSection: TransformStageEntry[], defaults: CliTransformOptions) { + + if (transformSection === undefined) { + logger.silly('config > transform', 'No transform stage.'); + return; + } + + if (Array.isArray(transformSection) === false) { + exit( 9, 'error', 'config > transform', `Expected config.transform to be array, but got ${objectType(transformSection)}.\n`); + } + + if (transformSection.length === 0) { + logger.silly('config > transform', 'Transform stage is empty.'); + return; + } + + transformSection.forEach(transformEntry => { + + const options = { + cwd: transformEntry.cwd, + transformer: transformEntry.transformer, + transformerOptions: transformEntry.transformerOptions + }; + const opts = _.defaultsDeep( {}, options, defaults ); + + const transformer = opts.transformer; + let { transformFile, transformGlob } = transformer; + + if (!transformFile && !transformGlob) { + transformFile = transformer; + transformGlob = transformer; + } + + if (typeof transformFile !== 'function') { + exit( 9, 'error', 'config > transform', `Expected transformFile to be function, but got ${objectType(transformFile)}.\n`); + } + + if (typeof transformGlob !== 'function') { + exit( 9, 'error', 'config > transform', `Expected transformGlob to be function, but got ${objectType(transformGlob)}.\n`); + } + + const { file, outFile } = transformEntry; + + if (typeof file === 'string') { + + if (typeof outFile !== 'string' ) { + exit( 9, 'error', 'config > build', `Expected outFile to be string, but got ${objectType(outFile)}.\n`); + } + + transformFile( file, outFile, opts ); + return; + } + + const { entry, output } = transformEntry; + + if ( typeof entry === 'string' ) { + transformGlob( [ entry ], output, opts ); + return; + } + + if (Array.isArray(entry)) { + transformGlob( entry, output, opts ); + return; + } + + exit( 9, 'error', 'config > build', `Expected file and outFile or entry fields.\n`); + }); + +} diff --git a/src/index.ts b/src/index.ts index b1af955..07f8830 100755 --- a/src/index.ts +++ b/src/index.ts @@ -2,8 +2,10 @@ export { sassBuild, sassBuildFiles, sassBuildString } from './build'; export { sassCompile, sassCompileString } from './compile'; -export { wrapImplementation as wrapCompiler } from './compiler'; +export { wrapCompiler } from './compiler'; export { sassCacheImporter } from './importers/cache-importer'; export { sassPackageImporter } from './importers/package-importer'; +export { JsonThemeTransformer, SassInlineTransformer } from './transformers'; +export { processConfig, processConfigFile } from './config'; export { cli } from './cli'; export { Logger } from './logger'; diff --git a/src/transform/index.ts b/src/transform/index.ts new file mode 100644 index 0000000..d5e7ab1 --- /dev/null +++ b/src/transform/index.ts @@ -0,0 +1 @@ +export * from './transform'; diff --git a/src/transform/transform.ts b/src/transform/transform.ts new file mode 100644 index 0000000..98f4a95 --- /dev/null +++ b/src/transform/transform.ts @@ -0,0 +1 @@ +export function transform() {} diff --git a/src/transformers/index.ts b/src/transformers/index.ts new file mode 100644 index 0000000..0524e54 --- /dev/null +++ b/src/transformers/index.ts @@ -0,0 +1,2 @@ +export * from './json-theme-transformer'; +export * from './sass-inline-transformer'; diff --git a/src/transformers/json-theme-transformer.ts b/src/transformers/json-theme-transformer.ts new file mode 100644 index 0000000..7693070 --- /dev/null +++ b/src/transformers/json-theme-transformer.ts @@ -0,0 +1,142 @@ +import fs from 'fs'; +import path from 'path'; +import glob from 'glob'; +import _ from 'lodash'; + +import { + CWD, + padCwd, + trimCwd, + isString, + logger, + writeFile, + replacePathVariables +} from '../utils'; + +export const JsonThemeTransformer : CliTransformer = { + transformFile, + transformGlob +}; + +function __jsonTransformer(jsonFile) { + const json = JSON.parse(fs.readFileSync(jsonFile, 'utf-8')); + const sassContent = []; + let groups; + + if (Array.isArray(json)) { + groups = json; + } else { + groups = json.groups || []; + } + + groups.forEach( (group) => { + + // group is { name: value } + if (typeof group.value === 'string') { + let name = group.name; + if (name[0] !== '$') { + name = `$${name}`; + } + sassContent.push(`${name}: ${group.value};`); + + return; + } + + // group is { variables: [] } + for ( const varEntry of Object.entries(group.variables) ) { + let name = varEntry[0].trim(); + let value = varEntry[1]; + + if (typeof value !== 'string') { + value = value.value; + } + + if (name[0] !== '$') { + name = `$${name}`; + } + sassContent.push(`${name}: ${value};`); + } + }); + + return sassContent.join('\n'); +} + +function transformFile( file: string, outFile: string, options: CliTransformOptions ) { + const _cwd = options.cwd; + const transformerOptions = options.transformerOptions; + let header = transformerOptions.header || ''; + let footer = transformerOptions.footer || ''; + + if (path.isAbsolute(file) === false) { + // eslint-disable-next-line no-param-reassign + file = padCwd( _cwd, file ); + } + + if (path.isAbsolute(outFile) === false) { + // eslint-disable-next-line no-param-reassign + outFile = padCwd( _cwd, outFile ); + } + + const json = JSON.parse(fs.readFileSync(file, 'utf-8')); + + if (!Array.isArray(json)) { + if (json.private === true) { + logger.info('transform', 'Skipping %s', trimCwd(CWD, file)); + return; + } + + if (typeof header === 'function') { + header = header(file, json); + } + + if (typeof footer === 'function') { + footer = footer(file, json); + } + } + + logger.info( + 'transform', '%s => %s', + trimCwd(CWD, file), + trimCwd(CWD, outFile) + ); + + const result = `${header}${__jsonTransformer( file )}${footer}`; + + writeFile( outFile, result ); +} + +function transformGlob( fileOrGlob: string | string[], output: OutputOptions, options: CliTransformOptions ) { + const _cwd = options.cwd; + + if (isString(fileOrGlob)) { + logger.warn( 'config > transform > transformGlob', 'Prefer string[] for fileOrGlob option.'); + // eslint-disable-next-line no-param-reassign + fileOrGlob = [ fileOrGlob ]; + } + + // eslint-disable-next-line no-param-reassign + output = _.defaults({}, output, { path: 'dist', filename: '[name].scss' }); + + if (path.isAbsolute(output.path) === false) { + output.path = padCwd( _cwd, output.path ); + } + + fileOrGlob.forEach(fileOrGlob => { + if (path.isAbsolute(fileOrGlob) === false) { + // eslint-disable-next-line no-param-reassign + fileOrGlob = padCwd( _cwd, fileOrGlob ); + } + + // eslint-disable-next-line no-param-reassign + fileOrGlob = fileOrGlob.split(path.sep).join(path.posix.sep); + + glob.sync(fileOrGlob).forEach(file => { + const outFile = path.resolve( + output.path, + replacePathVariables( output.filename, file ) + ); + + transformFile( file, outFile, options ); + }); + }); +} diff --git a/src/transformers/sass-inline-transformer.ts b/src/transformers/sass-inline-transformer.ts new file mode 100644 index 0000000..81f8275 --- /dev/null +++ b/src/transformers/sass-inline-transformer.ts @@ -0,0 +1,79 @@ +import path from 'path'; +import glob from 'glob'; +import _ from 'lodash'; +import baka from '@joneff/baka'; + +import { + CWD, + padCwd, + trimCwd, + isString, + logger, + writeFile, + replacePathVariables +} from '../utils'; + +export const SassInlineTransformer : CliTransformer = { + transformFile, + transformGlob +}; + +function transformFile( file: string, outFile: string, options: CliTransformOptions ) { + const _cwd = options.cwd; + + if (path.isAbsolute(file) === false) { + // eslint-disable-next-line no-param-reassign + file = padCwd( _cwd, file ); + } + + if (path.isAbsolute(outFile) === false) { + // eslint-disable-next-line no-param-reassign + outFile = padCwd( _cwd, outFile ); + } + + logger.info( + 'transform', '%s => %s', + trimCwd(CWD, file), + trimCwd(CWD, outFile) + ); + + const result = baka.compile( file, { cwd: _cwd } ); + + writeFile( outFile, result.content ); +} + +function transformGlob( fileOrGlob: string | string[], output: OutputOptions, options: CliTransformOptions ) { + const _cwd = options.cwd; + + if (isString(fileOrGlob)) { + logger.warn( 'cli > config > transform > transformGlob', 'Prefer string[] for fileOrGlob option.'); + // eslint-disable-next-line no-param-reassign + fileOrGlob = [ fileOrGlob ]; + } + + // eslint-disable-next-line no-param-reassign + output = _.defaults({}, output, { path: 'dist', filename: '[name].css' }); + + if (path.isAbsolute(output.path) === false) { + output.path = padCwd( _cwd, output.path ); + } + + fileOrGlob.forEach(fileOrGlob => { + if (path.isAbsolute(fileOrGlob) === false) { + // eslint-disable-next-line no-param-reassign + fileOrGlob = padCwd( _cwd, fileOrGlob ); + } + + // eslint-disable-next-line no-param-reassign + fileOrGlob = fileOrGlob.split(path.sep).join(path.posix.sep); + + glob.sync(fileOrGlob).forEach(file => { + const outFile = path.resolve( + output.path, + replacePathVariables( output.filename, file ) + ); + + transformFile( file, outFile, options ); + }); + }); +} diff --git a/src/utils.ts b/src/utils.ts index 46281ed..0fdfe87 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -135,7 +135,7 @@ export function getPostcss( options?: false | 'auto' | [] | PostcssProcessor ) : // #region sass compiler -function getDefaultSassCompiler() : SassImplementation { +function getDefaultSassCompiler() : NativeSassCompiler { let sassPkg = 'node-sass'; try { @@ -155,11 +155,11 @@ function getDefaultSassCompiler() : SassImplementation { } // eslint-disable-next-line @typescript-eslint/no-var-requires - return require(sassPkg); + return require(sassPkg); } -export function getSassCompiler(compiler?: string | SassImplementation) : SassImplementation { - let resolvedCompiler = compiler; +export function getSassCompiler(compiler?: string | NativeSassCompiler) : NativeSassCompiler { + let resolvedCompiler = compiler; if (resolvedCompiler === undefined) { resolvedCompiler = getDefaultSassCompiler(); diff --git a/types/cli/cli-options.d.ts b/types/cli/cli-options.d.ts new file mode 100644 index 0000000..506cbfd --- /dev/null +++ b/types/cli/cli-options.d.ts @@ -0,0 +1,38 @@ +declare type ApiType = 'modern' | 'legacy'; + +declare type CommonCliOptions = { + cwd: string; +} + + +declare type CliBuildOptions = CommonCliOptions & { + compiler: string | NativeSassCompiler; + api: ApiType; + postcss: false | 'auto' | [] | PostcssProcessor; + sassOptions: SassOptions; +} +declare type CliBuilder = string | Function | { + buildFile: Function; + buildGlob: Function; +} + + +declare type CliBundleOptions = CommonCliOptions & { + bundler: string | Function; + bundlerOptions?: any; +} + + +declare type CliTransformOptions = CommonCliOptions & { + transformer: CliTransformer; + transformerOptions: { + header: string | ((file: string, content: any)=> string); + footer: string | ((file: string, content: any)=> string); + }; +} +declare type CliTransformer = (Object | ((...args) => void)) & { + transformFile: TransformFileFn; + transformGlob: TransformGlobFn; +}; + +declare type CliOptions = CliBuildOptions | CliTransformOptions; diff --git a/types/cli/index.d.ts b/types/cli/index.d.ts new file mode 100644 index 0000000..b47a333 --- /dev/null +++ b/types/cli/index.d.ts @@ -0,0 +1 @@ +/// diff --git a/types/index.d.ts b/types/index.d.ts index 6a6bb3b..2af6746 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,3 +1,5 @@ /// -/// +/// +/// +/// /// diff --git a/types/sass/index.d.ts b/types/sass/index.d.ts new file mode 100644 index 0000000..142f323 --- /dev/null +++ b/types/sass/index.d.ts @@ -0,0 +1,8 @@ + +/// +/// +/// +/// +/// +/// +/// diff --git a/types/sass/sass-compile-result.d.ts b/types/sass/sass-compile-result.d.ts new file mode 100644 index 0000000..9805f86 --- /dev/null +++ b/types/sass/sass-compile-result.d.ts @@ -0,0 +1,7 @@ +declare type ModernCompileResult = { + css: string; +} + +declare type LegacyCompileResult = { + css: Buffer; +} diff --git a/types/sass/sass-compiler.d.ts b/types/sass/sass-compiler.d.ts new file mode 100644 index 0000000..4c27fe0 --- /dev/null +++ b/types/sass/sass-compiler.d.ts @@ -0,0 +1,24 @@ +declare type SassCompiler = { + build( file: string, outFile: string, sassOptions?: SassOptions ) : void; + buildFiles( files: string | string[], output: OutputOptions, sassOptions?: SassOptions) : void; + buildString( source: string, outFile: string, sassOptions?: SassOptions ) : void; + compile( file: string, sassOptions?: SassOptions ) : string; + compileString( source: string, sassOptions?: SassOptions ) : string; + info: string; +} + +declare type LegacySassImplementation = { + renderSync(options: LegacySassOptions): LegacyCompileResult; + renderSync(options: Omit): LegacyCompileResult; + logger: SassLogger; + info: string; +} + +declare type ModernSassImplementation = { + compile( file: string, options: ModernSassOptions ) : ModernCompileResult; + compileString( source: string, options: ModernSassOptions ): ModernCompileResult; + logger: SassLogger; + info: string; +} + +declare type NativeSassCompiler = LegacySassImplementation | ModernSassImplementation; diff --git a/types/sass/sass-function.d.ts b/types/sass/sass-function.d.ts new file mode 100644 index 0000000..c23c7a0 --- /dev/null +++ b/types/sass/sass-function.d.ts @@ -0,0 +1,2 @@ +declare type ModernCustomFunction = (args: SassValue[]) => SassValue; +declare type LegacyCustomFunction = (...args: SassValue[]) => SassValue; diff --git a/types/sass-importer.d.ts b/types/sass/sass-importer.d.ts similarity index 100% rename from types/sass-importer.d.ts rename to types/sass/sass-importer.d.ts diff --git a/types/sass/sass-logger.d.ts b/types/sass/sass-logger.d.ts new file mode 100644 index 0000000..d205fa4 --- /dev/null +++ b/types/sass/sass-logger.d.ts @@ -0,0 +1,5 @@ +declare type SassLogger = { + silent: SassLogger; + warn( message: string, options ) : void; + debug( message: string, options ) : void; +} diff --git a/types/sass/sass-options.d.ts b/types/sass/sass-options.d.ts new file mode 100644 index 0000000..f8fc24e --- /dev/null +++ b/types/sass/sass-options.d.ts @@ -0,0 +1,42 @@ +declare type SassOptions = { + file: string; + outFile: string; + source: string; + minify: boolean; + logger: SassLogger; + loadPaths: string[]; + functions: Record; + importers: SassImporter[]; + sourceMap: boolean; +} + +declare type SharedSassOptions = { + charset: boolean; + precision: 10; + indentType: 'space'; + indentWidth: 4; + linefeed: 'lf'; + sourceMap: boolean; + logger: SassLogger; + verbose: boolean; + quietDeps: boolean; +} + +declare type ModernSassOptions = SharedSassOptions & { + loadPaths: []; + style: 'expanded' | 'compressed'; + functions: Record; + importers: SassImporter[]; +} + +declare type LegacySassOptions = SharedSassOptions & { + file: string; + outFile: string; + data: string; + includePaths: []; + outputStyle: 'expanded' | 'compressed'; + functions: Record; + importer: SassImporter[]; +} + +declare type NativeSassOptions = ModernSassOptions | LegacySassOptions; diff --git a/types/sass/sass-value.d.ts b/types/sass/sass-value.d.ts new file mode 100644 index 0000000..64ad5a8 --- /dev/null +++ b/types/sass/sass-value.d.ts @@ -0,0 +1 @@ +declare type SassValue = {}; diff --git a/types/transformer.d.ts b/types/transformer.d.ts new file mode 100644 index 0000000..b8df789 --- /dev/null +++ b/types/transformer.d.ts @@ -0,0 +1,10 @@ +declare type TransformFileFn = (( + file: string, + outFile: string, + options: CliTransformOptions +) => void); +declare type TransformGlobFn = (( + fileOrGlob: string | string[], + output: OutputOptions, options: + CliTransformOptions +) => void); diff --git a/types/types.d.ts b/types/types.d.ts index 9c3534e..1411249 100644 --- a/types/types.d.ts +++ b/types/types.d.ts @@ -1,88 +1,3 @@ -// #region sass types -declare type SassValue = {}; -declare type ModernCustomFunction = (args: SassValue[]) => SassValue; -declare type LegacyCustomFunction = (...args: SassValue[]) => SassValue; -declare type ModernCompileResult = { - css: string; -} -declare type LegacyCompileResult = { - css: Buffer; -} -declare type SassLogger = { - silent: SassLogger; - warn( message: string, options ) : void; - debug( message: string, options ) : void; -} -// #endregion - -// #region sass options -declare type SharedSassOptions = { - charset: boolean; - precision: 10; - indentType: 'space'; - indentWidth: 4; - linefeed: 'lf'; - sourceMap: boolean; - logger: SassLogger; - verbose: boolean; - quietDeps: boolean; -} - -// #region native sass options -declare type ModernSassOptions = SharedSassOptions & { - loadPaths: []; - style: 'expanded' | 'compressed'; - functions: Record; - importers: SassImporter[]; -} -declare type LegacySassOptions = SharedSassOptions & { - file: string; - outFile: string; - data: string; - includePaths: []; - outputStyle: 'expanded' | 'compressed'; - functions: Record; - importer: SassImporter[]; -} -// #endregion - -declare type SassOptions = { - file: string; - outFile: string; - source: string; - minify: boolean; - logger: SassLogger; - loadPaths: string[]; - functions: Record; - importers: SassImporter[]; - sourceMap: boolean -}; -// #endregion - -// #region sass implementation -declare type LegacySassImplementation = { - renderSync(options: LegacySassOptions): LegacyCompileResult; - renderSync(options: Omit): LegacyCompileResult; - logger: SassLogger; - info: string; -} - -declare type ModernSassImplementation = { - compile( file: string, options: ModernSassOptions ) : ModernCompileResult; - compileString( source: string, options: ModernSassOptions ): ModernCompileResult; - logger: SassLogger; - info: string; -} - -declare type SassImplementation = LegacySassImplementation | ModernSassImplementation; -// #endregion - -// #region defaults options -declare type DefaultsOptions = { - cwd?: string | (() => string); -} -// #endregion - // #region sass importers declare type PackageImporterOptions = { cwd?: string | (() => string) @@ -93,6 +8,7 @@ declare type CacheImporterOptions = { } // #endregion + // #region postcss declare type PostcssProcessor = { version: string; @@ -100,6 +16,7 @@ declare type PostcssProcessor = { }; // #endregion + // #region path data declare type FileData = { mime: string, @@ -127,58 +44,45 @@ declare type PathData = FileData & { } // #endregion -// #region sass compiler -declare type OutputOptions = { - filename: string, - path: string -} - -declare type SassCompiler = { - build( file: string, outFile: string, sassOptions?: SassOptions ) : void; - buildFiles( files: string | string[], output: OutputOptions, sassOptions?: SassOptions) : void; - buildString( source: string, outFile: string, sassOptions?: SassOptions ) : void; - compile( file: string, sassOptions?: SassOptions ) : string; - compileString( source: string, sassOptions?: SassOptions ) : string; - info: string; -} -// #endregion - -// #region cli options -declare type CliOptions = { - cwd: string, - implementation: string | SassImplementation; - api: ApiType; - postcss: false | 'auto' | [] | PostcssProcessor; - sassOptions: SassOptions; -} - -declare type ApiType = 'modern' | 'legacy'; -declare type ConfigOptions = CliOptions & { - extends: string | string[], - files: ConfigFileEntry[] +// #region config options +declare type ConfigOptions = { + extends: string | string[]; + defaults: { + transform: CliTransformOptions; + build: CliBuildOptions; + bundle: CliBundleOptions; + } + files: BuildStageEntry[]; + transform: TransformStageEntry[]; + build: BuildStageEntry[]; + bundle: BundleStageEntry[]; } -declare type ConfigStringFileEntry = String; -declare type ConfigSingleFileEntry = CliOptions & { +declare type ConfigStageFileEntry = { file: string; outFile: string; -}; -declare type ConfigMultipleFilesEntry = CliOptions & { - files: string | string[]; +} +declare type ConfigStageGlobEntry = { + entry: string; output: OutputOptions; } +declare type ConfigStageEntry = ConfigStageFileEntry | ConfigStageGlobEntry; + +declare type TransformStageEntry = ConfigStageEntry & CliTransformOptions; + +declare type BuildStageEntry = ConfigStageEntry & CliBuildOptions; -declare type ConfigFileEntry = ConfigStringFileEntry | ConfigSingleFileEntry +declare type BundleStageEntry = ConfigStageEntry & CliBundleOptions; // #endregion declare module 'sass-build' { - export function sassCompile(file: string, options?: CliOptions): string; - export function sassCompileString(source: string, options?: CliOptions): string; - export function sassBuild(file: string, outFile: string, options?: CliOptions): void; - export function sassBuildFiles(files: string | string[], output: OutputOptions, options?: CliOptions): void; - export function sassBuildString(source: string, outFile: string, options?: CliOptions): void; - export function wrapCompiler(options: CliOptions): SassCompiler; + export function sassCompile(file: string, options?: CliBuildOptions): string; + export function sassCompileString(source: string, options?: CliBuildOptions): string; + export function sassBuild(file: string, outFile: string, options?: CliBuildOptions): void; + export function sassBuildFiles(files: string | string[], output: OutputOptions, options?: CliBuildOptions): void; + export function sassBuildString(source: string, outFile: string, options?: CliBuildOptions): void; + export function wrapCompiler(options: CliBuildOptions): SassCompiler; export class Logger implements LoggerType { time(label: string): void; timeEnd(label: string, level?: string, prefix?: string, message?: string): string | void;