@arcadialdev/arcality 4.0.0 → 4.0.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arcadialdev/arcality",
3
- "version": "4.0.0",
3
+ "version": "4.0.1",
4
4
  "description": "El primer ingeniero QA Autónomo integrado al CI/CD. Creado por Arcadial.",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -78,6 +78,19 @@ function matchesPageFilters(routeEntry, filters) {
78
78
  return haystacks.some(value => value === normalized || value.includes(normalized));
79
79
  });
80
80
  }
81
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
82
+
83
+ function isLikelyUuidFilter(filter) {
84
+ return UUID_RE.test(String(filter || '').trim());
85
+ }
86
+
87
+ function formatRouteExamples(routes, maxItems = 3) {
88
+ return routes
89
+ .slice(0, maxItems)
90
+ .map(entry => `${entry.route} -> ${entry.pagePath}`)
91
+ .join('\n- ');
92
+ }
93
+
81
94
 
82
95
  function limitEntries(entries, count) {
83
96
  if (!Number.isFinite(count) || count <= 0) return entries;
@@ -114,6 +127,14 @@ function printSummary(analysis, selectedRoutes, options, generationContext) {
114
127
 
115
128
  if (selectedRoutes.length === 0) {
116
129
  console.log('\nNo candidate routes matched the provided filters.');
130
+ const uuidFilters = (options.page || []).filter(isLikelyUuidFilter);
131
+ if (uuidFilters.length > 0) {
132
+ console.log('Tip: the current --page filter only matches route fragments or page file paths, not backend page IDs or UUIDs.');
133
+ }
134
+ if ((options.page || []).length > 0 && analysis.routes.length > 0) {
135
+ console.log('Try values such as a route (`/checkout`) or a page path fragment (`app/checkout/page.tsx`).');
136
+ console.log(`Examples:\n- ${formatRouteExamples(analysis.routes)}`);
137
+ }
117
138
  return;
118
139
  }
119
140
 
@@ -221,23 +221,38 @@ function analyzeSourceSignals(sourceFile, route) {
221
221
  const fileLower = toPosix(sourceFile).toLowerCase();
222
222
  const semanticFileLower = fileLower.replace(/\([^/\\]+\)/g, '');
223
223
  const has = (...patterns) => patterns.some(pattern => lower.includes(pattern));
224
+ const count = (...patterns) => patterns.reduce((total, pattern) => total + (lower.match(new RegExp(pattern, 'g')) || []).length, 0);
224
225
  const routeHas = (...patterns) => patterns.some(pattern => routeLower.includes(pattern) || semanticFileLower.includes(pattern));
225
226
  const isRouterConfigFile = has('createbrowserrouter', 'useroutes', '<routes', '<route');
226
227
  const contextualHas = (...patterns) => {
227
228
  if (routeHas(...patterns)) return true;
228
229
  return !isRouterConfigFile && has(...patterns);
229
230
  };
231
+ const formControlCount = count(
232
+ '<input',
233
+ '<select',
234
+ '<textarea',
235
+ 'textfield',
236
+ 'inputbase',
237
+ 'autocomplete',
238
+ 'radiogroup',
239
+ 'checkbox'
240
+ );
241
+ const hasStepFlow = contextualHas('siguiente', 'continuar', 'anterior', 'atras', 'paso', 'stepper', 'wizard');
242
+ const hasValidationCopy = contextualHas('campo obligatorio', 'requerido', 'obligatorio', 'valida', 'validacion', 'validation');
230
243
 
231
244
  const signals = {
232
- hasForm: has('<form', 'useform', 'formik', 'react-hook-form', 'zodresolver', 'onsubmit', 'handleSubmit'.toLowerCase()),
245
+ hasForm: has('<form', 'useform', 'formik', 'react-hook-form', 'zodresolver', 'onsubmit', 'handlesubmit')
246
+ || formControlCount >= 2
247
+ || (formControlCount >= 1 && (hasStepFlow || hasValidationCopy)),
233
248
  hasTable: has('<table', 'datatable', 'ag-grid', 'tanstack table', 'role="table"', 'role="grid"'),
234
249
  hasSearch: contextualHas('search', 'buscar', 'query', 'placeholder="buscar', 'placeholder=\'buscar'),
235
250
  hasFilter: contextualHas('filter', 'filtro', 'filtrar'),
236
251
  hasCreateAction: contextualHas('crear', 'create', 'nuevo', 'new ', 'agregar', 'add '),
237
252
  hasEditAction: contextualHas('editar', 'edit', 'actualizar', 'update'),
238
- hasAuth: has('password', 'contraseña', 'iniciar sesión', 'login', 'sign in') || routeHas('login', 'signin', 'auth'),
253
+ hasAuth: has('password', 'contrase\u00f1a', 'iniciar sesi\u00f3n', 'login', 'sign in') || routeHas('login', 'signin', 'auth'),
239
254
  hasCheckout: contextualHas('payment', 'card', 'checkout', 'billing', 'stripe'),
240
- hasSettings: has('settings', 'configuración', 'preferencias', 'preferences') || routeHas('settings', 'config', 'preferences'),
255
+ hasSettings: has('settings', 'configuraci\u00f3n', 'preferencias', 'preferences') || routeHas('settings', 'config', 'preferences'),
241
256
  hasUpload: contextualHas('type="file"', "type='file'", 'dropzone', 'upload', 'subir archivo', 'subir imagen'),
242
257
  isDynamicRoute: /\[[^\]]+\]/.test(route) || /:\w+/.test(route),
243
258
  routeSegments: routeLower.replace(/^\/+/, '').split('/').filter(Boolean),