@massimo-cassandro/minimo 1.15.1 → 1.16.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.
@@ -6,9 +6,31 @@ A collection of standalone Node.js CLI utilities to help manage a web project's
6
6
  * [Svg Icons Tools](./svg-icons-tools/README.md) — optimizes SVG icons and combines/converts them into symbols, JSX, or SCSS variables
7
7
  * [Create favicons](./create-favicons/README.md) — generates the full favicon set (SVG, PNG, ICO, webmanifest, HTML snippet) from a source image
8
8
  * [upd@m](./upd@m/README.md) — updates all `@massimo-cassandro/*` packages installed in `node_modules`
9
- * **webpack-setup** — script for installing minimo environment
9
+ * [webpack-setup](#webpack-setup) — script for installing minimo environment
10
10
 
11
- ## Usage of SVG adn favicons tools
11
+ ## webpack-setup
12
+
13
+ `webpack-setup/starter-install.sh` bootstraps a new frontend project: it copies the starter config files (`package.json`, `.gitignore`, `jsconfig.json`, eslint/stylelint configs, webpack config and modules, ...) and installs all the required dev dependencies.
14
+
15
+ The script **requires zsh** (it exits with an error if launched with `sh` or `bash`). Existing files are never overwritten: root config files are copied with a `NEW-` prefix, while `package.json` and the `*.code-workspace` file are merged (template keys are appended at the end, prefixed with `_`).
16
+
17
+ ### If minimo is already installed
18
+
19
+ ```bash
20
+ zsh node_modules/@massimo-cassandro/minimo/dev-tools/webpack-setup/starter-install.sh
21
+ ```
22
+
23
+ ### Without installing minimo
24
+
25
+ To bootstrap a project **before** (or without) installing the whole package, download only the `webpack-setup` folder from the npm tarball and run the script from there:
26
+
27
+ ```bash
28
+ curl -sL "$(npm view @massimo-cassandro/minimo dist.tarball)" | tar xz package/dev-tools/webpack-setup
29
+ zsh package/dev-tools/webpack-setup/starter-install.sh
30
+ rm -rf package
31
+ ```
32
+
33
+ ## SVG adn favicons tools
12
34
 
13
35
  ```bash
14
36
  ## SVG Icons Tools
@@ -0,0 +1,119 @@
1
+ #!/usr/bin/env node
2
+ // Merge JSONC: aggiunge in fondo al file di destinazione le chiavi di primo
3
+ // livello del template, prefissate con '_', preservando commenti e
4
+ // formattazione di entrambi i file.
5
+ // Uso: node merge-jsonc.cjs <template> <destinazione>
6
+
7
+ const fs = require('fs');
8
+
9
+ // Analizza un testo JSONC ignorando stringhe e commenti: individua
10
+ // l'oggetto principale, le virgole a profondità 1 e la posizione
11
+ // dell'ultimo carattere significativo (non spazio, non commento)
12
+ function scan(text) {
13
+ let depth = 0;
14
+ let open = -1;
15
+ let close = -1;
16
+ let last = -1;
17
+ const commas = [];
18
+ let i = 0;
19
+ while (i < text.length) {
20
+ const c = text[i];
21
+ const next = text[i + 1];
22
+ if (c === '"') {
23
+ i++;
24
+ while (i < text.length && text[i] !== '"') {
25
+ if (text[i] === '\\') i++;
26
+ i++;
27
+ }
28
+ last = i;
29
+ } else if (c === '/' && next === '/') {
30
+ while (i < text.length && text[i] !== '\n') i++;
31
+ continue;
32
+ } else if (c === '/' && next === '*') {
33
+ i += 2;
34
+ while (i < text.length && !(text[i] === '*' && text[i + 1] === '/')) i++;
35
+ i++;
36
+ } else {
37
+ if (c === '{' || c === '[') {
38
+ if (depth === 0 && open === -1 && c === '{') open = i;
39
+ depth++;
40
+ } else if (c === '}' || c === ']') {
41
+ depth--;
42
+ if (depth === 0 && close === -1) close = i;
43
+ } else if (c === ',' && depth === 1) {
44
+ commas.push(i);
45
+ }
46
+ if (!/\s/.test(c)) last = i;
47
+ }
48
+ i++;
49
+ }
50
+ return { open, close, commas, last };
51
+ }
52
+
53
+ // Posizione della prima doppia virgoletta fuori dai commenti
54
+ function firstQuotePos(text) {
55
+ let i = 0;
56
+ while (i < text.length) {
57
+ const c = text[i];
58
+ const next = text[i + 1];
59
+ if (c === '/' && next === '/') {
60
+ while (i < text.length && text[i] !== '\n') i++;
61
+ } else if (c === '/' && next === '*') {
62
+ i += 2;
63
+ while (i < text.length && !(text[i] === '*' && text[i + 1] === '/')) i++;
64
+ i += 2;
65
+ } else if (c === '"') {
66
+ return i;
67
+ } else {
68
+ i++;
69
+ }
70
+ }
71
+ return -1;
72
+ }
73
+
74
+ const [tplPath, destPath] = process.argv.slice(2);
75
+
76
+ try {
77
+ const tpl = fs.readFileSync(tplPath, 'utf8');
78
+ const dest = fs.readFileSync(destPath, 'utf8');
79
+ const t = scan(tpl);
80
+ const d = scan(dest);
81
+ if (t.open < 0 || t.close < 0) throw new Error(tplPath + ': oggetto JSON non trovato');
82
+ if (d.open < 0 || d.close < 0) throw new Error(destPath + ': oggetto JSON non trovato');
83
+
84
+ // voci di primo livello del template (spezzate sulle virgole a profondità 1)
85
+ const body = tpl.slice(t.open + 1, t.close);
86
+ const offset = t.open + 1;
87
+ const bounds = t.commas.map((p) => p - offset).concat(body.length);
88
+ const entries = [];
89
+ let prev = 0;
90
+ for (const b of bounds) {
91
+ entries.push(body.slice(prev, b));
92
+ prev = b + 1;
93
+ }
94
+
95
+ // prefissa con '_' la chiave di ogni voce (voci di soli commenti/spazi escluse)
96
+ const renamed = [];
97
+ for (const entry of entries) {
98
+ const cleaned = entry.replace(/^\s+/, '').replace(/\s+$/, '');
99
+ const q = firstQuotePos(cleaned);
100
+ if (q < 0) continue;
101
+ renamed.push('\n ' + cleaned.slice(0, q + 1) + '_' + cleaned.slice(q + 1));
102
+ }
103
+ if (renamed.length === 0) process.exit(0);
104
+
105
+ // aggiunge le voci prima della chiusura dell'oggetto principale della
106
+ // destinazione, inserendo una virgola dopo l'ultima voce esistente se serve
107
+ const dBody = dest.slice(d.open + 1, d.close);
108
+ const b = scan(dBody);
109
+ const needsComma = b.last >= 0 && dBody[b.last] !== ',';
110
+ const insertAt = d.open + 1 + b.last + 1;
111
+ const out = needsComma
112
+ ? dest.slice(0, insertAt) + ',' + dest.slice(insertAt, d.close) + renamed.join(',') + '\n' + dest.slice(d.close)
113
+ : dest.slice(0, d.close) + renamed.join(',') + '\n' + dest.slice(d.close);
114
+
115
+ fs.writeFileSync(destPath, out);
116
+ } catch (err) {
117
+ console.error('merge-jsonc: ' + err.message);
118
+ process.exit(1);
119
+ }
@@ -1,8 +1,13 @@
1
1
  #!/bin/zsh
2
2
 
3
+ RED='\033[0;31m'
4
+ YELLOW='\033[0;33m'
5
+ GREEN='\033[0;32m'
6
+ NC='\033[0m' # No Color
7
+
3
8
  # Questo script richiede zsh: se lanciato con sh/bash blocca l'esecuzione
4
9
  if [ -z "$ZSH_VERSION" ]; then
5
- echo "Errore: lanciare con 'zsh starter-install.sh', non con sh/bash." >&2
10
+ printf "${RED}Errore: lanciare con 'zsh starter-install.sh', non con sh/bash.${NC}\n" >&2
6
11
  exit 1
7
12
  fi
8
13
 
@@ -22,11 +27,6 @@ TEMPLATES_DIR="${BASE_URL}/templates"
22
27
  # WEBPACK_SOURCE_DIR="$BASE_URL/webpack-setup"
23
28
  WEBPACK_SOURCE_DIR="$BASE_URL"
24
29
 
25
- RED='\033[0;31m'
26
- YELLOW='\033[0;33m'
27
- GREEN='\033[0;32m'
28
- NC='\033[0m' # No Color
29
-
30
30
  # protezione contro la sovrascrittura
31
31
  set -C
32
32
 
@@ -58,7 +58,25 @@ safe_cat() {
58
58
  }
59
59
 
60
60
  echo -e "${GREEN}...package.json${NC}"
61
- safe_cat "${TEMPLATES_DIR}/package-tpl.json" package.json new
61
+ if [ ! -f package.json ]; then
62
+ safe_cat "${TEMPLATES_DIR}/package-tpl.json" package.json
63
+ elif [ ! -f "${TEMPLATES_DIR}/package-tpl.json" ]; then
64
+ echo -e "${RED}Sorgente mancante: ${TEMPLATES_DIR}/package-tpl.json${NC}"
65
+ else
66
+ # package.json esistente: merge con il template, aggiungendo in fondo
67
+ # le chiavi del template prefissate con '_' (ordine originale preservato)
68
+ node -e '
69
+ const fs = require("fs");
70
+ const existing = JSON.parse(fs.readFileSync("package.json", "utf8"));
71
+ const tpl = JSON.parse(fs.readFileSync(process.argv[1], "utf8"));
72
+ for (const [key, value] of Object.entries(tpl)) {
73
+ existing["_" + key] = value;
74
+ }
75
+ fs.writeFileSync("package.json", JSON.stringify(existing, null, 2) + "\n");
76
+ ' "${TEMPLATES_DIR}/package-tpl.json"
77
+ echo -e "${YELLOW}package.json esistente: chiavi del template aggiunte in fondo con prefisso '_' (da integrare o rimuovere)${NC}"
78
+ BLOCKED_FILES+=("package.json → merge: chiavi template aggiunte con prefisso \`_\`")
79
+ fi
62
80
 
63
81
  echo -e "${GREEN}...gitignore${NC}"
64
82
  safe_cat "${TEMPLATES_DIR}/_gitignore" .gitignore new
@@ -88,7 +106,26 @@ safe_cat "${TEMPLATES_DIR}/_browserslistrc" .browserslistrc new
88
106
  safe_cat "${TEMPLATES_DIR}/_editorconfig" .editorconfig new
89
107
  safe_cat "${TEMPLATES_DIR}/_prettierrc" .prettierrc new
90
108
  safe_cat "${TEMPLATES_DIR}/jsconfig.json" jsconfig.json new
91
- safe_cat "${TEMPLATES_DIR}/__project__.code-workspace" __project__.code-workspace new
109
+
110
+ # code-workspace: se un file .code-workspace esiste già (qualunque sia il nome),
111
+ # le chiavi del template vengono aggiunte in fondo con prefisso '_'
112
+ WORKSPACE_TPL="${TEMPLATES_DIR}/__project__.code-workspace"
113
+ WORKSPACE_FILES=( *.code-workspace(N) )
114
+ if [ ${#WORKSPACE_FILES[@]} -gt 1 ]; then
115
+ echo -e "${RED}Trovati più file .code-workspace (${WORKSPACE_FILES[*]}): merge non eseguito${NC}"
116
+ elif [ ${#WORKSPACE_FILES[@]} -eq 0 ]; then
117
+ safe_cat "$WORKSPACE_TPL" __project__.code-workspace
118
+ elif [ ! -f "$WORKSPACE_TPL" ]; then
119
+ echo -e "${RED}Sorgente mancante: ${WORKSPACE_TPL}${NC}"
120
+ else
121
+ WORKSPACE_FILE="${WORKSPACE_FILES[1]}"
122
+ if node "${BASE_URL}/merge-jsonc.cjs" "$WORKSPACE_TPL" "$WORKSPACE_FILE"; then
123
+ echo -e "${YELLOW}${WORKSPACE_FILE} esistente: chiavi del template aggiunte in fondo con prefisso '_' (da integrare o rimuovere)${NC}"
124
+ BLOCKED_FILES+=("${WORKSPACE_FILE} → merge: chiavi template aggiunte con prefisso \`_\`")
125
+ else
126
+ echo -e "${RED}Merge di ${WORKSPACE_FILE} non riuscito${NC}"
127
+ fi
128
+ fi
92
129
 
93
130
 
94
131
  echo -e "\n${GREEN}...eslint${NC}"
@@ -32,6 +32,6 @@
32
32
  "build tokens": "npx buildTokens --config ./path/to/tokens-config.mjs",
33
33
  "check unresolved props": "npx checkUnresolvedProps --config ./path/to/tokens-config.mjs"
34
34
  },
35
- "dependencies": {},
36
- "devDependencies": {}
35
+ "devDependencies": {},
36
+ "dependencies": {}
37
37
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@massimo-cassandro/minimo",
3
- "version": "1.15.1",
3
+ "version": "1.16.0",
4
4
  "description": "Light css framework & utilities",
5
5
  "type": "module",
6
6
  "main": "./index.js",