@massimo-cassandro/minimo 1.41.4 → 1.41.5

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.
Files changed (131) hide show
  1. package/README.md +12 -12
  2. package/charts/src/node-helpers/create-svg-canvas-node.mjs +2 -2
  3. package/charts/src/node-helpers/svg-text-to-path.js +9 -9
  4. package/charts/src/rating-display/index.js +1 -1
  5. package/charts/src/rating-display/ratindDisplayAnimation.js +3 -3
  6. package/design-tokens/README.md +2 -2
  7. package/design-tokens/_src/_readme.md +26 -26
  8. package/dev-tools/README.md +16 -16
  9. package/dev-tools/create-favicons/README.md +31 -31
  10. package/dev-tools/create-favicons/src/create-ico.mjs +2 -2
  11. package/dev-tools/create-favicons/src/default-params.mjs +1 -1
  12. package/dev-tools/create-favicons/src/init.mjs +1 -1
  13. package/dev-tools/design-tokens-builder/README.md +102 -102
  14. package/dev-tools/design-tokens-builder/build-tokens-src/build-source-modes.mjs +85 -73
  15. package/dev-tools/design-tokens-builder/build-tokens-src/config.mjs +109 -85
  16. package/dev-tools/design-tokens-builder/build-tokens-src/formats/css.mjs +113 -90
  17. package/dev-tools/design-tokens-builder/build-tokens-src/formats/json.mjs +107 -95
  18. package/dev-tools/design-tokens-builder/build-tokens-src/legacy-tokens-parser.mjs +71 -64
  19. package/dev-tools/design-tokens-builder/build-tokens-src/light-dark.mjs +75 -65
  20. package/dev-tools/design-tokens-builder/build-tokens-src/merge-css.mjs +113 -102
  21. package/dev-tools/design-tokens-builder/build-tokens-src/platforms.mjs +36 -30
  22. package/dev-tools/design-tokens-builder/build-tokens-src/resolve-source-paths.mjs +15 -13
  23. package/dev-tools/design-tokens-builder/build-tokens-src/source-prefixes.mjs +44 -42
  24. package/dev-tools/design-tokens-builder/build-tokens-src/source-transforms.mjs +89 -83
  25. package/dev-tools/design-tokens-builder/build-tokens-src/token-rename-parser.mjs +99 -86
  26. package/dev-tools/design-tokens-builder/build-tokens-src/transforms.mjs +64 -48
  27. package/dev-tools/design-tokens-builder/build-tokens.mjs +80 -68
  28. package/dev-tools/design-tokens-builder/check-unresolved-custom-props.mjs +103 -77
  29. package/dev-tools/design-tokens-builder/tokens-config-sample.mjs +275 -238
  30. package/dev-tools/find-orphan-css-classes/find-orphan-css-classes.mjs +2 -2
  31. package/dev-tools/starter-kit/source_files/app/CLAUDE.md +4 -2
  32. package/dev-tools/starter-kit/source_files/app/{css/index.css → index.css} +2 -2
  33. package/dev-tools/starter-kit/source_files/app/index.js +1 -1
  34. package/dev-tools/starter-kit/source_files/root/_sf/controller/ImgViewerController.php +3 -3
  35. package/dev-tools/starter-kit/source_files/root/_sf/controller/ViewerController.php +2 -2
  36. package/dev-tools/starter-kit/source_files/root/stylelint.config.mjs +1 -1
  37. package/dev-tools/starter-kit/source_files/root/webpack-config-modules/css-rules.mjs +1 -1
  38. package/dev-tools/stylelint-config/README.md +7 -7
  39. package/dev-tools/svg-icons-tools/README.md +32 -32
  40. package/dev-tools/svg-icons-tools/src/config-manager.mjs +1 -1
  41. package/dev-tools/svg-icons-tools/src/default-config.mjs +118 -118
  42. package/dev-tools/svg-icons-tools/src/jsx-icon-file-builder.mjs +24 -24
  43. package/dev-tools/svg-icons-tools/src/parse-svg-filename.mjs +3 -3
  44. package/dev-tools/svg-icons-tools/src/parse-svg-files.mjs +1 -1
  45. package/dev-tools/svg-icons-tools/src/parse-svg-markup.mjs +4 -4
  46. package/dev-tools/svg-icons-tools/src/svg-to-jsx.mjs +2 -2
  47. package/dev-tools/svg-icons-tools/src/svg-to-optimized.mjs +2 -2
  48. package/dev-tools/svg-icons-tools/src/svg-to-symbols.mjs +2 -2
  49. package/dev-tools/upd@m/README.md +1 -1
  50. package/dev-tools/upd@m/index.mjs +1 -1
  51. package/dev-tools/update-version/README.md +9 -9
  52. package/package.json +1 -1
  53. package/snippets/unsplash-browser-app/README.md +1 -1
  54. package/snippets/unsplash-browser-app/unsplash-utilities.js +9 -9
  55. package/src/components/autocomplete/README.md +3 -3
  56. package/src/components/autocomplete/autocomplete-engine.js +75 -63
  57. package/src/components/autocomplete/check-autocomplete.js +3 -3
  58. package/src/components/dismiss-alerts.js +3 -3
  59. package/src/components/form-reset-submit.js +6 -6
  60. package/src/components/inner-nav/inner-nav.js +2 -2
  61. package/src/components/modal-alert/modal-alert.js +67 -65
  62. package/src/components/modal-alert/modal-alert.minimo.tokens.mjs +1 -1
  63. package/src/components/modal-popup/modal-popup.js +56 -56
  64. package/src/components/overlay/overlay.js +3 -3
  65. package/src/components/sf-macro/readme.md +1 -1
  66. package/src/components/sf-macro/sf-macro.js +27 -23
  67. package/src/components/slide-up-down-toggle/slide-up-down-toggle.js +83 -79
  68. package/src/components/slide-up-down-toggle/slide-up-down-toggle.module.css +44 -44
  69. package/src/components/snackbar/snackbar.js +19 -19
  70. package/src/components/spinner/spinner.js +3 -3
  71. package/src/components/unsplash-page/README.md +8 -8
  72. package/src/components/unsplash-page/fetch-unsplash-data.js +3 -3
  73. package/src/components/unsplash-page/unsplash-page.js +33 -33
  74. package/src/components/unsplash-page/unsplash-page.module.css +1 -1
  75. package/src/css/alerts.css +2 -2
  76. package/src/css/forms/forms.css +4 -4
  77. package/src/css/forms/validation.css +1 -1
  78. package/src/css/margin-padding-media.css +4 -4
  79. package/src/css/margin-padding.css +4 -4
  80. package/src/css/reset.css +11 -11
  81. package/src/icons/read-me.md +1 -1
  82. package/src/minimo.css +3 -3
  83. package/src/utilities/better-text-with-places.js +22 -22
  84. package/src/utilities/better-text.js +42 -35
  85. package/src/utilities/classnames.js +8 -8
  86. package/src/utilities/cookies.js +6 -6
  87. package/src/utilities/create-id.js +3 -3
  88. package/src/utilities/disable-btns-on-submit.js +2 -2
  89. package/src/utilities/dom-builder/dom-builder.js +89 -86
  90. package/src/utilities/dom-builder/domBuilderBasicSetup.js +9 -9
  91. package/src/utilities/dom-builder/parseDomString.js +23 -23
  92. package/src/utilities/dom-builder-helpers/README.md +2 -2
  93. package/src/utilities/dom-builder-helpers/form-tags.js +100 -100
  94. package/src/utilities/dom-builder-helpers/picture-tag.js +39 -39
  95. package/src/utilities/enable-submit-btns.js +1 -1
  96. package/src/utilities/escape-html.js +2 -2
  97. package/src/utilities/generate-pwd.js +4 -4
  98. package/src/utilities/linked-dates.js +13 -13
  99. package/src/utilities/parse-file-size.js +6 -6
  100. package/src/utilities/random-id.js +3 -3
  101. package/src/utilities/relative-date.js +40 -40
  102. package/src/utilities/sentence-case.js +1 -1
  103. package/src/utilities/strip-tags.js +1 -1
  104. package/src/utilities/title-case.js +1 -1
  105. package/src/utilities/truncate-string.js +5 -5
  106. package/src/utilities/validation-error-class.js +12 -12
  107. package/src/web-components/json-table/json-table-component.js +123 -121
  108. package/src/web-components/json-table/json-table-component.module.css +6 -6
  109. package/src/web-components/json-table/json-table.minimo.tokens.mjs +6 -6
  110. package/src/web-components/json-table/readme.md +72 -108
  111. package/src/web-components/json-table/src/cell-content.js +25 -25
  112. package/src/web-components/json-table/src/content-utils.js +21 -21
  113. package/src/web-components/json-table/src/data-types.js +32 -32
  114. package/src/web-components/json-table/src/defaults.js +230 -191
  115. package/src/web-components/json-table/src/get-data.js +55 -38
  116. package/src/web-components/json-table/src/icons.js +17 -17
  117. package/src/web-components/json-table/src/info-section.js +18 -18
  118. package/src/web-components/json-table/src/main-builder.js +45 -45
  119. package/src/web-components/json-table/src/pagination.js +32 -32
  120. package/src/web-components/json-table/src/parse-cols.js +18 -18
  121. package/src/web-components/json-table/src/parse-rows.js +17 -17
  122. package/src/web-components/json-table/src/resolve-params.js +53 -41
  123. package/src/web-components/json-table/src/search.js +13 -13
  124. package/src/web-components/json-table/src/sorting.js +20 -20
  125. package/src/web-components/json-table/src/table-body.js +13 -13
  126. package/src/web-components/json-table/src/table-builder.js +34 -34
  127. package/src/web-components/json-table/src/table-tfoot.js +8 -8
  128. package/src/web-components/json-table/src/table-thead.js +21 -21
  129. package/src/web-components/json-table/src/update-info.js +11 -11
  130. package/types/classes.d.ts +2 -2
  131. package/types/global.d.ts +18 -12
@@ -1,69 +1,75 @@
1
- // build-tokens-src/formats/json.mjs
2
- // Registers the 'json/tokens' format and exports buildJsonFiles() and
3
- // collectConcreteFilePaths().
4
- //
5
- // The format produces a W3C DTCG nested JSON(C) file, independent of any
6
- // specific consuming tool (usable in Penpot, Figma via plugin, Token Studio,
7
- // Supernova, or any other DTCG-compatible tool).
8
- //
9
- // Output format is controlled by the jsonFormat option in the project config:
10
- // 'jsonc' -> .jsonc extension + generated-file disclaimer header
11
- // 'json' -> plain .json, no disclaimer
12
- //
13
- // buildJsonFiles() builds the `files` array for the json platform:
14
- // jsonDestFile set -> single aggregated file
15
- // jsonDestFile null -> one file per concrete source file, all placed flat
16
- // in jsonBuildPath (no subdirectories) — see the
17
- // collision check in buildJsonFiles()
18
- //
19
- // ── Expression handling (jsonExpression option) ─────────────────────────────
20
- //
21
- // Dimension tokens may carry math expressions in their $value, e.g.:
22
- // { $type: "dimension", $value: "{size.base} * .25" }
23
- //
24
- // The jsonExpression config option controls how these are handled:
25
- //
26
- // 'keep' (default) — write the expression as-is; the consuming tool is
27
- // expected to evaluate it.
28
- // 'calc' — wrap in a CSS calc(): "calc({size.base} * .25)"
29
- // aliases are left as {references} for the consuming
30
- // tool to resolve.
31
- // 'resolve' — evaluate the expression numerically and write a concrete value.
32
- // The unit is inherited from the first dimension token
33
- // referenced in the expression (e.g. {size.base} = 16px
34
- // -> 16 * .25 = 4 -> "4px"). If evaluation fails the
35
- // original expression is kept with a warning.
1
+ /*
2
+ build-tokens-src/formats/json.mjs
3
+ Registra il format 'json/tokens' ed esporta buildJsonFiles() e
4
+ collectConcreteFilePaths().
5
+
6
+ Il format produce un file JSON(C) annidato W3C DTCG, indipendente da qualsiasi
7
+ strumento specifico (utilizzabile in Penpot, Figma tramite plugin, Token Studio,
8
+ Supernova o qualsiasi altro strumento compatibile con DTCG).
9
+
10
+ Il formato di output è controllato dall'opzione jsonFormat nella config del progetto:
11
+ 'jsonc' -> estensione .jsonc + intestazione che segnala il file generato
12
+ 'json' -> .json semplice, senza intestazione
13
+
14
+ buildJsonFiles() costruisce l'array `files` per la platform json:
15
+ jsonDestFile impostato -> singolo file aggregato
16
+ jsonDestFile null -> un file per ogni file sorgente concreto, tutti nella stessa
17
+ cartella jsonBuildPath (senza sottocartelle) — vedi il
18
+ controllo delle collisioni in buildJsonFiles()
19
+
20
+ ── Gestione delle espressioni (opzione jsonExpression) ─────────────────────
21
+
22
+ I token dimension possono avere espressioni matematiche nel proprio $value, ad es.:
23
+ { $type: "dimension", $value: "{size.base} * .25" }
24
+
25
+ L'opzione di config jsonExpression controlla come vengono gestite:
26
+
27
+ 'keep' (default) — scrive l'espressione così com'è; si presume che lo
28
+ strumento che la usa la valuti.
29
+ 'calc' — la racchiude in un calc() CSS: "calc({size.base} * .25)"
30
+ gli alias restano come {riferimenti} che lo strumento
31
+ che li usa dovrà risolvere.
32
+ 'resolve' — valuta l'espressione numericamente e scrive un valore concreto.
33
+ L'unità è ereditata dal primo token dimension
34
+ referenziato nell'espressione (ad es. {size.base} = 16px
35
+ -> 16 * .25 = 4 -> "4px"). Se la valutazione fallisce
36
+ l'espressione originale viene mantenuta con un warning.
37
+ */
36
38
 
37
39
  import StyleDictionary from 'style-dictionary';
38
40
  import path from 'node:path';
39
41
 
40
- // Disclaimer prepended to every generated file when jsonFormat is 'jsonc'
42
+ // Intestazione anteposta a ogni file generato quando jsonFormat è 'jsonc'
41
43
  const DISCLAIMER = [
42
44
  '// -----------------------------------------------------------------------',
43
- '// Generated file — do not edit manually.',
44
- '// This file is produced by the design-token build pipeline.',
45
- '// Source of truth: the token files in the project source directory.',
46
- '// Re-generate with: node build-tokens.mjs --config <path/to/config>',
45
+ '// File generato — non modificare a mano.',
46
+ '// Questo file è prodotto dalla pipeline di build dei design token.',
47
+ '// Fonte di verità: i file dei token nella directory sorgente del progetto.',
48
+ '// Per rigenerarlo: node build-tokens.mjs --config <path/to/config>',
47
49
  '// -----------------------------------------------------------------------',
48
50
  '',
49
51
  ].join('\n');
50
52
 
51
- // ── Expression helpers ────────────────────────────────────────────────────────
53
+ // ── Helper per le espressioni ─────────────────────────────────────────────────
52
54
 
53
- // Returns true if the string contains a math expression — i.e. it has at least
54
- // one operator (+, -, *, /) outside of a token reference ({...}).
55
- // Negative values like "-0.5rem" or "-8px" are NOT expressions.
55
+ /*
56
+ Restituisce true se la stringa contiene un'espressione matematica — cioè ha almeno
57
+ un operatore (+, -, *, /) fuori da un riferimento a token ({...}).
58
+ I valori negativi come "-0.5rem" o "-8px" NON sono espressioni.
59
+ */
56
60
  const isExpression = (str) => {
57
61
  if (typeof str !== 'string') return false;
58
- // Strip token references, then check for operators
62
+ // Rimuove i riferimenti ai token, poi cerca gli operatori
59
63
  const stripped = str.replace(/\{[^}]+\}/g, '0');
60
- // Remove leading minus (negative number) before testing for operators.
61
- // An operator is only meaningful when it appears between two operands,
62
- // i.e. it is preceded by a digit, closing paren, or word character.
64
+ /*
65
+ Rimuove il meno iniziale (numero negativo) prima di cercare gli operatori.
66
+ Un operatore ha significato solo quando compare tra due operandi,
67
+ cioè è preceduto da una cifra, una parentesi chiusa o un carattere di parola.
68
+ */
63
69
  return /[\d)]\s*[+\-*/]/.test(stripped) || /[+*/]/.test(stripped.replace(/^-/, ''));
64
70
  };
65
71
 
66
- // Builds a token lookup map (dot-path -> token) from the dictionary.
72
+ // Costruisce una mappa di lookup dei token (dot-path -> token) dal dizionario.
67
73
  const makeTokenMap = (dictionary) => {
68
74
  const map = {};
69
75
  for (const token of dictionary.allTokens) {
@@ -72,23 +78,25 @@ const makeTokenMap = (dictionary) => {
72
78
  return map;
73
79
  };
74
80
 
75
- // Resolves a dimension expression to a concrete value string (e.g. "4px").
76
- //
77
- // Strategy:
78
- // 1. Find the first {reference} in the expression.
79
- // 2. Look it up in the token map to obtain its resolved numeric value and unit.
80
- // 3. Replace ALL {references} in the expression with their numeric values.
81
- // 4. Evaluate the resulting arithmetic expression with Function().
82
- // 5. Reattach the unit from step 2.
83
- //
84
- // Returns null if resolution fails (caller falls back to the original string).
81
+ /*
82
+ Risolve un'espressione dimension in una stringa di valore concreto (ad es. "4px").
83
+
84
+ Strategia:
85
+ 1. Trova il primo {riferimento} nell'espressione.
86
+ 2. Lo cerca nella mappa dei token per ottenerne il valore numerico risolto e l'unità.
87
+ 3. Sostituisce TUTTI i {riferimenti} nell'espressione con i loro valori numerici.
88
+ 4. Valuta con Function() l'espressione aritmetica risultante.
89
+ 5. Riattacca l'unità del passo 2.
90
+
91
+ Restituisce null se la risoluzione fallisce (il chiamante ripiega sulla stringa originale).
92
+ */
85
93
  const resolveExpression = (orig, tokenMap) => {
86
- // Collect all {reference} keys in order of appearance
94
+ // Raccoglie tutte le chiavi {reference} in ordine di comparsa
87
95
  const refPattern = /\{([^}]+)\}/g;
88
96
  const refs = [...orig.matchAll(refPattern)];
89
97
  if (refs.length === 0) return null;
90
98
 
91
- // Determine unit from the first referenced dimension token
99
+ // Determina l'unità dal primo token dimension referenziato
92
100
  const firstRef = tokenMap[refs[0][1]];
93
101
  if (!firstRef) return null;
94
102
 
@@ -98,7 +106,7 @@ const resolveExpression = (orig, tokenMap) => {
98
106
  const baseNum = parseFloat(firstVal);
99
107
  if (isNaN(baseNum)) return null;
100
108
 
101
- // Replace every {ref} with its numeric value
109
+ // Sostituisce ogni {ref} con il suo valore numerico
102
110
  let expr = orig;
103
111
  for (const match of refs) {
104
112
  const refKey = match[1];
@@ -109,13 +117,13 @@ const resolveExpression = (orig, tokenMap) => {
109
117
  expr = expr.replace(match[0], String(refVal));
110
118
  }
111
119
 
112
- // Evaluate — only allow digits, whitespace and arithmetic operators
120
+ // Valuta — consente solo cifre, spazi e operatori aritmetici
113
121
  if (!/^[\d\s+\-*/.()]+$/.test(expr)) return null;
114
122
 
115
123
  try {
116
124
  const result = Function(`"use strict"; return (${expr})`)();
117
125
  if (typeof result !== 'number' || !isFinite(result)) return null;
118
- // Round to a reasonable precision to avoid floating-point noise
126
+ // Arrotonda a una precisione ragionevole per evitare il rumore della virgola mobile
119
127
  const rounded = parseFloat(result.toPrecision(10));
120
128
  return unit ? `${rounded}${unit}` : String(rounded);
121
129
  } catch {
@@ -123,7 +131,7 @@ const resolveExpression = (orig, tokenMap) => {
123
131
  }
124
132
  };
125
133
 
126
- // Wraps a dimension expression in CSS calc(), leaving {references} intact.
134
+ // Racchiude un'espressione dimension in calc() CSS, lasciando intatti i {riferimenti}.
127
135
  const toCalc = (orig) => `calc(${orig})`;
128
136
 
129
137
  // ── Format ───────────────────────────────────────────────────────────────────
@@ -136,11 +144,11 @@ StyleDictionary.registerFormat({
136
144
  const tokenMap = (expressionMode === 'resolve') ? makeTokenMap(dictionary) : null;
137
145
 
138
146
  for (const token of dictionary.allTokens) {
139
- // Tokens loaded via `include` (sourceModes: base-mode tokens made
140
- // available to other modes for reference resolution) are not output.
147
+ // I token caricati tramite `include` (sourceModes: token della modalità base resi
148
+ // disponibili alle altre modalità per la risoluzione dei riferimenti) non vengono emessi.
141
149
  if (token.isSource === false) continue;
142
150
 
143
- // Rebuild the nested tree from the token path
151
+ // Ricostruisce l'albero annidato dal percorso del token
144
152
  let node = root;
145
153
  for (let i = 0; i < token.path.length - 1; i++) {
146
154
  const segment = token.path[i];
@@ -152,7 +160,7 @@ StyleDictionary.registerFormat({
152
160
  const type = token.$type ?? token.type;
153
161
  const orig = token.original?.$value ?? token.original?.value;
154
162
 
155
- // ── Value resolution ────────────────────────────────────────────────────
163
+ // ── Risoluzione del valore ──────────────────────────────────────────────
156
164
  let value;
157
165
 
158
166
  if (
@@ -160,29 +168,31 @@ StyleDictionary.registerFormat({
160
168
  typeof orig === 'string' &&
161
169
  isExpression(orig)
162
170
  ) {
163
- // The original $value is a math expression
171
+ // Il $value originale è un'espressione matematica
164
172
  if (expressionMode === 'resolve') {
165
173
  const resolved = resolveExpression(orig, tokenMap);
166
174
  if (resolved !== null) {
167
175
  value = resolved;
168
176
  } else {
169
- // Resolution failed — keep the original and emit a warning
177
+ // Risoluzione fallita — mantiene l'originale ed emette un warning
170
178
  // eslint-disable-next-line no-console
171
179
  console.warn(`[build-tokens] json: could not resolve expression "${orig}" for token "${token.path.join('.')}". Keeping original.`);
172
180
  value = orig;
173
181
  }
174
182
  } else if (expressionMode === 'calc') {
175
- // Replace {refs} with their alias notation and wrap in calc()
183
+ // Sostituisce i {riferimenti} con la loro notazione alias e racchiude in calc()
176
184
  value = toCalc(orig);
177
185
  } else {
178
- // 'keep' — write the expression unchanged
186
+ // 'keep' — scrive l'espressione invariata
179
187
  value = orig;
180
188
  }
181
189
  } else {
182
- // Non-expression value: preserve {references} wherever they appear.
183
- // - Pure alias: "{some.token}" → kept as-is to preserve token links
184
- // - CSS function: "color-mix(in srgb, {some.token} 60%, #000)" → kept as-is
185
- // - Plain value: "#ff0000", "16px", … → use the resolved $value
190
+ /*
191
+ Valore non espressione: conserva i {riferimenti} ovunque compaiano.
192
+ - Alias puro: "{some.token}" → mantenuto così com'è per preservare i collegamenti tra token
193
+ - Funzione CSS: "color-mix(in srgb, {some.token} 60%, #000)" → mantenuta così com'è
194
+ - Valore semplice: "#ff0000", "16px", … → usa il $value risolto
195
+ */
186
196
  const containsRef = typeof orig === 'string' && orig.includes('{');
187
197
  value = containsRef ? orig : (token.$value ?? token.value);
188
198
  }
@@ -201,9 +211,8 @@ StyleDictionary.registerFormat({
201
211
  });
202
212
 
203
213
  // ── collectConcreteFilePaths ──────────────────────────────────────────────────
204
- //
205
- // Extracts the unique concrete file paths from a Style Dictionary instance.
206
- // Must be called AFTER `await sd.hasInitialized`.
214
+ // Estrae i percorsi di file concreti univoci da un'istanza di Style Dictionary.
215
+ // Va chiamata DOPO `await sd.hasInitialized`.
207
216
 
208
217
  export const collectConcreteFilePaths = async (sd) => {
209
218
  await sd.hasInitialized;
@@ -215,16 +224,17 @@ export const collectConcreteFilePaths = async (sd) => {
215
224
  };
216
225
 
217
226
  // ── buildJsonFiles ──────────────────────────────────────────────────────────
218
- //
219
- // @param {string[]} concreteFilePaths From collectConcreteFilePaths()
220
- // @param {string|null} jsonDestFile Aggregated file base name, or null
221
- // @param {'json'|'jsonc'} jsonFormat Output format
222
- // @param {'keep'|'calc'|'resolve'} jsonExpression Expression handling mode
223
- // @param {string} [suffix] Appended to every destination
224
- // filename, before the extension — used by the sourceModes build
225
- // (build-source-modes.mjs) to produce one set of files per mode, e.g.
226
- // "-light" -> "tokens-light.jsonc" / "size-light.jsonc" (default: '')
227
- // @returns {object[]} File descriptors for the Style Dictionary platform
227
+ /*
228
+ @param {string[]} concreteFilePaths Da collectConcreteFilePaths()
229
+ @param {string|null} jsonDestFile Nome base del file aggregato, oppure null
230
+ @param {'json'|'jsonc'} jsonFormat Formato di output
231
+ @param {'keep'|'calc'|'resolve'} jsonExpression Modalità di gestione delle espressioni
232
+ @param {string} [suffix] Aggiunto a ogni nome di file di
233
+ destinazione, prima dell'estensione — usato dalla build sourceModes
234
+ (build-source-modes.mjs) per produrre un set di file per modalità, ad es.
235
+ "-light" -> "tokens-light.jsonc" / "size-light.jsonc" (default: '')
236
+ @returns {object[]} Descrittori di file per la platform di Style Dictionary
237
+ */
228
238
 
229
239
  export const buildJsonFiles = (
230
240
  concreteFilePaths,
@@ -244,11 +254,13 @@ export const buildJsonFiles = (
244
254
  }];
245
255
  }
246
256
 
247
- // One file per source, all placed flat in jsonBuildPath — no subdirectories
248
- // mirroring the source tree. Since source files can share a basename across
249
- // different directories (e.g. two components each with their own
250
- // <name>.minimo.tokens.mjs), fail loudly on collisions instead of letting
251
- // one silently overwrite the other.
257
+ /*
258
+ Un file per sorgente, tutti nella stessa cartella jsonBuildPath — senza sottocartelle
259
+ che replicano l'albero dei sorgenti. Dato che i file sorgente possono condividere il nome base in
260
+ directory diverse (ad es. due componenti ciascuno con il proprio
261
+ <name>.minimo.tokens.mjs), in caso di collisioni fallisce in modo esplicito invece di lasciare
262
+ che uno sovrascriva l'altro in silenzio.
263
+ */
252
264
  const pathsByDestName = new Map();
253
265
  for (const filePath of concreteFilePaths) {
254
266
  const destName = path.basename(filePath).replace(/\.[^.]+$/, '') + suffix + ext;
@@ -1,75 +1,79 @@
1
- // build-tokens-src/legacy-tokens-parser.mjs
2
- // Registers a Style Dictionary parser that bridges "legacy" token files
3
- // (Style Dictionary v3/v4-style syntax: no `$` prefix on `value`/`type`,
4
- // references written as `{group.token.value}`) into the W3C DTCG syntax
5
- // (`$value`/`$type`, references as `{group.token}`) required by Style
6
- // Dictionary v5.
7
- //
8
- // Why this is needed: Style Dictionary v5 decides whether a build "usesDtcg"
9
- // ONCE per build, from whichever source file is processed first (see
10
- // detectDtcgSyntax() called inside combineJSON.js in style-dictionary) — it
11
- // is a single global flag, not a per-file check. Mixing a legacy-syntax file
12
- // (e.g. a file exported from Open Props, or from an old Style Dictionary
13
- // v3/v4 project) together with DTCG sources therefore causes the legacy
14
- // file's tokens to be silently dropped regardless of file order: they never
15
- // carry the `$value` key combineJSON's own tagging (and the rest of the
16
- // pipeline) expects.
17
- //
18
- // This parser intercepts every `.json` source file (not `.jsonc` — that
19
- // extension is reserved in this project for hand-authored DTCG sources,
20
- // already handled correctly by Style Dictionary's own built-in loader) and
21
- // converts, node by node:
22
- // value -> $value, type -> $type, comment/description -> $description
23
- // "{group.token.value}" -> "{group.token}" inside reference strings
24
- // Nodes that already use `$value` (DTCG v5 syntax) are left untouched, so
25
- // the parser is a safe no-op for files that don't need conversion — no
26
- // config flag or file list is required, detection is fully automatic.
27
- //
28
- // "Hybrid" nodes (a token with its own value that is also a group with
29
- // nested children, e.g. Open Props' other.ease.out) can't be represented in
30
- // DTCG v5, where a node with $value is a leaf. The own value is moved to a
31
- // child token named `default` (or `base` if `default` is already a child
32
- // name; the build fails if both are taken) — see collectHybridNodes().
33
- //
34
- // Limitation: `.json` files handled by this parser are parsed with plain
35
- // JSON.parse (no comments, no trailing commas), unlike Style Dictionary's
36
- // own built-in loader (which uses JSON5 for .json/.jsonc/.json5). This keeps
37
- // the builder dependency-free — legacy token exports (Open Props, old Style
38
- // Dictionary v3/v4 projects) are virtually always strict JSON anyway. Use
39
- // `.jsonc` or `.mjs` for hand-authored DTCG sources that need comments.
1
+ /*
2
+ build-tokens-src/legacy-tokens-parser.mjs
3
+ Registra un parser di Style Dictionary che fa da ponte tra i file di token "legacy"
4
+ (sintassi in stile Style Dictionary v3/v4: nessun prefisso `$` su `value`/`type`,
5
+ riferimenti scritti come `{group.token.value}`) e la sintassi W3C DTCG
6
+ (`$value`/`$type`, riferimenti come `{group.token}`) richiesta da Style
7
+ Dictionary v5.
8
+
9
+ Perché serve: Style Dictionary v5 decide se una build "usesDtcg"
10
+ UNA SOLA VOLTA per build, a partire dal primo file sorgente elaborato (vedi
11
+ detectDtcgSyntax() chiamata in combineJSON.js di style-dictionary) — è
12
+ un unico flag globale, non un controllo per file. Mescolare un file in sintassi
13
+ legacy (ad es. un file esportato da Open Props, o da un vecchio progetto
14
+ Style Dictionary v3/v4) con sorgenti DTCG fa quindi sì che i token del
15
+ file legacy vengano scartati in silenzio, qualunque sia l'ordine dei file: non hanno mai
16
+ la chiave `$value` che il tagging di combineJSON (e il resto della
17
+ pipeline) si aspetta.
18
+
19
+ Questo parser intercetta ogni file sorgente `.json` (non `.jsonc` — quell'
20
+ estensione è riservata in questo progetto alle sorgenti DTCG scritte a mano,
21
+ già gestite correttamente dal loader integrato di Style Dictionary) e
22
+ converte, nodo per nodo:
23
+ value -> $value, type -> $type, comment/description -> $description
24
+ "{group.token.value}" -> "{group.token}" dentro le stringhe di riferimento
25
+ I nodi che usano già `$value` (sintassi DTCG v5) restano intatti, quindi
26
+ il parser è un no-op sicuro per i file che non richiedono conversione — non serve
27
+ alcun flag di config né elenco di file, il rilevamento è completamente automatico.
28
+
29
+ I nodi "ibridi" (un token con un valore proprio che è anche un gruppo con
30
+ figli annidati, ad es. other.ease.out di Open Props) non possono essere rappresentati in
31
+ DTCG v5, dove un nodo con $value è una foglia. Il valore proprio viene spostato in un
32
+ token figlio chiamato `default` (oppure `base` se `default` è già il nome di un
33
+ figlio; la build fallisce se entrambi sono occupati) — vedi collectHybridNodes().
34
+
35
+ Limitazione: i file `.json` gestiti da questo parser vengono letti con un semplice
36
+ JSON.parse (niente commenti, niente trailing comma), a differenza del loader
37
+ integrato di Style Dictionary (che usa JSON5 per .json/.jsonc/.json5). Così il builder
38
+ resta privo di dipendenze — le esportazioni di token legacy (Open Props, vecchi progetti
39
+ Style Dictionary v3/v4) sono comunque quasi sempre JSON rigoroso. Usare
40
+ `.jsonc` o `.mjs` per le sorgenti DTCG scritte a mano che richiedono commenti.
41
+ */
40
42
 
41
43
  import StyleDictionary from 'style-dictionary';
42
44
 
43
45
  export const LEGACY_TOKENS_PARSER_NAME = 'minimo/legacy-tokens';
44
46
 
45
- // Matches "{some.token.path.value}" -> captures "some.token.path"
47
+ // Corrisponde a "{some.token.path.value}" -> cattura "some.token.path"
46
48
  const LEGACY_REF = /\{([^}]+)\.value\}/g;
47
49
 
48
- // Name of the child token that receives the own value of a "hybrid" node
49
- // (see collectHybridNodes()); FALLBACK_LEAF is used when a child with the
50
- // preferred name already exists.
50
+ /*
51
+ Nome del token figlio che riceve il valore proprio di un nodo "ibrido"
52
+ (vedi collectHybridNodes()); FALLBACK_LEAF viene usato quando esiste già un figlio
53
+ con il nome preferito.
54
+ */
51
55
  const PREFERRED_LEAF = 'default';
52
56
  const FALLBACK_LEAF = 'base';
53
57
 
54
58
  /** @param {unknown} node @returns {node is Record<string, unknown>} */
55
59
  const isPlainObject = (node) => node !== null && typeof node === 'object' && !Array.isArray(node);
56
60
 
57
- // True if the node is (or contains, at any depth) a token, legacy or DTCG.
61
+ // True se il nodo è (o contiene, a qualsiasi profondità) un token, legacy o DTCG.
58
62
  /** @param {unknown} node @returns {boolean} */
59
63
  const hasTokenDescendant = (node) => isPlainObject(node)
60
64
  && (Object.hasOwn(node, 'value') || Object.hasOwn(node, '$value')
61
65
  || Object.values(node).some(hasTokenDescendant));
62
66
 
63
67
  /*
64
- * A "hybrid" legacy node is a token (own `value`) that is also a group, i.e.
65
- * has children that are tokens or groups of tokens (e.g. Open Props'
66
- * other.ease.out, with its own value plus out.1 ... out.5). The own value is
67
- * moved to a child token: `default`, or `base` if `default` is already a
68
- * child name. If both are taken the build fails. Returns a map
69
- * dot.path -> chosen child name, used to convert the node itself and to
70
- * rewrite references pointing to it (references are only rewritten within
71
- * the same file: a reference from another file to a hybrid node must use the
72
- * child name explicitly).
68
+ * Un nodo legacy "ibrido" è un token (con `value` proprio) che è anche un gruppo, cioè
69
+ * ha figli che sono token o gruppi di token (ad es. other.ease.out di Open Props,
70
+ * con un valore proprio più out.1 ... out.5). Il valore proprio viene
71
+ * spostato in un token figlio: `default`, oppure `base` se `default` è già il nome
72
+ * di un figlio. Se entrambi sono occupati la build fallisce. Restituisce una mappa
73
+ * dot.path -> nome del figlio scelto, usata per convertire il nodo stesso e per
74
+ * riscrivere i riferimenti che puntano a esso (i riferimenti vengono riscritti solo
75
+ * all'interno dello stesso file: un riferimento da un altro file a un nodo ibrido deve
76
+ * usare esplicitamente il nome del figlio).
73
77
  */
74
78
  /**
75
79
  * @param {unknown} node
@@ -130,7 +134,7 @@ const convertLegacyRefs = (value, hybrids) => {
130
134
  const convertLegacyNode = (node, path, hybrids) => {
131
135
  if (!isPlainObject(node)) return node;
132
136
 
133
- // Already DTCG v5 syntax: leave untouched.
137
+ // Già sintassi DTCG v5: lascia intatto.
134
138
  if (Object.hasOwn(node, '$value')) return node;
135
139
 
136
140
  if (Object.hasOwn(node, 'value')) {
@@ -145,7 +149,7 @@ const convertLegacyNode = (node, path, hybrids) => {
145
149
  const hybridLeaf = hybrids.get(path.join('.'));
146
150
  if (hybridLeaf === undefined) return token;
147
151
 
148
- // Hybrid node: becomes a group, its own value moves to a child token.
152
+ // Nodo ibrido: diventa un gruppo, il suo valore proprio si sposta in un token figlio.
149
153
  return {
150
154
  ...Object.fromEntries(
151
155
  Object.entries(rest).map(([key, child]) => [key, convertLegacyNode(child, [...path, key], hybrids)])
@@ -154,26 +158,29 @@ const convertLegacyNode = (node, path, hybrids) => {
154
158
  };
155
159
  }
156
160
 
157
- // Group node: recurse into children.
161
+ // Nodo gruppo: ricorre nei figli.
158
162
  return Object.fromEntries(
159
163
  Object.entries(node).map(([key, child]) => [key, convertLegacyNode(child, [...path, key], hybrids)])
160
164
  );
161
165
  };
162
166
 
163
- // Exported for reuse by token-rename-parser.mjs, which needs the same
164
- // legacy-or-DTCG .json loading (hybrid-node handling included) for the
165
- // subset of files that also have a `transform` rename map registered.
167
+ /*
168
+ Esportata per il riutilizzo da token-rename-parser.mjs, che richiede lo stesso
169
+ caricamento .json legacy-o-DTCG (gestione dei nodi ibridi inclusa) per il
170
+ sottoinsieme di file che hanno anche una mappa di rinomina `transform` registrata.
171
+ */
166
172
  /** @param {string} contents @param {string} filePath @returns {unknown} */
167
173
  export const parseLegacyFile = (contents, filePath) => {
168
174
  const tree = JSON.parse(contents);
169
175
  return convertLegacyNode(tree, [], collectHybridNodes(tree, [], filePath));
170
176
  };
171
177
 
172
- // Registers the parser globally on the StyleDictionary class. To actually
173
- // run it, a Style Dictionary instance must also opt in via
174
- // `parsers: [LEGACY_TOKENS_PARSER_NAME]` in its config (registering alone
175
- // does not activate it for every instance — see Style Dictionary's parser
176
- // hooks docs).
178
+ /*
179
+ Registra il parser globalmente sulla classe StyleDictionary. Per eseguirlo
180
+ effettivamente, anche un'istanza di Style Dictionary deve aderire tramite
181
+ `parsers: [LEGACY_TOKENS_PARSER_NAME]` nella propria config (la sola registrazione
182
+ non lo attiva per ogni istanza — vedi la documentazione degli hook parser di Style Dictionary).
183
+ */
177
184
  export const registerLegacyTokensParser = () => {
178
185
  StyleDictionary.registerParser({
179
186
  name: LEGACY_TOKENS_PARSER_NAME,