Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
5599148
commit 1d7a889
Showing
2 changed files
with
241 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
'use strict'; | ||
|
||
const LazyResult = require('postcss/lib/lazy-result'); | ||
const postcss = require('postcss'); | ||
const postcssSafeParser = require('postcss-safe-parser'); | ||
|
||
const createPartialStylelintResult = require('./createPartialStylelintResult'); | ||
const jsonFormatter = require('./formatters/jsonFormatter'); | ||
const lintPostcssResult = require('./lintPostcssResult'); | ||
const normalizeAllRuleSettings = require('./normalizeAllRuleSettings'); | ||
const prepareReturnValue = require('./prepareReturnValue'); | ||
|
||
const postcssProcessor = postcss(); | ||
|
||
/** @typedef {import('stylelint').StylelintStandaloneOptions} StylelintStandaloneOptions */ | ||
/** @typedef {import('stylelint').StylelintStandaloneReturnValue} StylelintStandaloneReturnValue */ | ||
/** @typedef {import('stylelint').StylelintResult} StylelintResult */ | ||
/** @typedef {import('stylelint').StylelintInternalApi} StylelintInternalApi */ | ||
/** @typedef {import('postcss').Syntax} Syntax */ | ||
|
||
/** TODO: create new type that's a subset of StylelintStandaloneOptions */ | ||
/** | ||
* @param {StylelintStandaloneOptions} options | ||
* @returns {Promise<StylelintStandaloneReturnValue>} | ||
*/ | ||
async function lint(options) { | ||
if (!options.code) { | ||
throw new Error( | ||
`"options.code" is missing. You must provide a string value in "options.code".`, | ||
); | ||
} | ||
|
||
if (!options.config) { | ||
throw new Error( | ||
`"options.config" is missing. You must provide a config object in "options.config".`, | ||
); | ||
} | ||
|
||
if (options.formatter) { | ||
throw new Error( | ||
`"options.formatter" is not supported for stylelint's browser bundle. Remove the formatter option or try the standalone version of stylelint. TODO: link here?`, | ||
); | ||
} | ||
|
||
if (options.syntax) { | ||
throw new Error( | ||
`"options.syntax" is not supported for stylelint's browser bundle. You must load a syntax and pass it in to "options.customSyntax". Refer to the stylelint browser bundle docs for more info. TODO: url here`, | ||
); | ||
} | ||
|
||
if (options.config.plugins) { | ||
throw new Error( | ||
`"options.config.plugins" is not supported for stylelint's browser bundle. Remove the plugins from your config or try the standalone version of stylelint. TODO: url here`, | ||
); | ||
} | ||
|
||
// TODO: more input validation? check for other options that aren't supported here | ||
|
||
const syntax = syntaxFromOptions(options); | ||
|
||
const postcssOptions = { | ||
syntax, | ||
from: undefined, | ||
}; | ||
|
||
let cssResult; | ||
let stylelintResult /** @type StylelintResult */; | ||
|
||
try { | ||
const lazyResult = await new LazyResult(postcssProcessor, options.code, postcssOptions); | ||
|
||
cssResult = Object.assign(lazyResult, { | ||
stylelint: { | ||
ruleSeverities: {}, | ||
customMessages: {}, | ||
disabledRanges: {}, | ||
}, | ||
}); | ||
|
||
const normalizedConfig = normalizeAllRuleSettings(options.config); | ||
|
||
await lintPostcssResult(options, cssResult, normalizedConfig); | ||
|
||
stylelintResult = createPartialStylelintResult(cssResult); | ||
} catch (error) { | ||
// This is equivalent to the `handleError` function in standalone.js | ||
if (error.name === 'CssSyntaxError') { | ||
stylelintResult = createPartialStylelintResult(undefined, error); | ||
} else { | ||
throw error; | ||
} | ||
} | ||
|
||
// TODO: this is mostly the same in standalone.js. Extract out? | ||
const postcssResult = stylelintResult._postcssResult; | ||
const returnValue = prepareReturnValue([stylelintResult], options, jsonFormatter); | ||
|
||
if (options.fix && postcssResult && !postcssResult.stylelint.ignored) { | ||
if (!postcssResult.stylelint.disableWritingFix) { | ||
// If we're fixing, the output should be the fixed code | ||
// @ts-ignore note: ts complaining that .root might not exist | ||
returnValue.output = postcssResult.root.toString(syntax); | ||
} else { | ||
// If the writing of the fix is disabled, the input code is returned as-is | ||
returnValue.output = options.code; | ||
} | ||
} | ||
|
||
return returnValue; | ||
} | ||
|
||
/** | ||
* @param {StylelintStandaloneOptions} options | ||
* @returns {Syntax} | ||
*/ | ||
function syntaxFromOptions(options) { | ||
const { customSyntax, fix } = options; | ||
|
||
if (!customSyntax) | ||
return { | ||
parse: fix ? postcssSafeParser : postcss.parse, | ||
stringify: postcss.stringify, | ||
}; | ||
|
||
if ( | ||
customSyntax && | ||
typeof customSyntax === 'object' && | ||
typeof customSyntax.parse == 'function' && | ||
typeof customSyntax.stringify == 'function' | ||
) { | ||
return customSyntax; | ||
} | ||
|
||
throw new Error( | ||
`Provided customSyntax is invalid. You must provide an object containing 'parse' and 'stringify' methods. TODO docs link?`, | ||
); | ||
} | ||
|
||
module.exports = { lint }; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
'use strict'; | ||
|
||
/* eslint-disable node/no-extraneous-require */ | ||
|
||
const bundleReport = require('@parcel/reporter-cli/lib/bundleReport').default; | ||
const defaultConfigContents = require('@parcel/config-default'); | ||
const defaultConfigFilePath = require.resolve('@parcel/config-default'); | ||
const Parcel = require('@parcel/core').default; | ||
const { createWorkerFarm } = require('@parcel/core'); | ||
|
||
/* eslint-enable node/no-extraneous-require */ | ||
|
||
// TODO: maybe it's worth verifying that all syntaxes are bundled? | ||
// Though this is unlikely to change very often. | ||
|
||
const config = { | ||
browser: { | ||
target: { distDir: 'dist' }, | ||
entry: 'lib/core-entrypoint.js', | ||
}, | ||
'syntax-css-in-js': { | ||
target: { distDir: 'dist' }, | ||
entry: 'lib/syntaxes/syntax-css-in-js.js', | ||
}, | ||
'syntax-html': { | ||
target: { distDir: 'dist' }, | ||
entry: 'lib/syntaxes/syntax-html.js', | ||
}, | ||
'syntax-less': { | ||
target: { distDir: 'dist' }, | ||
entry: 'lib/syntaxes/syntax-less.js', | ||
}, | ||
'syntax-markdown': { | ||
target: { distDir: 'dist' }, | ||
entry: 'lib/syntaxes/syntax-markdown.js', | ||
}, | ||
'syntax-sass': { | ||
target: { distDir: 'dist' }, | ||
entry: 'lib/syntaxes/syntax-sass.js', | ||
}, | ||
'syntax-scss': { | ||
target: { distDir: 'dist' }, | ||
entry: 'lib/syntaxes/syntax-scss.js', | ||
}, | ||
'syntax-sugarss': { | ||
target: { distDir: 'dist' }, | ||
entry: 'lib/syntaxes/syntax-sugarss.js', | ||
}, | ||
}; | ||
|
||
// Workers have a startup cost. We can keep the workers around between runs, | ||
// then shut them down when all bundles have been created. | ||
let workerFarm = createWorkerFarm(); | ||
|
||
let tasks = []; | ||
|
||
// eslint-disable-next-line guard-for-in -- meh | ||
for (const module in config) { | ||
let task = async () => { | ||
let bundler = new Parcel({ | ||
entries: config[module].entry, | ||
targets: { [module]: config[module].target }, | ||
defaultConfig: { | ||
...defaultConfigContents, | ||
filePath: defaultConfigFilePath, | ||
}, | ||
defaultEngines: { | ||
browsers: ['> 0.25%'], | ||
}, | ||
includeNodeModules: true, | ||
isLibrary: false, | ||
logLevel: 'warn', | ||
minify: true, | ||
mode: 'production', | ||
outputFormat: 'esmodule', | ||
patchConsole: false, | ||
workerFarm, | ||
}); | ||
|
||
const bundleGraph = await bundler.run(); | ||
const options = bundler._getResolvedParcelOptions(); // hackety hack. Not a public API | ||
|
||
// log stats to console. This is similar to setting `logLevel: verbose`, but skips the progress spinner to avoid unnecessary output | ||
await bundleReport(bundleGraph, options.outputFS, options.projectRoot, options.detailedReport); | ||
|
||
return bundleGraph; | ||
}; | ||
|
||
tasks.push(task); | ||
} | ||
|
||
(async () => { | ||
try { | ||
for (const task of tasks) { | ||
await task(); | ||
} | ||
} catch (error) { | ||
console.error(error); // eslint-disable-line no-console | ||
} finally { | ||
await workerFarm.end(); // finished bundling, so we can shut the farm. | ||
} | ||
})(); |