@glassnote/client 2.4.0 → 2.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/INSTALACION.md +0 -0
- package/README.md +0 -0
- package/autoStart.js +0 -0
- package/autoupdate.js +0 -0
- package/autoupdate_renderer.js +14 -21
- package/bin/glassnote.js +54 -0
- package/images/demo01.png +0 -0
- package/images/dmg-background.png +0 -0
- package/images/dmg-background.svg +0 -0
- package/images/icon-16.png +0 -0
- package/images/icon-24.png +0 -0
- package/images/icon-512.png +0 -0
- package/images/icon.ico +0 -0
- package/images/icon.png +0 -0
- package/images/splash.svg +0 -0
- package/localserver.js +0 -0
- package/logUtilities.js +0 -0
- package/main.js +3 -46
- package/npmMode.js +0 -0
- package/npmUpdate.js +40 -8
- package/package.json +2 -1
- package/preload.js +0 -0
- package/rendererPaths.js +62 -0
- package/userData.js +0 -0
package/INSTALACION.md
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
File without changes
|
package/autoStart.js
CHANGED
|
File without changes
|
package/autoupdate.js
CHANGED
|
File without changes
|
package/autoupdate_renderer.js
CHANGED
|
@@ -5,6 +5,7 @@ const https = require('https');
|
|
|
5
5
|
const crypto = require('crypto');
|
|
6
6
|
const { exec } = require('child_process');
|
|
7
7
|
const userData = require('./userData');
|
|
8
|
+
const { baselineRendererDir, rendererVersionFrom } = require('./rendererPaths');
|
|
8
9
|
|
|
9
10
|
// El renderer se baja siempre del bucket de PRODUCCIÓN. Antes esto lo decidía un campo
|
|
10
11
|
// `stage` en package.json que elegía entre este bucket y `glassnotedev`: ese ambiente ya
|
|
@@ -23,29 +24,21 @@ class AutoUpdateRenderer {
|
|
|
23
24
|
}
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
|
-
*
|
|
27
|
+
* La versión del renderer que está EN USO, que es contra la que hay que comparar el
|
|
28
|
+
* canal. En uso es la que elige loadRendererHtml: la más alta entre lo bajado a
|
|
29
|
+
* userData y el baseline que viaja con el paquete.
|
|
30
|
+
*
|
|
31
|
+
* Antes esto miraba solo userData y, si no había, `<paquete>/renderer/package.json`
|
|
32
|
+
* —una carpeta que dejó de existir cuando el renderer pasó a ser dependencia npm—.
|
|
33
|
+
* Devolvía 0.0.0, así que en cada instalación nueva cualquier versión del canal le
|
|
34
|
+
* ganaba: bajaba el zip de S3 aunque fuera MÁS VIEJO que el baseline, y después el
|
|
35
|
+
* loader se quedaba con el baseline igual: 1.1 MB tirados y una versión "actual"
|
|
36
|
+
* que no era la que se estaba usando.
|
|
27
37
|
*/
|
|
28
38
|
getCurrentRendererVersion() {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
if (fs.existsSync(userDataRendererPath)) {
|
|
33
|
-
const packageJson = JSON.parse(fs.readFileSync(userDataRendererPath, 'utf8'));
|
|
34
|
-
return packageJson.version;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Si no existe en userData, verificar en la aplicación (versión por defecto)
|
|
38
|
-
const appRendererPath = path.join(__dirname, 'renderer', 'package.json');
|
|
39
|
-
if (fs.existsSync(appRendererPath)) {
|
|
40
|
-
const packageJson = JSON.parse(fs.readFileSync(appRendererPath, 'utf8'));
|
|
41
|
-
return packageJson.version;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
return '0.0.0'; // Versión por defecto si no existe
|
|
45
|
-
} catch (error) {
|
|
46
|
-
console.error('Error reading renderer version:', error);
|
|
47
|
-
return '0.0.0';
|
|
48
|
-
}
|
|
39
|
+
const enUserData = rendererVersionFrom(path.join(userData.getUserDataDir(), 'renderer'));
|
|
40
|
+
const enBaseline = rendererVersionFrom(baselineRendererDir());
|
|
41
|
+
return this.compareVersions(enUserData, enBaseline) >= 0 ? enUserData : enBaseline;
|
|
49
42
|
}
|
|
50
43
|
|
|
51
44
|
/**
|
package/bin/glassnote.js
CHANGED
|
@@ -32,6 +32,48 @@ function npmEnv() {
|
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
// userData tira de `uuid`, y este CLI corre también donde el árbol de dependencias no
|
|
36
|
+
// está (un tarball recién desempacado, un install a medias). Por eso se carga tarde y
|
|
37
|
+
// tolerando el fallo: si no se puede dejar constancia, el peor caso es que la app
|
|
38
|
+
// reintente en el chequeo siguiente. Romper el CLI —que es quien instala— sería peor.
|
|
39
|
+
function conUserData(hacer) {
|
|
40
|
+
try {
|
|
41
|
+
return hacer(require('../userData'));
|
|
42
|
+
} catch (error) {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// La app mira esto antes de reintentar: sin memoria del fallo, un npm que falla siempre
|
|
48
|
+
// deja al cliente cerrándose y abriéndose cada veinte segundos (falla, se relanza,
|
|
49
|
+
// chequea a los 5 segundos, vuelve a fallar).
|
|
50
|
+
function recordarFalloDeUpdate(version, motivo) {
|
|
51
|
+
conUserData((userData) => userData.set('failedUpdate', { version, at: Date.now(), motivo }));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function olvidarFalloDeUpdate() {
|
|
55
|
+
conUserData((userData) => {
|
|
56
|
+
if (userData.get('failedUpdate')) userData.remove('failedUpdate');
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// ¿Hay un cliente vivo? Levanta su servidor local en 48984 (localserver.js), así que su
|
|
61
|
+
// /uuid es la señal más barata. Node no tiene HTTP síncrono y el CLI sí lo es, así que la
|
|
62
|
+
// consulta va en un proceso aparte.
|
|
63
|
+
function clienteEnMarcha() {
|
|
64
|
+
const sonda =
|
|
65
|
+
"const http=require('http');" +
|
|
66
|
+
"const r=http.get('http://127.0.0.1:48984/uuid',(res)=>{res.resume();process.exit(res.statusCode===200?0:1)});" +
|
|
67
|
+
"r.on('error',()=>process.exit(1));" +
|
|
68
|
+
"r.setTimeout(700,()=>{r.destroy();process.exit(1)});";
|
|
69
|
+
const res = spawnSync(process.execPath, ['-e', sonda], {
|
|
70
|
+
env: Object.assign({}, process.env, { ELECTRON_RUN_AS_NODE: '1' }),
|
|
71
|
+
stdio: 'ignore',
|
|
72
|
+
timeout: 4000,
|
|
73
|
+
});
|
|
74
|
+
return res.status === 0;
|
|
75
|
+
}
|
|
76
|
+
|
|
35
77
|
// Sueño síncrono sin dependencias: el ayudante de actualización tiene que esperar a que
|
|
36
78
|
// la app termine de cerrarse antes de que npm le reemplace los archivos.
|
|
37
79
|
function sleepSync(ms) {
|
|
@@ -346,6 +388,7 @@ function cmdUpdate(args) {
|
|
|
346
388
|
env: npmEnv(),
|
|
347
389
|
});
|
|
348
390
|
if (res.status !== 0) {
|
|
391
|
+
recordarFalloDeUpdate(version, `npm salió con ${res.status}`);
|
|
349
392
|
if (relaunch) {
|
|
350
393
|
// Falló la actualización: al menos el cliente vuelve. Quedarse sin app por
|
|
351
394
|
// un npm que no pudo con la red es peor que seguir en la versión vieja.
|
|
@@ -355,6 +398,7 @@ function cmdUpdate(args) {
|
|
|
355
398
|
fail('npm no pudo actualizar el paquete.');
|
|
356
399
|
}
|
|
357
400
|
|
|
401
|
+
olvidarFalloDeUpdate();
|
|
358
402
|
log(`Actualizado a v${installedVersion()}.`);
|
|
359
403
|
if (relaunch) {
|
|
360
404
|
launch({ detach: true });
|
|
@@ -366,6 +410,10 @@ function cmdUpdate(args) {
|
|
|
366
410
|
|
|
367
411
|
function cmdUninstall() {
|
|
368
412
|
log('glassnote — desinstalando');
|
|
413
|
+
// Se comprueba ANTES de borrar: después los archivos ya no están, pero el proceso que
|
|
414
|
+
// los tenía abiertos sigue vivo y con su ícono en la bandeja. Decir "Desinstalado" con
|
|
415
|
+
// la app todavía en pantalla es lo que confunde.
|
|
416
|
+
const seguiaAbierto = clienteEnMarcha();
|
|
369
417
|
step('quitando el autoarranque');
|
|
370
418
|
removeAutoStart();
|
|
371
419
|
|
|
@@ -383,6 +431,12 @@ function cmdUninstall() {
|
|
|
383
431
|
fs.rmSync(mode.HOME_DIR, { recursive: true, force: true });
|
|
384
432
|
}
|
|
385
433
|
log('');
|
|
434
|
+
if (seguiaAbierto) {
|
|
435
|
+
log('OJO: el cliente sigue abierto. Sus archivos ya no están, pero el proceso vive');
|
|
436
|
+
log('hasta que lo cierres desde el ícono de la bandeja (Salir). Después no vuelve a');
|
|
437
|
+
log('abrirse: el autoarranque ya no está.');
|
|
438
|
+
log('');
|
|
439
|
+
}
|
|
386
440
|
log('Desinstalado. Tus datos y notas siguen donde estaban:');
|
|
387
441
|
log(` ${userDataDir()}`);
|
|
388
442
|
log('Borralos a mano si también querés perderlos.');
|
package/images/demo01.png
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
package/images/icon-16.png
CHANGED
|
File without changes
|
package/images/icon-24.png
CHANGED
|
File without changes
|
package/images/icon-512.png
CHANGED
|
File without changes
|
package/images/icon.ico
CHANGED
|
File without changes
|
package/images/icon.png
CHANGED
|
File without changes
|
package/images/splash.svg
CHANGED
|
File without changes
|
package/localserver.js
CHANGED
|
File without changes
|
package/logUtilities.js
CHANGED
|
File without changes
|
package/main.js
CHANGED
|
@@ -17,6 +17,7 @@ const AutoUpdate = require('./autoupdate');
|
|
|
17
17
|
const NpmUpdate = require('./npmUpdate');
|
|
18
18
|
const npmMode = require('./npmMode');
|
|
19
19
|
const AutoUpdateRenderer = require('./autoupdate_renderer');
|
|
20
|
+
const { baselineRendererDir, rendererVersionFrom: getRendererVersionFromPath } = require('./rendererPaths');
|
|
20
21
|
const { createTailUtility } = require('./logUtilities');
|
|
21
22
|
|
|
22
23
|
const logRenderer = packageJson.logRenderer !== undefined ? packageJson.logRenderer : true;
|
|
@@ -556,20 +557,7 @@ process.on('unhandledRejection', (reason, promise) => {
|
|
|
556
557
|
*
|
|
557
558
|
* Gana la version mas alta, sin importar de donde venga; empate, gana userData.
|
|
558
559
|
*/
|
|
559
|
-
//
|
|
560
|
-
// que npm resuelve sola. Pero si hay un clon del renderer al lado —el flujo de quien lo
|
|
561
|
-
// desarrolla, con `npm run watch-renderer`— ese gana: si no, editarlo no se veria nunca,
|
|
562
|
-
// tapado por la version publicada.
|
|
563
|
-
function baselineRendererDir() {
|
|
564
|
-
const clonLocal = path.join(__dirname, 'glassnote-renderer', 'dist');
|
|
565
|
-
if (fs.existsSync(clonLocal)) return clonLocal;
|
|
566
|
-
try {
|
|
567
|
-
return path.join(path.dirname(require.resolve('@glassnote/renderer/package.json')), 'dist');
|
|
568
|
-
} catch (error) {
|
|
569
|
-
// Sin dependencia ni clon solo queda userData; si tampoco esta, mas abajo se avisa.
|
|
570
|
-
return clonLocal;
|
|
571
|
-
}
|
|
572
|
-
}
|
|
560
|
+
// baselineRendererDir vive en rendererPaths.js: lo comparte con el updater del renderer.
|
|
573
561
|
|
|
574
562
|
function loadRendererHtml(window, uuid) {
|
|
575
563
|
// Definir las dos fuentes a considerar con archivos HTML alternativos
|
|
@@ -695,38 +683,7 @@ function compareVersions(version1, version2) {
|
|
|
695
683
|
return 0; // Las versiones son iguales
|
|
696
684
|
}
|
|
697
685
|
|
|
698
|
-
|
|
699
|
-
* Obtiene la versión del renderer desde el package.json en el directorio especificado
|
|
700
|
-
* Si el directorio es un dist/ sin package.json, se mira el del paquete que lo contiene.
|
|
701
|
-
*/
|
|
702
|
-
function getRendererVersionFromPath(rendererPath) {
|
|
703
|
-
try {
|
|
704
|
-
// Primero intentar en el directorio especificado
|
|
705
|
-
const packageJsonPath = path.join(rendererPath, 'package.json');
|
|
706
|
-
if (fs.existsSync(packageJsonPath)) {
|
|
707
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
|
|
708
|
-
return packageJson.version || '0.0.0';
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
// Un dist/ sin package.json propio: la version la tiene el paquete de arriba.
|
|
712
|
-
if (path.basename(rendererPath) === 'dist') {
|
|
713
|
-
const parentDir = path.join(rendererPath, '..'); // Subir un nivel
|
|
714
|
-
const parentPackageJsonPath = path.join(parentDir, 'package.json');
|
|
715
|
-
if (fs.existsSync(parentPackageJsonPath)) {
|
|
716
|
-
const packageJson = JSON.parse(fs.readFileSync(parentPackageJsonPath, 'utf8'));
|
|
717
|
-
return packageJson.version || '0.0.0';
|
|
718
|
-
}
|
|
719
|
-
}
|
|
720
|
-
} catch (error) {
|
|
721
|
-
console.error(
|
|
722
|
-
'Error reading renderer version from',
|
|
723
|
-
rendererPath,
|
|
724
|
-
':',
|
|
725
|
-
error
|
|
726
|
-
);
|
|
727
|
-
}
|
|
728
|
-
return '0.0.0'; // Versión por defecto si no existe o hay error
|
|
729
|
-
}
|
|
686
|
+
// getRendererVersionFromPath = rendererVersionFrom de rendererPaths.js (ver el require de arriba).
|
|
730
687
|
|
|
731
688
|
/**
|
|
732
689
|
* Recarga el main window después de una actualización del renderer
|
package/npmMode.js
CHANGED
|
File without changes
|
package/npmUpdate.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// desprendido, la app se cierra, el ayudante actualiza y la vuelve a abrir. Igual en las
|
|
9
9
|
// tres plataformas, así no hay una rama por sistema operativo que solo se pruebe en uno.
|
|
10
10
|
const https = require('https');
|
|
11
|
+
const fs = require('fs');
|
|
11
12
|
const path = require('path');
|
|
12
13
|
const { spawn } = require('child_process');
|
|
13
14
|
|
|
@@ -90,18 +91,38 @@ class NpmUpdate {
|
|
|
90
91
|
const meta = await this.getJson(`${REGISTRY}/${npmMode.PKG_NAME}/${target}`);
|
|
91
92
|
if (!meta || !meta.version) return;
|
|
92
93
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
94
|
+
const objetivo = meta.version;
|
|
95
|
+
const hayQueActualizar = isLatest
|
|
96
|
+
? compareVersions(this.currentVersion, objetivo) < 0
|
|
97
|
+
: this.currentVersion !== objetivo;
|
|
98
|
+
if (!hayQueActualizar) return;
|
|
99
|
+
if (this.fallidoHacePoco(objetivo)) return;
|
|
100
|
+
this.applyUpdate(objetivo);
|
|
100
101
|
} catch (error) {
|
|
101
102
|
console.error('[update] error comprobando actualizaciones:', error.message);
|
|
102
103
|
}
|
|
103
104
|
}
|
|
104
105
|
|
|
106
|
+
// Una actualización que falló NO se reintenta enseguida. cmdUpdate relanza la app a
|
|
107
|
+
// propósito cuando npm falla —quedarse sin cliente es peor que quedarse en la versión
|
|
108
|
+
// vieja—, pero el chequeo vuelve a los 5 segundos de arrancar. Con un fallo que
|
|
109
|
+
// persiste (sin red, el registry caído, una dependencia que no resuelve) eso es la app
|
|
110
|
+
// cerrándose y abriéndose cada veinte segundos, para siempre y sin decir por qué. Se
|
|
111
|
+
// recuerda la versión que falló y se espera al chequeo normal.
|
|
112
|
+
fallidoHacePoco(version) {
|
|
113
|
+
try {
|
|
114
|
+
const fallo = userData.get('failedUpdate');
|
|
115
|
+
if (!fallo || fallo.version !== version) return false;
|
|
116
|
+
const desde = Date.now() - (fallo.at || 0);
|
|
117
|
+
if (desde >= CHECK_INTERVAL_MS) return false;
|
|
118
|
+
const minutos = Math.max(1, Math.round((CHECK_INTERVAL_MS - desde) / 60000));
|
|
119
|
+
console.log(`[update] ${version} ya falló; no se reintenta hasta dentro de ~${minutos} min`);
|
|
120
|
+
return true;
|
|
121
|
+
} catch (error) {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
105
126
|
applyUpdate(version) {
|
|
106
127
|
if (this.updating) return;
|
|
107
128
|
this.updating = true;
|
|
@@ -117,11 +138,22 @@ class NpmUpdate {
|
|
|
117
138
|
PATH: `${npmMode.BIN_DIR}${path.delimiter}${process.env.PATH || ''}`,
|
|
118
139
|
});
|
|
119
140
|
|
|
141
|
+
// El ayudante corre desprendido y su salida no la veía nadie: cuando npm fallaba,
|
|
142
|
+
// el único síntoma era la app reiniciándose sola. Va a un archivo al lado de los
|
|
143
|
+
// datos de usuario, que es donde alguien lo va a buscar.
|
|
144
|
+
let salida = 'ignore';
|
|
145
|
+
try {
|
|
146
|
+
fs.mkdirSync(userData.getUserDataDir(), { recursive: true });
|
|
147
|
+
salida = fs.openSync(path.join(userData.getUserDataDir(), 'update.log'), 'a');
|
|
148
|
+
} catch (error) {
|
|
149
|
+
console.error('[update] no se pudo abrir update.log:', error.message);
|
|
150
|
+
}
|
|
151
|
+
|
|
120
152
|
try {
|
|
121
153
|
const child = spawn(
|
|
122
154
|
process.execPath,
|
|
123
155
|
[cli, 'update', version, '--relaunch', '--wait', '4000'],
|
|
124
|
-
{ detached: true, stdio: 'ignore', env }
|
|
156
|
+
{ detached: true, stdio: ['ignore', salida, salida], env }
|
|
125
157
|
);
|
|
126
158
|
child.unref();
|
|
127
159
|
} catch (error) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glassnote/client",
|
|
3
|
-
"version": "2.4.
|
|
3
|
+
"version": "2.4.2",
|
|
4
4
|
"description": "GlassNote — cliente de escritorio de notas superpuestas. Se instala con npx, sin instaladores nativos ni firmas.",
|
|
5
5
|
"main": "main.js",
|
|
6
6
|
"publishConfig": {
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"autoStart.js",
|
|
30
30
|
"autoupdate.js",
|
|
31
31
|
"autoupdate_renderer.js",
|
|
32
|
+
"rendererPaths.js",
|
|
32
33
|
"npmMode.js",
|
|
33
34
|
"npmUpdate.js",
|
|
34
35
|
"localserver.js",
|
package/preload.js
CHANGED
|
File without changes
|
package/rendererPaths.js
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
// De dónde sale el renderer y qué versión tiene. En un solo sitio a propósito.
|
|
2
|
+
//
|
|
3
|
+
// Esto vivía duplicado en main.js y en autoupdate_renderer.js, y las dos copias se
|
|
4
|
+
// fueron separando: la del updater seguía mirando `<paquete>/renderer/`, una carpeta que
|
|
5
|
+
// dejó de existir cuando el renderer pasó a ser la dependencia @glassnote/renderer. Como
|
|
6
|
+
// no la encontraba devolvía 0.0.0, cualquier versión del canal le ganaba, y cada
|
|
7
|
+
// instalación nueva bajaba el zip de S3 —incluso más viejo que el baseline— para después
|
|
8
|
+
// no usarlo. Un bug silencioso: se ve como 1.1 MB de tráfico que nadie pidió.
|
|
9
|
+
'use strict';
|
|
10
|
+
|
|
11
|
+
const fs = require('fs');
|
|
12
|
+
const path = require('path');
|
|
13
|
+
|
|
14
|
+
// El baseline es la dependencia @glassnote/renderer, que npm resuelve sola. Pero si hay
|
|
15
|
+
// un clon del renderer al lado —el flujo de quien lo desarrolla, con `npm run
|
|
16
|
+
// watch-renderer`— ese gana: si no, editarlo no se vería nunca, tapado por la versión
|
|
17
|
+
// publicada.
|
|
18
|
+
function baselineRendererDir() {
|
|
19
|
+
const clonLocal = path.join(__dirname, 'glassnote-renderer', 'dist');
|
|
20
|
+
if (fs.existsSync(clonLocal)) return clonLocal;
|
|
21
|
+
try {
|
|
22
|
+
return path.join(path.dirname(require.resolve('@glassnote/renderer/package.json')), 'dist');
|
|
23
|
+
} catch (error) {
|
|
24
|
+
// Sin dependencia ni clon solo queda userData; quien llama avisa si tampoco está.
|
|
25
|
+
return clonLocal;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// La versión de un directorio de renderer. El dist/ publicado trae su propio
|
|
30
|
+
// package.json; si algún día no lo trajera, la versión la tiene el paquete de arriba.
|
|
31
|
+
function rendererVersionFrom(rendererPath) {
|
|
32
|
+
try {
|
|
33
|
+
const propio = path.join(rendererPath, 'package.json');
|
|
34
|
+
if (fs.existsSync(propio)) {
|
|
35
|
+
return JSON.parse(fs.readFileSync(propio, 'utf8')).version || '0.0.0';
|
|
36
|
+
}
|
|
37
|
+
if (path.basename(rendererPath) === 'dist') {
|
|
38
|
+
const delPadre = path.join(rendererPath, '..', 'package.json');
|
|
39
|
+
if (fs.existsSync(delPadre)) {
|
|
40
|
+
return JSON.parse(fs.readFileSync(delPadre, 'utf8')).version || '0.0.0';
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
} catch (error) {
|
|
44
|
+
console.error('Error reading renderer version from', rendererPath, ':', error);
|
|
45
|
+
}
|
|
46
|
+
return '0.0.0'; // No hay renderer ahí, o no se pudo leer.
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Compara dos versiones semánticas: 1 si a es mayor, -1 si b lo es, 0 si empatan.
|
|
50
|
+
function compareRendererVersions(a, b) {
|
|
51
|
+
const pa = String(a).split('.').map((n) => parseInt(n, 10) || 0);
|
|
52
|
+
const pb = String(b).split('.').map((n) => parseInt(n, 10) || 0);
|
|
53
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
54
|
+
const va = i < pa.length ? pa[i] : 0;
|
|
55
|
+
const vb = i < pb.length ? pb[i] : 0;
|
|
56
|
+
if (va > vb) return 1;
|
|
57
|
+
if (va < vb) return -1;
|
|
58
|
+
}
|
|
59
|
+
return 0;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
module.exports = { baselineRendererDir, rendererVersionFrom, compareRendererVersions };
|
package/userData.js
CHANGED
|
File without changes
|