electron-info 1.22.4 → 1.23.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.
Files changed (32) hide show
  1. package/README.md +1 -1
  2. package/dist/{esm/ElectronInfo.js → ElectronInfo.js} +1 -1
  3. package/dist/{esm/ElectronInfo.test.js → ElectronInfo.test.js} +3 -3
  4. package/dist/{esm/FileService.js → FileService.js} +5 -5
  5. package/dist/{esm/HTTPService.js → HTTPService.js} +2 -2
  6. package/dist/{esm/cli.js → cli.js} +34 -6
  7. package/package.json +11 -21
  8. package/dist/cjs/ElectronInfo.js +0 -172
  9. package/dist/cjs/ElectronInfo.test.js +0 -149
  10. package/dist/cjs/FileService.js +0 -112
  11. package/dist/cjs/HTTPService.js +0 -46
  12. package/dist/cjs/HTTPService.test.js +0 -38
  13. package/dist/cjs/cli.js +0 -108
  14. package/dist/cjs/package.json +0 -3
  15. package/dist/esm/ElectronInfo.d.ts +0 -70
  16. package/dist/esm/ElectronInfo.test.d.ts +0 -1
  17. package/dist/esm/FileService.d.ts +0 -12
  18. package/dist/esm/HTTPService.d.ts +0 -8
  19. package/dist/esm/HTTPService.test.d.ts +0 -1
  20. package/dist/esm/cli.d.ts +0 -2
  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.test.d.ts → ElectronInfo.test.d.ts} +0 -0
  26. /package/dist/{cjs/FileService.d.ts → FileService.d.ts} +0 -0
  27. /package/dist/{cjs/HTTPService.d.ts → HTTPService.d.ts} +0 -0
  28. /package/dist/{cjs/HTTPService.test.d.ts → HTTPService.test.d.ts} +0 -0
  29. /package/dist/{esm/HTTPService.test.js → HTTPService.test.js} +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
 
@@ -25,7 +25,7 @@ export const SupportedDependencies = {
25
25
  };
26
26
  export class ElectronInfo {
27
27
  constructor(options) {
28
- this.options = Object.assign(Object.assign({}, defaultOptions), options);
28
+ this.options = { ...defaultOptions, ...options };
29
29
  this.options.limit = Math.max(0, this.options.limit);
30
30
  this.logger = logdown('electron-info/ElectronInfo', {
31
31
  logger: console,
@@ -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 {
@@ -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)
@@ -37,7 +41,15 @@ commander
37
41
  process.exit();
38
42
  }
39
43
  try {
40
- const electronInfo = new ElectronInfo(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (commanderOptions.debug && { debug: true })), (commanderOptions.force && { forceUpdate: true })), (commanderOptions.latest && { latest: true })), (commanderOptions.limit && { limit: parseInt(commanderOptions.limit, 10) })), (typeof commanderOptions.prereleases !== 'undefined' && { electronPrereleases: commanderOptions.prereleases })), (commanderOptions.source && { releasesUrl: commanderOptions.source })), (commanderOptions.timeout && { timeout: parseInt(commanderOptions.timeout, 10) })));
44
+ const electronInfo = new ElectronInfo({
45
+ ...(commanderOptions.debug && { debug: true }),
46
+ ...(commanderOptions.force && { forceUpdate: true }),
47
+ ...(commanderOptions.latest && { latest: true }),
48
+ ...(commanderOptions.limit && { limit: parseInt(commanderOptions.limit, 10) }),
49
+ ...(typeof commanderOptions.prereleases !== 'undefined' && { electronPrereleases: commanderOptions.prereleases }),
50
+ ...(commanderOptions.source && { releasesUrl: commanderOptions.source }),
51
+ ...(commanderOptions.timeout && { timeout: parseInt(commanderOptions.timeout, 10) }),
52
+ });
41
53
  const releases = commanderOptions.raw
42
54
  ? await electronInfo.getElectronReleases(input)
43
55
  : await electronInfo.getElectronReleases(input, true, commanderOptions.colors);
@@ -62,7 +74,15 @@ for (const [dependencyShortName, dependencyFullName] of Object.entries(Supported
62
74
  process.exit();
63
75
  }
64
76
  try {
65
- const electronInfo = new ElectronInfo(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (commanderOptions.debug && { debug: true })), (commanderOptions.force && { forceUpdate: true })), (commanderOptions.latest && { latest: true })), (commanderOptions.limit && { limit: parseInt(commanderOptions.limit, 10) })), (typeof commanderOptions.prereleases !== 'undefined' && { electronPrereleases: commanderOptions.prereleases })), (commanderOptions.source && { releasesUrl: commanderOptions.source })), (commanderOptions.timeout && { timeout: commanderOptions.timeout })));
77
+ const electronInfo = new ElectronInfo({
78
+ ...(commanderOptions.debug && { debug: true }),
79
+ ...(commanderOptions.force && { forceUpdate: true }),
80
+ ...(commanderOptions.latest && { latest: true }),
81
+ ...(commanderOptions.limit && { limit: parseInt(commanderOptions.limit, 10) }),
82
+ ...(typeof commanderOptions.prereleases !== 'undefined' && { electronPrereleases: commanderOptions.prereleases }),
83
+ ...(commanderOptions.source && { releasesUrl: commanderOptions.source }),
84
+ ...(commanderOptions.timeout && { timeout: commanderOptions.timeout }),
85
+ });
66
86
  const releases = commanderOptions.raw
67
87
  ? await electronInfo.getDependencyReleases(dependencyShortName, version)
68
88
  : await electronInfo.getDependencyReleases(dependencyShortName, version, true, commanderOptions.colors);
@@ -81,7 +101,15 @@ commander
81
101
  .action(async () => {
82
102
  matchedCommand = true;
83
103
  try {
84
- const electronInfo = new ElectronInfo(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (commanderOptions.debug && { debug: true })), (commanderOptions.force && { forceUpdate: true })), (commanderOptions.latest && { latest: true })), (commanderOptions.limit && { limit: parseInt(commanderOptions.limit, 10) })), (typeof commanderOptions.prereleases !== 'undefined' && { electronPrereleases: commanderOptions.prereleases })), (commanderOptions.source && { releasesUrl: commanderOptions.source })), (commanderOptions.timeout && { timeout: commanderOptions.timeout })));
104
+ const electronInfo = new ElectronInfo({
105
+ ...(commanderOptions.debug && { debug: true }),
106
+ ...(commanderOptions.force && { forceUpdate: true }),
107
+ ...(commanderOptions.latest && { latest: true }),
108
+ ...(commanderOptions.limit && { limit: parseInt(commanderOptions.limit, 10) }),
109
+ ...(typeof commanderOptions.prereleases !== 'undefined' && { electronPrereleases: commanderOptions.prereleases }),
110
+ ...(commanderOptions.source && { releasesUrl: commanderOptions.source }),
111
+ ...(commanderOptions.timeout && { timeout: commanderOptions.timeout }),
112
+ });
85
113
  const releases = commanderOptions.raw
86
114
  ? await electronInfo.getAllReleases()
87
115
  : await electronInfo.getAllReleases(true, commanderOptions.colors);
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.4.5",
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.4",
62
- "gitHead": "28c184f53a87d8eb082cc27c923ef7b352bbe875"
51
+ "version": "1.23.0",
52
+ "gitHead": "f1a74d8ec9721d5b52a00e41b2ec73278e048290"
63
53
  }
@@ -1,172 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import chalk from 'chalk';
11
- import { format as formatDate } from 'date-fns';
12
- import { table as createTable } from 'table';
13
- import logdown from 'logdown';
14
- import semver from 'semver';
15
- import { FileService } from './FileService.js';
16
- const defaultOptions = {
17
- debug: false,
18
- electronPrereleases: true,
19
- forceUpdate: false,
20
- latest: false,
21
- limit: 0,
22
- releasesUrl: 'https://raw.githubusercontent.com/electron/releases/master/lite.json',
23
- tempDirectory: '',
24
- timeout: 2000,
25
- };
26
- export const SupportedDependencies = {
27
- chrome: 'Chrome',
28
- modules: 'Modules (Node ABI)',
29
- node: 'Node.js',
30
- openssl: 'OpenSSL',
31
- uv: 'uv',
32
- v8: 'V8',
33
- zlib: 'zlib',
34
- };
35
- export class ElectronInfo {
36
- constructor(options) {
37
- this.options = Object.assign(Object.assign({}, defaultOptions), options);
38
- this.options.limit = Math.max(0, this.options.limit);
39
- this.logger = logdown('electron-info/ElectronInfo', {
40
- logger: console,
41
- markdown: false,
42
- });
43
- if (this.options.debug) {
44
- this.logger.state.isEnabled = true;
45
- }
46
- this.fileService = new FileService(this.options);
47
- this.logger.log('Initialized', this.options);
48
- }
49
- getAllReleases(formatted, colored) {
50
- return __awaiter(this, void 0, void 0, function* () {
51
- this.logger.log('Getting all releases:', { colored, formatted });
52
- const allReleases = yield this.fileService.getReleases();
53
- const limitedReleases = this.limitReleases(allReleases);
54
- return formatted ? this.formatReleases(limitedReleases, colored) : limitedReleases;
55
- });
56
- }
57
- getDependencyReleases(dependency, version, formatted, colored) {
58
- return __awaiter(this, void 0, void 0, function* () {
59
- this.logger.log('Getting dependency releases:', { colored, dependency, formatted, version });
60
- const allReleases = yield this.fileService.getReleases();
61
- const dependencyVersions = yield this.getVersions(allReleases, dependency, version);
62
- const filteredReleases = allReleases.filter(release => release.deps && dependencyVersions.includes(release.deps[dependency]));
63
- const limitedReleases = this.limitReleases(filteredReleases);
64
- return formatted ? this.formatDependencyReleases(limitedReleases, colored) : limitedReleases;
65
- });
66
- }
67
- getElectronReleases(version, formatted, colored) {
68
- return __awaiter(this, void 0, void 0, function* () {
69
- this.logger.log('Getting Electron releases:', { colored, formatted, version });
70
- const allReleases = yield this.fileService.getReleases();
71
- const electronVersions = yield this.getVersions(allReleases, 'electron', version);
72
- const filteredReleases = allReleases.filter(release => electronVersions.includes(release.version));
73
- const limitedReleases = this.limitReleases(filteredReleases);
74
- return formatted ? this.formatReleases(limitedReleases, colored) : limitedReleases;
75
- });
76
- }
77
- buildFoundString(releases) {
78
- this.logger.log('Building found string:', { releasesLength: releases.length });
79
- return `Found ${releases.length} release${releases.length === 1 ? '' : 's'}.`;
80
- }
81
- buildRawTables(releases, colored) {
82
- this.logger.log('Building raw tables:', { colored, releasesLength: releases.length });
83
- const coloredOrNot = (text, style) => (colored ? style(text) : text);
84
- return releases.map(release => {
85
- const electronVersion = `${release.version}${release.prerelease ? ' (prerelease)' : ''}`;
86
- const parsedDate = new Date(release.published_at);
87
- const releaseDate = formatDate(parsedDate, 'yyyy-MM-dd');
88
- const table = [
89
- [coloredOrNot('Electron', chalk.bold), electronVersion],
90
- [coloredOrNot('Published on', chalk.bold), releaseDate],
91
- ];
92
- if (release.deps) {
93
- 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],
94
- // eslint-disable-next-line no-magic-numbers
95
- [coloredOrNot(SupportedDependencies.v8, chalk.bold.rgb(150, 150, 150)), release.deps.v8], [coloredOrNot(SupportedDependencies.zlib, chalk.bold.magenta), release.deps.zlib]);
96
- }
97
- return table;
98
- });
99
- }
100
- formatDependencyReleases(releases, colored) {
101
- this.logger.log('Formatting dependency releases:', { colored, releasesLength: releases.length });
102
- releases = releases.filter(release => !!release.deps);
103
- if (!releases.length) {
104
- return this.buildFoundString(releases);
105
- }
106
- const joinedReleases = this.buildRawTables(releases, colored)
107
- .map(table => createTable(table))
108
- .join('\n');
109
- return `${joinedReleases}\n${this.buildFoundString(releases)}`;
110
- }
111
- formatReleases(releases, colored) {
112
- this.logger.log('Formatting releases:', { colored, releasesLength: releases.length });
113
- if (!releases.length) {
114
- return this.buildFoundString(releases);
115
- }
116
- const joinedReleases = this.buildRawTables(releases, colored)
117
- .map(table => createTable(table))
118
- .join('\n');
119
- return `${joinedReleases}\n${this.buildFoundString(releases)}`;
120
- }
121
- getVersions(releases, key, inputVersion) {
122
- return __awaiter(this, void 0, void 0, function* () {
123
- this.logger.log('Getting versions:', { inputVersion, key });
124
- const satisfiesVersion = (dependencyVersion, inputVersion) => {
125
- const dependencyVersionClean = semver.clean(dependencyVersion, { loose: true }) || '';
126
- return semver.satisfies(dependencyVersionClean, inputVersion, {
127
- includePrerelease: true,
128
- loose: true,
129
- });
130
- };
131
- let dependencyVersions = [];
132
- if (!this.options.electronPrereleases) {
133
- const tempReleaseNumber = releases.length;
134
- releases = releases.filter(release => semver.prerelease(release.version) === null);
135
- this.logger.log('Removing electron prereleases from found versions', {
136
- after: releases.length,
137
- before: tempReleaseNumber,
138
- });
139
- }
140
- dependencyVersions = releases
141
- .filter(release => {
142
- if (key !== 'electron' && !release.deps) {
143
- return false;
144
- }
145
- if (inputVersion === 'all') {
146
- return true;
147
- }
148
- if (key === 'electron' && release.npm_dist_tags && release.npm_dist_tags.includes(inputVersion)) {
149
- return true;
150
- }
151
- return key === 'electron'
152
- ? satisfiesVersion(release.version, inputVersion)
153
- : satisfiesVersion(release.deps[key], inputVersion);
154
- })
155
- .map(release => (key === 'electron' ? release.version : release.deps[key]));
156
- return dependencyVersions;
157
- });
158
- }
159
- limitReleases(releases) {
160
- const limit = this.options.limit || (this.options.latest ? 1 : undefined);
161
- if (limit) {
162
- const slicedArray = releases.slice(0, limit);
163
- this.logger.log('Limiting found versions', {
164
- after: slicedArray.length,
165
- before: releases.length,
166
- limit,
167
- });
168
- return slicedArray;
169
- }
170
- return releases;
171
- }
172
- }
@@ -1,149 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { expect, describe, test, beforeEach, beforeAll, afterAll, afterEach } from 'vitest';
11
- import { StatusCodes as HTTP_STATUS } from 'http-status-codes';
12
- import nock from 'nock';
13
- import * as fs from 'fs-extra';
14
- import path from 'path';
15
- import { fileURLToPath } from 'url';
16
- import { randomUUID } from 'crypto';
17
- import { ElectronInfo } from './ElectronInfo.js';
18
- const __filename = fileURLToPath(import.meta.url);
19
- const __dirname = path.dirname(__filename);
20
- const tempDir = path.resolve(__dirname, '.temp');
21
- const tempDirDownload = path.resolve(__dirname, '.temp/download');
22
- const mockUrl = 'http://example.com';
23
- const invalidUrl = 'http://invalid.inv';
24
- const fixturesDir = path.resolve(__dirname, '../fixtures');
25
- const fullReleasesFile = path.join(fixturesDir, 'electron-releases-full.json');
26
- const createRandomBody = () => [
27
- {
28
- name: 'electron v8.0.0-nightly.20190820',
29
- node_id: randomUUID(),
30
- npm_dist_tags: [],
31
- prerelease: !!Math.round(Math.random()),
32
- published_at: new Date().toUTCString(),
33
- tag_name: 'v8.0.0-nightly.20190820',
34
- // eslint-disable-next-line no-magic-numbers
35
- total_downloads: Math.round(Math.random() * 1000),
36
- version: '8.0.0-nightly.20190820',
37
- },
38
- ];
39
- const provideReleaseFile = () => __awaiter(void 0, void 0, void 0, function* () {
40
- yield fs.copy(fullReleasesFile, path.join(tempDirDownload, 'latest.json'));
41
- });
42
- describe('ElectronInfo', () => {
43
- let releases;
44
- beforeAll(() => __awaiter(void 0, void 0, void 0, function* () {
45
- yield fs.ensureDir(tempDir);
46
- releases = yield fs.readFile(fullReleasesFile, 'utf8');
47
- }));
48
- beforeEach(() => {
49
- nock(mockUrl).get('/').reply(HTTP_STATUS.OK, releases);
50
- });
51
- afterAll(() => fs.remove(tempDir));
52
- afterEach(() => nock.cleanAll());
53
- describe('getElectronReleases', () => {
54
- test('parses Electron versions', () => __awaiter(void 0, void 0, void 0, function* () {
55
- const result = yield new ElectronInfo({
56
- releasesUrl: mockUrl,
57
- tempDirectory: tempDir,
58
- }).getElectronReleases('5.0.8');
59
- expect(result.length).toBe(1);
60
- expect(result[0].version).toBe('5.0.8');
61
- }));
62
- test('parses Electron SemVer', () => __awaiter(void 0, void 0, void 0, function* () {
63
- const result = yield new ElectronInfo({
64
- releasesUrl: mockUrl,
65
- tempDirectory: tempDir,
66
- }).getElectronReleases('^5');
67
- // eslint-disable-next-line no-magic-numbers
68
- expect(result.length).toBe(23);
69
- }));
70
- test('parses dist tags', () => __awaiter(void 0, void 0, void 0, function* () {
71
- const result = yield new ElectronInfo({
72
- releasesUrl: mockUrl,
73
- tempDirectory: tempDir,
74
- }).getElectronReleases('5-0-x');
75
- expect(result.length).toBe(1);
76
- }));
77
- test('returns nothing for invalid versions', () => __awaiter(void 0, void 0, void 0, function* () {
78
- const result = yield new ElectronInfo({
79
- releasesUrl: mockUrl,
80
- tempDirectory: tempDir,
81
- }).getElectronReleases('invalid');
82
- expect(result.length).toBe(0);
83
- }));
84
- test('forces downloading the release file', () => __awaiter(void 0, void 0, void 0, function* () {
85
- const customBody = createRandomBody();
86
- const customUrl = 'http://custom.com';
87
- yield provideReleaseFile();
88
- nock(customUrl).get('/').reply(HTTP_STATUS.OK, customBody);
89
- const result = yield new ElectronInfo({
90
- forceUpdate: true,
91
- releasesUrl: customUrl,
92
- tempDirectory: tempDirDownload,
93
- }).getElectronReleases('all');
94
- expect(result).toEqual(customBody);
95
- }));
96
- });
97
- describe('getDependencyReleases', () => {
98
- test('parses Chrome versions', () => __awaiter(void 0, void 0, void 0, function* () {
99
- const result = yield new ElectronInfo({
100
- releasesUrl: mockUrl,
101
- tempDirectory: tempDir,
102
- }).getDependencyReleases('chrome', '71.0.3578.98');
103
- expect(result.length).toBe(2);
104
- expect(result[0].deps).toBeDefined();
105
- expect(result[0].deps.chrome).toBe('71.0.3578.98');
106
- }));
107
- test('parses Chrome SemVer', () => __awaiter(void 0, void 0, void 0, function* () {
108
- const result = yield new ElectronInfo({
109
- releasesUrl: mockUrl,
110
- tempDirectory: tempDir,
111
- }).getDependencyReleases('chrome', '~66');
112
- // eslint-disable-next-line no-magic-numbers
113
- expect(result.length).toBe(56);
114
- }));
115
- test('returns nothing for invalid versions', () => __awaiter(void 0, void 0, void 0, function* () {
116
- const result = yield new ElectronInfo({
117
- releasesUrl: mockUrl,
118
- tempDirectory: tempDir,
119
- }).getDependencyReleases('chrome', 'invalid');
120
- expect(result.length).toBe(0);
121
- }));
122
- test('limits releases', () => __awaiter(void 0, void 0, void 0, function* () {
123
- const limit = 2;
124
- const result = yield new ElectronInfo({
125
- limit,
126
- releasesUrl: mockUrl,
127
- tempDirectory: tempDir,
128
- }).getDependencyReleases('chrome', 'all');
129
- expect(result.length).toBe(limit);
130
- }));
131
- test('uses a local copy of the releases', () => __awaiter(void 0, void 0, void 0, function* () {
132
- nock(invalidUrl).get('/').reply(HTTP_STATUS.NOT_FOUND);
133
- yield provideReleaseFile();
134
- yield new ElectronInfo({
135
- releasesUrl: invalidUrl,
136
- tempDirectory: tempDirDownload,
137
- }).getDependencyReleases('chrome', 'all');
138
- }));
139
- test('uses latest as alias for limit=1', () => __awaiter(void 0, void 0, void 0, function* () {
140
- const result = yield new ElectronInfo({
141
- latest: true,
142
- releasesUrl: mockUrl,
143
- tempDirectory: tempDir,
144
- }).getElectronReleases('all');
145
- expect(result.length).toBe(1);
146
- expect(result[0].version).toBe('8.0.0-nightly.20190820');
147
- }));
148
- });
149
- });
@@ -1,112 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { isAfter as isAfterDate, sub as subtractDate } from 'date-fns';
11
- import { constants as fsConstants, promises as fs } from 'fs';
12
- import parseUrl from 'parse-url';
13
- import logdown from 'logdown';
14
- import os from 'os';
15
- import path from 'path';
16
- import { HTTPService } from './HTTPService.js';
17
- export class FileService {
18
- constructor(options) {
19
- this.options = options;
20
- this.logger = logdown('electron-info/FileService', {
21
- logger: console,
22
- markdown: false,
23
- });
24
- if (this.options.debug) {
25
- this.logger.state.isEnabled = true;
26
- }
27
- this.logger.log('Initialized', this.options);
28
- this.httpService = new HTTPService({
29
- debug: this.options.debug,
30
- timeout: this.options.timeout,
31
- });
32
- }
33
- getReleases() {
34
- return __awaiter(this, void 0, void 0, function* () {
35
- this.logger.log('Parsing releases URL', { releasesUrl: this.options.releasesUrl });
36
- const parsedUrl = parseUrl(this.options.releasesUrl);
37
- if (!parsedUrl.href) {
38
- throw new Error('Invalid releases URL provided');
39
- }
40
- if (parsedUrl.protocol === 'file') {
41
- this.logger.log('Releases URL points to a local file:', { releasesUrl: this.options.releasesUrl });
42
- return this.loadReleasesFile(path.resolve(this.options.releasesUrl));
43
- }
44
- this.logger.log('Releases URL points to a URL:', { releasesUrl: this.options.releasesUrl });
45
- const tempDirectory = yield this.createTempDir();
46
- const tempFile = path.join(tempDirectory, 'latest.json');
47
- const tempFileExists = yield this.isPathReadable(tempFile);
48
- if (this.options.forceUpdate) {
49
- this.logger.log(`Force download of the releases file requested`, {
50
- forceUpdate: this.options.forceUpdate,
51
- releasesUrl: this.options.releasesUrl,
52
- tempFile,
53
- });
54
- return this.httpService.downloadReleasesFile(this.options.releasesUrl, tempFile);
55
- }
56
- if (tempFileExists) {
57
- this.logger.log('Found a local copy of the releases file:', { tempFile });
58
- const tempFileFromToday = yield this.isFileFromToday(tempFile);
59
- this.logger.log(`Releases file "${tempFile}" is less than 24 hours old:`, tempFileFromToday);
60
- if (tempFileFromToday) {
61
- return this.loadReleasesFile(tempFile);
62
- }
63
- }
64
- return this.httpService.downloadReleasesFile(this.options.releasesUrl, tempFile);
65
- });
66
- }
67
- createTempDir() {
68
- return __awaiter(this, void 0, void 0, function* () {
69
- const tempDirectory = this.options.tempDirectory || path.join(os.tmpdir(), 'electron-info');
70
- const tempDirectoryExists = yield this.isPathReadable(tempDirectory);
71
- if (!tempDirectoryExists) {
72
- this.logger.log('Creating temp directory', { tempDirectory });
73
- yield fs.mkdir(tempDirectory);
74
- }
75
- else {
76
- this.logger.log('Temp directory exists', { tempDirectory });
77
- }
78
- return tempDirectory;
79
- });
80
- }
81
- isFileFromToday(fileName) {
82
- return __awaiter(this, void 0, void 0, function* () {
83
- const { mtime: fileModifiedDate } = yield fs.stat(fileName);
84
- this.logger.log(`File "${fileName}" is from "${fileModifiedDate.toString()}"`);
85
- const yesterday = subtractDate(new Date(), { days: 1 });
86
- return isAfterDate(fileModifiedDate, yesterday);
87
- });
88
- }
89
- isPathReadable(filePath) {
90
- return __awaiter(this, void 0, void 0, function* () {
91
- try {
92
- yield fs.access(filePath, fsConstants.F_OK | fsConstants.R_OK);
93
- return true;
94
- }
95
- catch (error) {
96
- this.logger.log('File is not readable:', { errorMessage: error.message });
97
- return false;
98
- }
99
- });
100
- }
101
- loadReleasesFile(localPath) {
102
- return __awaiter(this, void 0, void 0, function* () {
103
- this.logger.log('Loading local releases file:', { localPath });
104
- const rawData = yield fs.readFile(localPath, 'utf8');
105
- const releases = JSON.parse(rawData);
106
- if (!Array.isArray(releases)) {
107
- throw new Error('Invalid data in releases file');
108
- }
109
- return releases;
110
- });
111
- }
112
- }
@@ -1,46 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { promises as fs } from 'fs';
11
- import { inspect } from 'util';
12
- import axios from 'axios';
13
- import logdown from 'logdown';
14
- export class HTTPService {
15
- constructor(options) {
16
- this.options = options;
17
- this.logger = logdown('electron-info/HTTPService', {
18
- logger: console,
19
- markdown: false,
20
- });
21
- if (this.options.debug) {
22
- this.logger.state.isEnabled = true;
23
- }
24
- this.logger.log('Initialized', this.options);
25
- }
26
- downloadReleasesFile(downloadUrl, targetFile) {
27
- return __awaiter(this, void 0, void 0, function* () {
28
- this.logger.log('Downloading releases file:', { downloadUrl, targetFile });
29
- let releases = [];
30
- try {
31
- const response = yield axios.get(downloadUrl, { timeout: this.options.timeout });
32
- releases = response.data;
33
- }
34
- catch (error) {
35
- throw new Error(`Request failed: "${error.message}"`);
36
- }
37
- // eslint-disable-next-line no-magic-numbers
38
- this.logger.info('Received data from server:', inspect(releases).toString().slice(0, 40), '...');
39
- if (!Array.isArray(releases)) {
40
- throw new Error('Invalid data received from server');
41
- }
42
- yield fs.writeFile(targetFile, JSON.stringify(releases));
43
- return releases;
44
- });
45
- }
46
- }
@@ -1,38 +0,0 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
- import { assert, describe, test, beforeEach, afterEach } from 'vitest';
11
- import { StatusCodes as HTTP_STATUS } from 'http-status-codes';
12
- import nock from 'nock';
13
- import { HTTPService } from './HTTPService.js';
14
- const mockUrl = 'http://example.com';
15
- const FIVE_SECONDS_IN_MILLIS = 5000;
16
- const HALF_SECOND_IN_MILLIS = 500;
17
- describe('HTTPService', () => {
18
- const httpService = new HTTPService({
19
- debug: false,
20
- timeout: HALF_SECOND_IN_MILLIS,
21
- });
22
- beforeEach(() => {
23
- nock(mockUrl)
24
- .get('/')
25
- .delayConnection(FIVE_SECONDS_IN_MILLIS)
26
- .reply(HTTP_STATUS.OK, [{ data: 'invalid' }]);
27
- });
28
- afterEach(() => nock.cleanAll());
29
- describe('downloadReleasesFile', () => {
30
- test('honors a custom timeout', () => __awaiter(void 0, void 0, void 0, function* () {
31
- try {
32
- yield httpService.downloadReleasesFile(mockUrl, '');
33
- assert.fail('Should throw on timeout');
34
- }
35
- catch (error) { }
36
- }));
37
- });
38
- });
package/dist/cjs/cli.js DELETED
@@ -1,108 +0,0 @@
1
- #!/usr/bin/env node
2
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
- return new (P || (P = Promise))(function (resolve, reject) {
5
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
- step((generator = generator.apply(thisArg, _arguments || [])).next());
9
- });
10
- };
11
- import { program as commander } from 'commander';
12
- import { createRequire } from 'module';
13
- const require = createRequire(import.meta.url);
14
- import { ElectronInfo, SupportedDependencies } from './ElectronInfo.js';
15
- const { description, name, version } = require('../package.json');
16
- let matchedCommand = false;
17
- commander
18
- .name(name)
19
- .description(`${description}
20
-
21
- Allowed version argument inputs:
22
- - SemVer versions (e.g. "~7")
23
- - npm dist tags (e.g. "5-0-x", only Electron)
24
- - "all"`)
25
- .option('-d, --debug', 'enable debug logging')
26
- .option('-f, --force', 'force downloading the latest release file')
27
- .option('-L, --latest', 'list only the latest release (alias for --limit 1, ignores limit)')
28
- .option('-l, --limit <number>', 'limit output of releases')
29
- .option('-r, --raw', 'output raw JSON')
30
- .option('-s, --source <url>', 'use a custom releases source URL or path')
31
- .option('-t, --timeout <number>', 'use a custom HTTP timeout')
32
- .version(version, '-v, --version')
33
- .option('--no-colors', `don't use colors for displaying`)
34
- .option('--no-prereleases', `don't include Electron prereleases`);
35
- const commanderOptions = commander.opts();
36
- commander
37
- .command('electron')
38
- .alias('e')
39
- .description('show data for Electron releases')
40
- .arguments('[version]')
41
- .action((input) => __awaiter(void 0, void 0, void 0, function* () {
42
- matchedCommand = true;
43
- if (!input) {
44
- console.error('No version specified.');
45
- commander.outputHelp();
46
- process.exit();
47
- }
48
- try {
49
- const electronInfo = new ElectronInfo(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (commanderOptions.debug && { debug: true })), (commanderOptions.force && { forceUpdate: true })), (commanderOptions.latest && { latest: true })), (commanderOptions.limit && { limit: parseInt(commanderOptions.limit, 10) })), (typeof commanderOptions.prereleases !== 'undefined' && { electronPrereleases: commanderOptions.prereleases })), (commanderOptions.source && { releasesUrl: commanderOptions.source })), (commanderOptions.timeout && { timeout: parseInt(commanderOptions.timeout, 10) })));
50
- const releases = commanderOptions.raw
51
- ? yield electronInfo.getElectronReleases(input)
52
- : yield electronInfo.getElectronReleases(input, true, commanderOptions.colors);
53
- console.info(releases);
54
- }
55
- catch (error) {
56
- console.error(error);
57
- process.exit(1);
58
- }
59
- }));
60
- for (const [dependencyShortName, dependencyFullName] of Object.entries(SupportedDependencies)) {
61
- commander
62
- .command(dependencyShortName)
63
- .alias(dependencyShortName[0])
64
- .description(`show data for ${dependencyFullName} releases`)
65
- .arguments('[version]')
66
- .action((version) => __awaiter(void 0, void 0, void 0, function* () {
67
- matchedCommand = true;
68
- if (!version) {
69
- console.error('No version specified.');
70
- commander.outputHelp();
71
- process.exit();
72
- }
73
- try {
74
- const electronInfo = new ElectronInfo(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (commanderOptions.debug && { debug: true })), (commanderOptions.force && { forceUpdate: true })), (commanderOptions.latest && { latest: true })), (commanderOptions.limit && { limit: parseInt(commanderOptions.limit, 10) })), (typeof commanderOptions.prereleases !== 'undefined' && { electronPrereleases: commanderOptions.prereleases })), (commanderOptions.source && { releasesUrl: commanderOptions.source })), (commanderOptions.timeout && { timeout: commanderOptions.timeout })));
75
- const releases = commanderOptions.raw
76
- ? yield electronInfo.getDependencyReleases(dependencyShortName, version)
77
- : yield electronInfo.getDependencyReleases(dependencyShortName, version, true, commanderOptions.colors);
78
- console.info(releases);
79
- }
80
- catch (error) {
81
- console.error(error);
82
- process.exit(1);
83
- }
84
- }));
85
- }
86
- commander
87
- .command('all', { isDefault: true })
88
- .alias('a')
89
- .description('show data for all kinds of releases')
90
- .action(() => __awaiter(void 0, void 0, void 0, function* () {
91
- matchedCommand = true;
92
- try {
93
- const electronInfo = new ElectronInfo(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign(Object.assign({}, (commanderOptions.debug && { debug: true })), (commanderOptions.force && { forceUpdate: true })), (commanderOptions.latest && { latest: true })), (commanderOptions.limit && { limit: parseInt(commanderOptions.limit, 10) })), (typeof commanderOptions.prereleases !== 'undefined' && { electronPrereleases: commanderOptions.prereleases })), (commanderOptions.source && { releasesUrl: commanderOptions.source })), (commanderOptions.timeout && { timeout: commanderOptions.timeout })));
94
- const releases = commanderOptions.raw
95
- ? yield electronInfo.getAllReleases()
96
- : yield electronInfo.getAllReleases(true, commanderOptions.colors);
97
- console.info(releases);
98
- }
99
- catch (error) {
100
- console.error(error);
101
- process.exit(1);
102
- }
103
- }));
104
- commander.parse(process.argv);
105
- if (!commander.args.length || !matchedCommand) {
106
- console.error('Invalid or no command specified.');
107
- commander.help();
108
- }
@@ -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 +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 {};
package/dist/esm/cli.d.ts DELETED
@@ -1,2 +0,0 @@
1
- #!/usr/bin/env node
2
- export {};
@@ -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