electron-info 1.22.5 → 1.23.1

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.
Files changed (32) hide show
  1. package/README.md +1 -1
  2. package/dist/{esm/ElectronInfo.test.js → ElectronInfo.test.js} +3 -3
  3. package/dist/{esm/FileService.js → FileService.js} +5 -5
  4. package/dist/{esm/HTTPService.js → HTTPService.js} +2 -2
  5. package/dist/{cjs/HTTPService.test.js → HTTPService.test.js} +1 -1
  6. package/dist/{cjs/cli.js → cli.js} +10 -4
  7. package/package.json +11 -21
  8. package/dist/cjs/ElectronInfo.test.js +0 -140
  9. package/dist/cjs/FileService.js +0 -93
  10. package/dist/cjs/HTTPService.js +0 -35
  11. package/dist/cjs/package.json +0 -3
  12. package/dist/esm/ElectronInfo.d.ts +0 -70
  13. package/dist/esm/ElectronInfo.js +0 -155
  14. package/dist/esm/ElectronInfo.test.d.ts +0 -1
  15. package/dist/esm/FileService.d.ts +0 -12
  16. package/dist/esm/HTTPService.d.ts +0 -8
  17. package/dist/esm/HTTPService.test.d.ts +0 -1
  18. package/dist/esm/HTTPService.test.js +0 -29
  19. package/dist/esm/cli.d.ts +0 -2
  20. package/dist/esm/cli.js +0 -123
  21. package/dist/esm/index.d.ts +0 -1
  22. package/dist/esm/index.js +0 -1
  23. package/dist/esm/package.json +0 -3
  24. /package/dist/{cjs/ElectronInfo.d.ts → ElectronInfo.d.ts} +0 -0
  25. /package/dist/{cjs/ElectronInfo.js → ElectronInfo.js} +0 -0
  26. /package/dist/{cjs/ElectronInfo.test.d.ts → ElectronInfo.test.d.ts} +0 -0
  27. /package/dist/{cjs/FileService.d.ts → FileService.d.ts} +0 -0
  28. /package/dist/{cjs/HTTPService.d.ts → HTTPService.d.ts} +0 -0
  29. /package/dist/{cjs/HTTPService.test.d.ts → HTTPService.test.d.ts} +0 -0
  30. /package/dist/{cjs/cli.d.ts → cli.d.ts} +0 -0
  31. /package/dist/{cjs/index.d.ts → index.d.ts} +0 -0
  32. /package/dist/{cjs/index.js → index.js} +0 -0
package/README.md CHANGED
@@ -11,7 +11,7 @@ Get useful data about Electron releases. Uses [electron-releases](https://github
11
11
 
12
12
  ## Installation
13
13
 
14
- ℹ️ This is a hybrid [CommonJS](https://nodejs.org/docs/latest/api/modules.html#modules-commonjs-modules) / [ESM](https://nodejs.org/api/esm.html#introduction) module.
14
+ ℹ️ This is a pure [ESM](https://nodejs.org/api/esm.html#introduction) module.
15
15
 
16
16
  Just run `npx electron-info`.
17
17
 
@@ -1,10 +1,10 @@
1
+ import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+ import { randomUUID } from 'node:crypto';
1
4
  import { expect, describe, test, beforeEach, beforeAll, afterAll, afterEach } from 'vitest';
2
5
  import { StatusCodes as HTTP_STATUS } from 'http-status-codes';
3
6
  import nock from 'nock';
4
7
  import * as fs from 'fs-extra';
5
- import path from 'path';
6
- import { fileURLToPath } from 'url';
7
- import { randomUUID } from 'crypto';
8
8
  import { ElectronInfo } from './ElectronInfo.js';
9
9
  const __filename = fileURLToPath(import.meta.url);
10
10
  const __dirname = path.dirname(__filename);
@@ -1,9 +1,9 @@
1
+ import { constants as fsConstants, promises as fs } from 'node:fs';
2
+ import os from 'node:os';
3
+ import path from 'node:path';
4
+ import URL from 'node:url';
1
5
  import { isAfter as isAfterDate, sub as subtractDate } from 'date-fns';
2
- import { constants as fsConstants, promises as fs } from 'fs';
3
- import parseUrl from 'parse-url';
4
6
  import logdown from 'logdown';
5
- import os from 'os';
6
- import path from 'path';
7
7
  import { HTTPService } from './HTTPService.js';
8
8
  export class FileService {
9
9
  constructor(options) {
@@ -23,7 +23,7 @@ export class FileService {
23
23
  }
24
24
  async getReleases() {
25
25
  this.logger.log('Parsing releases URL', { releasesUrl: this.options.releasesUrl });
26
- const parsedUrl = parseUrl(this.options.releasesUrl);
26
+ const parsedUrl = URL.parse(this.options.releasesUrl);
27
27
  if (!parsedUrl.href) {
28
28
  throw new Error('Invalid releases URL provided');
29
29
  }
@@ -1,5 +1,5 @@
1
- import { promises as fs } from 'fs';
2
- import { inspect } from 'util';
1
+ import { promises as fs } from 'node:fs';
2
+ import { inspect } from 'node:util';
3
3
  import axios from 'axios';
4
4
  import logdown from 'logdown';
5
5
  export class HTTPService {
@@ -23,7 +23,7 @@ describe('HTTPService', () => {
23
23
  await httpService.downloadReleasesFile(mockUrl, '');
24
24
  assert.fail('Should throw on timeout');
25
25
  }
26
- catch (error) { }
26
+ catch (_error) { }
27
27
  });
28
28
  });
29
29
  });
@@ -1,9 +1,13 @@
1
1
  #!/usr/bin/env node
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
2
5
  import { program as commander } from 'commander';
3
- import { createRequire } from 'module';
4
- const require = createRequire(import.meta.url);
5
6
  import { ElectronInfo, SupportedDependencies } from './ElectronInfo.js';
6
- const { description, name, version } = require('../package.json');
7
+ const __filename = fileURLToPath(import.meta.url);
8
+ const __dirname = path.dirname(__filename);
9
+ const packageJsonPath = path.join(__dirname, '../package.json');
10
+ const { description, name, version } = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
7
11
  let matchedCommand = false;
8
12
  commander
9
13
  .name(name)
@@ -75,7 +79,9 @@ for (const [dependencyShortName, dependencyFullName] of Object.entries(Supported
75
79
  ...(commanderOptions.force && { forceUpdate: true }),
76
80
  ...(commanderOptions.latest && { latest: true }),
77
81
  ...(commanderOptions.limit && { limit: parseInt(commanderOptions.limit, 10) }),
78
- ...(typeof commanderOptions.prereleases !== 'undefined' && { electronPrereleases: commanderOptions.prereleases }),
82
+ ...(typeof commanderOptions.prereleases !== 'undefined' && {
83
+ electronPrereleases: commanderOptions.prereleases,
84
+ }),
79
85
  ...(commanderOptions.source && { releasesUrl: commanderOptions.source }),
80
86
  ...(commanderOptions.timeout && { timeout: commanderOptions.timeout }),
81
87
  });
package/package.json CHANGED
@@ -1,14 +1,13 @@
1
1
  {
2
2
  "author": "Florian Imdahl <git@ffflorian.de>",
3
- "bin": "dist/cjs/cli.js",
3
+ "bin": "dist/cli.js",
4
4
  "dependencies": {
5
- "axios": "1.7.2",
5
+ "axios": "1.7.3",
6
6
  "chalk": "5.3.0",
7
7
  "commander": "12.1.0",
8
8
  "date-fns": "3.6.0",
9
9
  "logdown": "3.3.1",
10
- "parse-url": "8.1.0",
11
- "semver": "7.6.2",
10
+ "semver": "7.6.3",
12
11
  "table": "6.8.2"
13
12
  },
14
13
  "description": "Get useful data about Electron releases.",
@@ -18,19 +17,14 @@
18
17
  "fs-extra": "11.2.0",
19
18
  "http-status-codes": "2.3.0",
20
19
  "nock": "13.5.4",
21
- "rimraf": "5.0.7",
22
- "typescript": "5.5.2",
23
- "vitest": "1.6.0"
20
+ "rimraf": "6.0.1",
21
+ "typescript": "5.5.4",
22
+ "vitest": "2.0.5"
24
23
  },
25
24
  "engines": {
26
25
  "node": ">= 18.0"
27
26
  },
28
- "exports": {
29
- ".": {
30
- "import": "./dist/esm/index.js",
31
- "require": "./dist/cjs/index.js"
32
- }
33
- },
27
+ "exports": "./dist/index.js",
34
28
  "files": [
35
29
  "dist"
36
30
  ],
@@ -43,21 +37,17 @@
43
37
  "typescript"
44
38
  ],
45
39
  "license": "GPL-3.0",
46
- "main": "dist/cjs/index.js",
47
- "module": "dist/esm/index.js",
40
+ "module": "dist/index.js",
48
41
  "name": "electron-info",
49
42
  "repository": "https://github.com/ffflorian/node-packages/tree/main/packages/electron-info",
50
43
  "scripts": {
51
- "build": "yarn build:cjs && yarn build:esm && yarn generate:packagejson",
52
- "build:cjs": "tsc -p tsconfig.cjs.json",
53
- "build:esm": "tsc -p tsconfig.json",
44
+ "build": "tsc -p tsconfig.json",
54
45
  "clean": "rimraf dist",
55
46
  "dist": "yarn clean && yarn build",
56
- "generate:packagejson": "../../bin/generate-hybrid-package-json.sh",
57
47
  "start": "node --loader ts-node/esm src/cli.ts -d",
58
48
  "test": "vitest run"
59
49
  },
60
50
  "type": "module",
61
- "version": "1.22.5",
62
- "gitHead": "f7a6a79286e4eb85392b5f2d33942ab166142109"
51
+ "version": "1.23.1",
52
+ "gitHead": "aadf648655ecd0f6bea0c989542a16ff636c71a7"
63
53
  }
@@ -1,140 +0,0 @@
1
- import { expect, describe, test, beforeEach, beforeAll, afterAll, afterEach } from 'vitest';
2
- import { StatusCodes as HTTP_STATUS } from 'http-status-codes';
3
- import nock from 'nock';
4
- import * as fs from 'fs-extra';
5
- import path from 'path';
6
- import { fileURLToPath } from 'url';
7
- import { randomUUID } from 'crypto';
8
- import { ElectronInfo } from './ElectronInfo.js';
9
- const __filename = fileURLToPath(import.meta.url);
10
- const __dirname = path.dirname(__filename);
11
- const tempDir = path.resolve(__dirname, '.temp');
12
- const tempDirDownload = path.resolve(__dirname, '.temp/download');
13
- const mockUrl = 'http://example.com';
14
- const invalidUrl = 'http://invalid.inv';
15
- const fixturesDir = path.resolve(__dirname, '../fixtures');
16
- const fullReleasesFile = path.join(fixturesDir, 'electron-releases-full.json');
17
- const createRandomBody = () => [
18
- {
19
- name: 'electron v8.0.0-nightly.20190820',
20
- node_id: randomUUID(),
21
- npm_dist_tags: [],
22
- prerelease: !!Math.round(Math.random()),
23
- published_at: new Date().toUTCString(),
24
- tag_name: 'v8.0.0-nightly.20190820',
25
- // eslint-disable-next-line no-magic-numbers
26
- total_downloads: Math.round(Math.random() * 1000),
27
- version: '8.0.0-nightly.20190820',
28
- },
29
- ];
30
- const provideReleaseFile = async () => {
31
- await fs.copy(fullReleasesFile, path.join(tempDirDownload, 'latest.json'));
32
- };
33
- describe('ElectronInfo', () => {
34
- let releases;
35
- beforeAll(async () => {
36
- await fs.ensureDir(tempDir);
37
- releases = await fs.readFile(fullReleasesFile, 'utf8');
38
- });
39
- beforeEach(() => {
40
- nock(mockUrl).get('/').reply(HTTP_STATUS.OK, releases);
41
- });
42
- afterAll(() => fs.remove(tempDir));
43
- afterEach(() => nock.cleanAll());
44
- describe('getElectronReleases', () => {
45
- test('parses Electron versions', async () => {
46
- const result = await new ElectronInfo({
47
- releasesUrl: mockUrl,
48
- tempDirectory: tempDir,
49
- }).getElectronReleases('5.0.8');
50
- expect(result.length).toBe(1);
51
- expect(result[0].version).toBe('5.0.8');
52
- });
53
- test('parses Electron SemVer', async () => {
54
- const result = await new ElectronInfo({
55
- releasesUrl: mockUrl,
56
- tempDirectory: tempDir,
57
- }).getElectronReleases('^5');
58
- // eslint-disable-next-line no-magic-numbers
59
- expect(result.length).toBe(23);
60
- });
61
- test('parses dist tags', async () => {
62
- const result = await new ElectronInfo({
63
- releasesUrl: mockUrl,
64
- tempDirectory: tempDir,
65
- }).getElectronReleases('5-0-x');
66
- expect(result.length).toBe(1);
67
- });
68
- test('returns nothing for invalid versions', async () => {
69
- const result = await new ElectronInfo({
70
- releasesUrl: mockUrl,
71
- tempDirectory: tempDir,
72
- }).getElectronReleases('invalid');
73
- expect(result.length).toBe(0);
74
- });
75
- test('forces downloading the release file', async () => {
76
- const customBody = createRandomBody();
77
- const customUrl = 'http://custom.com';
78
- await provideReleaseFile();
79
- nock(customUrl).get('/').reply(HTTP_STATUS.OK, customBody);
80
- const result = await new ElectronInfo({
81
- forceUpdate: true,
82
- releasesUrl: customUrl,
83
- tempDirectory: tempDirDownload,
84
- }).getElectronReleases('all');
85
- expect(result).toEqual(customBody);
86
- });
87
- });
88
- describe('getDependencyReleases', () => {
89
- test('parses Chrome versions', async () => {
90
- const result = await new ElectronInfo({
91
- releasesUrl: mockUrl,
92
- tempDirectory: tempDir,
93
- }).getDependencyReleases('chrome', '71.0.3578.98');
94
- expect(result.length).toBe(2);
95
- expect(result[0].deps).toBeDefined();
96
- expect(result[0].deps.chrome).toBe('71.0.3578.98');
97
- });
98
- test('parses Chrome SemVer', async () => {
99
- const result = await new ElectronInfo({
100
- releasesUrl: mockUrl,
101
- tempDirectory: tempDir,
102
- }).getDependencyReleases('chrome', '~66');
103
- // eslint-disable-next-line no-magic-numbers
104
- expect(result.length).toBe(56);
105
- });
106
- test('returns nothing for invalid versions', async () => {
107
- const result = await new ElectronInfo({
108
- releasesUrl: mockUrl,
109
- tempDirectory: tempDir,
110
- }).getDependencyReleases('chrome', 'invalid');
111
- expect(result.length).toBe(0);
112
- });
113
- test('limits releases', async () => {
114
- const limit = 2;
115
- const result = await new ElectronInfo({
116
- limit,
117
- releasesUrl: mockUrl,
118
- tempDirectory: tempDir,
119
- }).getDependencyReleases('chrome', 'all');
120
- expect(result.length).toBe(limit);
121
- });
122
- test('uses a local copy of the releases', async () => {
123
- nock(invalidUrl).get('/').reply(HTTP_STATUS.NOT_FOUND);
124
- await provideReleaseFile();
125
- await new ElectronInfo({
126
- releasesUrl: invalidUrl,
127
- tempDirectory: tempDirDownload,
128
- }).getDependencyReleases('chrome', 'all');
129
- });
130
- test('uses latest as alias for limit=1', async () => {
131
- const result = await new ElectronInfo({
132
- latest: true,
133
- releasesUrl: mockUrl,
134
- tempDirectory: tempDir,
135
- }).getElectronReleases('all');
136
- expect(result.length).toBe(1);
137
- expect(result[0].version).toBe('8.0.0-nightly.20190820');
138
- });
139
- });
140
- });
@@ -1,93 +0,0 @@
1
- import { isAfter as isAfterDate, sub as subtractDate } from 'date-fns';
2
- import { constants as fsConstants, promises as fs } from 'fs';
3
- import parseUrl from 'parse-url';
4
- import logdown from 'logdown';
5
- import os from 'os';
6
- import path from 'path';
7
- import { HTTPService } from './HTTPService.js';
8
- export class FileService {
9
- constructor(options) {
10
- this.options = options;
11
- this.logger = logdown('electron-info/FileService', {
12
- logger: console,
13
- markdown: false,
14
- });
15
- if (this.options.debug) {
16
- this.logger.state.isEnabled = true;
17
- }
18
- this.logger.log('Initialized', this.options);
19
- this.httpService = new HTTPService({
20
- debug: this.options.debug,
21
- timeout: this.options.timeout,
22
- });
23
- }
24
- async getReleases() {
25
- this.logger.log('Parsing releases URL', { releasesUrl: this.options.releasesUrl });
26
- const parsedUrl = parseUrl(this.options.releasesUrl);
27
- if (!parsedUrl.href) {
28
- throw new Error('Invalid releases URL provided');
29
- }
30
- if (parsedUrl.protocol === 'file') {
31
- this.logger.log('Releases URL points to a local file:', { releasesUrl: this.options.releasesUrl });
32
- return this.loadReleasesFile(path.resolve(this.options.releasesUrl));
33
- }
34
- this.logger.log('Releases URL points to a URL:', { releasesUrl: this.options.releasesUrl });
35
- const tempDirectory = await this.createTempDir();
36
- const tempFile = path.join(tempDirectory, 'latest.json');
37
- const tempFileExists = await this.isPathReadable(tempFile);
38
- if (this.options.forceUpdate) {
39
- this.logger.log(`Force download of the releases file requested`, {
40
- forceUpdate: this.options.forceUpdate,
41
- releasesUrl: this.options.releasesUrl,
42
- tempFile,
43
- });
44
- return this.httpService.downloadReleasesFile(this.options.releasesUrl, tempFile);
45
- }
46
- if (tempFileExists) {
47
- this.logger.log('Found a local copy of the releases file:', { tempFile });
48
- const tempFileFromToday = await this.isFileFromToday(tempFile);
49
- this.logger.log(`Releases file "${tempFile}" is less than 24 hours old:`, tempFileFromToday);
50
- if (tempFileFromToday) {
51
- return this.loadReleasesFile(tempFile);
52
- }
53
- }
54
- return this.httpService.downloadReleasesFile(this.options.releasesUrl, tempFile);
55
- }
56
- async createTempDir() {
57
- const tempDirectory = this.options.tempDirectory || path.join(os.tmpdir(), 'electron-info');
58
- const tempDirectoryExists = await this.isPathReadable(tempDirectory);
59
- if (!tempDirectoryExists) {
60
- this.logger.log('Creating temp directory', { tempDirectory });
61
- await fs.mkdir(tempDirectory);
62
- }
63
- else {
64
- this.logger.log('Temp directory exists', { tempDirectory });
65
- }
66
- return tempDirectory;
67
- }
68
- async isFileFromToday(fileName) {
69
- const { mtime: fileModifiedDate } = await fs.stat(fileName);
70
- this.logger.log(`File "${fileName}" is from "${fileModifiedDate.toString()}"`);
71
- const yesterday = subtractDate(new Date(), { days: 1 });
72
- return isAfterDate(fileModifiedDate, yesterday);
73
- }
74
- async isPathReadable(filePath) {
75
- try {
76
- await fs.access(filePath, fsConstants.F_OK | fsConstants.R_OK);
77
- return true;
78
- }
79
- catch (error) {
80
- this.logger.log('File is not readable:', { errorMessage: error.message });
81
- return false;
82
- }
83
- }
84
- async loadReleasesFile(localPath) {
85
- this.logger.log('Loading local releases file:', { localPath });
86
- const rawData = await fs.readFile(localPath, 'utf8');
87
- const releases = JSON.parse(rawData);
88
- if (!Array.isArray(releases)) {
89
- throw new Error('Invalid data in releases file');
90
- }
91
- return releases;
92
- }
93
- }
@@ -1,35 +0,0 @@
1
- import { promises as fs } from 'fs';
2
- import { inspect } from 'util';
3
- import axios from 'axios';
4
- import logdown from 'logdown';
5
- export class HTTPService {
6
- constructor(options) {
7
- this.options = options;
8
- this.logger = logdown('electron-info/HTTPService', {
9
- logger: console,
10
- markdown: false,
11
- });
12
- if (this.options.debug) {
13
- this.logger.state.isEnabled = true;
14
- }
15
- this.logger.log('Initialized', this.options);
16
- }
17
- async downloadReleasesFile(downloadUrl, targetFile) {
18
- this.logger.log('Downloading releases file:', { downloadUrl, targetFile });
19
- let releases = [];
20
- try {
21
- const response = await axios.get(downloadUrl, { timeout: this.options.timeout });
22
- releases = response.data;
23
- }
24
- catch (error) {
25
- throw new Error(`Request failed: "${error.message}"`);
26
- }
27
- // eslint-disable-next-line no-magic-numbers
28
- this.logger.info('Received data from server:', inspect(releases).toString().slice(0, 40), '...');
29
- if (!Array.isArray(releases)) {
30
- throw new Error('Invalid data received from server');
31
- }
32
- await fs.writeFile(targetFile, JSON.stringify(releases));
33
- return releases;
34
- }
35
- }
@@ -1,3 +0,0 @@
1
- {
2
- "type": "commonjs"
3
- }
@@ -1,70 +0,0 @@
1
- export interface RawDeps {
2
- chrome: string;
3
- modules: string;
4
- node: string;
5
- openssl: string;
6
- uv: string;
7
- v8: string;
8
- zlib: string;
9
- }
10
- export interface RawReleaseInfo {
11
- deps?: RawDeps;
12
- name: string;
13
- node_id: string;
14
- npm_dist_tags: string[];
15
- npm_package_name?: string;
16
- prerelease: boolean;
17
- published_at: string;
18
- tag_name: string;
19
- total_downloads: number;
20
- version: string;
21
- }
22
- export interface Options {
23
- /** Enable debug logging. Default: `false`. */
24
- debug?: boolean;
25
- /** If Electron prereleases should be included. Default: `true`. */
26
- electronPrereleases?: boolean;
27
- /** Force downloading the latest release file. Default: `false`. */
28
- forceUpdate?: boolean;
29
- /**
30
- * Include only the latest release. Alias for `limit=1`. Ignores `limit`.
31
- * Default: `false`.
32
- */
33
- latest?: boolean;
34
- /**
35
- * Limit output of releases. Everything below 1 will be treated as no limit.
36
- * Default: 0.
37
- */
38
- limit?: number;
39
- /**
40
- * Can be a URL or a local path. Default:
41
- * https://raw.githubusercontent.com/electron/releases/master/lite.json.
42
- */
43
- releasesUrl?: string;
44
- /**
45
- * Use a custom temporary directory. If not defined, the system's temporary
46
- * directory will be used.
47
- */
48
- tempDirectory?: string;
49
- /** Use a custom HTTP timeout in milliseconds. Default is `2000`. */
50
- timeout?: number;
51
- }
52
- export declare const SupportedDependencies: RawDeps;
53
- export declare class ElectronInfo {
54
- private readonly fileService;
55
- private readonly logger;
56
- private readonly options;
57
- constructor(options?: Options);
58
- getAllReleases(formatted: true, colored?: boolean): Promise<string>;
59
- getAllReleases(formatted?: false): Promise<RawReleaseInfo[]>;
60
- getDependencyReleases(dependency: keyof RawDeps, version: string, formatted?: false): Promise<RawReleaseInfo[]>;
61
- getDependencyReleases(dependency: keyof RawDeps, version: string, formatted: true, colored?: boolean): Promise<RawReleaseInfo[] | string>;
62
- getElectronReleases(version: string, formatted: true, colored?: boolean): Promise<string>;
63
- getElectronReleases(version: string, formatted?: false): Promise<RawReleaseInfo[]>;
64
- private buildFoundString;
65
- private buildRawTables;
66
- private formatDependencyReleases;
67
- private formatReleases;
68
- private getVersions;
69
- private limitReleases;
70
- }
@@ -1,155 +0,0 @@
1
- import chalk from 'chalk';
2
- import { format as formatDate } from 'date-fns';
3
- import { table as createTable } from 'table';
4
- import logdown from 'logdown';
5
- import semver from 'semver';
6
- import { FileService } from './FileService.js';
7
- const defaultOptions = {
8
- debug: false,
9
- electronPrereleases: true,
10
- forceUpdate: false,
11
- latest: false,
12
- limit: 0,
13
- releasesUrl: 'https://raw.githubusercontent.com/electron/releases/master/lite.json',
14
- tempDirectory: '',
15
- timeout: 2000,
16
- };
17
- export const SupportedDependencies = {
18
- chrome: 'Chrome',
19
- modules: 'Modules (Node ABI)',
20
- node: 'Node.js',
21
- openssl: 'OpenSSL',
22
- uv: 'uv',
23
- v8: 'V8',
24
- zlib: 'zlib',
25
- };
26
- export class ElectronInfo {
27
- constructor(options) {
28
- this.options = { ...defaultOptions, ...options };
29
- this.options.limit = Math.max(0, this.options.limit);
30
- this.logger = logdown('electron-info/ElectronInfo', {
31
- logger: console,
32
- markdown: false,
33
- });
34
- if (this.options.debug) {
35
- this.logger.state.isEnabled = true;
36
- }
37
- this.fileService = new FileService(this.options);
38
- this.logger.log('Initialized', this.options);
39
- }
40
- async getAllReleases(formatted, colored) {
41
- this.logger.log('Getting all releases:', { colored, formatted });
42
- const allReleases = await this.fileService.getReleases();
43
- const limitedReleases = this.limitReleases(allReleases);
44
- return formatted ? this.formatReleases(limitedReleases, colored) : limitedReleases;
45
- }
46
- async getDependencyReleases(dependency, version, formatted, colored) {
47
- this.logger.log('Getting dependency releases:', { colored, dependency, formatted, version });
48
- const allReleases = await this.fileService.getReleases();
49
- const dependencyVersions = await this.getVersions(allReleases, dependency, version);
50
- const filteredReleases = allReleases.filter(release => release.deps && dependencyVersions.includes(release.deps[dependency]));
51
- const limitedReleases = this.limitReleases(filteredReleases);
52
- return formatted ? this.formatDependencyReleases(limitedReleases, colored) : limitedReleases;
53
- }
54
- async getElectronReleases(version, formatted, colored) {
55
- this.logger.log('Getting Electron releases:', { colored, formatted, version });
56
- const allReleases = await this.fileService.getReleases();
57
- const electronVersions = await this.getVersions(allReleases, 'electron', version);
58
- const filteredReleases = allReleases.filter(release => electronVersions.includes(release.version));
59
- const limitedReleases = this.limitReleases(filteredReleases);
60
- return formatted ? this.formatReleases(limitedReleases, colored) : limitedReleases;
61
- }
62
- buildFoundString(releases) {
63
- this.logger.log('Building found string:', { releasesLength: releases.length });
64
- return `Found ${releases.length} release${releases.length === 1 ? '' : 's'}.`;
65
- }
66
- buildRawTables(releases, colored) {
67
- this.logger.log('Building raw tables:', { colored, releasesLength: releases.length });
68
- const coloredOrNot = (text, style) => (colored ? style(text) : text);
69
- return releases.map(release => {
70
- const electronVersion = `${release.version}${release.prerelease ? ' (prerelease)' : ''}`;
71
- const parsedDate = new Date(release.published_at);
72
- const releaseDate = formatDate(parsedDate, 'yyyy-MM-dd');
73
- const table = [
74
- [coloredOrNot('Electron', chalk.bold), electronVersion],
75
- [coloredOrNot('Published on', chalk.bold), releaseDate],
76
- ];
77
- if (release.deps) {
78
- table.push([coloredOrNot(SupportedDependencies.node, chalk.bold.red), release.deps.node], [coloredOrNot(SupportedDependencies.chrome, chalk.bold.green), release.deps.chrome], [coloredOrNot(SupportedDependencies.openssl, chalk.bold.blue), release.deps.openssl], [coloredOrNot(SupportedDependencies.modules, chalk.bold.yellow), release.deps.modules], [coloredOrNot(SupportedDependencies.uv, chalk.bold.cyan), release.deps.uv],
79
- // eslint-disable-next-line no-magic-numbers
80
- [coloredOrNot(SupportedDependencies.v8, chalk.bold.rgb(150, 150, 150)), release.deps.v8], [coloredOrNot(SupportedDependencies.zlib, chalk.bold.magenta), release.deps.zlib]);
81
- }
82
- return table;
83
- });
84
- }
85
- formatDependencyReleases(releases, colored) {
86
- this.logger.log('Formatting dependency releases:', { colored, releasesLength: releases.length });
87
- releases = releases.filter(release => !!release.deps);
88
- if (!releases.length) {
89
- return this.buildFoundString(releases);
90
- }
91
- const joinedReleases = this.buildRawTables(releases, colored)
92
- .map(table => createTable(table))
93
- .join('\n');
94
- return `${joinedReleases}\n${this.buildFoundString(releases)}`;
95
- }
96
- formatReleases(releases, colored) {
97
- this.logger.log('Formatting releases:', { colored, releasesLength: releases.length });
98
- if (!releases.length) {
99
- return this.buildFoundString(releases);
100
- }
101
- const joinedReleases = this.buildRawTables(releases, colored)
102
- .map(table => createTable(table))
103
- .join('\n');
104
- return `${joinedReleases}\n${this.buildFoundString(releases)}`;
105
- }
106
- async getVersions(releases, key, inputVersion) {
107
- this.logger.log('Getting versions:', { inputVersion, key });
108
- const satisfiesVersion = (dependencyVersion, inputVersion) => {
109
- const dependencyVersionClean = semver.clean(dependencyVersion, { loose: true }) || '';
110
- return semver.satisfies(dependencyVersionClean, inputVersion, {
111
- includePrerelease: true,
112
- loose: true,
113
- });
114
- };
115
- let dependencyVersions = [];
116
- if (!this.options.electronPrereleases) {
117
- const tempReleaseNumber = releases.length;
118
- releases = releases.filter(release => semver.prerelease(release.version) === null);
119
- this.logger.log('Removing electron prereleases from found versions', {
120
- after: releases.length,
121
- before: tempReleaseNumber,
122
- });
123
- }
124
- dependencyVersions = releases
125
- .filter(release => {
126
- if (key !== 'electron' && !release.deps) {
127
- return false;
128
- }
129
- if (inputVersion === 'all') {
130
- return true;
131
- }
132
- if (key === 'electron' && release.npm_dist_tags && release.npm_dist_tags.includes(inputVersion)) {
133
- return true;
134
- }
135
- return key === 'electron'
136
- ? satisfiesVersion(release.version, inputVersion)
137
- : satisfiesVersion(release.deps[key], inputVersion);
138
- })
139
- .map(release => (key === 'electron' ? release.version : release.deps[key]));
140
- return dependencyVersions;
141
- }
142
- limitReleases(releases) {
143
- const limit = this.options.limit || (this.options.latest ? 1 : undefined);
144
- if (limit) {
145
- const slicedArray = releases.slice(0, limit);
146
- this.logger.log('Limiting found versions', {
147
- after: slicedArray.length,
148
- before: releases.length,
149
- limit,
150
- });
151
- return slicedArray;
152
- }
153
- return releases;
154
- }
155
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,12 +0,0 @@
1
- import type { Options, RawReleaseInfo } from './ElectronInfo.js';
2
- export declare class FileService {
3
- private readonly httpService;
4
- private readonly logger;
5
- private readonly options;
6
- constructor(options: Required<Options>);
7
- getReleases(): Promise<RawReleaseInfo[]>;
8
- private createTempDir;
9
- private isFileFromToday;
10
- private isPathReadable;
11
- private loadReleasesFile;
12
- }
@@ -1,8 +0,0 @@
1
- import type { Options, RawReleaseInfo } from './ElectronInfo.js';
2
- export type HTTPOptions = Pick<Options, 'debug' | 'timeout'>;
3
- export declare class HTTPService {
4
- private readonly logger;
5
- private readonly options;
6
- constructor(options: Required<HTTPOptions>);
7
- downloadReleasesFile(downloadUrl: string, targetFile: string): Promise<RawReleaseInfo[]>;
8
- }
@@ -1 +0,0 @@
1
- export {};
@@ -1,29 +0,0 @@
1
- import { assert, describe, test, beforeEach, afterEach } from 'vitest';
2
- import { StatusCodes as HTTP_STATUS } from 'http-status-codes';
3
- import nock from 'nock';
4
- import { HTTPService } from './HTTPService.js';
5
- const mockUrl = 'http://example.com';
6
- const FIVE_SECONDS_IN_MILLIS = 5000;
7
- const HALF_SECOND_IN_MILLIS = 500;
8
- describe('HTTPService', () => {
9
- const httpService = new HTTPService({
10
- debug: false,
11
- timeout: HALF_SECOND_IN_MILLIS,
12
- });
13
- beforeEach(() => {
14
- nock(mockUrl)
15
- .get('/')
16
- .delayConnection(FIVE_SECONDS_IN_MILLIS)
17
- .reply(HTTP_STATUS.OK, [{ data: 'invalid' }]);
18
- });
19
- afterEach(() => nock.cleanAll());
20
- describe('downloadReleasesFile', () => {
21
- test('honors a custom timeout', async () => {
22
- try {
23
- await httpService.downloadReleasesFile(mockUrl, '');
24
- assert.fail('Should throw on timeout');
25
- }
26
- catch (error) { }
27
- });
28
- });
29
- });
package/dist/esm/cli.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
package/dist/esm/cli.js DELETED
@@ -1,123 +0,0 @@
1
- #!/usr/bin/env node
2
- import { program as commander } from 'commander';
3
- import { createRequire } from 'module';
4
- const require = createRequire(import.meta.url);
5
- import { ElectronInfo, SupportedDependencies } from './ElectronInfo.js';
6
- const { description, name, version } = require('../package.json');
7
- let matchedCommand = false;
8
- commander
9
- .name(name)
10
- .description(`${description}
11
-
12
- Allowed version argument inputs:
13
- - SemVer versions (e.g. "~7")
14
- - npm dist tags (e.g. "5-0-x", only Electron)
15
- - "all"`)
16
- .option('-d, --debug', 'enable debug logging')
17
- .option('-f, --force', 'force downloading the latest release file')
18
- .option('-L, --latest', 'list only the latest release (alias for --limit 1, ignores limit)')
19
- .option('-l, --limit <number>', 'limit output of releases')
20
- .option('-r, --raw', 'output raw JSON')
21
- .option('-s, --source <url>', 'use a custom releases source URL or path')
22
- .option('-t, --timeout <number>', 'use a custom HTTP timeout')
23
- .version(version, '-v, --version')
24
- .option('--no-colors', `don't use colors for displaying`)
25
- .option('--no-prereleases', `don't include Electron prereleases`);
26
- const commanderOptions = commander.opts();
27
- commander
28
- .command('electron')
29
- .alias('e')
30
- .description('show data for Electron releases')
31
- .arguments('[version]')
32
- .action(async (input) => {
33
- matchedCommand = true;
34
- if (!input) {
35
- console.error('No version specified.');
36
- commander.outputHelp();
37
- process.exit();
38
- }
39
- try {
40
- const electronInfo = new ElectronInfo({
41
- ...(commanderOptions.debug && { debug: true }),
42
- ...(commanderOptions.force && { forceUpdate: true }),
43
- ...(commanderOptions.latest && { latest: true }),
44
- ...(commanderOptions.limit && { limit: parseInt(commanderOptions.limit, 10) }),
45
- ...(typeof commanderOptions.prereleases !== 'undefined' && { electronPrereleases: commanderOptions.prereleases }),
46
- ...(commanderOptions.source && { releasesUrl: commanderOptions.source }),
47
- ...(commanderOptions.timeout && { timeout: parseInt(commanderOptions.timeout, 10) }),
48
- });
49
- const releases = commanderOptions.raw
50
- ? await electronInfo.getElectronReleases(input)
51
- : await electronInfo.getElectronReleases(input, true, commanderOptions.colors);
52
- console.info(releases);
53
- }
54
- catch (error) {
55
- console.error(error);
56
- process.exit(1);
57
- }
58
- });
59
- for (const [dependencyShortName, dependencyFullName] of Object.entries(SupportedDependencies)) {
60
- commander
61
- .command(dependencyShortName)
62
- .alias(dependencyShortName[0])
63
- .description(`show data for ${dependencyFullName} releases`)
64
- .arguments('[version]')
65
- .action(async (version) => {
66
- matchedCommand = true;
67
- if (!version) {
68
- console.error('No version specified.');
69
- commander.outputHelp();
70
- process.exit();
71
- }
72
- try {
73
- const electronInfo = new ElectronInfo({
74
- ...(commanderOptions.debug && { debug: true }),
75
- ...(commanderOptions.force && { forceUpdate: true }),
76
- ...(commanderOptions.latest && { latest: true }),
77
- ...(commanderOptions.limit && { limit: parseInt(commanderOptions.limit, 10) }),
78
- ...(typeof commanderOptions.prereleases !== 'undefined' && { electronPrereleases: commanderOptions.prereleases }),
79
- ...(commanderOptions.source && { releasesUrl: commanderOptions.source }),
80
- ...(commanderOptions.timeout && { timeout: commanderOptions.timeout }),
81
- });
82
- const releases = commanderOptions.raw
83
- ? await electronInfo.getDependencyReleases(dependencyShortName, version)
84
- : await electronInfo.getDependencyReleases(dependencyShortName, version, true, commanderOptions.colors);
85
- console.info(releases);
86
- }
87
- catch (error) {
88
- console.error(error);
89
- process.exit(1);
90
- }
91
- });
92
- }
93
- commander
94
- .command('all', { isDefault: true })
95
- .alias('a')
96
- .description('show data for all kinds of releases')
97
- .action(async () => {
98
- matchedCommand = true;
99
- try {
100
- const electronInfo = new ElectronInfo({
101
- ...(commanderOptions.debug && { debug: true }),
102
- ...(commanderOptions.force && { forceUpdate: true }),
103
- ...(commanderOptions.latest && { latest: true }),
104
- ...(commanderOptions.limit && { limit: parseInt(commanderOptions.limit, 10) }),
105
- ...(typeof commanderOptions.prereleases !== 'undefined' && { electronPrereleases: commanderOptions.prereleases }),
106
- ...(commanderOptions.source && { releasesUrl: commanderOptions.source }),
107
- ...(commanderOptions.timeout && { timeout: commanderOptions.timeout }),
108
- });
109
- const releases = commanderOptions.raw
110
- ? await electronInfo.getAllReleases()
111
- : await electronInfo.getAllReleases(true, commanderOptions.colors);
112
- console.info(releases);
113
- }
114
- catch (error) {
115
- console.error(error);
116
- process.exit(1);
117
- }
118
- });
119
- commander.parse(process.argv);
120
- if (!commander.args.length || !matchedCommand) {
121
- console.error('Invalid or no command specified.');
122
- commander.help();
123
- }
@@ -1 +0,0 @@
1
- export * from './ElectronInfo.js';
package/dist/esm/index.js DELETED
@@ -1 +0,0 @@
1
- export * from './ElectronInfo.js';
@@ -1,3 +0,0 @@
1
- {
2
- "type": "module"
3
- }
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes