@massimo-cassandro/minimo 1.18.3 → 1.19.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
@@ -31,6 +31,10 @@ rm -rf package
31
31
 
32
32
  ---
33
33
 
34
+ ## Design tokens
35
+
36
+ Minimo comes with a set of design tokens and some utilities to manage them. See [Design Tokens readme](design-tokens/README.md).
37
+
34
38
  ## Dev Tools
35
39
 
36
40
  The [`dev-tools`](./dev-tools/README.md) directory contains a set of standalone Node.js CLI utilities for managing a web project — updating dependencies, bumping the version and changelog, and generating/optimizing SVG icons and favicons. They are published as part of the `minimo` package and exposed via the `bin` entries in `package.json` (`update-version`, `upd@m`, `svgIconsTools`, `create-favicons`); see the [Dev Tools README](./dev-tools/README.md) for the full list and usage.
@@ -38,7 +42,7 @@ The [`dev-tools`](./dev-tools/README.md) directory contains a set of standalone
38
42
 
39
43
  ## Docs & Demo
40
44
 
41
- [Docs](docs)
45
+ [Docs](docs/README.md)
42
46
 
43
47
  [Demo](https://massimo-cassandro.github.io/minimo/) (in progress)
44
48
 
@@ -16,7 +16,7 @@
16
16
  },
17
17
  "max-width": {
18
18
  "$type": "dimension",
19
- "$value": "98dvw"
19
+ "$value": "70dvw"
20
20
  },
21
21
  "height": {
22
22
  "$type": "dimension",
@@ -75,6 +75,11 @@ export const penpotExpressions = VALID_EXPR_MODES.includes(buildConfig.penpotExp
75
75
  ? buildConfig.penpotExpressions
76
76
  : 'resolve';
77
77
 
78
+ // mergeCustomProps: if true, custom properties already present in the CSS
79
+ // destination file take priority over the ones generated by this build (see
80
+ // build-tokens-src/merge-css.mjs). Default: false.
81
+ export const mergeCustomProps = buildConfig.mergeCustomProps === true;
82
+
78
83
  // ---------------------------------------------------------------------------
79
84
  // Source: resolve patterns relative to the config directory and normalise to
80
85
  // forward-slash absolute paths (fast-glob, used internally by Style Dictionary,
@@ -6,6 +6,7 @@
6
6
  // - individual properties for letterSpacing, textTransform, textDecoration
7
7
 
8
8
  import StyleDictionary from 'style-dictionary';
9
+ import { mergeCustomProps, parseCustomProps } from '../merge-css.mjs';
9
10
 
10
11
  const BASE_FONT_SIZE = 16;
11
12
 
@@ -224,7 +225,22 @@ StyleDictionary.registerFormat({
224
225
  return [` --${token.name}: ${value};`];
225
226
  });
226
227
 
227
- customPropsCount = lines.length;
228
- return `${selector} {\n${lines.join('\n')}\n}\n`;
228
+ // Build a name → declaration-tail map from the declarations generated
229
+ // above, then merge with any pre-existing custom properties loaded via
230
+ // loadExistingCustomProps() (see ../merge-css.mjs). Pre-existing values
231
+ // (including trailing comments) take priority when both exist;
232
+ // pre-existing-only properties are kept.
233
+ const generatedProps = parseCustomProps(lines.join('\n'));
234
+ const finalProps = mergeCustomProps(generatedProps);
235
+
236
+ // Final output is always sorted alphabetically ascending by property
237
+ // name, regardless of merge — this also keeps pre-existing-only
238
+ // properties from merge-css.mjs in order instead of trailing at the end.
239
+ const outLines = Object.entries(finalProps)
240
+ .sort(([a], [b]) => a.localeCompare(b, 'en', { numeric: true, sensitivity: 'base' }))
241
+ .map(([name, tail]) => ` --${name}: ${tail}`);
242
+
243
+ customPropsCount = outLines.length;
244
+ return `${selector} {\n${outLines.join('\n')}\n}\n`;
229
245
  },
230
246
  });
@@ -0,0 +1,60 @@
1
+ // build-tokens-src/merge-css.mjs
2
+ // Supports the `mergeCustomProps` config option: pre-existing custom
3
+ // properties in the CSS destination file take priority over the ones
4
+ // generated by the current build (manual overrides/additions survive rebuilds).
5
+ //
6
+ // Usage:
7
+ // 1. Call loadExistingCustomProps(absDestPath) BEFORE Style Dictionary runs,
8
+ // since it reads the file that is about to be overwritten.
9
+ // 2. The css/variables-sorted format (see formats/css.mjs) calls
10
+ // mergeCustomProps(generatedMap) while building the output, right before
11
+ // serialising the final CSS text.
12
+
13
+ import { existsSync, readFileSync } from 'node:fs';
14
+
15
+ const CUSTOM_PROP_RE = /^\s*--([\w-]+):\s*(.+)$/gm;
16
+
17
+ /**
18
+ * Parses `--name: <tail>` declarations out of a CSS text block. <tail> is
19
+ * captured verbatim (value, terminating `;`, and anything else on the same
20
+ * line, e.g. a trailing comment) so it round-trips unchanged through a merge.
21
+ * Only single-line declarations are supported.
22
+ * @param {string} cssText
23
+ * @returns {Record<string,string>} name → declaration-tail map, in first-seen order
24
+ */
25
+ export const parseCustomProps = (cssText) => {
26
+ /** @type {Record<string,string>} */
27
+ const map = {};
28
+ for (const match of cssText.matchAll(CUSTOM_PROP_RE)) {
29
+ map[match[1]] = match[2].trim();
30
+ }
31
+ return map;
32
+ };
33
+
34
+ // null = merge disabled, or destination file not found yet (first build)
35
+ /** @type {Record<string,string>|null} */
36
+ let existingCustomProps = null;
37
+
38
+ /**
39
+ * Reads the CSS destination file (if it exists) and stores a name → value
40
+ * map of its current custom properties for later merging.
41
+ * @param {string} absDestPath absolute path of the CSS file to read
42
+ * @returns {Record<string,string>|null}
43
+ */
44
+ export const loadExistingCustomProps = (absDestPath) => {
45
+ existingCustomProps = existsSync(absDestPath)
46
+ ? parseCustomProps(readFileSync(absDestPath, 'utf8'))
47
+ : null;
48
+ return existingCustomProps;
49
+ };
50
+
51
+ /**
52
+ * Merges freshly generated custom properties with the ones previously loaded
53
+ * via loadExistingCustomProps(). Pre-existing values take priority; custom
54
+ * properties found only in the pre-existing file (no longer generated) are
55
+ * kept as well.
56
+ * @param {Record<string,string>} generated name → value map produced by this build
57
+ * @returns {Record<string,string>}
58
+ */
59
+ export const mergeCustomProps = (generated) =>
60
+ existingCustomProps ? { ...generated, ...existingCustomProps } : generated;
@@ -31,6 +31,7 @@ import {
31
31
  penpotFormat,
32
32
  penpotExpressions,
33
33
  source,
34
+ mergeCustomProps,
34
35
  } from './build-tokens-src/config.mjs';
35
36
 
36
37
  // ── 2. Custom transforms ─────────────────────────────────────────────────────
@@ -38,7 +39,9 @@ import './build-tokens-src/transforms.mjs';
38
39
 
39
40
  // ── 3. CSS format ─────────────────────────────────────────────────────────────
40
41
  // customPropsCount is updated by the format at render time
42
+ // loadExistingCustomProps supports the mergeCustomProps option (see below)
41
43
  import { customPropsCount } from './build-tokens-src/formats/css.mjs';
44
+ import { loadExistingCustomProps } from './build-tokens-src/merge-css.mjs';
42
45
 
43
46
  // ── 4. Penpot format ──────────────────────────────────────────────────────────
44
47
  import { buildPenpotFiles, collectConcreteFilePaths } from './build-tokens-src/formats/penpot.mjs';
@@ -46,6 +49,15 @@ import { buildPenpotFiles, collectConcreteFilePaths } from './build-tokens-src/f
46
49
  // ── 5. Platforms builder ──────────────────────────────────────────────────────
47
50
  import { buildPlatforms } from './build-tokens-src/platforms.mjs';
48
51
 
52
+ // ── 5b. Pre-existing custom properties (mergeCustomProps option) ────────────
53
+ // Read before Style Dictionary runs, since it overwrites the destination
54
+ // file. The css/variables-sorted format (formats/css.mjs) merges these
55
+ // values in — pre-existing values take priority — right before serialising
56
+ // the final CSS output. See merge-css.mjs.
57
+ if (mergeCustomProps) {
58
+ loadExistingCustomProps(path.join(buildPath, destFile));
59
+ }
60
+
49
61
  // ── 6. Collect concrete source file paths (multi-file Penpot mode only) ──────
50
62
  // Source entries may be glob patterns. SD expands them internally and stores
51
63
  // the concrete path in token.filePath. We need those concrete paths to build
@@ -75,6 +75,14 @@ const config = {
75
75
  // e.g. {size.base} = 16px, "{size.base} * .25" -> "4px"
76
76
  penpotExpressions: 'resolve',
77
77
 
78
+ // If true, custom properties already present in the CSS destination file
79
+ // (destFile, from a previous build) take priority over the ones generated
80
+ // by this build. Properties found only in the pre-existing file (no longer
81
+ // generated) are kept too. Useful to preserve manual overrides/additions
82
+ // made directly in the compiled CSS across rebuilds. Ignored on the first
83
+ // build, when destFile does not exist yet. Default: false.
84
+ mergeCustomProps: false,
85
+
78
86
 
79
87
 
80
88
  // ---------------------------------------------------------------------------
@@ -34,6 +34,14 @@ zsh package/dev-tools/starter-kit/starter-install.sh
34
34
  rm -rf package
35
35
  ```
36
36
 
37
+ To test the installation skipping all `npm install` commands, use the `--no-npm` parameter:
38
+
39
+ ```bash
40
+ curl -sL "$(npm view @massimo-cassandro/minimo dist.tarball)" | tar xz package/dev-tools/starter-kit
41
+ zsh package/dev-tools/starter-kit/starter-install.sh --no-npm
42
+ rm -rf package
43
+ ```
44
+
37
45
  ## SVG adn favicons tools
38
46
 
39
47
  ```bash
@@ -18,6 +18,23 @@ if [ -z "$ZSH_VERSION" ]; then
18
18
  exit 1
19
19
  fi
20
20
 
21
+ # --no-npm: salta le installazioni npm (utile per testare rapidamente lo script)
22
+ SKIP_NPM=0
23
+ for ARG in "$@"; do
24
+ if [ "$ARG" = "--no-npm" ]; then
25
+ SKIP_NPM=1
26
+ fi
27
+ done
28
+
29
+ # Wrapper: esegue "npm i ..." a meno che SKIP_NPM sia attivo
30
+ npm_i() {
31
+ if [ "$SKIP_NPM" = "1" ]; then
32
+ echo "(--no-npm) skip: npm i $*"
33
+ else
34
+ npm i "$@"
35
+ fi
36
+ }
37
+
21
38
  # Configurazione variabili
22
39
  # BASE_URL="https://raw.githubusercontent.com/massimo-cassandro/minimo/refs/heads/main"
23
40
 
@@ -139,28 +156,28 @@ fi
139
156
 
140
157
 
141
158
  echo -e "\n${GREEN}...eslint${NC}"
142
- npm i -D @massimo-cassandro/eslint-config
159
+ npm_i -D @massimo-cassandro/eslint-config
143
160
  safe_cat "${TEMPLATES_DIR}/eslint.config.mjs" eslint.config.mjs new
144
161
 
145
162
  echo -e "\n${GREEN}...stylelint${NC}"
146
- npm i -D @massimo-cassandro/stylelint-config
163
+ npm_i -D @massimo-cassandro/stylelint-config
147
164
  safe_cat "${TEMPLATES_DIR}/stylelint.config.mjs" stylelint.config.mjs new
148
165
 
149
166
  echo -e "\n${GREEN}...webpack${NC}"
150
- npm i -D webpack-cli webpack-dev-server webpack-manifest-plugin webpack
151
- npm i -D @babel/core @babel/preset-env babel-loader terser-webpack-plugin
152
- npm i -D webpack-remove-empty-scripts copy-webpack-plugin html-loader html-webpack-plugin
153
- npm i -D postcss autoprefixer postcss-custom-media @csstools/postcss-global-data postcss-loader postcss-preset-env
167
+ npm_i -D webpack-cli webpack-dev-server webpack-manifest-plugin webpack
168
+ npm_i -D @babel/core @babel/preset-env babel-loader terser-webpack-plugin
169
+ npm_i -D webpack-remove-empty-scripts copy-webpack-plugin html-loader html-webpack-plugin
170
+ npm_i -D postcss autoprefixer postcss-custom-media @csstools/postcss-global-data postcss-loader postcss-preset-env
154
171
  # NB: niente cssnano: la minificazione è di css-minimizer-webpack-plugin e cssnano
155
172
  # nel loader postcss eliminerebbe i commenti `purgecss ignore` prima di PurgeCSS
156
- npm i -D mini-css-extract-plugin style-loader css-loader css-minimizer-webpack-plugin
157
- npm i -D responsive-loader
158
- npm i -D process dotenv-webpack
159
- npm i -D svgo svg-url-loader svgo-loader svgo-add-viewbox mini-svg-data-uri
160
- npm i -D ejs-loader
161
- npm i -D purgecss-webpack-plugin glob
173
+ npm_i -D mini-css-extract-plugin style-loader css-loader css-minimizer-webpack-plugin
174
+ npm_i -D responsive-loader
175
+ npm_i -D process dotenv-webpack
176
+ npm_i -D svgo svg-url-loader svgo-loader svgo-add-viewbox mini-svg-data-uri
177
+ npm_i -D ejs-loader
178
+ npm_i -D purgecss-webpack-plugin glob
162
179
 
163
- npm i -D style-dictionary
180
+ npm_i -D style-dictionary
164
181
 
165
182
  safe_cat "${WEBPACK_SOURCE_DIR}/webpack.config.mjs" "${FRONTEND_INSTALL_PATH}/webpack.config.mjs"
166
183
  safe_cat "${WEBPACK_SOURCE_DIR}/webpack-template.ejs" "${FRONTEND_INSTALL_PATH}/webpack-template.ejs"
@@ -168,15 +185,6 @@ safe_cat "${WEBPACK_SOURCE_DIR}/webpack-template.ejs" "${FRONTEND_INSTALL_PATH}/
168
185
  # cartella webpack
169
186
  WEBPACK_LOCAL_DIR="${FRONTEND_INSTALL_PATH}/webpack-modules"
170
187
  WEBPACK_MODULES_REMOTE_URL="${WEBPACK_SOURCE_DIR}/webpack-modules"
171
- FILES=(
172
- 'css-rules.mjs'
173
- 'get-jsConfig-aliases.mjs'
174
- 'mini-svg-data-uri-loader.cjs'
175
- 'svg-rules.mjs'
176
- 'svgo.config.mjs'
177
- 'postcss.config.mjs'
178
- 'purgecss-variables-safelist.mjs'
179
- )
180
188
 
181
189
  # se la cartella esiste già, i moduli vengono copiati in NEW-webpack-modules
182
190
  # (da integrare manualmente o rimuovere)
@@ -188,18 +196,30 @@ fi
188
196
 
189
197
  mkdir -p "$WEBPACK_LOCAL_DIR"
190
198
 
191
- for FILE in "${FILES[@]}"; do
192
- safe_cat "${WEBPACK_MODULES_REMOTE_URL}/${FILE}" "${WEBPACK_LOCAL_DIR}/${FILE}"
199
+ # copia tutti i file presenti in webpack-modules,
200
+ for FILE in "${WEBPACK_MODULES_REMOTE_URL}"/*; do
201
+ [ -f "$FILE" ] || continue
202
+ safe_cat "$FILE" "${WEBPACK_LOCAL_DIR}/$(basename "$FILE")"
193
203
  done
194
204
 
195
205
  echo -e "\n${GREEN}Creating a template of your frontend application's folder structured${NC}"
196
206
 
197
- TEMPLATE_DIR_NAME="__frontend_app_dir_template__"
207
+ TEMPLATE_DIR_NAME="__frontend_dir__"
198
208
  mkdir -p "$TEMPLATE_DIR_NAME"
199
209
  cd "$TEMPLATE_DIR_NAME"
200
- mkdir -p error-pages imgs icons src src/css favicons design-tokens
210
+ mkdir -p error-pages imgs icons src css favicons design-tokens
201
211
  cd ..
202
212
 
213
+ # copia dei file css presenti nella root di minimo/src
214
+ # (custom-properties.css, custom-media.css, fonts.css, minimo.css, ...):
215
+ MINIMO_ROOT_CSS_DIR="${BASE_URL}/../../src"
216
+ for FILE in "${MINIMO_ROOT_CSS_DIR}"/*.css; do
217
+ safe_cat "$FILE" "${TEMPLATE_DIR_NAME}/css/$(basename "$FILE")"
218
+ done
219
+
220
+ # copia tokens.config.mjs
221
+ safe_cat "${BASE_URL}/../../design-tokens/tokens-config.mjs" "${TEMPLATE_DIR_NAME}/css/tokens-config.mjs"
222
+
203
223
  # template delle entry css (globale/di pagina e critical): ogni entry deve
204
224
  # importare direttamente custom-properties.css (vedi commenti nei file stessi)
205
225
  safe_cat "${TEMPLATES_DIR}/entry-tpl.css" "${TEMPLATE_DIR_NAME}/src/entry-tpl.css"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massimo-cassandro/minimo",
3
- "version": "1.18.3",
3
+ "version": "1.19.0",
4
4
  "description": "Light css framework & utilities",
5
5
  "type": "module",
6
6
  "main": "./index.js",
@@ -11,7 +11,7 @@ export default {
11
11
  },
12
12
  'max-width': {
13
13
  $type: 'dimension',
14
- $value: '98dvw',
14
+ $value: '70dvw',
15
15
  },
16
16
  height: {
17
17
  $type: 'dimension',
@@ -232,7 +232,7 @@
232
232
  --mpopup-header-padding: var(--size-xs);
233
233
  --mpopup-height: max-content;
234
234
  --mpopup-max-height: 5.625rem;
235
- --mpopup-max-width: 6.125rem;
235
+ --mpopup-max-width: 4.375rem;
236
236
  --mpopup-min-height: 18.75rem;
237
237
  --mpopup-min-width: 25rem;
238
238
  --mpopup-width: max-content;
@@ -1,185 +0,0 @@
1
- # Design Token Utilities
2
-
3
- A set of Node.js scripts for managing CSS design tokens in a project. Built on top of [Style Dictionary v5](https://styledictionary.com/).
4
-
5
- ## Scripts
6
-
7
- | Script | Purpose |
8
- |---|---|
9
- | `build-tokens.mjs` | Generates a CSS custom properties file from design token source files |
10
- | `check-unresolved-custom-props.mjs` | Scans CSS files and reports any `var(--...)` references not found in the generated token file |
11
-
12
- Both scripts share the same config file, passed via `--config`.
13
-
14
- ## Setup
15
-
16
- The scripts are intended to be used as npm scripts. Add them to your `package.json`:
17
-
18
- ```json
19
- {
20
- "scripts": {
21
- "build tokens": "npx buildTokens --config ./path/to/tokens-config.mjs",
22
- "check unresolved props": "npx checkUnresolvedProps --config ./path/to/tokens-config.mjs"
23
- }
24
- }
25
- ```
26
-
27
- ### Dependencies
28
-
29
- The following packages must be present in your project:
30
-
31
- ```json
32
- {
33
- "style-dictionary": "^5",
34
- "stylelint": "^16"
35
- }
36
- ```
37
-
38
- ## Configuration file
39
-
40
- Both scripts read a shared config file passed with `--config`. Use `tokens-config-sample.mjs` as a starting point.
41
-
42
- Read comments inside the sample file for more info.
43
-
44
-
45
- ## `build-tokens.mjs`
46
-
47
- Reads design token source files and generates:
48
- - A **CSS file** containing all tokens as custom properties inside `:root { ... }`
49
- - Optionally, one or more **W3C DTCG JSON/JSONC** files to import into Penpot/Figma (use in Figma requires a plugin).
50
-
51
- ### Usage
52
-
53
- ```sh
54
- npx buildTokens --config ./path/to/tokens-config.mjs
55
- ```
56
-
57
- ### Source files
58
-
59
- The `source` array accepts any combination of:
60
- - Concrete file paths: `'./tokens/colors.jsonc'`
61
- - Glob patterns: `'./tokens/**/*.{json,jsonc,mjs}'`
62
-
63
- **Supported formats:**
64
- - `.json` / `.jsonc` — parsed directly as token data
65
- - `.mjs` / `.js` — imported as ES modules; must export a W3C DTCG-compliant object as `default`
66
-
67
-
68
- ### Token file format (JS example)
69
-
70
- When using `.mjs` source files, export a default object following the [W3C Design Token Community Group format](https://design-tokens.github.io/community-group/format/):
71
-
72
- ```js
73
- // colors.tokens.mjs
74
- export default {
75
- color: {
76
- brand: {
77
- primary: { $type: 'color', $value: '#0057FF' },
78
- secondary: { $type: 'color', $value: '#FF6B00' },
79
- },
80
- neutral: {
81
- '100': { $type: 'color', $value: '#F5F5F5' },
82
- '900': { $type: 'color', $value: '#1A1A1A' },
83
- },
84
- },
85
- semantic: {
86
- color: {
87
- text: {
88
- primary: { $type: 'color', $value: '{color.neutral.900}' }, // alias
89
- },
90
- },
91
- },
92
- };
93
- ```
94
-
95
- The main advantage of `.mjs` over `.json` is the ability to use JavaScript variables, comments, and computed values within the token definition.
96
-
97
- Values can be expressions like `"{size.base} * .25"`, see `tokens-config-sample.mjs` for more info.
98
-
99
- ### Custom transforms
100
-
101
- The following transforms are registered on top of Style Dictionary's built-ins:
102
-
103
- | Name | Type | Description |
104
- |---|---|---|
105
- | `shadow/css` | value | Converts shadow objects (single or array) to a `box-shadow` CSS string. px values are converted to rem. |
106
- | `size/pxToRem-smart` | value | Converts `dimension` token values from px to rem. Skips values already in rem. |
107
- | `color/css-modern` | value | Color passthrough with transitive alias support. |
108
- | `gradient/css` | value | Converts gradient objects to CSS `linear-gradient`, `radial-gradient` or `conic-gradient`. |
109
- | `composite/css` | value | Converts `border`, `outline`, `transition` and `animation` objects to their CSS shorthand. |
110
- | `typography/css` | value | Typography passthrough — the format handles exploding the value into individual properties. |
111
-
112
- ### CSS output
113
-
114
- All tokens are output as CSS custom properties inside `:root`, sorted alphabetically.
115
-
116
- Typography tokens are expanded into multiple properties:
117
- - `--token-name-font` — a `font` shorthand (when both `fontSize` and `fontFamily` are present)
118
- - `--token-name-letter-spacing`, `--token-name-text-transform`, `--token-name-text-decoration` — individual properties
119
-
120
- The generated file is linted and auto-fixed with stylelint using the config specified in `stylelintConfigPath`.
121
-
122
- ### Penpot output
123
-
124
- When `penpotBuildPath` is set, the script also generates W3C DTCG token files for import into Penpot via the [Design Tokens plugin](https://penpot.app/penpot-files/design-tokens).
125
-
126
- **Single file** (`penpotDestFile` is a string):
127
- ```
128
- penpotBuildPath/tokens.jsonc ← all tokens in one file
129
- ```
130
-
131
- **One file per source** (`penpotDestFile` is `null` or omitted):
132
- ```
133
- penpotBuildPath/colors.tokens.jsonc
134
- penpotBuildPath/spacing.tokens.jsonc
135
- penpotBuildPath/typography.tokens.jsonc
136
- ```
137
-
138
- The `penpotFormat` option controls the output:
139
-
140
- | Value | Extension | Disclaimer header |
141
- |---|---|---|
142
- | `'jsonc'` | `.jsonc` | Yes |
143
- | `'json'` | `.json` | No |
144
-
145
- Alias references (`{color.brand.primary}`) are preserved in the output so Penpot maintains token links between primitive and semantic tokens.
146
-
147
- > Penpot token files intentionally use a minimal set of transforms (no px→rem conversion, no shorthand expansion) because Penpot expects original values and structured objects, not resolved CSS strings.
148
-
149
- ---
150
-
151
- ## `check-unresolved-custom-props.mjs`
152
-
153
- Scans all `.css` files in `dir_to_check` (recursively) and reports any `var(--...)` references that are not defined in the generated token CSS file or in any `extra_custom_props_files`.
154
-
155
- Results are written to `unresolved-props.md` in the same directory as the config file.
156
-
157
- ### Usage
158
-
159
- ```sh
160
- npx checkUnresolvedProps --config ./path/to/tokens-config.mjs
161
- ```
162
-
163
- ### Output
164
-
165
- The script creates a `unresolved-props.md` file next to the config file. Each line links to the file and line number where the unresolved property is used:
166
-
167
- ```markdown
168
- * [components.css :: 42](../src/components.css#L42) -> var(--color-action-hover)
169
- * [layout.css :: 17](../src/layout.css#L17) -> var(--spacing-missing)
170
- ```
171
-
172
- In VS Code, Option/Alt-clicking on the URL opens the file at the required line.
173
-
174
-
175
- ### Excluding properties
176
-
177
- Use `exclude_pattern` to suppress false positives — for example, internal/private custom properties that are defined dynamically or inline:
178
-
179
- ```js
180
- // skips all custom props starting with `--_` or `--js-`
181
- exclude_pattern: [
182
- /^--_/,
183
- /^--js-/,
184
- ]
185
- ```