Compare commits

...
Author SHA1 Message Date
Felix Rieseberg ebf421ebed wip: Properly select Node version 2019-12-12 15:20:13 -05:00
Felix Rieseberg 41409f578e wip: Even more stuff 2019-12-12 14:58:34 -05:00
13 changed files with 365 additions and 60 deletions
+11 -3
View File
@@ -4,7 +4,7 @@ export type Files = Map<string, string>;
export type FileTransform = (files: Files) => Promise<Files>;
export enum ElectronVersionState {
export enum VersionState {
ready = 'ready',
downloading = 'downloading',
unknown = 'unknown'
@@ -14,12 +14,20 @@ export enum ElectronVersionSource {
remote = 'remote',
local = 'local'
}
export interface NpmVersion {
export interface Version {
version: string;
}
export interface NpmVersion extends Version {
name?: string;
localPath?: string;
}
export interface NodeVersion extends Version {
state: VersionState;
}
export interface EditorValues {
main: string;
renderer: string;
@@ -29,7 +37,7 @@ export interface EditorValues {
}
export interface ElectronVersion extends NpmVersion {
state: ElectronVersionState;
state: VersionState;
source: ElectronVersionSource;
}
@@ -3,9 +3,9 @@ import { ItemPredicate, ItemRenderer, Select } from '@blueprintjs/select';
import { observer } from 'mobx-react';
import * as React from 'react';
import { ElectronVersion, ElectronVersionSource, ElectronVersionState } from '../../interfaces';
import { ElectronVersion, ElectronVersionSource, VersionState } from '../../interfaces';
import { highlightText } from '../../utils/highlight-text';
import { sortedElectronMap } from '../../utils/sorted-electron-map';
import { sortedElectronMap } from '../../utils/sorted-map';
import { AppState } from '../state';
import { getReleaseChannel } from '../versions';
@@ -24,11 +24,11 @@ export function getItemLabel({ source, state, name }: ElectronVersion): string {
if (source === ElectronVersionSource.local) {
label = name || 'Local';
} else {
if (state === ElectronVersionState.unknown) {
if (state === VersionState.unknown) {
label = `Not downloaded`;
} else if (state === ElectronVersionState.ready) {
} else if (state === VersionState.ready) {
label = `Downloaded`;
} else if (state === ElectronVersionState.downloading) {
} else if (state === VersionState.downloading) {
label = `Downloading`;
}
}
@@ -127,7 +127,7 @@ export const getVersionsFromAppState = (appState: AppState) => {
* @extends {React.Component<VersionChooserProps, VersionChooserState>}
*/
@observer
export class VersionChooser extends React.Component<VersionChooserProps, VersionChooserState> {
export class ElectronVersionChooser extends React.Component<VersionChooserProps, VersionChooserState> {
constructor(props: VersionChooserProps) {
super(props);
@@ -0,0 +1,151 @@
import { Button, ButtonGroup, MenuItem } from '@blueprintjs/core';
import { ItemPredicate, ItemRenderer, Select } from '@blueprintjs/select';
import { observer } from 'mobx-react';
import * as React from 'react';
import { ElectronVersion, NodeVersion, VersionState } from '../../interfaces';
import { highlightText } from '../../utils/highlight-text';
import { sortedNodeMap } from '../../utils/sorted-map';
import { AppState } from '../state';
const ElectronVersionSelect = Select.ofType<NodeVersion>();
/**
* Helper method: Returns the <Select /> label for an Electron
* version.
*
* @param {ElectronVersion} { source, state }
* @returns {string}
*/
export function getItemLabel({ state }: NodeVersion): string {
let label = '';
if (state === VersionState.unknown) {
label = `Not downloaded`;
} else if (state === VersionState.ready) {
label = `Downloaded`;
} else if (state === VersionState.downloading) {
label = `Downloading`;
}
return label;
}
/**
* Helper method: Returns the <Select /> icon for an Electron
* version.
*
* @param {ElectronVersion} { state }
* @returns
*/
export function getItemIcon({ state }: NodeVersion) {
return state === 'ready'
? 'saved'
: state === 'downloading' ? 'cloud-download' : 'cloud';
}
/**
* Helper method: Returns the <Select /> predicate for an Electron
* version.
*
* @param {string} query
* @param {ElectronVersion} { version }
* @returns
*/
export const filterItem: ItemPredicate<NodeVersion> = (query, { version }) => {
return version.toLowerCase().includes(query.toLowerCase());
};
/**
* Helper method: Returns the <Select /> <MenuItem /> for Electron
* versions.
*
* @param {ElectronVersion} item
* @param {IItemRendererProps} { handleClick, modifiers, query }
* @returns
*/
export const renderItem: ItemRenderer<NodeVersion> = (item, { handleClick, modifiers, query }) => {
if (!modifiers.matchesPredicate) {
return null;
}
return (
<MenuItem
active={modifiers.active}
disabled={modifiers.disabled}
text={highlightText(item.version, query)}
key={item.version}
onClick={handleClick}
label={getItemLabel(item)}
icon={getItemIcon(item)}
/>
);
};
export interface VersionChooserState {
value: string;
}
export interface VersionChooserProps {
appState: AppState;
}
export const getVersionsFromAppState = (appState: AppState) => {
const { nodeVersions } = appState;
return sortedNodeMap<NodeVersion>(nodeVersions, (_key, item) => item)
.filter((item) => !!item);
};
/**
* A dropdown allowing the selection of Electron versions. The actual
* download is managed in the state.
*
* @class VersionChooser
* @extends {React.Component<VersionChooserProps, VersionChooserState>}
*/
@observer
export class NodeVersionChooser extends React.Component<VersionChooserProps, VersionChooserState> {
constructor(props: VersionChooserProps) {
super(props);
this.onItemSelect = this.onItemSelect.bind(this);
}
/**
* Handle change, which usually means that we'd like update
* the selection version.
*
* @param {React.ChangeEvent<HTMLSelectElement>} event
*/
public onItemSelect({ version }: ElectronVersion) {
this.props.appState.setNodeVersion(version);
}
public render() {
const { currentNodeVersion, Bisector } = this.props.appState;
const { version } = currentNodeVersion;
return (
<ButtonGroup>
<ElectronVersionSelect
filterable={true}
items={getVersionsFromAppState(this.props.appState)}
itemRenderer={renderItem}
itemPredicate={filterItem}
onItemSelect={this.onItemSelect}
noResults={<MenuItem disabled={true} text='No results.' />}
disabled={!!Bisector}
>
<Button
className='version-chooser'
text={`Node v${version}`}
icon={getItemIcon(currentNodeVersion)}
disabled={!!Bisector}
/>
</ElectronVersionSelect>
</ButtonGroup>
);
}
}
+3 -3
View File
@@ -2,7 +2,7 @@ import { Button, IButtonProps, Spinner } from '@blueprintjs/core';
import { observer } from 'mobx-react';
import * as React from 'react';
import { ElectronVersionState } from '../../interfaces';
import { VersionState } from '../../interfaces';
import { AppState } from '../state';
export interface RunnerState {
@@ -27,11 +27,11 @@ export class Runner extends React.Component<RunnerProps, RunnerState> {
const state = currentElectronVersion && currentElectronVersion.state;
const props: IButtonProps = { className: 'button-run' };
if (state === ElectronVersionState.downloading) {
if (state === VersionState.downloading) {
props.text = 'Downloading';
props.disabled = true;
props.icon = <Spinner size={16} />;
} else if (state === ElectronVersionState.ready) {
} else if (state === VersionState.ready) {
if (isRunning) {
props.active = true;
props.text = 'Stop';
+19 -2
View File
@@ -6,9 +6,10 @@ import { AppState } from '../state';
import { AddressBar } from './commands-address-bar';
import { BisectHandler } from './commands-bisect';
import { EditorDropdown } from './commands-editors';
import { ElectronVersionChooser } from './commands-electron-chooser';
import { NodeVersionChooser } from './commands-node-chooser';
import { PublishButton } from './commands-publish-button';
import { Runner } from './commands-runner';
import { VersionChooser } from './commands-version-chooser';
export interface CommandsProps {
appState: AppState;
@@ -35,7 +36,7 @@ export class Commands extends React.Component<CommandsProps, {}> {
<div className='commands'>
<div>
<ControlGroup fill={true} vertical={false}>
<VersionChooser appState={appState} />
{this.getVersionChooser()}
<Runner appState={appState} />
</ControlGroup>
{
@@ -54,6 +55,12 @@ export class Commands extends React.Component<CommandsProps, {}> {
text='Console'
onClick={appState.toggleConsole}
/>
<Button
active={appState.isNodeMode}
icon='ninja'
text='Node.js Mode'
onClick={appState.toggleNodeMode}
/>
<EditorDropdown appState={appState} />
</ControlGroup>
</div>
@@ -64,4 +71,14 @@ export class Commands extends React.Component<CommandsProps, {}> {
</div>
);
}
public getVersionChooser() {
const { appState } = this.props;
if (appState.isNodeMode) {
return <NodeVersionChooser appState={appState} />;
} else {
return <ElectronVersionChooser appState={appState} />;
}
}
}
+1 -1
View File
@@ -6,7 +6,7 @@ import * as React from 'react';
import { ElectronVersion } from '../../interfaces';
import { Bisector } from '../bisect';
import { AppState } from '../state';
import { filterItem, getItemIcon, getVersionsFromAppState, renderItem } from './commands-version-chooser';
import { filterItem, getItemIcon, getVersionsFromAppState, renderItem } from './commands-electron-chooser';
const ElectronVersionSelect = Select.ofType<ElectronVersion>();
@@ -12,9 +12,9 @@ import {
import { observer } from 'mobx-react';
import * as React from 'react';
import { ElectronVersion, ElectronVersionSource, ElectronVersionState } from '../../interfaces';
import { ElectronVersion, ElectronVersionSource, VersionState } from '../../interfaces';
import { normalizeVersion } from '../../utils/normalize-version';
import { sortedElectronMap } from '../../utils/sorted-electron-map';
import { sortedElectronMap } from '../../utils/sorted-map';
import { AppState } from '../state';
import { ElectronReleaseChannel, getReleaseChannel } from '../versions';
@@ -69,7 +69,7 @@ export class ElectronSettings extends React.Component<ElectronSettingsProps, Ele
if (!checked) {
appState.statesToShow = appState.statesToShow.filter((s) => s !== id);
} else {
appState.statesToShow.push(id as ElectronVersionState);
appState.statesToShow.push(id as VersionState);
}
}
@@ -202,7 +202,7 @@ export class ElectronSettings extends React.Component<ElectronSettingsProps, Ele
*/
private renderVersionStateOptions(): JSX.Element {
const { appState } = this.props;
const getIsChecked = (state: ElectronVersionState) => {
const getIsChecked = (state: VersionState) => {
return appState.statesToShow.includes(state);
};
@@ -211,21 +211,21 @@ export class ElectronSettings extends React.Component<ElectronSettingsProps, Ele
label='Include Electron versions that are:'
>
<Checkbox
checked={getIsChecked(ElectronVersionState.downloading)}
checked={getIsChecked(VersionState.downloading)}
label='Downloading'
id='downloading'
onChange={this.handleStateChange}
inline={true}
/>
<Checkbox
checked={getIsChecked(ElectronVersionState.ready)}
checked={getIsChecked(VersionState.ready)}
label='Downloaded'
id='ready'
onChange={this.handleStateChange}
inline={true}
/>
<Checkbox
checked={getIsChecked(ElectronVersionState.unknown)}
checked={getIsChecked(VersionState.unknown)}
label='Not Downloaded'
id='unknown'
onChange={this.handleStateChange}
@@ -350,10 +350,10 @@ export class ElectronSettings extends React.Component<ElectronSettingsProps, Ele
let icon: IconName = 'box';
let humanState = 'Downloaded';
if (state === ElectronVersionState.downloading) {
if (state === VersionState.downloading) {
icon = 'cloud-download';
humanState = 'Downloading';
} else if (state === ElectronVersionState.unknown) {
} else if (state === VersionState.unknown) {
icon = 'cloud';
humanState = 'Not downloaded';
}
+1 -1
View File
@@ -3,7 +3,7 @@ import { when } from 'mobx';
import { EditorId, EditorValues } from '../interfaces';
import { INDEX_HTML_NAME, MAIN_JS_NAME, PRELOAD_JS_NAME, RENDERER_JS_NAME } from '../shared-constants';
import { getOctokit } from '../utils/octokit';
import { sortedElectronMap } from '../utils/sorted-electron-map';
import { sortedElectronMap } from '../utils/sorted-map';
import { ELECTRON_ORG, ELECTRON_REPO } from './constants';
import { getContent } from './content';
import { AppState } from './state';
+71 -10
View File
@@ -8,11 +8,12 @@ import {
EditorId,
ElectronVersion,
ElectronVersionSource,
ElectronVersionState,
MosaicId,
NodeVersion,
NpmVersion,
OutputEntry,
OutputOptions,
VersionState,
WarningDialogTexts
} from '../interfaces';
import { IpcEvents } from '../ipc-events';
@@ -34,14 +35,16 @@ import { activateTheme } from './themes';
import {
addLocalVersion,
ElectronReleaseChannel,
getAllElectronVersions,
getDefaultVersion,
getElectronVersions,
getUpdatedElectronVersions,
getUpdatedNodeVersions,
saveLocalVersions
} from './versions';
const knownVersions = getElectronVersions();
const knownVersions = getAllElectronVersions();
const defaultVersion = getDefaultVersion(knownVersions);
const defaultNodeVersion = '12.0.0';
/**
* Editors exist outside of React's world. To make things *a lot*
@@ -66,6 +69,7 @@ window.ElectronFiddle = window.ElectronFiddle || {
export class AppState {
// -- Persisted settings ------------------
@observable public version: string = defaultVersion;
@observable public nodeVersion: string = defaultNodeVersion;
@observable public theme: string | null = localStorage.getItem('theme');
@observable public gitHubAvatarUrl: string | null = localStorage.getItem('gitHubAvatarUrl');
@observable public gitHubName: string | null = localStorage.getItem('gitHubName');
@@ -75,9 +79,9 @@ export class AppState {
@observable public versionsToShow: Array<ElectronReleaseChannel> =
this.retrieve('versionsToShow') as Array<ElectronReleaseChannel>
|| [ElectronReleaseChannel.stable, ElectronReleaseChannel.beta];
@observable public statesToShow: Array<ElectronVersionState> =
this.retrieve('statesToShow') as Array<ElectronVersionState>
|| [ElectronVersionState.downloading, ElectronVersionState.ready, ElectronVersionState.unknown];
@observable public statesToShow: Array<VersionState> =
this.retrieve('statesToShow') as Array<VersionState>
|| [VersionState.downloading, VersionState.ready, VersionState.unknown];
@observable public isKeepingUserDataDirs: boolean = !!this.retrieve('isKeepingUserDataDirs');
@observable public isEnablingElectronLogging: boolean = !!this.retrieve('isEnablingElectronLogging');
@observable public isClearingConsoleOnRun: boolean = !!this.retrieve('isClearingConsoleOnRun');
@@ -85,6 +89,7 @@ export class AppState {
// -- Various session-only state ------------------
@observable public gistId: string = '';
@observable public versions: Record<string, ElectronVersion> = arrayToStringMap(knownVersions);
@observable public nodeVersions: Record<string, NodeVersion> = arrayToStringMap([] as Array<NodeVersion>);
@observable public output: Array<OutputEntry> = [];
@observable public localPath: string | undefined;
@observable public warningDialogTexts = { label: '', ok: 'Okay', cancel: 'Cancel' };
@@ -113,6 +118,7 @@ export class AppState {
@observable public isBisectDialogShowing: boolean = false;
@observable public isAddVersionDialogShowing: boolean = false;
@observable public isThemeDialogShowing: boolean = false;
@observable public isNodeMode: boolean = false;
@observable public isTourShowing: boolean = !localStorage.getItem('hasShownTour');
// -- Editor Values stored when we close the editor ------------------
@@ -130,11 +136,13 @@ export class AppState {
this.pushOutput = this.pushOutput.bind(this);
this.removeVersion = this.removeVersion.bind(this);
this.setVersion = this.setVersion.bind(this);
this.setNodeVersion = this.setNodeVersion.bind(this);
this.showTour = this.showTour.bind(this);
this.signOutGitHub = this.signOutGitHub.bind(this);
this.toggleBisectCommands = this.toggleBisectCommands.bind(this);
this.toggleAuthDialog = this.toggleAuthDialog.bind(this);
this.toggleConsole = this.toggleConsole.bind(this);
this.toggleNodeMode = this.toggleNodeMode.bind(this);
this.clearConsole = this.clearConsole.bind(this);
this.toggleSettings = this.toggleSettings.bind(this);
this.toggleBisectDialog = this.toggleBisectDialog.bind(this);
@@ -196,6 +204,7 @@ export class AppState {
// Update our known versions
this.updateElectronVersions();
this.updateNodeVersions();
// Make sure the console isn't all empty and sad
this.pushOutput('Console ready 🔬');
@@ -213,6 +222,18 @@ export class AppState {
}
}
/**
* Returns the current NodeVersion or the first
* one that can be found.
*/
@computed get currentNodeVersion(): NodeVersion {
if (this.nodeVersions[this.nodeVersion]) {
return this.nodeVersions[this.nodeVersion];
} else {
return this.nodeVersions[defaultNodeVersion];
}
}
/**
* Update the Electron versions: First, fetch them from GitHub,
* then update their respective downloaded state.
@@ -233,6 +254,21 @@ export class AppState {
this.isUpdatingElectronVersions = false;
}
/**
* Update the Node versions: First, fetch them from Node.js,
* then update their respective downloaded state.
*
* Fails silently.
*/
@action public async updateNodeVersions() {
try {
const nodeVersions = await getUpdatedNodeVersions();
this.nodeVersions = arrayToStringMap(nodeVersions);
} catch (error) {
console.warn(`State: Could not update Node.js versions`, error);
}
}
@action public async getName() {
if (!this.name) {
this.name = await getName(this);
@@ -245,6 +281,10 @@ export class AppState {
this.isConsoleShowing = !this.isConsoleShowing;
}
@action public toggleNodeMode() {
this.isNodeMode = !this.isNodeMode;
}
@action public clearConsole() {
this.output = [];
}
@@ -332,7 +372,7 @@ export class AppState {
@action public addLocalVersion(input: NpmVersion) {
addLocalVersion(input);
this.versions = arrayToStringMap(getElectronVersions());
this.versions = arrayToStringMap(getAllElectronVersions());
this.updateDownloadedVersionState();
}
@@ -368,7 +408,7 @@ export class AppState {
saveLocalVersions(versionsAsArray);
} else {
await this.binaryManager.remove(version);
updatedVersions[version].state = ElectronVersionState.unknown;
updatedVersions[version].state = VersionState.unknown;
}
this.versions = updatedVersions;
@@ -394,7 +434,7 @@ export class AppState {
console.log(`State: Instructing BinaryManager to fetch v${version}`);
const updatedVersions = { ...this.versions };
updatedVersions[version] = updatedVersions[version] || {};
updatedVersions[version].state = ElectronVersionState.downloading;
updatedVersions[version].state = VersionState.downloading;
this.versions = updatedVersions;
await this.binaryManager.setup(version);
@@ -404,6 +444,27 @@ export class AppState {
}
}
/**
* Select a version of Node.js (and download fi necessary)
*
* @param {string} input
* @returns {Promise<void>}
*/
@action public async setNodeVersion(input: string) {
const version = normalizeVersion(input);
if (!this.nodeVersions[version]) {
console.warn(`State: Called setNodeVersion() with ${version}, which does not exist.`);
this.setVersion(this.nodeVersions[0].version);
return;
}
console.log(`State: Switching to Node ${version}`);
this.nodeVersion = version;
}
/**
* Select a version of Electron (and download it if necessary).
*
@@ -465,7 +526,7 @@ export class AppState {
(downloadedVersions || []).forEach((version) => {
if (updatedVersions[version]) {
updatedVersions[version].state = ElectronVersionState.ready;
updatedVersions[version].state = VersionState.ready;
}
});
console.log(`State: Updated version state`, updatedVersions);
+3 -3
View File
@@ -5,9 +5,9 @@ import {
} from 'electron';
import { autorun } from 'mobx';
import { ElectronVersion, ElectronVersionState } from '../interfaces';
import { ElectronVersion, VersionState } from '../interfaces';
import { getNiceGreeting } from '../utils/nice-greeting';
import { sortedElectronMap } from '../utils/sorted-electron-map';
import { sortedElectronMap } from '../utils/sorted-map';
import { AppState } from './state';
const { TouchBar } = remote;
@@ -26,7 +26,7 @@ const {
* @returns {string}
*/
export function getItemIcon(
{ state }: Partial<ElectronVersion> = { state: ElectronVersionState.unknown }
{ state }: Partial<ElectronVersion> = { state: VersionState.unknown }
) {
return state === 'ready'
? '💾'
+62 -16
View File
@@ -1,4 +1,4 @@
import { ElectronVersion, ElectronVersionSource, ElectronVersionState, NpmVersion } from '../interfaces';
import { ElectronVersion, ElectronVersionSource, NodeVersion, NpmVersion, VersionState } from '../interfaces';
import { normalizeVersion } from '../utils/normalize-version';
export const enum ElectronReleaseChannel {
@@ -82,7 +82,7 @@ export const enum VersionKeys {
* @param {() => Array<NpmVersion>} fallbackMethod
* @returns {Array<NpmVersion>}
*/
function getVersions(
function getElectronVersions(
key: VersionKeys, fallbackMethod: () => Array<NpmVersion>
): Array<NpmVersion> {
const fromLs = window.localStorage.getItem(key);
@@ -117,7 +117,7 @@ function getVersions(
* @param {VersionKeys} key
* @param {Array<NpmVersion} versions
*/
function saveVersions(key: VersionKeys, versions: Array<NpmVersion>) {
function saveElectronVersions(key: VersionKeys, versions: Array<NpmVersion>) {
const stringified = JSON.stringify(versions);
window.localStorage.setItem(key, stringified);
}
@@ -127,12 +127,12 @@ function saveVersions(key: VersionKeys, versions: Array<NpmVersion>) {
*
* @returns {Array<NpmVersion>}
*/
export function getElectronVersions(): Array<ElectronVersion> {
export function getAllElectronVersions(): Array<ElectronVersion> {
const known: Array<ElectronVersion> = getKnownVersions().map((version) => {
return {
...version,
source: ElectronVersionSource.remote,
state: ElectronVersionState.unknown
state: VersionState.unknown
};
});
@@ -140,11 +140,11 @@ export function getElectronVersions(): Array<ElectronVersion> {
return {
...version,
source: ElectronVersionSource.local,
state: ElectronVersionState.ready
state: VersionState.ready
};
});
return [ ...known, ...local ];
return [...known, ...local];
}
/**
@@ -171,7 +171,7 @@ export function addLocalVersion(input: NpmVersion): Array<NpmVersion> {
* @returns {Array<NpmVersion>}
*/
export function getLocalVersions(): Array<NpmVersion> {
const versions = getVersions(VersionKeys.local, () => []);
const versions = getElectronVersions(VersionKeys.local, () => []);
return versions;
}
@@ -190,7 +190,7 @@ export function saveLocalVersions(versions: Array<NpmVersion | ElectronVersion>)
return true;
});
return saveVersions(VersionKeys.local, filteredVersions);
return saveElectronVersions(VersionKeys.local, filteredVersions);
}
/**
@@ -200,7 +200,7 @@ export function saveLocalVersions(versions: Array<NpmVersion | ElectronVersion>)
* @returns {Array<NpmVersion>}
*/
export function getKnownVersions(): Array<NpmVersion> {
return getVersions(VersionKeys.known, () => require('../../static/releases.json'));
return getElectronVersions(VersionKeys.known, () => require('../../static/releases.json'));
}
/**
@@ -209,7 +209,7 @@ export function getKnownVersions(): Array<NpmVersion> {
* @param {Array<NpmVersion>} versions
*/
export function saveKnownVersions(versions: Array<NpmVersion>) {
return saveVersions(VersionKeys.known, versions);
return saveElectronVersions(VersionKeys.known, versions);
}
/**
@@ -222,20 +222,66 @@ export function saveKnownVersions(versions: Array<NpmVersion>) {
export async function getUpdatedElectronVersions(
): Promise<Array<ElectronVersion>> {
try {
await fetchVersions();
await fetchElectronVersions();
} catch (error) {
console.warn(`Versions: Failed to fetch versions`, { error });
console.warn(`Versions: Failed to fetch Electron versions`, { error });
}
return getElectronVersions();
return getAllElectronVersions();
}
export async function getUpdatedNodeVersions(): Promise<Array<NodeVersion>> {
try {
return await fetchNodeVersions();
} catch (error) {
console.warn(`Versions: Failed to fetch Node.js versions`, { error });
}
return [];
}
/**
* Fetch the latest known versions directly from npm.
* Fetch the latest known Node.js versions directly from Node.js.
*
* @returns {Promise<Array<NpmVersion>>}
*
* let entry = {
* "headers": 1,
* "linux-arm64": 2,
* "linux-x64": 6,
* "osx-x64-tar": 8,
* "win-x64-zip": 14,
* "win-x86-zip": 18
* }
*
* nodejs.org/dist/${version}/node-${version}-${files[entry]}.file-ext
* ^ for windows, take the plat and extend with the file extension in the identifier above
*/
export async function fetchNodeVersions() {
const channels = [
`https://nodejs.org/dist/index.json`
];
let output: Array<NodeVersion> = [];
for (const channelUrl of channels) {
const response = await window.fetch(channelUrl);
const versions = await response.json();
output = versions.map((input: any) => ({
version: normalizeVersion(input.version)
}));
}
return output;
}
/**
* Fetch the latest known Electron versions directly from npm.
*
* @returns {Promise<Array<NpmVersion>>}
*/
export async function fetchVersions() {
export async function fetchElectronVersions() {
const channels = [
`https://registry.npmjs.org/electron`, // stable, beta
`https://registry.npmjs.org/electron-nightly` // nightly
+4 -4
View File
@@ -1,4 +1,4 @@
import { ElectronVersion } from '../interfaces';
import { Version } from '../interfaces';
import { normalizeVersion } from './normalize-version';
/**
@@ -8,9 +8,9 @@ import { normalizeVersion } from './normalize-version';
* @param {Array<ElectronVersion>} input
* @returns {Record<string, ElectronVersion>}
*/
export function arrayToStringMap(
input: Array<ElectronVersion>
): Record<string, ElectronVersion> {
export function arrayToStringMap<T extends Version>(
input: Array<T>
): Record<string, T> {
const output = {};
input.forEach((version) => {
@@ -1,6 +1,6 @@
import * as semver from 'semver';
import { ElectronVersion } from '../interfaces';
import { ElectronVersion, NodeVersion } from '../interfaces';
/**
* Sorts Electron versions and returns the result of a
@@ -13,6 +13,28 @@ import { ElectronVersion } from '../interfaces';
export function sortedElectronMap<T>(
versions: Record<string, ElectronVersion>,
mapFn: (key: string, version: ElectronVersion) => T
) {
return sortedMap<ElectronVersion, T>(versions, mapFn);
}
/**
* Sorts Node versions and returns the result of a
* map function.
*
* @param {Record<string, NodeVersion>} versions
* @param {(key: string, version: NodeVersion) => void} mapFn
* @returns {Array<T>}
*/
export function sortedNodeMap<T>(
versions: Record<string, NodeVersion>,
mapFn: (key: string, version: NodeVersion) => T
) {
return sortedMap<NodeVersion, T>(versions, mapFn);
}
function sortedMap<T1, T2>(
versions: Record<string, T1>,
mapFn: (key: string, version: T1) => T2
) {
return Object.keys(versions)
.sort((a, b) => {
@@ -30,5 +52,5 @@ export function sortedElectronMap<T>(
return semver.gt(a, b, true) ? -1 : 1;
})
.map((key) => mapFn(key, versions[key])) as Array<T>;
.map((key) => mapFn(key, versions[key])) as Array<T2>;
}