Buscar/Desarrollar un framework que ofrezca una sola API en varios lenguajes de programación

Desarrollar un framework que ofrezca una sola API en varios lenguajes de programación

Para crear un framework que genera paquetes para varios lenguajes desde un solo código. Fija reglas para el protocolo JSON entre procesos, los tipos exportables, la generación de código y las pruebas que comprueban que todos los lenguajes se comportan igual.

Para usar estas reglas de IA
## Mantener el mismo comportamiento y la compatibilidad hacia atrás en todos los lenguajes Un framework entre lenguajes debe optimizar un comportamiento que siga siendo comprensible y equivalente en todos los lenguajes compatibles, no todos los modismos disponibles en su lenguaje de implementación. ### Invariantes fundamentales - Preserva la compatibilidad con versiones anteriores del formato del ensamblado, el protocolo de ejecución y las API públicas. - Exige un comportamiento observable equivalente en todos los lenguajes de destino compatibles. - Genera código que siga las convenciones habituales de nombres, empaquetado y tipos de cada lenguaje de destino. - Acepta solo características del lenguaje de origen que puedan representarse fielmente en todos los destinos. - Prioriza la corrección y la interoperabilidad frente a los atajos de rendimiento específicos de un destino. ### Límites de los paquetes - Separa el núcleo del protocolo, los entornos de ejecución anfitriones, las definiciones de esquema, los generadores de código, las herramientas de reflexión, las comprobaciones de compatibilidad y los fixtures de prueba. - Mantén las utilidades de compilación y los informes de conformidad fuera de los paquetes de ejecución. - Trata cada entorno de ejecución de lenguaje y cada integración opcional como un paquete con responsabilidad independiente. - Coloca los fixtures compartidos donde todos los compiladores, generadores y pruebas de ejecución puedan consumir los mismos casos de comportamiento. - Mantén los componentes alojados en repositorios separados detrás de dependencias explícitas y versionadas. ## Ejecutar el código en un proceso núcleo que se comunica por JSON con cada lenguaje Utiliza un modelo de ejecución de dos partes cuando los lenguajes anfitriones no puedan ejecutar directamente el lenguaje de implementación. El proceso anfitrión se comunica con un proceso del núcleo mediante mensajes JSON por la entrada y la salida estándar, mientras que toda la ejecución del lenguaje de implementación permanece en el núcleo. ### Límite entre procesos - Asigna a cada solicitud un discriminador de operación explícito. - Cubre la carga de ensamblados, el ciclo de vida de los objetos, las llamadas a métodos, el acceso a propiedades, el trabajo asíncrono, las estadísticas y las llamadas de retorno con operaciones de protocolo distintas. - Utiliza un proceso envoltorio adicional solo cuando un entorno de ejecución anfitrión no pueda conservar los descriptores de archivo requeridos por el proceso principal. - Mantén la salida de diagnóstico en el flujo de errores para que no pueda corromper el flujo del protocolo. ### Secuencia de llamada de retorno Cuando el código del lenguaje de implementación alcanza un método o una propiedad sobrescritos por el lenguaje anfitrión: 1. El núcleo envía una solicitud de llamada de retorno en lugar de la respuesta original. 2. El anfitrión ejecuta la sobrescritura y devuelve un mensaje de finalización con el resultado o el fallo. 3. El núcleo reanuda la operación original y devuelve su respuesta real. ### Evolución del protocolo - Trata los nombres de las solicitudes, el significado de los campos, el orden de las respuestas y la secuencia de las llamadas de retorno como contratos de compatibilidad. - Actualiza conjuntamente todos los entornos de ejecución anfitriones cuando cambie el protocolo. - Añade pruebas de compatibilidad antes de cambiar la estructura de un mensaje o una regla del ciclo de vida. ## Decidir si los valores pasan entre lenguajes por copia o por referencia Define una representación de intercambio para cada categoría de valor portátil y haz visible la semántica de propiedad. Un valor que se transmite por copia no debe confundirse con un objeto cuya propiedad conserva el núcleo. ### Representación de intercambio - Envía booleanos, números y cadenas por valor mediante su representación JSON. - Envía listas y mapas por valor, con un envoltorio etiquetado explícito cuando sea necesario distinguirlos de otros objetos. - Codifica las enumeraciones con un identificador de miembro completamente cualificado. - Codifica las fechas con una representación de marca temporal etiquetada e inequívoca. - Codifica las estructuras que solo contienen datos con su tipo completamente cualificado y los datos de sus campos. - Codifica las instancias de clases por referencia mediante un identificador de objeto estable. ### Reglas de los límites - Preserva las cadenas UTF-8, el comportamiento de coma flotante, la nulabilidad y la semántica de copia de las colecciones entre lenguajes. - Mantén estables las claves etiquetadas de intercambio una vez que los consumidores dependan de ellas. - Libera explícitamente las referencias a objetos cuando el protocolo gestione el ciclo de vida remoto. - Prueba los recorridos de ida y vuelta a través de cada entorno de ejecución anfitrión, no solo desde el lado del lenguaje de implementación. ## Exportar solo tipos que todos los lenguajes puedan representar Aplica las restricciones de portabilidad a las declaraciones exportadas desde el punto de entrada principal del módulo, pero permite que el código interno de implementación utilice características más amplias del lenguaje. ### Superficie de API portátil - Admite tipos primitivos, listas, mapas, enumeraciones, fechas, clases, interfaces, estructuras de datos, promesas y valores opacos solo cuando todos los destinos dispongan de una representación sólida. - Distingue las interfaces de comportamiento de las estructuras que solo contienen datos mediante una regla explícita de nombres o de esquema. - Exige que las estructuras que solo contienen datos tengan propiedades de solo lectura y ningún método. - Permite promesas únicamente en posiciones que todos los destinos puedan exponer de forma coherente, como los tipos de retorno de los métodos. - Trata los valores opacos como implícitamente anulables cuando los destinos con tipado estático no puedan recuperar un tipo más preciso. - Pasa las clases por referencia y las estructuras similares a valores por copia. ### Restricciones - Rechaza construcciones exportadas no compatibles, como tuplas, tipos no habitados, enteros de precisión arbitraria, símbolos y sobrecargas de métodos. - Exige que los métodos sobrescritos mantengan firmas exactamente compatibles; no dependas de retornos covariantes ni de parámetros contravariantes. - Evita las uniones cuando se reduzcan a un objeto sin tipo en destinos con tipado estático. - No permitas que las interfaces de comportamiento y las estructuras que solo contienen datos hereden unas de otras. ## Generar el paquete de cada lenguaje desde el mismo ensamblado compilado Genera cada destino a partir del mismo ensamblado compilado para que los paquetes de destino compartan una única fuente de verdad de la API. ### Canalización de generación 1. Lee el ensamblado del paquete compilado del lenguaje de implementación. 2. Genera código fuente idiomático para el lenguaje de destino seleccionado. 3. Compila el código generado con la cadena de herramientas de ese lenguaje. 4. Empaqueta el resultado con el gestor de paquetes estándar del ecosistema de destino. ### Diseño de los destinos - Proporciona a cada lenguaje de destino su propio adaptador, construido sobre una abstracción compartida de recorrido. - Utiliza un destino maduro como referencia al añadir uno nuevo, pero conserva los modismos del nuevo lenguaje. - Incluye el artefacto de implementación original solo cuando la arquitectura de ejecución lo requiera. - Incluye los metadatos del ensamblado que necesiten las herramientas posteriores de reflexión o generación. - Comparte entre los destinos las utilidades de formato, sangría, creación de archivos y bloques de código. - Actualiza las instantáneas del código generado cada vez que cambie un destino. ## Compilar y probar en el monorepo con las versiones fijas de las herramientas Ejecuta la instalación, las compilaciones, las pruebas, el análisis estático, las actualizaciones de instantáneas y la generación de informes de conformidad mediante la cadena de herramientas fijada del espacio de trabajo del repositorio. ### Entorno y alcance - Comienza en la raíz del repositorio para realizar la preparación completa y la validación de todo el repositorio. - Ejecuta los scripts limitados a un paquete desde el directorio de ese paquete para realizar iteraciones específicas. - Respeta las versiones declaradas del gestor de paquetes y de las herramientas de orquestación. - Limita la concurrencia de compilación cuando las dependencias entre paquetes hagan insegura la ejecución paralela. ### Flujo de cambios - Identifica el paquete responsable del cambio antes de editar o ejecutar comandos. - Compila y prueba primero el paquete específico y luego ejecuta una validación más amplia de los contratos compartidos. - Edita el código fuente en lugar de los artefactos empaquetados generados y vuelve a compilar mediante la canalización designada. - Mantén en local las anulaciones temporales del entorno de ejecución y la configuración del depurador. - Actualiza las instantáneas solo después de confirmar que el cambio generado es intencionado. ## Probar con snapshots y un conjunto común de pruebas que todos los lenguajes deben pasar Combina pruebas rápidas a nivel de paquete con comprobaciones de regresión de la salida generada y una suite de conformidad entre lenguajes. ### Capas de validación - Utiliza pruebas unitarias para la lógica de los paquetes y los casos extremos del protocolo. - Utiliza instantáneas para detectar cambios no intencionados en el código fuente generado. - Utiliza fixtures compartidos que ejerciten clases, interfaces, estructuras de datos, enumeraciones, colecciones, llamadas asíncronas y sobrescrituras. - Utiliza pruebas de conformidad para verificar un comportamiento equivalente en cada enlace de lenguaje. ### Fixtures e informes - Compila los fixtures compartidos con el mismo compilador que utilizan los consumidores reales. - Actualiza todas las instantáneas afectadas de los generadores, la reflexión y el entorno de ejecución cuando cambien los fixtures. - Define cada caso de conformidad una sola vez y exige que cada enlace de lenguaje lo implemente o lo clasifique explícitamente. - Regenera e incluye en un commit el informe de conformidad cada vez que cambien los casos o los resultados. - Haz que la validación falle cuando un enlace añada un caso ausente de la definición de la suite o cuando el informe esté desactualizado. ## Publicar cambios con snapshots e informes al día, sin forzar el push Trata el código generado, los formatos de protocolo, las bibliotecas de ejecución y los informes como superficies de publicación coordinadas. ### Restricciones no negociables - No debilites las restricciones de tipos exportados sin validación en todos los destinos. - No cambies las operaciones del protocolo ni los formatos de serialización etiquetados sin actualizar de forma coordinada los entornos de ejecución anfitriones. - No cambies los patrones de generación sin actualizar y revisar las instantáneas. - No presupongas seguridad de hilos cuando las bibliotecas de ejecución estén diseñadas deliberadamente para un único hilo. - No introduzcas dependencias circulares entre paquetes cuando el grafo de compilación rechace los ciclos. - No modifiques directamente la salida empaquetada. ### Solicitud de incorporación y traspaso - Utiliza el formato de título, las convenciones de alcance y la confirmación de licencia de contribución requeridos por el repositorio. - Incluye todas las instantáneas generadas y los informes de conformidad requeridos por el cambio en el código fuente. - Mantén fuera del cambio los archivos generados no relacionados, los cambios del archivo de bloqueo y la configuración local. - Si la rama remota ha avanzado, recupera los cambios y haz rebase o merge, resuelve los conflictos, valida y sube con normalidad; nunca hagas force-push. - Registra la sincronización de repositorios dependientes o de documentación en la lista de comprobación de la publicación, en lugar de confiar en la memoria.