xonecode 0.28.0 → 0.31.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -9,14 +9,16 @@
9
9
  * en memoria, y por eso se sube también a disco — sin eso,
10
10
  * relanzar la app la devuelve a la versión anterior.
11
11
  * JavaScript (`.js`) → `uploadFile` + `loadIncludeFile` con `compile: true`.
12
- * CSS, `.ini`, `app.xml`, un `.xne` sin colección (mappings)
13
- * → `uploadFile`, y hace falta RELANZAR la app. Medido:
14
- * `setCssAttribute`, `relayout` y `refresh` contestan
15
- * `result:true` y no cambian nada.
12
+ * CSS (`.css`) → `uploadFile` + `runScript` con `appData.unloadCssFile` y
13
+ * `appData.loadCssFile` + `refresh` (idea suya, medido: el
14
+ * color cambia sin relanzar). Si el script falla, se relanza.
15
+ * `.ini`, `app.xml`, un `.xne` sin colección (mappings)
16
+ * → `uploadFile` y se RELANZA la app, que es lo único que los
17
+ * relee.
16
18
  * todo lo demás (iconos, `bd/`, `files/`) → no se recarga: lo lleva el despliegue entero.
17
19
  *
18
- * **Relanzar no se hace solo**: se pierde el estado de la pantalla en que está la persona, así
19
- * que lo que se devuelve es «hace falta relanzar» y la pantalla lo OFRECE.
20
+ * **Relanzar SÍ se hace solo** (lo pidió así: lo guardado tiene que verse): el precio, que la app
21
+ * vuelve a su pantalla de inicio, lo dice la frase.
20
22
  */
21
23
  import { decodificarComoTexto, esUtf8Valido, tablaDeLosBytes } from "./codificacion.js";
22
24
  /** Las extensiones que el aparato sabe tomar sueltas. Las mismas del script. */
@@ -43,6 +45,8 @@ export function claseDeRecarga(ruta, bytes) {
43
45
  return "no-aplica";
44
46
  if (ext === ".js")
45
47
  return "js";
48
+ if (ext === ".css")
49
+ return "css";
46
50
  if (ext === ".xne") {
47
51
  let cabeza = "";
48
52
  for (const b of bytes)
@@ -88,11 +92,15 @@ export function textoDeRecarga(r) {
88
92
  case "aplicada":
89
93
  return r.clase === "js"
90
94
  ? "Aparato: JavaScript recargado; la app sigue viva"
91
- : "Aparato: pantalla recargada en caliente; la app sigue viva";
95
+ : r.clase === "css"
96
+ ? "Aparato: estilos recargados en caliente; la app sigue viva"
97
+ : "Aparato: pantalla recargada en caliente; la app sigue viva";
92
98
  case "relanzar":
93
99
  return "Aparato: subido; para verlo hay que relanzar la app";
94
100
  case "relanzada":
95
- return "Aparato: app relanzada y viva";
101
+ return r.clase === "relanzar" || r.clase === "css"
102
+ ? "Aparato: cambios aplicados relanzando la app (vuelve a su pantalla de inicio)"
103
+ : "Aparato: app relanzada y viva";
96
104
  case "sin-app":
97
105
  // El motivo, si se sabe: «no hay aparato elegido» y «no está en la medida» no se arreglan
98
106
  // en el mismo sitio que «la app no corre».
@@ -1 +1 @@
1
- {"version":3,"file":"recargaEnCaliente.js","sourceRoot":"","sources":["../../src/core/recargaEnCaliente.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"recargaEnCaliente.js","sourceRoot":"","sources":["../../src/core/recargaEnCaliente.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAIxF,gFAAgF;AAChF,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAErE,gEAAgE;AAChE,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;AAEvC,oGAAoG;AACpG,MAAM,iBAAiB,GAAG,aAAa,CAAC;AAExC,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,MAAM,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACtC,OAAO,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,WAAW,EAAE,CAAC;AAC7D,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY,EAAE,KAAiB;IAC5D,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IACxC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAAE,OAAO,WAAW,CAAC;IACtF,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;IAC9B,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,OAAO,WAAW,CAAC;IAC9C,IAAI,GAAG,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IAC/B,IAAI,GAAG,KAAK,MAAM;QAAE,OAAO,KAAK,CAAC;IACjC,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACnB,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,KAAK,MAAM,CAAC,IAAI,KAAK;YAAE,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACxD,OAAO,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,UAAU,CAAC;IACnE,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,yBAAyB,CAAC,KAAiB;IACzD,IAAI,YAAY,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IACxC,OAAO,eAAe,CAAC,KAAK,CAAC,KAAK,aAAa,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,cAAc,CAAC;AACnF,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAiB;IACtD,MAAM,KAAK,GAAG,oBAAoB,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACjE,MAAM,cAAc,GAAG,KAAK,CAAC,OAAO,CAClC,kDAAkD,EAClD,CAAC,KAAK,EAAE,KAAa,EAAE,OAAe,EAAE,EAAE,CAAC,GAAG,KAAK,GAAG,OAAO,QAAQ,OAAO,EAAE,CAC/E,CAAC;IACF,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,cAAc,CAAC,CAAC;AAClD,CAAC;AAED,iGAAiG;AACjG,MAAM,UAAU,kBAAkB,CAAC,GAAW,EAAE,IAAY;IAC1D,OAAO,OAAO,GAAG,CAAC,WAAW,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC;AAChE,CAAC;AAoCD,iFAAiF;AACjF,MAAM,UAAU,cAAc,CAAC,CAAqB;IAClD,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAC;QACjB,KAAK,UAAU;YACb,OAAO,CAAC,CAAC,KAAK,KAAK,IAAI;gBACrB,CAAC,CAAC,kDAAkD;gBACpD,CAAC,CAAC,CAAC,CAAC,KAAK,KAAK,KAAK;oBACjB,CAAC,CAAC,4DAA4D;oBAC9D,CAAC,CAAC,4DAA4D,CAAC;QACrE,KAAK,UAAU;YACb,OAAO,qDAAqD,CAAC;QAC/D,KAAK,WAAW;YACd,OAAO,CAAC,CAAC,KAAK,KAAK,UAAU,IAAI,CAAC,CAAC,KAAK,KAAK,KAAK;gBAChD,CAAC,CAAC,+EAA+E;gBACjF,CAAC,CAAC,+BAA+B,CAAC;QACtC,KAAK,SAAS;YACZ,0FAA0F;YAC1F,2CAA2C;YAC3C,OAAO,CAAC,CAAC,MAAM,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,oBAAoB,CAAC;gBACvE,CAAC,CAAC,2BAA2B,CAAC,CAAC,MAAM,GAAG;gBACxC,CAAC,CAAC,0EAA0E,CAAC;QACjF,KAAK,YAAY;YACf,OAAO,4CAA4C,CAAC;QACtD,KAAK,aAAa;YAChB,OAAO,gFAAgF,CAAC;QAC1F,KAAK,SAAS;YACZ,OAAO,2DAA2D,CAAC;QACrE,KAAK,WAAW;YACd,OAAO,yEAAyE,CAAC;QACnF,KAAK,OAAO;YACV,OAAO,iCAAiC,CAAC,CAAC,MAAM,IAAI,YAAY,GAAG,CAAC;IACxE,CAAC;AACH,CAAC"}
@@ -0,0 +1,206 @@
1
+ /**
2
+ * ¿Está bien formado este XML? Puro, sin librerías y sin llamar a nadie.
3
+ *
4
+ * Existe por un turno real (soporte de APPSalud): la persona pegó el error del parser de Studio
5
+ * («'name' is an unexpected token. The expected token is '='. Line 381, position 4») y el agente,
6
+ * sin forma de comprobarlo, revisó el fichero a ojo durante minutos — tenía razón a los dos
7
+ * minutos («está bien formado») y no se lo creyó. Esto contesta la pregunta con un sí o con la
8
+ * línea y la columna, como un parser.
9
+ *
10
+ * Solo la FORMA del XML: etiquetas que abren y cierran en orden, atributos con su `=` y su valor
11
+ * entre comillas, sin repetir, separados por blancos; comentarios (sin `--` dentro), CDATA,
12
+ * instrucciones `<?…?>`, entidades, una sola raíz. **No** sabe nada de XOne: un atributo que XOne
13
+ * no conoce está bien formado (para eso, `xone_atributos`).
14
+ */
15
+ const ENTIDADES = new Set(["amp", "lt", "gt", "quot", "apos"]);
16
+ /** Primer carácter de un nombre XML (aproximado a lo que usa un proyecto XOne, con Unicode). */
17
+ const INICIO_DE_NOMBRE = /[A-Za-z_:À-￿]/;
18
+ const RESTO_DE_NOMBRE = /[A-Za-z0-9_:.\-·À-￿]/;
19
+ export function comprobarXml(entrada) {
20
+ const texto = entrada.startsWith("") ? entrada.slice(1) : entrada;
21
+ let i = 0;
22
+ /** Línea y columna (desde 1) de una posición. */
23
+ const donde = (pos) => {
24
+ let linea = 1;
25
+ let inicio = 0;
26
+ for (let k = 0; k < pos && k < texto.length; k++) {
27
+ if (texto[k] === "\n") {
28
+ linea += 1;
29
+ inicio = k + 1;
30
+ }
31
+ }
32
+ return { linea, columna: pos - inicio + 1 };
33
+ };
34
+ const fallo = (pos, motivo) => ({ ok: false, ...donde(pos), motivo });
35
+ const blanco = (c) => c === " " || c === "\t" || c === "\n" || c === "\r";
36
+ const saltarBlancos = () => {
37
+ while (blanco(texto[i]))
38
+ i++;
39
+ };
40
+ const leerNombre = () => {
41
+ const desde = i;
42
+ if (i < texto.length && INICIO_DE_NOMBRE.test(texto[i])) {
43
+ i++;
44
+ while (i < texto.length && RESTO_DE_NOMBRE.test(texto[i]))
45
+ i++;
46
+ }
47
+ return texto.slice(desde, i);
48
+ };
49
+ /** Una entidad que empieza en `pos` (un `&`). Devuelve el motivo si no vale. */
50
+ const entidadMala = (pos) => {
51
+ const fin = texto.indexOf(";", pos);
52
+ const cuerpo = fin < 0 ? "" : texto.slice(pos + 1, fin);
53
+ if (fin < 0 || fin - pos > 12 || !/^#?[A-Za-z0-9]+$/.test(cuerpo))
54
+ return "un «&» suelto: escríbelo «&amp;»";
55
+ if (/^#[0-9]+$/.test(cuerpo) || /^#x[0-9A-Fa-f]+$/.test(cuerpo) || ENTIDADES.has(cuerpo))
56
+ return undefined;
57
+ return `entidad desconocida «&${cuerpo};»: en XML solo valen &amp; &lt; &gt; &quot; &apos; y las numéricas`;
58
+ };
59
+ const abiertas = [];
60
+ let raices = 0;
61
+ while (i < texto.length) {
62
+ const c = texto[i];
63
+ if (c !== "<") {
64
+ if (c === "&") {
65
+ const mala = entidadMala(i);
66
+ if (mala !== undefined)
67
+ return fallo(i, mala);
68
+ }
69
+ else if (abiertas.length === 0 && !blanco(c)) {
70
+ return fallo(i, raices === 0 ? "hay texto antes del elemento raíz" : "hay texto después de cerrar el elemento raíz");
71
+ }
72
+ i++;
73
+ continue;
74
+ }
75
+ // Comentario.
76
+ if (texto.startsWith("<!--", i)) {
77
+ const fin = texto.indexOf("-->", i + 4);
78
+ if (fin < 0)
79
+ return fallo(i, "un comentario «<!--» que no se cierra con «-->»");
80
+ const dobleGuion = texto.indexOf("--", i + 4);
81
+ if (dobleGuion >= 0 && dobleGuion < fin)
82
+ return fallo(dobleGuion, "«--» dentro de un comentario: XML no lo admite");
83
+ i = fin + 3;
84
+ continue;
85
+ }
86
+ // CDATA.
87
+ if (texto.startsWith("<![CDATA[", i)) {
88
+ if (abiertas.length === 0)
89
+ return fallo(i, "un bloque CDATA fuera del elemento raíz");
90
+ const fin = texto.indexOf("]]>", i + 9);
91
+ if (fin < 0)
92
+ return fallo(i, "un «<![CDATA[» que no se cierra con «]]>»");
93
+ i = fin + 3;
94
+ continue;
95
+ }
96
+ // DOCTYPE: se salta entero, hasta su «>».
97
+ if (texto.startsWith("<!DOCTYPE", i)) {
98
+ const fin = texto.indexOf(">", i);
99
+ if (fin < 0)
100
+ return fallo(i, "un «<!DOCTYPE» sin cerrar");
101
+ i = fin + 1;
102
+ continue;
103
+ }
104
+ // Instrucción de proceso (el prólogo `<?xml …?>`).
105
+ if (texto.startsWith("<?", i)) {
106
+ const fin = texto.indexOf("?>", i + 2);
107
+ if (fin < 0)
108
+ return fallo(i, "un «<?» que no se cierra con «?>»");
109
+ i = fin + 2;
110
+ continue;
111
+ }
112
+ // Cierre.
113
+ if (texto.startsWith("</", i)) {
114
+ const pos = i;
115
+ i += 2;
116
+ const nombre = leerNombre();
117
+ if (nombre === "")
118
+ return fallo(i, "falta el nombre de la etiqueta tras «</»");
119
+ saltarBlancos();
120
+ if (texto[i] !== ">")
121
+ return fallo(i, `se esperaba «>» para cerrar «</${nombre}»`);
122
+ const abierta = abiertas.pop();
123
+ if (abierta === undefined)
124
+ return fallo(pos, `«</${nombre}>» cierra algo que no está abierto`);
125
+ if (abierta.nombre !== nombre) {
126
+ const { linea } = donde(abierta.pos);
127
+ return fallo(pos, `«</${nombre}>» no cierra la etiqueta abierta, que es «<${abierta.nombre}>» (línea ${linea})`);
128
+ }
129
+ i++;
130
+ continue;
131
+ }
132
+ // Apertura.
133
+ const pos = i;
134
+ i++;
135
+ const nombre = leerNombre();
136
+ if (nombre === "")
137
+ return fallo(i, "un «<» que no empieza ninguna etiqueta: si es texto, escríbelo «&lt;»");
138
+ if (abiertas.length === 0) {
139
+ raices += 1;
140
+ if (raices > 1)
141
+ return fallo(pos, `un segundo elemento raíz «<${nombre}>»: un XML solo tiene una raíz`);
142
+ }
143
+ const vistos = new Set();
144
+ for (;;) {
145
+ const antes = i;
146
+ saltarBlancos();
147
+ const c2 = texto[i];
148
+ if (c2 === undefined)
149
+ return fallo(pos, `la etiqueta «<${nombre}» no se cierra`);
150
+ if (c2 === ">") {
151
+ abiertas.push({ nombre, pos });
152
+ i++;
153
+ break;
154
+ }
155
+ if (c2 === "/") {
156
+ if (texto[i + 1] !== ">")
157
+ return fallo(i, "se esperaba «/>»");
158
+ i += 2;
159
+ break;
160
+ }
161
+ if (i === antes)
162
+ return fallo(i, `falta un espacio antes del atributo, en «<${nombre}»`);
163
+ const posAtributo = i;
164
+ const atributo = leerNombre();
165
+ if (atributo === "")
166
+ return fallo(i, `carácter inesperado «${c2}» dentro de «<${nombre}»`);
167
+ saltarBlancos();
168
+ if (texto[i] !== "=") {
169
+ // El caso del soporte: un atributo sin su `=` (el .NET de Studio lo dice al revés: el
170
+ // token que encuentra donde esperaba el `=`).
171
+ return fallo(i, `al atributo «${atributo}» le falta el «=» y su valor`);
172
+ }
173
+ i++;
174
+ saltarBlancos();
175
+ const comilla = texto[i];
176
+ if (comilla !== '"' && comilla !== "'")
177
+ return fallo(i, `el valor del atributo «${atributo}» tiene que ir entre comillas`);
178
+ const fin = texto.indexOf(comilla, i + 1);
179
+ if (fin < 0)
180
+ return fallo(i, `el valor del atributo «${atributo}» no cierra su comilla`);
181
+ for (let k = i + 1; k < fin; k++) {
182
+ if (texto[k] === "<")
183
+ return fallo(k, `un «<» dentro del valor de «${atributo}»: escríbelo «&lt;»`);
184
+ if (texto[k] === "&") {
185
+ const mala = entidadMala(k);
186
+ if (mala !== undefined)
187
+ return fallo(k, mala);
188
+ }
189
+ }
190
+ if (vistos.has(atributo))
191
+ return fallo(posAtributo, `el atributo «${atributo}» está repetido en «<${nombre}»`);
192
+ vistos.add(atributo);
193
+ i = fin + 1;
194
+ if (!blanco(texto[i]) && texto[i] !== ">" && texto[i] !== "/" && texto[i] !== undefined) {
195
+ return fallo(i, `falta un espacio entre el atributo «${atributo}» y lo que sigue`);
196
+ }
197
+ }
198
+ }
199
+ const abierta = abiertas.pop();
200
+ if (abierta !== undefined)
201
+ return fallo(abierta.pos, `«<${abierta.nombre}>» se abre y no se cierra antes de que acabe el fichero`);
202
+ if (raices === 0)
203
+ return fallo(texto.length, "no hay ningún elemento raíz");
204
+ return { ok: true };
205
+ }
206
+ //# sourceMappingURL=xmlBienFormado.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"xmlBienFormado.js","sourceRoot":"","sources":["../../src/core/xmlBienFormado.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xonecode",
3
- "version": "0.28.0",
3
+ "version": "0.31.0",
4
4
  "description": "Consola CLI y harness de agente para desarrollar aplicaciones XOne",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -46,6 +46,7 @@
46
46
  "@langchain/openai": "1.5.5",
47
47
  "@modelcontextprotocol/sdk": "^1.30.0",
48
48
  "@truefoundry/trueforge-core": "0.2.1",
49
+ "acorn": "^8.19.0",
49
50
  "better-sqlite3": "13.0.3",
50
51
  "deepagents": "^1.14.0",
51
52
  "fflate": "^0.8.3",
@@ -107,7 +107,8 @@ xone-desplegar-android --app MiApp --serie emulator-5554
107
107
  # «cambié un botón / una función / un color»: NO despliegues entero. Compara el proyecto con el
108
108
  # aparato, sube SOLO lo que difiere y lo aplica por la vía más barata (1-2 s si es una colección):
109
109
  # colección (.xne) → recarga en caliente JavaScript (.js) → recarga del include
110
- # CSS, app.xml, app.ini, mappings → relanza la app (unos 6 s)
110
+ # CSS (.css) → recarga en caliente (loadCssFile; en frameworks viejos, por runScript)
111
+ # app.xml, app.ini, mappings → relanza la app (unos 6 s)
111
112
  # Necesita la app YA desplegada. Lo que no sabe aplicar (iconos, bd) lo dice y manda a desplegar.
112
113
  xone-recargar-android
113
114
  xone-recargar-android MenuPrincipal.xne functions.js # solo esos, sin comparar
@@ -246,7 +247,7 @@ Detalle de despliegue, relanzado y endpoints de fichero: [conexión y despliegue
246
247
  | Tocar (`click`, `tap`, `doubleTap`, `longPress`, `openSelector`, `fill`, `clear`, `scroll`, `pressKey`) | sí | **sí**, con desviaciones (abajo) |
247
248
  | Ciclo de app (`launchApplication`, `exitApplication`, `directdownload`) | sí | `launchApplication` y `directdownload` sí; `exitApplication` no |
248
249
  | Atributos y colecciones (`setAttribute`, `deleteAttribute`, `loadCollection`) | sí | sí |
249
- | CSS, `replaceProperty`, `refresh`, `relayout`, `loadIncludeFile` | sí | **no** |
250
+ | CSS (`setCssAttribute`, `loadCssFile`/`unloadCssFile`), `replaceProperty`, `refresh`, `relayout`, `loadIncludeFile` | sí | **no** |
250
251
  | Ficheros (`/file_upload`, `/file_download`, `uploadFile`, `getFileChecksum`) | sí | **no** (`listappfiles` sí) |
251
252
  | Scripts y SQL (`runScript`, `runSql`, `getDatabaseTableNames`, `queryDatabaseTable`) | sí | **no** |
252
253
  | Logs (`getLog`, `*DeviceLogging`, `setLog*`) | sí | **no** |
@@ -81,6 +81,7 @@ por los dos canales.
81
81
  | `deleteAttribute` | sí | sí | **solo WS** |
82
82
  | `replaceProperty` | sí | — | — |
83
83
  | `setCssAttribute` / `deleteCssAttribute` | sí | — | — |
84
+ | `loadCssFile` / `unloadCssFile` (desde 5.0.5.7dev) | sí | — | — |
84
85
  | `refresh` / `relayout` | sí | — | — |
85
86
  | `status` / `state` | sí | sí | **solo WS** |
86
87
  | `uploadFile` | sí | — | — |
@@ -542,7 +543,8 @@ Carga o recarga una colección XML en caliente. **Entrada:** `xmlNode` (XML en *
542
543
  |---|---|---|
543
544
  | Colección `.xne` | `loadCollection` con el fichero entero en Base64 y `encoding=UTF-8` | Se repinta en ~2 s, **solo en memoria**: al relanzar la app vuelve la versión de disco. Para que persista, subir también el fichero con `uploadFile`. |
544
545
  | JavaScript | `uploadFile` y luego `loadIncludeFile` con `compile=true` | Se aplica al instante. Solo subirlo, o `loadCollection`, **no** lo recarga. |
545
- | CSS | `uploadFile` y luego `launchApplication` | Se aplica al relanzar. `setCssAttribute`, `relayout`, `refresh` y `loadCollection` contestan `result:true` y el color **no cambia**; `loadIncludeFile` no admite css (`Unknown script language css`). |
546
+ | CSS (5.0.5.7dev en adelante) | `uploadFile` y luego `loadCssFile` con `fileName` | Se aplica al instante (medido: ~50 ms), **sin relanzar ni `refresh`**: sustituye la hoja en su sitio de la cascada y relayouta. |
547
+ | CSS (antes de 5.0.5.7dev, donde `loadCssFile` es `Unknown command`) | `uploadFile`, `runScript` con `appData.unloadCssFile(n); appData.loadCssFile(n, enc); return "ok";` y luego `refresh` | Se aplica sin relanzar. **Sin el `refresh` no se ve**: el cambio entra en el siguiente pintado. `setCssAttribute`, `relayout`, `refresh` y `loadCollection` solos contestan `result:true` y el color **no cambia**; `loadIncludeFile` no admite css (`Unknown script language css`). |
546
548
 
547
549
  `uploadFile`: `destinationPath` cuelga del directorio de datos del framework, no del de la app.
548
550
  La app vive en `app_<nombre en minúsculas>/`, así que hay que dar `app_holamundo/functions.js`; con
@@ -567,6 +569,20 @@ relayout o refresh según el atributo. **(iOS)** también es legado: solo WebSoc
567
569
  ### `setCssAttribute` / `deleteCssAttribute` — solo Android
568
570
  `fileName`, `className`, `attributeName` (+ `attributeValue` en el set).
569
571
 
572
+ ### `loadCssFile` / `unloadCssFile` — solo Android, desde 5.0.5.7dev
573
+ `loadCssFile`: `fileName` (sí), `encoding` (no, `UTF-8`), `conditions` (no, vacío = siempre),
574
+ `strictMode` (no, `false`). Carga una hoja que **ya está en el dispositivo** (súbela antes con
575
+ `uploadFile`), como un `<style>` del `<app>`, y relayouta las ventanas visibles. Si ya estaba cargada
576
+ con las mismas `conditions`, la **sustituye** en su sitio: así se aplica una hoja recién subida, sin
577
+ `unloadCssFile` antes. `unloadCssFile`: `fileName` (sí); quita la hoja y relayouta; una que no está
578
+ cargada responde éxito.
579
+
580
+ **Medido (5.0.5.7dev, emulador):** `uploadFile` + `loadCssFile fileName=default-colors.css` cambia el
581
+ color de un botón en ~50 ms, sin relanzar. Un nombre que no existe: `result:false` con
582
+ `FileNotFoundException`. Sin app cargada contestan `App is not running` en `status`. En 5.0.5.5dev el
583
+ comando no existe (`Unknown command: loadCssFile`): ahí, las funciones de XOne por `runScript` + `refresh`
584
+ (tabla de arriba).
585
+
570
586
  ### `refresh` / `relayout` — solo Android
571
587
  En iOS las ramas existen en el dispatcher pero están **vacías**: no hacen nada.
572
588
 
@@ -13,9 +13,13 @@
13
13
  * devuelve a la versión anterior.
14
14
  * JavaScript (.js) → `loadIncludeFile` con compile=true. Subir el fichero NO basta,
15
15
  * y `loadCollection` tampoco lo recarga.
16
- * CSS, .ini, app.xml, mappings → relanzar la app (`launchApplication`). Medido: `setCssAttribute`,
17
- * `relayout`, `refresh` y `loadCollection` contestan `result:true`
18
- * y el color NO cambia; `loadIncludeFile` no admite css.
16
+ * CSS (.css) → el comando `loadCssFile` (framework 5.0.5.7dev en adelante): la
17
+ * sustituye y relayouta solo. En uno anterior, que contesta
18
+ * `Unknown command`, `runScript` con `appData.unloadCssFile` +
19
+ * `appData.loadCssFile` y un `refresh`. Medidos los dos: el color
20
+ * cambia SIN relanzar. Lo que no sirve, también medido:
21
+ * `setCssAttribute`, `relayout`, `refresh` o `loadCollection` solos.
22
+ * .ini, app.xml, mappings → relanzar la app (`launchApplication`): solo se leen al cargarla.
19
23
  *
20
24
  * **`result:true` es «aceptado», no «aplicado».** Lo que dice si funcionó es el árbol de
21
25
  * controles, y por eso el script lo pide al acabar. Un atributo que XOne no conoce tampoco da
@@ -202,6 +206,7 @@ if (cambiados.length === 0) {
202
206
  function clase(rel) {
203
207
  const ext = extname(rel).toLowerCase();
204
208
  if (ext === ".js") return "js";
209
+ if (ext === ".css") return "css";
205
210
  if (ext === ".xne") return /<coll[\s>]/.test(readFileSync(rel, "latin1")) ? "coleccion" : "relanzar";
206
211
  return "relanzar";
207
212
  }
@@ -248,6 +253,7 @@ for (const rel of cambiados) {
248
253
  const clases = new Map(subidos.map((f) => [f, clase(f)]));
249
254
  const hayQueRelanzar = [...clases.values()].includes("relanzar");
250
255
  const fallos = [];
256
+ let necesitaRefresh = false;
251
257
 
252
258
  if (hayQueRelanzar) {
253
259
  const r = mandar("launchApplication", { appName: app });
@@ -263,12 +269,39 @@ if (hayQueRelanzar) {
263
269
  const r = mandar("loadCollection", { xmlNode: xmlEnUtf8(readFileSync(f)).toString("base64"), encoding: "UTF-8" });
264
270
  if (r.result !== true) fallos.push(`${f}: loadCollection ${r.exceptionMessage ?? r.status ?? "sin motivo"}`);
265
271
  else console.log(` ${f} → colección recargada en caliente`);
272
+ } else if (c === "css") {
273
+ // La codificación de SUS bytes: `loadCssFile` asume UTF-8 si no se le dice.
274
+ let tabla = "UTF-8";
275
+ try {
276
+ new TextDecoder("utf-8", { fatal: true }).decode(readFileSync(f));
277
+ } catch {
278
+ tabla = "windows-1252";
279
+ }
280
+ const nativo = mandar("loadCssFile", { fileName: f, encoding: tabla });
281
+ if (nativo.result === true) {
282
+ console.log(` ${f} → estilos recargados en caliente`);
283
+ } else if (/Unknown command/i.test(String(nativo.exceptionMessage ?? nativo.status ?? ""))) {
284
+ // Framework anterior a 5.0.5.7dev: las mismas funciones de XOne, por `runScript`, y un
285
+ // `refresh` (abajo) para que se pinte.
286
+ const script = `appData.unloadCssFile(${JSON.stringify(f)}); appData.loadCssFile(${JSON.stringify(f)}, ${JSON.stringify(tabla)}); return "ok";`;
287
+ const r = mandar("runScript", { scriptLanguage: "javascript", scriptText: Buffer.from(script, "utf8").toString("base64") });
288
+ if (r.result !== true) fallos.push(`${f}: loadCssFile ${r.exceptionMessage ?? r.status ?? "sin motivo"}`);
289
+ else {
290
+ necesitaRefresh = true;
291
+ console.log(` ${f} → estilos recargados en caliente (por runScript)`);
292
+ }
293
+ } else {
294
+ fallos.push(`${f}: loadCssFile ${nativo.exceptionMessage ?? nativo.status ?? "sin motivo"}`);
295
+ }
266
296
  } else {
267
297
  const r = mandar("loadIncludeFile", { file: f, language: "javascript", encoding: "UTF-8", compile: true });
268
298
  if (r.result !== true) fallos.push(`${f}: loadIncludeFile ${r.exceptionMessage ?? r.status ?? "sin motivo"}`);
269
299
  else console.log(` ${f} → JavaScript recargado`);
270
300
  }
271
301
  }
302
+ // Por `runScript` los estilos se ven en el SIGUIENTE pintado: sin este `refresh`, no cambia nada
303
+ // (medido). El comando `loadCssFile` relayouta él solo.
304
+ if (necesitaRefresh) mandar("refresh");
272
305
  dormir(1);
273
306
  }
274
307