@saulwade/swl-ses 1.0.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/CLAUDE.md +238 -0
- package/README.md +560 -0
- package/_userland/agentes/.gitkeep +0 -0
- package/_userland/habilidades/.gitkeep +0 -0
- package/agentes/.evolved.json +9 -0
- package/agentes/accesibilidad-wcag-swl.md +692 -0
- package/agentes/arquitecto-swl.md +238 -0
- package/agentes/auto-evolucion-swl.md +854 -0
- package/agentes/backend-api-swl.md +470 -0
- package/agentes/backend-csharp-swl.md +418 -0
- package/agentes/backend-go-swl.md +388 -0
- package/agentes/backend-java-swl.md +279 -0
- package/agentes/backend-node-swl.md +477 -0
- package/agentes/backend-python-swl.md +608 -0
- package/agentes/backend-rust-swl.md +362 -0
- package/agentes/backend-workers-swl.md +480 -0
- package/agentes/cloud-infra-swl.md +485 -0
- package/agentes/consolidador-swl.md +539 -0
- package/agentes/datos-swl.md +584 -0
- package/agentes/depurador-swl.md +349 -0
- package/agentes/devops-ci-swl.md +374 -0
- package/agentes/disenador-ui-swl.md +558 -0
- package/agentes/documentador-swl.md +343 -0
- package/agentes/evals/arquitecto-swl.evals.json +56 -0
- package/agentes/evals/auto-evolucion-swl.evals.json +68 -0
- package/agentes/evals/implementador-swl.evals.json +56 -0
- package/agentes/evals/orquestador-swl.evals.json +60 -0
- package/agentes/evals/perfilador-usuario-swl.evals.json +60 -0
- package/agentes/evals/red-team-swl.evals.json +59 -0
- package/agentes/evals/revisor-codigo-swl.evals.json +59 -0
- package/agentes/frontend-angular-swl.md +627 -0
- package/agentes/frontend-css-swl.md +720 -0
- package/agentes/frontend-react-swl.md +696 -0
- package/agentes/frontend-swl.md +500 -0
- package/agentes/frontend-tailwind-swl.md +830 -0
- package/agentes/implementador-swl.md +328 -0
- package/agentes/investigador-swl.md +430 -0
- package/agentes/investigador-ux-swl.md +500 -0
- package/agentes/llm-apps-swl.md +276 -0
- package/agentes/migrador-swl.md +417 -0
- package/agentes/mobile-android-swl.md +509 -0
- package/agentes/mobile-cross-swl.md +539 -0
- package/agentes/mobile-ios-swl.md +500 -0
- package/agentes/mobile-testing-swl.md +300 -0
- package/agentes/notificador-swl.md +916 -0
- package/agentes/observabilidad-swl.md +436 -0
- package/agentes/orquestador-swl.md +884 -0
- package/agentes/pagos-swl.md +283 -0
- package/agentes/perfilador-usuario-swl.md +306 -0
- package/agentes/planificador-swl.md +402 -0
- package/agentes/producto-prd-swl.md +587 -0
- package/agentes/red-team-swl.md +216 -0
- package/agentes/release-manager-swl.md +568 -0
- package/agentes/rendimiento-swl.md +714 -0
- package/agentes/resolutor-build-swl.md +243 -0
- package/agentes/revisor-angular-swl.md +276 -0
- package/agentes/revisor-codigo-swl.md +348 -0
- package/agentes/revisor-csharp-swl.md +262 -0
- package/agentes/revisor-go-swl.md +257 -0
- package/agentes/revisor-java-swl.md +255 -0
- package/agentes/revisor-kotlin-swl.md +271 -0
- package/agentes/revisor-nextjs-swl.md +279 -0
- package/agentes/revisor-php-swl.md +269 -0
- package/agentes/revisor-react-swl.md +276 -0
- package/agentes/revisor-rust-swl.md +344 -0
- package/agentes/revisor-seguridad-swl.md +390 -0
- package/agentes/revisor-swift-swl.md +266 -0
- package/agentes/revisor-typescript-swl.md +344 -0
- package/agentes/sre-swl.md +265 -0
- package/agentes/tdd-qa-swl.md +354 -0
- package/agentes/ux-disenador-swl.md +501 -0
- package/bin/lib/bot-comandos.js +1030 -0
- package/bin/lib/bot-discovery.js +182 -0
- package/bin/lib/bot-git.js +142 -0
- package/bin/swl-ses.js +325 -0
- package/bin/swl-telegram-bot.js +442 -0
- package/bin/swl-telegram-bot.plist +21 -0
- package/bin/swl-telegram-bot.service +14 -0
- package/comandos/swl/.evolved.json +23 -0
- package/comandos/swl/actualizar.md +174 -0
- package/comandos/swl/adoptar-proyecto.md +207 -0
- package/comandos/swl/aprender.md +701 -0
- package/comandos/swl/auditar-deps.md +134 -0
- package/comandos/swl/autoresearch.md +170 -0
- package/comandos/swl/ayuda.md +224 -0
- package/comandos/swl/brainstorm.md +50 -0
- package/comandos/swl/checkpoint.md +330 -0
- package/comandos/swl/compactar.md +283 -0
- package/comandos/swl/configurar-ci.md +227 -0
- package/comandos/swl/contexto.md +112 -0
- package/comandos/swl/contribuir.md +233 -0
- package/comandos/swl/crear-skill.md +292 -0
- package/comandos/swl/cron.md +196 -0
- package/comandos/swl/dashboard.md +146 -0
- package/comandos/swl/discutir-fase.md +230 -0
- package/comandos/swl/ejecutar-fase.md +135 -0
- package/comandos/swl/evaluar-skill.md +487 -0
- package/comandos/swl/evolucion-estado.md +142 -0
- package/comandos/swl/evolucionar.md +259 -0
- package/comandos/swl/exportar-vault.md +189 -0
- package/comandos/swl/gateway.md +158 -0
- package/comandos/swl/inbox.md +116 -0
- package/comandos/swl/instalar.md +220 -0
- package/comandos/swl/instintos.md +86 -0
- package/comandos/swl/mapear-codebase.md +312 -0
- package/comandos/swl/mcp-status.md +175 -0
- package/comandos/swl/metricas.md +270 -0
- package/comandos/swl/modelo.md +102 -0
- package/comandos/swl/notificaciones.md +396 -0
- package/comandos/swl/nuevo-proyecto.md +154 -0
- package/comandos/swl/planear-fase.md +221 -0
- package/comandos/swl/plugins.md +256 -0
- package/comandos/swl/reflect-skills.md +125 -0
- package/comandos/swl/release.md +217 -0
- package/comandos/swl/revisar-impacto.md +206 -0
- package/comandos/swl/revisar.md +330 -0
- package/comandos/swl/salud.md +363 -0
- package/comandos/swl/sesiones.md +200 -0
- package/comandos/swl/skill-search.md +113 -0
- package/comandos/swl/verificar.md +585 -0
- package/comandos/swl/wiki.md +620 -0
- package/contextos/dev.md +32 -0
- package/contextos/research.md +30 -0
- package/contextos/review.md +31 -0
- package/habilidades/accesibilidad-a11y/SKILL.md +201 -0
- package/habilidades/accesibilidad-a11y/evals/evals.json +56 -0
- package/habilidades/accesibilidad-a11y/recursos/ejemplos-y-checklist-completo.md +441 -0
- package/habilidades/agent-browser/SKILL.md +218 -0
- package/habilidades/agentes-como-servicio/SKILL.md +218 -0
- package/habilidades/ai-runtime-security/SKILL.md +273 -0
- package/habilidades/angular-avanzado/SKILL.md +164 -0
- package/habilidades/angular-avanzado/recursos/ejemplos-avanzados.md +219 -0
- package/habilidades/angular-moderno/SKILL.md +186 -0
- package/habilidades/angular-moderno/evals/evals.json +45 -0
- package/habilidades/angular-moderno/recursos/ejemplos-avanzados.md +106 -0
- package/habilidades/api-rest-diseno/SKILL.md +191 -0
- package/habilidades/api-rest-diseno/recursos/openapi-template.yaml +506 -0
- package/habilidades/api-rest-diseno/recursos/referencia-api.md +140 -0
- package/habilidades/aprendizaje-continuo/SKILL.md +151 -0
- package/habilidades/aprendizaje-continuo/evals/evals.json +53 -0
- package/habilidades/aprendizaje-continuo/recursos/referencia-instintos.md +290 -0
- package/habilidades/async-python/SKILL.md +149 -0
- package/habilidades/async-python/evals/evals.json +47 -0
- package/habilidades/async-python/recursos/patrones-y-ejemplos-completos.md +292 -0
- package/habilidades/auth-patrones/.evolved.json +9 -0
- package/habilidades/auth-patrones/SKILL.md +413 -0
- package/habilidades/auth-patrones/recursos/implementaciones-completas.md +229 -0
- package/habilidades/auto-evolucion-protocolo/SKILL.md +276 -0
- package/habilidades/auto-evolucion-protocolo/evals/evals.json +55 -0
- package/habilidades/auto-evolucion-protocolo/recursos/referencia-completa.md +145 -0
- package/habilidades/autoresearch/SKILL.md +268 -0
- package/habilidades/autoresearch/evals/evals.json +41 -0
- package/habilidades/autoresearch/recursos/checklist-template.md +191 -0
- package/habilidades/autoresearch/scripts/calcular-score.js +88 -0
- package/habilidades/azure-cloud/SKILL.md +308 -0
- package/habilidades/azure-cloud/recursos/aks.md +327 -0
- package/habilidades/backend-mcp-servidor/SKILL.md +270 -0
- package/habilidades/backend-production-resilience/SKILL.md +288 -0
- package/habilidades/brainstorming/SKILL.md +295 -0
- package/habilidades/brainstorming/recursos/componentes-html.md +247 -0
- package/habilidades/build-errors-cpp/SKILL.md +270 -0
- package/habilidades/build-errors-csharp/SKILL.md +265 -0
- package/habilidades/build-errors-go/SKILL.md +306 -0
- package/habilidades/build-errors-java/SKILL.md +278 -0
- package/habilidades/build-errors-kotlin/SKILL.md +303 -0
- package/habilidades/build-errors-nextjs/SKILL.md +312 -0
- package/habilidades/build-errors-php/SKILL.md +270 -0
- package/habilidades/build-errors-python/SKILL.md +292 -0
- package/habilidades/build-errors-rust/SKILL.md +284 -0
- package/habilidades/build-errors-swift/SKILL.md +272 -0
- package/habilidades/build-errors-typescript/SKILL.md +369 -0
- package/habilidades/checklist-calidad/SKILL.md +271 -0
- package/habilidades/checklist-calidad/recursos/quality-report-template.md +148 -0
- package/habilidades/checklist-seguridad/SKILL.md +285 -0
- package/habilidades/checkpoints-verificacion/SKILL.md +298 -0
- package/habilidades/checkpoints-verificacion/recursos/checkpoint-templates.md +360 -0
- package/habilidades/ci-cd-pipelines/SKILL.md +157 -0
- package/habilidades/ci-cd-pipelines/recursos/github-actions-template.yaml +403 -0
- package/habilidades/ci-cd-pipelines/recursos/pipelines-completos.md +487 -0
- package/habilidades/cloud-aws/SKILL.md +142 -0
- package/habilidades/cloud-aws/recursos/servicios-aws-referencia.md +321 -0
- package/habilidades/compactacion-contexto/SKILL.md +247 -0
- package/habilidades/contenedores-docker/SKILL.md +137 -0
- package/habilidades/contenedores-docker/recursos/dockerfile-template.dockerfile +160 -0
- package/habilidades/contenedores-docker/recursos/ejemplos-y-configuraciones.md +327 -0
- package/habilidades/context-builder/SKILL.md +170 -0
- package/habilidades/control-profundidad/SKILL.md +128 -0
- package/habilidades/csharp-experto/SKILL.md +322 -0
- package/habilidades/csharp-patrones/SKILL.md +316 -0
- package/habilidades/csharp-testing/SKILL.md +286 -0
- package/habilidades/css-moderno/SKILL.md +166 -0
- package/habilidades/css-moderno/evals/evals.json +43 -0
- package/habilidades/css-moderno/recursos/ejemplos-y-patrones-completos.md +337 -0
- package/habilidades/datos-etl/SKILL.md +129 -0
- package/habilidades/datos-etl/recursos/implementaciones-completas.md +322 -0
- package/habilidades/dbml-experto/SKILL.md +339 -0
- package/habilidades/dbml-experto/evals/evals.json +56 -0
- package/habilidades/dependencias-auditoria/SKILL.md +320 -0
- package/habilidades/deprecacion-migracion/SKILL.md +169 -0
- package/habilidades/deprecacion-migracion/recursos/implementaciones-completas.md +220 -0
- package/habilidades/design-tokens/SKILL.md +158 -0
- package/habilidades/design-tokens/recursos/tokens-y-configuracion.md +363 -0
- package/habilidades/devsecops-pipeline-security/SKILL.md +309 -0
- package/habilidades/diagrama-arquitectura/SKILL.md +165 -0
- package/habilidades/diagrama-arquitectura/assets/template.html +276 -0
- package/habilidades/discutir-fase/SKILL.md +188 -0
- package/habilidades/diseno-herramientas-agente/SKILL.md +199 -0
- package/habilidades/diseno-responsivo/SKILL.md +186 -0
- package/habilidades/diseno-responsivo/recursos/ejemplos-layouts.md +156 -0
- package/habilidades/django-experto/SKILL.md +205 -0
- package/habilidades/django-experto/recursos/async-django.md +390 -0
- package/habilidades/django-experto/recursos/drf-patrones.md +438 -0
- package/habilidades/django-experto/recursos/orm-avanzado.md +382 -0
- package/habilidades/django-experto/recursos/referencia-completa.md +188 -0
- package/habilidades/django-experto/recursos/testing-django.md +415 -0
- package/habilidades/doc-sync/SKILL.md +280 -0
- package/habilidades/drift-detection/SKILL.md +179 -0
- package/habilidades/ejecutar-fase/SKILL.md +468 -0
- package/habilidades/estilo-sin-ai-isms/SKILL.md +775 -0
- package/habilidades/estilo-sin-ai-isms/evals/evals.json +63 -0
- package/habilidades/estilo-sin-ai-isms/scripts/detectar_aiisms.py +500 -0
- package/habilidades/estructura-proyecto-claude/SKILL.md +215 -0
- package/habilidades/estructura-proyecto-claude/recursos/claude-md-template.md +261 -0
- package/habilidades/estructura-proyecto-claude/recursos/configuracion-y-extensiones.md +176 -0
- package/habilidades/estructura-proyecto-claude/recursos/frontmatter-y-hooks-referencia.md +289 -0
- package/habilidades/estructura-proyecto-claude/recursos/mcp-json-template.json +77 -0
- package/habilidades/estructura-proyecto-claude/recursos/variantes-por-stack.md +177 -0
- package/habilidades/evaluacion-agentes/SKILL.md +314 -0
- package/habilidades/event-driven/SKILL.md +153 -0
- package/habilidades/event-driven/recursos/implementaciones-completas.md +423 -0
- package/habilidades/extraccion-documentos/SKILL.md +221 -0
- package/habilidades/extractor-de-aprendizajes/.evolved.json +9 -0
- package/habilidades/extractor-de-aprendizajes/SKILL.md +311 -0
- package/habilidades/extractor-de-aprendizajes/evals/evals.json +55 -0
- package/habilidades/fastapi-experto/SKILL.md +221 -0
- package/habilidades/fastapi-experto/recursos/async-patterns.md +438 -0
- package/habilidades/fastapi-experto/recursos/dependency-injection.md +330 -0
- package/habilidades/fastapi-experto/recursos/referencia-completa.md +79 -0
- package/habilidades/fastapi-experto/recursos/testing-httpx.md +420 -0
- package/habilidades/filament-admin/SKILL.md +290 -0
- package/habilidades/frontend-avanzado/SKILL.md +257 -0
- package/habilidades/frontend-avanzado/recursos/apis-nativas-ejemplos.md +341 -0
- package/habilidades/gcp-cloud/SKILL.md +260 -0
- package/habilidades/gcp-cloud/recursos/gke.md +234 -0
- package/habilidades/gcp-cloud/recursos/terraform-gcp.md +307 -0
- package/habilidades/generacion-mermaid/SKILL.md +229 -0
- package/habilidades/git-worktrees-paralelo/SKILL.md +270 -0
- package/habilidades/go-experto/SKILL.md +305 -0
- package/habilidades/go-patrones/SKILL.md +299 -0
- package/habilidades/go-testing/SKILL.md +291 -0
- package/habilidades/graphql-experto/SKILL.md +323 -0
- package/habilidades/guardrail-semantico/SKILL.md +282 -0
- package/habilidades/harness-claude-code/SKILL.md +299 -0
- package/habilidades/iam-secretos/SKILL.md +265 -0
- package/habilidades/iam-secretos/recursos/implementaciones-completas.md +356 -0
- package/habilidades/infra-github-actions/SKILL.md +166 -0
- package/habilidades/instalar-sistema/.evolved.json +9 -0
- package/habilidades/instalar-sistema/SKILL.md +221 -0
- package/habilidades/java-experto/SKILL.md +290 -0
- package/habilidades/java-patrones/SKILL.md +275 -0
- package/habilidades/java-testing/SKILL.md +288 -0
- package/habilidades/kotlin-compose/SKILL.md +278 -0
- package/habilidades/kotlin-compose/recursos/animaciones-performance.md +93 -0
- package/habilidades/kotlin-experto/SKILL.md +318 -0
- package/habilidades/kotlin-testing/SKILL.md +267 -0
- package/habilidades/kotlin-testing/recursos/testing-avanzado.md +74 -0
- package/habilidades/kubernetes-orquestacion/SKILL.md +152 -0
- package/habilidades/kubernetes-orquestacion/recursos/manifiestos-completos.md +452 -0
- package/habilidades/langchain-langraph/SKILL.md +386 -0
- package/habilidades/langchain-langraph/recursos/evaluacion-rag.md +321 -0
- package/habilidades/langchain-langraph/recursos/rag-maturity-model.md +225 -0
- package/habilidades/langchain-langraph/recursos/vectorstores.md +306 -0
- package/habilidades/legacy-code-rescue/SKILL.md +267 -0
- package/habilidades/likec4-experto/SKILL.md +412 -0
- package/habilidades/likec4-experto/evals/evals.json +69 -0
- package/habilidades/manejo-errores/.evolved.json +9 -0
- package/habilidades/manejo-errores/SKILL.md +407 -0
- package/habilidades/manejo-errores/recursos/implementaciones-completas.md +248 -0
- package/habilidades/mapear-codebase/SKILL.md +275 -0
- package/habilidades/memoria-busqueda/SKILL.md +194 -0
- package/habilidades/memoria-busqueda/evals/evals.json +44 -0
- package/habilidades/meta-skills-estandar/SKILL.md +298 -0
- package/habilidades/meta-skills-estandar/recursos/anti-patrones-y-leyes.md +205 -0
- package/habilidades/meta-skills-estandar/recursos/frameworks-seguridad.md +107 -0
- package/habilidades/meta-skills-estandar/recursos/idiomas-framework.md +60 -0
- package/habilidades/meta-skills-estandar/recursos/skills-as-agents.md +163 -0
- package/habilidades/microservicios/SKILL.md +155 -0
- package/habilidades/microservicios/recursos/patrones-y-ejemplos-completos.md +325 -0
- package/habilidades/mobile-flutter/SKILL.md +199 -0
- package/habilidades/mobile-flutter/recursos/ejemplos-completos.md +319 -0
- package/habilidades/mobile-react-native/SKILL.md +176 -0
- package/habilidades/mobile-react-native/recursos/ejemplos-completos.md +216 -0
- package/habilidades/mongodb-experto/SKILL.md +302 -0
- package/habilidades/monitoring-alertas/SKILL.md +201 -0
- package/habilidades/monitoring-alertas/recursos/instrumentacion-y-alertas.md +301 -0
- package/habilidades/nestjs-experto/SKILL.md +307 -0
- package/habilidades/nestjs-experto/recursos/guards-interceptors.md +339 -0
- package/habilidades/nestjs-experto/recursos/modulos-di.md +287 -0
- package/habilidades/nestjs-experto/recursos/testing-nestjs.md +354 -0
- package/habilidades/nextjs-experto/SKILL.md +335 -0
- package/habilidades/nextjs-patrones/SKILL.md +303 -0
- package/habilidades/nextjs-testing/SKILL.md +331 -0
- package/habilidades/node-experto/.evolved.json +9 -0
- package/habilidades/node-experto/SKILL.md +266 -0
- package/habilidades/node-experto/recursos/patrones-completos.md +283 -0
- package/habilidades/notificaciones-multicanal/SKILL.md +159 -0
- package/habilidades/notificaciones-multicanal/recursos/config-template.json +115 -0
- package/habilidades/notificaciones-multicanal/recursos/configuracion-y-templates.md +303 -0
- package/habilidades/nuevo-proyecto/SKILL.md +204 -0
- package/habilidades/orquestacion-async/SKILL.md +303 -0
- package/habilidades/paid-media-tracking/SKILL.md +269 -0
- package/habilidades/paid-media-tracking/recursos/auditoria-tracking.md +220 -0
- package/habilidades/paid-media-tracking/recursos/google-ads-api.md +215 -0
- package/habilidades/patrones-python/SKILL.md +228 -0
- package/habilidades/patrones-python/evals/evals.json +56 -0
- package/habilidades/patrones-python/recursos/patrones-avanzados.md +469 -0
- package/habilidades/patrones-python/recursos/referencia-completa.md +202 -0
- package/habilidades/perfil-usuario/SKILL.md +200 -0
- package/habilidades/perfil-usuario/evals/evals.json +55 -0
- package/habilidades/performance-baseline/SKILL.md +297 -0
- package/habilidades/php-experto/SKILL.md +291 -0
- package/habilidades/php-patrones/SKILL.md +306 -0
- package/habilidades/php-testing/SKILL.md +280 -0
- package/habilidades/planear-fase/SKILL.md +269 -0
- package/habilidades/postgresql-experto/SKILL.md +151 -0
- package/habilidades/postgresql-experto/evals/evals.json +53 -0
- package/habilidades/postgresql-experto/recursos/referencia-completa.md +215 -0
- package/habilidades/prevencion-racionalizacion/SKILL.md +175 -0
- package/habilidades/prevencion-sobreingenieria/SKILL.md +323 -0
- package/habilidades/privacy-memoria/SKILL.md +141 -0
- package/habilidades/privacy-memoria/evals/evals.json +43 -0
- package/habilidades/prompt-engineering/SKILL.md +518 -0
- package/habilidades/prompt-engineering/recursos/patrones-avanzados.md +467 -0
- package/habilidades/rag-arquitectura/SKILL.md +338 -0
- package/habilidades/rails-experto/SKILL.md +237 -0
- package/habilidades/rails-experto/recursos/active-record.md +260 -0
- package/habilidades/rails-experto/recursos/hotwire-turbo.md +293 -0
- package/habilidades/rails-experto/recursos/testing-rspec.md +362 -0
- package/habilidades/react-experto/SKILL.md +209 -0
- package/habilidades/react-experto/evals/evals.json +55 -0
- package/habilidades/react-experto/recursos/patrones-y-ejemplos-completos.md +240 -0
- package/habilidades/react-optimizacion/SKILL.md +174 -0
- package/habilidades/react-optimizacion/recursos/patrones-avanzados.md +138 -0
- package/habilidades/redis-experto/SKILL.md +305 -0
- package/habilidades/release-semver/.evolved.json +9 -0
- package/habilidades/release-semver/SKILL.md +248 -0
- package/habilidades/release-semver/scripts/generar-changelog.sh +238 -0
- package/habilidades/rust-experto/SKILL.md +400 -0
- package/habilidades/rust-patrones/SKILL.md +296 -0
- package/habilidades/rust-testing/SKILL.md +311 -0
- package/habilidades/seguridad-skills-ia/SKILL.md +262 -0
- package/habilidades/sql-optimizacion/SKILL.md +200 -0
- package/habilidades/sql-optimizacion/evals/evals.json +54 -0
- package/habilidades/sql-optimizacion/recursos/patrones-sql-avanzados.md +131 -0
- package/habilidades/sre-patrones/SKILL.md +333 -0
- package/habilidades/sre-patrones/recursos/chaos-engineering.md +241 -0
- package/habilidades/sre-patrones/recursos/oncall-design.md +236 -0
- package/habilidades/stripe-pagos/SKILL.md +550 -0
- package/habilidades/stripe-pagos/recursos/errores-reintentos.md +390 -0
- package/habilidades/stripe-pagos/recursos/stripe-connect.md +290 -0
- package/habilidades/structured-outputs/SKILL.md +343 -0
- package/habilidades/swift-experto/SKILL.md +320 -0
- package/habilidades/swift-experto/recursos/keychain-y-wrappers.md +110 -0
- package/habilidades/swift-patrones/SKILL.md +313 -0
- package/habilidades/swift-patrones/recursos/tca-ejemplo-completo.md +113 -0
- package/habilidades/swift-testing/SKILL.md +254 -0
- package/habilidades/swift-testing/recursos/xcuitest-planes.md +143 -0
- package/habilidades/swl-dashboard/SKILL.md +370 -0
- package/habilidades/swl-markitdown/SKILL.md +285 -0
- package/habilidades/swl-markitdown/evals/evals.json +52 -0
- package/habilidades/swl-revisar-impacto/SKILL.md +233 -0
- package/habilidades/tailwind-experto/SKILL.md +240 -0
- package/habilidades/tailwind-experto/recursos/referencia-completa.md +184 -0
- package/habilidades/tdd-workflow/SKILL.md +293 -0
- package/habilidades/terraform-experto/SKILL.md +321 -0
- package/habilidades/testing-python/SKILL.md +340 -0
- package/habilidades/testing-python/recursos/ejemplos-completos.md +167 -0
- package/habilidades/threat-model-lite/SKILL.md +246 -0
- package/habilidades/tracing-processor/SKILL.md +212 -0
- package/habilidades/tracking-measurement/SKILL.md +239 -0
- package/habilidades/tracking-measurement/recursos/consent-mode.md +231 -0
- package/habilidades/tracking-measurement/recursos/gtm-datalayer.md +216 -0
- package/habilidades/tracking-measurement/recursos/meta-capi.md +262 -0
- package/habilidades/typescript-avanzado/SKILL.md +144 -0
- package/habilidades/typescript-avanzado/evals/evals.json +55 -0
- package/habilidades/typescript-avanzado/recursos/patrones-y-ejemplos-completos.md +298 -0
- package/habilidades/typescript-diagnosticos/SKILL.md +513 -0
- package/habilidades/ux-diseno/SKILL.md +116 -0
- package/habilidades/ux-diseno/evals/evals.json +43 -0
- package/habilidades/ux-diseno/recursos/patrones-ux-referencia.md +214 -0
- package/habilidades/validacion-ci-sistema/SKILL.md +136 -0
- package/habilidades/validacion-ci-sistema/recursos/validadores-completos.md +369 -0
- package/habilidades/validacion-ci-sistema/scripts/validar-sistema.sh +286 -0
- package/habilidades/verificacion-evidencia/SKILL.md +160 -0
- package/habilidades/verificar-trabajo/SKILL.md +303 -0
- package/habilidades/verificar-trabajo/recursos/plantilla-verificacion.md +60 -0
- package/habilidades/wiki-conocimiento/SKILL.md +276 -0
- package/habilidades/wireframes-flujos/SKILL.md +212 -0
- package/habilidades/wireframes-flujos/recursos/referencia-completa.md +192 -0
- package/habilidades/workflow-claude-code/SKILL.md +260 -0
- package/habilidades/workflow-claude-code/recursos/referencia-completa.md +109 -0
- package/hooks/_run-hook.sh +57 -0
- package/hooks/actualizar-perfil-usuario.js +364 -0
- package/hooks/agente-lifecycle.js +71 -0
- package/hooks/aiisms-detector.js +173 -0
- package/hooks/audit-trail.js +204 -0
- package/hooks/auto-background.js +97 -0
- package/hooks/auto-consolidacion.js +178 -0
- package/hooks/auto-evolucion.js +666 -0
- package/hooks/auto-restaurar-settings.js +360 -0
- package/hooks/calidad-pre-commit.js +929 -0
- package/hooks/calidad-typescript.js +511 -0
- package/hooks/captura-feedback-usuario.js +148 -0
- package/hooks/check-update.js +211 -0
- package/hooks/clasificador-mensajes.js +271 -0
- package/hooks/degradacion-instintos.js +272 -0
- package/hooks/escaneo-secretos.js +389 -0
- package/hooks/extraccion-aprendizajes.js +763 -0
- package/hooks/grafo-contexto.js +129 -0
- package/hooks/graph-update.js +67 -0
- package/hooks/guardrail-modelo.js +247 -0
- package/hooks/inbox-aviso.js +75 -0
- package/hooks/inyeccion-contexto.js +246 -0
- package/hooks/lib/abort-registry.js +214 -0
- package/hooks/lib/agent-backend.js +210 -0
- package/hooks/lib/agent-comms.js +263 -0
- package/hooks/lib/agent-issue-codes.js +284 -0
- package/hooks/lib/agent-matcher.js +189 -0
- package/hooks/lib/async-hook-registry.js +252 -0
- package/hooks/lib/atomic-write.js +130 -0
- package/hooks/lib/auto-consolidator.js +335 -0
- package/hooks/lib/canary-skills.js +187 -0
- package/hooks/lib/consolidation-lock.js +291 -0
- package/hooks/lib/context-builder.js +430 -0
- package/hooks/lib/context-compressor.js +657 -0
- package/hooks/lib/convergence-detector.js +105 -0
- package/hooks/lib/delegation-tracker.js +198 -0
- package/hooks/lib/detectar-package-manager.js +423 -0
- package/hooks/lib/edit-accumulator.js +171 -0
- package/hooks/lib/error-classifier.js +308 -0
- package/hooks/lib/event-bus.js +112 -0
- package/hooks/lib/evolution-tracker.js +442 -0
- package/hooks/lib/execution-state.js +316 -0
- package/hooks/lib/fingerprint-id.js +135 -0
- package/hooks/lib/gateway-notify.js +116 -0
- package/hooks/lib/graph-security.js +75 -0
- package/hooks/lib/guardrail-metrics.js +202 -0
- package/hooks/lib/hook-circuit-breaker.js +206 -0
- package/hooks/lib/loop-detector.js +267 -0
- package/hooks/lib/mcp-health.js +184 -0
- package/hooks/lib/mcp-pool.js +436 -0
- package/hooks/lib/memory-search.js +506 -0
- package/hooks/lib/merkle-audit.js +96 -0
- package/hooks/lib/model-router.js +222 -0
- package/hooks/lib/normalize-error.js +324 -0
- package/hooks/lib/normalize-input.js +65 -0
- package/hooks/lib/nudge-tracker.js +306 -0
- package/hooks/lib/otlp-exporter.js +365 -0
- package/hooks/lib/performance-marks.js +239 -0
- package/hooks/lib/privacy-filter.js +128 -0
- package/hooks/lib/prompt-injection-scanner.js +209 -0
- package/hooks/lib/provenance-tracker.js +183 -0
- package/hooks/lib/rate-limit-tracker.js +253 -0
- package/hooks/lib/reflect-classifier.js +164 -0
- package/hooks/lib/resource-quota.js +122 -0
- package/hooks/lib/retry-jitter.js +165 -0
- package/hooks/lib/risk-engine.js +368 -0
- package/hooks/lib/run-log.js +408 -0
- package/hooks/lib/session-fts.js +379 -0
- package/hooks/lib/session-store.js +293 -0
- package/hooks/lib/singleton-guard.js +159 -0
- package/hooks/lib/skill-auditor.js +588 -0
- package/hooks/lib/sync-status.js +228 -0
- package/hooks/lib/taint-tracker.js +107 -0
- package/hooks/lib/task-service.js +295 -0
- package/hooks/lib/tech-skills-map.js +146 -0
- package/hooks/lib/telegram-cliente.js +159 -0
- package/hooks/lib/telegram-config.js +170 -0
- package/hooks/lib/token-budget.js +156 -0
- package/hooks/lib/token-estimator.js +420 -0
- package/hooks/lib/toon-compressor.js +245 -0
- package/hooks/lib/usage-model.js +183 -0
- package/hooks/lib/variable-resolver.js +230 -0
- package/hooks/linea-estado.js +324 -0
- package/hooks/metricas-evolucion.js +209 -0
- package/hooks/monitor-contexto.js +325 -0
- package/hooks/notificacion-sesion-stop.js +198 -0
- package/hooks/notificacion-telegram-notification.js +4 -0
- package/hooks/notificacion-telegram-subagent.js +4 -0
- package/hooks/notificacion-telegram.js +267 -0
- package/hooks/preservar-estado-pre-compact.js +150 -0
- package/hooks/proteccion-rutas.js +366 -0
- package/hooks/registro-turnos.js +209 -0
- package/hooks/resumen-sesion.js +249 -0
- package/hooks/risk-scoring.js +323 -0
- package/hooks/rotar-audit-auto.js +122 -0
- package/hooks/sugerir-regenerar-inventario.js +170 -0
- package/hooks/telemetria-agentes.js +167 -0
- package/hooks/tracking-costos.js +688 -0
- package/instintos/global.yaml +8 -0
- package/instintos/perfil-usuario.yaml +53 -0
- package/instintos/prompt-appendices.yaml +57 -0
- package/instintos/proyecto.yaml +372 -0
- package/manifiestos/gateway-config.json +77 -0
- package/manifiestos/handoff-context.json +223 -0
- package/manifiestos/hook-profiles.json +44 -0
- package/manifiestos/hooks-config.json +360 -0
- package/manifiestos/modulos.json +1173 -0
- package/manifiestos/perfiles.json +404 -0
- package/package.json +86 -0
- package/plantillas/ESTADO.md +109 -0
- package/plantillas/HOJA-RUTA.md +143 -0
- package/plantillas/PROYECTO.md +122 -0
- package/plantillas/REQUISITOS.md +132 -0
- package/plantillas/auditor-veto-template.md +105 -0
- package/plantillas/github-workflows/README.md +47 -0
- package/plantillas/github-workflows/release-please.yml +44 -0
- package/plantillas/github-workflows/swl-ci.yml +107 -0
- package/plantillas/github-workflows/swl-security.yml +51 -0
- package/plantillas/mcp-mineru.json +13 -0
- package/plantillas/research/ARQUITECTURA.md +220 -0
- package/plantillas/research/FUNCIONALIDADES.md +175 -0
- package/plantillas/research/RESUMEN.md +165 -0
- package/plantillas/research/STACK.md +233 -0
- package/plantillas/research/TRAMPAS.md +299 -0
- package/plantillas/skill-evals-template.json +44 -0
- package/plugin.json +343 -0
- package/reglas/accesibilidad.md +269 -0
- package/reglas/api-diseno.md +400 -0
- package/reglas/arquitectura.md +352 -0
- package/reglas/brevedad-output.md +124 -0
- package/reglas/cloud-infra.md +247 -0
- package/reglas/docs.md +245 -0
- package/reglas/estilo-codigo.md +201 -0
- package/reglas/git-workflow.md +245 -0
- package/reglas/gobernanza.md +271 -0
- package/reglas/harness-claude-code.md +213 -0
- package/reglas/hooks.md +186 -0
- package/reglas/lenguajes/csharp/estilo-codigo.md +231 -0
- package/reglas/lenguajes/csharp/hooks.md +281 -0
- package/reglas/lenguajes/csharp/patrones.md +226 -0
- package/reglas/lenguajes/csharp/seguridad.md +258 -0
- package/reglas/lenguajes/csharp/testing.md +176 -0
- package/reglas/lenguajes/go/estilo-codigo.md +195 -0
- package/reglas/lenguajes/go/hooks.md +249 -0
- package/reglas/lenguajes/go/patrones.md +249 -0
- package/reglas/lenguajes/go/seguridad.md +225 -0
- package/reglas/lenguajes/go/testing.md +272 -0
- package/reglas/lenguajes/java/estilo-codigo.md +217 -0
- package/reglas/lenguajes/java/hooks.md +251 -0
- package/reglas/lenguajes/java/patrones.md +226 -0
- package/reglas/lenguajes/java/seguridad.md +233 -0
- package/reglas/lenguajes/java/testing.md +238 -0
- package/reglas/lenguajes/kotlin/estilo-codigo.md +208 -0
- package/reglas/lenguajes/kotlin/hooks.md +245 -0
- package/reglas/lenguajes/kotlin/patrones.md +201 -0
- package/reglas/lenguajes/kotlin/seguridad.md +202 -0
- package/reglas/lenguajes/kotlin/testing.md +236 -0
- package/reglas/lenguajes/nextjs/estilo-codigo.md +175 -0
- package/reglas/lenguajes/nextjs/hooks.md +186 -0
- package/reglas/lenguajes/nextjs/patrones.md +225 -0
- package/reglas/lenguajes/nextjs/seguridad.md +216 -0
- package/reglas/lenguajes/nextjs/testing.md +193 -0
- package/reglas/lenguajes/php/estilo-codigo.md +228 -0
- package/reglas/lenguajes/php/hooks.md +165 -0
- package/reglas/lenguajes/php/patrones.md +233 -0
- package/reglas/lenguajes/php/seguridad.md +186 -0
- package/reglas/lenguajes/php/testing.md +205 -0
- package/reglas/lenguajes/rust/estilo-codigo.md +207 -0
- package/reglas/lenguajes/rust/hooks.md +240 -0
- package/reglas/lenguajes/rust/patrones.md +250 -0
- package/reglas/lenguajes/rust/seguridad.md +221 -0
- package/reglas/lenguajes/rust/testing.md +194 -0
- package/reglas/lenguajes/swift/estilo-codigo.md +238 -0
- package/reglas/lenguajes/swift/hooks.md +257 -0
- package/reglas/lenguajes/swift/patrones.md +235 -0
- package/reglas/lenguajes/swift/seguridad.md +248 -0
- package/reglas/lenguajes/swift/testing.md +242 -0
- package/reglas/markitdown.md +60 -0
- package/reglas/memoria-consolidada.md +209 -0
- package/reglas/patrones.md +225 -0
- package/reglas/performance.md +195 -0
- package/reglas/pruebas.md +159 -0
- package/reglas/seguridad-agentes.md +351 -0
- package/reglas/seguridad.md +151 -0
- package/reglas/skills-estandar.md +373 -0
- package/reglas/testing.md +193 -0
- package/schemas/agent-contract.json +176 -0
- package/schemas/agent-frontmatter.schema.json +149 -0
- package/schemas/agent-message.schema.json +53 -0
- package/schemas/agent-output-implementacion.schema.json +85 -0
- package/schemas/agent-output-planificacion.schema.json +113 -0
- package/schemas/agent-output-review.schema.json +78 -0
- package/schemas/diary-entry.schema.json +80 -0
- package/schemas/hook-profiles.schema.json +39 -0
- package/schemas/hooks-config.schema.json +74 -0
- package/schemas/instinct.schema.json +115 -0
- package/schemas/modulos.schema.json +29 -0
- package/schemas/perfiles.schema.json +28 -0
- package/schemas/plugin.schema.json +64 -0
- package/schemas/skill-evals.schema.json +95 -0
- package/schemas/skill-frontmatter.schema.json +170 -0
- package/scripts/actualizar.js +145 -0
- package/scripts/audit-skills.sh +78 -0
- package/scripts/auditar-agentes-gaps.js +149 -0
- package/scripts/auditar-cobertura-frameworks.js +241 -0
- package/scripts/auditar-skills-gaps.js +206 -0
- package/scripts/bootstrap-instintos.js +259 -0
- package/scripts/check-update.js +109 -0
- package/scripts/comandos/agents.js +105 -0
- package/scripts/comandos/info.js +108 -0
- package/scripts/comandos/install-asistido.js +186 -0
- package/scripts/comandos/skills.js +211 -0
- package/scripts/configurar-branch-protection.js +418 -0
- package/scripts/daemon-swl.py +388 -0
- package/scripts/desinstalar.js +130 -0
- package/scripts/doctor.js +559 -0
- package/scripts/field-report.js +199 -0
- package/scripts/generar-inventario.js +317 -0
- package/scripts/inbox-tmux-inject.js +161 -0
- package/scripts/inferir-herramientas-permitidas.js +586 -0
- package/scripts/inicializar.js +133 -0
- package/scripts/instalador.js +1031 -0
- package/scripts/instalar-git-hook.js +122 -0
- package/scripts/lib/agp-frontmatter.js +222 -0
- package/scripts/lib/append-con-marcadores.js +199 -0
- package/scripts/lib/artefactos-python.js +43 -0
- package/scripts/lib/audit-query.js +221 -0
- package/scripts/lib/autostart-linux.js +347 -0
- package/scripts/lib/autostart-macos.js +360 -0
- package/scripts/lib/autostart-windows.js +307 -0
- package/scripts/lib/budget-enforcer.js +252 -0
- package/scripts/lib/claude-sessions.js +285 -0
- package/scripts/lib/configurar-ci.js +380 -0
- package/scripts/lib/console-span-exporter.js +92 -0
- package/scripts/lib/contadores-inventario.js +217 -0
- package/scripts/lib/dashboard-widgets.js +290 -0
- package/scripts/lib/detectar-runtime.js +279 -0
- package/scripts/lib/detectar-stack.js +187 -0
- package/scripts/lib/diary-entry.js +234 -0
- package/scripts/lib/drift-detector.js +545 -0
- package/scripts/lib/estado.js +124 -0
- package/scripts/lib/gestor-componentes.js +243 -0
- package/scripts/lib/gitignore-manifest.js +305 -0
- package/scripts/lib/graph-analyze.py +556 -0
- package/scripts/lib/graph-builder.py +485 -0
- package/scripts/lib/graph-cluster.py +259 -0
- package/scripts/lib/health-row.js +168 -0
- package/scripts/lib/hooks-settings.js +789 -0
- package/scripts/lib/manifiestos.js +138 -0
- package/scripts/lib/mc-client.js +137 -0
- package/scripts/lib/notificaciones-telegram.js +1107 -0
- package/scripts/lib/npm-version.js +261 -0
- package/scripts/lib/paquetes-conocidos.js +50 -0
- package/scripts/lib/preservar-usuario.js +586 -0
- package/scripts/lib/prompt-builder.js +264 -0
- package/scripts/lib/resolver-externo.js +332 -0
- package/scripts/lib/schedule-parser.js +305 -0
- package/scripts/lib/scoring-instintos.js +240 -0
- package/scripts/lib/seguridad.js +160 -0
- package/scripts/lib/selector-interactivo.js +152 -0
- package/scripts/lib/semantic-search.js +242 -0
- package/scripts/lib/skill-discovery.js +234 -0
- package/scripts/lib/skill-metrics.js +246 -0
- package/scripts/lib/skill-normalizer.js +112 -0
- package/scripts/lib/skills-hub.js +340 -0
- package/scripts/lib/span-schema.js +134 -0
- package/scripts/lib/tool-cost-analyzer.js +255 -0
- package/scripts/lib/tracing-processor-interface.js +286 -0
- package/scripts/lib/transformadores/base.js +80 -0
- package/scripts/lib/transformadores/claude.js +124 -0
- package/scripts/lib/transformadores/codex.js +115 -0
- package/scripts/lib/transformadores/copilot.js +106 -0
- package/scripts/lib/transformadores/gemini.js +74 -0
- package/scripts/lib/transformadores/index.js +35 -0
- package/scripts/lib/transformadores/opencode.js +75 -0
- package/scripts/lib/ui.js +259 -0
- package/scripts/limpiar-artefactos-python.js +131 -0
- package/scripts/mcp-orchestrator.py +386 -0
- package/scripts/mcp-pool-manager.py +352 -0
- package/scripts/mcp-telemetry.py +378 -0
- package/scripts/poblar-evolvable.js +226 -0
- package/scripts/publicar.js +287 -0
- package/scripts/reflect-skills.js +403 -0
- package/scripts/rotar-audit-logs.js +185 -0
- package/scripts/run-skill-evals.js +242 -0
- package/scripts/smoke-test.js +374 -0
- package/scripts/token-analysis.py +471 -0
- package/scripts/validar-manifest.js +195 -0
- package/scripts/validar-memoria.js +321 -0
- package/scripts/validar-tests-aislamiento.js +184 -0
- package/scripts/validar-tokens-test.js +208 -0
- package/scripts/validar.js +147 -0
- package/scripts/validate-markdown.py +339 -0
- package/scripts/validate-skills.py +385 -0
- package/scripts/vendor/claude-usage/README.md +116 -0
- package/scripts/vendor/claude-usage/cli.py +334 -0
- package/scripts/vendor/claude-usage/dashboard.py +795 -0
- package/scripts/vendor/claude-usage/scanner.py +467 -0
- package/scripts/vendor/markitdown/cli.py +194 -0
- package/scripts/verificar-evolucion.js +289 -0
- package/scripts/verificar-release.js +494 -0
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
# Angular Avanzado — Ejemplos Completos
|
|
2
|
+
|
|
3
|
+
## Resource API (v19+) — Datos Asíncronos como Signals
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
// Resource API — alternativa a RxJS para carga de datos simple
|
|
7
|
+
import { resource, linkedSignal } from "@angular/core";
|
|
8
|
+
|
|
9
|
+
@Component({ standalone: true, ... })
|
|
10
|
+
export class UsuariosComponent {
|
|
11
|
+
private http = inject(HttpClient);
|
|
12
|
+
|
|
13
|
+
// Filtro reactivo
|
|
14
|
+
readonly busqueda = signal("");
|
|
15
|
+
readonly pagina = signal(1);
|
|
16
|
+
|
|
17
|
+
// Resource — carga datos cuando cambia el request
|
|
18
|
+
readonly usuariosResource = resource({
|
|
19
|
+
request: () => ({
|
|
20
|
+
q: this.busqueda(),
|
|
21
|
+
page: this.pagina(),
|
|
22
|
+
}),
|
|
23
|
+
|
|
24
|
+
loader: ({ request }) =>
|
|
25
|
+
firstValueFrom(
|
|
26
|
+
this.http.get<PaginatedResponse<Usuario>>("/api/usuarios", {
|
|
27
|
+
params: { q: request.q, page: String(request.page) },
|
|
28
|
+
})
|
|
29
|
+
),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Signals derivados del resource
|
|
33
|
+
readonly usuarios = computed(() => this.usuariosResource.value()?.items ?? []);
|
|
34
|
+
readonly cargando = computed(() => this.usuariosResource.isLoading());
|
|
35
|
+
readonly error = computed(() => this.usuariosResource.error());
|
|
36
|
+
readonly totalPaginas = computed(() => this.usuariosResource.value()?.totalPaginas ?? 0);
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
```html
|
|
41
|
+
<!-- Template con @defer y resource -->
|
|
42
|
+
<div class="usuarios-lista">
|
|
43
|
+
@if (cargando()) {
|
|
44
|
+
<mat-progress-bar mode="indeterminate" />
|
|
45
|
+
} @else if (error()) {
|
|
46
|
+
<p class="error">Error al cargar: {{ error()?.message }}</p>
|
|
47
|
+
} @else {
|
|
48
|
+
@for (usuario of usuarios(); track usuario.id) {
|
|
49
|
+
<app-tarjeta-usuario [usuario]="usuario" />
|
|
50
|
+
} @empty {
|
|
51
|
+
<p class="vacio">No se encontraron usuarios</p>
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
</div>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
---
|
|
58
|
+
|
|
59
|
+
## Guards, Resolvers e Interceptors Funcionales
|
|
60
|
+
|
|
61
|
+
```typescript
|
|
62
|
+
// guards/auth.guard.ts — funcional, sin clase
|
|
63
|
+
import { inject } from "@angular/core";
|
|
64
|
+
import { CanActivateFn, Router } from "@angular/router";
|
|
65
|
+
import { AuthService } from "../services/auth.service";
|
|
66
|
+
|
|
67
|
+
export const authGuard: CanActivateFn = (route, state) => {
|
|
68
|
+
const auth = inject(AuthService);
|
|
69
|
+
const router = inject(Router);
|
|
70
|
+
|
|
71
|
+
if (auth.estaAutenticado()) {
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
return router.createUrlTree(["/login"], {
|
|
76
|
+
queryParams: { returnUrl: state.url },
|
|
77
|
+
});
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// Guard con roles — composable
|
|
81
|
+
export const roleGuard = (rolesPermitidos: string[]): CanActivateFn =>
|
|
82
|
+
() => {
|
|
83
|
+
const auth = inject(AuthService);
|
|
84
|
+
const router = inject(Router);
|
|
85
|
+
|
|
86
|
+
if (rolesPermitidos.includes(auth.usuarioActual()?.rol ?? "")) {
|
|
87
|
+
return true;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return router.createUrlTree(["/sin-permisos"]);
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
// resolvers/usuario.resolver.ts
|
|
94
|
+
import { ResolveFn } from "@angular/router";
|
|
95
|
+
import { inject } from "@angular/core";
|
|
96
|
+
import { UsuariosService } from "../services/usuarios.service";
|
|
97
|
+
|
|
98
|
+
export const usuarioResolver: ResolveFn<Usuario> = (route) => {
|
|
99
|
+
return inject(UsuariosService).obtenerPorId(route.paramMap.get("id")!);
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
// interceptors/auth.interceptor.ts
|
|
103
|
+
import { HttpInterceptorFn } from "@angular/common/http";
|
|
104
|
+
import { inject } from "@angular/core";
|
|
105
|
+
import { AuthService } from "../services/auth.service";
|
|
106
|
+
|
|
107
|
+
export const authInterceptor: HttpInterceptorFn = (req, next) => {
|
|
108
|
+
const auth = inject(AuthService);
|
|
109
|
+
const token = auth.token();
|
|
110
|
+
|
|
111
|
+
if (!token) return next(req);
|
|
112
|
+
|
|
113
|
+
return next(req.clone({
|
|
114
|
+
setHeaders: { Authorization: `Bearer ${token}` },
|
|
115
|
+
}));
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
// app.config.ts — registrar todo funcionalmente
|
|
119
|
+
export const appConfig: ApplicationConfig = {
|
|
120
|
+
providers: [
|
|
121
|
+
provideRouter(routes, withComponentInputBinding()),
|
|
122
|
+
provideHttpClient(withInterceptors([authInterceptor, errorInterceptor])),
|
|
123
|
+
provideAnimationsAsync(),
|
|
124
|
+
],
|
|
125
|
+
};
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
---
|
|
129
|
+
|
|
130
|
+
## SSR / SSG con Angular Universal
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
// Detectar si estamos en el servidor o el navegador
|
|
134
|
+
import { isPlatformBrowser, isPlatformServer } from "@angular/common";
|
|
135
|
+
import { PLATFORM_ID, inject } from "@angular/core";
|
|
136
|
+
|
|
137
|
+
@Injectable({ providedIn: "root" })
|
|
138
|
+
export class PlatformService {
|
|
139
|
+
private platformId = inject(PLATFORM_ID);
|
|
140
|
+
|
|
141
|
+
readonly esBrowser = isPlatformBrowser(this.platformId);
|
|
142
|
+
readonly esServidor = isPlatformServer(this.platformId);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// Uso en componente — evitar acceso a APIs del browser en servidor
|
|
146
|
+
@Component({ standalone: true, ... })
|
|
147
|
+
export class MapaComponent implements OnInit {
|
|
148
|
+
private platform = inject(PlatformService);
|
|
149
|
+
|
|
150
|
+
ngOnInit(): void {
|
|
151
|
+
if (!this.platform.esBrowser) return;
|
|
152
|
+
|
|
153
|
+
import("leaflet").then(L => {
|
|
154
|
+
const mapa = L.map("mapa").setView([19.4326, -99.1332], 13);
|
|
155
|
+
L.tileLayer("https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png").addTo(mapa);
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Transferir estado del servidor al cliente — evitar doble petición
|
|
161
|
+
import { TransferState, makeStateKey } from "@angular/core";
|
|
162
|
+
|
|
163
|
+
const CLAVE_PRODUCTOS = makeStateKey<Producto[]>("productos");
|
|
164
|
+
|
|
165
|
+
@Injectable({ providedIn: "root" })
|
|
166
|
+
export class ProductosService {
|
|
167
|
+
private http = inject(HttpClient);
|
|
168
|
+
private transferState = inject(TransferState);
|
|
169
|
+
|
|
170
|
+
obtenerTodos(): Observable<Producto[]> {
|
|
171
|
+
if (this.transferState.hasKey(CLAVE_PRODUCTOS)) {
|
|
172
|
+
const productos = this.transferState.get(CLAVE_PRODUCTOS, []);
|
|
173
|
+
this.transferState.remove(CLAVE_PRODUCTOS);
|
|
174
|
+
return of(productos);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
return this.http.get<Producto[]>("/api/productos").pipe(
|
|
178
|
+
tap(productos => this.transferState.set(CLAVE_PRODUCTOS, productos))
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## Angular Zoneless (Experimental v18+)
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
// app.config.ts — habilitar zoneless
|
|
190
|
+
import { provideExperimentalZonelessChangeDetection } from "@angular/core";
|
|
191
|
+
|
|
192
|
+
export const appConfig: ApplicationConfig = {
|
|
193
|
+
providers: [
|
|
194
|
+
provideExperimentalZonelessChangeDetection(),
|
|
195
|
+
],
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
// Con zoneless, la detección de cambios sólo ocurre cuando:
|
|
199
|
+
// 1. Un signal cambia (automático)
|
|
200
|
+
// 2. Se llama markForCheck() manualmente (para casos especiales)
|
|
201
|
+
// 3. Un async pipe emite un valor
|
|
202
|
+
|
|
203
|
+
// Componente completamente reactivo — cero zone.js
|
|
204
|
+
@Component({
|
|
205
|
+
standalone: true,
|
|
206
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
207
|
+
template: `
|
|
208
|
+
<p>Contador: {{ contador() }}</p>
|
|
209
|
+
<button (click)="incrementar()">+</button>
|
|
210
|
+
`,
|
|
211
|
+
})
|
|
212
|
+
export class ContadorComponent {
|
|
213
|
+
readonly contador = signal(0);
|
|
214
|
+
|
|
215
|
+
incrementar(): void {
|
|
216
|
+
this.contador.update(n => n + 1);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
```
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: angular-moderno
|
|
3
|
+
description: Angular v17+/v20+. Signals, standalone components, OnPush, host bindings, nueva sintaxis de control flow (@if/@for/@switch), defer blocks y patrones modernos.
|
|
4
|
+
version: "1.0.0"
|
|
5
|
+
herramientasPermitidas: [Read]
|
|
6
|
+
exclusiones:
|
|
7
|
+
- "No cargar para patrones Angular avanzados (zoneless, SSR, Resource API, interceptores funcionales) — para eso cargar `angular-avanzado`."
|
|
8
|
+
- "No cargar para formularios Angular complejos, state management o animaciones avanzadas — cargar `angular-avanzado`."
|
|
9
|
+
- "No cargar para frameworks React o Vue — los patrones de signals y control flow son específicos de Angular."
|
|
10
|
+
- "No cargar para testing Angular (TestBed, harnesses, Spectator) — para testing cargar el skill de testing del stack."
|
|
11
|
+
evolvable: true # default para skill estandar
|
|
12
|
+
---
|
|
13
|
+
# Angular Moderno (v17+)
|
|
14
|
+
|
|
15
|
+
## Cuándo NO cargar
|
|
16
|
+
|
|
17
|
+
- La tarea requiere Angular avanzado: zoneless, SSR/SSG con Angular Universal, Resource API, interceptores funcionales — cargar `angular-avanzado`.
|
|
18
|
+
- Los temas son formularios reactivos complejos, state management con signals store o animaciones Angular — cargar `angular-avanzado`.
|
|
19
|
+
- El framework es React, Vue o Svelte — los patrones de signals y `@if`/`@for` son específicos de Angular.
|
|
20
|
+
- La tarea es escribir tests Angular (TestBed, harnesses de Material) — usar el skill de testing correspondiente.
|
|
21
|
+
|
|
22
|
+
## Principios de la era moderna de Angular
|
|
23
|
+
|
|
24
|
+
Angular evolucionó hacia un modelo más reactivo y explícito:
|
|
25
|
+
- **Signals** reemplaza Zone.js para la detección de cambios.
|
|
26
|
+
- **Standalone** elimina NgModules como unidad de organización obligatoria.
|
|
27
|
+
- **New control flow** (@if, @for, @switch) reemplaza directivas estructurales.
|
|
28
|
+
- **OnPush + Signals** es el estándar para componentes de producción.
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## Standalone Components
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { Component, OnInit, inject } from '@angular/core';
|
|
36
|
+
import { RouterLink } from '@angular/router';
|
|
37
|
+
import { MatButtonModule } from '@angular/material/button';
|
|
38
|
+
import { FacturaCardComponent } from './factura-card/factura-card.component';
|
|
39
|
+
|
|
40
|
+
@Component({
|
|
41
|
+
selector: 'app-facturas-lista',
|
|
42
|
+
standalone: true,
|
|
43
|
+
imports: [RouterLink, MatButtonModule, FacturaCardComponent],
|
|
44
|
+
templateUrl: './facturas-lista.component.html',
|
|
45
|
+
styleUrl: './facturas-lista.component.css',
|
|
46
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
47
|
+
})
|
|
48
|
+
export class FacturasListaComponent implements OnInit {
|
|
49
|
+
private readonly facturasService = inject(FacturasService);
|
|
50
|
+
ngOnInit(): void { ... }
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
---
|
|
55
|
+
|
|
56
|
+
## Signals — Estado reactivo
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
import { signal, computed, Signal } from '@angular/core';
|
|
60
|
+
|
|
61
|
+
@Component({ ... })
|
|
62
|
+
export class FacturasListaComponent {
|
|
63
|
+
private readonly _facturas = signal<Factura[]>([]);
|
|
64
|
+
private readonly _cargando = signal(false);
|
|
65
|
+
private readonly _filtro = signal('');
|
|
66
|
+
|
|
67
|
+
readonly facturas: Signal<Factura[]> = this._facturas.asReadonly();
|
|
68
|
+
readonly cargando: Signal<boolean> = this._cargando.asReadonly();
|
|
69
|
+
|
|
70
|
+
// Derivaciones con computed() — NUNCA funciones directas en templates
|
|
71
|
+
readonly facturasFiltradas = computed(() => {
|
|
72
|
+
const filtro = this._filtro().toLowerCase();
|
|
73
|
+
return this._facturas().filter(f =>
|
|
74
|
+
f.folio.toLowerCase().includes(filtro)
|
|
75
|
+
);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
readonly totalFacturas = computed(() => this.facturasFiltradas().length);
|
|
79
|
+
|
|
80
|
+
actualizarFiltro(valor: string): void {
|
|
81
|
+
this._filtro.set(valor);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Nueva sintaxis de control flow
|
|
89
|
+
|
|
90
|
+
```html
|
|
91
|
+
<!-- @if — reemplaza *ngIf -->
|
|
92
|
+
@if (cargando()) {
|
|
93
|
+
<mat-spinner diameter="40" />
|
|
94
|
+
} @else if (hayFacturas()) {
|
|
95
|
+
<div class="lista-facturas">
|
|
96
|
+
<!-- @for — reemplaza *ngFor, track OBLIGATORIO -->
|
|
97
|
+
@for (factura of facturasFiltradas(); track factura.id) {
|
|
98
|
+
<app-factura-card [factura]="factura" />
|
|
99
|
+
} @empty {
|
|
100
|
+
<p>No se encontraron facturas con ese filtro.</p>
|
|
101
|
+
}
|
|
102
|
+
</div>
|
|
103
|
+
} @else {
|
|
104
|
+
<p>No tienes facturas registradas.</p>
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
<!-- @switch — reemplaza ngSwitch -->
|
|
108
|
+
@switch (factura.estatus) {
|
|
109
|
+
@case ('emitida') { <span class="badge-verde">Emitida</span> }
|
|
110
|
+
@case ('cancelada') { <span class="badge-rojo">Cancelada</span> }
|
|
111
|
+
}
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## @defer — Carga diferida de componentes
|
|
117
|
+
|
|
118
|
+
```html
|
|
119
|
+
@defer (on viewport) {
|
|
120
|
+
<app-grafica-ventas [datos]="datosGrafica()" />
|
|
121
|
+
} @placeholder {
|
|
122
|
+
<div class="h-64 bg-gray-100 animate-pulse rounded"></div>
|
|
123
|
+
} @loading (minimum 300ms) {
|
|
124
|
+
<mat-spinner />
|
|
125
|
+
} @error {
|
|
126
|
+
<p>Error al cargar la gráfica.</p>
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Input y Output modernos (Angular v17.1+)
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
import { input, output, model } from '@angular/core';
|
|
136
|
+
|
|
137
|
+
@Component({ ... })
|
|
138
|
+
export class FacturaCardComponent {
|
|
139
|
+
readonly factura = input.required<Factura>();
|
|
140
|
+
readonly modoCompacto = input(false);
|
|
141
|
+
readonly facturaId = input('', { transform: (v: string) => v.trim() });
|
|
142
|
+
|
|
143
|
+
readonly cancelar = output<string>();
|
|
144
|
+
readonly seleccionar = output<Factura>();
|
|
145
|
+
readonly checked = model(false); // two-way binding
|
|
146
|
+
|
|
147
|
+
alCancelar(): void {
|
|
148
|
+
this.cancelar.emit(this.factura().id);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## Host bindings, Services con Signals y Formularios reactivos
|
|
156
|
+
|
|
157
|
+
Para ejemplos completos de host bindings con clases dinámicas, services store con signals y HttpClient, y formularios reactivos con FormBuilder, ver [recursos/ejemplos-avanzados.md](recursos/ejemplos-avanzados.md).
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Anti-patrones a evitar
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
// MAL: *ngIf / *ngFor en Angular v17+
|
|
165
|
+
// BIEN: @if / @for con track obligatorio
|
|
166
|
+
|
|
167
|
+
// MAL: funciones en templates (se evalúan en cada CD)
|
|
168
|
+
// {{ getTotal() }}
|
|
169
|
+
// BIEN: computed()
|
|
170
|
+
// readonly total = computed(() => this.calcularTotal());
|
|
171
|
+
|
|
172
|
+
// MAL: NgModules innecesarios en proyectos nuevos
|
|
173
|
+
|
|
174
|
+
// MAL: item?.propiedad para signals (NG8107)
|
|
175
|
+
// BIEN: @if (item()) { {{ item()!.nombre }} }
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Gotchas / Errores comunes no obvios
|
|
179
|
+
|
|
180
|
+
**`@for` sin `track` compila con advertencia en v17 pero causa re-renderizado completo de la lista**: si se omite `track` (o se usa `track $index` en listas mutables), Angular recrea todos los elementos DOM al cambiar el array en lugar de hacer reconciliación. Causa: sin `track`, Angular no puede identificar qué elemento cambió. Fix: usar `track item.id` con el identificador estable del elemento; solo usar `track $index` en listas de solo lectura que nunca cambian de orden.
|
|
181
|
+
|
|
182
|
+
**`computed()` que lee otra signal dentro de un `effect()` no re-ejecuta el efecto cuando cambia la computed**: si un `effect()` lee `this.total()` que es un `computed()`, el efecto sí se suscribe a la computed — pero si dentro del `effect` se llama a un método que modifica otra signal no leída directamente en el efecto, ese efecto no se re-ejecuta. Causa: Angular rastrea solo las signals leídas síncronamente dentro del cuerpo del efecto. Fix: leer explícitamente todas las signals de las que depende el efecto en su cuerpo, no mediante funciones intermedias.
|
|
183
|
+
|
|
184
|
+
**`input.required<T>()` accedido fuera del contexto de renderizado (en `constructor`) lanza error de runtime**: `this.factura()` dentro del `constructor` de un componente que usa `input.required<Factura>()` lanza `NG0950: Input is required but no value is available yet`. Causa: los inputs signal no tienen valor hasta que Angular completa la inicialización del componente. Fix: acceder a inputs en `ngOnInit`, en `computed()`, o en métodos del template — nunca en el constructor.
|
|
185
|
+
|
|
186
|
+
**`takeUntilDestroyed()` usado fuera del contexto de inyección lanza error**: `takeUntilDestroyed()` sin argumentos requiere un `DestroyRef` del contexto de inyección activo — si se llama dentro de un callback asíncrono (como `.then()` o `setTimeout`), el injection context ya no está activo. Causa: `inject()` solo funciona en contextos de inyección síncronos. Fix: capturar `DestroyRef` en el constructor con `private destroyRef = inject(DestroyRef)` y pasarlo explícitamente: `takeUntilDestroyed(this.destroyRef)`.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schemas/skill-evals.schema.json",
|
|
3
|
+
"skill_name": "angular-moderno",
|
|
4
|
+
"artifact_type": "skill",
|
|
5
|
+
"schema_version": 1,
|
|
6
|
+
"description": "Evals para angular-moderno — signals, control flow, standalone components (Angular 17+).",
|
|
7
|
+
"evals": [
|
|
8
|
+
{
|
|
9
|
+
"id": 0,
|
|
10
|
+
"prompt": "Componente Angular 17+ minimal con signal — snippet paste-ready.",
|
|
11
|
+
"files": [],
|
|
12
|
+
"expectations": [
|
|
13
|
+
"Usa `signal()` (no `BehaviorSubject` ni property simple).",
|
|
14
|
+
"`standalone: true` en el decorador o import standalone.",
|
|
15
|
+
"NO usa NgModule."
|
|
16
|
+
],
|
|
17
|
+
"tags": ["signals"],
|
|
18
|
+
"weight": 1.5
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "anti-ngif",
|
|
22
|
+
"prompt": "Condicional en template Angular moderno.",
|
|
23
|
+
"files": [],
|
|
24
|
+
"expectations": [
|
|
25
|
+
"Usa `@if (...) { ... } @else { ... }` (control flow block, Angular 17+).",
|
|
26
|
+
"NO usa `*ngIf` (legacy).",
|
|
27
|
+
"La respuesta menciona que `*ngIf` sigue funcionando pero es deprecated."
|
|
28
|
+
],
|
|
29
|
+
"grading_guidance": "Failure si usa *ngIf sin comentar que es legacy.",
|
|
30
|
+
"tags": ["anti-pattern", "control-flow"],
|
|
31
|
+
"weight": 1.5
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"id": "computed",
|
|
35
|
+
"prompt": "Derivar un valor de dos signals — ¿cómo?",
|
|
36
|
+
"files": [],
|
|
37
|
+
"expectations": [
|
|
38
|
+
"Usa `computed(() => signalA() + signalB())`.",
|
|
39
|
+
"NO usa `effect()` para derivar valores.",
|
|
40
|
+
"Menciona que computed es lazy y memoizado."
|
|
41
|
+
],
|
|
42
|
+
"tags": ["signals"]
|
|
43
|
+
}
|
|
44
|
+
]
|
|
45
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
# Angular Moderno — Ejemplos avanzados
|
|
2
|
+
|
|
3
|
+
## Host bindings
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
@Component({
|
|
7
|
+
selector: 'app-badge',
|
|
8
|
+
template: `{{ texto() }}`,
|
|
9
|
+
host: {
|
|
10
|
+
// Clases estáticas
|
|
11
|
+
'class': 'inline-flex items-center px-2 py-1 rounded text-sm font-medium',
|
|
12
|
+
// Bindings dinámicos
|
|
13
|
+
'[class.bg-green-100]': "tipo() === 'exito'",
|
|
14
|
+
'[class.bg-red-100]': "tipo() === 'error'",
|
|
15
|
+
'[class.bg-yellow-100]': "tipo() === 'advertencia'",
|
|
16
|
+
'[attr.role]': '"status"',
|
|
17
|
+
'[attr.aria-label]': 'texto()',
|
|
18
|
+
},
|
|
19
|
+
})
|
|
20
|
+
export class BadgeComponent {
|
|
21
|
+
readonly texto = input.required<string>();
|
|
22
|
+
readonly tipo = input<'exito' | 'error' | 'advertencia'>('exito');
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Services con Signals — ejemplo completo
|
|
29
|
+
|
|
30
|
+
```typescript
|
|
31
|
+
import { Injectable, signal, computed } from '@angular/core';
|
|
32
|
+
import { HttpClient } from '@angular/common/http';
|
|
33
|
+
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
34
|
+
|
|
35
|
+
@Injectable({ providedIn: 'root' })
|
|
36
|
+
export class FacturasStore {
|
|
37
|
+
private readonly http = inject(HttpClient);
|
|
38
|
+
private readonly destroyRef = inject(DestroyRef);
|
|
39
|
+
|
|
40
|
+
// Estado interno
|
|
41
|
+
private readonly _facturas = signal<Factura[]>([]);
|
|
42
|
+
private readonly _cargando = signal(false);
|
|
43
|
+
private readonly _error = signal<string | null>(null);
|
|
44
|
+
|
|
45
|
+
// API pública
|
|
46
|
+
readonly facturas = this._facturas.asReadonly();
|
|
47
|
+
readonly cargando = this._cargando.asReadonly();
|
|
48
|
+
readonly error = this._error.asReadonly();
|
|
49
|
+
readonly totalEmitidas = computed(() =>
|
|
50
|
+
this._facturas().filter(f => f.estatus === 'emitida').length
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
cargar(): void {
|
|
54
|
+
this._cargando.set(true);
|
|
55
|
+
this._error.set(null);
|
|
56
|
+
this.http.get<PaginatedResponse<Factura>>('/api/v1/facturas/')
|
|
57
|
+
.pipe(
|
|
58
|
+
map(resp => resp.items),
|
|
59
|
+
takeUntilDestroyed(this.destroyRef),
|
|
60
|
+
)
|
|
61
|
+
.subscribe({
|
|
62
|
+
next: facturas => {
|
|
63
|
+
this._facturas.set(facturas);
|
|
64
|
+
this._cargando.set(false);
|
|
65
|
+
},
|
|
66
|
+
error: err => {
|
|
67
|
+
this._error.set(err.message);
|
|
68
|
+
this._cargando.set(false);
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## Formularios reactivos — ejemplo completo
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { FormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
|
|
81
|
+
|
|
82
|
+
@Component({
|
|
83
|
+
standalone: true,
|
|
84
|
+
imports: [ReactiveFormsModule, MatFormFieldModule, MatInputModule, MatDatepickerModule],
|
|
85
|
+
...
|
|
86
|
+
})
|
|
87
|
+
export class FacturaFormComponent {
|
|
88
|
+
private readonly fb = inject(FormBuilder);
|
|
89
|
+
|
|
90
|
+
readonly form = this.fb.group({
|
|
91
|
+
folio: ['', [Validators.required, Validators.maxLength(20)]],
|
|
92
|
+
// MatDatepicker OBLIGATORIO — NUNCA <input type="date">
|
|
93
|
+
fecha: [new Date(), Validators.required],
|
|
94
|
+
monto: [null as number | null, [Validators.required, Validators.min(0.01)]],
|
|
95
|
+
estatus: ['borrador' as 'borrador' | 'emitida', Validators.required],
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
get folioControl() { return this.form.controls.folio; }
|
|
99
|
+
|
|
100
|
+
onSubmit(): void {
|
|
101
|
+
if (this.form.invalid) return;
|
|
102
|
+
const datos = this.form.getRawValue();
|
|
103
|
+
// ...
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
```
|