@mimi-ng/cli 0.4.0 → 0.5.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.
Files changed (35) hide show
  1. package/README.md +29 -7
  2. package/dist/init/index.js +8 -0
  3. package/dist/registry.js +4 -1
  4. package/dist/registry.json +87 -1
  5. package/dist/templates/blocks/login-01/login-01.ts +12 -3
  6. package/dist/templates/blocks/login-02/login-02.ts +12 -3
  7. package/dist/templates/blocks/otp-01/otp-01.ts +12 -3
  8. package/dist/templates/blocks/pricing-01/pricing-01.ts +1 -1
  9. package/dist/templates/blocks/settings-01/settings-01.ts +13 -3
  10. package/dist/templates/blocks/signup-01/signup-01.ts +12 -2
  11. package/dist/templates/blocks/table-01/index.ts +1 -0
  12. package/dist/templates/blocks/table-01/table-01.html +214 -0
  13. package/dist/templates/blocks/table-01/table-01.ts +266 -0
  14. package/dist/templates/components/checkbox/checkbox.ts +14 -5
  15. package/dist/templates/components/command/command-texts.ts +65 -0
  16. package/dist/templates/components/command/command.ts +553 -0
  17. package/dist/templates/components/command/index.ts +13 -0
  18. package/dist/templates/components/data-table/data-table-texts.ts +110 -0
  19. package/dist/templates/components/data-table/data-table.ts +1153 -0
  20. package/dist/templates/components/data-table/index.ts +18 -0
  21. package/dist/templates/components/sortable-list/index.ts +9 -0
  22. package/dist/templates/components/sortable-list/sortable-list-texts.ts +71 -0
  23. package/dist/templates/components/sortable-list/sortable-list.ts +510 -0
  24. package/dist/templates/components/tree/index.ts +9 -0
  25. package/dist/templates/components/tree/tree-texts.ts +45 -0
  26. package/dist/templates/components/tree/tree.ts +730 -0
  27. package/dist/templates/theme/provider.ts +4 -0
  28. package/dist/templates/theme/types.ts +84 -0
  29. package/dist/ui/index.js +232 -40
  30. package/dist/ui/schema.json +30 -6
  31. package/dist/utils/pages.js +138 -0
  32. package/dist/utils/project.js +33 -9
  33. package/dist/utils/tailwind.js +15 -11
  34. package/dist/utils/write-files.js +32 -7
  35. package/package.json +1 -1
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ /**
3
+ * Blocks de tipo página (B.11): `ng g mimi login-01` no copia el Block tal cual (`Login01`,
4
+ * `mimi-login-01`), sino que genera una página del usuario en `aliases.pages`
5
+ * (`src/app/pages/login/login.ts`, clase `LoginPage`) con su archivo de rutas.
6
+ *
7
+ * Solo funciones de texto, sin schematics: lo usa también el sitio para mostrar el código como
8
+ * lo genera la CLI.
9
+ *
10
+ * **Seguimiento por el nombre del registro (B.11-f):** los archivos de una página se identifican
11
+ * con claves `pages/<ítem>/…` (`pages/login-01/login-01.ts`), que son también las de sus bases
12
+ * (`.mimi/base/pages/login-01/`) y las del manifiesto. La carpeta y el nombre que eligió el
13
+ * usuario solo deciden dónde se escriben y cómo se llaman.
14
+ */
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.isBlockLikeName = exports.pageItemOf = exports.pageKeys = exports.pageKeyOf = exports.routesKey = exports.pageSourceFiles = exports.routesConstName = exports.pageClassName = exports.defaultPageName = exports.PAGE_NAME = exports.isPageFile = exports.PAGES_PREFIX = void 0;
17
+ exports.pageSelector = pageSelector;
18
+ exports.pageTargetPath = pageTargetPath;
19
+ exports.renderPageFile = renderPageFile;
20
+ exports.routesFile = routesFile;
21
+ exports.routeLine = routeLine;
22
+ /** Prefijo de las claves de los archivos de una página. */
23
+ exports.PAGES_PREFIX = 'pages/';
24
+ /** ¿Es la clave de un archivo de una página? */
25
+ const isPageFile = (file) => file.startsWith(exports.PAGES_PREFIX);
26
+ exports.isPageFile = isPageFile;
27
+ /** Nombre válido para `--name`: kebab-case, empieza con una letra (`login`, `admin-login`). */
28
+ exports.PAGE_NAME = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
29
+ /** Nombre por defecto: el del registro sin el número (`login-01` → `login`). */
30
+ const defaultPageName = (item) => item.replace(/-\d+$/, '');
31
+ exports.defaultPageName = defaultPageName;
32
+ const pascal = (kebab) => kebab
33
+ .split('-')
34
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
35
+ .join('');
36
+ const endsWithPage = (name) => name === 'page' || name.endsWith('-page');
37
+ /** `login` → `LoginPage`; `login-page` → `LoginPage` (sin repetir «Page»). */
38
+ const pageClassName = (name) => endsWithPage(name) ? pascal(name) : `${pascal(name)}Page`;
39
+ exports.pageClassName = pageClassName;
40
+ /** `app` y `login` → `app-login-page`; sin prefijo, `login-page`. */
41
+ function pageSelector(prefix, name) {
42
+ const base = endsWithPage(name) ? name : `${name}-page`;
43
+ return prefix ? `${prefix}-${base}` : base;
44
+ }
45
+ /** `login` → `LOGIN_ROUTES`; `admin-login` → `ADMIN_LOGIN_ROUTES`. */
46
+ const routesConstName = (name) => `${name.replace(/-/g, '_').toUpperCase()}_ROUTES`;
47
+ exports.routesConstName = routesConstName;
48
+ const basename = (file) => file.slice(file.lastIndexOf('/') + 1);
49
+ /** Los archivos del Block que pasan a la página: todos menos su `index.ts`. */
50
+ const pageSourceFiles = (files) => files.filter((file) => basename(file) !== 'index.ts');
51
+ exports.pageSourceFiles = pageSourceFiles;
52
+ /** Clave del archivo de rutas (`pages/login-01/login-01.routes.ts`). */
53
+ const routesKey = (item) => `${exports.PAGES_PREFIX}${item}/${item}.routes.ts`;
54
+ exports.routesKey = routesKey;
55
+ /** Clave de un archivo del Block en la página: `blocks/login-01/login-01.html` → `pages/login-01/login-01.html`. */
56
+ const pageKeyOf = (item, file) => `${exports.PAGES_PREFIX}${item}/${basename(file)}`;
57
+ exports.pageKeyOf = pageKeyOf;
58
+ /** Las claves de los archivos de una página: los del Block (sin `index.ts`) y el de rutas. */
59
+ const pageKeys = (item, files) => [
60
+ ...(0, exports.pageSourceFiles)(files).map((file) => (0, exports.pageKeyOf)(item, file)),
61
+ (0, exports.routesKey)(item),
62
+ ];
63
+ exports.pageKeys = pageKeys;
64
+ /** El ítem de una clave de página (`pages/login-01/login-01.ts` → `login-01`). */
65
+ const pageItemOf = (key) => key.slice(exports.PAGES_PREFIX.length).split('/')[0];
66
+ exports.pageItemOf = pageItemOf;
67
+ /**
68
+ * Ruta en el workspace de un archivo de la página: `pages/login-01/login-01.ts` con
69
+ * `{ dir: 'src/app/pages/login', name: 'login' }` → `src/app/pages/login/login.ts`.
70
+ */
71
+ function pageTargetPath(key, target) {
72
+ const file = basename(key);
73
+ const rest = file.startsWith(target.item) ? file.slice(target.item.length) : `.${file}`;
74
+ return `${target.dir}/${target.name}${rest}`;
75
+ }
76
+ const escape = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
77
+ /** `settings-01` → `SETTINGS_01`; `Login-Page` → `LOGIN_PAGE`. */
78
+ const constantCase = (kebab) => kebab.replace(/-/g, '_').toUpperCase();
79
+ /**
80
+ * ¿El nombre de página contiene el del Block (`login-01`, `login-01-x`)? La conversión no
81
+ * distinguiría lo viejo de lo nuevo: `ng g mimi` lo rechaza con su propio mensaje.
82
+ */
83
+ const isBlockLikeName = (item, name) => name === item || name.startsWith(`${item}-`);
84
+ exports.isBlockLikeName = isBlockLikeName;
85
+ /**
86
+ * El código de un archivo del Block convertido en el de la página: el selector `mimi-login-01`
87
+ * (también en los `id`) pasa a `app-login-page`; la clase `Login01` y sus tipos (`Login01Value`)
88
+ * a `LoginPage` (`LoginPageValue`); las constantes (`SETTINGS_01_PLAN`) a `SETTINGS_PAGE_PLAN`;
89
+ * los archivos propios (`./login-01.html`) a `./login.html`. Lanza un error si queda algo del
90
+ * nombre del Block (un Block nuevo con otra forma necesita que se revise esta función; lo prueba
91
+ * `pages.spec.ts` con los Blocks reales). El nombre de la página no puede contener el del Block
92
+ * (`--name login-01`): lo rechaza antes `isBlockLikeName`.
93
+ */
94
+ function renderPageFile(source, target) {
95
+ const { item, name } = target;
96
+ const fromClass = pascal(item);
97
+ const fromConstant = constantCase(item);
98
+ const result = source
99
+ .split(`mimi-${item}`)
100
+ .join(pageSelector(target.prefix, name))
101
+ .replace(new RegExp(`(['"\`])\\./${escape(item)}\\.`, 'g'), `$1./${name}.`)
102
+ .replace(new RegExp(`\\b${escape(fromClass)}`, 'g'), (0, exports.pageClassName)(name))
103
+ .replace(new RegExp(`\\b${escape(fromConstant)}(?=_|\\b)`, 'g'), constantCase((0, exports.pageClassName)(name).replace(/([a-z0-9])([A-Z])/g, '$1-$2')));
104
+ const left = [`mimi-${item}`, `./${item}.`].filter((text) => result.includes(text));
105
+ if (new RegExp(`\\b${escape(fromClass)}`).test(result))
106
+ left.push(fromClass);
107
+ if (new RegExp(`\\b${escape(fromConstant)}(?=_|\\b)`).test(result))
108
+ left.push(fromConstant);
109
+ if (left.length > 0) {
110
+ throw new Error(`No se pudo convertir ${item} en una página: quedan ${left.join(', ')}. Es un error de Mimi; ` +
111
+ 'avísanos en https://github.com/nuki23/mimi-ng/issues.');
112
+ }
113
+ return result;
114
+ }
115
+ /** `login.routes.ts`: la página en carga diferida, lista para `loadChildren`. */
116
+ function routesFile(target) {
117
+ const className = (0, exports.pageClassName)(target.name);
118
+ return [
119
+ "import type { Routes } from '@angular/router';",
120
+ '',
121
+ '/**',
122
+ ` * Rutas de la página ${target.name} (${target.item} de Mimi). La página se carga al entrar en`,
123
+ ' * ella. En app.routes.ts, con loadChildren (ng g mimi te dio la línea exacta).',
124
+ ' */',
125
+ `export const ${(0, exports.routesConstName)(target.name)}: Routes = [`,
126
+ ` { path: '', loadComponent: () => import('./${target.name}').then((m) => m.${className}) },`,
127
+ '];',
128
+ '',
129
+ ].join('\n');
130
+ }
131
+ /**
132
+ * La línea para `app.routes.ts` (que está en `appDir`): `{ path: 'login', loadChildren: () =>
133
+ * import('./pages/login/login.routes').then((m) => m.LOGIN_ROUTES) },`.
134
+ */
135
+ function routeLine(target, routesImport) {
136
+ return (`{ path: '${target.name}', loadChildren: () => import('${routesImport}')` +
137
+ `.then((m) => m.${(0, exports.routesConstName)(target.name)}) },`);
138
+ }
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.MIMI_COLLECTION = void 0;
4
4
  exports.defaultBlocksDir = defaultBlocksDir;
5
+ exports.defaultPagesDir = defaultPagesDir;
5
6
  exports.assertAliases = assertAliases;
6
7
  exports.readJson = readJson;
7
8
  exports.allDependencies = allDependencies;
@@ -16,6 +17,16 @@ exports.MIMI_COLLECTION = '@mimi-ng/cli';
16
17
  * de la carpeta de componentes (`src/app/ui` → `src/app/blocks`).
17
18
  */
18
19
  function defaultBlocksDir(componentsDir) {
20
+ return siblingOfComponents(componentsDir, 'blocks');
21
+ }
22
+ /**
23
+ * Carpeta de las páginas si mimi.json no la dice (B.11-b), con la misma regla que la de los
24
+ * Blocks: `src/app/components/ui` → `src/app/pages`.
25
+ */
26
+ function defaultPagesDir(componentsDir) {
27
+ return siblingOfComponents(componentsDir, 'pages');
28
+ }
29
+ function siblingOfComponents(componentsDir, folder) {
19
30
  const parts = componentsDir.split('/').filter(Boolean);
20
31
  if (parts.length >= 2 && parts.at(-1) === 'ui' && parts.at(-2) === 'components') {
21
32
  parts.splice(-2, 2);
@@ -23,25 +34,38 @@ function defaultBlocksDir(componentsDir) {
23
34
  else {
24
35
  parts.pop();
25
36
  }
26
- return [...parts, 'blocks'].join('/');
37
+ return [...parts, folder].join('/');
27
38
  }
39
+ const ALIAS_EXAMPLES = {
40
+ components: 'src/app/components/ui',
41
+ blocks: 'src/app/blocks',
42
+ pages: 'src/app/pages',
43
+ };
28
44
  /**
29
- * M2: falla con un error claro (sin escribir nada) si `aliases.components` o `aliases.blocks` de
30
- * mimi.json es absoluto, tiene `..` o sale del proyecto.
45
+ * M2: falla con un error claro (sin escribir nada) si `aliases.components`, `aliases.blocks` o
46
+ * `aliases.pages` de mimi.json, o la carpeta de una página (`blocks.<ítem>.path`, B.11), es
47
+ * absoluto, tiene `..` o sale del proyecto.
31
48
  */
32
49
  function assertAliases(config) {
33
- for (const name of ['components', 'blocks']) {
50
+ for (const name of ['components', 'blocks', 'pages']) {
34
51
  const value = config.aliases?.[name];
35
52
  if (value === undefined)
36
53
  continue;
37
- const reason = (0, paths_1.invalidAliasReason)(value);
38
- if (!reason)
54
+ assertRelative(`aliases.${name}`, value, ALIAS_EXAMPLES[name]);
55
+ }
56
+ for (const [item, entry] of Object.entries(config.blocks ?? {})) {
57
+ if (entry?.path === undefined)
39
58
  continue;
40
- const example = name === 'blocks' ? 'src/app/blocks' : 'src/app/components/ui';
41
- throw new schematics_1.SchematicsException(`mimi.json → aliases.${name} ${reason}: ${JSON.stringify(value)}. Usa una ruta relativa a ` +
42
- `la raíz del workspace y dentro de ella (por ejemplo "${example}"). No se cambió nada.`);
59
+ assertRelative(`blocks.${item}.path`, entry.path, `${ALIAS_EXAMPLES.pages}/login`);
43
60
  }
44
61
  }
62
+ function assertRelative(key, value, example) {
63
+ const reason = (0, paths_1.invalidAliasReason)(value);
64
+ if (!reason)
65
+ return;
66
+ throw new schematics_1.SchematicsException(`mimi.json → ${key} ${reason}: ${JSON.stringify(value)}. Usa una ruta relativa a ` +
67
+ `la raíz del workspace y dentro de ella (por ejemplo "${example}"). No se cambió nada.`);
68
+ }
45
69
  function readJson(tree, path) {
46
70
  if (!tree.exists(path))
47
71
  return null;
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.tailwindSupportsSourceNot = tailwindSupportsSourceNot;
4
- exports.withBlocksSource = withBlocksSource;
4
+ exports.withFolderSource = withFolderSource;
5
5
  exports.mimiSourceNotLine = mimiSourceNotLine;
6
6
  exports.mimiSourceNotPath = mimiSourceNotPath;
7
7
  exports.missingMimiExclusion = missingMimiExclusion;
@@ -37,24 +37,28 @@ function atLeast41(version) {
37
37
  }
38
38
  /**
39
39
  * Con `source(none)`, Tailwind solo escanea lo que dice un `@source`: la carpeta de los Blocks
40
- * necesita el suyo (G1), como la de componentes. Devuelve el CSS con la línea agregada (después
41
- * del `@source` de componentes, o del tema), o `null` si no hace falta: sin `source(none)`, o si
42
- * ya está (comillas simples o dobles).
40
+ * (G1) y la de las páginas (B.11) necesitan el suyo, como la de componentes. Devuelve el CSS con
41
+ * la línea agregada (después del último `@source` de `afterDirs` que esté, o del tema), o `null`
42
+ * si no hace falta: sin `source(none)`, o si ya está (comillas simples o dobles).
43
43
  */
44
- function withBlocksSource(css, cssPath, componentsDir, blocksDir) {
44
+ function withFolderSource(css, cssPath, afterDirs, dir) {
45
45
  const tailwind = (0, css_1.findTailwindImport)(css);
46
46
  if (!tailwind?.sourceNone)
47
47
  return null;
48
48
  const cssDir = (0, paths_1.dirnameOf)(cssPath);
49
- const path = (0, paths_1.relativePath)(cssDir, blocksDir);
49
+ const path = (0, paths_1.relativePath)(cssDir, dir);
50
50
  if ((0, css_1.hasDirective)(css, '@source', path))
51
51
  return null;
52
52
  const line = `@source "${path}";`;
53
- const after = new RegExp(String.raw `^[ \t]*@source\s+(["'])` +
54
- (0, paths_1.relativePath)(cssDir, componentsDir).replace(/[.*+?^${}()|[\]\\]/g, '\\$&') +
55
- String.raw `\1[^;\n]*;[^\n]*$`, 'm').exec(css);
56
- if (after) {
57
- const end = after.index + after[0].length;
53
+ let end = -1;
54
+ for (const after of afterDirs) {
55
+ const match = new RegExp(String.raw `^[ \t]*@source\s+(["'])` +
56
+ (0, paths_1.relativePath)(cssDir, after).replace(/[.*+?^${}()|[\]\\]/g, '\\$&') +
57
+ String.raw `\1[^;\n]*;[^\n]*$`, 'm').exec(css);
58
+ if (match)
59
+ end = Math.max(end, match.index + match[0].length);
60
+ }
61
+ if (end >= 0) {
58
62
  const eol = /\r\n/.test(css) ? '\r\n' : '\n';
59
63
  return { css: css.slice(0, end) + eol + line + css.slice(end), line };
60
64
  }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isBlockFile = exports.hasFileChanges = exports.emptyReport = exports.MANIFEST = exports.BASE_DIR = void 0;
3
+ exports.isBlockFile = exports.hasFileChanges = exports.emptyReport = exports.MANIFEST = exports.BASE_DIR = exports.itemFiles = void 0;
4
4
  exports.projectPathOf = projectPathOf;
5
5
  exports.targetPathOf = targetPathOf;
6
6
  exports.basePathOf = basePathOf;
@@ -10,7 +10,14 @@ exports.compareVersions = compareVersions;
10
10
  exports.updatedMessages = updatedMessages;
11
11
  const schematics_1 = require("@angular-devkit/schematics");
12
12
  const registry_1 = require("../registry");
13
+ const pages_1 = require("./pages");
13
14
  const project_1 = require("./project");
15
+ /**
16
+ * Los archivos de un ítem: los del registro o, si se genera como página, sus claves
17
+ * `pages/<ítem>/…` (B.11-f).
18
+ */
19
+ const itemFiles = (item, pages = {}) => pages[item] ? (0, pages_1.pageKeys)(item, registry_1.registry.items[item].files) : registry_1.registry.items[item].files;
20
+ exports.itemFiles = itemFiles;
14
21
  /** Carpeta de las copias originales, en la raíz del workspace. Debe quedar en git. */
15
22
  exports.BASE_DIR = '.mimi/base';
16
23
  /** Versión de Mimi con la que se escribió la base de cada archivo. */
@@ -46,7 +53,13 @@ exports.isBlockFile = isBlockFile;
46
53
  * `blocks/` (`blocks/login-01/login-01.ts` → `<blocksDir>/login-01/login-01.ts`); el resto, a la
47
54
  * de componentes (ver projectPathOf).
48
55
  */
49
- function targetPathOf(file, componentsDir, blocksDir) {
56
+ function targetPathOf(file, componentsDir, blocksDir, pages = {}) {
57
+ if ((0, pages_1.isPageFile)(file)) {
58
+ const target = pages[(0, pages_1.pageItemOf)(file)];
59
+ if (!target)
60
+ throw new Error(`Falta la carpeta de la página de ${file}.`);
61
+ return (0, pages_1.pageTargetPath)(file, target);
62
+ }
50
63
  return (0, exports.isBlockFile)(file)
51
64
  ? `${blocksDir}/${file.slice(BLOCKS_PREFIX.length)}`
52
65
  : `${componentsDir}/${projectPathOf(file)}`;
@@ -54,7 +67,8 @@ function targetPathOf(file, componentsDir, blocksDir) {
54
67
  /**
55
68
  * Copia original en .mimi/base, con la misma estructura (`.mimi/base/button/button.ts`). Los
56
69
  * Blocks conservan `blocks/` (`.mimi/base/blocks/login-01/login-01.ts`), y esa es también su
57
- * clave en el manifiesto.
70
+ * clave en el manifiesto. Las páginas van por su nombre del registro, no por el de su carpeta
71
+ * (`.mimi/base/pages/login-01/login-01.ts`, B.11-f).
58
72
  */
59
73
  function basePathOf(file) {
60
74
  return `${exports.BASE_DIR}/${projectPathOf(file)}`;
@@ -95,6 +109,8 @@ function readManifest(tree) {
95
109
  function writeTemplates(options) {
96
110
  const items = [...new Set(options.items)];
97
111
  const implicit = new Set(options.implicit ?? []);
112
+ const pages = options.pages ?? {};
113
+ const filesOf = (item) => (0, exports.itemFiles)(item, pages);
98
114
  const files = new Set(items.flatMap((item) => registry_1.registry.items[item].files));
99
115
  const contents = new Map();
100
116
  // 1. Lee las plantillas (sin escribir nada: forEach devuelve null).
@@ -107,9 +123,18 @@ function writeTemplates(options) {
107
123
  ]));
108
124
  // 2. Decide por ítem y escribe.
109
125
  const write = (tree) => {
126
+ // Las páginas: su código sale del Block, con el nombre que eligió el usuario (B.11).
127
+ for (const [item, target] of Object.entries(pages)) {
128
+ for (const file of (0, pages_1.pageSourceFiles)(registry_1.registry.items[item].files)) {
129
+ const source = contents.get(file);
130
+ if (source !== undefined)
131
+ contents.set((0, pages_1.pageKeyOf)(item, file), (0, pages_1.renderPageFile)(source, target));
132
+ }
133
+ contents.set((0, pages_1.routesKey)(item), (0, pages_1.routesFile)(target));
134
+ }
110
135
  const manifest = readManifest(tree);
111
136
  let manifestChanged = false;
112
- const targetOf = (file) => targetPathOf(file, options.componentsDir, options.blocksDir ?? (0, project_1.defaultBlocksDir)(options.componentsDir));
137
+ const targetOf = (file) => targetPathOf(file, options.componentsDir, options.blocksDir ?? (0, project_1.defaultBlocksDir)(options.componentsDir), pages);
113
138
  const stateOf = (file) => {
114
139
  const target = targetOf(file);
115
140
  if (!tree.exists(target))
@@ -130,7 +155,7 @@ function writeTemplates(options) {
130
155
  };
131
156
  const states = new Map(items.map((item) => [
132
157
  item,
133
- registry_1.registry.items[item].files
158
+ filesOf(item)
134
159
  .filter((file) => contents.has(file))
135
160
  .map((file) => ({ file, ...stateOf(file) })),
136
161
  ]));
@@ -240,8 +265,8 @@ function writeTemplates(options) {
240
265
  * Los avisos de los ítems que no se escribieron (`report.blocked`): qué no se actualizó, por qué
241
266
  * y qué hacer. Nunca dicen «actualizado».
242
267
  */
243
- function blockedMessages(report, componentsDir, version, blocksDir = (0, project_1.defaultBlocksDir)(componentsDir)) {
244
- const path = (file) => targetPathOf(file, componentsDir, blocksDir);
268
+ function blockedMessages(report, componentsDir, version, blocksDir = (0, project_1.defaultBlocksDir)(componentsDir), pages = {}) {
269
+ const path = (file) => targetPathOf(file, componentsDir, blocksDir, pages);
245
270
  return report.blocked.map(({ item, files, dependency, installed }) => {
246
271
  if (dependency) {
247
272
  const needs = `necesita ${dependency} ${version}, que no se actualizó (ver el aviso de ${dependency}).`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mimi-ng/cli",
3
- "version": "0.4.0",
3
+ "version": "0.5.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",