nexora-lang 0.10.0__tar.gz
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.
- nexora_lang-0.10.0/CHANGELOG.md +913 -0
- nexora_lang-0.10.0/CODE_OF_CONDUCT.md +51 -0
- nexora_lang-0.10.0/CONTRIBUTING.md +210 -0
- nexora_lang-0.10.0/LICENSE +21 -0
- nexora_lang-0.10.0/MANIFEST.in +6 -0
- nexora_lang-0.10.0/PKG-INFO +314 -0
- nexora_lang-0.10.0/README.md +287 -0
- nexora_lang-0.10.0/SECURITY.md +99 -0
- nexora_lang-0.10.0/docs/ai-context.md +918 -0
- nexora_lang-0.10.0/docs/ai-tooling.md +405 -0
- nexora_lang-0.10.0/docs/architecture.md +218 -0
- nexora_lang-0.10.0/docs/cli-reference.md +286 -0
- nexora_lang-0.10.0/docs/contracts.md +468 -0
- nexora_lang-0.10.0/docs/decisions/0001-tipos-estaticos-sin-conversiones-implicitas.md +57 -0
- nexora_lang-0.10.0/docs/decisions/0002-el-interprete-solo-ejecuta-programas-comprobados.md +47 -0
- nexora_lang-0.10.0/docs/decisions/0003-funciones-retorno-e-if.md +54 -0
- nexora_lang-0.10.0/docs/decisions/0004-contratos-en-ejecucion.md +56 -0
- nexora_lang-0.10.0/docs/decisions/0005-diagnosticos-y-esquemas-json.md +49 -0
- nexora_lang-0.10.0/docs/decisions/0006-requisitos-verificables.md +212 -0
- nexora_lang-0.10.0/docs/decisions/0007-contratos-estables-y-tipos-refinados.md +125 -0
- nexora_lang-0.10.0/docs/decisions/0008-ejemplos-y-nex-test.md +872 -0
- nexora_lang-0.10.0/docs/decisions/0009-memoria-agotada.md +312 -0
- nexora_lang-0.10.0/docs/decisions/0010-var-y-while.md +376 -0
- nexora_lang-0.10.0/docs/decisions/0011-operaciones-sobre-textos.md +825 -0
- nexora_lang-0.10.0/docs/decisions/0012-modelo-de-tipos-patrones-iteracion-y-verificabilidad.md +1100 -0
- nexora_lang-0.10.0/docs/decisions/0013-listas-y-for.md +314 -0
- nexora_lang-0.10.0/docs/decisions/0014-registros-nominales-inmutables.md +467 -0
- nexora_lang-0.10.0/docs/decisions/0015-entrada-argumentos-archivos-y-permisos.md +306 -0
- nexora_lang-0.10.0/docs/decisions/0016-option-y-result.md +202 -0
- nexora_lang-0.10.0/docs/decisions/README.md +36 -0
- nexora_lang-0.10.0/docs/diagnostics.md +272 -0
- nexora_lang-0.10.0/docs/functions.md +379 -0
- nexora_lang-0.10.0/docs/getting-started.md +364 -0
- nexora_lang-0.10.0/docs/index.md +61 -0
- nexora_lang-0.10.0/docs/inspect-schema.md +217 -0
- nexora_lang-0.10.0/docs/installation.md +194 -0
- nexora_lang-0.10.0/docs/json-protocol.md +248 -0
- nexora_lang-0.10.0/docs/language-spec.md +1962 -0
- nexora_lang-0.10.0/docs/limitations.md +154 -0
- nexora_lang-0.10.0/docs/lsp.md +74 -0
- nexora_lang-0.10.0/docs/mcp.md +242 -0
- nexora_lang-0.10.0/docs/playground.md +906 -0
- nexora_lang-0.10.0/docs/roadmap.md +134 -0
- nexora_lang-0.10.0/docs/schemas/nexora-capabilities.schema.json +176 -0
- nexora_lang-0.10.0/docs/schemas/nexora-context.schema.json +646 -0
- nexora_lang-0.10.0/docs/schemas/nexora-diagnostics.schema.json +158 -0
- nexora_lang-0.10.0/docs/schemas/nexora-inspect.schema.json +2105 -0
- nexora_lang-0.10.0/docs/schemas/nexora-result.schema.json +174 -0
- nexora_lang-0.10.0/docs/schemas/nexora-spec.schema.json +90 -0
- nexora_lang-0.10.0/docs/schemas/nexora-symbols.schema.json +372 -0
- nexora_lang-0.10.0/docs/schemas/nexora-test.schema.json +380 -0
- nexora_lang-0.10.0/docs/testing.md +770 -0
- nexora_lang-0.10.0/docs/types.md +657 -0
- nexora_lang-0.10.0/examples/README.md +61 -0
- nexora_lang-0.10.0/examples/arithmetic.nex +37 -0
- nexora_lang-0.10.0/examples/checked_examples.nex +26 -0
- nexora_lang-0.10.0/examples/console.nex +24 -0
- nexora_lang-0.10.0/examples/contracts.nex +34 -0
- nexora_lang-0.10.0/examples/failing/contract_violation.nex +18 -0
- nexora_lang-0.10.0/examples/failing/loop_measure.nex +22 -0
- nexora_lang-0.10.0/examples/failing/parse_number.nex +12 -0
- nexora_lang-0.10.0/examples/failing/refinement_violation.nex +16 -0
- nexora_lang-0.10.0/examples/failing/runtime_error.nex +10 -0
- nexora_lang-0.10.0/examples/files.nex +20 -0
- nexora_lang-0.10.0/examples/functions.nex +68 -0
- nexora_lang-0.10.0/examples/hello.nex +5 -0
- nexora_lang-0.10.0/examples/invalid/name_errors.nex +24 -0
- nexora_lang-0.10.0/examples/invalid/refinement_errors.nex +23 -0
- nexora_lang-0.10.0/examples/invalid/syntax_error.nex +16 -0
- nexora_lang-0.10.0/examples/invalid/type_errors.nex +26 -0
- nexora_lang-0.10.0/examples/lists.nex +53 -0
- nexora_lang-0.10.0/examples/loops.nex +61 -0
- nexora_lang-0.10.0/examples/option_result.nex +57 -0
- nexora_lang-0.10.0/examples/records.nex +54 -0
- nexora_lang-0.10.0/examples/refined_types.nex +36 -0
- nexora_lang-0.10.0/examples/texts.nex +63 -0
- nexora_lang-0.10.0/examples/types.nex +40 -0
- nexora_lang-0.10.0/examples/variables.nex +42 -0
- nexora_lang-0.10.0/pyproject.toml +77 -0
- nexora_lang-0.10.0/setup.cfg +4 -0
- nexora_lang-0.10.0/src/nexora/__init__.py +5 -0
- nexora_lang-0.10.0/src/nexora/__main__.py +5 -0
- nexora_lang-0.10.0/src/nexora/api.py +333 -0
- nexora_lang-0.10.0/src/nexora/ast_nodes.py +361 -0
- nexora_lang-0.10.0/src/nexora/capabilities.py +189 -0
- nexora_lang-0.10.0/src/nexora/checker.py +2174 -0
- nexora_lang-0.10.0/src/nexora/cli.py +475 -0
- nexora_lang-0.10.0/src/nexora/diagnostics.py +229 -0
- nexora_lang-0.10.0/src/nexora/host.py +93 -0
- nexora_lang-0.10.0/src/nexora/interpreter.py +887 -0
- nexora_lang-0.10.0/src/nexora/lexer.py +280 -0
- nexora_lang-0.10.0/src/nexora/mcp_server.py +170 -0
- nexora_lang-0.10.0/src/nexora/parser.py +1026 -0
- nexora_lang-0.10.0/src/nexora/pipeline.py +73 -0
- nexora_lang-0.10.0/src/nexora/prelude.py +185 -0
- nexora_lang-0.10.0/src/nexora/schemas.py +482 -0
- nexora_lang-0.10.0/src/nexora/tokens.py +127 -0
- nexora_lang-0.10.0/src/nexora/tooling.py +697 -0
- nexora_lang-0.10.0/src/nexora/type_adapter.py +281 -0
- nexora_lang-0.10.0/src/nexora/types.py +467 -0
- nexora_lang-0.10.0/src/nexora/values.py +113 -0
- nexora_lang-0.10.0/src/nexora/version.py +3 -0
- nexora_lang-0.10.0/src/nexora/worker.py +144 -0
- nexora_lang-0.10.0/src/nexora_lang.egg-info/PKG-INFO +314 -0
- nexora_lang-0.10.0/src/nexora_lang.egg-info/SOURCES.txt +238 -0
- nexora_lang-0.10.0/src/nexora_lang.egg-info/dependency_links.txt +1 -0
- nexora_lang-0.10.0/src/nexora_lang.egg-info/entry_points.txt +3 -0
- nexora_lang-0.10.0/src/nexora_lang.egg-info/requires.txt +10 -0
- nexora_lang-0.10.0/src/nexora_lang.egg-info/top_level.txt +1 -0
- nexora_lang-0.10.0/tests/golden/examples/arithmetic.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/arithmetic.run.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/arithmetic.run.stdout +17 -0
- nexora_lang-0.10.0/tests/golden/examples/checked_examples.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/checked_examples.run.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/checked_examples.run.stdout +1 -0
- nexora_lang-0.10.0/tests/golden/examples/checked_examples.test.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/checked_examples.test.stdout +4 -0
- nexora_lang-0.10.0/tests/golden/examples/console.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/console.run.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/console.run.stdout +1 -0
- nexora_lang-0.10.0/tests/golden/examples/contracts.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/contracts.run.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/contracts.run.stdout +3 -0
- nexora_lang-0.10.0/tests/golden/examples/failing__contract_violation.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/failing__contract_violation.run.stderr +10 -0
- nexora_lang-0.10.0/tests/golden/examples/failing__contract_violation.run.stdout +1 -0
- nexora_lang-0.10.0/tests/golden/examples/failing__loop_measure.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/failing__loop_measure.run.stderr +12 -0
- nexora_lang-0.10.0/tests/golden/examples/failing__loop_measure.run.stdout +0 -0
- nexora_lang-0.10.0/tests/golden/examples/failing__parse_number.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/failing__parse_number.run.stderr +12 -0
- nexora_lang-0.10.0/tests/golden/examples/failing__parse_number.run.stdout +1 -0
- nexora_lang-0.10.0/tests/golden/examples/failing__refinement_violation.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/failing__refinement_violation.run.stderr +11 -0
- nexora_lang-0.10.0/tests/golden/examples/failing__refinement_violation.run.stdout +1 -0
- nexora_lang-0.10.0/tests/golden/examples/failing__runtime_error.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/failing__runtime_error.run.stderr +7 -0
- nexora_lang-0.10.0/tests/golden/examples/failing__runtime_error.run.stdout +1 -0
- nexora_lang-0.10.0/tests/golden/examples/files.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/files.run.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/files.run.stdout +3 -0
- nexora_lang-0.10.0/tests/golden/examples/functions.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/functions.run.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/functions.run.stdout +9 -0
- nexora_lang-0.10.0/tests/golden/examples/hello.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/hello.run.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/hello.run.stdout +1 -0
- nexora_lang-0.10.0/tests/golden/examples/invalid__name_errors.check.stderr +65 -0
- nexora_lang-0.10.0/tests/golden/examples/invalid__name_errors.run.stderr +65 -0
- nexora_lang-0.10.0/tests/golden/examples/invalid__name_errors.run.stdout +0 -0
- nexora_lang-0.10.0/tests/golden/examples/invalid__refinement_errors.check.stderr +47 -0
- nexora_lang-0.10.0/tests/golden/examples/invalid__refinement_errors.run.stderr +47 -0
- nexora_lang-0.10.0/tests/golden/examples/invalid__refinement_errors.run.stdout +0 -0
- nexora_lang-0.10.0/tests/golden/examples/invalid__syntax_error.check.stderr +41 -0
- nexora_lang-0.10.0/tests/golden/examples/invalid__syntax_error.run.stderr +41 -0
- nexora_lang-0.10.0/tests/golden/examples/invalid__syntax_error.run.stdout +0 -0
- nexora_lang-0.10.0/tests/golden/examples/invalid__type_errors.check.stderr +79 -0
- nexora_lang-0.10.0/tests/golden/examples/invalid__type_errors.run.stderr +79 -0
- nexora_lang-0.10.0/tests/golden/examples/invalid__type_errors.run.stdout +0 -0
- nexora_lang-0.10.0/tests/golden/examples/lists.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/lists.run.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/lists.run.stdout +12 -0
- nexora_lang-0.10.0/tests/golden/examples/loops.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/loops.run.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/loops.run.stdout +7 -0
- nexora_lang-0.10.0/tests/golden/examples/loops.test.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/loops.test.stdout +5 -0
- nexora_lang-0.10.0/tests/golden/examples/option_result.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/option_result.run.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/option_result.run.stdout +14 -0
- nexora_lang-0.10.0/tests/golden/examples/records.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/records.run.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/records.run.stdout +11 -0
- nexora_lang-0.10.0/tests/golden/examples/refined_types.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/refined_types.run.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/refined_types.run.stdout +3 -0
- nexora_lang-0.10.0/tests/golden/examples/texts.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/texts.run.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/texts.run.stdout +14 -0
- nexora_lang-0.10.0/tests/golden/examples/texts.test.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/texts.test.stdout +4 -0
- nexora_lang-0.10.0/tests/golden/examples/types.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/types.run.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/types.run.stdout +14 -0
- nexora_lang-0.10.0/tests/golden/examples/variables.check.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/variables.run.stderr +0 -0
- nexora_lang-0.10.0/tests/golden/examples/variables.run.stdout +15 -0
- nexora_lang-0.10.0/tests/golden/schemas/nexora-inspect-0.3.1.schema.json +1160 -0
- nexora_lang-0.10.0/tests/golden/schemas/nexora-inspect-0.4.0.schema.json +1226 -0
- nexora_lang-0.10.0/tests/golden/schemas/nexora-inspect-0.5.1.schema.json +1418 -0
- nexora_lang-0.10.0/tests/helpers.py +85 -0
- nexora_lang-0.10.0/tests/test_api.py +203 -0
- nexora_lang-0.10.0/tests/test_checker.py +190 -0
- nexora_lang-0.10.0/tests/test_cli.py +643 -0
- nexora_lang-0.10.0/tests/test_contracts.py +289 -0
- nexora_lang-0.10.0/tests/test_diagnostics.py +133 -0
- nexora_lang-0.10.0/tests/test_docs.py +311 -0
- nexora_lang-0.10.0/tests/test_example_clauses.py +298 -0
- nexora_lang-0.10.0/tests/test_examples.py +178 -0
- nexora_lang-0.10.0/tests/test_for.py +266 -0
- nexora_lang-0.10.0/tests/test_functions.py +314 -0
- nexora_lang-0.10.0/tests/test_input_arguments.py +94 -0
- nexora_lang-0.10.0/tests/test_input_stdin.py +121 -0
- nexora_lang-0.10.0/tests/test_inspect.py +206 -0
- nexora_lang-0.10.0/tests/test_interpreter.py +152 -0
- nexora_lang-0.10.0/tests/test_lexer.py +207 -0
- nexora_lang-0.10.0/tests/test_loops.py +555 -0
- nexora_lang-0.10.0/tests/test_mcp.py +244 -0
- nexora_lang-0.10.0/tests/test_nex_test.py +509 -0
- nexora_lang-0.10.0/tests/test_option_result.py +388 -0
- nexora_lang-0.10.0/tests/test_out_of_memory.py +298 -0
- nexora_lang-0.10.0/tests/test_parser.py +264 -0
- nexora_lang-0.10.0/tests/test_permissions_environments.py +126 -0
- nexora_lang-0.10.0/tests/test_permissions_files.py +314 -0
- nexora_lang-0.10.0/tests/test_permissions_static.py +88 -0
- nexora_lang-0.10.0/tests/test_records_diagnostics.py +97 -0
- nexora_lang-0.10.0/tests/test_records_syntax.py +170 -0
- nexora_lang-0.10.0/tests/test_records_tools.py +97 -0
- nexora_lang-0.10.0/tests/test_records_types.py +201 -0
- nexora_lang-0.10.0/tests/test_records_values.py +162 -0
- nexora_lang-0.10.0/tests/test_refined_types.py +408 -0
- nexora_lang-0.10.0/tests/test_robustness.py +237 -0
- nexora_lang-0.10.0/tests/test_security.py +209 -0
- nexora_lang-0.10.0/tests/test_text_operations.py +576 -0
- nexora_lang-0.10.0/tests/test_tooling.py +567 -0
- nexora_lang-0.10.0/tests/test_tooling_tasks.py +48 -0
- nexora_lang-0.10.0/tests/test_type_adapter.py +770 -0
- nexora_lang-0.10.0/tests/test_type_b4.py +389 -0
- nexora_lang-0.10.0/tests/test_type_b5.py +408 -0
- nexora_lang-0.10.0/tests/test_type_b6.py +432 -0
- nexora_lang-0.10.0/tests/test_type_b7.py +510 -0
- nexora_lang-0.10.0/tests/test_type_b8.py +612 -0
- nexora_lang-0.10.0/tests/test_type_lists.py +258 -0
- nexora_lang-0.10.0/tests/test_type_lists_functions.py +254 -0
- nexora_lang-0.10.0/tests/test_type_lists_syntax.py +188 -0
- nexora_lang-0.10.0/tests/test_type_lists_values.py +258 -0
- nexora_lang-0.10.0/tests/test_type_model.py +327 -0
- nexora_lang-0.10.0/tests/test_types.py +244 -0
- nexora_lang-0.10.0/tests/test_worker.py +141 -0
- nexora_lang-0.10.0/tests/tooling_tasks.py +125 -0
|
@@ -0,0 +1,913 @@
|
|
|
1
|
+
# Cambios
|
|
2
|
+
|
|
3
|
+
Registro de los cambios de NEXORA, con la versión más reciente primero.
|
|
4
|
+
|
|
5
|
+
Todas las versiones son anteriores a la 1.0: el lenguaje puede cambiar de forma incompatible
|
|
6
|
+
entre versiones. Cada cambio incompatible se indica aquí y se explica en `docs/decisions/`.
|
|
7
|
+
|
|
8
|
+
Este registro empieza con la versión 0.1.0, la primera que pudo ejecutarse. No hay versiones
|
|
9
|
+
publicadas en ningún repositorio de paquetes: los números identifican estados del código.
|
|
10
|
+
|
|
11
|
+
Cada versión agrupa sus cambios en estas secciones, cuando tienen contenido:
|
|
12
|
+
|
|
13
|
+
| Sección | Qué recoge |
|
|
14
|
+
|---------|------------|
|
|
15
|
+
| Añadido | Funcionalidades nuevas |
|
|
16
|
+
| Corregido | Defectos resueltos |
|
|
17
|
+
| Cambios incompatibles | Lo que puede hacer que un programa o un script existente deje de funcionar, y cómo actualizarlo |
|
|
18
|
+
| Retirado | Lo que deja de existir |
|
|
19
|
+
| Documentación | Cambios relevantes en la documentación |
|
|
20
|
+
| Limitaciones | Restricciones conocidas que conviene tener presentes |
|
|
21
|
+
|
|
22
|
+
## 0.10.0 — Option y Result
|
|
23
|
+
|
|
24
|
+
Estado del repositorio, no una versión publicada: todavía no hay tag ni paquete de esta versión en
|
|
25
|
+
ningún registro. Esta versión implementa la
|
|
26
|
+
[decisión 0016](docs/decisions/0016-option-y-result.md), que da al lenguaje los dos tipos que
|
|
27
|
+
permiten decir que **no hay valor** y que **algo falló**, sin excepciones.
|
|
28
|
+
|
|
29
|
+
### Añadido
|
|
30
|
+
|
|
31
|
+
- **`Option[T]`**, con sus dos variantes: `Some(valor)` y `None`. `Option.is_some` y
|
|
32
|
+
`Option.is_none` dicen cuál es; `Option.unwrap_or` devuelve el valor o un defecto del mismo tipo, y
|
|
33
|
+
`Option.unwrap` lo lee sin defecto, con el diagnóstico `E3011` si no lo hay.
|
|
34
|
+
- **`Result[T, E]`**, con `Ok(valor)` y `Err(error)`. `Result.is_ok` y `Result.is_err` dicen cuál es;
|
|
35
|
+
`Result.unwrap_or` devuelve el valor o un defecto, y `Result.unwrap` y `Result.error` lo leen sin
|
|
36
|
+
defecto, con los diagnósticos `E3012` y `E3013` cuando la variante no lo lleva. **El error se
|
|
37
|
+
guarda tal cual**: `Err("falta el archivo")` sigue siendo ese texto al leerlo.
|
|
38
|
+
- **Los tipos `Option[T]` y `Result[T, E]` se pueden escribir**, y anidarse: `Option[Option[Int]]`,
|
|
39
|
+
`Result[Text, Error]`.
|
|
40
|
+
- **Un ejemplo nuevo**, `examples/option_result.nex`, con una búsqueda opcional y un análisis que
|
|
41
|
+
puede fallar.
|
|
42
|
+
|
|
43
|
+
### Cambios incompatibles
|
|
44
|
+
|
|
45
|
+
- Los nombres `Option`, `Result`, `Some`, `Ok` y `Err` pasan a estar en el lenguaje. Un programa que
|
|
46
|
+
declarara una función con uno de esos nombres usaría la integrada, como ya pasaba con `print` o
|
|
47
|
+
`to_text`. `None` es el caso contrario: si el programa declara un nombre así, el suyo gana.
|
|
48
|
+
- Los tipos con argumentos escribibles pasan de ser solo `List[T]` a ser también `Option[T]` y
|
|
49
|
+
`Result[T, E]`.
|
|
50
|
+
- La especificación pasa a la versión 0.10 y la implementación de referencia a la 0.10.0. La 0.9.0 ya
|
|
51
|
+
publicada en npm no se toca.
|
|
52
|
+
|
|
53
|
+
### Documentación
|
|
54
|
+
|
|
55
|
+
- La especificación describe los dos tipos en la sección 4.7 y sus funciones en la 8.4.
|
|
56
|
+
- `docs/types.md` tiene una sección nueva con los dos tipos, cuándo usar cada uno y lo que no hay.
|
|
57
|
+
- Nueva [ADR 0016](docs/decisions/0016-option-y-result.md), que explica la decisión y por qué la
|
|
58
|
+
propagación `?` no se implementa ahora.
|
|
59
|
+
|
|
60
|
+
### Limitaciones
|
|
61
|
+
|
|
62
|
+
- No hay `match`, ni `if let`, ni el operador `?`: las variantes se reconocen con funciones y el
|
|
63
|
+
valor se lee con `unwrap_or` cuando se sabe cuál es. La 0012 sigue siendo propuesta en los enums
|
|
64
|
+
del usuario y el `match`.
|
|
65
|
+
- El tipo de un `None`, de un `Ok` o de un `Err` escrito directamente en una comparación no se
|
|
66
|
+
deduce: hay que escribir antes el tipo del resultado en una variable.
|
|
67
|
+
|
|
68
|
+
## 0.9.0 — Entrada, argumentos, archivos y permisos
|
|
69
|
+
|
|
70
|
+
Estado del repositorio, no una versión publicada: no hay tag ni paquete en ningún repositorio. Esta
|
|
71
|
+
versión implementa la [decisión 0015](docs/decisions/0015-entrada-argumentos-archivos-y-permisos.md),
|
|
72
|
+
que describe la entrada de un programa, sus argumentos y el acceso a los archivos con permisos
|
|
73
|
+
explícitos. La [0012](docs/decisions/0012-modelo-de-tipos-patrones-iteracion-y-verificabilidad.md) no se
|
|
74
|
+
reescribe: su parte de entrada (D11) y su sistema de efectos siguen siendo propuesta, y esta
|
|
75
|
+
versión decide otra forma de hacer lo mismo.
|
|
76
|
+
|
|
77
|
+
### Añadido
|
|
78
|
+
|
|
79
|
+
- **Los argumentos del programa**: `args() -> List[Text]` devuelve los argumentos con los que se
|
|
80
|
+
ejecutó, escritos tras `--`: `nex run programa.nex -- uno dos`. No necesitan ninguna declaración.
|
|
81
|
+
- **La entrada estándar**: `input() -> Text` lee una línea, sin el final de línea. Cuando ya no
|
|
82
|
+
queda nada que leer, el programa se detiene con `E3009`. No necesita ninguna declaración.
|
|
83
|
+
- **Los archivos**: `read_file(ruta)` y `write_file(ruta, texto)`. Un programa declara lo que
|
|
84
|
+
necesita con `uses read "ruta"` o `uses write "ruta"`, y quien lo ejecuta tiene que permitirlo
|
|
85
|
+
con `--allow-read=RUTA` o `--allow-write=RUTA`.
|
|
86
|
+
- **El modelo de permisos**: la capacidad efectiva es la intersección de lo que declara el
|
|
87
|
+
programa, lo que concede quien lo ejecuta y lo que permite el entorno. Declarar no concede,
|
|
88
|
+
conceder no habilita, y el entorno manda. Las rutas se confinan sobre la ruta resuelta: un `..` o
|
|
89
|
+
un enlace simbólico que salen del ámbito concedido no sirven de nada.
|
|
90
|
+
- **Herramientas**: `nexora.context/1` añade el campo `capabilities`, con lo que el programa
|
|
91
|
+
declara; `nexora.inspect/2` añade el nodo `UsesDecl` y el campo `uses` en `Program`. Los números
|
|
92
|
+
de los formatos no cambian.
|
|
93
|
+
|
|
94
|
+
### Cambiado
|
|
95
|
+
|
|
96
|
+
- Solo en programas que ya eran inválidos: `uses` pasa de palabra reservada a palabra clave, y
|
|
97
|
+
`read`, `write`, `args`, `input`, `read_file` y `write_file` pasan a ser nombres predefinidos.
|
|
98
|
+
- La versión del repositorio pasa a `0.9.0` y la especificación a `0.9`. Los esquemas JSON no
|
|
99
|
+
cambian de versión: los campos y nodos nuevos son aditivos.
|
|
100
|
+
|
|
101
|
+
### Documentación
|
|
102
|
+
|
|
103
|
+
- La [especificación](docs/language-spec.md) pasa a la versión 0.9 y documenta la entrada, los
|
|
104
|
+
argumentos y los archivos (sección 8.3), con la gramática, los permisos y las rutas.
|
|
105
|
+
- Nuevo [ADR 0015](docs/decisions/0015-entrada-argumentos-archivos-y-permisos.md).
|
|
106
|
+
- Actualizados `diagnostics.md`, `limitations.md`, `cli-reference.md`, `playground.md`,
|
|
107
|
+
`architecture.md`, `roadmap.md`, `types.md`, `json-protocol.md`, `inspect-schema.md` y `README.md`.
|
|
108
|
+
|
|
109
|
+
### Limitaciones
|
|
110
|
+
|
|
111
|
+
- No se puede leer «hasta el final» de la entrada estándar sin parar: `input()` falla con `E3009`.
|
|
112
|
+
- Solo se leen y escriben archivos de texto: no hay directorios, ni binarios, ni renombrar, ni
|
|
113
|
+
borrar.
|
|
114
|
+
- No hay red, ni procesos externos, ni variables de entorno.
|
|
115
|
+
- El playground y el servidor MCP no admiten archivos: el worker no tiene ningún campo en su
|
|
116
|
+
protocolo para concederlos.
|
|
117
|
+
|
|
118
|
+
## 0.8.0 — Registros nominales inmutables
|
|
119
|
+
|
|
120
|
+
Estado del repositorio, no una versión publicada: no hay tag ni paquete en ningún repositorio. Esta
|
|
121
|
+
versión implementa la [decisión 0014](docs/decisions/0014-registros-nominales-inmutables.md), que
|
|
122
|
+
acepta la parte de D02 (registros nominales frente a estructurales) de la propuesta
|
|
123
|
+
[0012](docs/decisions/0012-modelo-de-tipos-patrones-iteracion-y-verificabilidad.md) en el alcance
|
|
124
|
+
realmente implementado. El resto de la 0012 sigue siendo una propuesta y no forma parte de esta
|
|
125
|
+
versión.
|
|
126
|
+
|
|
127
|
+
### Añadido
|
|
128
|
+
|
|
129
|
+
- **Registros**: un tipo que declara el programa, con campos inmutables y obligatorios:
|
|
130
|
+
`type Point = { x: Int, y: Int }`. Se construyen con los campos por nombre
|
|
131
|
+
(`Point(x: 1, y: 2)`, en cualquier orden) y sus campos se leen con `p.x`, también en cadena
|
|
132
|
+
(`p.x.y`). Un registro es **nominal**: su identidad es la de su declaración, no la de su nombre
|
|
133
|
+
ni la de sus campos, así que dos registros con los mismos campos son tipos distintos (`E2011`) y
|
|
134
|
+
dos valores del mismo registro se comparan por valor.
|
|
135
|
+
- **Identidad nominal en el modelo de tipos** (`types.py`): la variante `Nominal` y el token opaco
|
|
136
|
+
`RecordIdentity`, que el comprobador crea una vez por declaración y que viaja en el
|
|
137
|
+
`CheckedProgram` hasta el intérprete. El intérprete no la reconstruye a partir del nombre.
|
|
138
|
+
- **Herramientas**: `nex inspect` añade los nodos `RecordDecl`, `FieldDecl`, `RecordConstruction`,
|
|
139
|
+
`FieldInitializer` y `FieldAccess`, la sentencia `FieldAssign` y el campo `records` al final de
|
|
140
|
+
`Program`; `type` puede ser el nombre de un registro. `nex context` añade el campo `records`
|
|
141
|
+
(con `name`, `fields`, `valid`, `line` y `reason`) y el valor `records` en `features`. `types`
|
|
142
|
+
sigue siendo solo de tipos refinados.
|
|
143
|
+
- **Diagnósticos**: `E2023` (Invalid record construction, `type`), `E2024` (Invalid field access,
|
|
144
|
+
`type`) y `E2025` (Cannot reassign a field, `semantic`).
|
|
145
|
+
- **Ejemplo** [`examples/records.nex`](examples/records.nex), con su salida registrada en las
|
|
146
|
+
pruebas.
|
|
147
|
+
|
|
148
|
+
### Cambiado
|
|
149
|
+
|
|
150
|
+
- Solo en programas que ya eran inválidos: `p.x`, donde `p` es una variable que no es un tipo,
|
|
151
|
+
pasa de ser `E1101` («Expected '(' to call 'p.x'») a ser un acceso a un campo. La forma de
|
|
152
|
+
llamada cualificada no cambia: `Text.length(s)` y `name.length()` se siguen diagnosticando igual,
|
|
153
|
+
y `Point.x` sigue siendo una llamada cualificada, no la lectura de un campo.
|
|
154
|
+
- La versión del repositorio pasa a `0.8.0` y la especificación a `0.8`. Los esquemas JSON no
|
|
155
|
+
cambian de versión: los campos y nodos nuevos son aditivos.
|
|
156
|
+
|
|
157
|
+
### Documentación
|
|
158
|
+
|
|
159
|
+
- La [especificación](docs/language-spec.md) pasa a la versión 0.8 y documenta los registros (4.6),
|
|
160
|
+
su gramática, su igualdad nominal, su impresión, la tabla de diagnósticos y las limitaciones.
|
|
161
|
+
- Actualizados `types.md`, `limitations.md`, `roadmap.md`, `architecture.md`, `index.md`,
|
|
162
|
+
`diagnostics.md`, `inspect-schema.md`, `json-protocol.md` y `README.md`.
|
|
163
|
+
- La [decisión 0014](docs/decisions/0014-registros-nominales-inmutables.md) pasa a aceptada, con su
|
|
164
|
+
implementación. La [0012](docs/decisions/0012-modelo-de-tipos-patrones-iteracion-y-verificabilidad.md)
|
|
165
|
+
no se reescribe y sigue siendo una propuesta para lo no implementado.
|
|
166
|
+
|
|
167
|
+
### Limitaciones
|
|
168
|
+
|
|
169
|
+
- Un registro no tiene métodos, ni funciones propias, ni refinamientos, ni recursión, ni parámetros
|
|
170
|
+
de tipo. Un tipo refinado no puede construirse sobre un registro (`E2016`).
|
|
171
|
+
- Un registro no puede contenerse a sí mismo, ni directamente ni a través de otro registro ni de
|
|
172
|
+
una lista (`E2016`).
|
|
173
|
+
- No hay `Option`, `Result`, enums, `match`, genéricos de usuario ni entrada de datos.
|
|
174
|
+
|
|
175
|
+
## 0.7.0 — Listas y `for` sobre listas
|
|
176
|
+
|
|
177
|
+
Estado del repositorio, no una versión publicada: no hay tag ni paquete en ningún repositorio. Esta
|
|
178
|
+
versión implementa la [decisión 0013](docs/decisions/0013-listas-y-for.md), que acepta, en el alcance
|
|
179
|
+
realmente implementado, las partes D01 (modelo de tipos), D08 (listas) y D09 (`for`) de la propuesta
|
|
180
|
+
[0012](docs/decisions/0012-modelo-de-tipos-patrones-iteracion-y-verificabilidad.md). El resto de la
|
|
181
|
+
0012 sigue siendo una propuesta y no forma parte de esta versión.
|
|
182
|
+
|
|
183
|
+
### Añadido
|
|
184
|
+
|
|
185
|
+
- **Listas inmutables `List[T]`**: literales `[1, 2, 3]` y `[]`, inferencia por el primer elemento,
|
|
186
|
+
homogeneidad, listas anidadas, igualdad estructural e impresión `[1, 2, 3]`. Una lista vacía
|
|
187
|
+
necesita un tipo esperado (`E2011`). Los argumentos de `List` son invariantes y `Void` no puede
|
|
188
|
+
ser elemento.
|
|
189
|
+
- **Funciones de `List`**: `List.length`, `List.get`, `List.append`, `List.concat` y
|
|
190
|
+
`List.contains`. `List.get` es parcial y declara `requires 0 <= i and i < List.length(xs)`; un
|
|
191
|
+
índice fuera de rango detiene el programa con `E4001`. `append` y `concat` construyen listas nuevas.
|
|
192
|
+
- **`for` sobre listas**: `for x in xs { ... }`, con iterador inmutable y de tipo `T`, un entorno
|
|
193
|
+
nuevo por vuelta, `invariant` comprobados antes de cada vuelta y una vez después de la última, y
|
|
194
|
+
sin `decreases` (`E2022`). El iterable se evalúa una vez y debe ser una `List[T]`. Siguen sin
|
|
195
|
+
existir `break` y `continue`.
|
|
196
|
+
- **Modelo de tipos interno** (`types.py` y `type_adapter.py`): representación estructurada de
|
|
197
|
+
primitivos, `List[T]`, tipos refinados y variables de tipo; identidad, compatibilidad, sustitución
|
|
198
|
+
y unificación. La forma canónica de los tipos sigue siendo el texto; la migración del comprobador
|
|
199
|
+
es parcial y las reglas no migradas conservan sus cadenas.
|
|
200
|
+
- **Herramientas**: `nex inspect` añade `arguments` a `TypeRef`, el nodo `ListLiteral` y el nodo
|
|
201
|
+
`For`; `type` puede ser `List[...]`. `nex context` distingue `while` y `for` en `loops.kind`.
|
|
202
|
+
`language_info()` incluye `List` en `types`, para que un editor lo coloree como los demás tipos.
|
|
203
|
+
- **Ejemplo** [`examples/lists.nex`](examples/lists.nex), con su salida registrada en las pruebas.
|
|
204
|
+
|
|
205
|
+
### Cambiado
|
|
206
|
+
|
|
207
|
+
- Solo en programas que ya eran inválidos: `for` e `in` pasan de palabras reservadas a palabras
|
|
208
|
+
clave, y `[` y `]` pasan a ser símbolos. `List` y los nombres de sus funciones no se reservan: las
|
|
209
|
+
funciones se llaman cualificadas (`List.length`).
|
|
210
|
+
- La versión del repositorio pasa a `0.7.0`. Los esquemas JSON no cambian de versión: los campos y
|
|
211
|
+
nodos nuevos son aditivos.
|
|
212
|
+
|
|
213
|
+
### Documentación
|
|
214
|
+
|
|
215
|
+
- La [especificación](docs/language-spec.md) pasa a la versión 0.7 y documenta las listas (4.5), las
|
|
216
|
+
funciones de `List` (8.2), `for` (9.6), la compatibilidad, las conversiones, los diagnósticos y las
|
|
217
|
+
limitaciones.
|
|
218
|
+
- Nuevo [ADR 0013](docs/decisions/0013-listas-y-for.md). La [0012](docs/decisions/0012-modelo-de-tipos-patrones-iteracion-y-verificabilidad.md)
|
|
219
|
+
no se reescribe y sigue siendo una propuesta para lo no implementado.
|
|
220
|
+
- Actualizados `types.md`, `limitations.md`, `roadmap.md`, `architecture.md`, `index.md`,
|
|
221
|
+
`diagnostics.md`, `inspect-schema.md` y `README.md`.
|
|
222
|
+
|
|
223
|
+
### Limitaciones
|
|
224
|
+
|
|
225
|
+
- No hay indexación sintáctica (`xs[i]`), mutación de elementos, `List.set`, `map`, `filter`,
|
|
226
|
+
ordenación ni una variante total de `List.get`.
|
|
227
|
+
- Todos los elementos de una lista tienen el mismo tipo; `[]` y `for x in []` necesitan un tipo
|
|
228
|
+
esperado. No se puede refinar una lista (`E2016`).
|
|
229
|
+
- Un `for` no cuenta como una ruta que siempre devuelve: si es la última sentencia de una función
|
|
230
|
+
que devuelve un valor, hace falta un `return` después.
|
|
231
|
+
- No hay `for` sobre rangos o `Text`, ni genéricos de usuario.
|
|
232
|
+
|
|
233
|
+
## Sin publicar — servidor y web
|
|
234
|
+
|
|
235
|
+
Cambios del servidor web (`servidor/`) y de la web (`web/`) posteriores al tag `v0.6.0`, todavía sin
|
|
236
|
+
versión. No forman parte de la 0.7.0 y no cambian el intérprete: el lenguaje y el paquete
|
|
237
|
+
`nexora-lang` de esta versión están documentados arriba.
|
|
238
|
+
|
|
239
|
+
### Añadido
|
|
240
|
+
|
|
241
|
+
- **Antispam en el registro y el inicio de sesión** (`servidor/src/captcha.js`): Google reCAPTCHA v3,
|
|
242
|
+
un campo trampa y un límite estricto por cliente (5 registros o 15 inicios de sesión por hora) para
|
|
243
|
+
toda petición sin un token que Google confirme. reCAPTCHA solo se carga en el navegador si la
|
|
244
|
+
persona lo acepta en el panel de cookies; sin él se puede entrar igual, con ese límite. La clave
|
|
245
|
+
secreta va en `RECAPTCHA_SECRET_KEY` y la del sitio en `web/js/consent-config.js`; al arrancar, el
|
|
246
|
+
servidor avisa si solo está una de las dos.
|
|
247
|
+
- **Freno del inicio de sesión por cuenta** (`servidor/src/login-throttle.js`): tras 5 fallos desde
|
|
248
|
+
un cliente, ese cliente espera cada vez más, hasta 15 minutos; tras 20 fallos contra una cuenta
|
|
249
|
+
desde cualquier cliente, cada intento espera, como mucho un minuto. Responde igual para un email
|
|
250
|
+
con cuenta y uno sin ella, y reserva cada intento antes de consultar la base de datos.
|
|
251
|
+
- **Límites por cliente con IPv6** (`servidor/src/rate-limits.js`): todos los límites cuentan una
|
|
252
|
+
dirección IPv6 por su bloque /56, y además cada red /48 con cuatro veces el cupo. Las cabeceras
|
|
253
|
+
`RateLimit-*` describen la cuenta que antes se agota, y cada rechazo lleva `Retry-After`.
|
|
254
|
+
- **Borrado de las sesiones caducadas** al arrancar y cada hora, por tandas, sin que dos pasadas se
|
|
255
|
+
solapen (`servidor/src/session-cleanup.js`).
|
|
256
|
+
- **Cabeceras de seguridad en todas las respuestas** (`servidor/src/security-headers.js`): la
|
|
257
|
+
política de contenido (CSP) sin código en línea que tenían el playground y la guía pasa a todas las
|
|
258
|
+
páginas, más `X-Frame-Options`, `Cross-Origin-Opener-Policy`, `Permissions-Policy`,
|
|
259
|
+
`Referrer-Policy` y, en producción y solo por HTTPS, HSTS. La API tiene una política que no carga
|
|
260
|
+
nada.
|
|
261
|
+
- `LISTEN_HOST`: la dirección en la que escucha el servidor. Con nginx en el mismo equipo,
|
|
262
|
+
`LISTEN_HOST=127.0.0.1` y `TRUST_PROXY=loopback`; al arrancar, el servidor avisa si no casan.
|
|
263
|
+
- Web: las tipografías se sirven desde el propio sitio (JetBrains Mono, con su licencia OFL) en vez
|
|
264
|
+
de Google Fonts, y todo el sitio usa JetBrains Mono; un gestor de consentimiento de cookies con
|
|
265
|
+
Google Consent Mode v2; las páginas legales, todavía en borrador (ver Limitaciones); y una
|
|
266
|
+
documentación web ampliada: qué es NEXORA, cómo se prueba y los cambios recientes.
|
|
267
|
+
- `GET /api/playground/status` dice si el playground está activado (`{"enabled": true}` o `false`).
|
|
268
|
+
Responde también con el playground desactivado y no arranca el worker. La página lo pregunta
|
|
269
|
+
primero: desactivado, no pide `/info` ni `/examples`.
|
|
270
|
+
- Las páginas legales llevan `<meta name="robots" content="noindex, nofollow">` mientras sean un
|
|
271
|
+
borrador, y una prueba lo exige. Solo pide a los buscadores que no las indexen: no impide abrirlas
|
|
272
|
+
a quien tenga el enlace.
|
|
273
|
+
- `GET /api/health`: dice si el proceso está en marcha y responde peticiones
|
|
274
|
+
(`{"status":"ok","checks":{"http":"ok"}}`), y nada más: no comprueba MySQL, Google, GitHub,
|
|
275
|
+
reCAPTCHA ni el playground, ni revela la versión o la configuración. Durante el apagado responde 503.
|
|
276
|
+
- **Apagado ordenado** (`servidor/src/lifecycle.js`): con `SIGTERM` o `SIGINT`, el servidor deja de
|
|
277
|
+
aceptar conexiones y responde con `Connection: close`, para que una conexión persistente no lo
|
|
278
|
+
retenga; espera hasta 10 s a las peticiones en curso y a la tanda de borrado de sesiones que esté
|
|
279
|
+
en MySQL (no envía ninguna más); cierra el pool de MySQL (otros 10 s como mucho) y sale con 0, o
|
|
280
|
+
con 1 si tuvo que cortar algo. Si durante el apagado llega la otra
|
|
281
|
+
señal, no se repite; si llega otra vez la misma, Node termina el proceso en el acto, sin esperar.
|
|
282
|
+
El límite de cada espera mantiene vivo el proceso hasta que vence: si lo único pendiente no tiene
|
|
283
|
+
ningún recurso detrás (un cierre del pool que no termina), el proceso ya no sale con 0 antes de
|
|
284
|
+
tiempo sin registrarlo, sino que espera el límite, lo registra y sale con 1. Probado con pruebas
|
|
285
|
+
automatizadas en Windows (Node 20.6.1, 22.23.3 y 24.21.0), sin señales reales: con systemd, sin
|
|
286
|
+
probar.
|
|
287
|
+
- **Pruebas de integración con MySQL, preparadas y nunca ejecutadas** (`servidor/test/integration/`).
|
|
288
|
+
`npm run test:integration` ejecutaría las consultas reales de la aplicación contra una base de pruebas
|
|
289
|
+
aislada (`nexora_test`), con una cuenta para las migraciones y otra para la aplicación, que un
|
|
290
|
+
administrador tendría que crear a mano con `setup-admin.sql` (una propuesta pendiente de revisión).
|
|
291
|
+
No forman parte de `npm test` ni de la integración continua. Antes de cargar nada, unas guardas
|
|
292
|
+
rechazan cualquier otro entorno (variables `DB_*`, otro servidor, el playground activable o permisos
|
|
293
|
+
distintos de los previstos), y un bloqueo con nombre (`GET_LOCK`) impide dos ejecuciones a la vez.
|
|
294
|
+
Las guardas solo admiten Node 22 desde 22.22.3 y Node 24 desde 24.14.0 (`HOOK_MINIMUMS` en
|
|
295
|
+
`servidor/test/integration/guard.js`): son los mínimos medidos en Windows para el gancho de módulos de
|
|
296
|
+
`preflight.js`, no los de `engines` en `servidor/package.json` (`^22.23.2 || ^24.18.1`), y una prueba
|
|
297
|
+
de `npm test` comprueba que todo lo que admite `engines` está dentro. Las demás ramas (23, 25, 26 y
|
|
298
|
+
posteriores) y las versiones que no son exactamente X.Y.Z se rechazan hasta medirlas. En las
|
|
299
|
+
versiones medidas por debajo de esos mínimos, el gancho bloqueó mysql2 también en el orden legítimo;
|
|
300
|
+
la causa no está confirmada. En un Node que las guardas no admiten, `npm test` omite con su motivo las 14 pruebas que lanzan
|
|
301
|
+
`preflight.js`: así ocurrió en la ejecución experimental de Node 26 de la integración continua
|
|
302
|
+
del 21 de octubre de 2026. **Nada de esto se ha ejecutado contra un MySQL
|
|
303
|
+
real**: ni el SQL de administración, ni las migraciones con permisos reducidos, ni el bloqueo.
|
|
304
|
+
|
|
305
|
+
### Cambios incompatibles
|
|
306
|
+
|
|
307
|
+
- **El servidor requiere Node.js 22.23.2 o posterior en la rama 22, o 24.18.1 o posterior en la rama
|
|
308
|
+
24** (`engines` en `servidor/package.json`: `^22.23.2 || ^24.18.1`; antes, 20.6 o posterior). Node 20
|
|
309
|
+
no tiene soporte desde el 30 de abril de 2026, y las mínimas son las últimas versiones de seguridad
|
|
310
|
+
de cada rama en octubre de 2026. Las ramas 23, 25 y 26 quedan fuera. npm solo avisa (`EBADENGINE`)
|
|
311
|
+
con otra versión, no impide instalar. Dentro del rango se han probado en local, en Windows, 22.23.3
|
|
312
|
+
y 24.21.0; los mínimos exactos no. La integración continua del servidor pasa a probar 22.23.2,
|
|
313
|
+
24.18.1, la última de las ramas 22 y 24 y, sin bloquear, Node 26; se ejecutó por primera vez el
|
|
314
|
+
21 de octubre de 2026.
|
|
315
|
+
- **Con `NODE_ENV=production`, `PLAYGROUND_ENABLED=true` exige la orden de contenedor** en
|
|
316
|
+
`PLAYGROUND_WORKER_COMMAND`. Sin ella (o con una orden de proceso), el servidor no arranca: el modo
|
|
317
|
+
de proceso ejecuta el código de los visitantes con los permisos del servidor. Fuera de producción,
|
|
318
|
+
el modo de proceso sigue disponible para probar en un equipo propio. Configurar la orden de
|
|
319
|
+
contenedor no demuestra que el aislamiento funcione: sigue sin comprobarse con Docker real.
|
|
320
|
+
|
|
321
|
+
- **`NODE_ENV` solo admite `development`, `test` o `production`, en minúsculas.** Antes cualquier
|
|
322
|
+
valor distinto de `production` (`Production`, `prod`, vacío) dejaba el servidor en desarrollo, sin
|
|
323
|
+
cookies solo por HTTPS. Ahora esos valores impiden arrancar. Sin definir sigue funcionando como
|
|
324
|
+
desarrollo, y el servidor lo avisa al arrancar.
|
|
325
|
+
- **`TRUST_PROXY` solo admite `0`, `loopback` o un entero de 1 a 10 sin ceros a la izquierda.**
|
|
326
|
+
Antes se leía con `Number()`: `true` o `nginx` daban `NaN` sin ningún aviso. Ahora cualquier otro
|
|
327
|
+
valor impide arrancar. Con nginx en el mismo equipo, se recomienda `loopback` en vez de `1`.
|
|
328
|
+
- `LISTEN_HOST` solo admite una dirección IP o quedar vacía; un nombre, también `localhost`, impide
|
|
329
|
+
arrancar.
|
|
330
|
+
- Con `NODE_ENV=production` y `RECAPTCHA_SECRET_KEY`, falta `RECAPTCHA_HOSTNAMES` impide arrancar.
|
|
331
|
+
`RECAPTCHA_MIN_SCORE` fuera de 0 a 1, o un `RECAPTCHA_HOSTNAMES` que no sea una lista de dominios,
|
|
332
|
+
también.
|
|
333
|
+
- **En producción sin `RECAPTCHA_SECRET_KEY`, todos los registros e inicios de sesión pasan por el
|
|
334
|
+
límite estricto** (5 registros o 15 inicios de sesión por cliente y hora). En desarrollo no cambia
|
|
335
|
+
nada.
|
|
336
|
+
- La API de cuentas tiene respuestas nuevas: `429` con `code: "login_throttled"` y `Retry-After`
|
|
337
|
+
durante el freno del inicio de sesión; `400` con `captcha_invalid` o `captcha_expired`; y `429`
|
|
338
|
+
con `captcha_required` en el límite estricto. Un campo `website` con contenido se rechaza con `400`.
|
|
339
|
+
|
|
340
|
+
- **El playground está desactivado salvo que se active de forma explícita.** Antes se activaba
|
|
341
|
+
siempre que `PLAYGROUND_ENABLED` no fuera exactamente `false`: sin definir, vacía o con una errata
|
|
342
|
+
(`False`, `0`), quedaba abierto. Ahora solo `PLAYGROUND_ENABLED=true` lo activa; sin definir,
|
|
343
|
+
vacía o `false`, la API responde 503 (`playground_disabled`) y no arranca ningún worker. Una
|
|
344
|
+
instalación local que quiera usar el playground tiene que añadir `PLAYGROUND_ENABLED=true` a su
|
|
345
|
+
`servidor/.env`.
|
|
346
|
+
- Cualquier otro valor de `PLAYGROUND_ENABLED` (`True`, `1`, `yes`…) impide arrancar el servidor,
|
|
347
|
+
con un mensaje que pide `"true"` o `"false"`.
|
|
348
|
+
- **La única orden de contenedor que admite `PLAYGROUND_WORKER_COMMAND` es la documentada.** Tiene
|
|
349
|
+
que empezar por `"docker","run"`, llevar exactamente una vez cada opción de aislamiento y de
|
|
350
|
+
límites de `servidor/.env.example` con su valor exacto, entre ellas `"--init"`,
|
|
351
|
+
`"--pull","never"` y `"--name","{container}"`, y terminar en la imagen. Cualquier otra orden de
|
|
352
|
+
contenedor impide arrancar el servidor, aunque el playground esté desactivado, con un mensaje que
|
|
353
|
+
nombra lo que falla. Eso incluye una opción que falte, se repita, tenga otro valor o no esté en la
|
|
354
|
+
lista, como los alias `-m`, `-u`, `--net` o `--interactive`; la forma `--opción=valor`; algo
|
|
355
|
+
después de la imagen; una ruta al ejecutable, `docker.exe`, `sudo`, Podman,
|
|
356
|
+
`docker container run` u opciones globales de Docker. Lo que va después de la imagen no lo aplica
|
|
357
|
+
Docker, sino que lo recibe el programa del contenedor. Con la comprobación anterior, un
|
|
358
|
+
`"--name","{container}"` escrito detrás de la imagen se aceptaba (comprobado con el validador
|
|
359
|
+
anterior) y, según el código, el servidor podía dar por eliminado un contenedor que seguía vivo;
|
|
360
|
+
no se ha observado con Docker real. Para actualizar una configuración existente, copia la orden
|
|
361
|
+
de `servidor/.env.example`. Cambiar un límite exige cambiar el servidor
|
|
362
|
+
(`servidor/src/playground/config.js`), no solo `servidor/.env`.
|
|
363
|
+
- **Solo se ejecuta la imagen local `nexora-worker`, y Docker no la descarga nunca.** La imagen
|
|
364
|
+
tiene que ser `nexora-worker` o `nexora-worker:<etiqueta>`: no se admite otro nombre, una ruta, un
|
|
365
|
+
registro ni un digest. `"--pull","never"` hace que, si la imagen no está en el equipo, la
|
|
366
|
+
ejecución falle en vez de descargarla. Hay que construir la imagen en el servidor antes de
|
|
367
|
+
activar el playground y en cada actualización (ver la
|
|
368
|
+
[guía del playground](docs/playground.md#3-imagen-del-worker)). `--pull` necesita Docker 20.10 o
|
|
369
|
+
posterior.
|
|
370
|
+
- Las órdenes del modo de proceso siguen sin comprobarse, salvo las que contienen `{container}` o
|
|
371
|
+
un ejecutable llamado `docker` o `podman`: esas se tratan como órdenes de contenedor y se
|
|
372
|
+
rechazan si no son la documentada.
|
|
373
|
+
|
|
374
|
+
### Corregido
|
|
375
|
+
|
|
376
|
+
- **Un contenedor que agota el tiempo ya no sigue ejecutándose con su hueco liberado.** Antes, el
|
|
377
|
+
servidor mataba el cliente `docker run`, que no detiene el contenedor, y liberaba el hueco en ese
|
|
378
|
+
momento. Según el código, eso permitía que hubiera más contenedores vivos que
|
|
379
|
+
`PLAYGROUND_MAX_CONCURRENT`; no se ha observado con Docker real, porque el modo contenedor
|
|
380
|
+
todavía no se ha probado. Ahora cada
|
|
381
|
+
contenedor tiene un nombre generado por el servidor; si no termina bien, se elimina por ese
|
|
382
|
+
nombre y el hueco solo se libera cuando se confirma que ya no existe. Los intentos de eliminarlo
|
|
383
|
+
están limitados; si ninguno confirma, el hueco queda ocupado.
|
|
384
|
+
- **El botón Run del playground vuelve a verse en móvil.** A 390 px quedaba cortado y a 320 y 360 px
|
|
385
|
+
no se veía; solo quedaba el atajo Ctrl+Enter. Por debajo de 440 px los cuatro botones van ahora en
|
|
386
|
+
dos filas.
|
|
387
|
+
- **Con el playground desactivado, la página ya no parece lista para ejecutar.** Antes mostraba
|
|
388
|
+
«Real interpreter» con un punto verde y Run y Check activos, y cada carga recibía dos respuestas
|
|
389
|
+
503. Ahora dice «Disabled», Run y Check están desactivados (también sus atajos), la ayuda y el pie
|
|
390
|
+
no dicen que el código se ejecuta, y no envía ninguna petición de ejecución. Mientras espera la
|
|
391
|
+
respuesta del servidor dice «Connecting…». Si el servidor no confirma si está activado (no
|
|
392
|
+
responde o responde algo que la página no entiende), dice «Status unknown» y tampoco deja ejecutar:
|
|
393
|
+
Run y Check solo se activan cuando el servidor lo confirma. «Real interpreter» en verde solo
|
|
394
|
+
aparece si además el intérprete respondió; si no, «Unavailable». Activado, se comporta como antes.
|
|
395
|
+
- El formulario de registro cabe entero, botón incluido, en una pantalla de 1366×768. El inicio de
|
|
396
|
+
sesión ya cabía y no cambia.
|
|
397
|
+
- **El registro es atómico.** Antes se creaba la cuenta y después, aparte, su primera sesión: si la
|
|
398
|
+
sesión no se podía guardar, la cuenta quedaba creada, la persona recibía un error y, al volver a
|
|
399
|
+
intentarlo, un 409. Ahora la cuenta y la sesión se guardan en una sola transacción, la cookie solo
|
|
400
|
+
se envía después de confirmarla, y el resumen de la contraseña se calcula antes de abrirla, para no
|
|
401
|
+
ocupar una conexión del pool durante scrypt. Si además falla el `ROLLBACK`, cuenta el error
|
|
402
|
+
original (un email duplicado sigue respondiendo 409) y esa conexión no vuelve al pool, porque podría
|
|
403
|
+
haber quedado con la transacción abierta: se destruye. El fallo del `ROLLBACK` queda en el registro
|
|
404
|
+
con su tipo y su código (`auth: sign-up rollback failed (Error ER_ERROR_DURING_ROLLBACK)`), sin el
|
|
405
|
+
mensaje ni ningún dato de la petición. Probado con una base de datos simulada; contra MySQL real, la
|
|
406
|
+
prueba está preparada y sin ejecutar.
|
|
407
|
+
- El inicio de sesión con Google o GitHub sigue la misma regla en su transacción: si falla el
|
|
408
|
+
`ROLLBACK`, cuenta el error original (por ejemplo, `account_exists` sigue siendo `account_exists`), la
|
|
409
|
+
conexión se destruye en vez de volver al pool (una sola vez, nunca devuelta y destruida) y queda una
|
|
410
|
+
línea `oauth: <proveedor>: rollback failed (…)` sin datos. Antes, un `ROLLBACK` fallido sustituía al
|
|
411
|
+
error original y la conexión volvía al pool. Probado con una base de datos simulada.
|
|
412
|
+
- **El registro del servidor ya no copia los errores enteros.** Un error interno de la aplicación o
|
|
413
|
+
del inicio de sesión con Google o GitHub escribía el objeto completo, que en un error de MySQL
|
|
414
|
+
incluye la consulta y el mensaje del servidor (con el email, por ejemplo). Ahora solo se escribe el
|
|
415
|
+
tipo y un código conocido (`Error ER_DUP_ENTRY`, `ProviderError token_http_500`), nunca el mensaje,
|
|
416
|
+
la pila, la consulta, el token, el código de autorización ni el secreto. La ruta se escribe por su
|
|
417
|
+
plantilla (`/api/auth/:provider/callback`), nunca por el camino pedido ni su cadena de consulta; sin
|
|
418
|
+
una ruta que coincida, `(no route)`. El borrado de sesiones caducadas sigue la misma regla: antes
|
|
419
|
+
escribía el mensaje del error cuando no tenía código.
|
|
420
|
+
- Google: una cuenta solo se crea o se enlaza si `email_verified` es exactamente `true`; antes
|
|
421
|
+
bastaba cualquier valor que JavaScript tome por verdadero. Un perfil sin identificador, o una lista
|
|
422
|
+
de emails de GitHub que no es una lista, son ahora un fallo del proveedor con su propio código.
|
|
423
|
+
- Un resumen de contraseña guardado con campos de más (`…$extra`) ya no se acepta como válido: el
|
|
424
|
+
formato tiene que ser exactamente el de `hashPassword`.
|
|
425
|
+
|
|
426
|
+
### Documentación
|
|
427
|
+
|
|
428
|
+
- `servidor/.env.example` deja el playground en `false`, y la [guía del playground](docs/playground.md)
|
|
429
|
+
lo mantiene desactivado en un servidor público hasta completar la
|
|
430
|
+
[comprobación del aislamiento](docs/playground.md#comprobar-el-aislamiento). Las comprobaciones
|
|
431
|
+
que necesitan el playground activo se hacen en un entorno controlado, sin exposición pública.
|
|
432
|
+
- Linux comprobado ([Pruebas](docs/testing.md#linux)): en Ubuntu 24.04 sobre WSL 2 pasan las
|
|
433
|
+
pruebas automáticas de `nexora/` con Python 3.11, 3.12 y 3.13 (también las cuatro de POSIX, que
|
|
434
|
+
nunca se habían ejecutado) y las de `npm/` y `servidor/`, y los paquetes de pip y npm se instalan
|
|
435
|
+
y funcionan. No hizo falta cambiar código. Docker y el aislamiento del playground siguen sin
|
|
436
|
+
comprobar.
|
|
437
|
+
- Despliegue ([guía del playground](docs/playground.md#despliegue-en-un-servidor-propio)): nginx con
|
|
438
|
+
redirección de HTTP a HTTPS, `limit_req`, `server_tokens off` y la sintaxis `http2 on` de las
|
|
439
|
+
versiones actuales; `TimeoutStopSec` en systemd; la ruta de salud; y copias de seguridad y
|
|
440
|
+
restauración de MySQL. **Nada de ello se ha probado** con nginx, systemd ni MySQL reales: la guía
|
|
441
|
+
lo dice en cada apartado.
|
|
442
|
+
|
|
443
|
+
### Limitaciones
|
|
444
|
+
|
|
445
|
+
- El aislamiento en contenedor sigue **sin comprobar**: este cambio evita activar el playground por
|
|
446
|
+
error, pero no lo hace más seguro una vez activado.
|
|
447
|
+
- Nada de esto se ha probado con Docker real. Las pruebas de la orden solo analizan la lista de
|
|
448
|
+
argumentos, sin ejecutar ningún Docker; las del ciclo de vida (eliminación de contenedores, hueco
|
|
449
|
+
ocupado, imagen ausente) usan un Docker falso. Si el servidor se cae, nadie elimina los
|
|
450
|
+
contenedores que tuviera en marcha.
|
|
451
|
+
- Qué es una orden de contenedor se decide solo por los nombres documentados. Un script
|
|
452
|
+
envoltorio, otra herramienta (`nerdctl`…) o un ejecutable de Docker con otro nombre quedan fuera
|
|
453
|
+
de la detección: no son una forma admitida de ejecutar contenedores, y el servidor no validaría
|
|
454
|
+
su orden ni eliminaría sus contenedores.
|
|
455
|
+
- Validar la orden no garantiza la configuración efectiva del demonio Docker ni de sus runtimes.
|
|
456
|
+
- La etiqueta local (`nexora-worker` o `nexora-worker:<etiqueta>`) es mutable: quien tenga acceso
|
|
457
|
+
al demonio Docker puede volver a etiquetar otra imagen con ese nombre, y el servidor la
|
|
458
|
+
ejecutaría sin notarlo. Que se ejecute la imagen de Nexora depende del control de acceso al
|
|
459
|
+
equipo y al demonio Docker.
|
|
460
|
+
- Docker en modo *rootless* no está admitido: la orden no permite `-H` ni `--context`, y el
|
|
461
|
+
servidor solo pasa `PATH` y `SystemRoot` a las órdenes que lanza.
|
|
462
|
+
- El antispam, el freno del inicio de sesión, el borrado de sesiones y las cabeceras se han probado
|
|
463
|
+
con la base de datos, Google reCAPTCHA y el navegador simulados: no contra un MySQL real, con claves
|
|
464
|
+
reales de reCAPTCHA, en un navegador ni detrás de nginx. Las pruebas automatizadas del servidor,
|
|
465
|
+
con esos mismos servicios simulados, dan 811 superadas y 0 fallos con Node 24.21.0 (una ejecución,
|
|
466
|
+
en Windows 11, con las guardas de las pruebas de integración limitadas a las ramas medidas). Antes de
|
|
467
|
+
ese cambio dieron 810 superadas y 0 fallos con Node 24.21.0 (en cada una de
|
|
468
|
+
tres ejecuciones), 24.14.0, 22.23.3 y 22.22.3, y 796 superadas, 14 omitidas (las que necesitan Node
|
|
469
|
+
22.22.3 o posterior en la rama 22, o 24.14.0 o posterior) y 0 fallos con Node 20.6.1 y 22.15.0 (una
|
|
470
|
+
ejecución con cada una de esas versiones), en Windows 11. Con los mínimos de `engines` (22.23.2 y
|
|
471
|
+
24.18.1) no se han ejecutado. En Ubuntu 24.04 en WSL 2 se ejecutaron antes de las últimas correcciones de la web
|
|
472
|
+
(567 superadas, 0 fallos, en cada una de tres ejecuciones) ([Pruebas](docs/testing.md)).
|
|
473
|
+
- Los contadores de los límites y del freno del inicio de sesión están en memoria: se pierden al
|
|
474
|
+
reiniciar y no se comparten entre varias instancias del servidor.
|
|
475
|
+
- En el inicio de sesión con Google o GitHub, la sesión se crea fuera de la transacción de la cuenta y
|
|
476
|
+
su enlace: si falla, la cuenta queda enlazada sin sesión hasta el siguiente intento. Durante el
|
|
477
|
+
apagado, un segundo `SIGTERM` o `SIGINT` termina el proceso sin completar la limpieza, y el 503 de
|
|
478
|
+
`/api/health` solo llega por conexiones ya abiertas. Las pruebas automatizadas, en Windows y con la
|
|
479
|
+
base de datos simulada, cubren el fallo de la sesión de OAuth y el reintento, el 503 durante el
|
|
480
|
+
apagado y el rechazo de las conexiones nuevas. No cubren la segunda señal del mismo tipo ni dos
|
|
481
|
+
primeros inicios simultáneos con la misma identidad, que siguen sin probar. Quedan pendientes las
|
|
482
|
+
pruebas contra un MySQL real, con señales reales del sistema operativo, con systemd y detrás de
|
|
483
|
+
nginx ([Tareas pendientes y riesgos](docs/playground.md#tareas-pendientes-y-riesgos)).
|
|
484
|
+
- Las páginas legales son un borrador sin los datos del titular ni revisión jurídica: no deben
|
|
485
|
+
publicarse así. Riesgos y decisiones pendientes (Analytics y su CSP, el `409` que revela si un email
|
|
486
|
+
tiene cuenta, la cancelación de consultas de MySQL):
|
|
487
|
+
[Tareas pendientes y riesgos](docs/playground.md#tareas-pendientes-y-riesgos).
|
|
488
|
+
|
|
489
|
+
## 0.6.0 — Operaciones sobre textos que declaran sus requisitos
|
|
490
|
+
|
|
491
|
+
Un programa puede medir un texto, cortarlo, buscar en él, ordenarlo y leer los números escritos en
|
|
492
|
+
él. Las funciones nuevas pertenecen a un tipo y se llaman con su nombre (`Text.length`,
|
|
493
|
+
`Int.parse`…), y las que pueden no tener respuesta declaran cuándo la tienen con un `requires`
|
|
494
|
+
escrito en NEXORA, igual que una función del programa. Implementa la
|
|
495
|
+
[decisión 0011](docs/decisions/0011-operaciones-sobre-textos.md). Ningún programa válido en la 0.5.1
|
|
496
|
+
deja de serlo ni cambia de resultado, y no se reserva ningún nombre. Para un programa válido solo
|
|
497
|
+
cambian los documentos de las herramientas, que ganan campos y entradas sin cambiar de versión:
|
|
498
|
+
`"qualifier": null` en los nodos `Call` de `nex inspect`, y las funciones nuevas en `nex symbols`.
|
|
499
|
+
|
|
500
|
+
### Añadido
|
|
501
|
+
|
|
502
|
+
- **Funciones de un tipo**, llamadas como `Tipo.función(…)`:
|
|
503
|
+
- `Text.length`, `Text.slice`, `Text.contains`, `Text.starts_with` y `Text.ends_with`. Trabajan
|
|
504
|
+
con caracteres (puntos de código Unicode), sin normalizar y distinguiendo mayúsculas.
|
|
505
|
+
- `Int.can_parse`, `Int.parse`, `Float.can_parse` y `Float.parse`. Leen una única forma de
|
|
506
|
+
número, la misma en cualquier máquina: `Int.parse` un entero dentro del rango de `Int`
|
|
507
|
+
(`"-42"`), y `Float.parse` un número con parte decimal o exponente (`"2.5"`, `"2.5e3"`, pero no
|
|
508
|
+
`"42"`). No admiten espacios, `+` delante, separadores ni otras bases.
|
|
509
|
+
- **Las funciones del lenguaje tienen `requires`.** `Text.slice`, `Int.parse` y `Float.parse`
|
|
510
|
+
declaran sus condiciones en NEXORA, con su explicación, y una llamada que las incumple se detiene
|
|
511
|
+
con el mismo `E4001` que una función del programa (código de salida `5`). En `Int.parse` y
|
|
512
|
+
`Float.parse`, el diagnóstico añade una sugerencia según lo que falló: comprobar antes el texto con
|
|
513
|
+
`Int.can_parse` o `Float.can_parse`, o el rango de `Int` si el número no cabe. Un programa puede
|
|
514
|
+
usar las mismas funciones en sus propios `requires` (`requires Int.can_parse(written)`) y en sus
|
|
515
|
+
tipos refinados (`type Code = Text where Text.length(value) == 3`).
|
|
516
|
+
- **Orden entre textos:** `<`, `<=`, `>` y `>=` entre dos `Text` (también de tipos refinados con
|
|
517
|
+
base `Text`). Se comparan carácter a carácter por punto de código, y un texto va antes que
|
|
518
|
+
cualquier otro que empiece por él (`"ab" < "abc"`, `"" < "a"`). No depende del idioma ni de la
|
|
519
|
+
configuración del sistema (`"Z" < "a"`), y compara caracteres, no números (`"10" < "9"`).
|
|
520
|
+
- Diagnósticos para la nueva sintaxis, sin códigos nuevos: `E1101` cuando la forma está mal
|
|
521
|
+
(`Text.length` sin paréntesis, espacios alrededor del `.`, más de un punto) y `E2008` cuando el
|
|
522
|
+
nombre no existe, con sugerencias como `Did you mean 'Text.length'?` para `length(t)`.
|
|
523
|
+
- `nex inspect`: campo `qualifier` en cada nodo `Call` (`null` en las llamadas sin cualificar),
|
|
524
|
+
sin cambiar la versión del esquema (`nexora.inspect/2`). `nex symbols` y las capacidades
|
|
525
|
+
(`language.builtins`): nombres cualificados y campo `contracts` con los requisitos de cada función
|
|
526
|
+
integrada. `nex context`: nombres cualificados en `builtins_called` y valor `text_operations` en
|
|
527
|
+
`features`.
|
|
528
|
+
- Ejemplos `texts.nex` y `failing/parse_number.nex`.
|
|
529
|
+
|
|
530
|
+
### Cambiado
|
|
531
|
+
|
|
532
|
+
Solo en programas que ya eran inválidos:
|
|
533
|
+
|
|
534
|
+
- Un `.` fuera de un número, un texto o un comentario pasa a ser un token. Donde antes había `E1001`
|
|
535
|
+
(`x.y`), ahora hay `E1101` o `E2008`.
|
|
536
|
+
- `E2011` mantiene su código, su título y su categoría, pero su sugerencia, cuando se compara un
|
|
537
|
+
`Text` con un número, propone convertir uno de los lados con `to_text(...)` o `Int.parse(...)`.
|
|
538
|
+
Ordenar dos `Text` ya no es un error.
|
|
539
|
+
|
|
540
|
+
### Corregido
|
|
541
|
+
|
|
542
|
+
- **El paquete de código fuente no podía ejecutar su propia batería de pruebas.** `MANIFEST.in` no
|
|
543
|
+
incluía los esquemas JSON de `tests/golden/schemas/`, y las pruebas que los leen fallaban en una
|
|
544
|
+
copia generada con `python -m build`. El paquete instalable (`.whl`) no estaba afectado.
|
|
545
|
+
|
|
546
|
+
### Documentación
|
|
547
|
+
|
|
548
|
+
- Especificación 0.6: sección 8.1 (funciones de un tipo y orden entre textos).
|
|
549
|
+
- Guías: requisitos de las funciones del lenguaje en
|
|
550
|
+
[contratos](docs/contracts.md#las-funciones-del-lenguaje-también-tienen-requires), y límites
|
|
551
|
+
actualizados en [limitaciones](docs/limitations.md).
|
|
552
|
+
- El ejemplo de bucles de la guía web y de la especificación suma hasta 10 000 en lugar de 100 000:
|
|
553
|
+
así se ejecuta con holgura dentro del límite de tiempo del playground.
|
|
554
|
+
|
|
555
|
+
### Limitaciones
|
|
556
|
+
|
|
557
|
+
- Un carácter es un punto de código, no lo que una persona ve como una letra: una `e` con el acento
|
|
558
|
+
combinado tiene longitud 2, y dos textos que se ven iguales pueden ser distintos para `==`.
|
|
559
|
+
- El orden entre textos no es alfabético en ningún idioma.
|
|
560
|
+
- Los requisitos de las funciones integradas se comprueban al ejecutar; `nex check` no avisa aunque
|
|
561
|
+
los argumentos sean constantes.
|
|
562
|
+
- `Float.parse` redondea al `Float` más cercano: el valor que devuelve puede no ser exactamente el
|
|
563
|
+
número escrito (`"0.1"`).
|
|
564
|
+
- No hay `trim`, mayúsculas, `split`, `replace`, interpolación ni búsqueda de posiciones.
|
|
565
|
+
|
|
566
|
+
## 0.5.1 — Revisión de la memoria agotada
|
|
567
|
+
|
|
568
|
+
Resultado de auditar la [decisión 0009](docs/decisions/0009-memoria-agotada.md) después de
|
|
569
|
+
implementarla. Su garantía se cumple: `E3007` se sigue construyendo sin retener los valores del
|
|
570
|
+
programa que falló, y cada ejemplo de `nex test` se evalúa aislado. La auditoría encontró dos
|
|
571
|
+
defectos alrededor de ella, corregidos aquí. Ningún programa cambia de resultado ni de código de
|
|
572
|
+
salida.
|
|
573
|
+
|
|
574
|
+
### Corregido
|
|
575
|
+
|
|
576
|
+
- **`E3007` y el `E3004` por falta de pila no decían en qué bucle ocurrieron.** La
|
|
577
|
+
[decisión 0010](docs/decisions/0010-var-y-while.md) (sección 7) da a todo error de ejecución
|
|
578
|
+
dentro de un bucle una nota por bucle (`In turn 3 of the loop at line 6.`). Estos dos se
|
|
579
|
+
construyen cuando el error ya ha salido de los bucles, y llegaban sin ellas. Ahora llevan las
|
|
580
|
+
mismas notas que cualquier otro error en el mismo punto, del bucle más interior al exterior y con
|
|
581
|
+
el mismo máximo de seis.
|
|
582
|
+
- **`nex test` en texto podía dejar un resumen sin terminar.** El informe se escribía a medida que
|
|
583
|
+
se preparaba: si fallaba después del resumen (un error interno, la memoria agotada), ese resumen
|
|
584
|
+
quedaba en la salida estándar igual que en un informe completo, con el código `70`. Ahora el
|
|
585
|
+
informe se prepara entero y se escribe al final, como el documento JSON: si algo falla, la salida
|
|
586
|
+
estándar queda vacía. Los informes normales no cambian.
|
|
587
|
+
|
|
588
|
+
### Limitaciones
|
|
589
|
+
|
|
590
|
+
- La prueba que agota memoria real (la del worker, con `RLIMIT_AS`) solo puede ejecutarse en Linux
|
|
591
|
+
y macOS, y no se ha ejecutado todavía: en Windows se omite y la integración continua no ha
|
|
592
|
+
funcionado nunca. Las demás pruebas de `E3007` provocan el `MemoryError` a propósito.
|
|
593
|
+
|
|
594
|
+
## 0.5.0 — `var` y bucles que dicen por qué terminan
|
|
595
|
+
|
|
596
|
+
La repetición deja de depender de la recursividad y del límite de 1000 llamadas. Y lo hace a la
|
|
597
|
+
manera de NEXORA: cada bucle declara por qué termina (`decreases`) y qué mantiene (`invariant`), y
|
|
598
|
+
el intérprete lo comprueba en cada vuelta. Así ningún bucle se queda repitiendo para siempre: o
|
|
599
|
+
termina, o se detiene y dice en qué vuelta y con qué valores. Implementa la
|
|
600
|
+
[decisión 0010](docs/decisions/0010-var-y-while.md).
|
|
601
|
+
|
|
602
|
+
### Añadido
|
|
603
|
+
|
|
604
|
+
- **Variables reasignables:** `var count = 0` y `count = count + 1`. El tipo de una `var` no cambia
|
|
605
|
+
nunca. `let` sigue siendo inmutable, y los parámetros también, para que `ensures` y los
|
|
606
|
+
diagnósticos vean siempre los valores con los que se llamó a la función. Una `var` de tipo
|
|
607
|
+
refinado conserva su garantía: se le asigna una constante válida o un valor comprobado con
|
|
608
|
+
`Tipo(x)`.
|
|
609
|
+
- **Bucles `while`** con dos cláusulas al principio del cuerpo, con la forma de los contratos y su
|
|
610
|
+
explicación opcional tras una coma:
|
|
611
|
+
- `decreases` (exactamente una): la medida, un `Int` que no baja de 0 y disminuye en cada vuelta.
|
|
612
|
+
- `invariant` (cero o más): condiciones que se cumplen antes de cada evaluación de la condición.
|
|
613
|
+
- Códigos nuevos: `E2021` (bucle sin medida, o con más de una), `E4005` (invariante incumplido) y
|
|
614
|
+
`E4006` (la medida no disminuye o es negativa), estos dos de categoría `contract`, con código de
|
|
615
|
+
salida `5`. Sus diagnósticos dicen la vuelta y los valores de todas las variables visibles.
|
|
616
|
+
- Un error dentro de un bucle (`E3xxx`, `E4xxx`) gana una nota por cada bucle que lo contiene:
|
|
617
|
+
`In turn 3 of the loop at line 6.`
|
|
618
|
+
- `nex test` ya no puede quedarse esperando por un bucle: el ejemplo queda en `error` con `E4006`.
|
|
619
|
+
- `nex inspect`: nodos `Var`, `While` y `LoopClause` (sigue siendo `nexora.inspect/2`). `nex symbols`:
|
|
620
|
+
campos `mutable` y `assignments`. `nex context`: campo `mutable` en las variables, campo `loops` al
|
|
621
|
+
final de cada función con la condición, los invariantes y la medida de cada bucle, valores
|
|
622
|
+
`mutable_variables`, `loops` y `loop_invariants` en `features`, y una nota cuando hay bucles.
|
|
623
|
+
- `E1103` sugiere cómo escribir con `while` lo que se intentaba con `for`, `break` o `continue`.
|
|
624
|
+
- Ejemplos `loops.nex` y `failing/loop_measure.nex`.
|
|
625
|
+
|
|
626
|
+
### Cambiado
|
|
627
|
+
|
|
628
|
+
- `E2007` mantiene su código y su título, pero su etiqueta y su sugerencia dicen ahora si el nombre
|
|
629
|
+
es una variable `let` o un parámetro, y proponen `var`.
|
|
630
|
+
- La sugerencia de `E2014` recuerda que un bucle puede no ejecutarse nunca.
|
|
631
|
+
|
|
632
|
+
### Cambios incompatibles
|
|
633
|
+
|
|
634
|
+
- **`invariant` y `decreases` pasan a ser palabras clave.** Un programa que los use como nombre de
|
|
635
|
+
variable, parámetro o función deja de ser válido (`E1101`); se renombran.
|
|
636
|
+
- `var` y `while` dejan de ser palabras reservadas. Ningún programa válido podía usarlas.
|
|
637
|
+
|
|
638
|
+
### Documentación
|
|
639
|
+
|
|
640
|
+
- Especificación 0.5: sección 5.3 (`var` y la asignación) y sección 9.5 (bucles).
|
|
641
|
+
- Guías: bucles en [contratos](docs/contracts.md#bucles-invariant-y-decreases) y en
|
|
642
|
+
[primeros pasos](docs/getting-started.md).
|
|
643
|
+
|
|
644
|
+
### Limitaciones
|
|
645
|
+
|
|
646
|
+
- No hay `for`, `break` ni `continue`, ni asignaciones compuestas (`+=`).
|
|
647
|
+
- La medida es un `Int`; no hay medidas compuestas.
|
|
648
|
+
- Una medida garantiza que un bucle termina, no que termine pronto: una medida inicial enorme
|
|
649
|
+
permite muchísimas vueltas. Una recursividad lenta (`fib(40)`) sigue sin límite de tiempo.
|
|
650
|
+
|
|
651
|
+
## 0.4.0 — Ejemplos y `nex test`
|
|
652
|
+
|
|
653
|
+
Tercer paso de la línea principal: una función puede llevar casos concretos de lo que debe dar, y
|
|
654
|
+
`nex test` los comprueba sin escribir `main`. Implementa la
|
|
655
|
+
[decisión 0008](docs/decisions/0008-ejemplos-y-nex-test.md) y la
|
|
656
|
+
[decisión 0009](docs/decisions/0009-memoria-agotada.md).
|
|
657
|
+
|
|
658
|
+
### Añadido
|
|
659
|
+
|
|
660
|
+
- **Ejemplos en las funciones:** `example double(2) == 4, "Two doubled"`, una cláusula del principio
|
|
661
|
+
del cuerpo junto a `requires` y `ensures`. Es una expresión `Bool` que tiene que llamar a su propia
|
|
662
|
+
función (`E2020` si no lo hace) y que no ve los parámetros ni `result`. El análisis nunca la evalúa.
|
|
663
|
+
- **`nex test`**: evalúa los ejemplos, cada uno en un intérprete nuevo, comprobando los contratos de
|
|
664
|
+
todo lo que se ejecuta. No exige `main` ni lo ejecuta. Opciones `--format text|json` y
|
|
665
|
+
`--function FUNCION`. Cada ejemplo termina en `passed`, `failed` (`E4004`, categoría nueva `test`) o
|
|
666
|
+
`error` (el diagnóstico original, con una nota que identifica el ejemplo).
|
|
667
|
+
- Código de salida `6`: algún ejemplo no pasó, o no había ningún ejemplo que evaluar.
|
|
668
|
+
- Formato `nexora.test/1` y `nexora.api.test_source`, que devuelve el mismo documento.
|
|
669
|
+
- `nex inspect`: nodo `Example` y campo `examples` al final de `Function` (sigue siendo
|
|
670
|
+
`nexora.inspect/2`). `nex context`: campo `examples` y valor `examples` en `features`.
|
|
671
|
+
- Ejemplo `examples/checked_examples.nex`.
|
|
672
|
+
- **`E3007` (Out of memory):** un programa que agota la memoria mientras se ejecuta recibe un
|
|
673
|
+
diagnóstico de ejecución, con la cadena de llamadas, en vez de un error interno. En `nex test`, el
|
|
674
|
+
ejemplo queda en `error` y se evalúan los siguientes. `nexora.api.run_source` sigue respondiendo
|
|
675
|
+
`memory_limit`, con el mismo mensaje, y ahora con el `E3007` en `diagnostics`.
|
|
676
|
+
|
|
677
|
+
### Corregido
|
|
678
|
+
|
|
679
|
+
- **Las pruebas de npm y del servidor no se ejecutaban con Node 18 y 20.** `node --test` solo expande
|
|
680
|
+
patrones como `"test/*.test.js"` desde Node 21, así que con las versiones que declaran los paquetes
|
|
681
|
+
no encontraba ningún archivo. Los scripts nombran ahora cada archivo, y una prueba comprueba que no
|
|
682
|
+
falte ninguno. La integración continua prueba npm con Node 18, 20 y 22, y el servidor con Node 20.6
|
|
683
|
+
y 22.
|
|
684
|
+
|
|
685
|
+
### Cambios incompatibles
|
|
686
|
+
|
|
687
|
+
- `example` pasa de palabra reservada a palabra clave. Ningún programa válido podía usarla como
|
|
688
|
+
nombre.
|
|
689
|
+
- **`nex run` con un programa que agota la memoria termina con `3`, no con `70`**, y la salida de
|
|
690
|
+
error muestra `runtime error[E3007]` en vez de `internal error`. Con `--format json` escribe el
|
|
691
|
+
documento `nexora.diagnostics/1`. El código `70` vuelve a significar solo un defecto de NEXORA.
|
|
692
|
+
Un script que trate `70` como "falta de memoria" debe mirar el código `E3007`.
|
|
693
|
+
|
|
694
|
+
### Limitaciones
|
|
695
|
+
|
|
696
|
+
- `nex test` no tiene límite de tiempo ni de memoria por ejemplo.
|
|
697
|
+
- `E3007` solo aparece si Python llega a quedarse sin memoria. En Linux, el sistema puede matar el
|
|
698
|
+
proceso antes, sin ningún mensaje.
|
|
699
|
+
- Una memoria agotada fuera de la ejecución (al analizar el programa o al construir un informe)
|
|
700
|
+
sigue terminando con `70`.
|
|
701
|
+
|
|
702
|
+
## 0.3.1 — Revisión de los tipos refinados
|
|
703
|
+
|
|
704
|
+
Resultado de intentar romper las garantías de la 0.3.0. La garantía principal resistió: ningún
|
|
705
|
+
camino permite que un valor llegue a un tipo refinado sin cumplir su condición, y la comprobación
|
|
706
|
+
sin ejecutar y la ejecución coinciden en los casos límite (`-0.0`, redondeo de `Float`, división
|
|
707
|
+
por cero evitada con `and`, desbordamiento). Esos ataques forman parte ahora de las pruebas.
|
|
708
|
+
La revisión encontró cuatro defectos alrededor de esa garantía, corregidos aquí.
|
|
709
|
+
|
|
710
|
+
### Corregido
|
|
711
|
+
|
|
712
|
+
- **`nex check` podía tardar demasiado con tipos refinados.** Cada constante evalúa las condiciones
|
|
713
|
+
de toda la cadena de su tipo, así que el trabajo crecía con tipos × condiciones × constantes: un
|
|
714
|
+
programa válido de 60 KB tardaba 2,5 s y agotaba el tiempo del playground (2 s). Ahora el
|
|
715
|
+
trabajo está acotado a 100 000 nodos de condición evaluados; por encima, el programa se rechaza
|
|
716
|
+
con el código nuevo `E2019` en vez de quedar comprobado a medias. El mismo programa se rechaza
|
|
717
|
+
ahora en 0,18 s, y uno corriente se comprueba en centésimas.
|
|
718
|
+
- **Una condición de tipo mal escrita producía errores falsos en cada uso del tipo** ("Cannot apply
|
|
719
|
+
'+' to Bad and Int", "Expected Bad, found Int"). Las condiciones se comprueban ahora antes que las
|
|
720
|
+
firmas, y un tipo con la condición incorrecta queda fuera sin más errores.
|
|
721
|
+
- **Un error de ejecución dentro de una condición no decía dónde se pidió la comprobación.** Si
|
|
722
|
+
`Huge(n)` desbordaba dentro de la condición de `Huge`, el diagnóstico señalaba la declaración del
|
|
723
|
+
tipo y nada más. Ahora añade la nota `While checking that a value is a valid Huge, at line …`.
|
|
724
|
+
- **Una explicación con `\n` rompía el formato de texto del diagnóstico.** Una explicación es ahora
|
|
725
|
+
una sola línea: un `\n` en ella es el error `E1101`.
|
|
726
|
+
|
|
727
|
+
### Documentación
|
|
728
|
+
|
|
729
|
+
- La especificación (sección 10.1), la guía del servidor MCP y la descripción de
|
|
730
|
+
`analysis_executes_code` decían que el análisis "no ejecuta nada". Ahora dicen con precisión lo
|
|
731
|
+
que hace: no ejecuta el programa, pero evalúa las condiciones de los tipos refinados sobre las
|
|
732
|
+
constantes, sin llamadas a funciones del programa y con el trabajo acotado.
|
|
733
|
+
- Nuevo límite en el documento de capacidades (`get_capabilities()` en Python y en el servidor
|
|
734
|
+
MCP): `max_refinement_steps`.
|
|
735
|
+
|
|
736
|
+
## 0.3.0 — Contratos y tipos refinados
|
|
737
|
+
|
|
738
|
+
Consolida la característica que distingue a NEXORA: los requisitos forman parte verificable del
|
|
739
|
+
programa ([decisión 0006](docs/decisions/0006-requisitos-verificables.md)). Los contratos dejan de
|
|
740
|
+
ser experimentales, cada regla puede llevar su explicación y llegan los tipos refinados. Los motivos
|
|
741
|
+
de cada elección están en la [decisión 0007](docs/decisions/0007-contratos-estables-y-tipos-refinados.md).
|
|
742
|
+
|
|
743
|
+
Esta versión incluye también todo lo hecho después de la 0.2.0 que no llegó a publicarse con otro
|
|
744
|
+
número: documentación, pruebas, playground y herramientas de análisis.
|
|
745
|
+
|
|
746
|
+
### Añadido
|
|
747
|
+
|
|
748
|
+
- **Tipos refinados:** `type Percent = Int where value >= 0 and value <= 100`. Todo valor de un
|
|
749
|
+
tipo refinado cumple su condición:
|
|
750
|
+
- Una constante usada como valor del tipo se comprueba **sin ejecutar** (`E2017`).
|
|
751
|
+
- Cualquier otro valor se comprueba explícitamente con `Percent(x)`, al ejecutar (`E4003`,
|
|
752
|
+
categoría `contract`, código de salida `5`).
|
|
753
|
+
- Un valor refinado se acepta donde se espera su base; una operación con él da un valor de la
|
|
754
|
+
base.
|
|
755
|
+
- Un tipo puede refinar otro (`type Pass = Percent where value >= 50`); se comprueban las dos
|
|
756
|
+
condiciones, desde la base.
|
|
757
|
+
- La condición solo puede usar `value`, literales, operadores y conversiones integradas
|
|
758
|
+
(`E2018`).
|
|
759
|
+
- **Explicación de las reglas:** `requires amount <= balance, "An account cannot go below zero"`.
|
|
760
|
+
Sirve en `requires`, `ensures` y `where`, y aparece en el diagnóstico como `Reason: ...` cuando
|
|
761
|
+
la regla se incumple.
|
|
762
|
+
- Códigos nuevos: `E2016` (declaración de tipo no válida), `E2017` (constante fuera del tipo
|
|
763
|
+
refinado), `E2018` (condición de refinamiento no válida) y `E4003` (refinamiento incumplido).
|
|
764
|
+
- `nex context` lista los tipos refinados (campo `types`) y la explicación de cada contrato (campo
|
|
765
|
+
`message`). Característica nueva en `features`: `refined_types`.
|
|
766
|
+
- Ejemplos `refined_types.nex`, `invalid/refinement_errors.nex` y
|
|
767
|
+
`failing/refinement_violation.nex`.
|
|
768
|
+
- **Licencia MIT** (`LICENSE`).
|
|
769
|
+
- **Paquete de npm** (`npm/`, nombre `nexora-lang`): instala el comando `nex` con un lanzador que
|
|
770
|
+
ejecuta el intérprete incluido usando el Python 3.11+ de la máquina. Preparado y probado en
|
|
771
|
+
local; **no publicado**.
|
|
772
|
+
- **`nex context`**: resumen de un programa (firmas, contratos, variables, llamadas entre
|
|
773
|
+
funciones, características usadas, diagnósticos), en texto o JSON. No ejecuta el programa.
|
|
774
|
+
- **`nex symbols`**: funciones, parámetros y variables con su tipo, su ámbito, su declaración y
|
|
775
|
+
cada uso, con los filtros `--name` y `--function`. No ejecuta el programa.
|
|
776
|
+
- **`nexora.tooling`**: API de Python con las mismas salidas (`check_source`, `inspect_source`,
|
|
777
|
+
`get_symbols`, `get_context`, `get_language_spec`, `get_capabilities`). **Experimental.**
|
|
778
|
+
- **Servidor MCP opcional** (`nex-mcp`, `pip install -e ".[mcp]"`): siete herramientas de análisis
|
|
779
|
+
para asistentes compatibles. No ejecuta código ni abre archivos indicados por quien llama.
|
|
780
|
+
Probado de forma automática con el cliente del SDK oficial (versión 2.3.0) y, a mano, en una
|
|
781
|
+
sesión de Claude Code 2.1.296 en Windows. No se ha probado en otros asistentes.
|
|
782
|
+
- Formatos `nexora.symbols/1`, `nexora.context/1`, `nexora.spec/1` y `nexora.capabilities/1`.
|
|
783
|
+
- JSON Schema de todos los formatos en `docs/schemas/`, generados desde el código y usados por las
|
|
784
|
+
pruebas para validar la salida real.
|
|
785
|
+
- Campo `nexora_version` en los documentos `nexora.diagnostics/1` y `nexora.inspect/1`. Es un campo
|
|
786
|
+
añadido: la versión del formato no cambia.
|
|
787
|
+
- Tareas de referencia para las herramientas de análisis (`tests/tooling_tasks.py`).
|
|
788
|
+
- **Análisis parcial con errores de sintaxis.** `nex inspect`, `nex symbols` y `nex context` (y sus
|
|
789
|
+
equivalentes en Python y en MCP) describen el código que sí pudo analizarse, con el campo nuevo
|
|
790
|
+
`complete` a `false`. Faltan las sentencias con errores y las funciones cuya declaración tiene
|
|
791
|
+
uno. Un programa con errores de sintaxis sigue sin ejecutarse.
|
|
792
|
+
|
|
793
|
+
- **Playground**: página web que comprueba y ejecuta código con el intérprete real
|
|
794
|
+
(`docs/playground.md`). Preparado para uso local; el aislamiento en contenedor para un servicio
|
|
795
|
+
público está configurado pero **no probado**.
|
|
796
|
+
- `nexora.api`: `check_source` y `run_source`, para comprobar o ejecutar código en memoria con
|
|
797
|
+
límites opcionales de salida y de longitud de texto. Esquema de resultado `nexora.result/1`.
|
|
798
|
+
- `python -m nexora.worker`: proceso de un solo uso que atiende una petición JSON.
|
|
799
|
+
- Diagnóstico `E3006` (texto demasiado largo), que solo aparece donde el entorno fija un límite.
|
|
800
|
+
- Código de salida `130` cuando la ejecución se interrumpe con Ctrl+C, en lugar de una traza de Python.
|
|
801
|
+
- Límite de 100 errores por etapa y archivo; el resumen del comando indica cuándo se alcanza.
|
|
802
|
+
- Ejemplos `arithmetic.nex` e `invalid/syntax_error.nex`.
|
|
803
|
+
- Pruebas: ejemplos con salida registrada, documentación ejecutable, seguridad y robustez.
|
|
804
|
+
- Medición de cobertura (`pytest-cov`) y análisis estático del código (`ruff`), como dependencias
|
|
805
|
+
de desarrollo.
|
|
806
|
+
- Configuración para generar un paquete instalable con el código, la documentación, los ejemplos
|
|
807
|
+
y las pruebas (`MANIFEST.in`).
|
|
808
|
+
- Flujo de integración continua para GitHub Actions. **No se ha ejecutado todavía.**
|
|
809
|
+
|
|
810
|
+
### Corregido
|
|
811
|
+
|
|
812
|
+
- Un número entero literal de más de 4300 cifras provocaba un error interno. Ahora es el
|
|
813
|
+
diagnóstico `E1004`.
|
|
814
|
+
- Un archivo que no es NEXORA (por ejemplo, un binario) producía un error por carácter, sin límite.
|
|
815
|
+
- Cuando la pila se agotaba por llamadas recursivas dentro de expresiones muy anidadas, el mensaje
|
|
816
|
+
de `E3004` afirmaba que se habían superado 1000 llamadas aunque no fuera así. Ahora indica
|
|
817
|
+
cuántas había.
|
|
818
|
+
- Si el lector de la salida se cerraba antes de tiempo (`nex run … | head -1`), se mostraba un
|
|
819
|
+
error interno. Ahora `nex` termina en silencio.
|
|
820
|
+
|
|
821
|
+
### Cambios incompatibles
|
|
822
|
+
|
|
823
|
+
- **`type` y `where` son palabras clave** (antes, palabras reservadas). Ningún programa válido de la
|
|
824
|
+
0.2 podía usarlas como nombres, así que ninguno deja de funcionar.
|
|
825
|
+
- **`nex inspect` pasa a `nexora.inspect/2`.** El campo `type` de una expresión puede ser el nombre
|
|
826
|
+
de un tipo refinado, no solo `Int`, `Float`, `Bool`, `Text` o `Void`. Añadidos: nodo `TypeDecl`,
|
|
827
|
+
campo `types` en `Program` y campo `message` en `Contract`. Cómo actualizar: aceptar cualquier
|
|
828
|
+
texto en `type` y comprobar `schema`.
|
|
829
|
+
- Los contratos dejan de ser experimentales: su sintaxis no cambia, pero a partir de ahora solo
|
|
830
|
+
cambiará siguiendo las reglas de los cambios incompatibles.
|
|
831
|
+
- El paquete de Python pasa a llamarse `nexora-lang` (antes `nexora`), porque `nexora` ya existe en
|
|
832
|
+
PyPI. El comando (`nex`) y el módulo (`import nexora`) no cambian. Cómo actualizar una
|
|
833
|
+
instalación en modo desarrollo: `python -m pip uninstall nexora` y `python -m pip install -e .`.
|
|
834
|
+
Los archivos generados se llaman ahora `nexora_lang-0.3.0…`, y el extra opcional se instala con
|
|
835
|
+
`nexora-lang[mcp]`.
|
|
836
|
+
- En el documento de `nex inspect`, con errores de sintaxis, `program` es ahora un árbol parcial y
|
|
837
|
+
no `null`. Sigue siendo `null` con errores léxicos o si el archivo no puede leerse. Cómo
|
|
838
|
+
actualizar: para saber si un programa es válido, usa `ok`; para saber si el árbol cubre todo el
|
|
839
|
+
archivo, usa `complete`. El nombre del formato (`nexora.inspect/1`) no cambia; el motivo está en
|
|
840
|
+
`docs/json-protocol.md`.
|
|
841
|
+
- Los ejemplos incorrectos a propósito se han movido: `examples/errors.nex` es ahora
|
|
842
|
+
`examples/invalid/name_errors.nex`; `type_errors.nex` está en `examples/invalid/`;
|
|
843
|
+
`runtime_error.nex` y `contract_violation.nex`, en `examples/failing/`.
|
|
844
|
+
|
|
845
|
+
### Retirado
|
|
846
|
+
|
|
847
|
+
- La función interna `values.type_name`, que no se usaba desde la 0.2.0.
|
|
848
|
+
|
|
849
|
+
### Documentación
|
|
850
|
+
|
|
851
|
+
- Nuevas guías: instalación, primeros pasos, tipos, funciones, contratos, CLI, diagnósticos,
|
|
852
|
+
herramientas automáticas e IA, arquitectura, pruebas, limitaciones y hoja de ruta.
|
|
853
|
+
- `CONTRIBUTING.md`, `SECURITY.md` y `CODE_OF_CONDUCT.md`.
|
|
854
|
+
- Todos los programas de la documentación se ejecutan en las pruebas y su salida se compara con
|
|
855
|
+
la real.
|
|
856
|
+
- Especificación 0.3: sección 4.4 (tipos refinados), contratos estables (sección 9) y códigos
|
|
857
|
+
nuevos. Guías de tipos y contratos ampliadas. Decisiones 0006 y 0007.
|
|
858
|
+
|
|
859
|
+
### Limitaciones
|
|
860
|
+
|
|
861
|
+
- De los tipos refinados, `nex check` solo comprueba las constantes; un valor calculado se comprueba
|
|
862
|
+
al ejecutar. No existe forma de comprobarlo sin detener el programa si falla (no hay `Result`).
|
|
863
|
+
- No hay alias de tipos sin condición.
|
|
864
|
+
- El proyecto sigue sin repositorio público y sin canal de contacto.
|
|
865
|
+
- Solo se ha comprobado en Windows 11 con Python 3.12.
|
|
866
|
+
|
|
867
|
+
## 0.2.0
|
|
868
|
+
|
|
869
|
+
Sistema de tipos, funciones, contratos (experimentales) y salidas estructuradas para herramientas.
|
|
870
|
+
|
|
871
|
+
### Añadido
|
|
872
|
+
|
|
873
|
+
- **Tipos:** anotaciones en `let` (`let age: Int = 25`), con inferencia cuando se omiten.
|
|
874
|
+
- **Operadores:** comparaciones `== != < <= > >=` y lógicos `and`, `or`, `not`.
|
|
875
|
+
- **Conversiones explícitas:** `to_float`, `to_int`, `to_text`.
|
|
876
|
+
- **Funciones** con parámetros tipados, tipo de retorno y `return`. Recursividad, con un máximo de
|
|
877
|
+
1000 llamadas anidadas.
|
|
878
|
+
- **`if` / `else if` / `else`** como sentencia.
|
|
879
|
+
- **Contratos (experimental):** `requires` y `ensures`, con `result`.
|
|
880
|
+
- **Análisis estático** de tipos de argumentos y de retorno, rutas de retorno (`E2014`), código
|
|
881
|
+
inalcanzable (`E2015`) y valores devueltos sin usar.
|
|
882
|
+
- **`nex inspect`:** el árbol de sintaxis en JSON, con tipos y posiciones (`nexora.inspect/1`).
|
|
883
|
+
- **`nex run --format json`:** errores en JSON por la salida de error.
|
|
884
|
+
- **Categoría** en cada diagnóstico (`file`, `lexical`, `syntax`, `semantic`, `type`, `runtime`,
|
|
885
|
+
`contract`) y campo `schema` en los documentos JSON (`nexora.diagnostics/1`).
|
|
886
|
+
- Cadena de llamadas en los diagnósticos de ejecución.
|
|
887
|
+
- Códigos nuevos: `E1106`, `E2012`–`E2015`, `E3004`, `E3005`, `E4001`, `E4002`.
|
|
888
|
+
- Código de salida `5`: contrato incumplido.
|
|
889
|
+
|
|
890
|
+
### Cambios incompatibles
|
|
891
|
+
|
|
892
|
+
- El tipo de texto se llama **`Text`** (antes `String`). Solo cambia en los mensajes: en 0.1 no se
|
|
893
|
+
podían escribir tipos.
|
|
894
|
+
- La cabecera de los diagnósticos de texto incluye la categoría:
|
|
895
|
+
`type error[E2011]: …` en lugar de `error[E2011]: …`.
|
|
896
|
+
- `to_text`, `to_float` y `to_int` ya no pueden usarse como nombres de variable.
|
|
897
|
+
- Un tipo de retorno desconocido es ahora `E2012` (antes `E2004`).
|
|
898
|
+
- Requiere Python 3.11 o superior (antes 3.10).
|
|
899
|
+
|
|
900
|
+
### Retirado
|
|
901
|
+
|
|
902
|
+
- `E1104` y `E2003`, que avisaban de que los parámetros, las anotaciones y las funciones propias no
|
|
903
|
+
existían.
|
|
904
|
+
|
|
905
|
+
### Compatibilidad
|
|
906
|
+
|
|
907
|
+
Los cuatro programas de ejemplo de 0.1 se ejecutan sin cambios y producen la misma salida.
|
|
908
|
+
|
|
909
|
+
## 0.1.0
|
|
910
|
+
|
|
911
|
+
Primera versión ejecutable: función `main`, variables inmutables con `let`, tipos `Int`, `Float`,
|
|
912
|
+
`Bool` y `String`, aritmética, bloques, comentarios, `print`, y los comandos `nex run` y
|
|
913
|
+
`nex check`.
|