@mimi-ng/cli 0.1.0 → 0.2.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 +19 -1
- package/dist/collection.json +1 -1
- package/dist/init/css.js +17 -0
- package/dist/init/index.js +7 -5
- package/dist/init/items.js +9 -0
- package/dist/ng-add/index.js +17 -1
- package/dist/ng-add/schema.json +27 -0
- package/dist/registry.json +222 -1
- package/dist/templates/components/avatar/avatar.ts +1 -1
- package/dist/templates/components/avatar/avatar.variants.ts +4 -4
- package/dist/templates/components/badge/badge.ts +41 -6
- package/dist/templates/components/badge/badge.variants.ts +105 -11
- package/dist/templates/components/button/button.ts +74 -7
- package/dist/templates/components/button/button.variants.ts +145 -21
- package/dist/templates/components/card/card.ts +8 -5
- package/dist/templates/components/checkbox/checkbox.ts +3 -3
- package/dist/templates/components/confirm/confirm-texts.ts +46 -0
- package/dist/templates/components/confirm/confirm.ts +190 -0
- package/dist/templates/components/confirm/index.ts +2 -0
- package/dist/templates/components/context-menu/context-menu.ts +378 -0
- package/dist/templates/components/context-menu/index.ts +14 -0
- package/dist/templates/components/dialog/dialog-texts.ts +41 -0
- package/dist/templates/components/dialog/dialog.ts +701 -0
- package/dist/templates/components/dialog/index.ts +18 -0
- package/dist/templates/components/dropdown-menu/dropdown-menu.ts +252 -0
- package/dist/templates/components/dropdown-menu/index.ts +14 -0
- package/dist/templates/components/form-field/form-error.ts +1 -1
- package/dist/templates/components/form-field/form-field.ts +3 -2
- package/dist/templates/components/input/input.variants.ts +6 -4
- package/dist/templates/components/menu/index.ts +15 -0
- package/dist/templates/components/menu/menu.ts +656 -0
- package/dist/templates/components/pagination/index.ts +2 -0
- package/dist/templates/components/pagination/pagination-page-size.ts +74 -0
- package/dist/templates/components/pagination/pagination-texts.ts +69 -0
- package/dist/templates/components/pagination/pagination.ts +443 -0
- package/dist/templates/components/popover/index.ts +12 -0
- package/dist/templates/components/popover/popover.ts +399 -0
- package/dist/templates/components/select/index.ts +12 -0
- package/dist/templates/components/select/select-texts.ts +62 -0
- package/dist/templates/components/select/select.ts +1085 -0
- package/dist/templates/components/separator/separator.variants.ts +10 -7
- package/dist/templates/components/skeleton/skeleton.ts +4 -1
- package/dist/templates/components/switch/switch.ts +6 -6
- package/dist/templates/components/tabs/index.ts +2 -0
- package/dist/templates/components/tabs/tabs.ts +426 -0
- package/dist/templates/components/textarea/textarea.variants.ts +14 -11
- package/dist/templates/components/toast/index.ts +3 -0
- package/dist/templates/components/toast/toast-config.ts +45 -0
- package/dist/templates/components/toast/toast-texts.ts +46 -0
- package/dist/templates/components/toast/toast.ts +1000 -0
- package/dist/templates/components/toolbar/index.ts +1 -0
- package/dist/templates/components/toolbar/toolbar.ts +377 -0
- package/dist/templates/components/tooltip/index.ts +7 -0
- package/dist/templates/components/tooltip/tooltip.ts +407 -0
- package/dist/templates/theme/provider.ts +62 -6
- package/dist/templates/theme/theme-base.css +307 -9
- package/dist/templates/theme/types.ts +278 -4
- package/dist/templates/utils/cn.ts +15 -1
- package/dist/templates/utils/control-styles.ts +2 -2
- package/dist/templates/utils/overlay.ts +140 -0
- package/dist/ui/index.js +80 -8
- package/dist/ui/schema.json +44 -0
- package/dist/utils/write-files.js +156 -59
- package/package.json +6 -5
package/dist/ui/index.js
CHANGED
|
@@ -4,6 +4,8 @@ exports.AVAILABLE = void 0;
|
|
|
4
4
|
exports.ui = ui;
|
|
5
5
|
const schematics_1 = require("@angular-devkit/schematics");
|
|
6
6
|
const utility_1 = require("@schematics/angular/utility");
|
|
7
|
+
const css_1 = require("../init/css");
|
|
8
|
+
const items_1 = require("../init/items");
|
|
7
9
|
const paths_1 = require("../init/paths");
|
|
8
10
|
const registry_1 = require("../registry");
|
|
9
11
|
const project_1 = require("../utils/project");
|
|
@@ -17,8 +19,10 @@ exports.AVAILABLE = Object.entries(registry_1.registry.items)
|
|
|
17
19
|
* `ng g mimi button input form-field`: copia los componentes y sus dependencias del registro a la
|
|
18
20
|
* carpeta de mimi.json. Sin nombres, pregunta (x-prompt de selección múltiple).
|
|
19
21
|
*
|
|
20
|
-
* Requiere init (mimi.json).
|
|
21
|
-
*
|
|
22
|
+
* Requiere init (mimi.json). Revisa también el tema y lo que copia init, y lo actualiza si el
|
|
23
|
+
* usuario no lo modificó. Todo o nada por componente (ver writeTemplates): si el usuario modificó
|
|
24
|
+
* un archivo de una versión anterior, ese componente y los que dependen de él no se tocan, con
|
|
25
|
+
* un aviso; --overwrite reemplaza. Guarda la copia original en .mimi/base/ y la versión de cada
|
|
22
26
|
* componente en mimi.json. Instala las dependencias que falten con el gestor del proyecto.
|
|
23
27
|
*/
|
|
24
28
|
function ui(options) {
|
|
@@ -27,13 +31,15 @@ function ui(options) {
|
|
|
27
31
|
const report = (0, write_files_1.emptyReport)();
|
|
28
32
|
return (0, schematics_1.chain)([
|
|
29
33
|
(0, write_files_1.writeTemplates)({
|
|
30
|
-
|
|
34
|
+
items: [...plan.items, ...plan.implicit],
|
|
35
|
+
implicit: plan.implicit,
|
|
31
36
|
componentsDir: plan.componentsDir,
|
|
32
37
|
overwrite: options.overwrite ?? false,
|
|
33
38
|
version: registry_1.registry.version,
|
|
34
39
|
report,
|
|
35
40
|
}),
|
|
36
41
|
updateMimiConfig(plan, report),
|
|
42
|
+
updateGlobalCss(plan),
|
|
37
43
|
...Object.entries(plan.newPackages).map(([name, version]) => (0, utility_1.addDependency)(name, version, {
|
|
38
44
|
type: utility_1.DependencyType.Default,
|
|
39
45
|
existing: utility_1.ExistingBehavior.Skip,
|
|
@@ -82,11 +88,37 @@ function inspect(tree, options) {
|
|
|
82
88
|
for (const [name, version] of Object.entries(registry_1.registry.items[item].peerDependencies ?? {})) {
|
|
83
89
|
if (installed[name])
|
|
84
90
|
continue;
|
|
85
|
-
newPackages[name] =
|
|
91
|
+
newPackages[name] =
|
|
92
|
+
name === '@angular/aria'
|
|
93
|
+
? ariaVersion(tree, installed, version)
|
|
94
|
+
: name.startsWith('@angular/') && angularRange
|
|
95
|
+
? angularRange
|
|
96
|
+
: version;
|
|
86
97
|
}
|
|
87
98
|
}
|
|
99
|
+
// aria necesita el cdk (bidi, a11y, platform). Un ítem que solo importa aria (Tabs) no declara
|
|
100
|
+
// el cdk como peer; sin otro ítem que lo traiga, va con la misma versión que aria.
|
|
101
|
+
if (newPackages['@angular/aria'] && !installed['@angular/cdk'] && !newPackages['@angular/cdk']) {
|
|
102
|
+
newPackages['@angular/cdk'] = newPackages['@angular/aria'];
|
|
103
|
+
}
|
|
104
|
+
const implicit = [...new Set(items_1.INIT_ITEMS.flatMap((item) => (0, registry_1.resolveItems)(item)))].filter((item) => !items.includes(item));
|
|
88
105
|
const componentsDir = (0, paths_1.normalizePath)(config.aliases?.components ?? 'src/app/components/ui');
|
|
89
|
-
return { componentsDir, config, items, newPackages };
|
|
106
|
+
return { componentsDir, config, items, implicit, newPackages };
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* @angular/aria pide como peer la versión exacta de @angular/cdk (22.1.7 → cdk 22.1.7). Si el cdk
|
|
110
|
+
* está instalado, aria va en esa versión (de `node_modules`, que el árbol del schematic lee del
|
|
111
|
+
* disco); si está declarado pero sin instalar, con su mismo rango; si no hay cdk, con el rango de
|
|
112
|
+
* `@angular/core`, igual que el cdk que se agrega junto con él (lo declare otro ítem o no).
|
|
113
|
+
*/
|
|
114
|
+
function ariaVersion(tree, installed, fallback) {
|
|
115
|
+
const cdk = tree.read('node_modules/@angular/cdk/package.json');
|
|
116
|
+
if (cdk) {
|
|
117
|
+
const { version } = JSON.parse(cdk.toString('utf-8'));
|
|
118
|
+
if (version)
|
|
119
|
+
return version;
|
|
120
|
+
}
|
|
121
|
+
return installed['@angular/cdk'] ?? installed['@angular/core'] ?? fallback;
|
|
90
122
|
}
|
|
91
123
|
/** El componente más parecido (distancia de edición ≤ 2, o que empiece igual). */
|
|
92
124
|
function closest(name) {
|
|
@@ -115,15 +147,19 @@ function editDistance(a, b) {
|
|
|
115
147
|
// ── mimi.json ─────────────────────────────────────────────────────────────────────────
|
|
116
148
|
/**
|
|
117
149
|
* Registra la versión de cada componente cuyos archivos quedaron iguales a la plantilla. Si
|
|
118
|
-
* alguno se omitió por estar modificado, se
|
|
150
|
+
* alguno se omitió por estar modificado, o el componente no se escribió (bloqueado), se conserva
|
|
151
|
+
* lo que había (y uno que no se agregó no aparece).
|
|
119
152
|
*/
|
|
120
153
|
function updateMimiConfig(plan, report) {
|
|
121
154
|
return (tree) => {
|
|
122
155
|
const skipped = new Set(report.skipped);
|
|
156
|
+
const blocked = new Set(report.blocked.map((b) => b.item));
|
|
123
157
|
const components = { ...plan.config.components };
|
|
124
158
|
for (const item of plan.items) {
|
|
125
159
|
if (registry_1.registry.items[item].type !== 'component')
|
|
126
160
|
continue;
|
|
161
|
+
if (blocked.has(item))
|
|
162
|
+
continue;
|
|
127
163
|
if (registry_1.registry.items[item].files.some((file) => skipped.has(file)))
|
|
128
164
|
continue;
|
|
129
165
|
components[item] = { version: registry_1.registry.version };
|
|
@@ -134,6 +170,38 @@ function updateMimiConfig(plan, report) {
|
|
|
134
170
|
tree.overwrite('mimi.json', text);
|
|
135
171
|
};
|
|
136
172
|
}
|
|
173
|
+
// ── CSS global ────────────────────────────────────────────────────────────────────────
|
|
174
|
+
/**
|
|
175
|
+
* Agrega los `cssImports` de los ítems (p. ej. `@angular/cdk/overlay-prebuilt.css`, que pide la
|
|
176
|
+
* guía del CDK) al CSS global de mimi.json, una sola vez. Van después del `@import` del tema (o
|
|
177
|
+
* del de Tailwind): los `@import` tienen que ir antes que cualquier otra regla, y así quedan
|
|
178
|
+
* junto a los de Mimi. Si no se encuentra el archivo, se explica cómo agregarlos a mano.
|
|
179
|
+
*/
|
|
180
|
+
function updateGlobalCss(plan) {
|
|
181
|
+
return (tree, context) => {
|
|
182
|
+
const imports = [
|
|
183
|
+
...new Set(plan.items.flatMap((item) => registry_1.registry.items[item].cssImports ?? [])),
|
|
184
|
+
];
|
|
185
|
+
if (imports.length === 0)
|
|
186
|
+
return;
|
|
187
|
+
const cssPath = plan.config.tailwind?.css;
|
|
188
|
+
const css = cssPath && tree.exists(cssPath) ? tree.readText(cssPath) : null;
|
|
189
|
+
const missing = imports.filter((path) => !css || !(0, css_1.hasDirective)(css, '@import', path));
|
|
190
|
+
if (missing.length === 0)
|
|
191
|
+
return;
|
|
192
|
+
const lines = missing.map((path) => `@import "${path}";`);
|
|
193
|
+
const updated = css === null ? null : (0, css_1.insertAfterTheme)(css, lines);
|
|
194
|
+
if (!cssPath || updated === null) {
|
|
195
|
+
context.logger.warn(`No se encontró el CSS global${cssPath ? ` (${cssPath})` : ''} con el @import de ` +
|
|
196
|
+
`Tailwind. Agrega a mano, después del tema de Mimi:\n${lines.map((l) => ` ${l}`).join('\n')}`);
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
tree.overwrite(cssPath, updated);
|
|
200
|
+
context.logger.info(`Agregado a ${cssPath}:`);
|
|
201
|
+
for (const line of lines)
|
|
202
|
+
context.logger.info(` ${line}`);
|
|
203
|
+
};
|
|
204
|
+
}
|
|
137
205
|
// ── Mensaje final ─────────────────────────────────────────────────────────────────────
|
|
138
206
|
function summary(plan, report) {
|
|
139
207
|
return (_tree, context) => {
|
|
@@ -149,13 +217,17 @@ function summary(plan, report) {
|
|
|
149
217
|
for (const file of report.overwritten)
|
|
150
218
|
log.info(` ~ ${path(file)}`);
|
|
151
219
|
}
|
|
152
|
-
const itemOf = (file) => plan.items.find((item) => registry_1.registry.items[item].files.includes(file)) ??
|
|
220
|
+
const itemOf = (file) => [...plan.items, ...plan.implicit].find((item) => registry_1.registry.items[item].files.includes(file)) ??
|
|
221
|
+
file;
|
|
153
222
|
for (const message of (0, write_files_1.updatedMessages)(report, itemOf, registry_1.registry.version))
|
|
154
223
|
log.info(message);
|
|
155
224
|
for (const file of report.skipped) {
|
|
156
225
|
log.warn(`Omitido: ${path(file)} ya existe con otro contenido (usa --overwrite para reemplazarlo).`);
|
|
157
226
|
}
|
|
158
|
-
|
|
227
|
+
for (const message of (0, write_files_1.blockedMessages)(report, plan.componentsDir, registry_1.registry.version)) {
|
|
228
|
+
log.warn(message);
|
|
229
|
+
}
|
|
230
|
+
if (!(0, write_files_1.hasFileChanges)(report) && report.skipped.length === 0 && report.blocked.length === 0) {
|
|
159
231
|
log.info('Nada que hacer: los archivos ya están al día.');
|
|
160
232
|
}
|
|
161
233
|
const packages = Object.entries(plan.newPackages);
|
package/dist/ui/schema.json
CHANGED
|
@@ -39,6 +39,22 @@
|
|
|
39
39
|
"value": "checkbox",
|
|
40
40
|
"label": "checkbox"
|
|
41
41
|
},
|
|
42
|
+
{
|
|
43
|
+
"value": "confirm",
|
|
44
|
+
"label": "confirm"
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
"value": "context-menu",
|
|
48
|
+
"label": "context-menu"
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
"value": "dialog",
|
|
52
|
+
"label": "dialog"
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
"value": "dropdown-menu",
|
|
56
|
+
"label": "dropdown-menu"
|
|
57
|
+
},
|
|
42
58
|
{
|
|
43
59
|
"value": "form-field",
|
|
44
60
|
"label": "form-field"
|
|
@@ -47,6 +63,18 @@
|
|
|
47
63
|
"value": "input",
|
|
48
64
|
"label": "input"
|
|
49
65
|
},
|
|
66
|
+
{
|
|
67
|
+
"value": "pagination",
|
|
68
|
+
"label": "pagination"
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"value": "popover",
|
|
72
|
+
"label": "popover"
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
"value": "select",
|
|
76
|
+
"label": "select"
|
|
77
|
+
},
|
|
50
78
|
{
|
|
51
79
|
"value": "separator",
|
|
52
80
|
"label": "separator"
|
|
@@ -59,9 +87,25 @@
|
|
|
59
87
|
"value": "switch",
|
|
60
88
|
"label": "switch"
|
|
61
89
|
},
|
|
90
|
+
{
|
|
91
|
+
"value": "tabs",
|
|
92
|
+
"label": "tabs"
|
|
93
|
+
},
|
|
62
94
|
{
|
|
63
95
|
"value": "textarea",
|
|
64
96
|
"label": "textarea"
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
"value": "toast",
|
|
100
|
+
"label": "toast"
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
"value": "toolbar",
|
|
104
|
+
"label": "toolbar"
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
"value": "tooltip",
|
|
108
|
+
"label": "tooltip"
|
|
65
109
|
}
|
|
66
110
|
]
|
|
67
111
|
}
|
|
@@ -4,9 +4,11 @@ exports.hasFileChanges = exports.emptyReport = exports.MANIFEST = exports.BASE_D
|
|
|
4
4
|
exports.projectPathOf = projectPathOf;
|
|
5
5
|
exports.basePathOf = basePathOf;
|
|
6
6
|
exports.writeTemplates = writeTemplates;
|
|
7
|
+
exports.blockedMessages = blockedMessages;
|
|
7
8
|
exports.compareVersions = compareVersions;
|
|
8
9
|
exports.updatedMessages = updatedMessages;
|
|
9
10
|
const schematics_1 = require("@angular-devkit/schematics");
|
|
11
|
+
const registry_1 = require("../registry");
|
|
10
12
|
/** Carpeta de las copias originales, en la raíz del workspace. Debe quedar en git. */
|
|
11
13
|
exports.BASE_DIR = '.mimi/base';
|
|
12
14
|
/** Versión de Mimi con la que se escribió la base de cada archivo. */
|
|
@@ -17,6 +19,7 @@ const emptyReport = () => ({
|
|
|
17
19
|
updated: [],
|
|
18
20
|
unchanged: [],
|
|
19
21
|
skipped: [],
|
|
22
|
+
blocked: [],
|
|
20
23
|
});
|
|
21
24
|
exports.emptyReport = emptyReport;
|
|
22
25
|
/** ¿El reporte tiene cambios en archivos del proyecto? */
|
|
@@ -47,26 +50,97 @@ function readManifest(tree) {
|
|
|
47
50
|
}
|
|
48
51
|
}
|
|
49
52
|
/**
|
|
50
|
-
* Copia archivos de
|
|
51
|
-
*
|
|
53
|
+
* Copia los archivos de los ítems del registro desde las plantillas del paquete
|
|
54
|
+
* (`dist/templates`) a `componentsDir`. **Todo o nada por ítem:** primero revisa cada archivo
|
|
55
|
+
* (ver `FileState`) y después decide por ítem:
|
|
52
56
|
*
|
|
53
|
-
* -
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* `overwrite`).
|
|
57
|
+
* - si el usuario modificó alguno de sus archivos de una versión anterior, no se escribe
|
|
58
|
+
* ninguno (ni los nuevos ni los que no tocó): mezclar versiones rompe la compilación;
|
|
59
|
+
* - lo mismo si depende (por `registryDependencies`, en cualquier nivel) de un ítem que quedó
|
|
60
|
+
* así, esté instalado o no;
|
|
61
|
+
* - si no, se crean los que faltan y se actualizan los que el usuario no tocó. Los modificados
|
|
62
|
+
* sobre esta versión se conservan (`skipped`).
|
|
60
63
|
*
|
|
61
|
-
*
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
+
* Con `overwrite`, todo se reemplaza y nada se bloquea. Los ítems `implicit` (el tema y lo que
|
|
65
|
+
* copia init, que `ng g mimi` revisa aunque no se pidan) solo se escriben si hay que
|
|
66
|
+
* actualizarlos: un cambio del usuario sobre la versión actual se respeta en silencio, también
|
|
67
|
+
* con `overwrite`, y no bloquean a otros ítems.
|
|
68
|
+
*
|
|
69
|
+
* Nunca deja que mergeWith encuentre un archivo existente ("merge conflicted"). Guarda la base y
|
|
70
|
+
* su versión en `.mimi/manifest.json` siempre que el archivo quede igual a la plantilla; los de un
|
|
71
|
+
* ítem bloqueado o conservado no cambian su base.
|
|
64
72
|
*/
|
|
65
73
|
function writeTemplates(options) {
|
|
66
|
-
const
|
|
67
|
-
|
|
74
|
+
const items = [...new Set(options.items)];
|
|
75
|
+
const implicit = new Set(options.implicit ?? []);
|
|
76
|
+
const files = new Set(items.flatMap((item) => registry_1.registry.items[item].files));
|
|
77
|
+
const contents = new Map();
|
|
78
|
+
// 1. Lee las plantillas (sin escribir nada: forEach devuelve null).
|
|
79
|
+
const read = (0, schematics_1.mergeWith)((0, schematics_1.apply)((0, schematics_1.url)('../templates'), [
|
|
80
|
+
(0, schematics_1.filter)((path) => files.has(path.replace(/^\//, ''))),
|
|
81
|
+
(0, schematics_1.forEach)((entry) => {
|
|
82
|
+
contents.set(entry.path.replace(/^\//, ''), entry.content.toString('utf8'));
|
|
83
|
+
return null;
|
|
84
|
+
}),
|
|
85
|
+
]));
|
|
86
|
+
// 2. Decide por ítem y escribe.
|
|
87
|
+
const write = (tree) => {
|
|
68
88
|
const manifest = readManifest(tree);
|
|
69
89
|
let manifestChanged = false;
|
|
90
|
+
const targetOf = (file) => `${options.componentsDir}/${projectPathOf(file)}`;
|
|
91
|
+
const stateOf = (file) => {
|
|
92
|
+
const target = targetOf(file);
|
|
93
|
+
if (!tree.exists(target))
|
|
94
|
+
return { state: 'new', from: null };
|
|
95
|
+
const current = tree.readText(target);
|
|
96
|
+
if (current === contents.get(file))
|
|
97
|
+
return { state: 'same', from: null };
|
|
98
|
+
const from = manifest.files[projectPathOf(file)] ?? null;
|
|
99
|
+
const base = basePathOf(file);
|
|
100
|
+
if (tree.exists(base)) {
|
|
101
|
+
if (tree.readText(base) === current) {
|
|
102
|
+
return { state: from === options.version ? 'formatted' : 'old', from };
|
|
103
|
+
}
|
|
104
|
+
if (from !== null && from !== options.version)
|
|
105
|
+
return { state: 'modifiedOld', from };
|
|
106
|
+
}
|
|
107
|
+
return { state: 'modified', from };
|
|
108
|
+
};
|
|
109
|
+
const states = new Map(items.map((item) => [
|
|
110
|
+
item,
|
|
111
|
+
registry_1.registry.items[item].files
|
|
112
|
+
.filter((file) => contents.has(file))
|
|
113
|
+
.map((file) => ({ file, ...stateOf(file) })),
|
|
114
|
+
]));
|
|
115
|
+
// Bloqueados por un cambio propio y, después, por una dependencia bloqueada.
|
|
116
|
+
const blocked = new Map();
|
|
117
|
+
if (!options.overwrite) {
|
|
118
|
+
for (const item of items) {
|
|
119
|
+
const modified = states.get(item).filter((s) => s.state === 'modifiedOld');
|
|
120
|
+
if (modified.length > 0) {
|
|
121
|
+
blocked.set(item, {
|
|
122
|
+
item,
|
|
123
|
+
files: modified.map((s) => s.file),
|
|
124
|
+
installed: true,
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
for (const item of items) {
|
|
129
|
+
if (blocked.has(item))
|
|
130
|
+
continue;
|
|
131
|
+
const dependency = (0, registry_1.resolveItems)(item)
|
|
132
|
+
.filter((dep) => dep !== item)
|
|
133
|
+
.find((dep) => blocked.has(dep) && blocked.get(dep).files.length > 0);
|
|
134
|
+
if (dependency) {
|
|
135
|
+
blocked.set(item, {
|
|
136
|
+
item,
|
|
137
|
+
files: [],
|
|
138
|
+
dependency,
|
|
139
|
+
installed: states.get(item).some((s) => s.state !== 'new'),
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
70
144
|
const writeBase = (file, content) => {
|
|
71
145
|
const base = basePathOf(file);
|
|
72
146
|
if (!tree.exists(base))
|
|
@@ -79,60 +153,83 @@ function writeTemplates(options) {
|
|
|
79
153
|
manifestChanged = true;
|
|
80
154
|
}
|
|
81
155
|
};
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const content =
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const from = manifest.files[projectPathOf(file)] ?? null;
|
|
102
|
-
if (from === options.version) {
|
|
103
|
-
// Mismo contenido que escribió Mimi, solo con otro formato.
|
|
156
|
+
for (const item of items) {
|
|
157
|
+
if (blocked.has(item)) {
|
|
158
|
+
options.report.blocked.push(blocked.get(item));
|
|
159
|
+
continue;
|
|
160
|
+
}
|
|
161
|
+
for (const { file, state, from } of states.get(item)) {
|
|
162
|
+
const content = contents.get(file);
|
|
163
|
+
const target = targetOf(file);
|
|
164
|
+
switch (state) {
|
|
165
|
+
case 'new':
|
|
166
|
+
tree.create(target, content);
|
|
167
|
+
options.report.created.push(file);
|
|
168
|
+
writeBase(file, content);
|
|
169
|
+
break;
|
|
170
|
+
case 'same':
|
|
171
|
+
options.report.unchanged.push(file);
|
|
172
|
+
writeBase(file, content);
|
|
173
|
+
break;
|
|
174
|
+
case 'formatted':
|
|
104
175
|
options.report.unchanged.push(file);
|
|
105
|
-
|
|
106
|
-
|
|
176
|
+
break;
|
|
177
|
+
case 'old':
|
|
107
178
|
tree.overwrite(target, content);
|
|
108
179
|
options.report.updated.push({ file, from });
|
|
109
180
|
writeBase(file, content);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
181
|
+
break;
|
|
182
|
+
case 'modifiedOld':
|
|
183
|
+
case 'modified':
|
|
184
|
+
// Un cambio sobre la versión actual de un ítem implícito se respeta siempre.
|
|
185
|
+
if (options.overwrite && !(implicit.has(item) && state === 'modified')) {
|
|
186
|
+
tree.overwrite(target, content);
|
|
187
|
+
options.report.overwritten.push(file);
|
|
188
|
+
writeBase(file, content);
|
|
189
|
+
}
|
|
190
|
+
else if (!implicit.has(item)) {
|
|
191
|
+
options.report.skipped.push(file);
|
|
192
|
+
}
|
|
193
|
+
break;
|
|
119
194
|
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
]));
|
|
124
|
-
const saveManifest = (t) => {
|
|
125
|
-
if (!manifestChanged)
|
|
126
|
-
return;
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
if (manifestChanged) {
|
|
127
198
|
const sorted = Object.fromEntries(Object.entries(manifest.files).sort());
|
|
128
199
|
const text = `${JSON.stringify({ files: sorted }, null, 2)}\n`;
|
|
129
|
-
if (
|
|
130
|
-
|
|
200
|
+
if (tree.exists(exports.MANIFEST))
|
|
201
|
+
tree.overwrite(exports.MANIFEST, text);
|
|
131
202
|
else
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
return (0, schematics_1.chain)([copy, saveManifest]);
|
|
203
|
+
tree.create(exports.MANIFEST, text);
|
|
204
|
+
}
|
|
135
205
|
};
|
|
206
|
+
return (0, schematics_1.chain)([read, write]);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Los avisos de los ítems que no se escribieron (`report.blocked`): qué no se actualizó, por qué
|
|
210
|
+
* y qué hacer. Nunca dicen «actualizado».
|
|
211
|
+
*/
|
|
212
|
+
function blockedMessages(report, componentsDir, version) {
|
|
213
|
+
const path = (file) => `${componentsDir}/${projectPathOf(file)}`;
|
|
214
|
+
return report.blocked.map(({ item, files, dependency, installed }) => {
|
|
215
|
+
if (dependency) {
|
|
216
|
+
const needs = `necesita ${dependency} ${version}, que no se actualizó (ver el aviso de ${dependency}).`;
|
|
217
|
+
return installed
|
|
218
|
+
? `${item} no se actualizó a ${version}: ${needs}`
|
|
219
|
+
: `${item} no se agregó: ${needs}`;
|
|
220
|
+
}
|
|
221
|
+
const isTheme = registry_1.registry.items[item]?.type === 'theme';
|
|
222
|
+
const label = isTheme ? 'El tema' : item;
|
|
223
|
+
const dir = projectPathOf(files[0]).split('/').slice(0, -1).join('/');
|
|
224
|
+
return (`${label} no se actualizó a ${version} porque modificaste ${files.map(path).join(', ')}. ` +
|
|
225
|
+
'No se cambió ninguno de sus archivos, para no mezclar versiones.' +
|
|
226
|
+
(isTheme
|
|
227
|
+
? ` Los componentes de la ${version} usan tokens nuevos del tema: sin ellos, algunos estilos no se generan.`
|
|
228
|
+
: '') +
|
|
229
|
+
' Para actualizarlo: guarda tus cambios (por ejemplo, en git), vuelve a ejecutar el ' +
|
|
230
|
+
'comando con --overwrite y aplícalos de nuevo. La versión de Mimi que modificaste está en ' +
|
|
231
|
+
`${exports.BASE_DIR}/${dir}/, para comparar.`);
|
|
232
|
+
});
|
|
136
233
|
}
|
|
137
234
|
/** Compara versiones `x.y.z` numéricamente (`0.10.0` > `0.9.0`). `null` es la más vieja. */
|
|
138
235
|
function compareVersions(a, b) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mimi-ng/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Angular + Tailwind CSS 4 UI components that a CLI copies into your project, so you own the code. Schematics for ng add and ng generate.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"angular",
|
|
@@ -44,12 +44,13 @@
|
|
|
44
44
|
"LICENSE",
|
|
45
45
|
"THIRD_PARTY_NOTICES.md"
|
|
46
46
|
],
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "node scripts/build.mjs",
|
|
49
|
+
"prepublishOnly": "node scripts/build.mjs"
|
|
50
|
+
},
|
|
47
51
|
"dependencies": {
|
|
48
52
|
"@angular-devkit/core": "^22.0.0",
|
|
49
53
|
"@angular-devkit/schematics": "^22.0.0",
|
|
50
54
|
"@schematics/angular": "^22.0.0"
|
|
51
|
-
},
|
|
52
|
-
"scripts": {
|
|
53
|
-
"build": "node scripts/build.mjs"
|
|
54
55
|
}
|
|
55
|
-
}
|
|
56
|
+
}
|