Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/unlucky-roses-try.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@shopify/polaris-migrator': minor
---

Internally setup stylelint metadata for SASS migrations in preparation for switching to stylelint as our migration runner.
49 changes: 43 additions & 6 deletions polaris-migrator/src/utilities/sass.ts
Original file line number Diff line number Diff line change
Expand Up @@ -258,16 +258,38 @@ interface PluginOptions extends Options, NamespaceOptions {}
interface PluginContext {
fix: boolean;
}

// Extracted from stylelint
type StylelintRuleBase<P = any, S = any> = (
primaryOption: P,
secondaryOptions: {[key: string]: S},
context: PluginContext,
) => (root: Root, result: Result) => void;

interface StylelintRuleMeta {
url: string;
deprecated?: boolean;
fixable?: boolean;
}

type StylelintRule<P = any, S = any> = StylelintRuleBase<P, S> & {
ruleName: string;
meta?: StylelintRuleMeta;
};
// End: Extracted from stylelint

export type PolarisMigrator = (
primaryOption: true,
secondaryOptions: PluginOptions,
context: PluginContext,
) => (root: Root, result: Result) => void;

export function createSassMigrator(name: string, ruleFn: PolarisMigrator) {
// Expose a stylelint-like API for creating sass migrators so we can easily
// migrate to that tool in the future.
function convertStylelintRuleToPostcssProcessor(ruleFn: StylelintRule) {
return (fileInfo: FileInfo, _: API, options: Options) => {
const plugin: Plugin = {
postcssPlugin: name,
postcssPlugin: ruleFn.ruleName,
// PostCSS will rewalk the AST every time a declaration/rule/etc is
// mutated by a plugin. This can be useful in some cases, but in ours we
// only want single-pass behaviour.
Expand All @@ -278,12 +300,14 @@ export function createSassMigrator(name: string, ruleFn: PolarisMigrator) {
// subsequent passes.
// 2) Using postcss's Once() plugin callback.
//
// We're going with the Once() callback as it's idomatic PostCSS.
// stylelint also uses `Once()`, so we're able to remove this once we've
// migrated:
// https://github.com/stylelint/stylelint/blob/cb425cb/lib/postcssPlugin.js#L22
Once(root, {result}) {
// NOTE: For fullest compatibility with stylelint, we initialise the
// rule here _inside_ the postcss Once function so multiple passes can
// be performed without rules accidentally retaining scoped variables,
// etc.
// rule here _inside_ the postcss Once function just like stylelint
// does. This means multiple passes can be performed without rules
// accidentally retaining scoped variables, etc.
ruleFn(
// Normally, this comes from stylelint config, but for this shim we
// just hard-code it, and instead rely on the "seconary" options
Expand All @@ -301,3 +325,16 @@ export function createSassMigrator(name: string, ruleFn: PolarisMigrator) {
}).css;
};
}

export function createSassMigrator(name: string, ruleFn: PolarisMigrator) {
const wrappedRule = ruleFn as StylelintRule;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This gives us a logical point to inject further functionality (see the next PR where we also shim stylelint's report() method)


wrappedRule.ruleName = name;
wrappedRule.meta = {
// TODO: link directly to the specific rule
url: 'https://www.npmjs.com/package/@shopify/stylelint-polaris',
fixable: true,
};

return convertStylelintRuleToPostcssProcessor(wrappedRule);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By splitting the shim out into its own function, the entire convertStylelintRuleToPostcssProcessor can be deleted once we're running on stylelint, and this simplified to:

-  return convertStylelintRuleToPostcssProcessor(wrappedRule);
+  return wrappedRule;

Without any changes to any of the migrations 🎉

}