Skip to content

Commit 32a2ccc

Browse files
authored
postcss-preset-env : array options (#1304)
1 parent 6417097 commit 32a2ccc

File tree

15 files changed

+594
-143
lines changed

15 files changed

+594
-143
lines changed
Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
11
import assert from 'assert';
22
import plugin from 'postcss-preset-env';
3-
plugin({ preserve: true });
3+
plugin({
4+
preserve: true,
5+
features: {
6+
'all-property': [true, { preserve: true }],
7+
'any-link-pseudo-class': [false, { preserve: true }],
8+
'cascade-layers': ['auto', { onImportLayerRule: 'warn' }],
9+
'color-function': { preserve: true, enableProgressiveCustomProperties: false },
10+
'color-mix': false,
11+
'light-dark-function': true,
12+
},
13+
});
414

515
assert.ok(plugin.postcss, 'should have "postcss flag"');
616
assert.equal(typeof plugin, 'function', 'should return a function');

plugin-packs/postcss-preset-env/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# Changes to PostCSS Preset Env
22

3-
### Unreleased (patch)
3+
### Unreleased (minor)
44

5+
- Add support for array options, e.g. `{ 'nesting-rules': ['auto', { noIsPseudoSelector: false }] }`
56
- Updated [`@csstools/postcss-gradients-interpolation-method`](https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-gradients-interpolation-method) to [`4.0.11`](https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-gradients-interpolation-method/CHANGELOG.md#4011) (patch)
67
- Updated [`postcss-nesting`](https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-nesting) to [`12.0.4`](https://github.com/csstools/postcss-plugins/tree/main/plugins/postcss-nesting/CHANGELOG.md#1204) (patch)
78

plugin-packs/postcss-preset-env/README.md

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ const yourConfig = {
2828
postcssPresetEnv({
2929
/* pluginOptions */
3030
features: {
31-
'nesting-rules': {
31+
'nesting-rules': ['auto', {
3232
noIsPseudoSelector: false,
33-
},
33+
}],
3434
},
3535
})
3636
]
@@ -266,6 +266,20 @@ postcssPresetEnv({
266266
})
267267
```
268268

269+
If you want to preserve automatic enabling of features
270+
based on the stage, implementations and or browserslist,
271+
you can pass an array: `['auto', { /* plugin options */ }]`.
272+
273+
```js
274+
postcssPresetEnv({
275+
/* use stage 3 features + custom-selectors (preserving the original CSS) */
276+
stage: 3,
277+
features: {
278+
'custom-selectors': ['auto', { preserve: true }]
279+
}
280+
})
281+
```
282+
269283
Any polyfills not explicitly enabled or disabled through `features` are
270284
determined by the [`stage`](#stage) option.
271285

plugin-packs/postcss-preset-env/dist/index.cjs

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

plugin-packs/postcss-preset-env/dist/index.d.ts

Lines changed: 59 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -149,119 +149,119 @@ export declare type pluginOptions = {
149149

150150
export declare type pluginsOptions = {
151151
/** plugin options for "@csstools/postcss-initial" */
152-
'all-property'?: pluginOptions_2 | boolean;
152+
'all-property'?: subPluginOptions<pluginOptions_2>;
153153
/** plugin options for "postcss-pseudo-class-any-link" */
154-
'any-link-pseudo-class'?: pluginOptions_3 | boolean;
154+
'any-link-pseudo-class'?: subPluginOptions<pluginOptions_3>;
155155
/** plugin options for "css-blank-pseudo" */
156-
'blank-pseudo-class'?: pluginOptions_4 | boolean;
156+
'blank-pseudo-class'?: subPluginOptions<pluginOptions_4>;
157157
/** plugin options for "postcss-page-break" */
158-
'break-properties'?: postcssPageBreakOptions | boolean;
158+
'break-properties'?: subPluginOptions<postcssPageBreakOptions>;
159159
/** plugin options for "@csstools/postcss-cascade-layers" */
160-
'cascade-layers'?: pluginOptions_5 | boolean;
160+
'cascade-layers'?: subPluginOptions<pluginOptions_5>;
161161
/** plugin options for "postcss-attribute-case-insensitive" */
162-
'case-insensitive-attributes'?: pluginOptions_6 | boolean;
162+
'case-insensitive-attributes'?: subPluginOptions<pluginOptions_6>;
163163
/** plugin options for "postcss-clamp" */
164-
'clamp'?: postcssClampOptions | boolean;
164+
'clamp'?: subPluginOptions<postcssClampOptions>;
165165
/** plugin options for "@csstools/postcss-color-function" */
166-
'color-function'?: pluginOptions_7 | boolean;
166+
'color-function'?: subPluginOptions<pluginOptions_7>;
167167
/** plugin options for "postcss-color-functional-notation" */
168-
'color-functional-notation'?: pluginOptions_8 | boolean;
168+
'color-functional-notation'?: subPluginOptions<pluginOptions_8>;
169169
/** plugin options for "@csstools/postcss-color-mix-function" */
170-
'color-mix'?: pluginOptions_9 | boolean;
170+
'color-mix'?: subPluginOptions<pluginOptions_9>;
171171
/** plugin options for "postcss-custom-media" */
172-
'custom-media-queries'?: pluginOptions_10 | boolean;
172+
'custom-media-queries'?: subPluginOptions<pluginOptions_10>;
173173
/** plugin options for "postcss-custom-properties" */
174-
'custom-properties'?: pluginOptions_11 | boolean;
174+
'custom-properties'?: subPluginOptions<pluginOptions_11>;
175175
/** plugin options for "postcss-custom-selectors" */
176-
'custom-selectors'?: pluginOptions_12 | boolean;
176+
'custom-selectors'?: subPluginOptions<pluginOptions_12>;
177177
/** plugin options for "postcss-dir-pseudo-class" */
178-
'dir-pseudo-class'?: pluginOptions_13 | boolean;
178+
'dir-pseudo-class'?: subPluginOptions<pluginOptions_13>;
179179
/** plugin options for "@csstools/postcss-normalize-display-values" */
180-
'display-two-values'?: pluginOptions_14 | boolean;
180+
'display-two-values'?: subPluginOptions<pluginOptions_14>;
181181
/** plugin options for "postcss-double-position-gradients" */
182-
'double-position-gradients'?: pluginOptions_15 | boolean;
182+
'double-position-gradients'?: subPluginOptions<pluginOptions_15>;
183183
/** plugin options for "@csstools/postcss-exponential-functions" */
184-
'exponential-functions'?: pluginOptions_16 | boolean;
184+
'exponential-functions'?: subPluginOptions<pluginOptions_16>;
185185
/** plugin options for "@csstools/postcss-logical-float-and-clear" */
186-
'float-clear-logical-values'?: pluginOptions_17 | boolean;
186+
'float-clear-logical-values'?: subPluginOptions<pluginOptions_17>;
187187
/** plugin options for "postcss-focus-visible" */
188-
'focus-visible-pseudo-class'?: pluginOptions_18 | boolean;
188+
'focus-visible-pseudo-class'?: subPluginOptions<pluginOptions_18>;
189189
/** plugin options for "postcss-focus-within" */
190-
'focus-within-pseudo-class'?: pluginOptions_19 | boolean;
190+
'focus-within-pseudo-class'?: subPluginOptions<pluginOptions_19>;
191191
/** plugin options for "@csstools/postcss-font-format-keywords" */
192-
'font-format-keywords'?: pluginOptions_20 | boolean;
192+
'font-format-keywords'?: subPluginOptions<pluginOptions_20>;
193193
/** plugin options for "postcss-font-variant" */
194-
'font-variant-property'?: postcssFontVariantOptions | boolean;
194+
'font-variant-property'?: subPluginOptions<postcssFontVariantOptions>;
195195
/** plugin options for "@csstools/postcss-gamut-mapping" */
196-
'gamut-mapping'?: pluginOptions_21 | boolean;
196+
'gamut-mapping'?: subPluginOptions<pluginOptions_21>;
197197
/** plugin options for "postcss-gap-properties" */
198-
'gap-properties'?: pluginOptions_22 | boolean;
198+
'gap-properties'?: subPluginOptions<pluginOptions_22>;
199199
/** plugin options for "@csstools/postcss-gradients-interpolation-method" */
200-
'gradients-interpolation-method'?: pluginOptions_23 | boolean;
200+
'gradients-interpolation-method'?: subPluginOptions<pluginOptions_23>;
201201
/** plugin options for "css-has-pseudo" */
202-
'has-pseudo-class'?: pluginOptions_24 | boolean;
202+
'has-pseudo-class'?: subPluginOptions<pluginOptions_24>;
203203
/** plugin options for "postcss-color-hex-alpha" */
204-
'hexadecimal-alpha-notation'?: pluginOptions_25 | boolean;
204+
'hexadecimal-alpha-notation'?: subPluginOptions<pluginOptions_25>;
205205
/** plugin options for "@csstools/postcss-hwb-function" */
206-
'hwb-function'?: pluginOptions_26 | boolean;
206+
'hwb-function'?: subPluginOptions<pluginOptions_26>;
207207
/** plugin options for "@csstools/postcss-ic-unit" */
208-
'ic-unit'?: pluginOptions_27 | boolean;
208+
'ic-unit'?: subPluginOptions<pluginOptions_27>;
209209
/** plugin options for "postcss-image-set-function" */
210-
'image-set-function'?: pluginOptions_28 | boolean;
210+
'image-set-function'?: subPluginOptions<pluginOptions_28>;
211211
/** plugin options for "@csstools/postcss-is-pseudo-class" */
212-
'is-pseudo-class'?: pluginOptions_29 | boolean;
212+
'is-pseudo-class'?: subPluginOptions<pluginOptions_29>;
213213
/** plugin options for "postcss-lab-function" */
214-
'lab-function'?: pluginOptions_30 | boolean;
214+
'lab-function'?: subPluginOptions<pluginOptions_30>;
215215
/** plugin options for "@csstools/postcss-light-dark-function" */
216-
'light-dark-function'?: pluginOptions_31 | boolean;
216+
'light-dark-function'?: subPluginOptions<pluginOptions_31>;
217217
/** plugin options for "@csstools/postcss-logical-overflow" */
218-
'logical-overflow'?: pluginOptions_32 | boolean;
218+
'logical-overflow'?: subPluginOptions<pluginOptions_32>;
219219
/** plugin options for "@csstools/postcss-logical-overscroll-behavior" */
220-
'logical-overscroll-behavior'?: pluginOptions_33 | boolean;
220+
'logical-overscroll-behavior'?: subPluginOptions<pluginOptions_33>;
221221
/** plugin options for "postcss-logical" */
222-
'logical-properties-and-values'?: pluginOptions_34 | boolean;
222+
'logical-properties-and-values'?: subPluginOptions<pluginOptions_34>;
223223
/** plugin options for "@csstools/postcss-logical-resize" */
224-
'logical-resize'?: pluginOptions_35 | boolean;
224+
'logical-resize'?: subPluginOptions<pluginOptions_35>;
225225
/** plugin options for "@csstools/postcss-logical-viewport-units" */
226-
'logical-viewport-units'?: pluginOptions_36 | boolean;
226+
'logical-viewport-units'?: subPluginOptions<pluginOptions_36>;
227227
/** plugin options for "@csstools/postcss-media-queries-aspect-ratio-number-values" */
228-
'media-queries-aspect-ratio-number-values'?: pluginOptions_37 | boolean;
228+
'media-queries-aspect-ratio-number-values'?: subPluginOptions<pluginOptions_37>;
229229
/** plugin options for "@csstools/postcss-media-minmax" */
230-
'media-query-ranges'?: pluginOptions_38 | boolean;
230+
'media-query-ranges'?: subPluginOptions<pluginOptions_38>;
231231
/** plugin options for "@csstools/postcss-nested-calc" */
232-
'nested-calc'?: pluginOptions_39 | boolean;
232+
'nested-calc'?: subPluginOptions<pluginOptions_39>;
233233
/** plugin options for "postcss-nesting" */
234-
'nesting-rules'?: pluginOptions_40 | boolean;
234+
'nesting-rules'?: subPluginOptions<pluginOptions_40>;
235235
/** plugin options for "postcss-selector-not" */
236-
'not-pseudo-class'?: pluginOptions_41 | boolean;
236+
'not-pseudo-class'?: subPluginOptions<pluginOptions_41>;
237237
/** plugin options for "@csstools/postcss-oklab-function" */
238-
'oklab-function'?: pluginOptions_42 | boolean;
238+
'oklab-function'?: subPluginOptions<pluginOptions_42>;
239239
/** plugin options for "postcss-opacity-percentage" */
240-
'opacity-percentage'?: postcssOpacityPercentageOptions | boolean;
240+
'opacity-percentage'?: subPluginOptions<postcssOpacityPercentageOptions>;
241241
/** plugin options for "postcss-overflow-shorthand" */
242-
'overflow-property'?: pluginOptions_43 | boolean;
242+
'overflow-property'?: subPluginOptions<pluginOptions_43>;
243243
/** plugin options for "postcss-replace-overflow-wrap" */
244-
'overflow-wrap-property'?: postcssReplaceOverflowWrapOptions | boolean;
244+
'overflow-wrap-property'?: subPluginOptions<postcssReplaceOverflowWrapOptions>;
245245
/** plugin options for "postcss-place" */
246-
'place-properties'?: pluginOptions_44 | boolean;
246+
'place-properties'?: subPluginOptions<pluginOptions_44>;
247247
/** plugin options for "css-prefers-color-scheme" */
248-
'prefers-color-scheme-query'?: pluginOptions_45 | boolean;
248+
'prefers-color-scheme-query'?: subPluginOptions<pluginOptions_45>;
249249
/** plugin options for "postcss-color-rebeccapurple" */
250-
'rebeccapurple-color'?: pluginOptions_46 | boolean;
250+
'rebeccapurple-color'?: subPluginOptions<pluginOptions_46>;
251251
/** plugin options for "@csstools/postcss-relative-color-syntax" */
252-
'relative-color-syntax'?: pluginOptions_47 | boolean;
252+
'relative-color-syntax'?: subPluginOptions<pluginOptions_47>;
253253
/** plugin options for "@csstools/postcss-scope-pseudo-class" */
254-
'scope-pseudo-class'?: pluginOptions_48 | boolean;
254+
'scope-pseudo-class'?: subPluginOptions<pluginOptions_48>;
255255
/** plugin options for "@csstools/postcss-stepped-value-functions" */
256-
'stepped-value-functions'?: pluginOptions_49 | boolean;
256+
'stepped-value-functions'?: subPluginOptions<pluginOptions_49>;
257257
/** plugin options for "postcss-system-ui-font-family" */
258-
'system-ui-font-family'?: postcssFontFamilySystemUIOptions | boolean;
258+
'system-ui-font-family'?: subPluginOptions<postcssFontFamilySystemUIOptions>;
259259
/** plugin options for "@csstools/postcss-text-decoration-shorthand" */
260-
'text-decoration-shorthand'?: pluginOptions_50 | boolean;
260+
'text-decoration-shorthand'?: subPluginOptions<pluginOptions_50>;
261261
/** plugin options for "@csstools/postcss-trigonometric-functions" */
262-
'trigonometric-functions'?: pluginOptions_51 | boolean;
262+
'trigonometric-functions'?: subPluginOptions<pluginOptions_51>;
263263
/** plugin options for "@csstools/postcss-unset-value" */
264-
'unset-value'?: pluginOptions_52 | boolean;
264+
'unset-value'?: subPluginOptions<pluginOptions_52>;
265265
};
266266

267267
/** postcss-clamp plugin options */
@@ -296,4 +296,6 @@ export declare type postcssReplaceOverflowWrapOptions = {
296296
preserve?: boolean;
297297
};
298298

299+
export declare type subPluginOptions<T> = ['auto' | boolean, T] | T | boolean;
300+
299301
export { }

plugin-packs/postcss-preset-env/dist/index.mjs

Lines changed: 1 addition & 1 deletion
Large diffs are not rendered by default.

plugin-packs/postcss-preset-env/scripts/generate-plugins-data.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,12 +44,13 @@ function generatePluginOptions(data) {
4444
}
4545
}
4646

47+
result += '\nexport type subPluginOptions<T> = [\'auto\' | boolean, T] | T | boolean;\n';
4748
result += '\nexport type pluginsOptions = {\n';
4849

4950
for (let i = 0; i < plugins.length; i++) {
5051
const plugin = plugins[i];
5152
result += `\t/** plugin options for "${plugin.packageName}" */\n`;
52-
result += `\t'${plugin.id}'?: ${plugin.importName}Options | boolean\n`;
53+
result += `\t'${plugin.id}'?: subPluginOptions<${plugin.importName}Options>\n`;
5354
}
5455

5556
result += '};\n';

plugin-packs/postcss-preset-env/src/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import { pluginIdHelp } from './plugins/plugin-id-help.mjs';
88
import type { pluginOptions } from './options';
99
import type { PluginCreator } from 'postcss';
1010
export type { pluginOptions, DirectionFlow } from './options';
11-
export type { pluginsOptions } from './plugins/plugins-options';
11+
export type { pluginsOptions, subPluginOptions } from './plugins/plugins-options';
1212
export type { postcssClampOptions } from './types/postcss-clamp/plugin-options';
1313
export type { postcssFontFamilySystemUIOptions } from './types/postcss-system-ui-font-family/plugin-options';
1414
export type { postcssFontVariantOptions } from './types/postcss-font-variant/plugin-options';

plugin-packs/postcss-preset-env/src/lib/format-feature.mjs

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -39,16 +39,10 @@ export function formatStagedFeature(cssdbList, supportedBrowsers, features, feat
3939

4040
pluginOption = getOptionsForBrowsersByFeature(supportedBrowsers, feature, cssdbList, options, logger);
4141

42-
if (features[feature.id] === true) {
43-
if (sharedOptions) {
44-
pluginOption = Object.assign({}, pluginOption, sharedOptions);
45-
}
42+
if (sharedOptions) {
43+
pluginOption = Object.assign({}, pluginOption, sharedOptions, featureOptions(features, feature.id));
4644
} else {
47-
if (sharedOptions) {
48-
pluginOption = Object.assign({}, pluginOption, sharedOptions, features[feature.id]);
49-
} else {
50-
pluginOption = Object.assign({}, pluginOption, features[feature.id]);
51-
}
45+
pluginOption = Object.assign({}, pluginOption, featureOptions(features, feature.id));
5246
}
5347

5448
// postcss-preset-env : option overrides
@@ -77,3 +71,16 @@ export function formatStagedFeature(cssdbList, supportedBrowsers, features, feat
7771
id: feature.id,
7872
};
7973
}
74+
75+
function featureOptions(features, featureId) {
76+
if (!(featureId in features)) {
77+
return undefined;
78+
}
79+
80+
const value = features[featureId];
81+
if (Array.isArray(value)) {
82+
return value[1];
83+
}
84+
85+
return value;
86+
}

plugin-packs/postcss-preset-env/src/lib/list-features.mjs

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ export function listFeatures(cssdbList, options, sharedOptions, logger) {
6262
return true;
6363
}
6464

65-
if (features[feature.id]) {
65+
if (featureEnabledByOptions(features, feature.id) === true) {
6666
// feature is explicitly enabled
6767
logger.log(` ${feature.id} does not meet the required vendor implementations but has been enabled by options`);
6868
return true;
@@ -86,8 +86,9 @@ export function listFeatures(cssdbList, options, sharedOptions, logger) {
8686
// TODO : this filter needs to be split up.
8787
const isAllowedStage = feature.stage >= stage;
8888
const isAllowedByType = enableClientSidePolyfills || !featuresWithClientSide.includes(feature.id);
89-
const isDisabled = features[feature.id] === false;
90-
const isAllowedFeature = features[feature.id] ? features[feature.id] : isAllowedStage && isAllowedByType;
89+
const enabledByOptions = featureEnabledByOptions(features, feature.id);
90+
const isDisabled = enabledByOptions === false;
91+
const isAllowedFeature = enabledByOptions === true ? true : isAllowedStage && isAllowedByType;
9192

9293
if (isDisabled) {
9394
logger.log(` ${feature.id} has been disabled by options`);
@@ -101,7 +102,7 @@ export function listFeatures(cssdbList, options, sharedOptions, logger) {
101102
logger.log(` ${feature.id} has been disabled by "enableClientSidePolyfills: false".`);
102103
}
103104

104-
return isAllowedFeature;
105+
return !isDisabled && isAllowedFeature;
105106
}).map((feature) => {
106107
return formatStagedFeature(cssdbList, supportedBrowsers, features, feature, sharedOptions, options, logger);
107108
});
@@ -114,8 +115,9 @@ export function listFeatures(cssdbList, options, sharedOptions, logger) {
114115
return true;
115116
}
116117

117-
if (feature.id in features) {
118-
return features[feature.id];
118+
const enabledByOptions = featureEnabledByOptions(features, feature.id);
119+
if (enabledByOptions === true || enabledByOptions === false) {
120+
return enabledByOptions;
119121
}
120122

121123
const unsupportedBrowsers = browserslist(feature.browsers, {
@@ -135,3 +137,24 @@ export function listFeatures(cssdbList, options, sharedOptions, logger) {
135137

136138
return supportedFeatures;
137139
}
140+
141+
function featureEnabledByOptions(features, featureId) {
142+
if (!(featureId in features)) {
143+
return 'auto';
144+
}
145+
146+
const value = features[featureId];
147+
if (Array.isArray(value)) {
148+
if (value[0] === true) {
149+
return true;
150+
}
151+
152+
if (value[0] === false) {
153+
return false;
154+
}
155+
156+
return 'auto';
157+
}
158+
159+
return Boolean(value);
160+
}

plugin-packs/postcss-preset-env/src/patch/postcss-system-ui-font-family.mjs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,15 @@ export default function postcssSystemUiFont() {
22
return {
33
postcssPlugin: 'postcss-system-ui-font',
44
Declaration(/** @type {import('postcss').Declaration} */ node) {
5-
if (PROPERTY_REGEX.test(node.prop)) {
6-
if (!node.value.includes(systemUIFamilies)) {
7-
node.value = node.value.replace(SYSTEM_UI_MATCH, systemUiReplace);
8-
}
5+
if (!PROPERTY_REGEX.test(node.prop)) {
6+
return;
97
}
8+
9+
if (node.value.includes(systemUIFamilies)) {
10+
return;
11+
}
12+
13+
node.value = node.value.replace(SYSTEM_UI_MATCH, systemUiReplace);
1014
},
1115
};
1216
}

0 commit comments

Comments
 (0)