@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.
package/dev-tools/README.md
CHANGED
|
@@ -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
|
-
*
|
|
9
|
+
* [webpack-setup](#webpack-setup) — script for installing minimo environment
|
|
10
10
|
|
|
11
|
-
##
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
"
|
|
36
|
-
"
|
|
35
|
+
"devDependencies": {},
|
|
36
|
+
"dependencies": {}
|
|
37
37
|
}
|