postcss-sort-media-queries 5.2.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -15,7 +15,7 @@
15
15
 
16
16
  [PostCSS] plugin for sorting and combining CSS media queries with **mobile first** / **desktop first** methodologies.
17
17
 
18
- > From 5.0.0 plugin support [Media Feature Types: “range”](https://www.w3.org/TR/mediaqueries-4/#mq-ranges)
18
+ > From v6.0.0 plugin supported nested media queries and ESM usage
19
19
 
20
20
  ## Table of Contents
21
21
 
@@ -43,52 +43,49 @@ And here is the [online demo](https://postcss-sort-media-queries.github.io)
43
43
 
44
44
  ### Mobile first sorting
45
45
 
46
- **before**
46
+ **Before**
47
47
 
48
48
  ```css
49
- @media screen and (max-width: 640px) {
50
- .head { color: #cfcfcf }
51
- }
52
- @media screen and (max-width: 768px) {
53
- .footer { color: #cfcfcf }
54
- }
55
- @media screen and (max-width: 640px) {
56
- .main { color: #cfcfcf }
57
- }
58
- @media screen and (min-width: 1280px) {
59
- .mobile-first { color: #cfcfcf }
60
- }
61
- @media screen and (width > 640px) {
62
- .mobile-first { color: #cfcfcf }
63
- }
64
- @media screen and (max-width: 640px) {
65
- .footer { color: #cfcfcf }
49
+ @media (min-width: 1400px) {}
50
+ @media (min-width: 1200px) {}
51
+
52
+ @layer reset {
53
+
54
+ @media (min-width: 1200px) {
55
+ @media (min-width: 992px) {}
56
+ @media (min-width: 768px) {}
57
+ }
58
+
59
+ @media (min-width: 768px) {
60
+ @media (min-width: 640px) {}
61
+ @media (min-width: 320px) {}
62
+ }
66
63
  }
67
64
  ```
68
65
 
69
- **after**
66
+ **After**
70
67
 
71
68
  ```css
72
- @media screen and (width > 640px) {
73
- .mobile-first { color: #cfcfcf }
74
- }
75
- @media screen and (min-width: 1280px) {
76
- .mobile-first { color: #cfcfcf }
77
- }
78
- @media screen and (max-width: 768px) {
79
- .footer { color: #cfcfcf }
80
- }
81
- @media screen and (max-width: 640px) {
82
- /* combined */
83
- .head { color: #cfcfcf }
84
- .main { color: #cfcfcf }
85
- .footer { color: #cfcfcf }
69
+ @layer reset {
70
+
71
+ @media (min-width: 768px) {
72
+ @media (min-width: 320px) {}
73
+ @media (min-width: 640px) {}
74
+ }
75
+
76
+ @media (min-width: 1200px) {
77
+ @media (min-width: 768px) {}
78
+ @media (min-width: 992px) {}
79
+ }
86
80
  }
81
+
82
+ @media (min-width: 1200px) {}
83
+ @media (min-width: 1400px) {}
87
84
  ```
88
85
 
89
86
  ### Desktop first sorting
90
87
 
91
- **before**
88
+ **Before**
92
89
  ```css
93
90
  @media screen and (width < 640px) {
94
91
  .header { color: #cdcdcd }
@@ -110,7 +107,7 @@ And here is the [online demo](https://postcss-sort-media-queries.github.io)
110
107
  }
111
108
  ```
112
109
 
113
- **after**
110
+ **After**
114
111
 
115
112
  ```css
116
113
  @media screen and (max-width: 760px) {
@@ -144,6 +141,15 @@ Check you project for existed PostCSS config: `postcss.config.js`
144
141
  in the project root, `"postcss"` section in `package.json`
145
142
  or `postcss` in bundle config.
146
143
 
144
+
145
+ ```js
146
+ // CJS
147
+ let sortCssMq = require('postcss-sort-media-queries');
148
+
149
+ // ESM
150
+ import sortCssMq from 'postcss-sort-media-queries';
151
+ ```
152
+
147
153
  If you already use PostCSS, add the plugin to plugins list:
148
154
 
149
155
  ```diff
@@ -176,7 +182,7 @@ and set this plugin in settings.
176
182
 
177
183
  ## Options
178
184
 
179
- > Sorting works based on [dutchenkoOleg/sort-css-media-queries](https://github.com/dutchenkoOleg/sort-css-media-queries) function.
185
+ > Sorting works based on [OlehDutchenko/sort-css-media-queries](https://github.com/OlehDutchenko/sort-css-media-queries) function.
180
186
 
181
187
  ### sort
182
188
 
@@ -237,18 +243,6 @@ postcss([
237
243
 
238
244
  Or alternatively create a `sort-css-mq.config.json` file in the root of your project. Or add property `sortCssMQ: {}` in your `package.json`.
239
245
 
240
- ### Only Top Level
241
-
242
- Sort only top level media queries to prevent eject nested media queries from parent node
243
-
244
- ```js
245
- postcss([
246
- sortMediaQueries({
247
- onlyTopLevel: true,
248
- })
249
- ]).process(css);
250
- ```
251
-
252
246
  ---
253
247
 
254
248
  ## Changelog
@@ -266,7 +260,7 @@ See [Releases history]
266
260
  ## Thanks
267
261
 
268
262
  - Andrey Sitnik [@ai](https://github.com/ai)
269
- - Oleh Dutchenko [@dutchenkoOleg](https://github.com/dutchenkoOleg)
263
+ - Oleh Dutchenko [@dutchenkoOleg](https://github.com/OlehDutchenko)
270
264
  - Jakub Caban [@Lustmored](https://github.com/Lustmored)
271
265
  - Dmytro Symonov [@Kassaila](https://github.com/Kassaila)
272
266
  - Kai Falkowski [@SassNinja](https://github.com/SassNinja)
@@ -0,0 +1,311 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+
19
+ // src/index.js
20
+ var index_exports = {};
21
+ __export(index_exports, {
22
+ default: () => index_default
23
+ });
24
+ module.exports = __toCommonJS(index_exports);
25
+
26
+ // node_modules/sort-css-media-queries/lib/create-sort.js
27
+ var minMaxWidth = /(!?\(\s*min(-device)?-width)(.|\n)+\(\s*max(-device)?-width|\(\s*width\s*>(=)?(.|\n)+\(\s*width\s*<(=)?|(!?\(.*<(=)?\s*width\s*<(=)?)/i;
28
+ var minWidth = /\(\s*min(-device)?-width|\(\s*width\s*>(=)?/i;
29
+ var maxMinWidth = /(!?\(\s*max(-device)?-width)(.|\n)+\(\s*min(-device)?-width|\(\s*width\s*<(=)?(.|\n)+\(\s*width\s*>(=)?|(!?\(.*>(=)?\s*width\s*>(=)?)/i;
30
+ var maxWidth = /\(\s*max(-device)?-width|\(\s*width\s*<(=)?/i;
31
+ var isMinWidth = _testQuery(minMaxWidth, maxMinWidth, minWidth);
32
+ var isMaxWidth = _testQuery(maxMinWidth, minMaxWidth, maxWidth);
33
+ var minMaxHeight = /(!?\(\s*min(-device)?-height)(.|\n)+\(\s*max(-device)?-height|\(\s*height\s*>(=)?(.|\n)+\(\s*height\s*<(=)?|(!?\(.*<(=)?\s*height\s*<(=)?)/i;
34
+ var minHeight = /\(\s*min(-device)?-height|\(\s*height\s*>(=)?/i;
35
+ var maxMinHeight = /(!?\(\s*max(-device)?-height)(.|\n)+\(\s*min(-device)?-height|\(\s*height\s*<(=)?(.|\n)+\(\s*height\s*>(=)?|(!?\(.*>(=)?\s*height\s*>(=)?)/i;
36
+ var maxHeight = /\(\s*max(-device)?-height|\(\s*height\s*<(=)?/i;
37
+ var isMinHeight = _testQuery(minMaxHeight, maxMinHeight, minHeight);
38
+ var isMaxHeight = _testQuery(maxMinHeight, minMaxHeight, maxHeight);
39
+ var lessThan = /<(?!=)/;
40
+ var grtrThan = />(?!=)/;
41
+ var isPrint = /print/i;
42
+ var isPrintOnly = /^print$/i;
43
+ var maxValue = Number.MAX_VALUE;
44
+ function _getQueryLength(query) {
45
+ let length = /(-?\d*\.?\d+)(ch|em|ex|px|rem)/.exec(query);
46
+ if (length === null && (isMinWidth(query) || isMinHeight(query))) {
47
+ length = /(\d)/.exec(query);
48
+ }
49
+ if (length === "0") {
50
+ return 0;
51
+ }
52
+ if (length === null) {
53
+ return maxValue;
54
+ }
55
+ let number = length[1];
56
+ const unit = length[2];
57
+ switch (unit) {
58
+ case "ch":
59
+ number = parseFloat(number) * 8.8984375;
60
+ break;
61
+ case "em":
62
+ case "rem":
63
+ number = parseFloat(number) * 16;
64
+ break;
65
+ case "ex":
66
+ number = parseFloat(number) * 8.296875;
67
+ break;
68
+ case "px":
69
+ number = parseFloat(number);
70
+ break;
71
+ }
72
+ return +number;
73
+ }
74
+ function _testQuery(doubleTestTrue, doubleTestFalse, singleTest) {
75
+ return function(query) {
76
+ let result;
77
+ if (doubleTestTrue.test(query)) result = true;
78
+ else if (doubleTestFalse.test(query)) result = false;
79
+ else result = singleTest.test(query);
80
+ return query.includes("not") ? !result : result;
81
+ };
82
+ }
83
+ function _testIsPrint(a, b) {
84
+ const isPrintA = isPrint.test(a);
85
+ const isPrintOnlyA = isPrintOnly.test(a);
86
+ const isPrintB = isPrint.test(b);
87
+ const isPrintOnlyB = isPrintOnly.test(b);
88
+ if (isPrintA && isPrintB) {
89
+ if (!isPrintOnlyA && isPrintOnlyB) {
90
+ return 1;
91
+ }
92
+ if (isPrintOnlyA && !isPrintOnlyB) {
93
+ return -1;
94
+ }
95
+ return a.localeCompare(b);
96
+ }
97
+ if (isPrintA) {
98
+ return 1;
99
+ }
100
+ if (isPrintB) {
101
+ return -1;
102
+ }
103
+ return null;
104
+ }
105
+ function createSort(configuration) {
106
+ const config = configuration || {};
107
+ const UNITLESS_MQ_ALWAYS_FIRST = config.unitlessMqAlwaysFirst;
108
+ function sortCSSmq(a, b) {
109
+ const testIsPrint = _testIsPrint(a, b);
110
+ if (testIsPrint !== null) {
111
+ return testIsPrint;
112
+ }
113
+ const minA = isMinWidth(a) || isMinHeight(a);
114
+ const maxA = isMaxWidth(a) || isMaxHeight(a);
115
+ const minB = isMinWidth(b) || isMinHeight(b);
116
+ const maxB = isMaxWidth(b) || isMaxHeight(b);
117
+ if (UNITLESS_MQ_ALWAYS_FIRST && (!minA && !maxA || !minB && !maxB)) {
118
+ if (!minA && !maxA && !minB && !maxB) {
119
+ return a.localeCompare(b);
120
+ }
121
+ return !minB && !maxB ? 1 : -1;
122
+ } else {
123
+ if (minA && maxB) {
124
+ return -1;
125
+ }
126
+ if (maxA && minB) {
127
+ return 1;
128
+ }
129
+ const lengthA = _getQueryLength(a);
130
+ const lengthB = _getQueryLength(b);
131
+ if (lengthA === maxValue && lengthB === maxValue) {
132
+ return a.localeCompare(b);
133
+ } else if (lengthA === maxValue) {
134
+ return 1;
135
+ } else if (lengthB === maxValue) {
136
+ return -1;
137
+ }
138
+ if (lengthA > lengthB) {
139
+ if (maxA) {
140
+ return -1;
141
+ }
142
+ return 1;
143
+ }
144
+ if (lengthA < lengthB) {
145
+ if (maxA) {
146
+ return 1;
147
+ }
148
+ return -1;
149
+ }
150
+ if (lengthA === lengthB) {
151
+ if (maxA && maxB) {
152
+ if (lessThan.test(a) && !lessThan.test(b)) {
153
+ return 1;
154
+ }
155
+ if (!lessThan.test(a) && lessThan.test(b)) {
156
+ return -1;
157
+ }
158
+ }
159
+ if (minA && minB) {
160
+ if (grtrThan.test(a) && !grtrThan.test(b)) {
161
+ return 1;
162
+ }
163
+ if (!grtrThan.test(a) && grtrThan.test(b)) {
164
+ return -1;
165
+ }
166
+ }
167
+ }
168
+ return a.localeCompare(b);
169
+ }
170
+ }
171
+ sortCSSmq.desktopFirst = function(a, b) {
172
+ const testIsPrint = _testIsPrint(a, b);
173
+ if (testIsPrint !== null) {
174
+ return testIsPrint;
175
+ }
176
+ const minA = isMinWidth(a) || isMinHeight(a);
177
+ const maxA = isMaxWidth(a) || isMaxHeight(a);
178
+ const minB = isMinWidth(b) || isMinHeight(b);
179
+ const maxB = isMaxWidth(b) || isMaxHeight(b);
180
+ if (UNITLESS_MQ_ALWAYS_FIRST && (!minA && !maxA || !minB && !maxB)) {
181
+ if (!minA && !maxA && !minB && !maxB) {
182
+ return a.localeCompare(b);
183
+ }
184
+ return !minB && !maxB ? 1 : -1;
185
+ } else {
186
+ if (minA && maxB) {
187
+ return 1;
188
+ }
189
+ if (maxA && minB) {
190
+ return -1;
191
+ }
192
+ const lengthA = _getQueryLength(a);
193
+ const lengthB = _getQueryLength(b);
194
+ if (lengthA === maxValue && lengthB === maxValue) {
195
+ return a.localeCompare(b);
196
+ } else if (lengthA === maxValue) {
197
+ return 1;
198
+ } else if (lengthB === maxValue) {
199
+ return -1;
200
+ }
201
+ if (lengthA > lengthB) {
202
+ if (maxA) {
203
+ return -1;
204
+ }
205
+ return 1;
206
+ }
207
+ if (lengthA < lengthB) {
208
+ if (maxA) {
209
+ return 1;
210
+ }
211
+ return -1;
212
+ }
213
+ if (lengthA === lengthB) {
214
+ if (maxA && maxB) {
215
+ if (lessThan.test(a) && !lessThan.test(b)) {
216
+ return 1;
217
+ }
218
+ if (!lessThan.test(a) && lessThan.test(b)) {
219
+ return -1;
220
+ }
221
+ }
222
+ if (minA && minB) {
223
+ if (grtrThan.test(a) && !grtrThan.test(b)) {
224
+ return 1;
225
+ }
226
+ if (!grtrThan.test(a) && grtrThan.test(b)) {
227
+ return -1;
228
+ }
229
+ }
230
+ }
231
+ return -a.localeCompare(b);
232
+ }
233
+ };
234
+ return sortCSSmq;
235
+ }
236
+
237
+ // src/index.js
238
+ function sortAtRules(queries, options, sortCSSmq) {
239
+ if (typeof options.sort !== "function") {
240
+ options.sort = options.sort === "desktop-first" ? sortCSSmq.desktopFirst : sortCSSmq;
241
+ }
242
+ return queries.sort(options.sort);
243
+ }
244
+ function plugin(options = {}) {
245
+ options = Object.assign(
246
+ {
247
+ sort: "mobile-first",
248
+ configuration: false
249
+ },
250
+ options
251
+ );
252
+ const sortCSSmq = createSort(options.configuration);
253
+ return {
254
+ postcssPlugin: "postcss-sort-media-queries",
255
+ OnceExit(root, { AtRule }) {
256
+ let parents = {
257
+ root: [],
258
+ nested: []
259
+ };
260
+ let processed = /* @__PURE__ */ Symbol("processed");
261
+ root.walkAtRules("media", (atRule) => {
262
+ if (atRule.parent[processed]) {
263
+ return;
264
+ }
265
+ if (atRule.parent.type === "root") {
266
+ parents.root.push(atRule.parent);
267
+ }
268
+ if (atRule.parent.type !== "root") {
269
+ parents.nested.push(atRule.parent);
270
+ }
271
+ atRule.parent[processed] = true;
272
+ return;
273
+ });
274
+ Object.keys(parents).forEach((type) => {
275
+ if (!parents[type].length) {
276
+ return;
277
+ }
278
+ parents[type].forEach((parent) => {
279
+ let media = parent.nodes.filter(
280
+ (n) => n.type === "atrule" && n.name === "media"
281
+ );
282
+ if (!media) {
283
+ return;
284
+ }
285
+ let atRules = [];
286
+ media.forEach((atRule) => {
287
+ let query = atRule.params;
288
+ if (!atRules[query]) {
289
+ atRules[query] = new AtRule({
290
+ name: atRule.name,
291
+ params: atRule.params,
292
+ source: atRule.source
293
+ });
294
+ }
295
+ atRule.nodes.forEach((node) => {
296
+ atRules[query].append(node.clone());
297
+ });
298
+ atRule.remove();
299
+ });
300
+ if (atRules) {
301
+ sortAtRules(Object.keys(atRules), options, sortCSSmq).forEach((query) => {
302
+ parent.append(atRules[query]);
303
+ });
304
+ }
305
+ });
306
+ });
307
+ }
308
+ };
309
+ }
310
+ plugin.postcss = true;
311
+ var index_default = plugin;
package/package.json CHANGED
@@ -1,7 +1,10 @@
1
1
  {
2
2
  "name": "postcss-sort-media-queries",
3
- "version": "5.2.0",
4
3
  "description": "PostCSS plugin for sorting and combining CSS media queries with mobile first / **desktop first methodologies",
4
+ "version": "6.0.0",
5
+ "engines": {
6
+ "node": ">=22.0.0"
7
+ },
5
8
  "keywords": [
6
9
  "postcss",
7
10
  "postcss-plugin",
@@ -29,67 +32,37 @@
29
32
  "url": "https://github.com/yunusga/postcss-sort-media-queries/issues"
30
33
  },
31
34
  "homepage": "https://github.com/yunusga/postcss-sort-media-queries",
32
- "scripts": {
33
- "test": "jest-ci --coverage && eslint",
34
- "refresh-deps": "rm -rf node_modules && rm package-lock.json && npm i"
35
- },
36
- "engines": {
37
- "node": ">=14.0.0"
35
+ "type": "module",
36
+ "main": "src/index.js",
37
+ "module": "src/index.js",
38
+ "exports": {
39
+ ".": {
40
+ "require": "./src/index.cjs",
41
+ "import": "./src/index.js",
42
+ "default": "./src/index.js"
43
+ }
38
44
  },
39
- "dependencies": {
40
- "sort-css-media-queries": "2.2.0"
45
+ "files": [
46
+ "build"
47
+ ],
48
+ "scripts": {
49
+ "test": "vitest run",
50
+ "test:watch": "vitest --watch",
51
+ "coverage": "vitest --coverage",
52
+ "build": "npm run build:cjs",
53
+ "build:cjs": "esbuild src/index.js --outfile=build/index.cjs --format=cjs --bundle --platform=node --external:postcss"
41
54
  },
42
55
  "devDependencies": {
43
- "autoprefixer": "^10.4.0",
44
- "eslint": "^8.3.0",
45
- "eslint-ci": "^1.0.0",
46
- "eslint-plugin-jest": "^25.3.0",
47
- "husky": "^7.0.4",
48
- "jest": "^27.3.1",
49
- "jest-ci": "^0.1.1",
50
- "jest-cli": "^27.3.1",
51
- "lint-staged": "^13.2.1",
52
- "postcss": "^8.4.23",
53
- "postcss-flexbugs-fixes": "^5.0.2",
54
- "postcss-media-minmax": "^5.0.0",
55
- "postcss-nested": "^5.0.6"
56
+ "@vitest/coverage-v8": "^4.0.18",
57
+ "esbuild": "^0.27.3",
58
+ "postcss": "^8.5.6",
59
+ "prettier": "3.8.1",
60
+ "vitest": "^4.0.18"
56
61
  },
57
62
  "peerDependencies": {
58
- "postcss": "^8.4.23"
63
+ "postcss": "^8.5.6"
59
64
  },
60
- "husky": {
61
- "hooks": {
62
- "pre-commit": "lint-staged"
63
- }
64
- },
65
- "lint-staged": {
66
- "*.js": "eslint --fix"
67
- },
68
- "eslintConfig": {
69
- "parserOptions": {
70
- "ecmaVersion": 2017
71
- },
72
- "env": {
73
- "node": true,
74
- "es6": true
75
- },
76
- "extends": [
77
- "eslint:recommended",
78
- "plugin:jest/recommended"
79
- ],
80
- "rules": {
81
- "jest/expect-expect": "off"
82
- }
83
- },
84
- "jest": {
85
- "testEnvironment": "node",
86
- "coverageThreshold": {
87
- "global": {
88
- "statements": 100
89
- }
90
- }
91
- },
92
- "sortCssMQ": {
93
- "unitlessMqAlwaysFirst": false
65
+ "dependencies": {
66
+ "sort-css-media-queries": "^3.0.1"
94
67
  }
95
68
  }
package/src/index.js ADDED
@@ -0,0 +1,122 @@
1
+ import createSort from 'sort-css-media-queries/create-sort';
2
+
3
+ // PostCSS plugin to sort CSS @media rules according to a configurable order.
4
+ // The plugin groups top-level and nested media at-rules, merges rules
5
+ // with identical queries, and re-inserts them in the desired order.
6
+
7
+ // Helper that ensures `options.sort` is a function and sorts queries.
8
+ function sortAtRules(queries, options, sortCSSmq) {
9
+ if (typeof options.sort !== 'function') {
10
+ options.sort = options.sort === 'desktop-first' ? sortCSSmq.desktopFirst : sortCSSmq;
11
+ }
12
+
13
+ return queries.sort(options.sort);
14
+ }
15
+
16
+ function plugin(options = {}) {
17
+
18
+ // Set default options and allow user overrides
19
+ options = Object.assign(
20
+ {
21
+ sort: 'mobile-first',
22
+ configuration: false,
23
+ },
24
+ options
25
+ );
26
+
27
+ // Create a sorter based on configuration (from sort-css-media-queries)
28
+ const sortCSSmq = createSort(options.configuration);
29
+
30
+ return {
31
+ postcssPlugin: 'postcss-sort-media-queries',
32
+
33
+ // Execute once after the entire tree has been parsed
34
+ OnceExit(root, { AtRule }) {
35
+ // Collect parent nodes that contain media at-rules. We separate
36
+ // top-level (`root`) parents from nested parents so ordering
37
+ // semantics can be preserved independently.
38
+ let parents = {
39
+ root: [],
40
+ nested: [],
41
+ };
42
+
43
+ // Symbol used to mark parents that we've already collected
44
+ let processed = Symbol('processed');
45
+
46
+ // Walk all @media at-rules and group their parents
47
+ root.walkAtRules('media', (atRule) => {
48
+ if (atRule.parent[processed]) {
49
+ return;
50
+ }
51
+
52
+ // If the parent is the root of the document, add to root list
53
+ if (atRule.parent.type === 'root') {
54
+ parents.root.push(atRule.parent);
55
+ }
56
+
57
+ // Otherwise treat it as a nested parent
58
+ if (atRule.parent.type !== 'root') {
59
+ parents.nested.push(atRule.parent);
60
+ }
61
+
62
+ // Mark this parent so we don't collect it twice
63
+ atRule.parent[processed] = true;
64
+
65
+ return;
66
+ });
67
+
68
+ // For each parent group, merge and sort its media at-rules
69
+ Object.keys(parents).forEach((type) => {
70
+ if (!parents[type].length) {
71
+ return;
72
+ }
73
+
74
+ parents[type].forEach((parent) => {
75
+ // Filter only @media nodes from the parent's children
76
+ let media = parent.nodes.filter(
77
+ n => n.type === 'atrule' && n.name === 'media'
78
+ );
79
+
80
+ if (!media) {
81
+ return;
82
+ }
83
+
84
+ // Combine at-rules with identical query params into a single
85
+ // AtRule instance, cloning their children to preserve content.
86
+ let atRules = [];
87
+
88
+ media.forEach((atRule) => {
89
+ let query = atRule.params;
90
+
91
+ if (!atRules[query]) {
92
+ atRules[query] = new AtRule({
93
+ name: atRule.name,
94
+ params: atRule.params,
95
+ source: atRule.source
96
+ });
97
+ }
98
+
99
+ atRule.nodes.forEach((node) => {
100
+ atRules[query].append(node.clone());
101
+ });
102
+
103
+ // Remove the original at-rule since its contents have been
104
+ // merged into `atRules[query]`.
105
+ atRule.remove();
106
+ });
107
+
108
+ // Sort query keys and append merged at-rules back to the parent
109
+ if (atRules) {
110
+ sortAtRules(Object.keys(atRules), options, sortCSSmq).forEach((query) => {
111
+ parent.append(atRules[query]);
112
+ });
113
+ }
114
+ });
115
+ });
116
+ }
117
+ };
118
+ }
119
+
120
+ plugin.postcss = true;
121
+
122
+ export default plugin;
package/browser.js DELETED
@@ -1,54 +0,0 @@
1
- function sortAtRules(queries, sort, sortCSSmq) {
2
- if (typeof sort !== 'function') {
3
- sort = sort === 'desktop-first' ? sortCSSmq.desktopFirst : sortCSSmq
4
- }
5
-
6
- return queries.sort(sort)
7
- }
8
-
9
- module.exports = (opts = {}) => {
10
-
11
- opts = Object.assign(
12
- {
13
- sort: 'mobile-first',
14
- configuration: {
15
- unitlessMqAlwaysFirst: false,
16
- },
17
- },
18
- opts
19
- )
20
-
21
- const createSort = require('sort-css-media-queries/lib/create-sort');
22
- const sortCSSmq = createSort(opts.configuration);
23
-
24
- return {
25
- postcssPlugin: 'postcss-sort-media-queries',
26
- OnceExit(root, { AtRule }) {
27
-
28
- let atRules = [];
29
-
30
- root.walkAtRules('media', atRule => {
31
- let query = atRule.params
32
-
33
- if (!atRules[query]) {
34
- atRules[query] = new AtRule({
35
- name: atRule.name,
36
- params: atRule.params,
37
- source: atRule.source
38
- })
39
- }
40
-
41
- atRule.nodes.forEach(node => {
42
- atRules[query].append(node.clone())
43
- })
44
-
45
- atRule.remove()
46
- })
47
-
48
- sortAtRules(Object.keys(atRules), opts.sort, sortCSSmq).forEach(query => {
49
- root.append(atRules[query])
50
- })
51
- }
52
- }
53
- }
54
- module.exports.postcss = true
package/index.js DELETED
@@ -1,75 +0,0 @@
1
- function sortAtRules(queries, sort, sortCSSmq) {
2
- if (typeof sort !== 'function') {
3
- sort = sort === 'desktop-first' ? sortCSSmq.desktopFirst : sortCSSmq
4
- }
5
-
6
- return queries.sort(sort)
7
- }
8
-
9
- module.exports = (opts = {}) => {
10
-
11
- opts = Object.assign(
12
- {
13
- sort: 'mobile-first',
14
- configuration: false,
15
- onlyTopLevel: false,
16
- },
17
- opts
18
- )
19
-
20
- const createSort = require('sort-css-media-queries/lib/create-sort');
21
- const sortCSSmq = opts.configuration ? createSort(opts.configuration) : require('sort-css-media-queries');
22
-
23
- return {
24
- postcssPlugin: 'postcss-sort-media-queries',
25
- OnceExit (root, { AtRule }) {
26
-
27
- let atRules = [];
28
-
29
- root.walkAtRules('media', atRule => {
30
- if (opts.onlyTopLevel && atRule.parent.type === 'root') {
31
- let query = atRule.params
32
-
33
- if (!atRules[query]) {
34
- atRules[query] = new AtRule({
35
- name: atRule.name,
36
- params: atRule.params,
37
- source: atRule.source
38
- })
39
- }
40
-
41
- atRule.nodes.forEach(node => {
42
- atRules[query].append(node.clone())
43
- })
44
-
45
- atRule.remove()
46
- }
47
-
48
- if (!opts.onlyTopLevel) {
49
- let query = atRule.params
50
-
51
- if (!atRules[query]) {
52
- atRules[query] = new AtRule({
53
- name: atRule.name,
54
- params: atRule.params,
55
- source: atRule.source
56
- })
57
- }
58
-
59
- atRule.nodes.forEach(node => {
60
- atRules[query].append(node.clone())
61
- })
62
-
63
- atRule.remove()
64
- }
65
- })
66
-
67
- if (atRules) {
68
- sortAtRules(Object.keys(atRules), opts.sort, sortCSSmq).forEach(query => {
69
- root.append(atRules[query])
70
- })
71
- }
72
- }
73
- }
74
- }
75
- module.exports.postcss = true