@db-ux/core-postcss-plugin 4.12.1 → 4.13.1-angular-signal-forms3-9c66774

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/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @db-ux/core-postcss-plugin
2
2
 
3
+ ## 4.13.0
4
+
5
+ _version bump_
6
+
3
7
  ## 4.12.1
4
8
 
5
9
  _version bump_
@@ -11,7 +11,7 @@ export type FlattenOptions = {
11
11
  };
12
12
  export type VarEntry = {
13
13
  value: string;
14
- layer: string | null;
14
+ layer: string | undefined;
15
15
  file: string;
16
16
  };
17
17
  export declare const DEFAULT_DYNAMIC_PREFIXES: string[];
@@ -11,7 +11,7 @@ export declare const isRootSelector: (selector: string) => boolean;
11
11
  * @param node - The PostCSS child node to start from
12
12
  * @returns The layer name, or null if not inside any `@layer`
13
13
  */
14
- export declare const getLayerName: (node: ChildNode) => string | null;
14
+ export declare const getLayerName: (node: ChildNode) => string | undefined;
15
15
  /**
16
16
  * Parse `@layer` order declarations (e.g. `@layer db-ux, db-theme;`) from a root.
17
17
  * Later names in the list get higher priority indices.
@@ -32,7 +32,7 @@ export declare const collectImportLayers: (root: Root) => Map<string, string>;
32
32
  * @param layerOrder - The layer priority map
33
33
  * @returns The numeric priority (higher = wins)
34
34
  */
35
- export declare const getLayerPriority: (layer: string | null, layerOrder: Map<string, number>) => number;
35
+ export declare const getLayerPriority: (layer: string | undefined, layerOrder: Map<string, number>) => number;
36
36
  /**
37
37
  * Pick the best (highest-priority) value from multiple `VarEntry` entries
38
38
  * for the same variable, based on `@layer` priority.
@@ -48,7 +48,7 @@ export declare const pickBestVar: (entries: VarEntry[], layerOrder: Map<string,
48
48
  * @param importLayerMap - Map of import specifiers to layer names
49
49
  * @returns The layer name, or null if not associated with any layer
50
50
  */
51
- export declare const getFileLayer: (filePath: string, importLayerMap: Map<string, string>) => string | null;
51
+ export declare const getFileLayer: (filePath: string, importLayerMap: Map<string, string>) => string | undefined;
52
52
  /**
53
53
  * Collect all CSS custom property declarations and `@property` initial-values
54
54
  * from a PostCSS root, assigning each a layer and detecting dynamic variables.
@@ -68,4 +68,4 @@ export declare const getFileLayer: (filePath: string, importLayerMap: Map<string
68
68
  * @param forceLayer - If set, overrides the detected layer for all entries
69
69
  * @param file - The source file path for deduplication
70
70
  */
71
- export declare const collectVarsWithLayer: (root: Root, varMap: Map<string, VarEntry[]>, propertyNames: Set<string>, dynamicVars: Set<string>, prefixes: string[], forceLayer: string | null, file: string) => void;
71
+ export declare const collectVarsWithLayer: (root: Root, varMap: Map<string, VarEntry[]>, propertyNames: Set<string>, dynamicVars: Set<string>, prefixes: string[], forceLayer: string | undefined, file: string) => void;
@@ -22,7 +22,7 @@ export const getLayerName = (node) => {
22
22
  }
23
23
  current = current.parent;
24
24
  }
25
- return null;
25
+ return undefined;
26
26
  };
27
27
  /**
28
28
  * Parse `@layer` order declarations (e.g. `@layer db-ux, db-theme;`) from a root.
@@ -39,8 +39,8 @@ export const collectLayerOrder = (root) => {
39
39
  .split(',')
40
40
  .map((n) => n.trim())
41
41
  .filter(Boolean);
42
- for (let i = 0; i < names.length; i++) {
43
- order.set(names[i], i);
42
+ for (const [i, name] of names.entries()) {
43
+ order.set(name, i);
44
44
  }
45
45
  });
46
46
  return order;
@@ -53,12 +53,12 @@ export const collectLayerOrder = (root) => {
53
53
  export const collectImportLayers = (root) => {
54
54
  const importLayers = new Map();
55
55
  root.walkAtRules('import', (atRule) => {
56
- const params = atRule.params;
57
- const layerMatch = params.match(/layer\(([^)]+)\)/);
56
+ const { params } = atRule;
57
+ const layerMatch = /layer\(([^)]+)\)/.exec(params);
58
58
  if (!layerMatch)
59
59
  return;
60
60
  const layerName = layerMatch[1].trim();
61
- const fileMatch = params.match(/(?:url\(\s*)?["']([^"']+)["'](?:\s*\))?/);
61
+ const fileMatch = /(?:url\(\s*)?["']([^"']+)["'](?:\s*\))?/.exec(params);
62
62
  if (!fileMatch)
63
63
  return;
64
64
  importLayers.set(fileMatch[1], layerName);
@@ -73,7 +73,7 @@ export const collectImportLayers = (root) => {
73
73
  * @returns The numeric priority (higher = wins)
74
74
  */
75
75
  export const getLayerPriority = (layer, layerOrder) => {
76
- if (layer === null)
76
+ if (!layer)
77
77
  return Number.MAX_SAFE_INTEGER;
78
78
  return layerOrder.get(layer) ?? -1;
79
79
  };
@@ -103,11 +103,13 @@ export const pickBestVar = (entries, layerOrder) => {
103
103
  */
104
104
  export const getFileLayer = (filePath, importLayerMap) => {
105
105
  for (const [specifier, layer] of importLayerMap) {
106
- if (filePath.replace(/\\/g, '/').endsWith(specifier.replace(/\\/g, '/'))) {
106
+ if (filePath
107
+ .replaceAll('\\', '/')
108
+ .endsWith(specifier.replaceAll('\\', '/'))) {
107
109
  return layer;
108
110
  }
109
111
  }
110
- return null;
112
+ return undefined;
111
113
  };
112
114
  /**
113
115
  * Collect all CSS custom property declarations and `@property` initial-values
@@ -132,11 +134,13 @@ export const collectVarsWithLayer = (root, varMap, propertyNames, dynamicVars, p
132
134
  const addVar = (prop, value, layer) => {
133
135
  const entries = varMap.get(prop);
134
136
  if (entries) {
135
- if (entries.some((e) => e.file === file &&
136
- e.layer === layer &&
137
- e.value === value))
138
- return;
139
- entries.push({ value, layer, file });
137
+ const existing = entries.find((e) => e.file === file && e.layer === layer);
138
+ if (existing) {
139
+ existing.value = value;
140
+ }
141
+ else {
142
+ entries.push({ value, layer, file });
143
+ }
140
144
  }
141
145
  else {
142
146
  varMap.set(prop, [{ value, layer, file }]);
@@ -151,21 +155,20 @@ export const collectVarsWithLayer = (root, varMap, propertyNames, dynamicVars, p
151
155
  });
152
156
  });
153
157
  root.walkDecls(/^--/, (decl) => {
154
- const parent = decl.parent;
158
+ const { parent } = decl;
155
159
  if (prefixes.some((p) => decl.prop.startsWith(p))) {
156
160
  dynamicVars.add(decl.prop);
157
161
  }
158
- if (parent && parent.type === 'rule') {
162
+ if (parent?.type === 'rule') {
159
163
  const rule = parent;
160
164
  if (!isRootSelector(rule.selector)) {
161
165
  dynamicVars.add(decl.prop);
162
166
  }
163
167
  }
164
- if (parent && parent.type === 'rule') {
168
+ if (parent?.type === 'rule') {
165
169
  const rule = parent;
166
170
  if (isRootSelector(rule.selector) &&
167
- rule.parent &&
168
- rule.parent.type === 'atrule') {
171
+ rule.parent?.type === 'atrule') {
169
172
  const atRule = rule.parent;
170
173
  if (atRule.name === 'media') {
171
174
  dynamicVars.add(decl.prop);
@@ -25,4 +25,4 @@ export declare const findCssFunction: (value: string, funcName: string, fromInde
25
25
  start: number;
26
26
  end: number;
27
27
  inner: string;
28
- } | null;
28
+ } | undefined;
@@ -47,10 +47,10 @@ export const findCssFunction = (value, funcName, fromIndex = 0) => {
47
47
  const prefix = `${funcName}(`;
48
48
  const idx = value.indexOf(prefix, fromIndex);
49
49
  if (idx === -1)
50
- return null;
50
+ return undefined;
51
51
  const end = findMatchingParenthesis(value, idx + prefix.length);
52
52
  if (end === -1)
53
- return null;
53
+ return undefined;
54
54
  return {
55
55
  start: idx,
56
56
  end,
@@ -9,14 +9,14 @@ import { findCssFunction, findTopLevelComma } from './css-parser.js';
9
9
  const findNextVar = (value, fromIndex) => {
10
10
  const found = findCssFunction(value, 'var', fromIndex);
11
11
  if (!found)
12
- return null;
12
+ return undefined;
13
13
  const commaIdx = findTopLevelComma(found.inner);
14
14
  if (commaIdx === -1) {
15
15
  return {
16
16
  start: found.start,
17
17
  end: found.end,
18
18
  name: found.inner.trim(),
19
- fallback: null
19
+ fallback: undefined
20
20
  };
21
21
  }
22
22
  return {
@@ -56,15 +56,15 @@ export const resolveVars = (value, varMap, seen = new Set()) => {
56
56
  result = result.slice(0, start) + resolvedValue + result.slice(end);
57
57
  searchFrom = start + resolvedValue.length;
58
58
  }
59
- else if (fallback !== null) {
59
+ else if (fallback === undefined) {
60
+ searchFrom = end;
61
+ }
62
+ else {
60
63
  const resolvedFallback = resolveVars(fallback, varMap, seen);
61
64
  const replacement = `var(${name}, ${resolvedFallback})`;
62
65
  result = result.slice(0, start) + replacement + result.slice(end);
63
66
  searchFrom = start + replacement.length;
64
67
  }
65
- else {
66
- searchFrom = end;
67
- }
68
68
  }
69
69
  return result;
70
70
  };
@@ -114,16 +114,16 @@ const resolveCssFunction = (value, funcName, evaluate, skipNestedFunctions = fal
114
114
  continue;
115
115
  }
116
116
  const evaluated = evaluate(found.inner);
117
- if (evaluated !== null) {
117
+ if (evaluated === undefined) {
118
+ searchFrom = found.end;
119
+ }
120
+ else {
118
121
  result =
119
122
  result.slice(0, found.start) +
120
123
  evaluated +
121
124
  result.slice(found.end);
122
125
  searchFrom = found.start + evaluated.length;
123
126
  }
124
- else {
125
- searchFrom = found.end;
126
- }
127
127
  }
128
128
  return result;
129
129
  };
@@ -133,10 +133,10 @@ const resolveCssFunction = (value, funcName, evaluate, skipNestedFunctions = fal
133
133
  * @param str - The string to parse (e.g. "0.75rem", "100%", "2")
134
134
  * @returns An object with `value` and `unit`, or null if not parseable
135
135
  */
136
- const parseUnit = (str) => {
137
- const match = str.trim().match(/^(-?[\d.]+)\s*(%|[a-z]*)$/i);
136
+ const parseUnit = (string_) => {
137
+ const match = /^(-?[\d.]+)\s*(%|[a-z]*)$/i.exec(string_.trim());
138
138
  if (!match)
139
- return null;
139
+ return undefined;
140
140
  return { value: Number.parseFloat(match[1]), unit: match[2] || '' };
141
141
  };
142
142
  /**
@@ -148,7 +148,7 @@ const parseUnit = (str) => {
148
148
  const evaluateCalc = (expr) => {
149
149
  const tokens = expr.trim().split(/\s+/).filter(Boolean);
150
150
  if (tokens.length === 0)
151
- return null;
151
+ return undefined;
152
152
  let result = 0;
153
153
  let resultUnit = '';
154
154
  let operator = '+';
@@ -159,28 +159,32 @@ const evaluateCalc = (expr) => {
159
159
  }
160
160
  const parsed = parseUnit(token);
161
161
  if (!parsed)
162
- return null;
162
+ return undefined;
163
163
  if (parsed.unit && !resultUnit) {
164
164
  resultUnit = parsed.unit;
165
165
  }
166
166
  else if (parsed.unit && parsed.unit !== resultUnit && resultUnit) {
167
- return null;
167
+ return undefined;
168
168
  }
169
169
  switch (operator) {
170
- case '+':
170
+ case '+': {
171
171
  result += parsed.value;
172
172
  break;
173
- case '-':
173
+ }
174
+ case '-': {
174
175
  result -= parsed.value;
175
176
  break;
176
- case '*':
177
+ }
178
+ case '*': {
177
179
  result *= parsed.value;
178
180
  break;
179
- case '/':
181
+ }
182
+ case '/': {
180
183
  if (parsed.value === 0)
181
- return null;
184
+ return undefined;
182
185
  result /= parsed.value;
183
186
  break;
187
+ }
184
188
  }
185
189
  }
186
190
  const rounded = Math.abs(result) < 1e-10 ? 0 : Math.round(result * 1e6) / 1e6;
@@ -202,38 +206,46 @@ export const resolveCalc = (value) => resolveCssFunction(value, 'calc', evaluate
202
206
  */
203
207
  const parseHexColor = (hex) => {
204
208
  const h = hex.replace('#', '');
205
- let r, g, b;
209
+ let r;
210
+ let g;
211
+ let b;
206
212
  let a = 1;
207
- if (h.length === 3) {
208
- r = Number.parseInt(h[0] + h[0], 16);
209
- g = Number.parseInt(h[1] + h[1], 16);
210
- b = Number.parseInt(h[2] + h[2], 16);
211
- }
212
- else if (h.length === 4) {
213
- r = Number.parseInt(h[0] + h[0], 16);
214
- g = Number.parseInt(h[1] + h[1], 16);
215
- b = Number.parseInt(h[2] + h[2], 16);
216
- a = Number.parseInt(h[3] + h[3], 16) / 255;
217
- }
218
- else if (h.length === 6) {
219
- r = Number.parseInt(h.slice(0, 2), 16);
220
- g = Number.parseInt(h.slice(2, 4), 16);
221
- b = Number.parseInt(h.slice(4, 6), 16);
222
- }
223
- else if (h.length === 8) {
224
- r = Number.parseInt(h.slice(0, 2), 16);
225
- g = Number.parseInt(h.slice(2, 4), 16);
226
- b = Number.parseInt(h.slice(4, 6), 16);
227
- a = Number.parseInt(h.slice(6, 8), 16) / 255;
228
- }
229
- else {
230
- return null;
213
+ switch (h.length) {
214
+ case 3: {
215
+ r = Number.parseInt(h[0] + h[0], 16);
216
+ g = Number.parseInt(h[1] + h[1], 16);
217
+ b = Number.parseInt(h[2] + h[2], 16);
218
+ break;
219
+ }
220
+ case 4: {
221
+ r = Number.parseInt(h[0] + h[0], 16);
222
+ g = Number.parseInt(h[1] + h[1], 16);
223
+ b = Number.parseInt(h[2] + h[2], 16);
224
+ a = Number.parseInt(h[3] + h[3], 16) / 255;
225
+ break;
226
+ }
227
+ case 6: {
228
+ r = Number.parseInt(h.slice(0, 2), 16);
229
+ g = Number.parseInt(h.slice(2, 4), 16);
230
+ b = Number.parseInt(h.slice(4, 6), 16);
231
+ break;
232
+ }
233
+ case 8: {
234
+ r = Number.parseInt(h.slice(0, 2), 16);
235
+ g = Number.parseInt(h.slice(2, 4), 16);
236
+ b = Number.parseInt(h.slice(4, 6), 16);
237
+ a = Number.parseInt(h.slice(6, 8), 16) / 255;
238
+ break;
239
+ }
240
+ default: {
241
+ return undefined;
242
+ }
231
243
  }
232
244
  if (Number.isNaN(r) ||
233
245
  Number.isNaN(g) ||
234
246
  Number.isNaN(b) ||
235
247
  Number.isNaN(a))
236
- return null;
248
+ return undefined;
237
249
  return [r, g, b, a];
238
250
  };
239
251
  /**
@@ -252,44 +264,45 @@ const toHex = (n) => Math.round(Math.max(0, Math.min(255, n)))
252
264
  * @returns The mixed color as a hex string, "transparent", or null if not evaluable
253
265
  */
254
266
  const evaluateColorMix = (args) => {
255
- const srgbMatch = args.match(/^in\s+srgb\s*,\s*([\s\S]+?)\s*,\s*([\s\S]+?)\s*$/);
267
+ const srgbMatch = /^in\s+srgb\s*,\s*([\s\S]+?)\s*,\s*([\s\S]+?)\s*$/.exec(args);
256
268
  if (!srgbMatch)
257
- return null;
269
+ return undefined;
258
270
  const parseColorArg = (arg) => {
259
271
  const parts = arg.trim().split(/\s+/);
260
272
  if (parts.length === 1)
261
- return { color: parts[0], percentage: null };
273
+ return { color: parts[0], percentage: undefined };
262
274
  if (parts.length === 2) {
263
- const pctMatch = parts[1].match(/^([\d.]+)%$/);
275
+ const pctMatch = /^([\d.]+)%$/.exec(parts[1]);
264
276
  if (!pctMatch)
265
- return null;
277
+ return undefined;
266
278
  return {
267
279
  color: parts[0],
268
280
  percentage: Number.parseFloat(pctMatch[1])
269
281
  };
270
282
  }
271
- return null;
283
+ return undefined;
272
284
  };
273
285
  const arg1 = parseColorArg(srgbMatch[1]);
274
286
  const arg2 = parseColorArg(srgbMatch[2]);
275
287
  if (!arg1 || !arg2)
276
- return null;
288
+ return undefined;
277
289
  let p1 = arg1.percentage;
278
290
  let p2 = arg2.percentage;
279
- if (p1 === null && p2 === null) {
291
+ if (p1 === undefined && p2 === undefined) {
280
292
  p1 = 50;
281
293
  p2 = 50;
282
294
  }
283
- else if (p1 !== null && p2 === null) {
295
+ else if (p1 !== undefined && p2 === undefined) {
284
296
  p2 = 100 - p1;
285
297
  }
286
- else if (p1 === null && p2 !== null) {
298
+ else if (p1 === undefined && p2 !== undefined) {
287
299
  p1 = 100 - p2;
288
300
  }
289
301
  const pct1 = p1 / 100;
290
302
  const pct2 = p2 / 100;
291
303
  const isTransparent = (c) => c === 'transparent';
292
- let rgb1, alpha1 = 1;
304
+ let rgb1;
305
+ let alpha1 = 1;
293
306
  if (isTransparent(arg1.color)) {
294
307
  rgb1 = [0, 0, 0];
295
308
  alpha1 = 0;
@@ -297,11 +310,12 @@ const evaluateColorMix = (args) => {
297
310
  else {
298
311
  const parsed = parseHexColor(arg1.color);
299
312
  if (!parsed)
300
- return null;
313
+ return undefined;
301
314
  rgb1 = [parsed[0], parsed[1], parsed[2]];
302
315
  alpha1 = parsed[3];
303
316
  }
304
- let rgb2, alpha2 = 1;
317
+ let rgb2;
318
+ let alpha2 = 1;
305
319
  if (isTransparent(arg2.color)) {
306
320
  rgb2 = [0, 0, 0];
307
321
  alpha2 = 0;
@@ -309,7 +323,7 @@ const evaluateColorMix = (args) => {
309
323
  else {
310
324
  const parsed = parseHexColor(arg2.color);
311
325
  if (!parsed)
312
- return null;
326
+ return undefined;
313
327
  rgb2 = [parsed[0], parsed[1], parsed[2]];
314
328
  alpha2 = parsed[3];
315
329
  }
@@ -97,13 +97,13 @@ const removeEmptyContainers = (root) => {
97
97
  while (changed) {
98
98
  changed = false;
99
99
  root.walkRules((rule) => {
100
- if (rule.nodes && rule.nodes.length === 0) {
100
+ if (rule.nodes?.length === 0) {
101
101
  rule.remove();
102
102
  changed = true;
103
103
  }
104
104
  });
105
105
  root.walkAtRules('layer', (atRule) => {
106
- if (atRule.nodes && atRule.nodes.length === 0) {
106
+ if (atRule.nodes?.length === 0) {
107
107
  atRule.remove();
108
108
  changed = true;
109
109
  }
@@ -1,5 +1,5 @@
1
1
  import type { PluginCreator } from 'postcss';
2
- import type { FlattenOptions } from './data.js';
2
+ import { type FlattenOptions } from './data.js';
3
3
  /**
4
4
  * PostCSS plugin that flattens DB UX Design System CSS custom properties
5
5
  * by resolving `var()`, `@property`, `calc()`, `color-mix()`, and `light-dark()`.
@@ -13,4 +13,4 @@ import type { FlattenOptions } from './data.js';
13
13
  */
14
14
  declare const dbUxFlatten: PluginCreator<FlattenOptions>;
15
15
  export { dbUxFlatten };
16
- export type { FlattenOptions };
16
+ export { type FlattenOptions } from './data.js';
@@ -12,10 +12,10 @@ import { transformRoot } from './helpers/transform.js';
12
12
  * @param opts - Plugin options
13
13
  * @returns A PostCSS plugin instance
14
14
  */
15
- const dbUxFlatten = (opts = {}) => {
16
- const removeAtProperty = opts.removeAtProperty ?? true;
17
- const removeResolved = opts.removeResolved ?? true;
18
- const dynamicPrefixes = opts.dynamicPrefixes ?? DEFAULT_DYNAMIC_PREFIXES;
15
+ const dbUxFlatten = (options = {}) => {
16
+ const removeAtProperty = options.removeAtProperty ?? true;
17
+ const removeResolved = options.removeResolved ?? true;
18
+ const dynamicPrefixes = options.dynamicPrefixes ?? DEFAULT_DYNAMIC_PREFIXES;
19
19
  const varMap = new Map();
20
20
  const propertyNames = new Set();
21
21
  const dynamicVars = new Set();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@db-ux/core-postcss-plugin",
3
- "version": "4.12.1",
3
+ "version": "4.13.1-angular-signal-forms3-9c66774",
4
4
  "type": "module",
5
5
  "description": "PostCSS plugins for DB UX Design System",
6
6
  "repository": {
@@ -33,7 +33,7 @@
33
33
  "npm-run-all2": "9.0.2",
34
34
  "postcss": "8.5.15",
35
35
  "typescript": "5.9.3",
36
- "vitest": "4.1.8"
36
+ "vitest": "4.1.9"
37
37
  },
38
38
  "publishConfig": {
39
39
  "registry": "https://registry.npmjs.org/",