From a3faa619699325963b23169f8e5e7f04ba2683cb Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Sat, 28 Apr 2018 13:20:03 +1000 Subject: [PATCH] refactor(all): rewrote in typescript * well here we go * refactor(all-makers): rewrote in typescript * now some publishers * more publishers * pretty much everything * Finish typescript conversion with core tests * Conflict resolution * Ensure ts output is generated (forgot the tsconfig) * Fix ES5 inclusion of fetch-mock * Remove .vscode --- .babelrc | 3 +- .gitignore | 5 +- mocha.opts | 1 + package.json | 49 +- packages/api/cli/package.json | 7 +- ...rge-import.js => electron-forge-import.ts} | 4 +- ...n-forge-init.js => electron-forge-init.ts} | 6 +- .../api/cli/src/electron-forge-install.js | 24 - .../api/cli/src/electron-forge-install.ts | 41 + ...n-forge-lint.js => electron-forge-lint.ts} | 4 +- ...n-forge-make.js => electron-forge-make.ts} | 8 +- ...e-package.js => electron-forge-package.ts} | 6 +- ...e-publish.js => electron-forge-publish.ts} | 9 +- ...forge-start.js => electron-forge-start.ts} | 8 +- .../{electron-forge.js => electron-forge.ts} | 2 +- .../util/{check-system.js => check-system.ts} | 22 +- .../src/util/{terminate.js => terminate.ts} | 2 +- ...ck-system_spec.js => check-system_spec.ts} | 8 +- packages/api/core/package.json | 12 +- .../api/core/src/api/{import.js => import.ts} | 83 +- packages/api/core/src/api/index.js | 28 - packages/api/core/src/api/index.ts | 40 + .../{init-custom.js => init-custom.ts} | 4 +- .../{init-directory.js => init-directory.ts} | 2 +- .../init-scripts/{init-git.js => init-git.ts} | 2 +- .../init-scripts/{init-npm.js => init-npm.ts} | 2 +- ...starter-files.js => init-starter-files.ts} | 8 +- packages/api/core/src/api/init.js | 45 - packages/api/core/src/api/init.ts | 48 + .../core/src/api/{install.js => install.ts} | 88 +- packages/api/core/src/api/lint.js | 58 - packages/api/core/src/api/lint.ts | 47 + .../api/core/src/api/{make.js => make.ts} | 128 +-- .../core/src/api/{package.js => package.ts} | 102 +- packages/api/core/src/api/publish.js | 165 --- packages/api/core/src/api/publish.ts | 172 +++ packages/api/core/src/api/start.js | 98 -- packages/api/core/src/api/start.ts | 120 +++ .../src/util/{config-fn.js => config-fn.ts} | 2 +- .../src/util/{deprecate.js => deprecate.ts} | 4 +- ...lectron-version.js => electron-version.ts} | 2 +- .../util/{forge-config.js => forge-config.ts} | 33 +- packages/api/core/src/util/hook.js | 13 - packages/api/core/src/util/hook.ts | 16 + ...ependencies.js => install-dependencies.ts} | 7 +- .../util/{is-installed.js => is-installed.ts} | 2 +- packages/api/core/src/util/linux-config.js | 19 - ...{linux-installer.js => linux-installer.ts} | 8 +- packages/api/core/src/util/messages.js | 13 - packages/api/core/src/util/messages.ts | 11 + .../core/src/util/{out-dir.js => out-dir.ts} | 5 +- packages/api/core/src/util/parse-archs.js | 9 - packages/api/core/src/util/parse-archs.ts | 15 + ...lugin-interface.js => plugin-interface.ts} | 25 +- .../{publish-state.js => publish-state.ts} | 23 +- ...d-package-json.js => read-package-json.ts} | 2 +- .../core/src/util/{rebuild.js => rebuild.ts} | 11 +- .../{require-search.js => require-search.ts} | 13 +- .../util/{resolve-dir.js => resolve-dir.ts} | 2 +- .../util/{yarn-or-npm.js => yarn-or-npm.ts} | 2 +- ...ge-config_spec.js => forge-config_spec.ts} | 8 +- .../test/fast/{hook_spec.js => hook_spec.ts} | 3 +- ...s_spec.js => install-dependencies_spec.ts} | 16 +- .../fast/{out-dir_spec.js => out-dir_spec.ts} | 7 +- ...arse-archs_spec.js => parse-archs_spec.ts} | 0 .../fast/{publish_spec.js => publish_spec.ts} | 71 +- ...json_spec.js => read-package-json_spec.ts} | 2 +- ...-search_spec.js => require-search_spec.ts} | 4 +- ...esolve-dir_spec.js => resolve-dir_spec.ts} | 0 .../fast/{start_spec.js => start_spec.ts} | 26 +- ...arn-or-npm_spec.js => yarn-or-npm_spec.ts} | 2 +- .../{api_spec_slow.js => api_spec_slow.ts} | 27 +- ...w.js => install-dependencies_spec_slow.ts} | 0 ...tall_spec_slow.js => install_spec_slow.ts} | 28 +- ...uild_spec_slow.js => rebuild_spec_slow.ts} | 6 +- packages/api/core/typings/ambient.d.ts | 18 + packages/installer/base/package.json | 8 +- .../base/src/{Installer.js => Installer.ts} | 20 +- .../{Installer_spec.js => Installer_spec.ts} | 11 +- packages/installer/darwin/package.json | 4 +- ...{InstallerDarwin.js => InstallerDarwin.ts} | 11 +- .../installer/darwin/typings/ambient.d.ts | 6 + packages/installer/deb/package.json | 1 + .../src/{InstallerDeb.js => InstallerDeb.ts} | 8 +- packages/installer/dmg/package.json | 1 + .../src/{InstallerDMG.js => InstallerDMG.ts} | 10 +- .../dmg/src/util/{hdiutil.js => hdiutil.ts} | 17 +- packages/installer/exe/package.json | 1 + packages/installer/exe/src/InstallerExe.js | 15 - packages/installer/exe/src/InstallerExe.ts | 13 + packages/installer/linux/package.json | 1 + .../installer/linux/src/InstallerLinux.js | 22 - .../installer/linux/src/InstallerLinux.ts | 24 + packages/installer/linux/typings/ambient.d.ts | 6 + packages/installer/rpm/package.json | 1 + .../src/{InstallerRpm.js => InstallerRpm.ts} | 8 +- packages/installer/zip/package.json | 1 + .../src/{InstallerZip.js => InstallerZip.ts} | 12 +- packages/maker/appx/package.json | 6 +- packages/maker/appx/src/Config.ts | 28 + .../appx/src/{MakerAppX.js => MakerAppX.ts} | 32 +- packages/maker/appx/src/util/author-name.js | 19 - packages/maker/appx/src/util/author-name.ts | 19 + .../{MakerAppX_spec.js => MakerAppX_spec.ts} | 2 +- ...uthor-name_spec.js => author-name_spec.ts} | 0 packages/maker/appx/typings/ambient.d.ts | 39 + packages/maker/base/package.json | 6 +- .../maker/base/src/{Maker.js => Maker.ts} | 56 +- ...e-output_spec.js => ensure-output_spec.ts} | 11 +- packages/maker/deb/package.json | 11 +- packages/maker/deb/src/Config.ts | 125 +++ .../deb/src/{MakerDeb.js => MakerDeb.ts} | 14 +- .../{MakerDeb_spec.js => MakerDeb_spec.ts} | 51 +- packages/maker/dmg/package.json | 6 +- packages/maker/dmg/src/Config.ts | 30 + .../dmg/src/{MakerDMG.js => MakerDMG.ts} | 10 +- .../{MakerDMG_spec.js => MakerDMG_spec.ts} | 33 +- packages/maker/flatpak/package.json | 6 +- packages/maker/flatpak/src/Config.ts | 104 ++ .../src/{MakerFlatpak.js => MakerFlatpak.ts} | 12 +- ...erFlatpak_spec.js => MakerFlatpak_spec.ts} | 38 +- packages/maker/rpm/package.json | 6 +- packages/maker/rpm/src/Config.ts | 79 ++ .../rpm/src/{MakerRpm.js => MakerRpm.ts} | 13 +- .../{MakerRpm_spec.js => MakerRpm_spec.ts} | 51 +- packages/maker/snap/package.json | 8 +- packages/maker/snap/src/Config.ts | 93 ++ .../snap/src/{MakerSnap.js => MakerSnap.ts} | 10 +- .../{MakerSnap_spec.js => MakerSnap_spec.ts} | 33 +- packages/maker/squirrel/package.json | 4 +- .../{MakerSquirrel.js => MakerSquirrel.ts} | 16 +- packages/maker/wix/package.json | 6 +- .../wix/src/{MakerWix.js => MakerWix.ts} | 14 +- packages/maker/wix/src/util/author-name.js | 19 - packages/maker/wix/src/util/author-name.ts | 19 + ...uthor-name_spec.js => author-name_spec.ts} | 0 packages/maker/wix/typings/ambient.d.ts | 10 + packages/maker/zip/package.json | 4 +- .../zip/src/{MakerZIP.js => MakerZIP.ts} | 16 +- packages/publisher/base/package.json | 6 +- .../base/src/{Publisher.js => Publisher.ts} | 44 +- .../publisher/base/test/Publisher_spec.js | 15 - .../publisher/base/test/Publisher_spec.ts | 20 + .../electron-release-server/package.json | 4 +- .../electron-release-server/src/Config.ts | 6 + .../src/PublisherERS.js | 127 --- .../src/PublisherERS.ts | 136 +++ packages/publisher/github/package.json | 6 +- packages/publisher/github/src/Config.ts | 12 + .../publisher/github/src/PublisherGithub.js | 85 -- .../publisher/github/src/PublisherGithub.ts | 111 ++ .../github/src/util/{github.js => github.ts} | 5 +- .../test/{github_spec.js => github_spec.ts} | 22 +- packages/publisher/s3/package.json | 5 +- packages/publisher/s3/src/Config.ts | 8 + .../s3/src/{PublisherS3.js => PublisherS3.ts} | 57 +- packages/publisher/snapcraft/package.json | 1 + packages/publisher/snapcraft/src/Config.ts | 6 + ...sherSnapcraft.js => PublisherSnapcraft.ts} | 13 +- packages/utils/async-ora/package.json | 7 +- .../async-ora/src/{index.js => index.ts} | 3 +- .../src/{ora-handler.js => ora-handler.ts} | 20 +- packages/utils/async-ora/src/ora.js | 39 - packages/utils/async-ora/src/ora.ts | 49 + ...ra-handler_spec.js => ora-handler_spec.ts} | 35 +- packages/utils/types/index.d.ts | 87 ++ packages/utils/types/package.json | 21 + packages/utils/types/src/index.ts | 3 + tools/link-ts.ts | 19 + tools/test-dist.ts | 34 + tools/test-setup.js | 4 + tsconfig.json | 23 + yarn.lock | 998 ++++++++++++------ 173 files changed, 3385 insertions(+), 1822 deletions(-) rename packages/api/cli/src/{electron-forge-import.js => electron-forge-import.ts} (85%) rename packages/api/cli/src/{electron-forge-init.js => electron-forge-init.ts} (86%) delete mode 100644 packages/api/cli/src/electron-forge-install.js create mode 100644 packages/api/cli/src/electron-forge-install.ts rename packages/api/cli/src/{electron-forge-lint.js => electron-forge-lint.ts} (89%) rename packages/api/cli/src/{electron-forge-make.js => electron-forge-make.ts} (86%) rename packages/api/cli/src/{electron-forge-package.js => electron-forge-package.ts} (85%) rename packages/api/cli/src/{electron-forge-publish.js => electron-forge-publish.ts} (83%) rename packages/api/cli/src/{electron-forge-start.js => electron-forge-start.ts} (92%) rename packages/api/cli/src/{electron-forge.js => electron-forge.ts} (95%) rename packages/api/cli/src/util/{check-system.js => check-system.ts} (69%) rename packages/api/cli/src/util/{terminate.js => terminate.ts} (94%) rename packages/api/cli/test/{check-system_spec.js => check-system_spec.ts} (80%) rename packages/api/core/src/api/{import.js => import.ts} (74%) delete mode 100644 packages/api/core/src/api/index.js create mode 100644 packages/api/core/src/api/index.ts rename packages/api/core/src/api/init-scripts/{init-custom.js => init-custom.ts} (96%) rename packages/api/core/src/api/init-scripts/{init-directory.js => init-directory.ts} (93%) rename packages/api/core/src/api/init-scripts/{init-git.js => init-git.ts} (94%) rename packages/api/core/src/api/init-scripts/{init-npm.js => init-npm.ts} (97%) rename packages/api/core/src/api/init-scripts/{init-starter-files.js => init-starter-files.ts} (80%) delete mode 100644 packages/api/core/src/api/init.js create mode 100644 packages/api/core/src/api/init.ts rename packages/api/core/src/api/{install.js => install.ts} (73%) delete mode 100644 packages/api/core/src/api/lint.js create mode 100644 packages/api/core/src/api/lint.ts rename packages/api/core/src/api/{make.js => make.ts} (61%) rename packages/api/core/src/api/{package.js => package.ts} (66%) delete mode 100644 packages/api/core/src/api/publish.js create mode 100644 packages/api/core/src/api/publish.ts delete mode 100644 packages/api/core/src/api/start.js create mode 100644 packages/api/core/src/api/start.ts rename packages/api/core/src/util/{config-fn.js => config-fn.ts} (55%) rename packages/api/core/src/util/{deprecate.js => deprecate.ts} (69%) rename packages/api/core/src/util/{electron-version.js => electron-version.ts} (85%) rename packages/api/core/src/util/{forge-config.js => forge-config.ts} (71%) delete mode 100644 packages/api/core/src/util/hook.js create mode 100644 packages/api/core/src/util/hook.ts rename packages/api/core/src/util/{install-dependencies.js => install-dependencies.ts} (90%) rename packages/api/core/src/util/{is-installed.js => is-installed.ts} (75%) delete mode 100644 packages/api/core/src/util/linux-config.js rename packages/api/core/src/util/{linux-installer.js => linux-installer.ts} (50%) delete mode 100644 packages/api/core/src/util/messages.js create mode 100644 packages/api/core/src/util/messages.ts rename packages/api/core/src/util/{out-dir.js => out-dir.ts} (68%) delete mode 100644 packages/api/core/src/util/parse-archs.js create mode 100644 packages/api/core/src/util/parse-archs.ts rename packages/api/core/src/util/{plugin-interface.js => plugin-interface.ts} (70%) rename packages/api/core/src/util/{publish-state.js => publish-state.ts} (76%) rename packages/api/core/src/util/{read-package-json.js => read-package-json.ts} (74%) rename packages/api/core/src/util/{rebuild.js => rebuild.ts} (68%) rename packages/api/core/src/util/{require-search.js => require-search.ts} (64%) rename packages/api/core/src/util/{resolve-dir.js => resolve-dir.ts} (96%) rename packages/api/core/src/util/{yarn-or-npm.js => yarn-or-npm.ts} (84%) rename packages/api/core/test/fast/{forge-config_spec.js => forge-config_spec.ts} (89%) rename packages/api/core/test/fast/{hook_spec.js => hook_spec.ts} (90%) rename packages/api/core/test/fast/{install-dependencies_spec.js => install-dependencies_spec.ts} (90%) rename packages/api/core/test/fast/{out-dir_spec.js => out-dir_spec.ts} (65%) rename packages/api/core/test/fast/{parse-archs_spec.js => parse-archs_spec.ts} (100%) rename packages/api/core/test/fast/{publish_spec.js => publish_spec.ts} (81%) rename packages/api/core/test/fast/{read-package-json_spec.js => read-package-json_spec.ts} (85%) rename packages/api/core/test/fast/{require-search_spec.js => require-search_spec.ts} (81%) rename packages/api/core/test/fast/{resolve-dir_spec.js => resolve-dir_spec.ts} (100%) rename packages/api/core/test/fast/{start_spec.js => start_spec.ts} (90%) rename packages/api/core/test/fast/{yarn-or-npm_spec.js => yarn-or-npm_spec.ts} (96%) rename packages/api/core/test/slow/{api_spec_slow.js => api_spec_slow.ts} (95%) rename packages/api/core/test/slow/{install-dependencies_spec_slow.js => install-dependencies_spec_slow.ts} (100%) rename packages/api/core/test/slow/{install_spec_slow.js => install_spec_slow.ts} (87%) rename packages/api/core/test/slow/{rebuild_spec_slow.js => rebuild_spec_slow.ts} (91%) create mode 100644 packages/api/core/typings/ambient.d.ts rename packages/installer/base/src/{Installer.js => Installer.ts} (55%) rename packages/installer/base/test/{Installer_spec.js => Installer_spec.ts} (56%) rename packages/installer/darwin/src/{InstallerDarwin.js => InstallerDarwin.ts} (63%) create mode 100644 packages/installer/darwin/typings/ambient.d.ts rename packages/installer/deb/src/{InstallerDeb.js => InstallerDeb.ts} (55%) rename packages/installer/dmg/src/{InstallerDMG.js => InstallerDMG.ts} (87%) rename packages/installer/dmg/src/util/{hdiutil.js => hdiutil.ts} (70%) delete mode 100644 packages/installer/exe/src/InstallerExe.js create mode 100644 packages/installer/exe/src/InstallerExe.ts delete mode 100644 packages/installer/linux/src/InstallerLinux.js create mode 100644 packages/installer/linux/src/InstallerLinux.ts create mode 100644 packages/installer/linux/typings/ambient.d.ts rename packages/installer/rpm/src/{InstallerRpm.js => InstallerRpm.ts} (59%) rename packages/installer/zip/src/{InstallerZip.js => InstallerZip.ts} (82%) create mode 100644 packages/maker/appx/src/Config.ts rename packages/maker/appx/src/{MakerAppX.js => MakerAppX.ts} (80%) delete mode 100644 packages/maker/appx/src/util/author-name.js create mode 100644 packages/maker/appx/src/util/author-name.ts rename packages/maker/appx/test/{MakerAppX_spec.js => MakerAppX_spec.ts} (97%) rename packages/maker/appx/test/{author-name_spec.js => author-name_spec.ts} (100%) create mode 100644 packages/maker/appx/typings/ambient.d.ts rename packages/maker/base/src/{Maker.js => Maker.ts} (58%) rename packages/maker/base/test/{ensure-output_spec.js => ensure-output_spec.ts} (93%) create mode 100644 packages/maker/deb/src/Config.ts rename packages/maker/deb/src/{MakerDeb.js => MakerDeb.ts} (70%) rename packages/maker/deb/test/{MakerDeb_spec.js => MakerDeb_spec.ts} (56%) create mode 100644 packages/maker/dmg/src/Config.ts rename packages/maker/dmg/src/{MakerDMG.js => MakerDMG.ts} (73%) rename packages/maker/dmg/test/{MakerDMG_spec.js => MakerDMG_spec.ts} (68%) create mode 100644 packages/maker/flatpak/src/Config.ts rename packages/maker/flatpak/src/{MakerFlatpak.js => MakerFlatpak.ts} (71%) rename packages/maker/flatpak/test/{MakerFlatpak_spec.js => MakerFlatpak_spec.ts} (59%) create mode 100644 packages/maker/rpm/src/Config.ts rename packages/maker/rpm/src/{MakerRpm.js => MakerRpm.ts} (71%) rename packages/maker/rpm/test/{MakerRpm_spec.js => MakerRpm_spec.ts} (55%) create mode 100644 packages/maker/snap/src/Config.ts rename packages/maker/snap/src/{MakerSnap.js => MakerSnap.ts} (63%) rename packages/maker/snap/test/{MakerSnap_spec.js => MakerSnap_spec.ts} (64%) rename packages/maker/squirrel/src/{MakerSquirrel.js => MakerSquirrel.ts} (74%) rename packages/maker/wix/src/{MakerWix.js => MakerWix.ts} (67%) delete mode 100644 packages/maker/wix/src/util/author-name.js create mode 100644 packages/maker/wix/src/util/author-name.ts rename packages/maker/wix/test/{author-name_spec.js => author-name_spec.ts} (100%) create mode 100644 packages/maker/wix/typings/ambient.d.ts rename packages/maker/zip/src/{MakerZIP.js => MakerZIP.ts} (69%) rename packages/publisher/base/src/{Publisher.js => Publisher.ts} (50%) delete mode 100644 packages/publisher/base/test/Publisher_spec.js create mode 100644 packages/publisher/base/test/Publisher_spec.ts create mode 100644 packages/publisher/electron-release-server/src/Config.ts delete mode 100644 packages/publisher/electron-release-server/src/PublisherERS.js create mode 100644 packages/publisher/electron-release-server/src/PublisherERS.ts create mode 100644 packages/publisher/github/src/Config.ts delete mode 100644 packages/publisher/github/src/PublisherGithub.js create mode 100644 packages/publisher/github/src/PublisherGithub.ts rename packages/publisher/github/src/util/{github.js => github.ts} (79%) rename packages/publisher/github/test/{github_spec.js => github_spec.ts} (83%) create mode 100644 packages/publisher/s3/src/Config.ts rename packages/publisher/s3/src/{PublisherS3.js => PublisherS3.ts} (54%) create mode 100644 packages/publisher/snapcraft/src/Config.ts rename packages/publisher/snapcraft/src/{PublisherSnapcraft.js => PublisherSnapcraft.ts} (72%) rename packages/utils/async-ora/src/{index.js => index.ts} (56%) rename packages/utils/async-ora/src/{ora-handler.js => ora-handler.ts} (66%) delete mode 100644 packages/utils/async-ora/src/ora.js create mode 100644 packages/utils/async-ora/src/ora.ts rename packages/utils/async-ora/test/{ora-handler_spec.js => ora-handler_spec.ts} (80%) create mode 100644 packages/utils/types/index.d.ts create mode 100644 packages/utils/types/package.json create mode 100644 packages/utils/types/src/index.ts create mode 100644 tools/link-ts.ts create mode 100644 tools/test-dist.ts create mode 100644 tools/test-setup.js create mode 100755 tsconfig.json diff --git a/.babelrc b/.babelrc index 9e0140afd4..7c9f8d2a74 100644 --- a/.babelrc +++ b/.babelrc @@ -12,6 +12,7 @@ "node": "6" } } - ] + ], + "@babel/typescript" ] } \ No newline at end of file diff --git a/.gitignore b/.gitignore index e6efd147e7..ef98cb66d1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,7 @@ node_modules dist yarn-error.log -packages/.old \ No newline at end of file +packages/.old +**/tsconfig.json +!/tsconfig.json +.vscode \ No newline at end of file diff --git a/mocha.opts b/mocha.opts index 5096a3f82f..6df08b99df 100644 --- a/mocha.opts +++ b/mocha.opts @@ -1,2 +1,3 @@ --require @babel/register +--require ../../../tools/test-setup.js --timeout 800000 diff --git a/package.json b/package.json index da26be7db4..2339996eba 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,10 @@ } }, "scripts": { - "build": "bolt ws exec -- node_modules/.bin/babel src -d dist --quiet", + "clean": "bolt ws exec -- rimraf dist", + "prebuild": "bolt clean && ts-node tools/link-ts.ts && bolt ws exec -- node_modules/.bin/tsc --emitDeclarationOnly", + "build": "bolt ws exec -- node_modules/.bin/babel src -d dist --quiet --extensions \".ts\"", + "postbuild": "ts-node tools/test-dist", "commit": "git-cz", "docs:build": "cd docs && gitbook build", "docs:install": "cd docs && gitbook install", @@ -32,7 +35,7 @@ "dependencies": { "@octokit/rest": "^15.2.6", "aws-sdk": "^2.9.0", - "colors": "^1.1.2", + "colors": "^1.2.0", "commander": "^2.9.0", "cross-spawn": "^6.0.4", "cross-spawn-promise": "^0.10.1", @@ -68,12 +71,37 @@ "zip-folder": "^1.0.0" }, "devDependencies": { - "@babel/cli": "^7.0.0-beta.40", - "@babel/core": "^7.0.0-beta.40", - "@babel/plugin-proposal-class-properties": "^7.0.0-beta.40", - "@babel/plugin-proposal-object-rest-spread": "^7.0.0-beta.40", - "@babel/preset-env": "^7.0.0-beta.40", - "@babel/register": "^7.0.0-beta.40", + "@babel/cli": "^7.0.0-beta.44", + "@babel/core": "^7.0.0-beta.44", + "@babel/plugin-proposal-class-properties": "^7.0.0-beta.44", + "@babel/plugin-proposal-object-rest-spread": "^7.0.0-beta.44", + "@babel/preset-env": "^7.0.0-beta.44", + "@babel/preset-typescript": "^7.0.0-beta.44", + "@babel/register": "^7.0.0-beta.44", + "@types/chai": "^4.1.2", + "@types/chai-as-promised": "^7.1.0", + "@types/cross-spawn": "^6.0.0", + "@types/debug": "^0.0.30", + "@types/electron-packager": "^10.1.0", + "@types/electron-winstaller": "^2.6.1", + "@types/fetch-mock": "^6.0.1", + "@types/form-data": "^2.2.1", + "@types/fs-extra": "^5.0.2", + "@types/glob": "^5.0.35", + "@types/inquirer": "^0.0.41", + "@types/lodash.merge": "^4.6.3", + "@types/lodash.template": "^4.4.3", + "@types/log-symbols": "^2.0.0", + "@types/mime-types": "^2.1.0", + "@types/mocha": "^5.1.0", + "@types/node": "^9.6.5", + "@types/node-fetch": "^1.6.8", + "@types/opn": "^5.1.0", + "@types/ora": "^1.3.4", + "@types/pify": "^3.0.1", + "@types/proxyquire": "^1.3.28", + "@types/semver": "^5.5.0", + "@types/sinon": "^4.3.1", "asar": "^0.14.0", "babel-eslint": "^7.0.0", "chai": "^4.0.0", @@ -95,7 +123,10 @@ "nodemon": "^1.11.0", "nyc": "^11.0.0", "proxyquire": "^2.0.1", - "sinon": "^4.1.2" + "rimraf": "^2.6.2", + "sinon": "^4.1.2", + "ts-node": "^6.0.0", + "typescript": "^2.8.1" }, "optionalDependencies": { "electron-installer-debian": "^0.8.0", diff --git a/packages/api/cli/package.json b/packages/api/cli/package.json index 8350d9fa29..7eede6bd1e 100644 --- a/packages/api/cli/package.json +++ b/packages/api/cli/package.json @@ -12,7 +12,7 @@ "electron-forge-vscode-win": "script/vscode.cmd" }, "scripts": { - "test": "mocha test/**/*_spec.js test/**/**/*_spec.js --opts ../../../mocha.opts" + "test": "mocha --require ts-node/register test/**/*_spec.ts test/**/**/*_spec.ts --opts ../../../mocha.opts" }, "devDependencies": { "chai": "^4.0.0", @@ -21,13 +21,14 @@ "dependencies": { "@electron-forge/async-ora": "6.0.0-beta.3", "@electron-forge/core": "6.0.0-beta.3", - "colors": "^1.1.2", + "colors": "^1.2.0", "commander": "^2.9.0", "debug": "^3.0.0", "fs-extra": "^5.0.0", + "inquirer": "^5.0.0", "semver": "^5.3.0" }, "engines": { "node": ">= 6.0" } -} +} \ No newline at end of file diff --git a/packages/api/cli/src/electron-forge-import.js b/packages/api/cli/src/electron-forge-import.ts similarity index 85% rename from packages/api/cli/src/electron-forge-import.js rename to packages/api/cli/src/electron-forge-import.ts index dfbb9c3bf8..4337c3038c 100644 --- a/packages/api/cli/src/electron-forge-import.js +++ b/packages/api/cli/src/electron-forge-import.ts @@ -1,4 +1,4 @@ -import { import as importAPI } from '@electron-forge/core'; +import { api } from '@electron-forge/core'; import path from 'path'; import program from 'commander'; @@ -20,7 +20,7 @@ import './util/terminate'; }) .parse(process.argv); - await importAPI({ + await api.import({ dir, interactive: true, }); diff --git a/packages/api/cli/src/electron-forge-init.js b/packages/api/cli/src/electron-forge-init.ts similarity index 86% rename from packages/api/cli/src/electron-forge-init.js rename to packages/api/cli/src/electron-forge-init.ts index ba81fe6bf7..7f660d1616 100644 --- a/packages/api/cli/src/electron-forge-init.js +++ b/packages/api/cli/src/electron-forge-init.ts @@ -1,4 +1,4 @@ -import { init } from '@electron-forge/core'; +import { api, InitOptions } from '@electron-forge/core'; import path from 'path'; import program from 'commander'; @@ -22,12 +22,12 @@ import './util/terminate'; }) .parse(process.argv); - const initOpts = { + const initOpts: InitOptions = { dir, interactive: true, copyCIFiles: !!program.copyCiFiles, }; if (program.template) initOpts.template = program.template; - await init(initOpts); + await api.init(initOpts); })(); diff --git a/packages/api/cli/src/electron-forge-install.js b/packages/api/cli/src/electron-forge-install.js deleted file mode 100644 index d0678a49d8..0000000000 --- a/packages/api/cli/src/electron-forge-install.js +++ /dev/null @@ -1,24 +0,0 @@ -import { install } from '@electron-forge/core'; - -import program from 'commander'; - -import './util/terminate'; - -(async () => { - let repo; - - program - .version(require('../package.json').version) - .arguments('[repository]') - .option('--prerelease', 'Fetch prerelease versions') - .action((repository) => { - repo = repository; - }) - .parse(process.argv); - - await install({ - repo, - interactive: true, - prerelease: program.prerelease, - }); -})(); diff --git a/packages/api/cli/src/electron-forge-install.ts b/packages/api/cli/src/electron-forge-install.ts new file mode 100644 index 0000000000..be540cf521 --- /dev/null +++ b/packages/api/cli/src/electron-forge-install.ts @@ -0,0 +1,41 @@ +import { api, InstallAsset } from '@electron-forge/core'; +import inquirer from 'inquirer'; + +import program from 'commander'; + +import './util/terminate'; + +(async () => { + let repo!: string; + + program + .version(require('../package.json').version) + .arguments('[repository]') + .option('--prerelease', 'Fetch prerelease versions') + .action((repository) => { + repo = repository; + }) + .parse(process.argv); + + const chooseAsset = async (assets: InstallAsset[]) => { + const choices: { name: string, value: string }[] = []; + assets.forEach((asset) => { + choices.push({ name: asset.name, value: asset.id }); + }); + const { assetID } = await inquirer.createPromptModule()<{ assetID: string }>({ + type: 'list', + name: 'assetID', + message: 'Multiple potential assets found, please choose one from the list below:'.cyan, + choices, + }); + + return assets.find(asset => asset.id === assetID)!; + } + + await api.install({ + repo, + interactive: true, + chooseAsset, + prerelease: program.prerelease, + }); +})(); diff --git a/packages/api/cli/src/electron-forge-lint.js b/packages/api/cli/src/electron-forge-lint.ts similarity index 89% rename from packages/api/cli/src/electron-forge-lint.js rename to packages/api/cli/src/electron-forge-lint.ts index b42f99f0b2..61106afb3f 100644 --- a/packages/api/cli/src/electron-forge-lint.js +++ b/packages/api/cli/src/electron-forge-lint.ts @@ -1,4 +1,4 @@ -import { lint } from '@electron-forge/core'; +import { api } from '@electron-forge/core'; import fs from 'fs'; import path from 'path'; @@ -21,7 +21,7 @@ import './util/terminate'; }) .parse(process.argv); - await lint({ + await api.lint({ dir, interactive: true, }); diff --git a/packages/api/cli/src/electron-forge-make.js b/packages/api/cli/src/electron-forge-make.ts similarity index 86% rename from packages/api/cli/src/electron-forge-make.js rename to packages/api/cli/src/electron-forge-make.ts index 86c7d7429f..476e9fc8da 100644 --- a/packages/api/cli/src/electron-forge-make.js +++ b/packages/api/cli/src/electron-forge-make.ts @@ -1,4 +1,4 @@ -import { make } from '@electron-forge/core'; +import { api, MakeOptions } from '@electron-forge/core'; import fs from 'fs-extra'; import path from 'path'; @@ -27,7 +27,7 @@ export const getMakeOptions = () => { }) .parse(process.argv); - const makeOpts = { + const makeOpts: MakeOptions = { dir, interactive: true, skipPackage: program.skipPackage, @@ -39,10 +39,10 @@ export const getMakeOptions = () => { return makeOpts; }; -if (process.mainModule === module || global.__LINKED_FORGE__) { +if (process.mainModule === module || (global as any).__LINKED_FORGE__) { (async () => { const makeOpts = getMakeOptions(); - await make(makeOpts); + await api.make(makeOpts); })(); } diff --git a/packages/api/cli/src/electron-forge-package.js b/packages/api/cli/src/electron-forge-package.ts similarity index 85% rename from packages/api/cli/src/electron-forge-package.js rename to packages/api/cli/src/electron-forge-package.ts index 3f5a11d607..f558ba1e98 100644 --- a/packages/api/cli/src/electron-forge-package.js +++ b/packages/api/cli/src/electron-forge-package.ts @@ -1,4 +1,4 @@ -import { package as packageAPI } from '@electron-forge/core'; +import { api, PackageOptions } from '@electron-forge/core'; import fs from 'fs-extra'; import path from 'path'; @@ -24,12 +24,12 @@ import './util/terminate'; }) .parse(process.argv); - const packageOpts = { + const packageOpts: PackageOptions = { dir, interactive: true, }; if (program.arch) packageOpts.arch = program.arch; if (program.platform) packageOpts.platform = program.platform; - await packageAPI(packageOpts); + await api.package(packageOpts); })(); diff --git a/packages/api/cli/src/electron-forge-publish.js b/packages/api/cli/src/electron-forge-publish.ts similarity index 83% rename from packages/api/cli/src/electron-forge-publish.js rename to packages/api/cli/src/electron-forge-publish.ts index ccd47b67ed..68f5820316 100644 --- a/packages/api/cli/src/electron-forge-publish.js +++ b/packages/api/cli/src/electron-forge-publish.ts @@ -1,4 +1,4 @@ -import { publish } from '@electron-forge/core'; +import { api, PublishOptions } from '@electron-forge/core'; import fs from 'fs-extra'; import path from 'path'; @@ -12,7 +12,6 @@ import { getMakeOptions } from './electron-forge-make'; program .version(require('../package.json').version) .arguments('[cwd]') - .option('--tag', 'The tag to publish to on GitHub') .option('--target [target[,target...]]', 'The comma-separated deployment targets, defaults to "github"') .option('--dry-run', 'Triggers a publish dry run which saves state and doesn\'t upload anything') .option('--from-dry-run', 'Attempts to publish artifacts from the last saved dry run') @@ -27,11 +26,9 @@ import { getMakeOptions } from './electron-forge-make'; }) .parse(process.argv); - const publishOpts = { + const publishOpts: PublishOptions = { dir, interactive: true, - authToken: program.authToken, - tag: program.tag, dryRun: program.dryRun, dryRunResume: program.fromDryRun, }; @@ -39,5 +36,5 @@ import { getMakeOptions } from './electron-forge-make'; publishOpts.makeOptions = getMakeOptions(); - await publish(publishOpts); + await api.publish(publishOpts); })(); diff --git a/packages/api/cli/src/electron-forge-start.js b/packages/api/cli/src/electron-forge-start.ts similarity index 92% rename from packages/api/cli/src/electron-forge-start.js rename to packages/api/cli/src/electron-forge-start.ts index 94a940014d..8bb542e265 100644 --- a/packages/api/cli/src/electron-forge-start.js +++ b/packages/api/cli/src/electron-forge-start.ts @@ -1,4 +1,4 @@ -import { start } from '@electron-forge/core'; +import { api, StartOptions } from '@electron-forge/core'; import fs from 'fs-extra'; import path from 'path'; @@ -43,7 +43,7 @@ import './util/terminate'; console.log(" will pass the arguments '-d -f foo.txt' to the Electron app"); }); - const opts = { + const opts: StartOptions = { dir, interactive: true, enableLogging: !!program.enableLogging, @@ -61,10 +61,10 @@ import './util/terminate'; if (program.appPath) opts.appPath = program.appPath; if (appArgs) opts.args = appArgs; - const spawned = await start(opts); + const spawned = await api.start(opts); await new Promise((resolve) => { - spawned.on('exit', (code) => { + spawned.on('exit', (code: number) => { if (code !== 0) { process.exit(code); } diff --git a/packages/api/cli/src/electron-forge.js b/packages/api/cli/src/electron-forge.ts similarity index 95% rename from packages/api/cli/src/electron-forge.js rename to packages/api/cli/src/electron-forge.ts index 644a6343ee..7c4f40a2c3 100644 --- a/packages/api/cli/src/electron-forge.js +++ b/packages/api/cli/src/electron-forge.ts @@ -8,7 +8,7 @@ import './util/terminate'; import checkSystem from './util/check-system'; const originalSC = program.executeSubCommand.bind(program); -program.executeSubCommand = (argv, args, unknown) => { +program.executeSubCommand = (argv: string[], args: string[], unknown: string[]) => { let indexOfDoubleDash = process.argv.indexOf('--'); indexOfDoubleDash = indexOfDoubleDash < 0 ? process.argv.length + 1 : indexOfDoubleDash; diff --git a/packages/api/cli/src/util/check-system.js b/packages/api/cli/src/util/check-system.ts similarity index 69% rename from packages/api/cli/src/util/check-system.js rename to packages/api/cli/src/util/check-system.ts index 546b6c53c4..ff2fa31df8 100644 --- a/packages/api/cli/src/util/check-system.js +++ b/packages/api/cli/src/util/check-system.ts @@ -3,11 +3,12 @@ import debug from 'debug'; import semver from 'semver'; import { hasYarn, yarnOrNpmSpawn } from '@electron-forge/core/dist/util/yarn-or-npm'; +import { OraImpl } from '@electron-forge/async-ora'; const d = debug('electron-forge:check-system'); async function checkGitExists() { - return new Promise((resolve) => { + return new Promise((resolve) => { exec('git --version', (err) => { if (err) return resolve(false); resolve(true); @@ -30,42 +31,43 @@ const YARN_WHITELISTED_VERSIONS = { linux: '0.27.5', }; -export function validPackageManagerVersion(packageManager, version, whitelistedVersions, ora) { +export function validPackageManagerVersion(packageManager: string, version: string, whitelistedVersions: string, ora: OraImpl) { try { return semver.satisfies(version, whitelistedVersions); } catch (e) { - ora.warn(`Could not check ${packageManager} version "${version}", assuming incompatible`); + ora.warn!(`Could not check ${packageManager} version "${version}", assuming incompatible`); d(`Exception while checking version: ${e}`); return false; } } -function warnIfPackageManagerIsntAKnownGoodVersion(packageManager, version, whitelistedVersions, ora) { +function warnIfPackageManagerIsntAKnownGoodVersion(packageManager: string, version: string, whitelistedVersions: { [key: string]: string }, ora: OraImpl) { const osVersions = whitelistedVersions[process.platform]; const versions = osVersions ? `${whitelistedVersions.all} || ${osVersions}` : whitelistedVersions.all; const versionString = version.toString(); if (!validPackageManagerVersion(packageManager, versionString, versions, ora)) { - ora.warn( + ora.warn!( `You are using ${packageManager}, but not a known good version.\n` + `The known versions that work with Electron Forge are: ${versions}` ); } } -async function checkPackageManagerVersion(ora) { +async function checkPackageManagerVersion(ora: OraImpl) { return yarnOrNpmSpawn(['--version']) .then((version) => { + const versionString = version.toString(); if (hasYarn()) { - warnIfPackageManagerIsntAKnownGoodVersion('Yarn', version, YARN_WHITELISTED_VERSIONS, ora); + warnIfPackageManagerIsntAKnownGoodVersion('Yarn', versionString, YARN_WHITELISTED_VERSIONS, ora); } else { - warnIfPackageManagerIsntAKnownGoodVersion('NPM', version, NPM_WHITELISTED_VERSIONS, ora); + warnIfPackageManagerIsntAKnownGoodVersion('NPM', versionString, NPM_WHITELISTED_VERSIONS, ora); } return true; }); } -export default async function (ora) { - return (await Promise.all([checkGitExists(ora), checkNodeVersion(ora), checkPackageManagerVersion(ora)])) +export default async function (ora: OraImpl) { + return (await Promise.all([checkGitExists(), checkNodeVersion(), checkPackageManagerVersion(ora)])) .every(check => check); } diff --git a/packages/api/cli/src/util/terminate.js b/packages/api/cli/src/util/terminate.ts similarity index 94% rename from packages/api/cli/src/util/terminate.js rename to packages/api/cli/src/util/terminate.ts index aac9aef978..0c8966ec6c 100644 --- a/packages/api/cli/src/util/terminate.js +++ b/packages/api/cli/src/util/terminate.ts @@ -1,6 +1,6 @@ import colors from 'colors'; -process.on('unhandledRejection', (err) => { +process.on('unhandledRejection', (err: Error) => { if (err && err.message && err.stack) { console.error('\nAn unhandled rejection has occurred inside Forge:'.red); console.error(colors.red(err.message)); diff --git a/packages/api/cli/test/check-system_spec.js b/packages/api/cli/test/check-system_spec.ts similarity index 80% rename from packages/api/cli/test/check-system_spec.js rename to packages/api/cli/test/check-system_spec.ts index 46f22cdd36..df5f499180 100644 --- a/packages/api/cli/test/check-system_spec.js +++ b/packages/api/cli/test/check-system_spec.ts @@ -5,20 +5,20 @@ import checkSystem, { validPackageManagerVersion } from '../src/util/check-syste describe('check-system', () => { it('should succeed on valid agents', async () => { - expect(await checkSystem(fakeOra())).to.be.equal(true); + expect(await checkSystem(fakeOra(''))).to.be.equal(true); }); describe('validPackageManagerVersion', () => { it('should consider whitelisted versions to be valid', () => { - expect(validPackageManagerVersion('NPM', '3.10.1', '^3.0.0', fakeOra())).to.be.equal(true); + expect(validPackageManagerVersion('NPM', '3.10.1', '^3.0.0', fakeOra(''))).to.be.equal(true); }); it('should consider Yarn nightly versions to be invalid', () => { - expect(validPackageManagerVersion('Yarn', '0.23.0-20170311.0515', '0.23.0', fakeOra())).to.be.equal(false); + expect(validPackageManagerVersion('Yarn', '0.23.0-20170311.0515', '0.23.0', fakeOra(''))).to.be.equal(false); }); it('should consider invalid semver versions to be invalid', () => { - expect(validPackageManagerVersion('Yarn', '0.22', '0.22.0', fakeOra())).to.be.equal(false); + expect(validPackageManagerVersion('Yarn', '0.22', '0.22.0', fakeOra(''))).to.be.equal(false); }); }); }); diff --git a/packages/api/core/package.json b/packages/api/core/package.json index 0bf5692380..5d167c369c 100644 --- a/packages/api/core/package.json +++ b/packages/api/core/package.json @@ -4,9 +4,11 @@ "description": "A complete tool for building modern Electron applications", "repository": "https://github.com/electron-userland/electron-forge", "main": "dist/api/index.js", + "typings": "dist/api/index.d.ts", "scripts": { "docs": "esdoc", - "test": "mocha test/**/*_spec*.js test/**/**/*_spec*.js --opts ../../../mocha.opts" + "test:fast": "mocha --require ts-node/register test/**/*_spec.ts test/**/**/*_spec.ts --opts ../../../mocha.opts", + "test": "mocha --require ts-node/register test/**/*_spec.ts test/**/**/*_spec.ts test/slow/*_spec_slow.ts --opts ../../../mocha.opts" }, "author": "Samuel Attard", "license": "MIT", @@ -38,14 +40,16 @@ "@electron-forge/installer-exe": "6.0.0-beta.3", "@electron-forge/installer-rpm": "6.0.0-beta.3", "@electron-forge/installer-zip": "6.0.0-beta.3", - "colors": "^1.1.2", + "@electron-forge/maker-base": "^6.0.0-beta.3", + "@electron-forge/publisher-base": "^6.0.0-beta.3", + "@electron-forge/shared-types": "^6.0.0-beta.3", + "colors": "^1.2.0", "cross-spawn-promise": "^0.10.1", "debug": "^3.0.0", "electron-packager": "^12.0.1", "electron-rebuild": "^1.6.0", "fs-extra": "^5.0.0", "glob": "^7.1.1", - "lodash.merge": "^4.6.0", "lodash.template": "^4.4.0", "log-symbols": "^2.0.0", "node-fetch": "^2.0.0", @@ -60,4 +64,4 @@ "engines": { "node": ">= 6.0" } -} +} \ No newline at end of file diff --git a/packages/api/core/src/api/import.js b/packages/api/core/src/api/import.ts similarity index 74% rename from packages/api/core/src/api/import.js rename to packages/api/core/src/api/import.ts index f9241f04ce..5f2e084bce 100644 --- a/packages/api/core/src/api/import.js +++ b/packages/api/core/src/api/import.ts @@ -13,34 +13,49 @@ import readPackageJSON from '../util/read-package-json'; const d = debug('electron-forge:import'); -/** - * @typedef {Object} ImportOptions - * @property {string} [dir=process.cwd()] The path to the app to be imported - * @property {boolean} [interactive=false] Whether to use sensible defaults or prompt the user visually - * @property {function} [confirmImport] An async function that returns true or false in order to confirm the start of importing - * @property {function} [shouldContinueOnExisting] An async function that returns whether the import should continue if it looks like a forge project already - * @property {function} [shouldRemoveDependency] An async function that returns whether the given dependency should be removed - * @property {function} [shouldUpdateScript] An async function that returns whether the given script should be overridden with a forge one - * @property {string} [outDir=`${dir}/out`] The path to the directory containing generated distributables - */ - -/** - * Attempt to import a given module directory to the Electron Forge standard. - * - * - Sets up `git` and the correct NPM dependencies - * - Adds a template forge config to `package.json` - * - * @param {ImportOptions} providedOptions - Options for the import method - * @return {Promise} Will resolve when the import process is complete - */ -export default async (providedOptions = {}) => { - const { dir, interactive, confirmImport, - shouldContinueOnExisting, shouldRemoveDependency, shouldUpdateScript } = Object.assign({ - dir: process.cwd(), - interactive: false, - }, providedOptions); - - const outDir = providedOptions.outDir || 'out'; +export interface ImportOptions { + /** + * The path to the app to be imported + */ + dir?: string; + /** + * Whether to use sensible defaults or prompt the user visually + */ + interactive?: boolean; + /** + * An async function that returns true or false in order to confirm the start + * of importing + */ + confirmImport?: () => Promise; + /** + * An async function that returns whether the import should continue if it + * looks like a forge project already + */ + shouldContinueOnExisting?: () => Promise; + /** + * An async function that returns whether the given dependency should be removed + */ + shouldRemoveDependency?: (dependency: string, explanation: string) => Promise; + /** + * An async function that returns whether the given script should be overridden with a forge one + */ + shouldUpdateScript?: (scriptName: string, newValue: string) => Promise; + /** + * The path to the directory containing generated distributables + */ + outDir?: string; +} + +export default async ({ + dir = process.cwd(), + interactive = false, + confirmImport, + shouldContinueOnExisting, + shouldRemoveDependency, + shouldUpdateScript, + outDir, +}: ImportOptions) => { + const calculatedOutDir = outDir || 'out'; asyncOra.interactive = interactive; d(`Attempting to import project in: ${dir}`); @@ -71,7 +86,9 @@ export default async (providedOptions = {}) => { packageJSON.devDependencies = packageJSON.devDependencies || {}; const keys = Object.keys(packageJSON.dependencies).concat(Object.keys(packageJSON.devDependencies)); - const buildToolPackages = { + const buildToolPackages: { + [key: string]: string | undefined; + } = { 'electron-builder': 'provides mostly equivalent functionality', 'electron-download': 'already uses this module as a transitive dependency', 'electron-installer-debian': 'already uses this module as a transitive dependency', @@ -85,7 +102,7 @@ export default async (providedOptions = {}) => { for (const key of keys) { if (buildToolPackages[key]) { - const explanation = buildToolPackages[key]; + const explanation = buildToolPackages[key]!; // eslint-disable-next-line max-len let remove = true; if (typeof shouldRemoveDependency === 'function') { @@ -102,7 +119,7 @@ export default async (providedOptions = {}) => { packageJSON.scripts = packageJSON.scripts || {}; d('reading current scripts object:', packageJSON.scripts); - const updatePackageScript = async (scriptName, newValue) => { + const updatePackageScript = async (scriptName: string, newValue: string) => { if (packageJSON.scripts[scriptName] !== newValue) { // eslint-disable-next-line max-len let update = true; @@ -160,8 +177,8 @@ export default async (providedOptions = {}) => { await asyncOra('Fixing .gitignore', async () => { if (await fs.pathExists(path.resolve(dir, '.gitignore'))) { const gitignore = await fs.readFile(path.resolve(dir, '.gitignore')); - if (!gitignore.includes(outDir)) { - await fs.writeFile(path.resolve(dir, '.gitignore'), `${gitignore}\n${outDir}/`); + if (!gitignore.includes(calculatedOutDir)) { + await fs.writeFile(path.resolve(dir, '.gitignore'), `${gitignore}\n${calculatedOutDir}/`); } } }); diff --git a/packages/api/core/src/api/index.js b/packages/api/core/src/api/index.js deleted file mode 100644 index a3e63e4a92..0000000000 --- a/packages/api/core/src/api/index.js +++ /dev/null @@ -1,28 +0,0 @@ -import 'colors'; - -import _import from './import'; -import init from './init'; -import install from './install'; -import lint from './lint'; -import make from './make'; -import _package from './package'; -import publish from './publish'; -import start from './start'; - -import getForgeConfig from '../util/forge-config'; -import readPackageJSON from '../util/read-package-json'; - -module.exports = { - 'import': _import, // eslint-disable-line - init, - install, - lint, - make, - 'package': _package, // eslint-disable-line - publish, - start, - utils: { - getForgeConfig, - readPackageJSON, - }, -}; diff --git a/packages/api/core/src/api/index.ts b/packages/api/core/src/api/index.ts new file mode 100644 index 0000000000..09cdb4e3f1 --- /dev/null +++ b/packages/api/core/src/api/index.ts @@ -0,0 +1,40 @@ +import 'colors'; +import { ForgeMakeResult } from '@electron-forge/shared-types'; +import { ChildProcess } from 'child_process'; + +import _import, { ImportOptions } from './import'; +import init, { InitOptions } from './init'; +import install, { InstallOptions, Asset as InstallAsset } from './install'; +import lint, { LintOptions } from './lint'; +import make, { MakeOptions } from './make'; +import _package, { PackageOptions } from './package'; +import publish, { PublishOptions } from './publish'; +import start, { StartOptions } from './start'; + +import getForgeConfig from '../util/forge-config'; +import readPackageJSON from '../util/read-package-json'; + +const api = { + 'import': _import, + init, + install, + lint, + make, + 'package': _package, + publish, + start, +} + +export { + ForgeMakeResult, + ImportOptions, + InitOptions, + InstallAsset, + InstallOptions, + LintOptions, + MakeOptions, + PackageOptions, + PublishOptions, + StartOptions, + api, +}; diff --git a/packages/api/core/src/api/init-scripts/init-custom.js b/packages/api/core/src/api/init-scripts/init-custom.ts similarity index 96% rename from packages/api/core/src/api/init-scripts/init-custom.js rename to packages/api/core/src/api/init-scripts/init-custom.ts index a15faca30e..fc0eab2591 100644 --- a/packages/api/core/src/api/init-scripts/init-custom.js +++ b/packages/api/core/src/api/init-scripts/init-custom.ts @@ -10,8 +10,8 @@ import installDepList from '../../util/install-dependencies'; const d = debug('electron-forge:init:custom'); -export default async (dir, template) => { - let templateModulePath; +export default async (dir: string, template: string) => { + let templateModulePath!: string; await asyncOra(`Locating custom template: "${template}"`, async () => { try { templateModulePath = await resolvePackage(`electron-forge-template-${template}`); diff --git a/packages/api/core/src/api/init-scripts/init-directory.js b/packages/api/core/src/api/init-scripts/init-directory.ts similarity index 93% rename from packages/api/core/src/api/init-scripts/init-directory.js rename to packages/api/core/src/api/init-scripts/init-directory.ts index 6876d92871..b056d1eb62 100644 --- a/packages/api/core/src/api/init-scripts/init-directory.js +++ b/packages/api/core/src/api/init-scripts/init-directory.ts @@ -5,7 +5,7 @@ import logSymbols from 'log-symbols'; const d = debug('electron-forge:init:directory'); -export default async (dir) => { +export default async (dir: string) => { await asyncOra('Initializing Project Directory', async (initSpinner) => { d('creating directory:', dir); await fs.mkdirs(dir); diff --git a/packages/api/core/src/api/init-scripts/init-git.js b/packages/api/core/src/api/init-scripts/init-git.ts similarity index 94% rename from packages/api/core/src/api/init-scripts/init-git.js rename to packages/api/core/src/api/init-scripts/init-git.ts index 7c6bd83dfb..2d3c26fdc4 100644 --- a/packages/api/core/src/api/init-scripts/init-git.js +++ b/packages/api/core/src/api/init-scripts/init-git.ts @@ -6,7 +6,7 @@ import path from 'path'; const d = debug('electron-forge:init:git'); -export default async (dir) => { +export default async (dir: string) => { await asyncOra('Initializing Git Repository', async () => { await new Promise(async (resolve, reject) => { if (await fs.pathExists(path.resolve(dir, '.git'))) { diff --git a/packages/api/core/src/api/init-scripts/init-npm.js b/packages/api/core/src/api/init-scripts/init-npm.ts similarity index 97% rename from packages/api/core/src/api/init-scripts/init-npm.js rename to packages/api/core/src/api/init-scripts/init-npm.ts index 08bebe80e1..787b3b44ca 100644 --- a/packages/api/core/src/api/init-scripts/init-npm.js +++ b/packages/api/core/src/api/init-scripts/init-npm.ts @@ -14,7 +14,7 @@ export const deps = ['electron-squirrel-startup']; export const devDeps = ['@electron-forge/cli']; export const exactDevDeps = ['electron']; -export default async (dir) => { +export default async (dir: string) => { await asyncOra('Initializing NPM Module', async () => { const packageJSON = await readPackageJSON(path.resolve(__dirname, '../../../tmpl')); packageJSON.productName = packageJSON.name = path.basename(dir).toLowerCase(); diff --git a/packages/api/core/src/api/init-scripts/init-starter-files.js b/packages/api/core/src/api/init-scripts/init-starter-files.ts similarity index 80% rename from packages/api/core/src/api/init-scripts/init-starter-files.js rename to packages/api/core/src/api/init-scripts/init-starter-files.ts index 1c3317e978..bab32c7f5e 100644 --- a/packages/api/core/src/api/init-scripts/init-starter-files.js +++ b/packages/api/core/src/api/init-scripts/init-starter-files.ts @@ -5,12 +5,16 @@ import path from 'path'; const d = debug('electron-forge:init:starter-files'); -export const copy = async (source, target) => { +export const copy = async (source: string, target: string) => { d(`copying "${source}" --> "${target}"`); await fs.copy(source, target); }; -export default async (dir, { copyCIFiles }) => { +export interface InitStarterFilesOptions { + copyCIFiles: boolean; +} + +export default async (dir: string, { copyCIFiles }: InitStarterFilesOptions) => { await asyncOra('Copying Starter Files', async () => { const tmplPath = path.resolve(__dirname, '../../../tmpl'); diff --git a/packages/api/core/src/api/init.js b/packages/api/core/src/api/init.js deleted file mode 100644 index 2b3017691a..0000000000 --- a/packages/api/core/src/api/init.js +++ /dev/null @@ -1,45 +0,0 @@ -import { asyncOra } from '@electron-forge/async-ora'; -import debug from 'debug'; - -import initCustom from './init-scripts/init-custom'; -import initDirectory from './init-scripts/init-directory'; -import initGit from './init-scripts/init-git'; -import initNPM from './init-scripts/init-npm'; -import initStarter from './init-scripts/init-starter-files'; - -const d = debug('electron-forge:init'); - -/** - * @typedef {Object} InitOptions - * @property {string} [dir=process.cwd()] The path to the app to be initialized - * @property {boolean} [interactive=false] Whether to use sensible defaults or prompt the user visually - * @property {boolean} [copyCIFiles=false] Whether to copy Travis and AppVeyor CI files - * @property {string} [template] The custom template to use. If left empty, the default template is used - */ - -/** - * Initialize a new Electron Forge template project in the given directory. - * - * @param {InitOptions} providedOptions - Options for the init method - * @return {Promise} Will resolve when the initialization process is complete - */ -export default async (providedOptions = {}) => { - // eslint-disable-next-line prefer-const, no-unused-vars - let { dir, interactive, copyCIFiles, template } = Object.assign({ - dir: process.cwd(), - interactive: false, - copyCIFiles: false, - template: null, - }, providedOptions); - asyncOra.interactive = interactive; - - d(`Initializing in: ${dir}`); - - await initDirectory(dir); - await initGit(dir); - await initStarter(dir, { copyCIFiles }); - await initNPM(dir); - if (template) { - await initCustom(dir, template); - } -}; diff --git a/packages/api/core/src/api/init.ts b/packages/api/core/src/api/init.ts new file mode 100644 index 0000000000..e0feae1fb4 --- /dev/null +++ b/packages/api/core/src/api/init.ts @@ -0,0 +1,48 @@ +import { asyncOra } from '@electron-forge/async-ora'; +import debug from 'debug'; + +import initCustom from './init-scripts/init-custom'; +import initDirectory from './init-scripts/init-directory'; +import initGit from './init-scripts/init-git'; +import initNPM from './init-scripts/init-npm'; +import initStarter from './init-scripts/init-starter-files'; + +const d = debug('electron-forge:init'); + +export interface InitOptions { + /** + * The path to the app to be initialized + */ + dir?: string; + /** + * Whether to use sensible defaults or prompt the user visually + */ + interactive?: boolean; + /** + * Whether to copy Travis and AppVeyor CI files + */ + copyCIFiles?: boolean; + /** + * The custom template to use. If left empty, the default template is used + */ + template?: string; +} + +export default async ({ + dir = process.cwd(), + interactive = false, + copyCIFiles = false, + template, +}: InitOptions) => { + asyncOra.interactive = interactive; + + d(`Initializing in: ${dir}`); + + await initDirectory(dir); + await initGit(dir); + await initStarter(dir, { copyCIFiles }); + await initNPM(dir); + if (template) { + await initCustom(dir, template); + } +}; diff --git a/packages/api/core/src/api/install.js b/packages/api/core/src/api/install.ts similarity index 73% rename from packages/api/core/src/api/install.js rename to packages/api/core/src/api/install.ts index 167c8dfaf3..125752d42e 100644 --- a/packages/api/core/src/api/install.js +++ b/packages/api/core/src/api/install.ts @@ -3,7 +3,6 @@ import { asyncOra } from '@electron-forge/async-ora'; import debug from 'debug'; import fetch from 'node-fetch'; import fs from 'fs-extra'; -import nugget from 'nugget'; import os from 'os'; import path from 'path'; import pify from 'pify'; @@ -17,38 +16,58 @@ import ExeInstaller from '@electron-forge/installer-exe'; import { info } from '../util/messages'; +const nugget = require('nugget'); + const d = debug('electron-forge:install'); const GITHUB_API = 'https://api.github.com'; -/** - * @typedef {Object} InstallOptions - * @property {boolean} [interactive=false] Whether to use sensible defaults or prompt the user visually - * @property {boolean} [prerelease=false] Whether to install prerelease versions - * @property {string} repo The GitHub repository to install from, in the format owner/name - * @property {function} chooseAsset A function that must return the asset to use/install from a provided array of compatible GitHub assets - */ - -/** - * Install an Electron application from GitHub. If you leave interactive as `false`, you MUST provide a `chooseAsset` function. - * - * @param {InstallOptions} providedOptions - Options for the install method - * @return {Promise} Will resolve when the install process is complete - */ -export default async (providedOptions = {}) => { - // eslint-disable-next-line prefer-const, no-unused-vars - let { interactive, prerelease, repo, chooseAsset } = Object.assign({ - interactive: false, - prerelease: false, - }, providedOptions); +interface Release { + tag_name: string; + prerelease: boolean; + assets: Asset[]; +} + +export interface Asset { + id: string; + name: string; + size: number; + browser_download_url: string; +} + +export interface InstallOptions { + /** + * Whether to use sensible defaults or prompt the user visually + */ + interactive?: boolean; + /** + * Whether to install prerelease versions + */ + prerelease?: boolean; + /** + * The GitHub repository to install from, in the format owner/name + */ + repo: string; + /** + * A function that must return the asset to use/install from a provided array of compatible GitHub assets + */ + chooseAsset: (assets: Asset[]) => Promise | Asset; +} + +export default async ({ + interactive = false, + prerelease = false, + repo, + chooseAsset +}: InstallOptions) => { asyncOra.interactive = interactive; if (typeof chooseAsset !== 'function') { throw 'Expected chooseAsset to be a function in install call'; } - let latestRelease; - let possibleAssets = []; + let latestRelease!: Release; + let possibleAssets: Asset[] = []; await asyncOra('Searching for Application', async (searchSpinner) => { if (!repo || repo.indexOf('/') === -1) { @@ -56,17 +75,21 @@ export default async (providedOptions = {}) => { } d('searching for repo:', repo); - let releases; + let releases!: Release[]; try { releases = await (await fetch(`${GITHUB_API}/repos/${repo}/releases`)).json(); } catch (err) { // Ignore error } - if (!releases || releases.message === 'Not Found' || !Array.isArray(releases)) { + if (!releases || (releases as any).message === 'Not Found' || !Array.isArray(releases)) { throw `Failed to find releases for repository "${repo}". Please check the name and try again.`; } + if (releases.length === 0) { + throw `Repository "${repo}" has no releases`; + } + releases = releases.filter(release => !release.prerelease || prerelease); const sortedReleases = releases.sort((releaseA, releaseB) => { @@ -81,11 +104,13 @@ export default async (providedOptions = {}) => { searchSpinner.text = 'Searching for Releases'; // eslint-disable-line const assets = latestRelease.assets; - if (!assets || !Array.isArray(assets)) { + if (!assets || !Array.isArray(assets) || assets.length === 0) { throw 'Could not find any assets for the latest release'; } - const installTargets = { + const installTargets: { + [key: string]: RegExp[]; + } = { win32: [/\.exe$/], darwin: [/OSX.*\.zip$/, /darwin.*\.zip$/, /macOS.*\.zip$/, /mac.*\.zip$/, /\.dmg$/], linux: [/\.rpm$/, /\.deb$/], @@ -129,7 +154,11 @@ export default async (providedOptions = {}) => { } await asyncOra('Installing Application', async (installSpinner) => { - const installActions = { + const installActions: { + [key: string]: { + [key: string]: any; + }; + } = { win32: { '.exe': ExeInstaller, }, @@ -144,6 +173,9 @@ export default async (providedOptions = {}) => { }; const suffixFnIdent = Object.keys(installActions[process.platform]).find(suffix => targetAsset.name.endsWith(suffix)); + if (!suffixFnIdent) { + throw `No installer to handle "${targetAsset.name}"`; + } const InstallerClass = installActions[process.platform][suffixFnIdent]; const installer = new InstallerClass(); await installer.install({ filePath: fullFilePath, installSpinner }); diff --git a/packages/api/core/src/api/lint.js b/packages/api/core/src/api/lint.js deleted file mode 100644 index c229fdc116..0000000000 --- a/packages/api/core/src/api/lint.js +++ /dev/null @@ -1,58 +0,0 @@ -import 'colors'; -import { asyncOra } from '@electron-forge/async-ora'; -import debug from 'debug'; -import { yarnOrNpmSpawn } from '../util/yarn-or-npm'; - -import resolveDir from '../util/resolve-dir'; - -const d = debug('electron-forge:lint'); - -/** - * @typedef {Object} LintOptions - * @property {string} [dir=process.cwd()] The path to the module to import - * @property {boolean} [interactive=false] Whether to use sensible defaults or prompt the user visually - */ - -/** - * Lint a local Electron application. - * - * The promise will be rejected with the stdout+stderr of the linting process if linting fails or - * will be resolved if it succeeds. - * - * @param {LintOptions} providedOptions - Options for the Lint method - * @return {Promise} Will resolve when the lint process is complete - */ -export default async (providedOptions = {}) => { - // eslint-disable-next-line prefer-const, no-unused-vars - let { dir, interactive } = Object.assign({ - dir: process.cwd(), - interactive: false, - }, providedOptions); - asyncOra.interactive = interactive; - - let success = true; - let result = null; - - await asyncOra('Linting Application', async (lintSpinner) => { - dir = await resolveDir(dir); - if (!dir) { - throw 'Failed to locate lintable Electron application'; - } - - d('executing "run lint" in dir:', dir); - try { - await yarnOrNpmSpawn(['run', 'lint'], { - stdio: process.platform === 'win32' ? 'inherit' : 'pipe', - cwd: dir, - }); - } catch (err) { - lintSpinner.fail(); - success = false; - result = err; - } - }); - - if (!success) { - throw result; - } -}; diff --git a/packages/api/core/src/api/lint.ts b/packages/api/core/src/api/lint.ts new file mode 100644 index 0000000000..bf6e157658 --- /dev/null +++ b/packages/api/core/src/api/lint.ts @@ -0,0 +1,47 @@ +import 'colors'; +import { asyncOra } from '@electron-forge/async-ora'; +import debug from 'debug'; +import { yarnOrNpmSpawn } from '../util/yarn-or-npm'; + +import resolveDir from '../util/resolve-dir'; + +const d = debug('electron-forge:lint'); + +export interface LintOptions { + dir?: string; + interactive?: boolean; +} + +export default async ({ + dir = process.cwd(), + interactive = false, +}: LintOptions) => { + asyncOra.interactive = interactive; + + let success = true; + let result = null; + + await asyncOra('Linting Application', async (lintSpinner) => { + const resolvedDir = await resolveDir(dir); + if (!resolvedDir) { + throw 'Failed to locate lintable Electron application'; + } + dir = resolvedDir; + + d('executing "run lint" in dir:', dir); + try { + await yarnOrNpmSpawn(['run', 'lint'], { + stdio: process.platform === 'win32' ? 'inherit' : 'pipe', + cwd: dir, + }); + } catch (err) { + lintSpinner.fail(); + success = false; + result = err; + } + }); + + if (!success) { + throw result; + } +}; diff --git a/packages/api/core/src/api/make.js b/packages/api/core/src/api/make.ts similarity index 61% rename from packages/api/core/src/api/make.js rename to packages/api/core/src/api/make.ts index 98364fe96a..4c10eb062c 100644 --- a/packages/api/core/src/api/make.js +++ b/packages/api/core/src/api/make.ts @@ -1,8 +1,9 @@ import 'colors'; import { asyncOra } from '@electron-forge/async-ora'; +import { IForgeResolvableMaker, ForgeConfig, ForgeArch, ForgePlatform, ForgeMakeResult } from '@electron-forge/shared-types'; +import MakerBase from '@electron-forge/maker-base'; import fs from 'fs-extra'; import path from 'path'; -import { hostArch } from 'electron-packager/targets'; import getForgeConfig from '../util/forge-config'; import runHook from '../util/hook'; @@ -15,61 +16,63 @@ import getElectronVersion from '../util/electron-version'; import packager from './package'; -/** - * @typedef {Object} MakeTarget - * @property {string} [name] The module name that exports the maker - * @property {Array} [platforms=null] The platforms this make target should run on - * @property {Object} [config] The arbitrary config to pass to this make target - */ - -/** - * @typedef {Object} MakeOptions - * @property {string} [dir=process.cwd()] The path to the app from which distributables are generated - * @property {boolean} [interactive=false] Whether to use sensible defaults or prompt the user visually - * @property {boolean} [skipPackage=false] Whether to skip the pre-make packaging step - * @property {Array} [overrideTargets] An array of make targets to override your forge config - * @property {string} [arch=host architecture] The target architecture - * @property {string} [platform=process.platform] The target platform. - * @property {string} [outDir=`${dir}/out`] The path to the directory containing generated distributables - */ - -/** - * @typedef {Object} MakeResult - * @property {Array} artifacts An array of paths to artifacts generated for this make run - * @property {Object} packageJSON The state of the package.json file when the make happened - * @property {string} platform The platform this make run was for - * @property {string} arch The arch this make run was for - */ - -/** - * Make distributables for an Electron application. - * - * @param {MakeOptions} providedOptions - Options for the make method - * @return {Promise>} Will resolve when the make process is complete - */ -export default async (providedOptions = {}) => { - // eslint-disable-next-line prefer-const, no-unused-vars - let { dir, interactive, skipPackage, overrideTargets, arch, platform } = Object.assign({ - dir: process.cwd(), - interactive: false, - skipPackage: false, - arch: hostArch(), - platform: process.platform, - }, providedOptions); +const { hostArch } = require('electron-packager/targets'); + +export interface MakeOptions { + /** + * The path to the app from which distrubutables are generated + */ + dir?: string; + /** + * Whether to use sensible defaults or prompt the user visually + */ + interactive?: boolean; + /** + * Whether to skip the pre-make packaging step + */ + skipPackage?: boolean; + /** + * An array of make targets to override your forge config + */ + overrideTargets?: (IForgeResolvableMaker | MakerBase)[]; + /** + * The target architecture + */ + arch?: ForgeArch; + /** + * The target platform + */ + platform?: ForgePlatform; + /** + * The path to the directory containing generated distributables + */ + outDir?: string; +} + +export default async ({ + dir = process.cwd(), + interactive = false, + skipPackage = false, + arch = hostArch(), + platform = process.platform as ForgePlatform, + overrideTargets, + outDir, +}: MakeOptions) => { asyncOra.interactive = interactive; - let forgeConfig; + let forgeConfig!: ForgeConfig; await asyncOra('Resolving Forge Config', async () => { - dir = await resolveDir(dir); - if (!dir) { + const resolvedDir = await resolveDir(dir); + if (!resolvedDir) { throw 'Failed to locate makeable Electron application'; } + dir = resolvedDir; forgeConfig = await getForgeConfig(dir); }); - const outDir = providedOptions.outDir || getCurrentOutDir(dir, forgeConfig); + const actualOutDir = outDir || getCurrentOutDir(dir, forgeConfig); const actualTargetPlatform = platform; platform = platform === 'mas' ? 'darwin' : platform; @@ -77,7 +80,9 @@ export default async (providedOptions = {}) => { throw new Error(`'${actualTargetPlatform}' is an invalid platform. Choices are 'darwin', 'mas', 'win32' or 'linux'`); } - const makers = {}; + const makers: { + [key: number]: MakerBase; + } = {}; const targets = (overrideTargets || forgeConfig.makers.filter( maker => maker.platforms ? maker.platforms.indexOf(platform) !== -1 @@ -91,20 +96,21 @@ export default async (providedOptions = {}) => { let targetId = 0; for (const target of targets) { - let maker; - if (target.__isElectronForgeMaker) { - maker = target; + let maker: MakerBase; + if ((target as MakerBase).__isElectronForgeMaker) { + maker = target as MakerBase; } else { + const resolvableTarget: IForgeResolvableMaker = target as IForgeResolvableMaker; let makerModule; try { - makerModule = require(target.name); + makerModule = require(resolvableTarget.name); } catch (err) { console.error(err); - throw `Could not find module with name: ${target.name}`; + throw `Could not find module with name: ${resolvableTarget.name}`; } const MakerClass = makerModule.default || makerModule; - maker = new MakerClass(target.config, target.platforms); + maker = new MakerClass(resolvableTarget.config, resolvableTarget.platforms); } if (!maker.isSupportedOnCurrentPlatform) { @@ -132,23 +138,23 @@ export default async (providedOptions = {}) => { dir, interactive, arch, - outDir, + outDir: actualOutDir, platform: actualTargetPlatform, }); } else { warn(interactive, 'WARNING: Skipping the packaging step, this could result in an out of date build'.red); } - info(interactive, 'Making for the following targets:', `${targets.join(', ')}`.cyan); + info(interactive, `Making for the following targets: ${`${targets.join(', ')}`.cyan}`); const packageJSON = await readPackageJSON(dir); const appName = forgeConfig.packagerConfig.name || packageJSON.productName || packageJSON.name; - let outputs = []; + let outputs: ForgeMakeResult[] = []; await runHook(forgeConfig, 'preMake'); for (const targetArch of parseArchs(platform, arch, getElectronVersion(packageJSON))) { - const packageDir = path.resolve(outDir, `${appName}-${actualTargetPlatform}-${targetArch}`); + const packageDir = path.resolve(actualOutDir, `${appName}-${actualTargetPlatform}-${targetArch}`); if (!(await fs.pathExists(packageDir))) { throw new Error(`Couldn't find packaged app at: ${packageDir}`); } @@ -163,7 +169,7 @@ export default async (providedOptions = {}) => { try { const artifacts = await maker.make({ dir: packageDir, - makeDir: path.resolve(outDir, 'make'), + makeDir: path.resolve(actualOutDir, 'make'), appName, targetPlatform: actualTargetPlatform, targetArch, @@ -180,18 +186,18 @@ export default async (providedOptions = {}) => { } catch (err) { if (err) { throw { - message: `An error occured while making for target: ${target.name}`, + message: `An error occured while making for target: ${maker.name}`, stack: `${err.message}\n${err.stack}`, }; } else { - throw new Error(`An unknown error occured while making for target: ${target}`); + throw new Error(`An unknown error occured while making for target: ${maker.name}`); } } }); } } - const result = await runHook(forgeConfig, 'postMake', outputs); + const result = await runHook(forgeConfig, 'postMake', outputs) as ForgeMakeResult[] | undefined; // If the postMake hooks modifies the locations / names of the outputs it must return // the new locations so that the publish step knows where to look if (Array.isArray(result)) { diff --git a/packages/api/core/src/api/package.js b/packages/api/core/src/api/package.ts similarity index 66% rename from packages/api/core/src/api/package.js rename to packages/api/core/src/api/package.ts index 7bcfe3c05f..bd31654f03 100644 --- a/packages/api/core/src/api/package.js +++ b/packages/api/core/src/api/package.ts @@ -1,12 +1,12 @@ import 'colors'; -import { ora as realOra, fakeOra } from '@electron-forge/async-ora'; +import { ora as realOra, fakeOra, OraImpl } from '@electron-forge/async-ora'; +import { ForgeArch, ForgePlatform, ForgeConfig } from '@electron-forge/shared-types'; import debug from 'debug'; import fs from 'fs-extra'; import glob from 'glob'; import path from 'path'; import pify from 'pify'; import packager from 'electron-packager'; -import { hostArch } from 'electron-packager/targets'; import getForgeConfig from '../util/forge-config'; import runHook from '../util/hook'; @@ -18,63 +18,83 @@ import resolveDir from '../util/resolve-dir'; import getCurrentOutDir from '../util/out-dir'; import getElectronVersion from '../util/electron-version'; +const { hostArch }: { hostArch: () => ForgeArch | 'all'} = require('electron-packager/targets'); + const d = debug('electron-forge:packager'); -/** - * @typedef {Object} PackageOptions - * @property {string} [dir=process.cwd()] The path to the app to package - * @property {boolean} [interactive=false] Whether to use sensible defaults or prompt the user visually - * @property {string} [arch=process.arch] The target arch - * @property {string} [platform=process.platform] The target platform. - * @property {string} [outDir=`${dir}/out`] The path to the output directory for packaged apps - */ +type ElectronPackagerAfterCopyHook = + (buildPath: string, electronVersion: string, pPlatform: ForgePlatform, pArch: ForgeArch, done: (err?: Error) => void) => void; /** * Resolves hooks if they are a path to a file (instead of a `Function`). */ -function resolveHooks(hooks, dir) { +function resolveHooks(hooks: (string | ElectronPackagerAfterCopyHook)[] | undefined, dir: string) { if (hooks) { - return hooks.map(hook => (typeof hook === 'string' ? requireSearch(dir, [hook]) : hook)); + return hooks.map(hook => ( + typeof hook === 'string' + ? requireSearch(dir, [hook]) as ElectronPackagerAfterCopyHook + : hook + )); } return []; } -function sequentialHooks(hooks) { - return [async (...args) => { +/** + * Runs given hooks sequentially by mapping them to promises and iterating + * through while awaiting + */ +function sequentialHooks(hooks: Function[]) { + return [async (...args: any[]) => { const done = args[args.length - 1]; const passedArgs = args.splice(0, args.length - 1); for (const hook of hooks) { await pify(hook)(...passedArgs); } done(); - }]; + }] as [(...args: any[]) => Promise]; } -/** - * Package an Electron application into an platform dependent format. - * - * @param {PackageOptions} providedOptions - Options for the Package method - * @return {Promise} Will resolve when the package process is complete - */ -export default async (providedOptions = {}) => { - // eslint-disable-next-line prefer-const, no-unused-vars - let { dir, interactive, arch, platform } = Object.assign({ - dir: process.cwd(), - interactive: false, - arch: hostArch(), - platform: process.platform, - }, providedOptions); +export interface PackageOptions { + /** + * The path to the app to package + */ + dir?: string; + /** + * Whether to use sensible defaults or prompt the user visually + */ + interactive?: boolean; + /** + * The target arch + */ + arch?: ForgeArch; + /** + * The target platform. + */ + platform?: ForgePlatform; + /** + * The path to the output directory for packaged apps + */ + outDir?: string; +} +export default async ({ + dir = process.cwd(), + interactive = false, + arch = hostArch(), + platform = process.platform, + outDir, +}: PackageOptions) => { const ora = interactive ? realOra : fakeOra; let prepareSpinner = ora(`Preparing to Package Application for arch: ${(arch === 'all' ? 'ia32' : arch).cyan}`).start(); let prepareCounter = 0; - dir = await resolveDir(dir); - if (!dir) { + const resolvedDir = await resolveDir(dir); + if (!resolvedDir) { throw 'Failed to locate compilable Electron application'; } + dir = resolvedDir; const packageJSON = await readPackageJSON(dir); @@ -84,12 +104,12 @@ export default async (providedOptions = {}) => { } const forgeConfig = await getForgeConfig(dir); - const outDir = providedOptions.outDir || getCurrentOutDir(dir, forgeConfig); - let packagerSpinner; + const calculatedOutDir = outDir || getCurrentOutDir(dir, forgeConfig); + let packagerSpinner: OraImpl | null = null; const pruneEnabled = !('prune' in forgeConfig.packagerConfig) || forgeConfig.packagerConfig.prune; - const afterCopyHooks = [ + const afterCopyHooks: ElectronPackagerAfterCopyHook[] = [ async (buildPath, electronVersion, pPlatform, pArch, done) => { if (packagerSpinner) { packagerSpinner.succeed(); @@ -107,7 +127,7 @@ export default async (providedOptions = {}) => { done(); }, async (buildPath, electronVersion, pPlatform, pArch, done) => { - await rebuildHook(buildPath, electronVersion, pPlatform, pArch, forgeConfig.rebuildConfig); + await rebuildHook(buildPath, electronVersion, pPlatform, pArch, forgeConfig.electronRebuildConfig); packagerSpinner = ora('Packaging Application').start(); done(); }, @@ -130,12 +150,12 @@ export default async (providedOptions = {}) => { afterPruneHooks.push(...resolveHooks(forgeConfig.packagerConfig.afterPrune, dir)); } - afterPruneHooks.push(async (buildPath, electronVersion, pPlatform, pArch, done) => { + afterPruneHooks.push((async (buildPath, electronVersion, pPlatform, pArch, done) => { await runHook(forgeConfig, 'packageAfterPrune', buildPath, electronVersion, pPlatform, pArch); done(); - }); + }) as ElectronPackagerAfterCopyHook); - const packageOpts = Object.assign({ + const packageOpts: packager.Options = Object.assign({ asar: false, overwrite: true, }, forgeConfig.packagerConfig, { @@ -145,7 +165,7 @@ export default async (providedOptions = {}) => { dir, arch, platform, - out: outDir, + out: calculatedOutDir, electronVersion: getElectronVersion(packageJSON), }); packageOpts.quiet = true; @@ -160,9 +180,9 @@ export default async (providedOptions = {}) => { d('packaging with options', packageOpts); - await packager(packageOpts); + await (packager as (opts: packager.Options) => Promise)(packageOpts); await runHook(forgeConfig, 'postPackage'); - packagerSpinner.succeed(); + if (packagerSpinner) packagerSpinner!.succeed(); }; diff --git a/packages/api/core/src/api/publish.js b/packages/api/core/src/api/publish.js deleted file mode 100644 index 6da6c90611..0000000000 --- a/packages/api/core/src/api/publish.js +++ /dev/null @@ -1,165 +0,0 @@ -import 'colors'; -import { asyncOra } from '@electron-forge/async-ora'; -import debug from 'debug'; -import fs from 'fs-extra'; -import path from 'path'; - -import getForgeConfig from '../util/forge-config'; -import readPackageJSON from '../util/read-package-json'; -import resolveDir from '../util/resolve-dir'; -import PublishState from '../util/publish-state'; -import getCurrentOutDir from '../util/out-dir'; - -import make from './make'; - -const d = debug('electron-forge:publish'); - -/** - * @typedef {Object} PublishTarget - * @property {string} [name] - * @property {Array} [platforms=[process.platform]] - * @property {Object} [config={}] - */ - -/** - * @typedef {Object} PublishOptions - * @property {string} [dir=process.cwd()] The path to the app to be published - * @property {boolean} [interactive=false] Whether to use sensible defaults or prompt the user visually - * @property {string} [tag=packageJSON.version] The string to tag this release with - * @property {Array} [publishTargets=[]] The publish targets - * @property {MakeOptions} [makeOptions] Options object to passed through to make() - * @property {string} [outDir=`${dir}/out`] The path to the directory containing generated distributables - * @property {boolean} [dryRun=false] Whether to generate dry run meta data but not actually publish - * @property {boolean} [dryRunResume=false] Whether or not to attempt to resume a previously saved `dryRun` and publish - * @property {MakeResult} [makeResults=null] Provide results from make so that the publish step doesn't run make itself - */ - -/** - * Publish an Electron application into the given target service. - * - * @param {PublishOptions} providedOptions - Options for the Publish method - * @return {Promise} Will resolve when the publish process is complete - */ -const publish = async (providedOptions = {}) => { - // eslint-disable-next-line prefer-const, no-unused-vars - let { dir, interactive, authToken, tag, publishTargets, makeOptions, dryRun, dryRunResume, makeResults } = Object.assign({ - dir: process.cwd(), - interactive: false, - tag: null, - makeOptions: {}, - publishTargets: null, - dryRun: false, - dryRunResume: false, - makeResults: null, - }, providedOptions); - asyncOra.interactive = interactive; - - if (dryRun && dryRunResume) { - throw 'Can\'t dry run and resume a dry run at the same time'; - } - if (dryRunResume && makeResults) { - throw 'Can\'t resume a dry run and use the provided makeResults at the same time'; - } - - let packageJSON = await readPackageJSON(dir); - if (tag === null) tag = packageJSON.version; - - const forgeConfig = await getForgeConfig(dir); - const outDir = providedOptions.outDir || getCurrentOutDir(dir, forgeConfig); - const dryRunDir = path.resolve(outDir, 'publish-dry-run'); - - if (dryRunResume) { - d('attempting to resume from dry run'); - const publishes = await PublishState.loadFromDirectory(dryRunDir, dir); - for (const publishStates of publishes) { - d('publishing for given state set'); - await publish({ - dir, - interactive, - authToken, - tag, - publishTargets, - makeOptions, - dryRun: false, - dryRunResume: false, - makeResults: publishStates.map(({ state }) => state), - }); - } - return; - } else if (!makeResults) { - d('triggering make'); - makeResults = await make(Object.assign({ - dir, - interactive, - }, makeOptions)); - } else { - // Restore values from dry run - d('restoring publish settings from dry run'); - - for (const makeResult of makeResults) { - packageJSON = makeResult.packageJSON; - makeOptions.platform = makeResult.platform; - makeOptions.arch = makeResult.arch; - - for (const makePath of makeResult.artifacts) { - if (!await fs.exists(makePath)) { - throw `Attempted to resume a dry run but an artifact (${makePath}) could not be found`; - } - } - } - } - - if (dryRun) { - d('saving results of make in dry run state', makeResults); - await fs.remove(dryRunDir); - await PublishState.saveToDirectory(dryRunDir, makeResults, dir); - return; - } - - dir = await resolveDir(dir); - if (!dir) { - throw 'Failed to locate publishable Electron application'; - } - - const testPlatform = makeOptions.platform || process.platform; - if (publishTargets === null) { - publishTargets = (forgeConfig.publishers || []) - .filter(publisher => publisher.platforms ? publisher.platforms.indexOf(testPlatform !== -1) : true); - } - publishTargets = publishTargets.map((target) => { - if (typeof target === 'string') return { name: target }; - return target; - }); - - for (const publishTarget of publishTargets) { - let publisher; - if (publishTarget.__isElectronForgePublisher) { - publisher = publishTarget; - } else { - let publisherModule; - await asyncOra(`Resolving publish target: ${`${publishTarget.name}`.cyan}`, async () => { // eslint-disable-line no-loop-func - try { - publisherModule = require(publishTarget.name); - } catch (err) { - console.error(err); - throw `Could not find a publish target with the name: ${publishTarget.name}`; - } - }); - - const PublisherClass = publisherModule.default || publisherModule; - publisher = new PublisherClass(publishTarget.config || {}, publishTarget.platforms); - } - - await publisher.publish({ - dir, - makeResults, - packageJSON, - forgeConfig, - tag, - platform: makeOptions.platform || process.platform, - arch: makeOptions.arch || process.arch, - }); - } -}; - -export default publish; diff --git a/packages/api/core/src/api/publish.ts b/packages/api/core/src/api/publish.ts new file mode 100644 index 0000000000..1c9326ab8e --- /dev/null +++ b/packages/api/core/src/api/publish.ts @@ -0,0 +1,172 @@ +import 'colors'; +import { asyncOra } from '@electron-forge/async-ora'; +import { IForgeResolvablePublisher, IForgePublisher, ForgeMakeResult, ForgePlatform } from '@electron-forge/shared-types'; +import PublisherBase from '@electron-forge/publisher-base'; +import debug from 'debug'; +import fs from 'fs-extra'; +import path from 'path'; + +import getForgeConfig from '../util/forge-config'; +import readPackageJSON from '../util/read-package-json'; +import resolveDir from '../util/resolve-dir'; +import PublishState from '../util/publish-state'; +import getCurrentOutDir from '../util/out-dir'; + +import make, { MakeOptions } from './make'; + +const d = debug('electron-forge:publish'); + +export interface PublishOptions { + /** + * The path to the app to be published + */ + dir?: string; + /** + * Whether to use sensible defaults or prompt the user visually + */ + interactive?: boolean; + /** + * The publish targets, by default pulled from forge config, set this prop to + * override that list + */ + publishTargets?: (IForgeResolvablePublisher | IForgePublisher | string)[]; + /** + * Options object to passed through to make() + */ + makeOptions?: MakeOptions; + /** + * The path to the directory containing generated distributables + */ + outDir?: string; + /** + * Whether to generate dry run meta data but not actually publish + */ + dryRun?: boolean; + /** + * Whether or not to attempt to resume a previously saved `dryRun` and publish + * + * You can't use this combination at the same time as dryRun=true + */ + dryRunResume?: boolean; + /** + * Provide results from make so that the publish step doesn't run make itself + */ + makeResults?: ForgeMakeResult[]; +} + +const publish = async ({ + dir = process.cwd(), + interactive = false, + makeOptions = {}, + publishTargets = undefined, + dryRun = false, + dryRunResume = false, + makeResults = undefined, + outDir, +}: PublishOptions) => { + asyncOra.interactive = interactive; + + if (dryRun && dryRunResume) { + throw 'Can\'t dry run and resume a dry run at the same time'; + } + if (dryRunResume && makeResults) { + throw 'Can\'t resume a dry run and use the provided makeResults at the same time'; + } + + let packageJSON = await readPackageJSON(dir); + + const forgeConfig = await getForgeConfig(dir); + const calculatedOutDir = outDir || getCurrentOutDir(dir, forgeConfig); + const dryRunDir = path.resolve(calculatedOutDir, 'publish-dry-run'); + + if (dryRunResume) { + d('attempting to resume from dry run'); + const publishes = await PublishState.loadFromDirectory(dryRunDir, dir); + for (const publishStates of publishes) { + d('publishing for given state set'); + await publish({ + dir, + interactive, + publishTargets, + makeOptions, + dryRun: false, + dryRunResume: false, + makeResults: publishStates.map(({ state }) => state), + }); + } + return; + } else if (!makeResults) { + d('triggering make'); + makeResults = await make(Object.assign({ + dir, + interactive, + }, makeOptions)); + } else { + // Restore values from dry run + d('restoring publish settings from dry run'); + + for (const makeResult of makeResults) { + packageJSON = makeResult.packageJSON; + makeOptions.platform = makeResult.platform; + makeOptions.arch = makeResult.arch; + + for (const makePath of makeResult.artifacts) { + if (!await fs.pathExists(makePath)) { + throw `Attempted to resume a dry run but an artifact (${makePath}) could not be found`; + } + } + } + } + + if (dryRun) { + d('saving results of make in dry run state', makeResults); + await fs.remove(dryRunDir); + await PublishState.saveToDirectory(dryRunDir, makeResults, dir); + return; + } + + const resolvedDir = await resolveDir(dir); + if (!resolvedDir) { + throw 'Failed to locate publishable Electron application'; + } + dir = resolvedDir; + + const testPlatform = makeOptions.platform || process.platform as ForgePlatform; + if (!publishTargets) { + publishTargets = (forgeConfig.publishers || []) + // .filter(publisher => (typeof publisher !== 'string' && publisher.platforms) ? publisher.platforms.indexOf(testPlatform) !== -1 : true); + } + publishTargets = publishTargets.map((target) => { + if (typeof target === 'string') return { name: target }; + return target; + }) as (IForgeResolvablePublisher | IForgePublisher)[]; + + for (const publishTarget of publishTargets) { + let publisher: PublisherBase; + if ((publishTarget as IForgePublisher).__isElectronForgePublisher) { + publisher = publishTarget as any; + } else { + const resolvablePublishTarget = publishTarget as IForgeResolvablePublisher; + let publisherModule: any; + await asyncOra(`Resolving publish target: ${`${resolvablePublishTarget.name}`.cyan}`, async () => { // eslint-disable-line no-loop-func + try { + publisherModule = require(resolvablePublishTarget.name); + } catch (err) { + console.error(err); + throw `Could not find a publish target with the name: ${resolvablePublishTarget.name}`; + } + }); + + const PublisherClass = publisherModule.default || publisherModule; + publisher = new PublisherClass(resolvablePublishTarget.config || {}, resolvablePublishTarget.platforms); + } + + await publisher.publish({ + dir, + makeResults, + forgeConfig, + }); + } +}; + +export default publish; diff --git a/packages/api/core/src/api/start.js b/packages/api/core/src/api/start.js deleted file mode 100644 index 4cb2f3d905..0000000000 --- a/packages/api/core/src/api/start.js +++ /dev/null @@ -1,98 +0,0 @@ -import 'colors'; -import { asyncOra } from '@electron-forge/async-ora'; -import { spawn } from 'child_process'; -import path from 'path'; - -import readPackageJSON from '../util/read-package-json'; -import rebuild from '../util/rebuild'; -import resolveDir from '../util/resolve-dir'; -import getForgeConfig from '../util/forge-config'; -import runHook from '../util/hook'; -import getElectronVersion from '../util/electron-version'; - -/** - * @typedef {Object} StartOptions - * @property {string} [dir=process.cwd()] The path to the electron forge project to run - * @property {string} [appPath='.'] The path (relative to dir) to the electron app to run relative to the project directory - * @property {boolean} [interactive=false] Whether to use sensible defaults or prompt the user visually - * @property {boolean} [enableLogging=false] Enables advanced internal Electron debug calls - * @property {Array} [args] Arguments to pass through to the launched Electron application - */ - -/** - * Start an Electron application. - * - * @param {StartOptions} providedOptions - Options for the Publish method - * @return {Promise} Will resolve when the application is launched - */ -export default async (providedOptions = {}) => { - // eslint-disable-next-line prefer-const, no-unused-vars - let { dir, interactive, enableLogging, appPath, args, runAsNode, inspect } = Object.assign({ - dir: process.cwd(), - appPath: '.', - interactive: false, - enableLogging: false, - args: [], - runAsNode: false, - inspect: false, - }, providedOptions); - asyncOra.interactive = interactive; - - await asyncOra('Locating Application', async () => { - dir = await resolveDir(dir); - if (!dir) { - throw 'Failed to locate startable Electron application'; - } - }); - - const packageJSON = await readPackageJSON(dir); - - if (!packageJSON.version) { - throw `Please set your application's 'version' in '${dir}/package.json'.`; - } - - const forgeConfig = await getForgeConfig(dir); - - await rebuild(dir, getElectronVersion(packageJSON), process.platform, process.arch, forgeConfig.electronRebuildConfig); - - await runHook(forgeConfig, 'generateAssets'); - - // If a plugin has taken over the start command let's stop here - const spawnedPluginChild = await forgeConfig.pluginInterface.overrideStartLogic({ - dir, - appPath, - interactive, - enableLogging, - args, - runAsNode, - inspect, - }); - if (spawnedPluginChild) return spawnedPluginChild; - - const spawnOpts = { - cwd: dir, - stdio: 'inherit', - env: Object.assign({}, process.env, enableLogging ? { - ELECTRON_ENABLE_LOGGING: true, - ELECTRON_ENABLE_STACK_DUMPING: true, - } : {}), - }; - - if (runAsNode) { - spawnOpts.env.ELECTRON_RUN_AS_NODE = true; - } else { - delete spawnOpts.env.ELECTRON_RUN_AS_NODE; - } - - if (inspect) { - args = ['--inspect'].concat(args); - } - - let spawned; - - await asyncOra('Launching Application', async () => { - spawned = spawn(process.execPath, [path.resolve(dir, 'node_modules/electron/cli'), appPath].concat(args), spawnOpts); - }); - - return spawned; -}; diff --git a/packages/api/core/src/api/start.ts b/packages/api/core/src/api/start.ts new file mode 100644 index 0000000000..7a85c9a402 --- /dev/null +++ b/packages/api/core/src/api/start.ts @@ -0,0 +1,120 @@ +import 'colors'; +import { asyncOra } from '@electron-forge/async-ora'; +import { spawn, ChildProcess } from 'child_process'; +import path from 'path'; + +import readPackageJSON from '../util/read-package-json'; +import rebuild from '../util/rebuild'; +import resolveDir from '../util/resolve-dir'; +import getForgeConfig from '../util/forge-config'; +import runHook from '../util/hook'; +import getElectronVersion from '../util/electron-version'; +import { ForgePlatform, ForgeArch } from '@electron-forge/shared-types'; + +export interface StartOptions { + /** + * The path to the electron forge project to run + */ + dir?: string; + /** + * The path (relative to dir) to the electron app to run relative to the project directory + */ + appPath?: string; + /** + * Whether to use sensible defaults or prompt the user visually + */ + interactive?: boolean; + /** + * Enables advanced internal Electron debug calls + */ + enableLogging?: boolean; + /** + * Arguments to pass through to the launched Electron application + */ + args?: (string | number)[]; + /** + * Runs the Electron process as if it were node, disables all Electron API's + */ + runAsNode?: boolean; + /** + * Enables the node inspector, you can connect to this from chrome://inspect + */ + inspect?: boolean; +} + +export default async ({ + dir = process.cwd(), + appPath = '.', + interactive = false, + enableLogging = false, + args = [], + runAsNode = false, + inspect = false, +}: StartOptions) => { + asyncOra.interactive = interactive; + + await asyncOra('Locating Application', async () => { + const resolvedDir = await resolveDir(dir); + if (!resolvedDir) { + throw 'Failed to locate startable Electron application'; + } + dir = resolvedDir; + }); + + const packageJSON = await readPackageJSON(dir); + + if (!packageJSON.version) { + throw `Please set your application's 'version' in '${dir}/package.json'.`; + } + + const forgeConfig = await getForgeConfig(dir); + + await rebuild( + dir, + getElectronVersion(packageJSON), + process.platform as ForgePlatform, + process.arch as ForgeArch, + forgeConfig.electronRebuildConfig + ); + + await runHook(forgeConfig, 'generateAssets'); + + // If a plugin has taken over the start command let's stop here + const spawnedPluginChild = await forgeConfig.pluginInterface.overrideStartLogic({ + dir, + appPath, + interactive, + enableLogging, + args, + runAsNode, + inspect, + }); + if (spawnedPluginChild) return spawnedPluginChild; + + const spawnOpts = { + cwd: dir, + stdio: 'inherit', + env: Object.assign({}, process.env, enableLogging ? { + ELECTRON_ENABLE_LOGGING: 'true', + ELECTRON_ENABLE_STACK_DUMPING: 'true', + } : {}) as NodeJS.ProcessEnv, + }; + + if (runAsNode) { + spawnOpts.env.ELECTRON_RUN_AS_NODE = 'true'; + } else { + delete spawnOpts.env.ELECTRON_RUN_AS_NODE; + } + + if (inspect) { + args = ['--inspect' as (string|number)].concat(args); + } + + let spawned!: ChildProcess; + + await asyncOra('Launching Application', async () => { + spawned = spawn(process.execPath, [path.resolve(dir, 'node_modules/electron/cli'), appPath].concat(args as string[]), spawnOpts); + }); + + return spawned; +}; diff --git a/packages/api/core/src/util/config-fn.js b/packages/api/core/src/util/config-fn.ts similarity index 55% rename from packages/api/core/src/util/config-fn.js rename to packages/api/core/src/util/config-fn.ts index 39f6341275..e537e904b6 100644 --- a/packages/api/core/src/util/config-fn.js +++ b/packages/api/core/src/util/config-fn.ts @@ -1,4 +1,4 @@ -export default (configObject, ...args) => { +export default (configObject: T | ((...args: A[]) => T), ...args: A[]): T => { if (typeof configObject === 'function') { return configObject(...args); } diff --git a/packages/api/core/src/util/deprecate.js b/packages/api/core/src/util/deprecate.ts similarity index 69% rename from packages/api/core/src/util/deprecate.js rename to packages/api/core/src/util/deprecate.ts index 75a5a6ce33..c32aeba399 100644 --- a/packages/api/core/src/util/deprecate.js +++ b/packages/api/core/src/util/deprecate.ts @@ -1,8 +1,8 @@ import 'colors'; import logSymbols from 'log-symbols'; -export default what => ({ - replaceWith: (replacement) => { +export default (what: string) => ({ + replaceWith: (replacement: string) => { console.warn(logSymbols.warning, `WARNING: ${what} is deprecated, please use ${replacement} instead`.yellow); }, }); diff --git a/packages/api/core/src/util/electron-version.js b/packages/api/core/src/util/electron-version.ts similarity index 85% rename from packages/api/core/src/util/electron-version.js rename to packages/api/core/src/util/electron-version.ts index 7e20cc6cd7..28c8dacc3f 100644 --- a/packages/api/core/src/util/electron-version.js +++ b/packages/api/core/src/util/electron-version.ts @@ -1,4 +1,4 @@ -export default (packageJSON) => { +export default (packageJSON: any) => { if (!packageJSON.devDependencies) return null; return (packageJSON.devDependencies['electron-prebuilt-compile'] || packageJSON.devDependencies['electron-prebuilt'] diff --git a/packages/api/core/src/util/forge-config.js b/packages/api/core/src/util/forge-config.ts similarity index 71% rename from packages/api/core/src/util/forge-config.js rename to packages/api/core/src/util/forge-config.ts index 60847c3858..4950245f65 100644 --- a/packages/api/core/src/util/forge-config.js +++ b/packages/api/core/src/util/forge-config.ts @@ -1,33 +1,35 @@ +import { ForgeConfig } from '@electron-forge/shared-types'; import fs from 'fs-extra'; import path from 'path'; import _template from 'lodash.template'; + import readPackageJSON from './read-package-json'; import PluginInterface from './plugin-interface'; -const underscoreCase = str => str.replace(/(.)([A-Z][a-z]+)/g, '$1_$2').replace(/([a-z0-9])([A-Z])/g, '$1_$2').toUpperCase(); +const underscoreCase = (str: string) => str.replace(/(.)([A-Z][a-z]+)/g, '$1_$2').replace(/([a-z0-9])([A-Z])/g, '$1_$2').toUpperCase(); -const proxify = (object, envPrefix) => { - const newObject = {}; +const proxify = (object: T, envPrefix: string): T => { + const newObject: T = {} as any; Object.keys(object).forEach((key) => { - if (typeof object[key] === 'object' && !Array.isArray(object[key]) && key !== 'pluginInterface') { - newObject[key] = proxify(object[key], `${envPrefix}_${underscoreCase(key)}`); + if (typeof (object as any)[key] === 'object' && !Array.isArray((object as any)[key]) && key !== 'pluginInterface') { + (newObject as any)[key] = proxify((object as any)[key], `${envPrefix}_${underscoreCase(key)}`); } else { - newObject[key] = object[key]; + (newObject as any)[key] = (object as any)[key]; } }); - return new Proxy(newObject, { + return new Proxy(newObject, { get(target, name) { // eslint-disable-next-line no-prototype-builtins if (!target.hasOwnProperty(name) && typeof name === 'string') { const envValue = process.env[`${envPrefix}_${underscoreCase(name)}`]; if (envValue) return envValue; } - return target[name]; + return (target as any)[name]; }, getOwnPropertyDescriptor(target, name) { - const envValue = process.env[`${envPrefix}_${underscoreCase(name)}`]; + const envValue = process.env[`${envPrefix}_${underscoreCase(name as string)}`]; // eslint-disable-next-line no-prototype-builtins if (target.hasOwnProperty(name)) { return Object.getOwnPropertyDescriptor(target, name); @@ -41,7 +43,7 @@ const proxify = (object, envPrefix) => { /** * Sets sensible defaults for the `config.forge` object. */ -export function setInitialForgeConfig(packageJSON) { +export function setInitialForgeConfig(packageJSON: any) { const { name = '' } = packageJSON; /* eslint-disable no-param-reassign */ @@ -49,12 +51,13 @@ export function setInitialForgeConfig(packageJSON) { /* eslint-enable no-param-reassign */ } -export default async (dir) => { +export default async (dir: string) => { const packageJSON = await readPackageJSON(dir); - let forgeConfig = packageJSON.config.forge; + let forgeConfig: ForgeConfig | string = packageJSON.config.forge; + if (typeof forgeConfig === 'string' && (await fs.pathExists(path.resolve(dir, forgeConfig)) || await fs.pathExists(path.resolve(dir, `${forgeConfig}.js`)))) { try { - forgeConfig = require(path.resolve(dir, forgeConfig)); + forgeConfig = require(path.resolve(dir, forgeConfig)) as ForgeConfig; } catch (err) { console.error(`Failed to load: ${path.resolve(dir, forgeConfig)}`); throw err; @@ -71,7 +74,7 @@ export default async (dir) => { }, forgeConfig); const templateObj = Object.assign({}, packageJSON, { year: (new Date()).getFullYear() }); - const template = (obj) => { + const template = (obj: any) => { Object.keys(obj).forEach((objKey) => { if (typeof obj[objKey] === 'object' && obj !== null) { template(obj[objKey]); @@ -88,5 +91,5 @@ export default async (dir) => { forgeConfig.pluginInterface = new PluginInterface(dir, forgeConfig); - return proxify(forgeConfig, 'ELECTRON_FORGE'); + return proxify(forgeConfig, 'ELECTRON_FORGE'); }; diff --git a/packages/api/core/src/util/hook.js b/packages/api/core/src/util/hook.js deleted file mode 100644 index 255b5f56bc..0000000000 --- a/packages/api/core/src/util/hook.js +++ /dev/null @@ -1,13 +0,0 @@ -import debug from 'debug'; - -const d = debug('electron-forge:hook'); - -export default async (forgeConfig, hookName, ...hookArgs) => { - const hooks = forgeConfig.hooks || {}; - d(`hook triggered: ${hookName}`); - if (typeof hooks[hookName] === 'function') { - d('calling hook:', hookName, 'with args:', hookArgs); - await hooks[hookName](forgeConfig, ...hookArgs); - } - await forgeConfig.pluginInterface.triggerHook(hookName, hookArgs); -}; diff --git a/packages/api/core/src/util/hook.ts b/packages/api/core/src/util/hook.ts new file mode 100644 index 0000000000..19ef5c0a98 --- /dev/null +++ b/packages/api/core/src/util/hook.ts @@ -0,0 +1,16 @@ +import { ForgeConfig } from '@electron-forge/shared-types'; +import debug from 'debug'; + +const d = debug('electron-forge:hook'); + +export default async (forgeConfig: ForgeConfig, hookName: string, ...hookArgs: any[]) => { + const hooks = forgeConfig.hooks; + if (hooks) { + d(`hook triggered: ${hookName}`); + if (typeof hooks[hookName] === 'function') { + d('calling hook:', hookName, 'with args:', hookArgs); + await hooks[hookName](forgeConfig, ...hookArgs); + } + } + await forgeConfig.pluginInterface.triggerHook(hookName, hookArgs); +}; diff --git a/packages/api/core/src/util/install-dependencies.js b/packages/api/core/src/util/install-dependencies.ts similarity index 90% rename from packages/api/core/src/util/install-dependencies.js rename to packages/api/core/src/util/install-dependencies.ts index 39ddaacce5..478a98a08d 100644 --- a/packages/api/core/src/util/install-dependencies.js +++ b/packages/api/core/src/util/install-dependencies.ts @@ -3,7 +3,12 @@ import { yarnOrNpmSpawn, hasYarn } from './yarn-or-npm'; const d = debug('electron-forge:dependency-installer'); -export default async (dir, deps, areDev = false, exact = false) => { +export default async ( + dir: string, + deps: string[], + areDev = false, + exact = false +) => { d('installing', JSON.stringify(deps), 'in:', dir, `dev=${areDev},exact=${exact},withYarn=${hasYarn()}`); if (deps.length === 0) { d('nothing to install, stopping immediately'); diff --git a/packages/api/core/src/util/is-installed.js b/packages/api/core/src/util/is-installed.ts similarity index 75% rename from packages/api/core/src/util/is-installed.js rename to packages/api/core/src/util/is-installed.ts index ad2c8f67c4..c84a152491 100644 --- a/packages/api/core/src/util/is-installed.js +++ b/packages/api/core/src/util/is-installed.ts @@ -1,4 +1,4 @@ -export default function isInstalled(pkg) { +export default function isInstalled(pkg: string) { try { require(pkg); return true; diff --git a/packages/api/core/src/util/linux-config.js b/packages/api/core/src/util/linux-config.js deleted file mode 100644 index eed0c812e1..0000000000 --- a/packages/api/core/src/util/linux-config.js +++ /dev/null @@ -1,19 +0,0 @@ -import merge from 'lodash.merge'; -import path from 'path'; - -import configFn from './config-fn'; - -export function populateConfig({ forgeConfig, configKey, targetArch }) { - const config = configFn(forgeConfig[configKey] || {}, targetArch); - config.options = config.options || {}; - - return config; -} - -export function linuxConfig({ config, pkgArch, dir, outPath }) { - return merge({}, config, { - arch: pkgArch, - dest: path.dirname(outPath), - src: dir, - }); -} diff --git a/packages/api/core/src/util/linux-installer.js b/packages/api/core/src/util/linux-installer.ts similarity index 50% rename from packages/api/core/src/util/linux-installer.js rename to packages/api/core/src/util/linux-installer.ts index c3c07c8546..48a5de5881 100644 --- a/packages/api/core/src/util/linux-installer.js +++ b/packages/api/core/src/util/linux-installer.ts @@ -2,15 +2,15 @@ import { spawnSync } from 'child_process'; import pify from 'pify'; import sudoPrompt from 'sudo-prompt'; -const which = async (type, prog, promise) => { +const which = async (type: string, prog: string, promise: () => Promise) => { if (spawnSync('which', [prog]).status === 0) { - await promise; + await promise(); } else { throw new Error(`${prog} is required to install ${type} packages`); } }; -export const sudo = (type, prog, args) => - which(type, prog, pify(sudoPrompt.exec)(`${prog} ${args}`, { name: 'Electron Forge' })); +export const sudo = (type: string, prog: string, args: string) => + which(type, prog, () => pify(sudoPrompt.exec)(`${prog} ${args}`, { name: 'Electron Forge' })); export default which; diff --git a/packages/api/core/src/util/messages.js b/packages/api/core/src/util/messages.js deleted file mode 100644 index 90309cdad2..0000000000 --- a/packages/api/core/src/util/messages.js +++ /dev/null @@ -1,13 +0,0 @@ -function info(interactive, message) { - if (interactive) { - console.info(message); - } -} - -function warn(interactive, message) { - if (interactive) { - console.warn(message); - } -} - -export { info, warn }; diff --git a/packages/api/core/src/util/messages.ts b/packages/api/core/src/util/messages.ts new file mode 100644 index 0000000000..b152f79edf --- /dev/null +++ b/packages/api/core/src/util/messages.ts @@ -0,0 +1,11 @@ +export function info(interactive: boolean, message: string) { + if (interactive) { + console.info(message); + } +} + +export function warn(interactive: boolean, message: string) { + if (interactive) { + console.warn(message); + } +} diff --git a/packages/api/core/src/util/out-dir.js b/packages/api/core/src/util/out-dir.ts similarity index 68% rename from packages/api/core/src/util/out-dir.js rename to packages/api/core/src/util/out-dir.ts index 372395d8a8..2dcd6186a7 100644 --- a/packages/api/core/src/util/out-dir.js +++ b/packages/api/core/src/util/out-dir.ts @@ -1,8 +1,9 @@ -const path = require('path'); +import { ForgeConfig } from '@electron-forge/shared-types'; +import path from 'path'; const BASE_OUT_DIR = 'out'; -export default (baseDir, forgeConfig) => { +export default (baseDir: string, forgeConfig: ForgeConfig) => { if (forgeConfig.buildIdentifier) { let identifier = forgeConfig.buildIdentifier; if (typeof identifier === 'function') { diff --git a/packages/api/core/src/util/parse-archs.js b/packages/api/core/src/util/parse-archs.js deleted file mode 100644 index 6f6c2073a5..0000000000 --- a/packages/api/core/src/util/parse-archs.js +++ /dev/null @@ -1,9 +0,0 @@ -import { allOfficialArchsForPlatformAndVersion } from 'electron-packager/targets'; - -export default function parseArchs(platform, declaredArch, electronVersion) { - if (declaredArch === 'all') { - return allOfficialArchsForPlatformAndVersion(platform, electronVersion) || ['x64']; - } - - return declaredArch.split(','); -} diff --git a/packages/api/core/src/util/parse-archs.ts b/packages/api/core/src/util/parse-archs.ts new file mode 100644 index 0000000000..d59e6956fa --- /dev/null +++ b/packages/api/core/src/util/parse-archs.ts @@ -0,0 +1,15 @@ +import { ForgePlatform, ForgeArch } from '@electron-forge/shared-types'; + +const { allOfficialArchsForPlatformAndVersion } = require('electron-packager/targets'); + +export default function parseArchs( + platform: ForgePlatform | string, + declaredArch: ForgeArch | 'all' | string, + electronVersion: string +): ForgeArch[] { + if (declaredArch === 'all') { + return allOfficialArchsForPlatformAndVersion(platform, electronVersion) || ['x64']; + } + + return declaredArch.split(',') as ForgeArch[]; +} diff --git a/packages/api/core/src/util/plugin-interface.js b/packages/api/core/src/util/plugin-interface.ts similarity index 70% rename from packages/api/core/src/util/plugin-interface.js rename to packages/api/core/src/util/plugin-interface.ts index 9525003204..f3fe068c3c 100644 --- a/packages/api/core/src/util/plugin-interface.js +++ b/packages/api/core/src/util/plugin-interface.ts @@ -1,12 +1,18 @@ import { asyncOra } from '@electron-forge/async-ora'; +import { IForgePluginInterface, ForgeConfig, IForgePlugin } from '@electron-forge/shared-types'; +import { ChildProcess } from 'child_process'; import debug from 'debug'; +import { StartOptions } from '../api'; const d = debug('electron-forge:plugins'); -export default class PluginInterface { - constructor(dir, forgeConfig) { +export default class PluginInterface implements IForgePluginInterface { + private plugins: IForgePlugin[]; + private config: ForgeConfig; + + constructor(dir: string, forgeConfig: ForgeConfig) { this.plugins = forgeConfig.plugins.map((plugin) => { - if (plugin.__isElectronForgePlugin) { + if ((plugin as IForgePlugin).__isElectronForgePlugin) { return plugin; } else if (Array.isArray(plugin)) { if (typeof plugin[0] !== 'string') { @@ -20,6 +26,8 @@ export default class PluginInterface { } throw `Expected plugin to either be a plugin instance or [string, object] but found ${plugin}`; // eslint-disable-line }); + // Fix linting + this.config = null as any; Object.defineProperty(this, 'config', { value: forgeConfig, enumerable: false, @@ -28,23 +36,24 @@ export default class PluginInterface { }); for (const plugin of this.plugins) { - plugin.init(dir, forgeConfig, asyncOra); + plugin.init(dir, forgeConfig); } this.triggerHook = this.triggerHook.bind(this); this.overrideStartLogic = this.overrideStartLogic.bind(this); } - async triggerHook(hookName, hookArgs) { + async triggerHook(hookName: string, hookArgs: any[]) { for (const plugin of this.plugins) { if (typeof plugin.getHook === 'function') { const hook = plugin.getHook(hookName); - if (hook) await hook(...hookArgs); + if (hook) await hook(this.config, ...hookArgs); } } } - async overrideStartLogic(opts) { + // FIXME: any + async overrideStartLogic(opts: StartOptions) { let newStartFn; const claimed = []; for (const plugin of this.plugins) { @@ -54,7 +63,7 @@ export default class PluginInterface { } } if (claimed.length > 1) throw `Multiple plugins tried to take control of the start command, please remove one of them\n --> ${claimed.join(', ')}`; - if (claimed.length === 1) { + if (claimed.length === 1 && newStartFn) { d(`plugin: "${claimed[0]}" has taken control of the start command`); return await newStartFn(opts); } diff --git a/packages/api/core/src/util/publish-state.js b/packages/api/core/src/util/publish-state.ts similarity index 76% rename from packages/api/core/src/util/publish-state.js rename to packages/api/core/src/util/publish-state.ts index ddf198f0c7..ef8a53c484 100644 --- a/packages/api/core/src/util/publish-state.js +++ b/packages/api/core/src/util/publish-state.ts @@ -1,3 +1,4 @@ +import { ForgeMakeResult } from '@electron-forge/shared-types'; import crypto from 'crypto'; import fs from 'fs-extra'; import path from 'path'; @@ -5,15 +6,16 @@ import path from 'path'; const EXTENSION = '.forge.publish'; export default class PublishState { - static async loadFromDirectory(directory, rootDir) { - if (!await fs.exists(directory)) { + static async loadFromDirectory(directory: string, rootDir: string) { + if (!await fs.pathExists(directory)) { throw new Error(`Attempted to load publish state from a missing directory: ${directory}`); } - const publishes = []; + const publishes: PublishState[][] = []; for (const dirName of await fs.readdir(directory)) { const subDir = path.resolve(directory, dirName); - const states = []; + const states: PublishState[] = []; + if ((await fs.stat(subDir)).isDirectory()) { const filePaths = (await fs.readdir(subDir)) .filter(fileName => fileName.endsWith(EXTENSION)) @@ -31,17 +33,22 @@ export default class PublishState { return publishes; } - static async saveToDirectory(directory, artifacts, rootDir) { + static async saveToDirectory(directory: string, artifacts: ForgeMakeResult[], rootDir: string) { const id = crypto.createHash('SHA256').update(JSON.stringify(artifacts)).digest('hex'); for (const artifact of artifacts) { artifact.artifacts = artifact.artifacts.map(artifactPath => path.relative(rootDir, artifactPath)); - const state = new PublishState(path.resolve(directory, id, 'null'), '', false); + const state = new PublishState(path.resolve(directory, id, 'null'), false); state.setState(artifact); await state.saveToDisk(); } } - constructor(filePath, hasHash = true) { + private dir: string; + private path: string; + private hasHash: boolean; + private state: ForgeMakeResult = {} as any; + + constructor(filePath: string, hasHash = true) { this.dir = path.dirname(filePath); this.path = filePath; this.hasHash = hasHash; @@ -52,7 +59,7 @@ export default class PublishState { return crypto.createHash('SHA256').update(content).digest('hex'); } - setState(state) { + setState(state: ForgeMakeResult) { this.state = state; } diff --git a/packages/api/core/src/util/read-package-json.js b/packages/api/core/src/util/read-package-json.ts similarity index 74% rename from packages/api/core/src/util/read-package-json.js rename to packages/api/core/src/util/read-package-json.ts index cee775dc1e..31e58aa1cc 100644 --- a/packages/api/core/src/util/read-package-json.js +++ b/packages/api/core/src/util/read-package-json.ts @@ -1,5 +1,5 @@ import fs from 'fs-extra'; import path from 'path'; -export default async dir => +export default async (dir: string) => await fs.readJson(path.resolve(dir, 'package.json')); diff --git a/packages/api/core/src/util/rebuild.js b/packages/api/core/src/util/rebuild.ts similarity index 68% rename from packages/api/core/src/util/rebuild.js rename to packages/api/core/src/util/rebuild.ts index c222a99aee..d143075777 100644 --- a/packages/api/core/src/util/rebuild.js +++ b/packages/api/core/src/util/rebuild.ts @@ -1,7 +1,16 @@ import { asyncOra } from '@electron-forge/async-ora'; +import { ForgePlatform, ForgeArch } from '@electron-forge/shared-types'; + import rebuild from 'electron-rebuild'; +import { RebuildOptions } from 'electron-rebuild/lib/src/rebuild'; -export default async (buildPath, electronVersion, platform, arch, config = {}) => { +export default async ( + buildPath: string, + electronVersion: string, + platform: ForgePlatform, + arch: ForgeArch, + config: Partial = {} +) => { await asyncOra('Preparing native dependencies', async (rebuildSpinner) => { const rebuilder = rebuild(Object.assign({}, config, { buildPath, diff --git a/packages/api/core/src/util/require-search.js b/packages/api/core/src/util/require-search.ts similarity index 64% rename from packages/api/core/src/util/require-search.js rename to packages/api/core/src/util/require-search.ts index 23c265b351..bc1cf4c631 100644 --- a/packages/api/core/src/util/require-search.js +++ b/packages/api/core/src/util/require-search.ts @@ -3,7 +3,7 @@ import path from 'path'; const d = debug('electron-forge:require-search'); -export function requireSearchRaw(relativeTo, paths) { +export function requireSearchRaw(relativeTo: string, paths: string[]): T | null { const testPaths = paths .concat(paths.map(mapPath => path.resolve(relativeTo, mapPath))) .concat(paths.map(mapPath => path.resolve(relativeTo, 'node_modules', mapPath))); @@ -17,9 +17,14 @@ export function requireSearchRaw(relativeTo, paths) { } } d('failed to find a module in', testPaths); + return null; } -export default (relativeTo, paths) => { - const result = requireSearchRaw(relativeTo, paths); - return typeof result === 'object' && result && result.default ? result.default : result; +export type PossibleModule = { + default?: T; +} & T; + +export default (relativeTo: string, paths: string[]): T | null => { + const result = requireSearchRaw>(relativeTo, paths); + return typeof result === 'object' && result && result.default ? result.default : result as (T | null); }; diff --git a/packages/api/core/src/util/resolve-dir.js b/packages/api/core/src/util/resolve-dir.ts similarity index 96% rename from packages/api/core/src/util/resolve-dir.js rename to packages/api/core/src/util/resolve-dir.ts index 66a70ba157..7eef1ebc7f 100644 --- a/packages/api/core/src/util/resolve-dir.js +++ b/packages/api/core/src/util/resolve-dir.ts @@ -6,7 +6,7 @@ import getElectronVersion from './electron-version'; const d = debug('electron-forge:project-resolver'); -export default async (dir) => { +export default async (dir: string) => { let mDir = dir; let prevDir; while (prevDir !== mDir) { diff --git a/packages/api/core/src/util/yarn-or-npm.js b/packages/api/core/src/util/yarn-or-npm.ts similarity index 84% rename from packages/api/core/src/util/yarn-or-npm.js rename to packages/api/core/src/util/yarn-or-npm.ts index e233201879..bcf2aa92a2 100644 --- a/packages/api/core/src/util/yarn-or-npm.js +++ b/packages/api/core/src/util/yarn-or-npm.ts @@ -18,6 +18,6 @@ const safeYarnOrNpm = () => { export default safeYarnOrNpm; -export const yarnOrNpmSpawn = (...args) => spawnPromise(safeYarnOrNpm(), ...args); +export const yarnOrNpmSpawn = (args?: string[], opts?: any) => spawnPromise(safeYarnOrNpm(), args, opts); export const hasYarn = () => safeYarnOrNpm() === 'yarn'; diff --git a/packages/api/core/test/fast/forge-config_spec.js b/packages/api/core/test/fast/forge-config_spec.ts similarity index 89% rename from packages/api/core/test/fast/forge-config_spec.js rename to packages/api/core/test/fast/forge-config_spec.ts index 1f5dea0cd2..ef93223101 100644 --- a/packages/api/core/test/fast/forge-config_spec.js +++ b/packages/api/core/test/fast/forge-config_spec.ts @@ -29,7 +29,7 @@ describe('forge-config', () => { }); it('should allow access to built-ins of proxied objects', async () => { - const conf = await findConfig(path.resolve(__dirname, '../fixture/dummy_js_conf')); + const conf: any = await findConfig(path.resolve(__dirname, '../fixture/dummy_js_conf')); expect(conf.packagerConfig.baz.hasOwnProperty).to.be.a('function'); process.env.ELECTRON_FORGE_S3_SECRET_ACCESS_KEY = 'SecretyThing'; // eslint-disable-next-line no-prototype-builtins @@ -38,7 +38,7 @@ describe('forge-config', () => { }); it('should allow overwrite of properties in proxied objects', async () => { - const conf = await findConfig(path.resolve(__dirname, '../fixture/dummy_js_conf')); + const conf: any = await findConfig(path.resolve(__dirname, '../fixture/dummy_js_conf')); expect(conf.packagerConfig.baz.hasOwnProperty).to.be.a('function'); expect(() => { conf.packagerConfig.baz = 'bar'; }).to.not.throw(); process.env.ELECTRON_FORGE_S3_SECRET_ACCESS_KEY = 'SecretyThing'; @@ -62,13 +62,13 @@ describe('forge-config', () => { }); it('should resolve the JS file exports in config.forge points to a JS file and maintain functions', async () => { - const conf = await findConfig(path.resolve(__dirname, '../fixture/dummy_js_conf')); + const conf: any = await findConfig(path.resolve(__dirname, '../fixture/dummy_js_conf')); expect(conf.magicFn).to.be.a('function'); expect(conf.magicFn()).to.be.equal('magic result'); }); it('should magically map properties to environment variables', async () => { - const conf = await findConfig(path.resolve(__dirname, '../fixture/dummy_js_conf')); + const conf: any = await findConfig(path.resolve(__dirname, '../fixture/dummy_js_conf')); expect(conf.s3.secretAccessKey).to.equal(undefined); process.env.ELECTRON_FORGE_S3_SECRET_ACCESS_KEY = 'SecretyThing'; diff --git a/packages/api/core/test/fast/hook_spec.js b/packages/api/core/test/fast/hook_spec.ts similarity index 90% rename from packages/api/core/test/fast/hook_spec.js rename to packages/api/core/test/fast/hook_spec.ts index 9484fb18c7..864a96792d 100644 --- a/packages/api/core/test/fast/hook_spec.js +++ b/packages/api/core/test/fast/hook_spec.ts @@ -1,3 +1,4 @@ +import { ForgeConfig } from '@electron-forge/shared-types'; import { expect } from 'chai'; import { stub } from 'sinon'; @@ -7,7 +8,7 @@ const fakeConfig = { pluginInterface: { triggerHook: async () => false, }, -}; +} as any as ForgeConfig; describe('runHook', () => { it('should not error when running non existent hooks', async () => { diff --git a/packages/api/core/test/fast/install-dependencies_spec.js b/packages/api/core/test/fast/install-dependencies_spec.ts similarity index 90% rename from packages/api/core/test/fast/install-dependencies_spec.js rename to packages/api/core/test/fast/install-dependencies_spec.ts index cc714f43d9..c5ee3427c8 100644 --- a/packages/api/core/test/fast/install-dependencies_spec.js +++ b/packages/api/core/test/fast/install-dependencies_spec.ts @@ -1,14 +1,16 @@ import { expect } from 'chai'; import proxyquire from 'proxyquire'; -import sinon from 'sinon'; +import sinon, { SinonStub } from 'sinon'; + +import installDependencies from '../../src/util/install-dependencies'; describe('Install dependencies', () => { - let install; - let spawnSpy; - let hasYarnSpy; - let spawnPromise; - let spawnPromiseResolve; - let spawnPromiseReject; + let install: typeof installDependencies; + let spawnSpy: SinonStub; + let hasYarnSpy: SinonStub; + let spawnPromise: Promise; + let spawnPromiseResolve: () => void; + let spawnPromiseReject: () => void; beforeEach(() => { spawnSpy = sinon.stub(); diff --git a/packages/api/core/test/fast/out-dir_spec.js b/packages/api/core/test/fast/out-dir_spec.ts similarity index 65% rename from packages/api/core/test/fast/out-dir_spec.js rename to packages/api/core/test/fast/out-dir_spec.ts index eaf61256ee..4acde74d21 100644 --- a/packages/api/core/test/fast/out-dir_spec.js +++ b/packages/api/core/test/fast/out-dir_spec.ts @@ -1,3 +1,4 @@ +import { ForgeConfig } from '@electron-forge/shared-types'; import { expect } from 'chai'; import path from 'path'; @@ -8,19 +9,19 @@ describe('out-dir', () => { describe('getCurrentOutDir', () => { it('resolves to the default out directory when nothing extra is declared', () => { - expect(getCurrentOutDir(DIR, {})).to.equal(`${DIR}${path.sep}out`); + expect(getCurrentOutDir(DIR, {} as any as ForgeConfig)).to.equal(`${DIR}${path.sep}out`); }); it('resolves to the provided identifier', () => { expect(getCurrentOutDir(DIR, { buildIdentifier: 'bar', - })).to.equal(`${DIR}${path.sep}out${path.sep}bar`); + } as any as ForgeConfig)).to.equal(`${DIR}${path.sep}out${path.sep}bar`); }); it('resolves to the return value of provided identifier getter', () => { expect(getCurrentOutDir(DIR, { buildIdentifier: () => 'thing', - })).to.equal(`${DIR}${path.sep}out${path.sep}thing`); + } as any as ForgeConfig)).to.equal(`${DIR}${path.sep}out${path.sep}thing`); }); }); }); diff --git a/packages/api/core/test/fast/parse-archs_spec.js b/packages/api/core/test/fast/parse-archs_spec.ts similarity index 100% rename from packages/api/core/test/fast/parse-archs_spec.js rename to packages/api/core/test/fast/parse-archs_spec.ts diff --git a/packages/api/core/test/fast/publish_spec.js b/packages/api/core/test/fast/publish_spec.ts similarity index 81% rename from packages/api/core/test/fast/publish_spec.js rename to packages/api/core/test/fast/publish_spec.ts index fb4154a283..1edd27c3ba 100644 --- a/packages/api/core/test/fast/publish_spec.js +++ b/packages/api/core/test/fast/publish_spec.ts @@ -1,21 +1,20 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; +import { expect } from 'chai'; import fs from 'fs-extra'; import os from 'os'; import path from 'path'; import proxyquire from 'proxyquire'; -import sinon from 'sinon'; +import sinon, { SinonStub, SinonSpy } from 'sinon'; -chai.use(chaiAsPromised); +import { PublishOptions } from '../../src/api'; describe('publish', () => { - let publish; - let makeStub; - let resolveStub; - let publisherSpy; - let voidStub; - let nowhereStub; - let publishers; + let publish: (opts: PublishOptions) => Promise; + let makeStub: SinonStub; + let resolveStub: SinonStub; + let publisherSpy: SinonStub; + let voidStub: SinonStub; + let nowhereStub: SinonStub; + let publishers: string[]; beforeEach(() => { resolveStub = sinon.stub(); @@ -24,15 +23,16 @@ describe('publish', () => { voidStub = sinon.stub(); nowhereStub = sinon.stub(); publishers = ['@electron-forge/publisher-test']; - const fakePublisher = stub => class { + const fakePublisher = (stub: SinonStub) => class { + private publish: SinonStub; constructor() { this.publish = stub; } }; publish = proxyquire.noCallThru().load('../../src/api/publish', { - './make': async (...args) => makeStub(...args), - '../util/resolve-dir': async dir => resolveStub(dir), + './make': async (...args: any[]) => makeStub(...args), + '../util/resolve-dir': async (dir: string) => resolveStub(dir), '../util/read-package-json': () => Promise.resolve(require('../fixture/dummy_app/package.json')), '../util/forge-config': async () => { const config = await (require('../../src/util/forge-config').default(path.resolve(__dirname, '../fixture/dummy_app'))); @@ -63,8 +63,6 @@ describe('publish', () => { await publish({ dir: __dirname, interactive: false, - authToken: 'my_token', - tag: 'my_special_tag', }); expect(publisherSpy.callCount).to.equal(1); // pluginInterface will be a new instance so we ignore it @@ -77,11 +75,7 @@ describe('publish', () => { expect(publisherSpy.firstCall.args).to.deep.equal([{ dir: resolveStub(), makeResults: [{ artifacts: ['artifact1', 'artifact2'] }], - packageJSON: require('../fixture/dummy_app/package.json'), forgeConfig: testConfig, - tag: 'my_special_tag', - platform: process.platform, - arch: process.arch, }]); }); @@ -90,13 +84,12 @@ describe('publish', () => { await publish({ dir: __dirname, interactive: false, - authToken: 'my_token', - tag: 'my_special_tag', // Fake instance of a publisher publishTargets: [{ __isElectronForgePublisher: true, publish: publisherSpy, - }], + platforms: null, + } as any], }); expect(publisherSpy.callCount).to.equal(1); // pluginInterface will be a new instance so we ignore it @@ -109,11 +102,7 @@ describe('publish', () => { expect(publisherSpy.firstCall.args).to.deep.equal([{ dir: resolveStub(), makeResults: [{ artifacts: ['artifact1', 'artifact2'] }], - packageJSON: require('../fixture/dummy_app/package.json'), forgeConfig: testConfig, - tag: 'my_special_tag', - platform: process.platform, - arch: process.arch, }]); }); @@ -149,9 +138,9 @@ describe('publish', () => { }); describe('dry run', () => { - let dir; + let dir: string; - const fakeMake = (platform) => { + const fakeMake = (platform: string) => { const ret = [ { artifacts: [ path.resolve(dir, `out/make/artifact1-${platform}`), @@ -187,17 +176,15 @@ describe('publish', () => { await publish({ dir, interactive: false, - target: [], dryRun: true, }); - expect(await fs.exists(path.resolve(dryPath, 'hash.json'))).to.equal(false, 'previous hashes should be erased'); + expect(await fs.pathExists(path.resolve(dryPath, 'hash.json'))).to.equal(false, 'previous hashes should be erased'); const backupDir = path.resolve(dir, 'out', 'backup'); await fs.move(dryPath, backupDir); makeStub.returns(fakeMake('win32')); await publish({ dir, interactive: false, - target: [], dryRun: true, }); for (const backedUp of await fs.readdir(backupDir)) { @@ -208,7 +195,7 @@ describe('publish', () => { it('should create dry run hash JSON files', async () => { expect(makeStub.callCount).to.equal(2); const dryRunFolder = path.resolve(dir, 'out', 'publish-dry-run'); - expect(await fs.exists(dryRunFolder)).to.equal(true); + expect(await fs.pathExists(dryRunFolder)).to.equal(true); const hashFolders = await fs.readdir(dryRunFolder); expect(hashFolders).to.have.length(2, 'Should contain two hashes (two publishes)'); @@ -241,7 +228,7 @@ describe('publish', () => { await publish({ dir, interactive: false, - target: [__filename], + publishTargets: ['@electron-forge/publisher-test'], dryRunResume: true, }); }); @@ -249,7 +236,7 @@ describe('publish', () => { it('should successfully restore values and pass them to publisher', () => { expect(makeStub.callCount).to.equal(0); expect(publisherSpy.callCount).to.equal(2, 'should call once for each platform (make run)'); - const darwinIndex = publisherSpy.firstCall.args[0].platform === 'darwin' ? 0 : 1; + const darwinIndex = publisherSpy.firstCall.args[0].makeResults[0].artifacts.some((a: string) => a.indexOf('darwin') !== -1) ? 0 : 1; const win32Index = darwinIndex === 0 ? 1 : 0; const darwinArgs = publisherSpy.getCall(darwinIndex).args[0]; const darwinArtifacts = []; @@ -257,26 +244,16 @@ describe('publish', () => { darwinArtifacts.push(...result.artifacts); } expect(darwinArtifacts.sort()).to.deep.equal( - fakeMake('darwin').reduce((accum, val) => accum.concat(val.artifacts), []).sort() + fakeMake('darwin').reduce((accum, val) => accum.concat(val.artifacts), [] as string[]).sort() ); - expect(darwinArgs.packageJSON).to.deep.equal({ state: 1 }); - expect(darwinArgs.authToken).to.equal(undefined); - expect(darwinArgs.tag).to.equal('1.0.0'); - expect(darwinArgs.platform).to.equal('darwin'); - expect(darwinArgs.arch).to.equal('x64'); const win32Args = publisherSpy.getCall(win32Index).args[0]; const win32Artifacts = []; for (const result of win32Args.makeResults) { win32Artifacts.push(...result.artifacts); } expect(win32Artifacts.sort()).to.deep.equal( - fakeMake('win32').reduce((accum, val) => accum.concat(val.artifacts), []).sort() + fakeMake('win32').reduce((accum, val) => accum.concat(val.artifacts), [] as string[]).sort() ); - expect(win32Args.packageJSON).to.deep.equal({ state: 0 }); - expect(win32Args.authToken).to.equal(undefined); - expect(win32Args.tag).to.equal('1.0.0'); - expect(win32Args.platform).to.equal('win32'); - expect(win32Args.arch).to.equal('x64'); }); }); diff --git a/packages/api/core/test/fast/read-package-json_spec.js b/packages/api/core/test/fast/read-package-json_spec.ts similarity index 85% rename from packages/api/core/test/fast/read-package-json_spec.js rename to packages/api/core/test/fast/read-package-json_spec.ts index 3f1d4ca5d3..0f995cb9f1 100644 --- a/packages/api/core/test/fast/read-package-json_spec.js +++ b/packages/api/core/test/fast/read-package-json_spec.ts @@ -5,6 +5,6 @@ import readPackageJSON from '../../src/util/read-package-json'; describe('read-package-json', () => { it('should find a package.json file from the given directory', async () => { - expect(await readPackageJSON(path.resolve(__dirname, '../..'))).to.deep.equal(require('../..//package.json')); + expect(await readPackageJSON(path.resolve(__dirname, '../..'))).to.deep.equal(require('../../package.json')); }); }); diff --git a/packages/api/core/test/fast/require-search_spec.js b/packages/api/core/test/fast/require-search_spec.ts similarity index 81% rename from packages/api/core/test/fast/require-search_spec.js rename to packages/api/core/test/fast/require-search_spec.ts index 497361d240..49ee2b5f3d 100644 --- a/packages/api/core/test/fast/require-search_spec.js +++ b/packages/api/core/test/fast/require-search_spec.ts @@ -4,9 +4,9 @@ import requireSearch from '../../src/util/require-search'; import findConfig from '../../src/util/forge-config'; describe('require-search', () => { - it('should resolve undefined if no file exists', () => { + it('should resolve null if no file exists', () => { const resolved = requireSearch(__dirname, ['../../src/util/wizard-secrets']); - expect(resolved).to.equal(undefined); + expect(resolved).to.equal(null); }); it('should resolve a file if it exists', () => { diff --git a/packages/api/core/test/fast/resolve-dir_spec.js b/packages/api/core/test/fast/resolve-dir_spec.ts similarity index 100% rename from packages/api/core/test/fast/resolve-dir_spec.js rename to packages/api/core/test/fast/resolve-dir_spec.ts diff --git a/packages/api/core/test/fast/start_spec.js b/packages/api/core/test/fast/start_spec.ts similarity index 90% rename from packages/api/core/test/fast/start_spec.js rename to packages/api/core/test/fast/start_spec.ts index 8e4c2f9b44..1818d4be36 100644 --- a/packages/api/core/test/fast/start_spec.js +++ b/packages/api/core/test/fast/start_spec.ts @@ -1,17 +1,17 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; +import { expect } from 'chai'; +import { ChildProcess } from 'child_process'; import path from 'path'; import proxyquire from 'proxyquire'; -import sinon from 'sinon'; +import sinon, { SinonStub } from 'sinon'; -chai.use(chaiAsPromised); +import { StartOptions } from '../../src/api'; describe('start', () => { - let start; - let packageJSON; - let resolveStub; - let spawnStub; - let shouldOverride; + let start: (opts: StartOptions) => Promise; + let packageJSON: any; + let resolveStub: SinonStub; + let spawnStub: SinonStub; + let shouldOverride: boolean; beforeEach(() => { resolveStub = sinon.stub(); @@ -26,7 +26,7 @@ describe('start', () => { triggerHook: async () => false, }, }), - '../util/resolve-dir': async dir => resolveStub(dir), + '../util/resolve-dir': async (dir: string) => resolveStub(dir), '../util/read-package-json': () => Promise.resolve(packageJSON), '../util/rebuild': () => Promise.resolve(), child_process: { @@ -91,7 +91,7 @@ describe('start', () => { expect(spawnStub.callCount).to.equal(1); expect(spawnStub.firstCall.args[0]).to.equal(process.execPath); expect(spawnStub.firstCall.args[1][0]).to.contain(`electron${path.sep}cli`); - expect(spawnStub.firstCall.args[2].env).to.have.property('ELECTRON_ENABLE_LOGGING', true); + expect(spawnStub.firstCall.args[2].env).to.have.property('ELECTRON_ENABLE_LOGGING', 'true'); }); it('should enable RUN_AS_NODE if runAsNode=true', async () => { @@ -102,7 +102,7 @@ describe('start', () => { runAsNode: true, }); expect(spawnStub.callCount).to.equal(1); - expect(spawnStub.firstCall.args[2].env).to.have.property('ELECTRON_RUN_AS_NODE', true); + expect(spawnStub.firstCall.args[2].env).to.have.property('ELECTRON_RUN_AS_NODE', 'true'); }); it('should disable RUN_AS_NODE if runAsNode=false', async () => { @@ -119,7 +119,7 @@ describe('start', () => { it('should throw if no dir could be found', async () => { resolveStub.returns(null); - await expect(start()).to.eventually.be.rejectedWith( + await expect(start({})).to.eventually.be.rejectedWith( 'Failed to locate startable Electron application' ); }); diff --git a/packages/api/core/test/fast/yarn-or-npm_spec.js b/packages/api/core/test/fast/yarn-or-npm_spec.ts similarity index 96% rename from packages/api/core/test/fast/yarn-or-npm_spec.js rename to packages/api/core/test/fast/yarn-or-npm_spec.ts index f322e206e6..996a29ec92 100644 --- a/packages/api/core/test/fast/yarn-or-npm_spec.js +++ b/packages/api/core/test/fast/yarn-or-npm_spec.ts @@ -4,7 +4,7 @@ import systemYarnOrNpm from 'yarn-or-npm'; import yarnOrNpm from '../../src/util/yarn-or-npm'; describe('yarn-or-npm', () => { - let nodeInstaller; + let nodeInstaller: string | undefined; beforeEach(() => { nodeInstaller = process.env.NODE_INSTALLER; diff --git a/packages/api/core/test/slow/api_spec_slow.js b/packages/api/core/test/slow/api_spec_slow.ts similarity index 95% rename from packages/api/core/test/slow/api_spec_slow.js rename to packages/api/core/test/slow/api_spec_slow.ts index 434d461790..fe5a01dbc4 100644 --- a/packages/api/core/test/slow/api_spec_slow.js +++ b/packages/api/core/test/slow/api_spec_slow.ts @@ -1,28 +1,27 @@ import { execSync } from 'child_process'; -import asar from 'asar'; import fs from 'fs-extra'; import os from 'os'; import path from 'path'; -import chai, { expect } from 'chai'; +import { expect } from 'chai'; import proxyquire from 'proxyquire'; -import chaiAsPromised from 'chai-as-promised'; import { createDefaultCertificate } from '@electron-forge/maker-appx'; import installDeps from '../../src/util/install-dependencies'; import readPackageJSON from '../../src/util/read-package-json'; import yarnOrNpm from '../../src/util/yarn-or-npm'; +import { InitOptions } from '../../src/api'; -chai.use(chaiAsPromised); +const asar = require('asar'); const nodeInstallerArg = process.argv.find(arg => arg.startsWith('--installer=')) || `--installer=${yarnOrNpm()}`; const nodeInstaller = nodeInstallerArg.substr(12); const forge = proxyquire.noCallThru().load('../../src/api', { './install': async () => {}, -}); +}).api; describe(`electron-forge API (with installer=${nodeInstaller})`, () => { - let dir; + let dir: string; let dirID = Date.now(); const ensureTestDirIsNonexistent = async () => { @@ -31,7 +30,7 @@ describe(`electron-forge API (with installer=${nodeInstaller})`, () => { await fs.remove(dir); }; - const beforeInitTest = (params, beforeInit) => { + const beforeInitTest = (params?: Partial, beforeInit?: Function) => { before(async () => { await ensureTestDirIsNonexistent(); if (beforeInit) { @@ -41,7 +40,7 @@ describe(`electron-forge API (with installer=${nodeInstaller})`, () => { }); }; - const expectProjectPathExists = async (subPath, pathType) => { + const expectProjectPathExists = async (subPath: string, pathType: string) => { expect(await fs.pathExists(path.resolve(dir, subPath)), `the ${subPath} ${pathType} should exist`).to.equal(true); }; @@ -189,7 +188,7 @@ describe(`electron-forge API (with installer=${nodeInstaller})`, () => { }); describe('after init', () => { - let devCert; + let devCert: string; before(async () => { dir = path.resolve(os.tmpdir(), `electron-forge-test-${dirID}/electron-forge-test`); @@ -275,7 +274,7 @@ describe(`electron-forge API (with installer=${nodeInstaller})`, () => { process.env.DISABLE_SQUIRREL_TEST = 'true'; } - function getMakers(good) { + function getMakers(good: boolean) { const allMakers = [ '@electron-forge/maker-appx', '@electron-forge/maker-deb', @@ -304,7 +303,7 @@ describe(`electron-forge API (with installer=${nodeInstaller})`, () => { const goodMakers = getMakers(true); const badMakers = getMakers(false); - const testMakeTarget = function testMakeTarget(target, shouldPass, ...options) { + const testMakeTarget = function testMakeTarget(target: () => { name: string }, shouldPass: boolean, ...options: any[]) { describe(`make (with target=${path.basename(target().name)})`, async () => { before(async () => { const packageJSON = await readPackageJSON(dir); @@ -314,16 +313,16 @@ describe(`electron-forge API (with installer=${nodeInstaller})`, () => { for (const optionsFetcher of options) { if (shouldPass) { - it(`successfully makes for config: ${JSON.stringify(optionsFetcher(), 2)}`, async () => { + it(`successfully makes for config: ${JSON.stringify(optionsFetcher())}`, async () => { const outputs = await forge.make(optionsFetcher()); for (const outputResult of outputs) { for (const output of outputResult.artifacts) { - expect(await fs.exists(output)).to.equal(true); + expect(await fs.pathExists(output)).to.equal(true); } } }); } else { - it(`fails for config: ${JSON.stringify(optionsFetcher(), 2)}`, async () => { + it(`fails for config: ${JSON.stringify(optionsFetcher())}`, async () => { await expect(forge.make(optionsFetcher())).to.eventually.be.rejected; }); } diff --git a/packages/api/core/test/slow/install-dependencies_spec_slow.js b/packages/api/core/test/slow/install-dependencies_spec_slow.ts similarity index 100% rename from packages/api/core/test/slow/install-dependencies_spec_slow.js rename to packages/api/core/test/slow/install-dependencies_spec_slow.ts diff --git a/packages/api/core/test/slow/install_spec_slow.js b/packages/api/core/test/slow/install_spec_slow.ts similarity index 87% rename from packages/api/core/test/slow/install_spec_slow.js rename to packages/api/core/test/slow/install_spec_slow.ts index 55c1106cb8..f49d33549c 100644 --- a/packages/api/core/test/slow/install_spec_slow.js +++ b/packages/api/core/test/slow/install_spec_slow.ts @@ -1,29 +1,29 @@ -import chai, { expect } from 'chai'; -import fetchMock from 'fetch-mock/es5/server'; -import chaiAsPromised from 'chai-as-promised'; +import { expect } from 'chai'; import proxyquire from 'proxyquire'; -import sinon from 'sinon'; +import sinon, { SinonSpy } from 'sinon'; -chai.use(chaiAsPromised); +import { InstallOptions, InstallAsset } from '../../src/api'; + +const fetchMock = require('fetch-mock/es5/server'); describe('install', () => { - let install; - let nuggetSpy; - let fetch; + let install: (opts: InstallOptions) => Promise; + let nuggetSpy: SinonSpy; + let fetch: any; class MockInstaller { async install() { return undefined; } } - const chooseAsset = arr => arr[0]; + const chooseAsset = (arr: InstallAsset[]) => arr[0]; beforeEach(() => { - fetch = fetchMock.sandbox(); + fetch = (fetchMock as any).sandbox(); nuggetSpy = sinon.stub(); install = proxyquire.noCallThru().load('../../src/api/install', { 'node-fetch': fetch, - nugget: (...args) => { + nugget: (...args: any[]) => { nuggetSpy(...args); args[args.length - 1](); }, @@ -40,7 +40,7 @@ describe('install', () => { }); it('should throw an error when a repo name is not given', async () => { - await expect(install()).to.eventually.be.rejected; + await expect(install({} as any)).to.eventually.be.rejected; }); it('should throw an error when given an invalid repository name', async () => { @@ -139,13 +139,13 @@ describe('install', () => { ], }, ]); - await expect(install({ repo: 'h/i', interactive: false })).to.eventually.be.rejectedWith( + await expect(install({ repo: 'h/i', interactive: false } as any)).to.eventually.be.rejectedWith( 'Expected chooseAsset to be a function in install call' ); }); it('should provide compatable assets to chooseAsset if more than one exists', async () => { - const chooseAssetSpy = sinon.spy(async assets => assets[0]); + const chooseAssetSpy = sinon.spy(async (assets: InstallAsset[]) => assets[0]); fetch.get('*', [ { tag_name: '1.0.0', diff --git a/packages/api/core/test/slow/rebuild_spec_slow.js b/packages/api/core/test/slow/rebuild_spec_slow.ts similarity index 91% rename from packages/api/core/test/slow/rebuild_spec_slow.js rename to packages/api/core/test/slow/rebuild_spec_slow.ts index b679af1538..0ea8963581 100644 --- a/packages/api/core/test/slow/rebuild_spec_slow.js +++ b/packages/api/core/test/slow/rebuild_spec_slow.ts @@ -1,3 +1,5 @@ +import { ForgeArch, ForgePlatform } from '@electron-forge/shared-types'; +import { RebuildOptions } from 'electron-rebuild/lib/src/rebuild'; import fs from 'fs-extra'; import path from 'path'; import os from 'os'; @@ -20,8 +22,8 @@ describe('rebuilder', () => { }); } - async function doRebuild(config) { - await rebuild(testModulePath, '1.4.12', process.platform, process.arch, config); + async function doRebuild(config?: Partial) { + await rebuild(testModulePath, '1.4.12', process.platform as ForgePlatform, process.arch as ForgeArch, config); } describe('no config', () => { diff --git a/packages/api/core/typings/ambient.d.ts b/packages/api/core/typings/ambient.d.ts new file mode 100644 index 0000000000..c28f62f0b0 --- /dev/null +++ b/packages/api/core/typings/ambient.d.ts @@ -0,0 +1,18 @@ +declare module 'yarn-or-npm' { + const yon: () => 'yarn' | 'npm'; + export default yon; +} + +declare module 'sudo-prompt' { + export const exec: () => void; +} + +declare module 'resolve-package' { + const resolve: (packageName: string) => Promise; + export default resolve; +} + +declare module 'username' { + const username: () => Promise; + export default username; +} diff --git a/packages/installer/base/package.json b/packages/installer/base/package.json index 8427f180ed..51a918da50 100644 --- a/packages/installer/base/package.json +++ b/packages/installer/base/package.json @@ -6,8 +6,9 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/Installer.js", + "typings": "dist/Installer.d.ts", "scripts": { - "test": "mocha test/**/*_spec.js test/**/**/*_spec.js --opts ../../../mocha.opts" + "test": "mocha --require ts-node/register test/**/*_spec.ts test/**/**/*_spec.ts --opts ../../../mocha.opts" }, "devDependencies": { "chai": "^4.0.0", @@ -15,5 +16,8 @@ }, "engines": { "node": ">= 6.0" + }, + "dependencies": { + "@electron-forge/async-ora": "^6.0.0-beta.3" } -} +} \ No newline at end of file diff --git a/packages/installer/base/src/Installer.js b/packages/installer/base/src/Installer.ts similarity index 55% rename from packages/installer/base/src/Installer.js rename to packages/installer/base/src/Installer.ts index 8fe4460fe2..3210fcdd09 100644 --- a/packages/installer/base/src/Installer.js +++ b/packages/installer/base/src/Installer.ts @@ -1,6 +1,15 @@ -export default class Installer { - constructor(name) { - this.name = name; +import { OraImpl } from '@electron-forge/async-ora'; + +export interface InstallerOptions { + filePath: string; + installSpinner: OraImpl; +} + +export default abstract class Installer { + abstract name: string; + __isElectronForgeInstaller!: boolean; + + constructor() { Object.defineProperty(this, '__isElectronForgeInstaller', { value: true, enumerable: false, @@ -12,10 +21,7 @@ export default class Installer { * Installers must implement this method and install the given filePath * when called. This method must return a promise */ - async install({ - filePath, // eslint-disable-line - installSpinner // eslint-disable-line - }) { + async install(opts: InstallerOptions) { throw new Error(`Installer ${this.name} did not implement the install method`); } } diff --git a/packages/installer/base/test/Installer_spec.js b/packages/installer/base/test/Installer_spec.ts similarity index 56% rename from packages/installer/base/test/Installer_spec.js rename to packages/installer/base/test/Installer_spec.ts index 5333cf45d2..7dd4c37bfd 100644 --- a/packages/installer/base/test/Installer_spec.js +++ b/packages/installer/base/test/Installer_spec.ts @@ -2,14 +2,19 @@ import { expect } from 'chai'; import Installer from '../src/Installer'; +class InstallerImpl extends Installer { + name = 'test'; +} + describe('Installer', () => { it('should define __isElectronForgeInstaller', () => { - const installer = new Installer('test'); + const installer = new InstallerImpl(); expect(installer).to.have.property('__isElectronForgeInstaller', true); + expect(installer.name).to.equal('test'); }); it('should throw an error when install is called', (done) => { - const installer = new Installer('test'); - installer.install({}).catch(() => done()); + const installer = new InstallerImpl(); + installer.install({} as any).catch(() => done()); }); }); diff --git a/packages/installer/darwin/package.json b/packages/installer/darwin/package.json index 79707f895e..20c822bf43 100644 --- a/packages/installer/darwin/package.json +++ b/packages/installer/darwin/package.json @@ -6,6 +6,7 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/InstallerDarwin.js", + "typings": "dist/InstallerDarwin.d.ts", "scripts": { "test": "exit 0" }, @@ -16,9 +17,10 @@ "node": ">= 6.0" }, "dependencies": { + "@electron-forge/async-ora": "^6.0.0-beta.3", "@electron-forge/installer-base": "6.0.0-beta.3", "fs-extra": "^5.0.0", "pify": "^3.0.0", "sudo-prompt": "^8.0.0" } -} +} \ No newline at end of file diff --git a/packages/installer/darwin/src/InstallerDarwin.js b/packages/installer/darwin/src/InstallerDarwin.ts similarity index 63% rename from packages/installer/darwin/src/InstallerDarwin.js rename to packages/installer/darwin/src/InstallerDarwin.ts index 077b36af90..f88e78f585 100644 --- a/packages/installer/darwin/src/InstallerDarwin.js +++ b/packages/installer/darwin/src/InstallerDarwin.ts @@ -1,4 +1,5 @@ -import InstallerBase from '@electron-forge/installer-base'; +import { OraImpl } from '@electron-forge/async-ora'; +import InstallerBase, { InstallerOptions } from '@electron-forge/installer-base'; import fs from 'fs-extra'; import path from 'path'; @@ -6,11 +7,13 @@ import pify from 'pify'; import sudo from 'sudo-prompt'; import { exec } from 'child_process'; -export default class InstallerDarwin extends InstallerBase { - async moveApp(appPath, targetApplicationPath, spinner, copyInstead = false) { +export { InstallerOptions }; + +export default abstract class InstallerDarwin extends InstallerBase { + async moveApp(appPath: string, targetApplicationPath: string, spinner: OraImpl, copyInstead = false) { let writeAccess = true; try { - await fs.access('/Applications', fs.W_OK); + await fs.access('/Applications', fs.constants.W_OK); } catch (err) { writeAccess = false; } diff --git a/packages/installer/darwin/typings/ambient.d.ts b/packages/installer/darwin/typings/ambient.d.ts new file mode 100644 index 0000000000..7dece2f169 --- /dev/null +++ b/packages/installer/darwin/typings/ambient.d.ts @@ -0,0 +1,6 @@ +declare module 'sudo-prompt' { + type Exec = (command: string, app: { + name: string; + }) => void; + export const exec: Exec; +} \ No newline at end of file diff --git a/packages/installer/deb/package.json b/packages/installer/deb/package.json index 323b77bd70..8adccc2271 100644 --- a/packages/installer/deb/package.json +++ b/packages/installer/deb/package.json @@ -6,6 +6,7 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/InstallerDeb.js", + "typings": "dist/InstallerDeb.d.ts", "scripts": { "test": "exit 0" }, diff --git a/packages/installer/deb/src/InstallerDeb.js b/packages/installer/deb/src/InstallerDeb.ts similarity index 55% rename from packages/installer/deb/src/InstallerDeb.js rename to packages/installer/deb/src/InstallerDeb.ts index 377df0afe9..9f2ba2759a 100644 --- a/packages/installer/deb/src/InstallerDeb.js +++ b/packages/installer/deb/src/InstallerDeb.ts @@ -1,13 +1,11 @@ -import InstallerLinux from '@electron-forge/installer-linux'; +import InstallerLinux, { InstallerOptions } from '@electron-forge/installer-linux'; export default class InstallerDeb extends InstallerLinux { - constructor() { - super('deb'); - } + name = 'deb'; async install({ filePath, - }) { + }: InstallerOptions) { await this.sudo('Debian', 'gdebi', `-n ${filePath}`); } } diff --git a/packages/installer/dmg/package.json b/packages/installer/dmg/package.json index 62dd1938c0..09ce2fc8d0 100644 --- a/packages/installer/dmg/package.json +++ b/packages/installer/dmg/package.json @@ -6,6 +6,7 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/InstallerDMG.js", + "typings": "dist/InstallerDMG.d.ts", "scripts": { "test": "exit 0" }, diff --git a/packages/installer/dmg/src/InstallerDMG.js b/packages/installer/dmg/src/InstallerDMG.ts similarity index 87% rename from packages/installer/dmg/src/InstallerDMG.js rename to packages/installer/dmg/src/InstallerDMG.ts index 9ecab5c526..de3a3b5833 100644 --- a/packages/installer/dmg/src/InstallerDMG.js +++ b/packages/installer/dmg/src/InstallerDMG.ts @@ -1,4 +1,4 @@ -import InstallerDarwin from '@electron-forge/installer-darwin'; +import InstallerDarwin, { InstallerOptions } from '@electron-forge/installer-darwin'; import spawnPromise from 'cross-spawn-promise'; import fs from 'fs-extra'; @@ -7,14 +7,12 @@ import path from 'path'; import { getMountedImages, mountImage, unmountImage } from './util/hdiutil'; export default class InstallerDMG extends InstallerDarwin { - constructor() { - super('dmg'); - } + name = 'dmg'; async install({ filePath, installSpinner, - }) { + }: InstallerOptions) { const mounts = await getMountedImages(); let targetMount = mounts.find(mount => mount.imagePath === filePath); @@ -33,7 +31,7 @@ export default class InstallerDMG extends InstallerDarwin { await this.moveApp(appPath, targetApplicationPath, installSpinner, true); - await spawnPromise('open', ['-R', targetApplicationPath], { detached: true }); + await spawnPromise('open', ['-R', targetApplicationPath], { detached: true } as any); } finally { await unmountImage(targetMount); } diff --git a/packages/installer/dmg/src/util/hdiutil.js b/packages/installer/dmg/src/util/hdiutil.ts similarity index 70% rename from packages/installer/dmg/src/util/hdiutil.js rename to packages/installer/dmg/src/util/hdiutil.ts index baabdc050c..84d4a76257 100644 --- a/packages/installer/dmg/src/util/hdiutil.js +++ b/packages/installer/dmg/src/util/hdiutil.ts @@ -3,7 +3,12 @@ import debug from 'debug'; const d = debug('electron-forge:hdiutil'); -export const getMountedImages = async () => { +export interface Mount { + mountPath: string; + imagePath: string; +} + +export const getMountedImages = async (): Promise => { const output = await spawnPromise('hdiutil', ['info']); const mounts = output.toString().split(/====\n/g); mounts.shift(); @@ -12,8 +17,8 @@ export const getMountedImages = async () => { for (const mount of mounts) { try { - const mountPath = /\/Volumes\/(.+)\n/g.exec(mount)[1]; - const imagePath = /image-path +: +(.+)\n/g.exec(mount)[1]; + const mountPath = /\/Volumes\/(.+)\n/g.exec(mount)![1]; + const imagePath = /image-path +: +(.+)\n/g.exec(mount)![1]; mountObjects.push({ mountPath, imagePath }); } catch (err) { // Ignore @@ -24,10 +29,10 @@ export const getMountedImages = async () => { return mountObjects; }; -export const mountImage = async (filePath) => { +export const mountImage = async (filePath: string): Promise => { d('mounting image:', filePath); const output = await spawnPromise('hdiutil', ['attach', '-noautoopen', '-nobrowse', '-noverify', filePath]); - const mountPath = /\/Volumes\/(.+)\n/g.exec(output.toString())[1]; + const mountPath = /\/Volumes\/(.+)\n/g.exec(output.toString())![1]; d('mounted at:', mountPath); return { @@ -36,7 +41,7 @@ export const mountImage = async (filePath) => { }; }; -export const unmountImage = async (mount) => { +export const unmountImage = async (mount: Mount) => { d('unmounting current mount:', mount); await spawnPromise('hdiutil', ['unmount', '-force', `/Volumes/${mount.mountPath}`]); }; diff --git a/packages/installer/exe/package.json b/packages/installer/exe/package.json index 75ecdea05f..d9912339b9 100644 --- a/packages/installer/exe/package.json +++ b/packages/installer/exe/package.json @@ -6,6 +6,7 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/InstallerExe.js", + "typings": "dist/InstallerExe.d.ts", "scripts": { "test": "exit 0" }, diff --git a/packages/installer/exe/src/InstallerExe.js b/packages/installer/exe/src/InstallerExe.js deleted file mode 100644 index 5046875ac5..0000000000 --- a/packages/installer/exe/src/InstallerExe.js +++ /dev/null @@ -1,15 +0,0 @@ -import InstallerBase from '@electron-forge/installer-base'; - -import opn from 'opn'; - -export default class InstallerExe extends InstallerBase { - constructor() { - super('exe'); - } - - async install({ - filePath, - }) { - return opn(filePath, { wait: false }); - } -} diff --git a/packages/installer/exe/src/InstallerExe.ts b/packages/installer/exe/src/InstallerExe.ts new file mode 100644 index 0000000000..9d8b6231a7 --- /dev/null +++ b/packages/installer/exe/src/InstallerExe.ts @@ -0,0 +1,13 @@ +import InstallerBase, { InstallerOptions } from '@electron-forge/installer-base'; + +import opn from 'opn'; + +export default class InstallerExe extends InstallerBase { + name = 'exe'; + + async install({ + filePath, + }: InstallerOptions) { + await opn(filePath, { wait: false }); + } +} diff --git a/packages/installer/linux/package.json b/packages/installer/linux/package.json index fa25167d1e..cb274e9cc6 100644 --- a/packages/installer/linux/package.json +++ b/packages/installer/linux/package.json @@ -6,6 +6,7 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/InstallerLinux.js", + "typings": "dist/InstallerLinux.d.ts", "scripts": { "test": "exit 0" }, diff --git a/packages/installer/linux/src/InstallerLinux.js b/packages/installer/linux/src/InstallerLinux.js deleted file mode 100644 index 05d6c0bb1d..0000000000 --- a/packages/installer/linux/src/InstallerLinux.js +++ /dev/null @@ -1,22 +0,0 @@ -import InstallerBase from '@electron-forge/installer-base'; - -import { spawnSync } from 'child_process'; -import pify from 'pify'; -import sudoPrompt from 'sudo-prompt'; - -export default class InstallerLinux extends InstallerBase { - which = async (type, prog, promise) => { - if (spawnSync('which', [prog]).status === 0) { - await promise; - } else { - throw new Error(`${prog} is required to install ${type} packages`); - } - } - - sudo = (type, program, args) => - this.which( - type, - program, - pify(sudoPrompt.exec)(`${program} ${args}`, { name: 'Electron Forge' }), - ); -} diff --git a/packages/installer/linux/src/InstallerLinux.ts b/packages/installer/linux/src/InstallerLinux.ts new file mode 100644 index 0000000000..0bb1f0f4c5 --- /dev/null +++ b/packages/installer/linux/src/InstallerLinux.ts @@ -0,0 +1,24 @@ +import InstallerBase, { InstallerOptions } from '@electron-forge/installer-base'; + +import { spawnSync } from 'child_process'; +import pify from 'pify'; +import sudoPrompt from 'sudo-prompt'; + +export { InstallerOptions }; + +export default abstract class InstallerLinux extends InstallerBase { + which = async (type: string, prog: string, promise: () => Promise) => { + if (spawnSync('which', [prog]).status === 0) { + await promise(); + } else { + throw new Error(`${prog} is required to install ${type} packages`); + } + } + + sudo = (type: string, program: string, args: string) => + this.which( + type, + program, + () => pify(sudoPrompt.exec)(`${program} ${args}`, { name: 'Electron Forge' }), + ); +} diff --git a/packages/installer/linux/typings/ambient.d.ts b/packages/installer/linux/typings/ambient.d.ts new file mode 100644 index 0000000000..7dece2f169 --- /dev/null +++ b/packages/installer/linux/typings/ambient.d.ts @@ -0,0 +1,6 @@ +declare module 'sudo-prompt' { + type Exec = (command: string, app: { + name: string; + }) => void; + export const exec: Exec; +} \ No newline at end of file diff --git a/packages/installer/rpm/package.json b/packages/installer/rpm/package.json index ca82f66278..24bf43de08 100644 --- a/packages/installer/rpm/package.json +++ b/packages/installer/rpm/package.json @@ -6,6 +6,7 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/InstallerRpm.js", + "typings": "dist/InstallerRpm.d.ts", "scripts": { "test": "exit 0" }, diff --git a/packages/installer/rpm/src/InstallerRpm.js b/packages/installer/rpm/src/InstallerRpm.ts similarity index 59% rename from packages/installer/rpm/src/InstallerRpm.js rename to packages/installer/rpm/src/InstallerRpm.ts index 3c7177f859..1205a65eb0 100644 --- a/packages/installer/rpm/src/InstallerRpm.js +++ b/packages/installer/rpm/src/InstallerRpm.ts @@ -1,13 +1,11 @@ -import InstallerLinux from '@electron-forge/installer-linux'; +import InstallerLinux, { InstallerOptions } from '@electron-forge/installer-linux'; export default class InstallerRpm extends InstallerLinux { - constructor() { - super('rpm'); - } + name = 'rpm'; async install({ filePath, - }) { + }: InstallerOptions) { await this.sudo('RPM', 'dnf', `--assumeyes --nogpgcheck install ${filePath}`); } } diff --git a/packages/installer/zip/package.json b/packages/installer/zip/package.json index 157e6c869c..1336f6a505 100644 --- a/packages/installer/zip/package.json +++ b/packages/installer/zip/package.json @@ -6,6 +6,7 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/InstallerZip.js", + "typings": "dist/InstallerZip.d.ts", "scripts": { "test": "exit 0" }, diff --git a/packages/installer/zip/src/InstallerZip.js b/packages/installer/zip/src/InstallerZip.ts similarity index 82% rename from packages/installer/zip/src/InstallerZip.js rename to packages/installer/zip/src/InstallerZip.ts index 8588783320..5847fa88f6 100644 --- a/packages/installer/zip/src/InstallerZip.js +++ b/packages/installer/zip/src/InstallerZip.ts @@ -1,21 +1,19 @@ -import InstallerDarwin from '@electron-forge/installer-darwin'; +import InstallerDarwin, { InstallerOptions } from '@electron-forge/installer-darwin'; import spawnPromise from 'cross-spawn-promise'; import fs from 'fs-extra'; import path from 'path'; export default class InstallerZip extends InstallerDarwin { - constructor() { - super('zip'); - } + name = 'zip'; async install({ filePath, installSpinner, - }) { + }: InstallerOptions) { await spawnPromise('unzip', ['-q', '-o', path.basename(filePath)], { cwd: path.dirname(filePath), - }); + } as any); const appPath = (await fs.readdir(path.dirname(filePath))).filter(file => file.endsWith('.app')) .map(file => path.resolve(path.dirname(filePath), file)) @@ -25,6 +23,6 @@ export default class InstallerZip extends InstallerDarwin { await this.moveApp(appPath, targetApplicationPath, installSpinner); - await spawnPromise('open', ['-R', targetApplicationPath], { detached: true }); + await spawnPromise('open', ['-R', targetApplicationPath], { detached: true } as any); } } diff --git a/packages/maker/appx/package.json b/packages/maker/appx/package.json index fa8178ea43..979b132724 100644 --- a/packages/maker/appx/package.json +++ b/packages/maker/appx/package.json @@ -6,8 +6,9 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/MakerAppX.js", + "typings": "dist/MakerAppX.d.ts", "scripts": { - "test": "mocha test/**/*_spec.js test/**/**/*_spec.js --opts ../../../mocha.opts" + "test": "mocha --require ts-node/register test/**/*_spec.ts test/**/**/*_spec.ts --opts ../../../mocha.opts" }, "devDependencies": { "chai": "^4.0.0", @@ -18,6 +19,7 @@ }, "dependencies": { "@electron-forge/maker-base": "6.0.0-beta.3", + "@electron-forge/shared-types": "^6.0.0-beta.3", "cross-spawn": "^6.0.4", "fs-extra": "^5.0.0", "parse-author": "^2.0.0", @@ -27,4 +29,4 @@ "electron-installer-dmg": "^0.2.0", "electron-windows-store": "^0.12.0" } -} +} \ No newline at end of file diff --git a/packages/maker/appx/src/Config.ts b/packages/maker/appx/src/Config.ts new file mode 100644 index 0000000000..ed2cb20c0b --- /dev/null +++ b/packages/maker/appx/src/Config.ts @@ -0,0 +1,28 @@ +// TODO: Upstream this to electron-windows-store +export interface MakerAppXConfig { + containerVirtualization?: boolean; + flatten?: boolean; + packageVersion?: string; + packageName?: string; + packageDisplayName?: string; + packageDescription?: string; + packageExecutable?: string; + assets?: string; + manifest?: string; + deploy?: boolean; + publisher?: string; + windowsKit?: string; + devCert?: string; + certPass?: string; + desktopConverter?: string; + expandedBaseImage?: string; + makeappxParams?: string[]; + signtoolParams?: string[]; + makePri?: boolean; + createConfigParams?: string[]; + createPriParams?: string[]; + finalSay?: () => Promise; + + // Magic Electron Forge Option + makeVersionWinStoreCompatible?: boolean; +} diff --git a/packages/maker/appx/src/MakerAppX.js b/packages/maker/appx/src/MakerAppX.ts similarity index 80% rename from packages/maker/appx/src/MakerAppX.js rename to packages/maker/appx/src/MakerAppX.ts index 522a440c52..d1b4df934d 100644 --- a/packages/maker/appx/src/MakerAppX.js +++ b/packages/maker/appx/src/MakerAppX.ts @@ -1,4 +1,5 @@ -import MakerBase from '@electron-forge/maker-base'; +import MakerBase, { MakerOptions } from '@electron-forge/maker-base'; +import { ForgePlatform } from '@electron-forge/shared-types'; import fs from 'fs-extra'; import path from 'path'; @@ -7,6 +8,7 @@ import windowsStore from 'electron-windows-store'; import { isValidPublisherName, makeCert } from 'electron-windows-store/lib/sign'; import getNameFromAuthor from './util/author-name'; +import { MakerAppXConfig } from './Config'; // NB: This is not a typo, we require AppXs to be built on 64-bit // but if we're running in a 32-bit node.js process, we're going to @@ -16,12 +18,12 @@ const windowsSdkPaths = [ 'C:\\Program Files (x86)\\Windows Kits\\10\\bin\\x64', ]; -async function findSdkTool(exe) { - let sdkTool; +async function findSdkTool(exe: string) { + let sdkTool: string | undefined; for (const testPath of windowsSdkPaths) { - if (await fs.exists(testPath)) { + if (await fs.pathExists(testPath)) { let testExe = path.resolve(testPath, exe); - if (await fs.exists(testExe)) { + if (await fs.pathExists(testExe)) { sdkTool = testExe; break; } @@ -31,25 +33,32 @@ async function findSdkTool(exe) { if (subVersion.substr(0, 2) !== '10') continue; // eslint-disable-line no-continue testExe = path.resolve(topDir, subVersion, 'x64', 'makecert.exe'); - if (await fs.exists(testExe)) { + if (await fs.pathExists(testExe)) { sdkTool = testExe; break; } } } } - if (!sdkTool || !await fs.exists(sdkTool)) { + if (!sdkTool || !await fs.pathExists(sdkTool)) { sdkTool = resolveCommand({ command: exe, options: { cwd: null } }, true); } - if (!sdkTool || !await fs.exists(sdkTool)) { + if (!sdkTool || !await fs.pathExists(sdkTool)) { throw `Can't find ${exe} in PATH. You probably need to install the Windows SDK.`; } return sdkTool; } -export async function createDefaultCertificate(publisherName, { certFilePath, certFileName, install, program }) { +export interface CreateDefaultCertOpts { + certFilePath?: string; + certFileName?: string; + program?: MakerAppXConfig; + install?: boolean; +} + +export async function createDefaultCertificate(publisherName: string, { certFilePath, certFileName, install, program }: CreateDefaultCertOpts) { const makeCertOptions = { publisherName, certFilePath: certFilePath || process.cwd(), @@ -65,8 +74,9 @@ export async function createDefaultCertificate(publisherName, { certFilePath, ce return await makeCert(makeCertOptions); } -export default class MakerAppX extends MakerBase { +export default class MakerAppX extends MakerBase { name = 'appx'; + defaultPlatforms: ForgePlatform[] = ['win32']; isSupportedOnCurrentPlatform() { return process.platform === 'win32'; @@ -78,7 +88,7 @@ export default class MakerAppX extends MakerBase { appName, packageJSON, targetArch, - }) { + }: MakerOptions) { const outPath = path.resolve(makeDir, `appx/${targetArch}`); await this.ensureDirectory(outPath); diff --git a/packages/maker/appx/src/util/author-name.js b/packages/maker/appx/src/util/author-name.js deleted file mode 100644 index 944c6febb9..0000000000 --- a/packages/maker/appx/src/util/author-name.js +++ /dev/null @@ -1,19 +0,0 @@ -import parseAuthor from 'parse-author'; - -export default function getNameFromAuthor(author) { - let publisher = author || ''; - - if (typeof publisher === 'string') { - publisher = parseAuthor(publisher); - } - - if (typeof publisher.name === 'string') { - publisher = publisher.name; - } - - if (typeof publisher !== 'string') { - publisher = ''; - } - - return publisher; -} diff --git a/packages/maker/appx/src/util/author-name.ts b/packages/maker/appx/src/util/author-name.ts new file mode 100644 index 0000000000..6309ce8190 --- /dev/null +++ b/packages/maker/appx/src/util/author-name.ts @@ -0,0 +1,19 @@ +import parseAuthor, { AuthorType } from 'parse-author'; + +export default function getNameFromAuthor(author: AuthorType) { + let publisher: AuthorType = author || ''; + + if (typeof publisher === 'string') { + publisher = parseAuthor(publisher); + } + + if (typeof publisher !== 'string' && publisher && typeof publisher.name === 'string') { + publisher = publisher.name; + } + + if (typeof publisher !== 'string') { + publisher = ''; + } + + return publisher; +} diff --git a/packages/maker/appx/test/MakerAppX_spec.js b/packages/maker/appx/test/MakerAppX_spec.ts similarity index 97% rename from packages/maker/appx/test/MakerAppX_spec.js rename to packages/maker/appx/test/MakerAppX_spec.ts index 2191315c2c..cc4d92ad32 100644 --- a/packages/maker/appx/test/MakerAppX_spec.js +++ b/packages/maker/appx/test/MakerAppX_spec.ts @@ -17,7 +17,7 @@ describe('MakerApPX', () => { await fs.remove(tmpDir); }); - let def = it; + let def: any = it; if (process.platform !== 'win32') { def = it.skip; } diff --git a/packages/maker/appx/test/author-name_spec.js b/packages/maker/appx/test/author-name_spec.ts similarity index 100% rename from packages/maker/appx/test/author-name_spec.js rename to packages/maker/appx/test/author-name_spec.ts diff --git a/packages/maker/appx/typings/ambient.d.ts b/packages/maker/appx/typings/ambient.d.ts new file mode 100644 index 0000000000..7cb63035c5 --- /dev/null +++ b/packages/maker/appx/typings/ambient.d.ts @@ -0,0 +1,39 @@ +declare module 'parse-author' { + export type AuthorType = string | { + name: string + } | undefined; + interface ParseAuthor { + (author: AuthorType): AuthorType; + } + const parseAuthor: ParseAuthor; + export default parseAuthor; +} + +declare module 'electron-windows-store' { + const run: (opts: any) => Promise; + export default run; +} + +declare module 'electron-windows-store/lib/sign' { + export const isValidPublisherName: (name: string) => boolean; + export const makeCert: (opts: MakerCertOptions) => Promise; + + interface MakerCertOptions { + publisherName: string; + certFilePath: string; + certFileName: string; + install: boolean; + program: any; + } +} + +declare module 'cross-spawn/lib/util/resolveCommand' { + interface Opts { + command: string; + options: { + cwd: string | null; + }; + } + const resolveCommand: (opts: Opts, work: boolean) => string; + export default resolveCommand; +} diff --git a/packages/maker/base/package.json b/packages/maker/base/package.json index d0f13fcc23..074bd62b29 100644 --- a/packages/maker/base/package.json +++ b/packages/maker/base/package.json @@ -6,8 +6,9 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/Maker.js", + "typings": "dist/Maker.d.ts", "scripts": { - "test": "mocha test/**/*_spec.js test/**/**/*_spec.js --opts ../../../mocha.opts" + "test": "mocha --require ts-node/register test/**/*_spec.ts test/**/**/*_spec.ts --opts ../../../mocha.opts" }, "devDependencies": { "chai": "^4.0.0", @@ -17,6 +18,7 @@ "node": ">= 6.0" }, "dependencies": { + "@electron-forge/shared-types": "^6.0.0-beta.3", "fs-extra": "^5.0.0" } -} +} \ No newline at end of file diff --git a/packages/maker/base/src/Maker.js b/packages/maker/base/src/Maker.ts similarity index 58% rename from packages/maker/base/src/Maker.js rename to packages/maker/base/src/Maker.ts index 0f9c359681..07487e955a 100644 --- a/packages/maker/base/src/Maker.js +++ b/packages/maker/base/src/Maker.ts @@ -1,12 +1,35 @@ /* eslint-disable no-unused-vars */ +import { ForgeArch, ForgeConfig, ForgePlatform, IForgeMaker } from '@electron-forge/shared-types'; import fs from 'fs-extra'; import path from 'path'; -export default class Maker { - constructor(config = {}, platforms = null) { - this.config = config; - this.platforms = platforms; +export interface MakerOptions { + /* The directory containing the packaged Electron application */ + dir: string; + /* + * The directory you should put all your artifacts in (potentially in sub folders) + * NOTE: this directory is not guarunteed to already exist + */ + makeDir: string + /* The resolved human friendly name of the project */ + appName: string; + /* The target platform you should make for */ + targetPlatform: ForgePlatform; + /* The target architecture you should make for */ + targetArch: ForgeArch; + /* Fully resolved forge configuration, you shouldn't really need this */ + forgeConfig: ForgeConfig; + /* The applications package.json file */ + packageJSON: any; +} + +export default abstract class Maker { + public abstract name: string; + public abstract defaultPlatforms: ForgePlatform[]; + __isElectronForgeMaker?: boolean; + + constructor(public config: C = {} as C, protected _platforms?: ForgePlatform[]) { Object.defineProperty(this, '__isElectronForgeMaker', { value: true, enumerable: false, @@ -14,6 +37,11 @@ export default class Maker { }); } + get platforms() { + if (this._platforms) return this._platforms; + return this.defaultPlatforms; + } + /** * Makers must implement this method and return true or false indicating whether * this maker can be run on the current platform. Normally this is just a process.platform @@ -23,7 +51,7 @@ export default class Maker { * If the issue is a missing dependency you should log out a HELPFUL error message * telling the developer exactly what is missing and if possible how to get it. */ - isSupportedOnCurrentPlatform() { + isSupportedOnCurrentPlatform(): boolean { throw new Error(`Maker ${this.name} did not implement the isSupportedOnCurrentPlatform method`); } @@ -31,17 +59,7 @@ export default class Maker { * Makers must implement this method and return an array of absolute paths * to the artifacts generated by your maker */ - async make({ - dir, // The directory containing the packaged Electron application - makeDir, // The directory you should put all your artifacts in (potentially in sub folders) - // NOTE: this directory is not guarunteed to already exist - appName, // The resolved human friendly name of the project - targetPlatform, // The target platform you should make for - targetArch, // The target architecture you should make for - config, // The configuration object designated for this maker - forgeConfig, // Fully resolved forge configuration, you shouldn't really need this - packageJSON, // The applications package.json file - }) { + async make(opts: MakerOptions): Promise { throw new Error(`Maker ${this.name} did not implement the make method`); } @@ -56,7 +74,7 @@ export default class Maker { * I.e. If the directory already exists it is deleted and recreated, this * is a destructive operation */ - async ensureDirectory(dir) { + async ensureDirectory(dir: string): Promise { if (await fs.pathExists(dir)) { await fs.remove(dir); } @@ -68,7 +86,7 @@ export default class Maker { * * I.e. If the file already exists it is deleted and the path created */ - async ensureFile(file) { + async ensureFile(file: string): Promise { if (await fs.pathExists(file)) { await fs.remove(file); } @@ -79,7 +97,7 @@ export default class Maker { * Checks if the given module is installed, used for testing if optional dependencies * are installed or not */ - isInstalled(module) { + isInstalled(module: string): boolean { try { require(module); return true; diff --git a/packages/maker/base/test/ensure-output_spec.js b/packages/maker/base/test/ensure-output_spec.ts similarity index 93% rename from packages/maker/base/test/ensure-output_spec.js rename to packages/maker/base/test/ensure-output_spec.ts index a3e4ba3ec8..7b86b87222 100644 --- a/packages/maker/base/test/ensure-output_spec.js +++ b/packages/maker/base/test/ensure-output_spec.ts @@ -5,8 +5,13 @@ import path from 'path'; import MakerBase from '../src/Maker'; +class MakerImpl extends MakerBase<{}> { + name = 'test'; + defaultPlatforms = []; +} + describe('ensure-output', () => { - const maker = new MakerBase('test'); + const maker = new MakerImpl({}, []); const tmpPath = path.resolve(os.tmpdir(), 'forge-ensure'); before(async () => { @@ -16,7 +21,7 @@ describe('ensure-output', () => { describe('ensureDirectory', () => { it('should delete the directory contents if it exists', async () => { await fs.mkdirs(path.resolve(tmpPath, 'foo')); - fs.writeFileSync(path.resolve(tmpPath, 'foo', 'touchedFile')); + fs.writeFileSync(path.resolve(tmpPath, 'foo', 'touchedFile'), ''); expect(await fs.pathExists(path.resolve(tmpPath, 'foo', 'touchedFile'))).to.equal(true); await maker.ensureDirectory(path.resolve(tmpPath, 'foo')); expect(await fs.pathExists(path.resolve(tmpPath, 'foo', 'touchedFile'))).to.equal(false); @@ -32,7 +37,7 @@ describe('ensure-output', () => { describe('ensureFile', () => { it('should delete the file if it exists', async () => { await fs.mkdirs(path.resolve(tmpPath, 'foo')); - fs.writeFileSync(path.resolve(tmpPath, 'foo', 'touchedFile')); + fs.writeFileSync(path.resolve(tmpPath, 'foo', 'touchedFile'), ''); expect(await fs.pathExists(path.resolve(tmpPath, 'foo', 'touchedFile'))).to.equal(true); await maker.ensureFile(path.resolve(tmpPath, 'foo')); expect(await fs.pathExists(path.resolve(tmpPath, 'foo', 'touchedFile'))).to.equal(false); diff --git a/packages/maker/deb/package.json b/packages/maker/deb/package.json index 150ad260f0..08002becb7 100644 --- a/packages/maker/deb/package.json +++ b/packages/maker/deb/package.json @@ -6,8 +6,9 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/MakerDeb.js", + "typings": "dist/MakerDeb.d.ts", "scripts": { - "test": "mocha test/**/*_spec.js test/**/**/*_spec.js --opts ../../../mocha.opts" + "test": "mocha --require ts-node/register test/**/*_spec.ts test/**/**/*_spec.ts --opts ../../../mocha.opts" }, "devDependencies": { "chai": "^4.0.0", @@ -20,6 +21,10 @@ "node": ">= 6.0" }, "dependencies": { - "@electron-forge/maker-base": "6.0.0-beta.3" + "@electron-forge/maker-base": "6.0.0-beta.3", + "@electron-forge/shared-types": "^6.0.0-beta.3" + }, + "optionalDependencies": { + "electron-installer-debian": "^0.8.0" } -} +} \ No newline at end of file diff --git a/packages/maker/deb/src/Config.ts b/packages/maker/deb/src/Config.ts new file mode 100644 index 0000000000..43e3e2b617 --- /dev/null +++ b/packages/maker/deb/src/Config.ts @@ -0,0 +1,125 @@ +export interface MakerDebConfig { + options?: { + /** + * Name of the package (e.g. atom), used in the Package field of the control + * specification. + * + * Package names [...] must consist only of lower case letters (a-z), digits + * (0-9), plus (+) and minus (-) signs, and periods (.). They must be at + * least two characters long and must start with an alphanumeric character. + */ + name?: string; + /** + * Name of the application (e.g. Atom), used in the Name field of the desktop specification. + */ + productName?: string; + /** + * Generic name of the application (e.g. Text Editor), used in the GenericName field of the desktop specification. + */ + genericName?: string; + /** + * Short description of the application, used in the Description field of the control specification. + */ + description?: string; + /** + * Long description of the application, used in the Description field of the control specification. + */ + productDescription?: string; + /** + * Version number of the package, used in the Version field of the control specification. + */ + version?: string; + /** + * Revision number of the package, used in the Version field of the control specification. + */ + revision?: string; + /** + * Application area into which the package has been classified. + * + * Possible sections. Generated on https://packages.debian.org/unstable/ with: + * + * $$('#content dt a').map(n => {const ss = n.href.split('/'); return `'${ss[ss.length - 2]}'`; }).sort().join(' | ') + */ + section?: 'admin' | 'cli-mono' | 'comm' | 'database' | 'debian-installer' | 'debug' | 'devel' | 'doc' | 'editors' | 'education' | 'electronics' | 'embedded' | 'fonts' | 'games' | 'gnome' | 'gnu-r' | 'gnustep' | 'graphics' | 'hamradio' | 'haskell' | 'httpd' | 'interpreters' | 'introspection' | 'java' | 'javascript' | 'kde' | 'kernel' | 'libdevel' | 'libs' | 'lisp' | 'localization' | 'mail' | 'math' | 'metapackages' | 'misc' | 'net' | 'news' | 'ocaml' | 'oldlibs' | 'otherosfs' | 'perl' | 'php' | 'python' | 'ruby' | 'rust' | 'science' | 'shells' | 'sound' | 'tasks' | 'tex' | 'text' | 'utils' | 'vcs' | 'video' | 'virtual' | 'web' | 'x11' | 'xfce' | 'zope'; + /** + * How important is it to have the package installed. + * + * You can read more: https://www.debian.org/doc/debian-policy/#priorities + */ + priority?: 'required' | 'important' | 'standard' | 'optional'; + /** + * Estimate of the total amount of disk space required to install the named package, + * used in the Installed-Size field of the control specification. + */ + size?: number; + /** + * Relationships to other packages, used in the Depends field of the control specification. + */ + depends?: string[]; + /** + * Relationships to other packages, used in the Recommends field of the control specification. + */ + recommends?: string[]; + /** + * Relationships to other packages, used in the Suggests field of the control specification. + */ + suggests?: string[]; + /** + * Relationships to other packages, used in the Enhances field of the control specification. + */ + enhances?: string[]; + /** + * Relationships to other packages, used in the Pre-Depends field of the control specification. + */ + preDepends?: string[]; + /** + * Maintainer of the package, used in the Maintainer field of the control specification. + */ + maintainer?: string; + /** + * URL of the homepage for the package, used in the Homepage field of the control specification. + */ + homepage?: string; + /** + * Relative path to the executable that will act as binary for the application, used in the Exec field of the desktop specification. + * + * Defaults to options.name + */ + bin?: string; + /** + * Path to a single image that will act as icon for the application: + */ + icon?: string; + /** + * Categories in which the application should be shown in a menu, used in the Categories field of the desktop specification. + * + * Generated on https://specifications.freedesktop.org/menu-spec/latest/apa.html with: + * + * `(${$$('.informaltable tr td:first-child').map(td => `'${td.innerText}'`).join(' | ')})[]` + */ + categories?: ('AudioVideo' | 'Audio' | 'Video' | 'Development' | 'Education' | 'Game' | 'Graphics' | 'Network' | 'Office' | 'Science' | 'Settings' | 'System' | 'Utility')[]; + /** + * MIME types the application is able to open, used in the MimeType field of the desktop specification. + */ + mimeType?: string[]; + /** + * You can use these to quieten lintian. + */ + lintianOverrides?: string[]; + /** + * Path to package maintainer scripts with their corresponding name, used in the installation procedure: + * + * Read More: https://www.debian.org/doc/debian-policy/#package-maintainer-scripts-and-installation-procedure + */ + scripts?: { + preinst?: string; + postinst?: string; + prerm?: string; + postrm?: string; + } + /** + * The absolute path to a custom template for the generated FreeDesktop.org desktop entry file. + */ + desktopTemplate?: string; + } +} \ No newline at end of file diff --git a/packages/maker/deb/src/MakerDeb.js b/packages/maker/deb/src/MakerDeb.ts similarity index 70% rename from packages/maker/deb/src/MakerDeb.js rename to packages/maker/deb/src/MakerDeb.ts index 1c2c1c2167..ef1574a5a0 100644 --- a/packages/maker/deb/src/MakerDeb.js +++ b/packages/maker/deb/src/MakerDeb.ts @@ -1,8 +1,10 @@ -import MakerBase from '@electron-forge/maker-base'; - +import MakerBase, { MakerOptions } from '@electron-forge/maker-base'; +import { ForgeArch, ForgePlatform } from '@electron-forge/shared-types'; import path from 'path'; -export function debianArch(nodeArch) { +import { MakerDebConfig } from './Config'; + +export function debianArch(nodeArch: ForgeArch) { switch (nodeArch) { case 'ia32': return 'i386'; case 'x64': return 'amd64'; @@ -12,8 +14,9 @@ export function debianArch(nodeArch) { } } -export default class MakerDeb extends MakerBase { +export default class MakerDeb extends MakerBase { name = 'deb'; + defaultPlatforms: ForgePlatform[] = ['linux']; isSupportedOnCurrentPlatform() { return this.isInstalled('electron-installer-debian') && process.platform === 'linux'; @@ -24,7 +27,7 @@ export default class MakerDeb extends MakerBase { makeDir, targetArch, packageJSON, - }) { + }: MakerOptions) { const installer = require('electron-installer-debian'); const arch = debianArch(targetArch); @@ -40,6 +43,7 @@ export default class MakerDeb extends MakerBase { src: dir, dest: path.dirname(outPath), arch, + rename: undefined, })); return [outPath]; diff --git a/packages/maker/deb/test/MakerDeb_spec.js b/packages/maker/deb/test/MakerDeb_spec.ts similarity index 56% rename from packages/maker/deb/test/MakerDeb_spec.js rename to packages/maker/deb/test/MakerDeb_spec.ts index 9efff594c9..73bde4c0f2 100644 --- a/packages/maker/deb/test/MakerDeb_spec.js +++ b/packages/maker/deb/test/MakerDeb_spec.ts @@ -1,18 +1,23 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; +import MakerBase from '@electron-forge/maker-base'; + +import { expect } from 'chai'; import path from 'path'; import proxyquire from 'proxyquire'; -import { stub } from 'sinon'; +import { stub, SinonStub } from 'sinon'; + +import { MakerDebConfig } from '../src/Config'; +import { debianArch } from '../src/MakerDeb'; +import { ForgeArch } from '@electron-forge/shared-types'; -chai.use(chaiAsPromised); +class MakerImpl extends MakerBase { name = 'test'; defaultPlatforms = [] } describe('MakerDeb', () => { - let MakerDeb; - let eidStub; - let ensureFileStub; - let config; - let maker; - let createMaker; + let MakerDeb: typeof MakerImpl; + let eidStub: SinonStub; + let ensureFileStub: SinonStub; + let config: MakerDebConfig; + let maker: MakerImpl; + let createMaker: () => void; const dir = '/my/test/dir/out'; const makeDir = path.resolve('/foo/bar/make'); @@ -27,22 +32,23 @@ describe('MakerDeb', () => { MakerDeb = proxyquire.noPreserveCache().noCallThru().load('../src/MakerDeb', { 'electron-installer-debian': eidStub, - }); + }).default; createMaker = () => { - maker = new MakerDeb.default(config); // eslint-disable-line + maker = new MakerDeb(config, []); // eslint-disable-line maker.ensureFile = ensureFileStub; }; createMaker(); }); it('should pass through correct defaults', async () => { - await maker.make({ dir, makeDir, appName, targetArch, packageJSON }); + await (maker.make as any)({ dir, makeDir, appName, targetArch, packageJSON }); const opts = eidStub.firstCall.args[0]; expect(opts).to.deep.equal({ - arch: MakerDeb.debianArch(process.arch), + arch: debianArch(process.arch as ForgeArch), options: {}, src: dir, dest: makeDir, + rename: undefined, }); expect(maker.config).to.deep.equal(config); }); @@ -53,41 +59,42 @@ describe('MakerDeb', () => { options: { productName: 'Debian', }, - }; + } as any; createMaker(); - await maker.make({ dir, makeDir, appName, targetArch, packageJSON }); + await (maker.make as any)({ dir, makeDir, appName, targetArch, packageJSON }); const opts = eidStub.firstCall.args[0]; expect(opts).to.deep.equal({ - arch: MakerDeb.debianArch(process.arch), + arch: debianArch(process.arch as ForgeArch), options: { productName: 'Debian', }, src: dir, dest: makeDir, + rename: undefined, }); }); describe('debianArch', () => { it('should convert ia32 to i386', () => { - expect(MakerDeb.debianArch('ia32')).to.equal('i386'); + expect(debianArch('ia32')).to.equal('i386'); }); it('should convert x64 to amd64', () => { - expect(MakerDeb.debianArch('x64')).to.equal('amd64'); + expect(debianArch('x64')).to.equal('amd64'); }); it('should convert arm to armel', () => { - expect(MakerDeb.debianArch('arm')).to.equal('armel'); + expect(debianArch('arm')).to.equal('armel'); }); it('should convert armv7l to armhf', () => { - expect(MakerDeb.debianArch('armv7l')).to.equal('armhf'); + expect(debianArch('armv7l')).to.equal('armhf'); }); it('should leave unknown values alone', () => { - expect(MakerDeb.debianArch('foo')).to.equal('foo'); + expect(debianArch('foo' as ForgeArch)).to.equal('foo'); }); }); }); diff --git a/packages/maker/dmg/package.json b/packages/maker/dmg/package.json index 9460a8c8bc..8196e1a8e6 100644 --- a/packages/maker/dmg/package.json +++ b/packages/maker/dmg/package.json @@ -6,8 +6,9 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/MakerDMG.js", + "typings": "dist/MakerDMG.d.ts", "scripts": { - "test": "mocha test/**/*_spec.js test/**/**/*_spec.js --opts ../../../mocha.opts" + "test": "mocha --require ts-node/register test/**/*_spec.ts test/**/**/*_spec.ts --opts ../../../mocha.opts" }, "devDependencies": { "chai": "^4.0.0", @@ -21,10 +22,11 @@ }, "dependencies": { "@electron-forge/maker-base": "6.0.0-beta.3", + "@electron-forge/shared-types": "^6.0.0-beta.3", "fs-extra": "^5.0.0", "pify": "^3.0.0" }, "optionalDependencies": { "electron-installer-dmg": "^0.2.0" } -} +} \ No newline at end of file diff --git a/packages/maker/dmg/src/Config.ts b/packages/maker/dmg/src/Config.ts new file mode 100644 index 0000000000..455a0ae193 --- /dev/null +++ b/packages/maker/dmg/src/Config.ts @@ -0,0 +1,30 @@ +export interface MakerDMGConfig { + /** + * The application name + */ + name?: string; + /** + * Path to the background for the DMG window + */ + background?: string; + /** + * Path to the icon to use for the app in the DMG window + */ + icon?: string; + /** + * Overwrite an existing DMG file if if already exists + */ + overwrite?: boolean; + /** + * Enable debug message output + */ + debug?: boolean; + /** + * How big to make the icon for the app in the DMG + */ + 'icon-size'?: number; + /** + * Disk image format + */ + format?: 'UDRW' | 'UDRO' | 'UDCO' | 'UDZO' | 'UDBZ' | 'ULFO'; +} \ No newline at end of file diff --git a/packages/maker/dmg/src/MakerDMG.js b/packages/maker/dmg/src/MakerDMG.ts similarity index 73% rename from packages/maker/dmg/src/MakerDMG.js rename to packages/maker/dmg/src/MakerDMG.ts index 2e174c71fc..ac20b3dd47 100644 --- a/packages/maker/dmg/src/MakerDMG.js +++ b/packages/maker/dmg/src/MakerDMG.ts @@ -1,11 +1,15 @@ -import MakerBase from '@electron-forge/maker-base'; +import MakerBase, { MakerOptions } from '@electron-forge/maker-base'; +import { ForgePlatform } from '@electron-forge/shared-types'; + +import { MakerDMGConfig } from './Config'; import fs from 'fs-extra'; import path from 'path'; import pify from 'pify'; -export default class MakerDMG extends MakerBase { +export default class MakerDMG extends MakerBase { name = 'dmg'; + defaultPlatforms: ForgePlatform[] = ['darwin', 'mas']; isSupportedOnCurrentPlatform() { return process.platform === 'darwin'; @@ -16,7 +20,7 @@ export default class MakerDMG extends MakerBase { makeDir, appName, packageJSON, - }) { + }: MakerOptions) { const electronDMG = require('electron-installer-dmg'); const outPath = path.resolve(makeDir, `${this.config.name || appName}.dmg`); diff --git a/packages/maker/dmg/test/MakerDMG_spec.js b/packages/maker/dmg/test/MakerDMG_spec.ts similarity index 68% rename from packages/maker/dmg/test/MakerDMG_spec.js rename to packages/maker/dmg/test/MakerDMG_spec.ts index 60629333c2..688e796ca6 100644 --- a/packages/maker/dmg/test/MakerDMG_spec.js +++ b/packages/maker/dmg/test/MakerDMG_spec.ts @@ -1,19 +1,22 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; +import MakerBase from '@electron-forge/maker-base'; + +import { expect } from 'chai'; import path from 'path'; import proxyquire from 'proxyquire'; -import { stub } from 'sinon'; +import { stub, SinonStub } from 'sinon'; + +import { MakerDMGConfig } from '../src/Config'; -chai.use(chaiAsPromised); +class MakerImpl extends MakerBase { name = 'test'; defaultPlatforms = [] } describe('MakerDMG', () => { - let MakerDMG; - let ensureFileStub; - let eidStub; - let renameStub; - let config; - let maker; - let createMaker; + let MakerDMG: typeof MakerImpl; + let ensureFileStub: SinonStub; + let eidStub: SinonStub; + let renameStub: SinonStub; + let config: MakerDMGConfig; + let maker: MakerImpl; + let createMaker: () => void; const dir = '/my/test/dir/out'; const makeDir = '/my/test/dir/make'; @@ -42,7 +45,7 @@ describe('MakerDMG', () => { }); it('should pass through correct defaults', async () => { - await maker.make({ dir, makeDir, appName, targetArch, packageJSON }); + await (maker.make as any)({ dir, makeDir, appName, targetArch, packageJSON }); const opts = eidStub.firstCall.args[0]; expect(opts).to.deep.equal({ overwrite: true, @@ -53,20 +56,20 @@ describe('MakerDMG', () => { }); it('should attempt to rename the DMG file if no custom name is set', async () => { - await maker.make({ dir, makeDir, appName, targetArch, packageJSON }); + await (maker.make as any)({ dir, makeDir, appName, targetArch, packageJSON }); expect(renameStub.callCount).to.equal(1); expect(renameStub.firstCall.args[1]).to.include('1.2.3'); }); it('should rename the DMG file to include the version if no custom name is set', async () => { - await maker.make({ dir, makeDir, appName, targetArch, packageJSON }); + await (maker.make as any)({ dir, makeDir, appName, targetArch, packageJSON }); expect(renameStub.firstCall.args[1]).to.include('1.2.3'); }); it('should not attempt to rename the DMG file if a custom name is set', async () => { config.name = 'foobar'; createMaker(); - await maker.make({ dir, makeDir, appName, targetArch, packageJSON }); + await (maker.make as any)({ dir, makeDir, appName, targetArch, packageJSON }); expect(renameStub.callCount).to.equal(0); }); }); diff --git a/packages/maker/flatpak/package.json b/packages/maker/flatpak/package.json index 2af334657a..8a5656c693 100644 --- a/packages/maker/flatpak/package.json +++ b/packages/maker/flatpak/package.json @@ -6,8 +6,9 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/MakerFlatpak.js", + "typings": "dist/MakerFlatpak.d.ts", "scripts": { - "test": "mocha test/**/*_spec.js test/**/**/*_spec.js --opts ../../../mocha.opts" + "test": "mocha --require ts-node/register test/**/*_spec.ts test/**/**/*_spec.ts --opts ../../../mocha.opts" }, "devDependencies": { "chai": "^4.0.0", @@ -18,10 +19,11 @@ }, "dependencies": { "@electron-forge/maker-base": "6.0.0-beta.3", + "@electron-forge/shared-types": "^6.0.0-beta.3", "fs-extra": "^5.0.0", "pify": "^3.0.0" }, "optionalDependencies": { "electron-installer-flatpak": "^0.8.0" } -} +} \ No newline at end of file diff --git a/packages/maker/flatpak/src/Config.ts b/packages/maker/flatpak/src/Config.ts new file mode 100644 index 0000000000..5e688cbe8d --- /dev/null +++ b/packages/maker/flatpak/src/Config.ts @@ -0,0 +1,104 @@ +export interface MakerFlatpakConfig { + options?: { + /** + * App id of the flatpak, used in the id field of a flatpak-builder manifest. + * + * Default: io.atom.electron + */ + id?: string; + /** + * Name of the application (e.g. Atom), used in the Name field of the desktop specification. + */ + productName?: string; + /** + * Generic name of the application (e.g. Text Editor), used in the GenericName field of the desktop specification. + */ + genericName?: string; + /** + * Short description of the application, used in the Comment field of the desktop specification. + */ + description?: string; + /** + * Release branch of the flatpak, used in the branch field of a flatpak-builder manifest. + * + * Default: master + */ + branch?: string; + /** + * Base app to use when building the flatpak, used in the base field of a flatpak-builder manifest. + * + * Default: io.atom.electron.BaseApp + */ + base?: string; + /** + * Base app version, used in the base-version field of a flatpak-builder manifest. + * + * Default: master + */ + baseVersion?: string; + /** + * Url of a flatpakref to use to auto install the base application. + */ + baseFlatpakref?: string; + /** + * Runtime id, used in the runtime field of a flatpak-builder manifest. + * + * Default: org.freedesktop.Platform + */ + runtime?: string; + /** + * Runtime version, used in the runtime-version field of a flatpak-builder manifest. + * + * Default: 1.4 + */ + runtimeVersion?: string; + /** + * Sdk id, used in the sdk field of a flatpak-builder manifest. + * + * Default: org.freedesktop.Sdk + */ + sdk?: string; + /** + * Arguments to use when call flatpak build-finish, use in the finish-args field of a flatpak-builder manifest. + */ + finishArgs?: string[]; + /** + * Files to copy directly into the app. Should be a list of [source, dest] tuples. + * Source should be a relative/absolute path to a file/directory to copy + * into the flatpak, and dest should be the path inside the app install + * prefix (e.g. /share/applications/) + * + * Application assets and code will be fully handled by electron-packager, + * but this is a useful way to install things such as appstream metadata + * for an app, or dbus configuration files. + */ + files: Array<[string, string]>; + /** + * This option can be used to build extra software modules into the flatpak + * application sandbox. Most electron applications will not need this, but + * if you are using native node modules that require certain libraries on + * the system, this may be necessary. + */ + modules?: any[]; + /** + * Relative path to the executable that will act as binary for the application, used in the Exec field of the desktop specification. + */ + bin?: string; + /** + * Path to a single image that will act as icon for the application: + */ + icon?: string; + /** + * Categories in which the application should be shown in a menu, used in the Categories field of the desktop specification. + * + * Generated on https://specifications.freedesktop.org/menu-spec/latest/apa.html with: + * + * `(${$$('.informaltable tr td:first-child').map(td => `'${td.innerText}'`).join(' | ')})[]` + */ + categories?: ('AudioVideo' | 'Audio' | 'Video' | 'Development' | 'Education' | 'Game' | 'Graphics' | 'Network' | 'Office' | 'Science' | 'Settings' | 'System' | 'Utility')[]; + /** + * MIME types the application is able to open, used in the MimeType field of the desktop specification. + */ + mimeType?: string[]; + } +} \ No newline at end of file diff --git a/packages/maker/flatpak/src/MakerFlatpak.js b/packages/maker/flatpak/src/MakerFlatpak.ts similarity index 71% rename from packages/maker/flatpak/src/MakerFlatpak.js rename to packages/maker/flatpak/src/MakerFlatpak.ts index 0cb441f5cf..89d61d3f8f 100644 --- a/packages/maker/flatpak/src/MakerFlatpak.js +++ b/packages/maker/flatpak/src/MakerFlatpak.ts @@ -1,10 +1,13 @@ -import MakerBase from '@electron-forge/maker-base'; +import MakerBase, { MakerOptions } from '@electron-forge/maker-base'; +import { ForgeArch, ForgePlatform } from '@electron-forge/shared-types'; import fs from 'fs-extra'; import path from 'path'; import pify from 'pify'; -export function flatpakArch(nodeArch) { +import { MakerFlatpakConfig } from './Config'; + +export function flatpakArch(nodeArch: ForgeArch) { switch (nodeArch) { case 'ia32': return 'i386'; case 'x64': return 'x86_64'; @@ -14,8 +17,9 @@ export function flatpakArch(nodeArch) { } } -export default class MakerFlatpak extends MakerBase { +export default class MakerFlatpak extends MakerBase { name = 'flatpak'; + defaultPlatforms: ForgePlatform[] = ['linux']; isSupportedOnCurrentPlatform() { return this.isInstalled('electron-installer-flatpak') && process.platform === 'linux'; @@ -25,7 +29,7 @@ export default class MakerFlatpak extends MakerBase { dir, makeDir, targetArch, - }) { + }: MakerOptions) { const installer = require('electron-installer-flatpak'); const arch = flatpakArch(targetArch); diff --git a/packages/maker/flatpak/test/MakerFlatpak_spec.js b/packages/maker/flatpak/test/MakerFlatpak_spec.ts similarity index 59% rename from packages/maker/flatpak/test/MakerFlatpak_spec.js rename to packages/maker/flatpak/test/MakerFlatpak_spec.ts index 916cd98827..7f999a4564 100644 --- a/packages/maker/flatpak/test/MakerFlatpak_spec.js +++ b/packages/maker/flatpak/test/MakerFlatpak_spec.ts @@ -1,18 +1,24 @@ -import chai, { expect } from 'chai'; +import MakerBase from '@electron-forge/maker-base'; + +import { expect } from 'chai'; import chaiAsPromised from 'chai-as-promised'; import path from 'path'; import proxyquire from 'proxyquire'; -import { stub } from 'sinon'; +import { stub, SinonStub } from 'sinon'; + +import { flatpakArch } from '../src/MakerFlatpak'; +import { MakerFlatpakConfig } from '../src/Config'; +import { ForgeArch } from '@electron-forge/shared-types'; -chai.use(chaiAsPromised); +class MakerImpl extends MakerBase { name = 'test'; defaultPlatforms = [] } describe('MakerFlatpak', () => { - let flatpakModule; - let maker; - let eidStub; - let ensureDirectoryStub; - let config; - let createMaker; + let flatpakModule: typeof MakerImpl; + let maker: MakerImpl; + let eidStub: SinonStub; + let ensureDirectoryStub: SinonStub; + let config: MakerFlatpakConfig; + let createMaker: () => void; const dir = '/my/test/dir/out'; const makeDir = path.resolve('/make/dir'); @@ -28,19 +34,19 @@ describe('MakerFlatpak', () => { flatpakModule = proxyquire.noPreserveCache().noCallThru().load('../src/MakerFlatpak', { 'fs-extra': { readdir: stub().returns(Promise.resolve([])) }, 'electron-installer-flatpak': eidStub, - }); + }).default; createMaker = () => { - maker = new flatpakModule.default(config); // eslint-disable-line + maker = new flatpakModule(config); // eslint-disable-line maker.ensureDirectory = ensureDirectoryStub; }; createMaker(); }); it('should pass through correct defaults', async () => { - await maker.make({ dir, makeDir, appName, targetArch, packageJSON }); + await (maker.make as any)({ dir, makeDir, appName, targetArch, packageJSON }); const opts = eidStub.firstCall.args[0]; expect(opts).to.deep.equal({ - arch: flatpakModule.flatpakArch(process.arch), + arch: flatpakArch(process.arch as ForgeArch), src: dir, dest: path.resolve(makeDir, 'flatpak'), }); @@ -52,13 +58,13 @@ describe('MakerFlatpak', () => { options: { productName: 'Flatpak', }, - }; + } as any; createMaker(); - await maker.make({ dir, makeDir, appName, targetArch, packageJSON }); + await (maker.make as any)({ dir, makeDir, appName, targetArch, packageJSON }); const opts = eidStub.firstCall.args[0]; expect(opts).to.deep.equal({ - arch: flatpakModule.flatpakArch(process.arch), + arch: flatpakArch(process.arch as ForgeArch), options: { productName: 'Flatpak', }, diff --git a/packages/maker/rpm/package.json b/packages/maker/rpm/package.json index 3fcd132c9a..f4a8461bb9 100644 --- a/packages/maker/rpm/package.json +++ b/packages/maker/rpm/package.json @@ -6,8 +6,9 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/MakerRpm.js", + "typings": "dist/MakerRpm.d.ts", "scripts": { - "test": "mocha test/**/*_spec.js test/**/**/*_spec.js --opts ../../../mocha.opts" + "test": "mocha --require ts-node/register test/**/*_spec.ts test/**/**/*_spec.ts --opts ../../../mocha.opts" }, "devDependencies": { "chai": "^4.0.0", @@ -21,9 +22,10 @@ }, "dependencies": { "@electron-forge/maker-base": "6.0.0-beta.3", + "@electron-forge/shared-types": "^6.0.0-beta.3", "pify": "^3.0.0" }, "optionalDependencies": { "electron-installer-redhat": "^0.5.0" } -} +} \ No newline at end of file diff --git a/packages/maker/rpm/src/Config.ts b/packages/maker/rpm/src/Config.ts new file mode 100644 index 0000000000..e2b11b8c9f --- /dev/null +++ b/packages/maker/rpm/src/Config.ts @@ -0,0 +1,79 @@ +export interface MakerRpmConfig { + options?: { + /** + * Name of the package (e.g. atom), used in the Package field of the control + * specification. + */ + name?: string; + /** + * Name of the application (e.g. Atom), used in the Name field of the desktop specification. + */ + productName?: string; + /** + * Generic name of the application (e.g. Text Editor), used in the GenericName field of the desktop specification. + */ + genericName?: string; + /** + * Short description of the application, used in the Summary field of the spec file. + */ + description?: string; + /** + * Long description of the application, used in the %description tag of the spec file. + */ + productDescription?: string; + /** + * Version number of the package, used in the Version field of the spec file. + */ + version?: string; + /** + * Revision number of the package, used in the Release field of the spec file. + */ + revision?: string; + /** + * License of the package, used in the License field of the spec file. + */ + license?: string; + /** + * Group of the package, used in the Group field of the spec file. + */ + group?: string; + /** + * Packages that are required when the program starts, used in the Requires field of the spec file. + */ + requires?: string[]; + /** + * URL of the homepage for the package, used in the Homepage field of the control specification. + */ + homepage?: string; + /** + * Package compression level, from 0 to 9. + */ + compressionLevel?: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; + /** + * Relative path to the executable that will act as binary for the application, used in the Exec field of the desktop specification. + * + * Defaults to options.name + */ + bin?: string; + /** + * Command-line arguments to pass to the executable. Will be added to the Exec field of the desktop specification. + */ + execArguments?: string[]; + /** + * Path to a single image that will act as icon for the application: + */ + icon?: string; + /** + * Categories in which the application should be shown in a menu, used in the Categories field of the desktop specification. + * + * Generated on https://specifications.freedesktop.org/menu-spec/latest/apa.html with: + * + * `(${$$('.informaltable tr td:first-child').map(td => `'${td.innerText}'`).join(' | ')})[]` + */ + categories?: ('AudioVideo' | 'Audio' | 'Video' | 'Development' | 'Education' | 'Game' | 'Graphics' | 'Network' | 'Office' | 'Science' | 'Settings' | 'System' | 'Utility')[]; + /** + * MIME types the application is able to open, used in the MimeType field of the desktop specification. + */ + mimeType?: string[]; + } +} diff --git a/packages/maker/rpm/src/MakerRpm.js b/packages/maker/rpm/src/MakerRpm.ts similarity index 71% rename from packages/maker/rpm/src/MakerRpm.js rename to packages/maker/rpm/src/MakerRpm.ts index dfe699f879..85fe55398e 100644 --- a/packages/maker/rpm/src/MakerRpm.js +++ b/packages/maker/rpm/src/MakerRpm.ts @@ -1,9 +1,12 @@ -import MakerBase from '@electron-forge/maker-base'; +import MakerBase, { MakerOptions } from '@electron-forge/maker-base'; +import { ForgeArch, ForgePlatform } from '@electron-forge/shared-types'; import path from 'path'; import pify from 'pify'; -export function rpmArch(nodeArch) { +import { MakerRpmConfig } from './Config'; + +export function rpmArch(nodeArch: ForgeArch) { switch (nodeArch) { case 'ia32': return 'i386'; case 'x64': return 'x86_64'; @@ -13,8 +16,9 @@ export function rpmArch(nodeArch) { } } -export default class MakerRpm extends MakerBase { +export default class MakerRpm extends MakerBase { name = 'rpm'; + defaultPlatforms: ForgePlatform[] = ['linux']; isSupportedOnCurrentPlatform() { return this.isInstalled('electron-installer-redhat') && process.platform === 'linux'; @@ -25,7 +29,7 @@ export default class MakerRpm extends MakerBase { makeDir, targetArch, packageJSON, - }) { + }: MakerOptions) { const installer = require('electron-installer-redhat'); const arch = rpmArch(targetArch); @@ -38,6 +42,7 @@ export default class MakerRpm extends MakerBase { arch, src: dir, dest: path.dirname(outPath), + rename: undefined, }); await pify(installer)(rpmConfig); diff --git a/packages/maker/rpm/test/MakerRpm_spec.js b/packages/maker/rpm/test/MakerRpm_spec.ts similarity index 55% rename from packages/maker/rpm/test/MakerRpm_spec.js rename to packages/maker/rpm/test/MakerRpm_spec.ts index f319a58761..4a38bc554b 100644 --- a/packages/maker/rpm/test/MakerRpm_spec.js +++ b/packages/maker/rpm/test/MakerRpm_spec.ts @@ -1,18 +1,23 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; +import MakerBase from '@electron-forge/maker-base'; + +import { expect } from 'chai'; import path from 'path'; import proxyquire from 'proxyquire'; -import { stub } from 'sinon'; +import { stub, SinonStub } from 'sinon'; + +import { MakerRpmConfig } from '../src/Config'; +import { rpmArch } from '../src/MakerRpm'; +import { ForgeArch } from '@electron-forge/shared-types'; -chai.use(chaiAsPromised); +class MakerImpl extends MakerBase { name = 'test'; defaultPlatforms = [] } describe('MakerRpm', () => { - let rpmModule; - let maker; - let eidStub; - let ensureFileStub; - let config; - let createMaker; + let rpmModule: typeof MakerImpl; + let maker: MakerImpl; + let eidStub: SinonStub; + let ensureFileStub: SinonStub; + let config: MakerRpmConfig; + let createMaker: () => void; const dir = '/my/test/dir/out'; const makeDir = path.resolve('/make/dir'); @@ -27,21 +32,22 @@ describe('MakerRpm', () => { rpmModule = proxyquire.noPreserveCache().noCallThru().load('../src/MakerRpm', { 'electron-installer-redhat': eidStub, - }); + }).default; createMaker = () => { - maker = new rpmModule.default(config); // eslint-disable-line + maker = new rpmModule(config); // eslint-disable-line maker.ensureFile = ensureFileStub; }; createMaker(); }); it('should pass through correct defaults', async () => { - await maker.make({ dir, makeDir, appName, targetArch, packageJSON }); + await (maker.make as any)({ dir, makeDir, appName, targetArch, packageJSON }); const opts = eidStub.firstCall.args[0]; expect(opts).to.deep.equal({ - arch: rpmModule.rpmArch(process.arch), + arch: rpmArch(process.arch as ForgeArch), src: dir, dest: makeDir, + rename: undefined, }); }); @@ -51,40 +57,41 @@ describe('MakerRpm', () => { options: { productName: 'Redhat', }, - }; + } as any; createMaker(); - await maker.make({ dir, makeDir, appName, targetArch, packageJSON }); + await (maker.make as any)({ dir, makeDir, appName, targetArch, packageJSON }); const opts = eidStub.firstCall.args[0]; expect(opts).to.deep.equal({ - arch: rpmModule.rpmArch(process.arch), + arch: rpmArch(process.arch as ForgeArch), options: { productName: 'Redhat', }, src: dir, dest: makeDir, + rename: undefined, }); }); describe('rpmArch', () => { it('should convert ia32 to i386', () => { - expect(rpmModule.rpmArch('ia32')).to.equal('i386'); + expect(rpmArch('ia32')).to.equal('i386'); }); it('should convert x64 to x86_64', () => { - expect(rpmModule.rpmArch('x64')).to.equal('x86_64'); + expect(rpmArch('x64')).to.equal('x86_64'); }); it('should convert arm to armv6hl', () => { - expect(rpmModule.rpmArch('arm')).to.equal('armv6hl'); + expect(rpmArch('arm')).to.equal('armv6hl'); }); it('should convert armv7l to armv7hl', () => { - expect(rpmModule.rpmArch('armv7l')).to.equal('armv7hl'); + expect(rpmArch('armv7l')).to.equal('armv7hl'); }); it('should leave unknown values alone', () => { - expect(rpmModule.rpmArch('foo')).to.equal('foo'); + expect(rpmArch('foo' as ForgeArch)).to.equal('foo'); }); }); }); diff --git a/packages/maker/snap/package.json b/packages/maker/snap/package.json index bc5c1cd477..c2261d8ff1 100644 --- a/packages/maker/snap/package.json +++ b/packages/maker/snap/package.json @@ -6,8 +6,9 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/MakerSnap.js", + "typings": "dist/MakerSnap.d.ts", "scripts": { - "test": "mocha test/**/*_spec.js test/**/**/*_spec.js --opts ../../../mocha.opts" + "test": "mocha --require ts-node/register test/**/*_spec.ts test/**/**/*_spec.ts --opts ../../../mocha.opts" }, "devDependencies": { "chai": "^4.0.0", @@ -20,9 +21,10 @@ "node": ">= 6.0" }, "dependencies": { - "@electron-forge/maker-base": "6.0.0-beta.3" + "@electron-forge/maker-base": "6.0.0-beta.3", + "@electron-forge/shared-types": "^6.0.0-beta.3" }, "optionalDependencies": { "electron-installer-snap": "^2.0.0" } -} +} \ No newline at end of file diff --git a/packages/maker/snap/src/Config.ts b/packages/maker/snap/src/Config.ts new file mode 100644 index 0000000000..45413f4c74 --- /dev/null +++ b/packages/maker/snap/src/Config.ts @@ -0,0 +1,93 @@ +export interface MakerSnapConfig { + /** + * [Additional Snapcraft configuration](https://docs.snapcraft.io/build-snaps/syntax#app-name) for the Electron app. + */ + appConfig?: string; + /** + * Additional [plugs](https://docs.snapcraft.io/reference/interfaces) for the + * Electron app which are necessary for the app to + * be a consumer of a feature in the system. Common features can be set via + * the `features` option. To set any attributes for the plugs, set them in the + * plugs option. + */ + appPlugs?: string[]; + /** + * Additional [slots](https://docs.snapcraft.io/reference/interfaces) for the + * Electron app which are necessary for the app to + * be a producer of a feature in the system. Common features can be set via + * the `features` option. To set any attributes for the plugs, set them in + * the slots option. + */ + appSlots?: string[]; + /** + * See the [Snapcraft documentation](https://snapcraft.io/docs/reference/confinement). + * + * Default: devmode + */ + confinement?: 'strict' | 'devmode' | 'classic'; + /** + * The longer description for the snap. Can contain newlines. + */ + description?: string; + /** + * The absolute path to a custom Freedesktop.org desktop file template. + */ + desktopTemplate?: string; + /** + * The executable name of the Electron app, sans file extension. Corresponds + * to the [`executableName` option](https://github.com/electron-userland/electron-packager/blob/master/docs/api#executablename) + * in Electron Packager. + */ + executableName?: string; + /** + * Describes what functionality the Electron app needs, in order to work inside the Snap sandbox. + */ + features?: { + /** + * PulseAudio support + */ + audio?: true; + /** + * ALSA support (replaces audio support if both are specified) + */ + alsa?: true; + /** + * [web browser functionality](https://github.com/snapcore/snapd/wiki/Interfaces#browser-support) (e.g., Brave) + */ + browserSandbox?: true; + /** + * [MPRIS](https://specifications.freedesktop.org/mpris-spec/latest/) support. + * + * If enabled, the interface name must be specified as the feature value. + */ + mpris?: string; + /** + * Access the secret service (e.g., GNOME Keyring) + */ + passwords?: true; + /** + * WebGL support (requires Mesa, etc.) + */ + webgl?: true; + }; + /** + * The quality grade of the Snap. See the [Snapcraft documentation](https://docs.snapcraft.io/build-snaps/syntax#grade) for valid values. + */ + grade?: 'devel' | 'stable'; + /** + * The name of the Snap package + */ + name?: string; + /** + * The absolute path to the snapcraft executable + */ + snapcraft?: string; + /** + * A 78 character long summary for the Snap + */ + summary?: string; + /** + * The version of the Snap package + */ + version?: string; +} \ No newline at end of file diff --git a/packages/maker/snap/src/MakerSnap.js b/packages/maker/snap/src/MakerSnap.ts similarity index 63% rename from packages/maker/snap/src/MakerSnap.js rename to packages/maker/snap/src/MakerSnap.ts index 6e0347b70b..6cc6704288 100644 --- a/packages/maker/snap/src/MakerSnap.js +++ b/packages/maker/snap/src/MakerSnap.ts @@ -1,9 +1,13 @@ -import MakerBase from '@electron-forge/maker-base'; +import MakerBase, { MakerOptions } from '@electron-forge/maker-base'; +import { ForgePlatform } from '@electron-forge/shared-types'; import path from 'path'; -export default class MakerSnap extends MakerBase { +import { MakerSnapConfig } from './Config'; + +export default class MakerSnap extends MakerBase { name = 'snap'; + defaultPlatforms: ForgePlatform[] = ['linux']; isSupportedOnCurrentPlatform() { return process.platform === 'linux'; @@ -13,7 +17,7 @@ export default class MakerSnap extends MakerBase { dir, makeDir, targetArch, - }) { + }: MakerOptions) { const installer = require('electron-installer-snap'); const outPath = path.resolve(makeDir, 'snap'); diff --git a/packages/maker/snap/test/MakerSnap_spec.js b/packages/maker/snap/test/MakerSnap_spec.ts similarity index 64% rename from packages/maker/snap/test/MakerSnap_spec.js rename to packages/maker/snap/test/MakerSnap_spec.ts index 4ef3b0e6a4..cbd513ad57 100644 --- a/packages/maker/snap/test/MakerSnap_spec.js +++ b/packages/maker/snap/test/MakerSnap_spec.ts @@ -1,18 +1,21 @@ -import chai, { expect } from 'chai'; -import chaiAsPromised from 'chai-as-promised'; +import MakerBase from '@electron-forge/maker-base'; + +import { expect } from 'chai'; import path from 'path'; import proxyquire from 'proxyquire'; -import { stub } from 'sinon'; +import { stub, SinonStub } from 'sinon'; + +import { MakerSnapConfig } from '../src/Config'; -chai.use(chaiAsPromised); +class MakerImpl extends MakerBase { name = 'test'; defaultPlatforms = [] } describe('MakerSnap', () => { - let MakerSnapModule; - let maker; - let eisStub; - let ensureDirectoryStub; - let config; - let createMaker; + let MakerSnapModule: typeof MakerImpl; + let maker: MakerImpl; + let eisStub: SinonStub; + let ensureDirectoryStub: SinonStub; + let config: MakerSnapConfig; + let createMaker: () => void; const dir = '/my/test/dir/out/foo-linux-x64'; const makeDir = path.resolve('/make/dir'); @@ -27,16 +30,16 @@ describe('MakerSnap', () => { MakerSnapModule = proxyquire.noPreserveCache().noCallThru().load('../src/MakerSnap', { 'electron-installer-snap': eisStub, - }); + }).default; createMaker = () => { - maker = new MakerSnapModule.default(config); // eslint-disable-line + maker = new MakerSnapModule(config); // eslint-disable-line maker.ensureDirectory = ensureDirectoryStub; }; createMaker(); }); it('should pass through correct defaults', async () => { - await maker.make({ dir, makeDir, appName, targetArch, packageJSON }); + await (maker.make as any)({ dir, makeDir, appName, targetArch, packageJSON }); const opts = eisStub.firstCall.args[0]; expect(opts).to.deep.equal({ arch: process.arch, @@ -49,10 +52,10 @@ describe('MakerSnap', () => { config = { arch: 'overridden', description: 'Snap description', - }; + } as any; createMaker(); - await maker.make({ dir, makeDir, appName, targetArch, packageJSON }); + await (maker.make as any)({ dir, makeDir, appName, targetArch, packageJSON }); const opts = eisStub.firstCall.args[0]; expect(opts).to.deep.equal({ arch: process.arch, diff --git a/packages/maker/squirrel/package.json b/packages/maker/squirrel/package.json index 969dd2053e..fa89d6f3e5 100644 --- a/packages/maker/squirrel/package.json +++ b/packages/maker/squirrel/package.json @@ -6,6 +6,7 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/MakerSquirrel.js", + "typings": "dist/MakerSquirrel.d.ts", "scripts": { "test": "exit 0" }, @@ -18,9 +19,10 @@ }, "dependencies": { "@electron-forge/maker-base": "6.0.0-beta.3", + "@electron-forge/shared-types": "^6.0.0-beta.3", "fs-extra": "^5.0.0" }, "optionalDependencies": { "electron-winstaller": "^2.5.0" } -} +} \ No newline at end of file diff --git a/packages/maker/squirrel/src/MakerSquirrel.js b/packages/maker/squirrel/src/MakerSquirrel.ts similarity index 74% rename from packages/maker/squirrel/src/MakerSquirrel.js rename to packages/maker/squirrel/src/MakerSquirrel.ts index 3f38a44f6a..10bb07202b 100644 --- a/packages/maker/squirrel/src/MakerSquirrel.js +++ b/packages/maker/squirrel/src/MakerSquirrel.ts @@ -1,10 +1,18 @@ -import MakerBase from '@electron-forge/maker-base'; +import MakerBase, { MakerOptions } from '@electron-forge/maker-base'; +import { ForgePlatform } from '@electron-forge/shared-types'; +import { createWindowsInstaller, Options as ElectronWinstallerOptions } from 'electron-winstaller'; import fs from 'fs-extra'; import path from 'path'; -export default class MakerSquirrel extends MakerBase { +// Hacks to fix make appDirectory optional +export type Optional = { + [K in keyof T]?: T[K]; +} + +export default class MakerSquirrel extends MakerBase> { name = 'squirrel'; + defaultPlatforms: ForgePlatform[] = ['win32']; isSupportedOnCurrentPlatform() { return this.isInstalled('electron-winstaller') && !process.env.DISABLE_SQUIRREL_TEST; @@ -16,9 +24,7 @@ export default class MakerSquirrel extends MakerBase { targetArch, packageJSON, appName, - }) { - const { createWindowsInstaller } = require('electron-winstaller'); - + }: MakerOptions) { const outPath = path.resolve(makeDir, `squirrel.windows/${targetArch}`); await this.ensureDirectory(outPath); diff --git a/packages/maker/wix/package.json b/packages/maker/wix/package.json index 0daa31bc8b..c5393e455b 100644 --- a/packages/maker/wix/package.json +++ b/packages/maker/wix/package.json @@ -6,8 +6,9 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/MakerWix.js", + "typings": "dist/MakerWix.d.ts", "scripts": { - "test": "mocha test/**/*_spec.js test/**/**/*_spec.js --opts ../../../mocha.opts" + "test": "mocha --require ts-node/register test/**/*_spec.ts test/**/**/*_spec.ts --opts ../../../mocha.opts" }, "devDependencies": { "chai": "^4.0.0", @@ -18,6 +19,7 @@ }, "dependencies": { "@electron-forge/maker-base": "6.0.0-beta.3", + "@electron-forge/shared-types": "^6.0.0-beta.3", "electron-wix-msi": "^1.3.0" } -} +} \ No newline at end of file diff --git a/packages/maker/wix/src/MakerWix.js b/packages/maker/wix/src/MakerWix.ts similarity index 67% rename from packages/maker/wix/src/MakerWix.js rename to packages/maker/wix/src/MakerWix.ts index 22b308841c..379d003986 100644 --- a/packages/maker/wix/src/MakerWix.js +++ b/packages/maker/wix/src/MakerWix.ts @@ -1,11 +1,15 @@ -import MakerBase from '@electron-forge/maker-base'; +import MakerBase, { MakerOptions } from '@electron-forge/maker-base'; +import { ForgePlatform } from '@electron-forge/shared-types'; import path from 'path'; import getNameFromAuthor from './util/author-name'; -export default class MakerWix extends MakerBase { +import { MSICreator, MSICreatorOptions } from 'electron-wix-msi/lib/creator'; + +export default class MakerWix extends MakerBase { name = 'wix'; + defaultPlatforms: ForgePlatform[] = ['win32']; isSupportedOnCurrentPlatform() { return process.platform === 'win32'; @@ -17,9 +21,7 @@ export default class MakerWix extends MakerBase { targetArch, packageJSON, appName, - }) { - const { MSICreator } = require('electron-wix-msi'); - + }: MakerOptions) { const outPath = path.resolve(makeDir, `/wix/${targetArch}`); await this.ensureDirectory(outPath); @@ -32,7 +34,7 @@ export default class MakerWix extends MakerBase { }, this.config, { appDirectory: dir, outputDirectory: outPath, - })); + }) as MSICreatorOptions); await creator.create(); const { msiFile } = await creator.compile(); diff --git a/packages/maker/wix/src/util/author-name.js b/packages/maker/wix/src/util/author-name.js deleted file mode 100644 index 944c6febb9..0000000000 --- a/packages/maker/wix/src/util/author-name.js +++ /dev/null @@ -1,19 +0,0 @@ -import parseAuthor from 'parse-author'; - -export default function getNameFromAuthor(author) { - let publisher = author || ''; - - if (typeof publisher === 'string') { - publisher = parseAuthor(publisher); - } - - if (typeof publisher.name === 'string') { - publisher = publisher.name; - } - - if (typeof publisher !== 'string') { - publisher = ''; - } - - return publisher; -} diff --git a/packages/maker/wix/src/util/author-name.ts b/packages/maker/wix/src/util/author-name.ts new file mode 100644 index 0000000000..6309ce8190 --- /dev/null +++ b/packages/maker/wix/src/util/author-name.ts @@ -0,0 +1,19 @@ +import parseAuthor, { AuthorType } from 'parse-author'; + +export default function getNameFromAuthor(author: AuthorType) { + let publisher: AuthorType = author || ''; + + if (typeof publisher === 'string') { + publisher = parseAuthor(publisher); + } + + if (typeof publisher !== 'string' && publisher && typeof publisher.name === 'string') { + publisher = publisher.name; + } + + if (typeof publisher !== 'string') { + publisher = ''; + } + + return publisher; +} diff --git a/packages/maker/wix/test/author-name_spec.js b/packages/maker/wix/test/author-name_spec.ts similarity index 100% rename from packages/maker/wix/test/author-name_spec.js rename to packages/maker/wix/test/author-name_spec.ts diff --git a/packages/maker/wix/typings/ambient.d.ts b/packages/maker/wix/typings/ambient.d.ts new file mode 100644 index 0000000000..f94674eb3e --- /dev/null +++ b/packages/maker/wix/typings/ambient.d.ts @@ -0,0 +1,10 @@ +declare module 'parse-author' { + export type AuthorType = string | { + name: string + } | undefined; + interface ParseAuthor { + (author: AuthorType): AuthorType; + } + const parseAuthor: ParseAuthor; + export default parseAuthor; +} diff --git a/packages/maker/zip/package.json b/packages/maker/zip/package.json index 72a2f4f1eb..85433343c7 100644 --- a/packages/maker/zip/package.json +++ b/packages/maker/zip/package.json @@ -6,6 +6,7 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/MakerZIP.js", + "typings": "dist/MakerZIP.d.ts", "scripts": { "test": "exit 0" }, @@ -18,8 +19,9 @@ }, "dependencies": { "@electron-forge/maker-base": "6.0.0-beta.3", + "@electron-forge/shared-types": "^6.0.0-beta.3", "fs-extra": "^5.0.0", "pify": "^3.0.0", "zip-folder": "^1.0.0" } -} +} \ No newline at end of file diff --git a/packages/maker/zip/src/MakerZIP.js b/packages/maker/zip/src/MakerZIP.ts similarity index 69% rename from packages/maker/zip/src/MakerZIP.js rename to packages/maker/zip/src/MakerZIP.ts index a07d75b932..d5158484fd 100644 --- a/packages/maker/zip/src/MakerZIP.js +++ b/packages/maker/zip/src/MakerZIP.ts @@ -1,11 +1,15 @@ -import MakerBase from '@electron-forge/maker-base'; +import MakerBase, { MakerOptions } from '@electron-forge/maker-base'; +import { ForgePlatform } from '@electron-forge/shared-types'; import { spawn } from 'child_process'; import path from 'path'; import pify from 'pify'; -export default class MakerZIP extends MakerBase { +export type MakerZIPConfig = {}; + +export default class MakerZIP extends MakerBase { name = 'zip'; + defaultPlatforms: ForgePlatform[] = ['darwin', 'mas', 'win32', 'linux']; isSupportedOnCurrentPlatform() { return true; @@ -17,7 +21,7 @@ export default class MakerZIP extends MakerBase { appName, packageJSON, targetPlatform, - }) { + }: MakerOptions) { const zipFolder = require('zip-folder'); const zipPath = path.resolve(makeDir, `${path.basename(dir)}-${packageJSON.version}.zip`); @@ -39,8 +43,8 @@ export default class MakerZIP extends MakerBase { return [zipPath]; } - zipPromise = (from, to) => - new Promise((resolve, reject) => { + private zipPromise = (from: string, to: string) => + new Promise((resolve, reject) => { const child = spawn('zip', ['-r', '-y', to, path.basename(from)], { cwd: path.dirname(from), }); @@ -50,7 +54,7 @@ export default class MakerZIP extends MakerBase { child.on('close', (code) => { if (code === 0) return resolve(); - reject(new Error(`Failed to zip, exitted with code: ${code}`)); + reject(new Error(`Failed to zip, exited with code: ${code}`)); }); }); } diff --git a/packages/publisher/base/package.json b/packages/publisher/base/package.json index 3d0a3e490c..a0eeb6309a 100644 --- a/packages/publisher/base/package.json +++ b/packages/publisher/base/package.json @@ -6,14 +6,16 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/Publisher.js", + "typings": "dist/Publisher.d.ts", "scripts": { - "test": "mocha test/**/*_spec.js test/**/**/*_spec.js --opts ../../../mocha.opts" + "test": "mocha --require ts-node/register test/**/*_spec.ts test/**/**/*_spec.ts --opts ../../../mocha.opts" }, "devDependencies": { + "@electron-forge/shared-types": "^6.0.0-beta.3", "chai": "^4.0.0", "mocha": "^5.0.0" }, "engines": { "node": ">= 6.0" } -} +} \ No newline at end of file diff --git a/packages/publisher/base/src/Publisher.js b/packages/publisher/base/src/Publisher.ts similarity index 50% rename from packages/publisher/base/src/Publisher.js rename to packages/publisher/base/src/Publisher.ts index 71723a87b2..d37076bdac 100644 --- a/packages/publisher/base/src/Publisher.js +++ b/packages/publisher/base/src/Publisher.ts @@ -1,9 +1,31 @@ +import { ForgePlatform, ForgeConfig, ForgeArch, ForgeMakeResult } from "@electron-forge/shared-types"; + /* eslint-disable no-unused-vars */ -export default class Publisher { - constructor(config = {}, platforms = null) { +export interface PublisherOptions { + /** + * The base directory of the apps source code + */ + dir: string; + /** + * The results from running the make command + */ + makeResults: ForgeMakeResult[]; + /** + * The raw forgeConfig this app is using. + * + * You probably shouldn't use this + */ + forgeConfig: ForgeConfig; +} + +export default abstract class Publisher { + public abstract name: string; + public defaultPlatforms?: ForgePlatform[]; + __isElectronForgePublisher?: boolean; + + constructor(public config: C, protected _platforms?: ForgePlatform[]) { this.config = config; - this.platforms = platforms; Object.defineProperty(this, '__isElectronForgePublisher', { value: true, enumerable: false, @@ -11,6 +33,12 @@ export default class Publisher { }); } + get platforms() { + if (this._platforms) return this._platforms; + if (this.defaultPlatforms) return this.defaultPlatforms; + return ['win32', 'linux', 'darwin', 'mas']; + } + /** * Publishers must implement this method to publish the artifacts returned from * make calls. If any errors occur you must throw them, failing silently or simply @@ -22,15 +50,7 @@ export default class Publisher { * you will have to create the version on GitHub and the second call will just * be appending files to the existing version. */ - async publish({ - dir, // The base directory of the apps source code - makeResults, // An array of MakeResult objects, see the MakeResult object definition for details - packageJSON, // The packageJSON of the app - config, // The config that is dedicated for this publisher - forgeConfig, // The raw forgeConfig this app is using, you shouldn't really have to use this - platform, // The platform these artifacts are for - arch, // The arch these artifacts are for - }) { + async publish(opts: PublisherOptions) { throw new Error(`Publisher ${this.name} did not implement the publish method`); } } diff --git a/packages/publisher/base/test/Publisher_spec.js b/packages/publisher/base/test/Publisher_spec.js deleted file mode 100644 index fed30c4273..0000000000 --- a/packages/publisher/base/test/Publisher_spec.js +++ /dev/null @@ -1,15 +0,0 @@ -import { expect } from 'chai'; - -import Publisher from '../src/Publisher'; - -describe('Publisher', () => { - it('should define __isElectronForgePublisher', () => { - const publisher = new Publisher('test'); - expect(publisher).to.have.property('__isElectronForgePublisher', true); - }); - - it('should throw an error when install is called', (done) => { - const publisher = new Publisher('test'); - publisher.publish({}).catch(() => done()); - }); -}); diff --git a/packages/publisher/base/test/Publisher_spec.ts b/packages/publisher/base/test/Publisher_spec.ts new file mode 100644 index 0000000000..9f541b5f19 --- /dev/null +++ b/packages/publisher/base/test/Publisher_spec.ts @@ -0,0 +1,20 @@ +import { expect } from 'chai'; + +import Publisher from '../src/Publisher'; + +class PublisherImpl extends Publisher { + defaultPlatforms = []; + name = 'test'; +} + +describe('Publisher', () => { + it('should define __isElectronForgePublisher', () => { + const publisher = new PublisherImpl(null); + expect(publisher).to.have.property('__isElectronForgePublisher', true); + }); + + it('should throw an error when publish is called is called', (done) => { + const publisher = new PublisherImpl(null); + publisher.publish({} as any).catch(() => done()); + }); +}); diff --git a/packages/publisher/electron-release-server/package.json b/packages/publisher/electron-release-server/package.json index 1a6a05ce79..daf5903ac8 100644 --- a/packages/publisher/electron-release-server/package.json +++ b/packages/publisher/electron-release-server/package.json @@ -6,6 +6,7 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/PublisherERS.js", + "typings": "dist/PublisherERS.d.ts", "scripts": { "test": "exit 0" }, @@ -19,9 +20,10 @@ "dependencies": { "@electron-forge/async-ora": "6.0.0-beta.3", "@electron-forge/publisher-base": "6.0.0-beta.3", + "@electron-forge/shared-types": "^6.0.0-beta.3", "debug": "^3.0.0", "form-data": "^2.1.4", "fs-extra": "^5.0.0", "node-fetch": "^2.0.0" } -} +} \ No newline at end of file diff --git a/packages/publisher/electron-release-server/src/Config.ts b/packages/publisher/electron-release-server/src/Config.ts new file mode 100644 index 0000000000..e5062e68b0 --- /dev/null +++ b/packages/publisher/electron-release-server/src/Config.ts @@ -0,0 +1,6 @@ +export interface PublisherERSConfig { + baseUrl: string; + username: string; + password: string; + channel?: string; +} \ No newline at end of file diff --git a/packages/publisher/electron-release-server/src/PublisherERS.js b/packages/publisher/electron-release-server/src/PublisherERS.js deleted file mode 100644 index 701454af82..0000000000 --- a/packages/publisher/electron-release-server/src/PublisherERS.js +++ /dev/null @@ -1,127 +0,0 @@ -import PublisherBase from '@electron-forge/publisher-base'; -import { asyncOra } from '@electron-forge/async-ora'; - -import debug from 'debug'; -import fetch from 'node-fetch'; -import FormData from 'form-data'; -import fs from 'fs-extra'; -import path from 'path'; - -const d = debug('electron-forge:publish:ers'); - -export const ersPlatform = (platform, arch) => { - switch (platform) { - case 'darwin': - return 'osx_64'; - case 'linux': - return arch === 'ia32' ? 'linux_32' : 'linux_64'; - case 'win32': - return arch === 'ia32' ? 'windows_32' : 'windows_64'; - default: - return platform; - } -}; - -export default class PublisherERS extends PublisherBase { - name = 'electron-release-server'; - - async publish({ makeResults, packageJSON, platform, arch }) { - const { config } = this; - - const artifacts = makeResults.reduce((flat, makeResult) => { - flat.push(...makeResult.artifacts); - return flat; - }, []); - - if (!(config.baseUrl && config.username && config.password)) { - throw 'In order to publish to ERS you must set the "electronReleaseServer.baseUrl", "electronReleaseServer.username" and "electronReleaseServer.password" properties in your forge config. See the docs for more info'; // eslint-disable-line - } - - d('attempting to authenticate to ERS'); - - const api = apiPath => `${config.baseUrl}/${apiPath}`; - - const { token } = await (await fetch(api('api/auth/login'), { - method: 'POST', - body: JSON.stringify({ - username: config.username, - password: config.password, - }), - headers: { - 'Content-Type': 'application/json', - }, - })).json(); - - const authFetch = (apiPath, options) => fetch(api(apiPath), Object.assign({}, options || {}, { - headers: Object.assign({}, (options || {}).headers, { Authorization: `Bearer ${token}` }), - })); - - const versions = await (await authFetch('api/version')).json(); - const existingVersion = versions.find(version => version.name === packageJSON.version); - - let channel = 'stable'; - if (config.channel) { - channel = config.channel; - } else if (packageJSON.version.includes('beta')) { - channel = 'beta'; - } else if (packageJSON.version.includes('alpha')) { - channel = 'alpha'; - } - - if (!existingVersion) { - await authFetch('api/version', { - method: 'POST', - body: JSON.stringify({ - channel: { - name: channel, - }, - name: packageJSON.version, - notes: '', - }), - headers: { - 'Content-Type': 'application/json', - }, - }); - } - - let uploaded = 0; - await asyncOra(`Uploading Artifacts ${uploaded}/${artifacts.length}`, async (uploadSpinner) => { - const updateSpinner = () => { - uploadSpinner.text = `Uploading Artifacts ${uploaded}/${artifacts.length}`; // eslint-disable-line no-param-reassign - }; - - await Promise.all(artifacts.map(artifactPath => - new Promise(async (resolve, reject) => { - if (existingVersion) { - const existingAsset = existingVersion.assets.find(asset => asset.name === path.basename(artifactPath)); - if (existingAsset) { - d('asset at path:', artifactPath, 'already exists on server'); - uploaded += 1; - updateSpinner(); - return; - } - } - try { - d('attempting to upload asset:', artifactPath); - const artifactForm = new FormData(); - artifactForm.append('token', token); - artifactForm.append('version', packageJSON.version); - artifactForm.append('platform', ersPlatform(platform, arch)); - artifactForm.append('file', fs.createReadStream(artifactPath)); - await authFetch('api/asset', { - method: 'POST', - body: artifactForm, - headers: artifactForm.getHeaders(), - }); - d('upload successful for asset:', artifactPath); - uploaded += 1; - updateSpinner(); - resolve(); - } catch (err) { - reject(err); - } - }) - )); - }); - } -} diff --git a/packages/publisher/electron-release-server/src/PublisherERS.ts b/packages/publisher/electron-release-server/src/PublisherERS.ts new file mode 100644 index 0000000000..f48a4695fe --- /dev/null +++ b/packages/publisher/electron-release-server/src/PublisherERS.ts @@ -0,0 +1,136 @@ +import PublisherBase, { PublisherOptions } from '@electron-forge/publisher-base'; +import { asyncOra } from '@electron-forge/async-ora'; +import { ForgePlatform, ForgeArch } from '@electron-forge/shared-types'; + +import debug from 'debug'; +import fetch from 'node-fetch'; +import FormData from 'form-data'; +import fs from 'fs-extra'; +import path from 'path'; + +import { PublisherERSConfig } from './Config'; + +const d = debug('electron-forge:publish:ers'); + +interface ERSVersion { + name: string; + assets: { name: string; }[]; +} + +export const ersPlatform = (platform: ForgePlatform, arch: ForgeArch) => { + switch (platform) { + case 'darwin': + return 'osx_64'; + case 'linux': + return arch === 'ia32' ? 'linux_32' : 'linux_64'; + case 'win32': + return arch === 'ia32' ? 'windows_32' : 'windows_64'; + default: + return platform; + } +}; + +export default class PublisherERS extends PublisherBase { + name = 'electron-release-server'; + + async publish({ makeResults }: PublisherOptions) { + const { config } = this; + + if (!(config.baseUrl && config.username && config.password)) { + throw 'In order to publish to ERS you must set the "electronReleaseServer.baseUrl", "electronReleaseServer.username" and "electronReleaseServer.password" properties in your forge config. See the docs for more info'; // eslint-disable-line + } + + d('attempting to authenticate to ERS'); + + const api = (apiPath: string) => `${config.baseUrl}/${apiPath}`; + + const { token } = await (await fetch(api('api/auth/login'), { + method: 'POST', + body: JSON.stringify({ + username: config.username, + password: config.password, + }), + headers: { + 'Content-Type': 'application/json', + }, + })).json(); + + const authFetch = (apiPath: string, options?: any) => + fetch(api(apiPath), Object.assign({}, options || {}, { + headers: Object.assign({}, (options || {}).headers, { Authorization: `Bearer ${token}` }), + })); + + const versions: ERSVersion[] = await (await authFetch('api/version')).json(); + + for (const makeResult of makeResults) { + const { artifacts, packageJSON } = makeResult; + + const existingVersion = versions.find(version => version.name === packageJSON.version); + + let channel = 'stable'; + if (config.channel) { + channel = config.channel; + } else if (packageJSON.version.includes('beta')) { + channel = 'beta'; + } else if (packageJSON.version.includes('alpha')) { + channel = 'alpha'; + } + + if (!existingVersion) { + await authFetch('api/version', { + method: 'POST', + body: JSON.stringify({ + channel: { + name: channel, + }, + name: packageJSON.version, + notes: '', + }), + headers: { + 'Content-Type': 'application/json', + }, + }); + } + + let uploaded = 0; + await asyncOra(`Uploading Artifacts ${uploaded}/${artifacts.length}`, async (uploadSpinner) => { + const updateSpinner = () => { + uploadSpinner.text = `Uploading Artifacts ${uploaded}/${artifacts.length}`; // eslint-disable-line no-param-reassign + }; + + await Promise.all(artifacts.map(artifactPath => + new Promise(async (resolve, reject) => { + if (existingVersion) { + const existingAsset = existingVersion.assets.find(asset => asset.name === path.basename(artifactPath)); + if (existingAsset) { + d('asset at path:', artifactPath, 'already exists on server'); + uploaded += 1; + updateSpinner(); + return; + } + } + try { + d('attempting to upload asset:', artifactPath); + const artifactForm = new FormData(); + artifactForm.append('token', token); + artifactForm.append('version', packageJSON.version); + artifactForm.append('platform', ersPlatform(makeResult.platform, makeResult.arch)); + artifactForm.append('file', fs.createReadStream(artifactPath)); + await authFetch('api/asset', { + method: 'POST', + body: artifactForm, + headers: artifactForm.getHeaders(), + }); + d('upload successful for asset:', artifactPath); + uploaded += 1; + updateSpinner(); + resolve(); + } catch (err) { + reject(err); + } + }) + )); + }); + } + } +} diff --git a/packages/publisher/github/package.json b/packages/publisher/github/package.json index 0964950bb7..1a4959b804 100644 --- a/packages/publisher/github/package.json +++ b/packages/publisher/github/package.json @@ -6,8 +6,9 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/PublisherGithub.js", + "typings": "dist/PublisherGithub.d.ts", "scripts": { - "test": "mocha test/**/*_spec.js test/**/**/*_spec.js --opts ../../../mocha.opts" + "test": "mocha --require ts-node/register test/**/*_spec.ts test/**/**/*_spec.ts --opts ../../../mocha.opts" }, "devDependencies": { "chai": "^4.0.0", @@ -19,9 +20,10 @@ "dependencies": { "@electron-forge/async-ora": "6.0.0-beta.3", "@electron-forge/publisher-base": "6.0.0-beta.3", + "@electron-forge/shared-types": "^6.0.0-beta.3", "@octokit/rest": "^15.2.6", "fs-extra": "^5.0.0", "lodash.merge": "^4.6.0", "mime-types": "^2.1.17" } -} +} \ No newline at end of file diff --git a/packages/publisher/github/src/Config.ts b/packages/publisher/github/src/Config.ts new file mode 100644 index 0000000000..3d18371e60 --- /dev/null +++ b/packages/publisher/github/src/Config.ts @@ -0,0 +1,12 @@ +import { Options } from '@octokit/rest'; + +export interface PublisherGithubConfig { + repository: { + name: string; + owner: string; + draft?: boolean; + } + authToken?: string; + octokitOptions?: Options; + prerelease?: boolean; +} \ No newline at end of file diff --git a/packages/publisher/github/src/PublisherGithub.js b/packages/publisher/github/src/PublisherGithub.js deleted file mode 100644 index 52c182fa00..0000000000 --- a/packages/publisher/github/src/PublisherGithub.js +++ /dev/null @@ -1,85 +0,0 @@ -import PublisherBase from '@electron-forge/publisher-base'; -import { asyncOra } from '@electron-forge/async-ora'; - -import fs from 'fs-extra'; -import mime from 'mime-types'; -import path from 'path'; - -import GitHub from './util/github'; - -export default class PublisherGithub extends PublisherBase { - name = 'github'; - - async publish({ makeResults, packageJSON, tag }) { - const { config } = this; - - const artifacts = makeResults.reduce((flat, makeResult) => { - flat.push(...makeResult.artifacts); - return flat; - }, []); - - if (!(config.repository && typeof config.repository === 'object' && - config.repository.owner && config.repository.name)) { - throw 'In order to publish to github you must set the "github_repository.owner" and "github_repository.name" properties in your forge config. See the docs for more info'; // eslint-disable-line - } - - const github = new GitHub(config.authToken, true, config.octokitOptions); - - let release; - await asyncOra('Searching for target release', async () => { - try { - release = (await github.getGitHub().repos.getReleases({ - owner: config.repository.owner, - repo: config.repository.name, - per_page: 100, - })).data.find(testRelease => testRelease.tag_name === (tag || `v${packageJSON.version}`)); - if (!release) { - throw { code: 404 }; - } - } catch (err) { - if (err.code === 404) { - // Release does not exist, let's make it - release = (await github.getGitHub().repos.createRelease({ - owner: config.repository.owner, - repo: config.repository.name, - tag_name: tag || `v${packageJSON.version}`, - name: tag || `v${packageJSON.version}`, - draft: config.repository.draft !== false, - prerelease: config.prerelease === true, - })).data; - } else { - // Unknown error - throw err; - } - } - }); - - let uploaded = 0; - await asyncOra(`Uploading Artifacts ${uploaded}/${artifacts.length}`, async (uploadSpinner) => { - const updateSpinner = () => { - uploadSpinner.text = `Uploading Artifacts ${uploaded}/${artifacts.length}`; // eslint-disable-line - }; - - await Promise.all(artifacts.map(artifactPath => - new Promise(async (resolve) => { - const done = () => { - uploaded += 1; - updateSpinner(); - resolve(); - }; - if (release.assets.find(asset => asset.name === path.basename(artifactPath))) { - return done(); - } - await github.getGitHub().repos.uploadAsset({ - url: release.upload_url, - file: fs.createReadStream(artifactPath), - contentType: mime.lookup(artifactPath) || 'application/octet-stream', - contentLength: (await fs.stat(artifactPath)).size, - name: path.basename(artifactPath), - }); - return done(); - }) - )); - }); - } -} diff --git a/packages/publisher/github/src/PublisherGithub.ts b/packages/publisher/github/src/PublisherGithub.ts new file mode 100644 index 0000000000..c62a6a3e3d --- /dev/null +++ b/packages/publisher/github/src/PublisherGithub.ts @@ -0,0 +1,111 @@ +import PublisherBase, { PublisherOptions } from '@electron-forge/publisher-base'; +import { asyncOra } from '@electron-forge/async-ora'; + +import fs from 'fs-extra'; +import mime from 'mime-types'; +import path from 'path'; + +import GitHub from './util/github'; +import { PublisherGithubConfig } from './Config'; +import { ForgeMakeResult } from '@electron-forge/shared-types'; + +interface GitHubRelease { + tag_name: string; + assets: { + name: string; + }[]; + upload_url: string; +} + +export default class PublisherGithub extends PublisherBase { + name = 'github'; + + async publish({ makeResults }: PublisherOptions) { + const { config } = this; + + const perReleaseArtifacts: { + [release: string]: ForgeMakeResult[]; + } = {}; + + for (const makeResult of makeResults) { + const release = makeResult.packageJSON.version; + if (!perReleaseArtifacts[release]) { + perReleaseArtifacts[release] = []; + } + perReleaseArtifacts[release].push(makeResult); + } + + if (!(config.repository && typeof config.repository === 'object' && + config.repository.owner && config.repository.name)) { + throw 'In order to publish to github you must set the "github_repository.owner" and "github_repository.name" properties in your forge config. See the docs for more info'; // eslint-disable-line + } + + const github = new GitHub(config.authToken, true, config.octokitOptions); + + for (const releaseName of Object.keys(perReleaseArtifacts)) { + let release: GitHubRelease; + const artifacts = perReleaseArtifacts[releaseName]; + + await asyncOra(`Searching for target release: ${releaseName}`, async () => { + try { + release = (await github.getGitHub().repos.getReleases({ + owner: config.repository.owner, + repo: config.repository.name, + per_page: 100, + })).data.find((testRelease: GitHubRelease) => testRelease.tag_name === `v${releaseName}`); + if (!release) { + throw { code: 404 }; + } + } catch (err) { + if (err.code === 404) { + // Release does not exist, let's make it + release = (await github.getGitHub().repos.createRelease({ + owner: config.repository.owner, + repo: config.repository.name, + tag_name: `v${releaseName}`, + name: `v${releaseName}`, + draft: config.repository.draft !== false, + prerelease: config.prerelease === true, + })).data; + } else { + // Unknown error + throw err; + } + } + }); + + let uploaded = 0; + await asyncOra(`Uploading Artifacts ${uploaded}/${artifacts.length} to v${releaseName}`, async (uploadSpinner) => { + const updateSpinner = () => { + uploadSpinner.text = `Uploading Artifacts ${uploaded}/${artifacts.length} to v${releaseName}`; // eslint-disable-line + }; + + const flatArtifacts: string[] = []; + for (const artifact of artifacts) { + flatArtifacts.push(...artifact.artifacts); + } + + await Promise.all(flatArtifacts.map(artifactPath => + new Promise(async (resolve) => { + const done = () => { + uploaded += 1; + updateSpinner(); + resolve(); + }; + if (release.assets.find(asset => asset.name === path.basename(artifactPath))) { + return done(); + } + await github.getGitHub().repos.uploadAsset({ + url: release.upload_url, + file: fs.createReadStream(artifactPath), + contentType: mime.lookup(artifactPath) || 'application/octet-stream', + contentLength: (await fs.stat(artifactPath)).size, + name: path.basename(artifactPath), + }); + return done(); + }) + )); + }); + } + } +} diff --git a/packages/publisher/github/src/util/github.js b/packages/publisher/github/src/util/github.ts similarity index 79% rename from packages/publisher/github/src/util/github.js rename to packages/publisher/github/src/util/github.ts index c50813affb..ab4e22d575 100644 --- a/packages/publisher/github/src/util/github.js +++ b/packages/publisher/github/src/util/github.ts @@ -2,7 +2,10 @@ import GitHubAPI from '@octokit/rest'; import merge from 'lodash.merge'; export default class GitHub { - constructor(authToken, requireAuth, options = {}) { + private options: GitHubAPI.Options; + token?: string; + + constructor(authToken: string | undefined = undefined, requireAuth: boolean = false, options: GitHubAPI.Options = {}) { this.options = merge( { protocol: 'https' }, options, diff --git a/packages/publisher/github/test/github_spec.js b/packages/publisher/github/test/github_spec.ts similarity index 83% rename from packages/publisher/github/test/github_spec.js rename to packages/publisher/github/test/github_spec.ts index 2db3b24c3f..a2c57a7152 100644 --- a/packages/publisher/github/test/github_spec.js +++ b/packages/publisher/github/test/github_spec.ts @@ -1,18 +1,22 @@ import { expect } from 'chai'; import proxyquire from 'proxyquire'; -import sinon from 'sinon'; +import sinon, { SinonSpy } from 'sinon'; + +import InternalGitHub from '../src/util/github'; describe('GitHub', () => { - let GitHub; - let gitHubSpy; - let gitHubAuthSpy; - let MockGitHub; + let GitHub: typeof InternalGitHub; + let gitHubSpy: SinonSpy; + let gitHubAuthSpy: SinonSpy; + let MockGitHub: any; beforeEach(() => { gitHubSpy = sinon.spy(); gitHubAuthSpy = sinon.spy(); MockGitHub = class { - constructor(options) { + private options: any; + + constructor(options: any) { gitHubSpy(); this.options = options; } @@ -52,7 +56,7 @@ describe('GitHub', () => { }); const api = gh.getGitHub(); - expect(api.options).to.deep.equal({ + expect((api as any).options).to.deep.equal({ protocol: 'https', host: 'github.example.com', port: 8443, @@ -67,7 +71,7 @@ describe('GitHub', () => { const gh = new GitHub('1234', true, { headers: { 'user-agent': 'Something' } }); const api = gh.getGitHub(); - expect(api.options.headers['user-agent']).to.equal('Electron Forge'); + expect((api as any).options.headers['user-agent']).to.equal('Electron Forge'); }); it('should authenticate if a token is present', () => { @@ -86,7 +90,7 @@ describe('GitHub', () => { it('should throw an exception if a token is required', () => { expect(() => { - const gh = new GitHub(null, true); + const gh = new GitHub(undefined, true); gh.getGitHub(); }).to.throw('Please set GITHUB_TOKEN in your environment to access these features'); }); diff --git a/packages/publisher/s3/package.json b/packages/publisher/s3/package.json index 10a08c9af9..03733436ab 100644 --- a/packages/publisher/s3/package.json +++ b/packages/publisher/s3/package.json @@ -6,6 +6,7 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/PublisherS3.js", + "typings": "dist/PublisherS3.d.ts", "scripts": { "test": "exit 0" }, @@ -17,9 +18,11 @@ "node": ">= 6.0" }, "dependencies": { + "@electron-forge/async-ora": "^6.0.0-beta.3", "@electron-forge/publisher-base": "6.0.0-beta.3", + "@electron-forge/shared-types": "^6.0.0-beta.3", "aws-sdk": "^2.9.0", "debug": "^3.0.0", "s3": "^4.4.0" } -} +} \ No newline at end of file diff --git a/packages/publisher/s3/src/Config.ts b/packages/publisher/s3/src/Config.ts new file mode 100644 index 0000000000..a6191f9691 --- /dev/null +++ b/packages/publisher/s3/src/Config.ts @@ -0,0 +1,8 @@ +export interface PublisherS3Config { + accessKeyId?: string; + secretAccessKey?: string; + bucket?: string; + folder?: string; + public?: boolean; + keyResolver?: (fileName: string, platform: string, arch: string) => string; +} \ No newline at end of file diff --git a/packages/publisher/s3/src/PublisherS3.js b/packages/publisher/s3/src/PublisherS3.ts similarity index 54% rename from packages/publisher/s3/src/PublisherS3.js rename to packages/publisher/s3/src/PublisherS3.ts index f58e4a772d..fde48d82c5 100644 --- a/packages/publisher/s3/src/PublisherS3.js +++ b/packages/publisher/s3/src/PublisherS3.ts @@ -1,29 +1,46 @@ -import PublisherBase from '@electron-forge/publisher-base'; +import PublisherBase, { PublisherOptions } from '@electron-forge/publisher-base'; import { asyncOra } from '@electron-forge/async-ora'; import AWS from 'aws-sdk'; import debug from 'debug'; import path from 'path'; -import s3 from 's3'; + +import { PublisherS3Config } from './Config'; +import { ForgePlatform } from '@electron-forge/shared-types'; + +// FIXME: Drop usage of s3 module in favor of AWS-sdk +const s3 = require('s3'); const d = debug('electron-forge:publish:s3'); -AWS.util.update(AWS.S3.prototype, { +(AWS as any).util.update(AWS.S3.prototype, { addExpect100Continue: function addExpect100Continue() { // Hack around large upload issue: https://github.com/andrewrk/node-s3-client/issues/74 }, }); -export default class PublisherS3 extends PublisherBase { +export default class PublisherS3 extends PublisherBase { name = 's3'; - async publish({ makeResults, packageJSON, tag, platform, arch }) { + async publish({ + makeResults, + }: PublisherOptions) { const { config } = this; + const artifacts: { + path: string; + keyPrefix: string; + platform: string; + arch: string; + }[] = []; - const artifacts = makeResults.reduce((flat, makeResult) => { - flat.push(...makeResult.artifacts); - return flat; - }, []); + for (const makeResult of makeResults) { + artifacts.push(...makeResult.artifacts.map(artifact => ({ + path: artifact, + keyPrefix: config.folder || makeResult.packageJSON.version, + platform: makeResult.platform, + arch: makeResult.arch, + }))); + } const s3Client = new AWS.S3({ accessKeyId: config.accessKeyId, @@ -41,17 +58,15 @@ export default class PublisherS3 extends PublisherBase { }); client.s3.addExpect100Continue = () => {}; - const folder = config.folder || tag || packageJSON.version; - let uploaded = 0; await asyncOra(`Uploading Artifacts ${uploaded}/${artifacts.length}`, async (uploadSpinner) => { const updateSpinner = () => { uploadSpinner.text = `Uploading Artifacts ${uploaded}/${artifacts.length}`; // eslint-disable-line }; - await Promise.all(artifacts.map(artifactPath => + await Promise.all(artifacts.map(artifact => new Promise(async (resolve, reject) => { - const done = (err) => { + const done = (err?: Error) => { if (err) return reject(err); uploaded += 1; updateSpinner(); @@ -59,20 +74,24 @@ export default class PublisherS3 extends PublisherBase { }; const uploader = client.uploadFile({ - localFile: artifactPath, + localFile: artifact.path, s3Params: { Bucket: config.bucket, Key: this.config.keyResolver - ? this.config.keyResolver(path.basename(artifactPath), platform, arch) - : `${folder}/${path.basename(artifactPath)}`, + ? this.config.keyResolver( + path.basename(artifact.path), + artifact.platform, + artifact.arch, + ) + : `${artifact.keyPrefix}/${path.basename(artifact.path)}`, ACL: config.public ? 'public-read' : 'private', }, }); - d('uploading:', artifactPath); + d('uploading:', artifact.path); - uploader.on('error', err => done(err)); + uploader.on('error', (err: Error) => done(err)); uploader.on('progress', () => { - d(`Upload Progress (${path.basename(artifactPath)}) ${Math.round((uploader.progressAmount / uploader.progressTotal) * 100)}%`); + d(`Upload Progress (${path.basename(artifact.path)}) ${Math.round((uploader.progressAmount / uploader.progressTotal) * 100)}%`); }); uploader.on('end', () => done()); }) diff --git a/packages/publisher/snapcraft/package.json b/packages/publisher/snapcraft/package.json index 8eb6220cff..074072db87 100644 --- a/packages/publisher/snapcraft/package.json +++ b/packages/publisher/snapcraft/package.json @@ -6,6 +6,7 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/PublisherSnapcraft.js", + "typings": "dist/PublisherSnapcraft.d.ts", "scripts": { "test": "exit 0" }, diff --git a/packages/publisher/snapcraft/src/Config.ts b/packages/publisher/snapcraft/src/Config.ts new file mode 100644 index 0000000000..fcc1e09a47 --- /dev/null +++ b/packages/publisher/snapcraft/src/Config.ts @@ -0,0 +1,6 @@ +export interface PublisherSnapcraftConfig { + /** + * A comma-separated list of channels to release to + */ + release: string; +} \ No newline at end of file diff --git a/packages/publisher/snapcraft/src/PublisherSnapcraft.js b/packages/publisher/snapcraft/src/PublisherSnapcraft.ts similarity index 72% rename from packages/publisher/snapcraft/src/PublisherSnapcraft.js rename to packages/publisher/snapcraft/src/PublisherSnapcraft.ts index a82caa7600..2e6e33aa7e 100644 --- a/packages/publisher/snapcraft/src/PublisherSnapcraft.js +++ b/packages/publisher/snapcraft/src/PublisherSnapcraft.ts @@ -1,18 +1,21 @@ -import PublisherBase from '@electron-forge/publisher-base'; +import PublisherBase, { PublisherOptions } from '@electron-forge/publisher-base'; import { asyncOra } from '@electron-forge/async-ora'; import fs from 'fs-extra'; import path from 'path'; -import Snapcraft from 'electron-installer-snap/snapcraft'; -export default class PublisherSnapcraft extends PublisherBase { +import { PublisherSnapcraftConfig } from './Config'; + +const Snapcraft = require('electron-installer-snap/snapcraft'); + +export default class PublisherSnapcraft extends PublisherBase { name = 'snapcraft'; - async publish({ dir, makeResults }) { + async publish({ dir, makeResults }: PublisherOptions) { const artifacts = makeResults.reduce((flat, makeResult) => { flat.push(...makeResult.artifacts); return flat; - }, []); + }, [] as string[]); const snapArtifacts = artifacts.filter(artifact => artifact.endsWith('.snap')); diff --git a/packages/utils/async-ora/package.json b/packages/utils/async-ora/package.json index b0b487fac1..dd5cae9f29 100644 --- a/packages/utils/async-ora/package.json +++ b/packages/utils/async-ora/package.json @@ -6,8 +6,9 @@ "author": "Samuel Attard", "license": "MIT", "main": "dist/index.js", + "typings": "dist/index.d.ts", "scripts": { - "test": "mocha test/**/*_spec.js test/**/**/*_spec.js --opts ../../../mocha.opts" + "test": "mocha --require ts-node/register test/**/*_spec.ts test/**/**/*_spec.ts --opts ../../../mocha.opts" }, "devDependencies": { "chai": "^4.0.0", @@ -16,7 +17,7 @@ "sinon": "^4.1.2" }, "dependencies": { - "colors": "^1.1.2", + "colors": "^1.2.0", "debug": "^3.0.0", "log-symbols": "^2.0.0", "ora": "^2.0.0" @@ -24,4 +25,4 @@ "engines": { "node": ">= 6.0" } -} +} \ No newline at end of file diff --git a/packages/utils/async-ora/src/index.js b/packages/utils/async-ora/src/index.ts similarity index 56% rename from packages/utils/async-ora/src/index.js rename to packages/utils/async-ora/src/index.ts index 5070f358a1..6ec4a5b350 100644 --- a/packages/utils/async-ora/src/index.js +++ b/packages/utils/async-ora/src/index.ts @@ -1,8 +1,9 @@ import ora, { fakeOra } from './ora'; -import asyncOra from './ora-handler'; +import asyncOra, { OraImpl } from './ora-handler'; export { ora, fakeOra, asyncOra, + OraImpl, }; diff --git a/packages/utils/async-ora/src/ora-handler.js b/packages/utils/async-ora/src/ora-handler.ts similarity index 66% rename from packages/utils/async-ora/src/ora-handler.js rename to packages/utils/async-ora/src/ora-handler.ts index a99870591f..a740ef084e 100644 --- a/packages/utils/async-ora/src/ora-handler.js +++ b/packages/utils/async-ora/src/ora-handler.ts @@ -1,15 +1,23 @@ import colors from 'colors'; import ora from './ora'; -class MockOra { - succeed() { return this; } - fail() { return this; } +export class OraImpl { + constructor(public text: string = '') {} + + succeed(symbol?: string) { return this; } + fail(symbol?: string) { return this; } start() { return this; } - stop() { return this; } + stop(symbol?: string) { return this; } + warn(message: string) { return this; } +} + +export interface AsyncOraMethod { + (initialOraValue: string, asyncFn: (ora: OraImpl) => Promise, processExitFn?: (code: number) => void): Promise; + interactive?: boolean; } -const asyncOra = (initialOraValue, asyncFn, processExitFn = process.exit) => { - let fnOra = new MockOra(); +const asyncOra: AsyncOraMethod = (initialOraValue, asyncFn, processExitFn = process.exit) => { + let fnOra = new OraImpl(initialOraValue); if (asyncOra.interactive) { fnOra = ora(initialOraValue).start(); } diff --git a/packages/utils/async-ora/src/ora.js b/packages/utils/async-ora/src/ora.js deleted file mode 100644 index 4631ae6e00..0000000000 --- a/packages/utils/async-ora/src/ora.js +++ /dev/null @@ -1,39 +0,0 @@ -import 'colors'; -import debug from 'debug'; -import logSymbols from 'log-symbols'; -import realOra from 'ora'; - -const d = debug('electron-forge:async-ora'); - -const useFakeOra = (process.env.DEBUG && process.env.DEBUG.includes('electron-forge')); - -if (useFakeOra) { - console.warn('WARNING: DEBUG environment variable detected. Progress indicators will be sent over electron-forge:lifecycle'.red); -} - -export const fakeOra = (name) => { - const fake = { - start: () => { - d('Process Started:', name); - return fake; - }, - warn: (msg) => { - console.warn(logSymbols.warning, msg.yellow); - }, - fail: () => { - d(`Process Failed: ${name}`.red); - return fake; - }, - succeed: () => { - d('Process Succeeded:', name); - return fake; - }, - stop: () => { - d('Process Stopped:', name); - return fake; - }, - }; - return fake; -}; - -export default useFakeOra ? fakeOra : realOra; diff --git a/packages/utils/async-ora/src/ora.ts b/packages/utils/async-ora/src/ora.ts new file mode 100644 index 0000000000..c36f953bc7 --- /dev/null +++ b/packages/utils/async-ora/src/ora.ts @@ -0,0 +1,49 @@ +import 'colors'; +import debug from 'debug'; +import logSymbols from 'log-symbols'; +import realOra from 'ora'; +import { OraImpl } from './ora-handler'; + +const d = debug('electron-forge:async-ora'); + +const useFakeOra = Boolean(process.env.DEBUG && process.env.DEBUG.includes('electron-forge')); + +if (useFakeOra) { + console.warn('WARNING: DEBUG environment variable detected. Progress indicators will be sent over electron-forge:lifecycle'.red); +} + +export const fakeOra = (name: string) => { + let _name = name; + const fake: OraImpl = { + start: () => { + d('Process Started:', fake.text); + return fake; + }, + fail: () => { + d(`Process Failed: ${fake.text}`.red); + return fake; + }, + succeed: () => { + d('Process Succeeded:', fake.text); + return fake; + }, + stop: () => { + d('Process Stopped:', fake.text); + return fake; + }, + warn: (warning: string) => { + d('Process Warned:', warning); + return fake; + }, + get text() { + return _name; + }, + set text(newName: string) { + d('Process Renamed:', _name, ' --> ', newName); + _name = newName; + }, + }; + return fake; +}; + +export default useFakeOra ? fakeOra : realOra; diff --git a/packages/utils/async-ora/test/ora-handler_spec.js b/packages/utils/async-ora/test/ora-handler_spec.ts similarity index 80% rename from packages/utils/async-ora/test/ora-handler_spec.js rename to packages/utils/async-ora/test/ora-handler_spec.ts index 67d13f452d..6b70b65280 100644 --- a/packages/utils/async-ora/test/ora-handler_spec.js +++ b/packages/utils/async-ora/test/ora-handler_spec.ts @@ -2,15 +2,18 @@ import { expect } from 'chai'; import proxyquire from 'proxyquire'; import sinon from 'sinon'; +import { asyncOra as ora, OraImpl } from '../src/index'; + describe('asyncOra', () => { - let asyncOra; - let MockOra; - let currentOra; + let asyncOra: typeof ora; + let MockOra: (text: string) => OraImpl | undefined; + let currentOra: OraImpl | undefined; beforeEach(() => { currentOra = undefined; MockOra = (text) => { currentOra = { + failed: false, start() { this.started = true; return currentOra; @@ -23,16 +26,20 @@ describe('asyncOra', () => { this.failed = true; return currentOra; }, + stop() { + this.failed = true; + return currentOra; + }, get text() { - return currentOra._text; + return (currentOra! as any)._text; }, set text(newText) { - currentOra._text = newText; + (currentOra! as any)._text = newText; }, - }; - currentOra.succeeded = false; - currentOra.failed = false; - currentOra._text = text; + } as any; + (currentOra as any).succeeded = false; + (currentOra as any).failed = false; + (currentOra as any)._text = text; return currentOra; }; asyncOra = proxyquire.noCallThru().load('../src/ora-handler', { @@ -43,7 +50,7 @@ describe('asyncOra', () => { it('should create an ora with an initial value', () => { asyncOra('say this first', async () => {}); expect(currentOra).to.not.equal(undefined); - expect(currentOra.text).to.equal('say this first'); + expect(currentOra!.text).to.equal('say this first'); }); it('should not create an ora when in non-interactive mode', () => { @@ -64,16 +71,16 @@ describe('asyncOra', () => { await asyncOra('random text', async () => { if (2 + 2 === 5) console.error('Big brother is at it again'); // eslint-disable-line }); - expect(currentOra.succeeded).to.equal(true); - expect(currentOra.failed).to.equal(false); + expect((currentOra as any).succeeded).to.equal(true); + expect((currentOra as any).failed).to.equal(false); }); it('should fail the ora if the async fn throws', async () => { await asyncOra('this is gonna end badly', async () => { throw { message: 'Not an error', stack: 'No Stack - Not an error' }; // eslint-disable-line }, () => {}); - expect(currentOra.succeeded).to.equal(false); - expect(currentOra.failed).to.equal(true); + expect((currentOra as any).succeeded).to.equal(false); + expect((currentOra as any).failed).to.equal(true); }); it('should exit the process with status 1 if the async fn throws', async () => { diff --git a/packages/utils/types/index.d.ts b/packages/utils/types/index.d.ts new file mode 100644 index 0000000000..48f367b358 --- /dev/null +++ b/packages/utils/types/index.d.ts @@ -0,0 +1,87 @@ +import { ChildProcess } from "child_process"; +import { Options } from "electron-packager"; +import { RebuildOptions } from "electron-rebuild/lib/src/rebuild"; + +declare module '@electron-forge/shared-types' { + export type ForgePlatform = 'darwin' | 'mas' | 'win32' | 'linux'; + export type ForgeArch = 'ia32' | 'x64' | 'armv7l' | 'arm'; + export type ForgeHookFn = (forgeConfig: ForgeConfig, ...args: any[]) => Promise; + export interface IForgePluginInterface { + triggerHook(hookName: string, hookArgs: any[]): Promise; + overrideStartLogic(opts: any): Promise; + } + export interface ForgeConfig { + /** + * A string to uniquely identify artifacts of this build, will be appended + * to the out dir to generate a nested directory. E.g. out/current-timestamp + * + * If a function is provided it must syncronously return the buildIdentifier + */ + buildIdentifier?: string | (() => string); + hooks?: { + [hookName: string]: ForgeHookFn; + }; + /** + * @generated + */ + pluginInterface: IForgePluginInterface; + /** + * An array of forge plugins or a tuple consisting of [pluginName, pluginOptions] + */ + plugins: (IForgePlugin | [string, any])[]; + electronRebuildConfig: RebuildOptions; + packagerConfig: Options; + makers: (IForgeResolvableMaker | IForgeMaker)[]; + publishers: (IForgeResolvablePublisher | IForgePublisher | string)[]; + } + export interface ForgeMakeResult { + /** + * An array of paths to artifacts generated for this make run + */ + artifacts: Array; + /** + * The state of the package.json file when the make happened + */ + packageJSON: any; + /** + * The platform this make run was for + */ + platform: ForgePlatform; + /** + * The arch this make run was for + */ + arch: ForgeArch; + } + + export interface IForgePlugin { + __isElectronForgePlugin: boolean; + name: string; + + init(dir: string, forgeConfig: ForgeConfig): void; + getHook?(hookName: string): ForgeHookFn | null; + // FIXME: MarshallOfSound - Having any here is depressing + startLogic?(opts: any): Promise; + } + + export interface IForgeResolvableMaker { + name: string; + platforms: ForgePlatform[] | null; + config: any; + } + + export interface IForgeMaker { + __isElectronForgeMaker: boolean; + platforms?: undefined; + } + + export interface IForgeResolvablePublisher { + name: string; + platforms?: ForgePlatform[] | null; + config?: any; + } + + export interface IForgePublisher { + __isElectronForgePublisher: boolean; + platforms?: undefined; + } +} diff --git a/packages/utils/types/package.json b/packages/utils/types/package.json new file mode 100644 index 0000000000..9503f1dd72 --- /dev/null +++ b/packages/utils/types/package.json @@ -0,0 +1,21 @@ +{ + "name": "@electron-forge/shared-types", + "version": "6.0.0-beta.3", + "description": "Shared types across forge", + "repository": "https://github.com/electron-userland/electron-forge", + "author": "Samuel Attard", + "license": "MIT", + "main": "dist/index.js", + "typings": "index.d.ts", + "scripts": { + "test": "echo No Tests For Shared Types" + }, + "dependencies": { + "@types/electron-packager": "^10.1.0", + "electron-rebuild": "^1.6.0", + "ora": "^2.0.0" + }, + "engines": { + "node": ">= 6.0" + } +} \ No newline at end of file diff --git a/packages/utils/types/src/index.ts b/packages/utils/types/src/index.ts new file mode 100644 index 0000000000..9fddf47b64 --- /dev/null +++ b/packages/utils/types/src/index.ts @@ -0,0 +1,3 @@ +export type Foo = 'bar'; + +throw new Error('Lol you can\'t do that...'); diff --git a/tools/link-ts.ts b/tools/link-ts.ts new file mode 100644 index 0000000000..82bbb1a685 --- /dev/null +++ b/tools/link-ts.ts @@ -0,0 +1,19 @@ +import * as fs from 'fs-extra'; +import * as path from 'path'; + +const BASE_DIR = path.resolve(__dirname, '..'); +const PACKAGES_DIR = path.resolve(BASE_DIR, 'packages'); + +(async () => { + const dirsToLink = []; + + for (const subDir of await fs.readdir(PACKAGES_DIR)) { + for (const packageDir of await fs.readdir(path.resolve(PACKAGES_DIR, subDir))) { + dirsToLink.push(path.resolve(PACKAGES_DIR, subDir, packageDir)); + } + } + + for (const dir of dirsToLink) { + await fs.copy(path.resolve(BASE_DIR, 'tsconfig.json'), path.resolve(dir, 'tsconfig.json')); + } +})(); diff --git a/tools/test-dist.ts b/tools/test-dist.ts new file mode 100644 index 0000000000..a5215537fe --- /dev/null +++ b/tools/test-dist.ts @@ -0,0 +1,34 @@ +import 'colors'; +import * as fs from 'fs-extra'; +import * as path from 'path'; + +const BASE_DIR = path.resolve(__dirname, '..'); +const PACKAGES_DIR = path.resolve(BASE_DIR, 'packages'); + +(async () => { + const dirsToCheck = []; + + for (const subDir of await fs.readdir(PACKAGES_DIR)) { + for (const packageDir of await fs.readdir(path.resolve(PACKAGES_DIR, subDir))) { + dirsToCheck.push(path.resolve(PACKAGES_DIR, subDir, packageDir)); + } + } + + let bad = false; + for (const dir of dirsToCheck) { + const pj = await fs.readJson(path.resolve(dir, 'package.json')); + if (pj.name === '@electron-forge/cli') continue; + if (!await fs.pathExists(path.resolve(dir, pj.main))) { + console.error(`${`[${pj.name}]`.cyan}:`, `Main entry not found (${pj.main})`.red); + bad = true; + } + if (!pj.typings || !await fs.pathExists(path.resolve(dir, pj.typings))) { + console.error(`${`[${pj.name}]`.cyan}:`, `Typings entry not found (${pj.typings})`.red); + bad = true; + } + } + + if (bad) { + process.exit(1); + } +})().catch(console.error); diff --git a/tools/test-setup.js b/tools/test-setup.js new file mode 100644 index 0000000000..03f5e17097 --- /dev/null +++ b/tools/test-setup.js @@ -0,0 +1,4 @@ +const chai = require('chai'); +const chaiAsPromised = require('chai-as-promised'); + +chai.use(chaiAsPromised); diff --git a/tsconfig.json b/tsconfig.json new file mode 100755 index 0000000000..a3cbfefba0 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "outDir": "dist", + "lib": [ + "es6", + "dom", + "es7" + ], + "sourceMap": true, + "rootDir": "src", + "experimentalDecorators": true, + "strict": true, + "esModuleInterop": true, + "declaration": true + }, + "exclude": [ + "node_modules", + "dist", + "test" + ] +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 459b8e7b9c..049a8fefd7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,9 +2,9 @@ # yarn lockfile v1 -"@babel/cli@^7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.0.0-beta.40.tgz#6f96760267685a4c2f053b40316e95fe8c924a6e" +"@babel/cli@^7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/cli/-/cli-7.0.0-beta.44.tgz#635a7f04277ab71a9b5be625667aaf1e33a31a09" dependencies: commander "^2.8.1" convert-source-map "^1.1.0" @@ -17,422 +17,507 @@ optionalDependencies: chokidar "^1.6.1" -"@babel/code-frame@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.40.tgz#37e2b0cf7c56026b4b21d3927cadf81adec32ac6" +"@babel/code-frame@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.44.tgz#2a02643368de80916162be70865c97774f3adbd9" dependencies: - "@babel/highlight" "7.0.0-beta.40" + "@babel/highlight" "7.0.0-beta.44" -"@babel/core@^7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.0.0-beta.40.tgz#455464dd81d499fd97d32b473f0331f74379a33f" +"@babel/core@^7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.0.0-beta.44.tgz#90bb9e897427e7ebec2a1b857f458ff74ca28057" dependencies: - "@babel/code-frame" "7.0.0-beta.40" - "@babel/generator" "7.0.0-beta.40" - "@babel/helpers" "7.0.0-beta.40" - "@babel/template" "7.0.0-beta.40" - "@babel/traverse" "7.0.0-beta.40" - "@babel/types" "7.0.0-beta.40" - babylon "7.0.0-beta.40" + "@babel/code-frame" "7.0.0-beta.44" + "@babel/generator" "7.0.0-beta.44" + "@babel/helpers" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" convert-source-map "^1.1.0" - debug "^3.0.1" + debug "^3.1.0" json5 "^0.5.0" lodash "^4.2.0" micromatch "^2.3.11" resolve "^1.3.2" + semver "^5.4.1" source-map "^0.5.0" -"@babel/generator@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.40.tgz#ab61f9556f4f71dbd1138949c795bb9a21e302ea" +"@babel/generator@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.44.tgz#c7e67b9b5284afcf69b309b50d7d37f3e5033d42" dependencies: - "@babel/types" "7.0.0-beta.40" + "@babel/types" "7.0.0-beta.44" jsesc "^2.5.1" lodash "^4.2.0" source-map "^0.5.0" trim-right "^1.0.1" -"@babel/helper-annotate-as-pure@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0-beta.40.tgz#095dd4c70b231eba17ebf61c3434e6f9d71bd574" +"@babel/helper-annotate-as-pure@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0-beta.44.tgz#8ecf33cc5235295afcc7f160a63cab17ce7776f4" dependencies: - "@babel/types" "7.0.0-beta.40" + "@babel/types" "7.0.0-beta.44" -"@babel/helper-builder-binary-assignment-operator-visitor@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.0.0-beta.40.tgz#bec4240c95d8b646812c5d4ac536a5579dbcdd53" +"@babel/helper-builder-binary-assignment-operator-visitor@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.0.0-beta.44.tgz#0e86d393c192bc846f871f3fcf4920b08a9cbb27" dependencies: - "@babel/helper-explode-assignable-expression" "7.0.0-beta.40" - "@babel/types" "7.0.0-beta.40" + "@babel/helper-explode-assignable-expression" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" -"@babel/helper-call-delegate@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.0.0-beta.40.tgz#5d5000d0bf76c68ee6866961e0b7eb6e9ed52438" +"@babel/helper-call-delegate@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.0.0-beta.44.tgz#e644536f8b3d2eabeecca000037cdced8e453d26" dependencies: - "@babel/helper-hoist-variables" "7.0.0-beta.40" - "@babel/traverse" "7.0.0-beta.40" - "@babel/types" "7.0.0-beta.40" + "@babel/helper-hoist-variables" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" -"@babel/helper-define-map@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.0.0-beta.40.tgz#ad64c548dd98e7746305852f113ed04dc74329c0" +"@babel/helper-define-map@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.0.0-beta.44.tgz#d63578a67c9654ff9f32e55bbf269c2d5f094c97" dependencies: - "@babel/helper-function-name" "7.0.0-beta.40" - "@babel/types" "7.0.0-beta.40" + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" lodash "^4.2.0" -"@babel/helper-explode-assignable-expression@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.0.0-beta.40.tgz#0ef579288d894a987c60bf0577c074ad18cfa9dd" +"@babel/helper-explode-assignable-expression@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.0.0-beta.44.tgz#1f06b9f76017deac2767ee09f3021d5b209bf5cd" dependencies: - "@babel/traverse" "7.0.0-beta.40" - "@babel/types" "7.0.0-beta.40" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" -"@babel/helper-function-name@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.40.tgz#9d033341ab16517f40d43a73f2d81fc431ccd7b6" +"@babel/helper-function-name@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.44.tgz#e18552aaae2231100a6e485e03854bc3532d44dd" dependencies: - "@babel/helper-get-function-arity" "7.0.0-beta.40" - "@babel/template" "7.0.0-beta.40" - "@babel/types" "7.0.0-beta.40" + "@babel/helper-get-function-arity" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" -"@babel/helper-get-function-arity@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.40.tgz#ac0419cf067b0ec16453e1274f03878195791c6e" +"@babel/helper-get-function-arity@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.44.tgz#d03ca6dd2b9f7b0b1e6b32c56c72836140db3a15" dependencies: - "@babel/types" "7.0.0-beta.40" + "@babel/types" "7.0.0-beta.44" -"@babel/helper-hoist-variables@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0-beta.40.tgz#59d47fd133782d60db89af0d18083ad3c9f4801c" +"@babel/helper-hoist-variables@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.0.0-beta.44.tgz#a1bbb2c25f9b4058e041ecc1556f096eacdbd142" dependencies: - "@babel/types" "7.0.0-beta.40" + "@babel/types" "7.0.0-beta.44" -"@babel/helper-module-imports@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.40.tgz#251cbb6404599282e8f7356a5b32c9381bef5d2d" +"@babel/helper-module-imports@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.44.tgz#60edc68cdf17e13eaca5be813c96127303085133" dependencies: - "@babel/types" "7.0.0-beta.40" + "@babel/types" "7.0.0-beta.44" lodash "^4.2.0" -"@babel/helper-module-transforms@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.0.0-beta.40.tgz#e5240afd47bd98f6ae65874b9ae508533abfee76" +"@babel/helper-module-transforms@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.0.0-beta.44.tgz#185dc17b37c4b9cc3daee0f0f44e74f000e21bb7" dependencies: - "@babel/helper-module-imports" "7.0.0-beta.40" - "@babel/helper-simple-access" "7.0.0-beta.40" - "@babel/template" "7.0.0-beta.40" - "@babel/types" "7.0.0-beta.40" + "@babel/helper-module-imports" "7.0.0-beta.44" + "@babel/helper-simple-access" "7.0.0-beta.44" + "@babel/helper-split-export-declaration" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" lodash "^4.2.0" -"@babel/helper-optimise-call-expression@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0-beta.40.tgz#f0e7f70d455bff8ab6a248a84f0221098fa468ac" +"@babel/helper-optimise-call-expression@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0-beta.44.tgz#84ceabfb99afc1c185d15668114a697cdad7a5d0" dependencies: - "@babel/types" "7.0.0-beta.40" + "@babel/types" "7.0.0-beta.44" -"@babel/helper-regex@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.0.0-beta.40.tgz#b47018ecca8ff66bb390c34a95ff71bc01495833" +"@babel/helper-plugin-utils@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0-beta.44.tgz#9f590bc3ae6daa8a10b853233baa3e25d263751d" + +"@babel/helper-regex@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.0.0-beta.44.tgz#f5b6828c1e40f0b74ab6ed90abdd52be0c38a74e" dependencies: lodash "^4.2.0" -"@babel/helper-remap-async-to-generator@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.0.0-beta.40.tgz#33414d1cc160ebf0991ebc60afebe36b08feae05" +"@babel/helper-remap-async-to-generator@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.0.0-beta.44.tgz#8ad8c12a57444042ca281bdb16734841425938ad" dependencies: - "@babel/helper-annotate-as-pure" "7.0.0-beta.40" - "@babel/helper-wrap-function" "7.0.0-beta.40" - "@babel/template" "7.0.0-beta.40" - "@babel/traverse" "7.0.0-beta.40" - "@babel/types" "7.0.0-beta.40" + "@babel/helper-annotate-as-pure" "7.0.0-beta.44" + "@babel/helper-wrap-function" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" -"@babel/helper-replace-supers@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.0.0-beta.40.tgz#2ab0c9e7fa17d313745f1634ce6b7bccaa5dd5fe" +"@babel/helper-replace-supers@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.0.0-beta.44.tgz#cf18697951431f533f9d8c201390b158d4a3ee04" dependencies: - "@babel/helper-optimise-call-expression" "7.0.0-beta.40" - "@babel/template" "7.0.0-beta.40" - "@babel/traverse" "7.0.0-beta.40" - "@babel/types" "7.0.0-beta.40" + "@babel/helper-optimise-call-expression" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" -"@babel/helper-simple-access@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.0.0-beta.40.tgz#018f765090a3d25153778958969f235dc6ce5b57" +"@babel/helper-simple-access@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.0.0-beta.44.tgz#03fb6bfc91eb0a95f6c11499153f8c663654dce5" dependencies: - "@babel/template" "7.0.0-beta.40" - "@babel/types" "7.0.0-beta.40" + "@babel/template" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" lodash "^4.2.0" -"@babel/helper-wrap-function@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.0.0-beta.40.tgz#4db4630cdaf4fd47fa2c45b5b7a9ecc33ff3f2be" +"@babel/helper-split-export-declaration@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc" + dependencies: + "@babel/types" "7.0.0-beta.44" + +"@babel/helper-wrap-function@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.0.0-beta.44.tgz#d128718a543f313264dff7cb386957e3e465c95d" dependencies: - "@babel/helper-function-name" "7.0.0-beta.40" - "@babel/template" "7.0.0-beta.40" - "@babel/traverse" "7.0.0-beta.40" - "@babel/types" "7.0.0-beta.40" + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/template" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" -"@babel/helpers@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.0.0-beta.40.tgz#82f8e144f56b2896b1d624ca88ac4603023ececd" +"@babel/helpers@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.0.0-beta.44.tgz#b1cc87fdc3b77351c0a4860bcd9d4ef457919bfd" dependencies: - "@babel/template" "7.0.0-beta.40" - "@babel/traverse" "7.0.0-beta.40" - "@babel/types" "7.0.0-beta.40" + "@babel/template" "7.0.0-beta.44" + "@babel/traverse" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" -"@babel/highlight@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.40.tgz#b43d67d76bf46e1d10d227f68cddcd263786b255" +"@babel/highlight@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.44.tgz#18c94ce543916a80553edcdcf681890b200747d5" dependencies: chalk "^2.0.0" esutils "^2.0.2" js-tokens "^3.0.0" -"@babel/plugin-proposal-async-generator-functions@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.0.0-beta.40.tgz#64f4aebc3fff33d2ae8f0a0870f0dfe2ff6815d6" +"@babel/plugin-proposal-async-generator-functions@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.0.0-beta.44.tgz#b08d90cd0f6a82e11cb5ae64eee4fba7d0d7999e" dependencies: - "@babel/helper-remap-async-to-generator" "7.0.0-beta.40" - "@babel/plugin-syntax-async-generators" "7.0.0-beta.40" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/helper-remap-async-to-generator" "7.0.0-beta.44" + "@babel/plugin-syntax-async-generators" "7.0.0-beta.44" -"@babel/plugin-proposal-class-properties@^7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.0.0-beta.40.tgz#ee0549729e9f44603efa17523b459ea3021458dc" +"@babel/plugin-proposal-class-properties@^7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.0.0-beta.44.tgz#aff9192a883b41fdf1c73026b9105c92e931c55e" dependencies: - "@babel/helper-function-name" "7.0.0-beta.40" - "@babel/plugin-syntax-class-properties" "7.0.0-beta.40" + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/plugin-syntax-class-properties" "7.0.0-beta.44" -"@babel/plugin-proposal-object-rest-spread@7.0.0-beta.40", "@babel/plugin-proposal-object-rest-spread@^7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0-beta.40.tgz#ce35d2240908e52706a612eb26d67db667cd700f" +"@babel/plugin-proposal-object-rest-spread@7.0.0-beta.44", "@babel/plugin-proposal-object-rest-spread@^7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.0.0-beta.44.tgz#b7817770cb9cf72f2e73ca6fcb83d61a87305259" dependencies: - "@babel/plugin-syntax-object-rest-spread" "7.0.0-beta.40" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/plugin-syntax-object-rest-spread" "7.0.0-beta.44" -"@babel/plugin-proposal-optional-catch-binding@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.0.0-beta.40.tgz#e76ddcb21880eea0225f1dcde20a5e97ca85fd39" +"@babel/plugin-proposal-optional-catch-binding@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.0.0-beta.44.tgz#87928d30c9fab4803cdba29f9c1260c16bc5d30f" dependencies: - "@babel/plugin-syntax-optional-catch-binding" "7.0.0-beta.40" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/plugin-syntax-optional-catch-binding" "7.0.0-beta.44" -"@babel/plugin-proposal-unicode-property-regex@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.0.0-beta.40.tgz#1fb2c29c8bd88d5fff82ec080dbe24e7126ec460" +"@babel/plugin-proposal-unicode-property-regex@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.0.0-beta.44.tgz#5efb0ddbe6635b4cb6674e961a16c28cef3cdb7f" dependencies: - "@babel/helper-regex" "7.0.0-beta.40" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/helper-regex" "7.0.0-beta.44" regexpu-core "^4.1.3" -"@babel/plugin-syntax-async-generators@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.0.0-beta.40.tgz#6c45889569add3b3721cc9a481ae99906f240874" +"@babel/plugin-syntax-async-generators@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.0.0-beta.44.tgz#5cf7ec4256ddd7df62654171059188bee2b3addc" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-syntax-class-properties@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.0.0-beta.40.tgz#ff82c04c6d97cdb947dc64e3f3d4bc791e85a16f" +"@babel/plugin-syntax-class-properties@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.0.0-beta.44.tgz#1e4e67ef6d7101a3a7d2ae5f60e580cbf4b7750f" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-syntax-object-rest-spread@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0-beta.40.tgz#d5e04536062e4df685c203ae48bb19bfe2cf235c" +"@babel/plugin-syntax-object-rest-spread@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.0.0-beta.44.tgz#c37d271e4edf8a1b5d4623fb2917ba0f5a9da3b3" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-syntax-optional-catch-binding@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.0.0-beta.40.tgz#2e3de0919d05136bb658172ef9ba9ef7e84bce9e" +"@babel/plugin-syntax-optional-catch-binding@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.0.0-beta.44.tgz#c79ee93c371831b104bb0a1cc9c85ac5373af4f3" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-arrow-functions@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0-beta.40.tgz#0842045b16835d6da0c334d0b09d575852f27962" +"@babel/plugin-syntax-typescript@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.0.0-beta.44.tgz#a2f1c4963be673ad8de792ba2a940a5e0c0e598b" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-async-to-generator@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.0.0-beta.40.tgz#9195e2473a435b9a9aabc0b64572e9d1ec1c57cb" +"@babel/plugin-transform-arrow-functions@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.0.0-beta.44.tgz#718dae35046eca6938c731d1eae10c5471c17398" dependencies: - "@babel/helper-module-imports" "7.0.0-beta.40" - "@babel/helper-remap-async-to-generator" "7.0.0-beta.40" + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-block-scoped-functions@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.0.0-beta.40.tgz#491e61f860cabe69379233983fe7ca14f879e41f" +"@babel/plugin-transform-async-to-generator@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.0.0-beta.44.tgz#b91881aa6e1a6bd330be31df43a936feeb145c29" + dependencies: + "@babel/helper-module-imports" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/helper-remap-async-to-generator" "7.0.0-beta.44" -"@babel/plugin-transform-block-scoping@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.0.0-beta.40.tgz#23197ee6f696b7e5ace884f0dc5434df20d7dd97" +"@babel/plugin-transform-block-scoped-functions@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.0.0-beta.44.tgz#d31bb2231ae861fa4ea6f9974b8b8f5641a3460a" dependencies: - lodash "^4.2.0" + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-classes@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.0.0-beta.40.tgz#c7a752009df4bb0f77179027daa0783f9a036b0b" +"@babel/plugin-transform-block-scoping@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.0.0-beta.44.tgz#a7b640e112743634b9226996e58ab92cdebb4ff0" dependencies: - "@babel/helper-annotate-as-pure" "7.0.0-beta.40" - "@babel/helper-define-map" "7.0.0-beta.40" - "@babel/helper-function-name" "7.0.0-beta.40" - "@babel/helper-optimise-call-expression" "7.0.0-beta.40" - "@babel/helper-replace-supers" "7.0.0-beta.40" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + lodash "^4.2.0" + +"@babel/plugin-transform-classes@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.0.0-beta.44.tgz#5410fcf6a9eeba3cc8e25bf0f72b43358336b534" + dependencies: + "@babel/helper-annotate-as-pure" "7.0.0-beta.44" + "@babel/helper-define-map" "7.0.0-beta.44" + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/helper-optimise-call-expression" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/helper-replace-supers" "7.0.0-beta.44" + "@babel/helper-split-export-declaration" "7.0.0-beta.44" globals "^11.1.0" -"@babel/plugin-transform-computed-properties@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.0.0-beta.40.tgz#e4bd53455d9f96882cc8e9923895d71690f6969e" +"@babel/plugin-transform-computed-properties@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.0.0-beta.44.tgz#1421b4e1a18dc3bd276d8648a12a4f8ea088c6a1" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-destructuring@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.0.0-beta.40.tgz#503a4719eb9ed8c933b50d4ec3f106ed371852ee" +"@babel/plugin-transform-destructuring@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.0.0-beta.44.tgz#57c8b40d56db45eaa39b44696818b24004306752" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-dotall-regex@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.0.0-beta.40.tgz#89b5ccff477624b97129f9a7e262a436437d7ae2" +"@babel/plugin-transform-dotall-regex@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.0.0-beta.44.tgz#414bd71f39199e45a8ddaa8053cb5bd9690707f4" dependencies: - "@babel/helper-regex" "7.0.0-beta.40" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/helper-regex" "7.0.0-beta.44" regexpu-core "^4.1.3" -"@babel/plugin-transform-duplicate-keys@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.0.0-beta.40.tgz#91599be229d4409cf3c9bbd094fb04d354bd8068" +"@babel/plugin-transform-duplicate-keys@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.0.0-beta.44.tgz#e945a7990d9adca4f9b58a7af46cdb1515b925b1" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-exponentiation-operator@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.0.0-beta.40.tgz#bf0bafdd5aad7061c25dba25e29e12329838baeb" +"@babel/plugin-transform-exponentiation-operator@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.0.0-beta.44.tgz#e6a9699b5036a7a75274e1546c23414ba945a135" dependencies: - "@babel/helper-builder-binary-assignment-operator-visitor" "7.0.0-beta.40" + "@babel/helper-builder-binary-assignment-operator-visitor" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-for-of@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.0.0-beta.40.tgz#67920d749bac4840ceeae9907d918dad33908244" +"@babel/plugin-transform-for-of@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.0.0-beta.44.tgz#b157e38e74c07beacbac01c1946b8ad11dbea32c" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-function-name@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.0.0-beta.40.tgz#37b5ca4f90fba207d359c0be3af5bfecdc737a3d" +"@babel/plugin-transform-function-name@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.0.0-beta.44.tgz#8cd5986dac8a0fd0df21b79e9a20de9b2c37b4c4" dependencies: - "@babel/helper-function-name" "7.0.0-beta.40" + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-literals@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.0.0-beta.40.tgz#a6bf8808f97accf42a171b27a133802aa0650d3e" +"@babel/plugin-transform-literals@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.0.0-beta.44.tgz#8c85631ea6fd8a6eecefdb81177ed6ae3d34b195" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-modules-amd@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.0.0-beta.40.tgz#1882f1a02b16d261a332c87c035c9aeefd402683" +"@babel/plugin-transform-modules-amd@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.0.0-beta.44.tgz#4d2df3f507f00bbbea3bc3ee07505ed97df1f22e" dependencies: - "@babel/helper-module-transforms" "7.0.0-beta.40" + "@babel/helper-module-transforms" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-modules-commonjs@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.0.0-beta.40.tgz#a85f8c311f498a94a45531cc4ed5ff98b338a70a" +"@babel/plugin-transform-modules-commonjs@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.0.0-beta.44.tgz#864a1fef64091bd5241b0aa7d4b235fb29f60580" dependencies: - "@babel/helper-module-transforms" "7.0.0-beta.40" - "@babel/helper-simple-access" "7.0.0-beta.40" + "@babel/helper-module-transforms" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/helper-simple-access" "7.0.0-beta.44" -"@babel/plugin-transform-modules-systemjs@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.0.0-beta.40.tgz#808b372bdbe06a28bf7a3870d8e810bd7298227a" +"@babel/plugin-transform-modules-systemjs@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.0.0-beta.44.tgz#f27e97e592dd9739c8c5df478f1729bb4b63b386" dependencies: - "@babel/helper-hoist-variables" "7.0.0-beta.40" + "@babel/helper-hoist-variables" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-modules-umd@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.0.0-beta.40.tgz#5bd4e395a2673e687ed592608ad2fd4883a5a119" +"@babel/plugin-transform-modules-umd@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.0.0-beta.44.tgz#66ca82476b72bfd1ce2d410ceaf2e85c1639a616" dependencies: - "@babel/helper-module-transforms" "7.0.0-beta.40" + "@babel/helper-module-transforms" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-new-target@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0-beta.40.tgz#ee52bb87fbf325ac054811ec739b25fbce97809e" +"@babel/plugin-transform-new-target@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.0.0-beta.44.tgz#7f3a2c46e01b5433093430892fbce287583cb1b8" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-object-super@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.0.0-beta.40.tgz#c64f9ba3587610d76c2edfdd8f507a59ea3ba63d" +"@babel/plugin-transform-object-super@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.0.0-beta.44.tgz#3c1688a7b38c4de8af269ff5c618cfd602864a39" dependencies: - "@babel/helper-replace-supers" "7.0.0-beta.40" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/helper-replace-supers" "7.0.0-beta.44" -"@babel/plugin-transform-parameters@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.0.0-beta.40.tgz#efa366fab0dcbd0221b46aa2662c324b4b414d1d" +"@babel/plugin-transform-parameters@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.0.0-beta.44.tgz#19eaf0b852d58168097435e33e754a00c3507fb9" dependencies: - "@babel/helper-call-delegate" "7.0.0-beta.40" - "@babel/helper-get-function-arity" "7.0.0-beta.40" + "@babel/helper-call-delegate" "7.0.0-beta.44" + "@babel/helper-get-function-arity" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-regenerator@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0-beta.40.tgz#f8a89ce89a0fae8e9cdfc2f2768104811517374a" +"@babel/plugin-transform-regenerator@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.0.0-beta.44.tgz#e9a21db8fbedfd99b9e5d04ac405f7440d36b290" dependencies: regenerator-transform "^0.12.3" -"@babel/plugin-transform-shorthand-properties@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0-beta.40.tgz#421835237b0fcab0e67c941726d95dfc543514f4" +"@babel/plugin-transform-shorthand-properties@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.0.0-beta.44.tgz#42e2a31aaa5edf479adaf4c2b677cd3457c99991" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-spread@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.0.0-beta.40.tgz#881578938e5750137301750bef7fdd0e01be76be" +"@babel/plugin-transform-spread@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.0.0-beta.44.tgz#94cacc3317cb8e2227b543c25b8046d7635d4114" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-sticky-regex@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.0.0-beta.40.tgz#5b44b31f8539fc66af18962e55752b82298032ee" +"@babel/plugin-transform-sticky-regex@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.0.0-beta.44.tgz#512597cd7535f313aa29f31d0b60572a0374db00" dependencies: - "@babel/helper-regex" "7.0.0-beta.40" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/helper-regex" "7.0.0-beta.44" -"@babel/plugin-transform-template-literals@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.0.0-beta.40.tgz#5ef3377d1294aee39b913768a1f884806a45393b" +"@babel/plugin-transform-template-literals@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.0.0-beta.44.tgz#88d4605e63a21a4354837af06371e8c51cd76d08" dependencies: - "@babel/helper-annotate-as-pure" "7.0.0-beta.40" + "@babel/helper-annotate-as-pure" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-typeof-symbol@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.0.0-beta.40.tgz#67f0b8a5dd298b0aa5b347c3b6738c9c7baf1bcf" +"@babel/plugin-transform-typeof-symbol@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.0.0-beta.44.tgz#ba0ded29aea2a51700e0730a054faa64a22ff38a" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" -"@babel/plugin-transform-unicode-regex@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.0.0-beta.40.tgz#a956187aad2965d7c095d64b1ae87eba10e0a2c6" +"@babel/plugin-transform-typescript@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.0.0-beta.44.tgz#85f326ccef4a903581098b2cdcd0fddf78c7dd47" dependencies: - "@babel/helper-regex" "7.0.0-beta.40" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/plugin-syntax-typescript" "7.0.0-beta.44" + +"@babel/plugin-transform-unicode-regex@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.0.0-beta.44.tgz#d7cf607948da5e997e277eba1caed30e80beaf76" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/helper-regex" "7.0.0-beta.44" regexpu-core "^4.1.3" -"@babel/preset-env@^7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.0.0-beta.40.tgz#713292f9e410f76b3f4301330756c89343c4b2e4" - dependencies: - "@babel/plugin-proposal-async-generator-functions" "7.0.0-beta.40" - "@babel/plugin-proposal-object-rest-spread" "7.0.0-beta.40" - "@babel/plugin-proposal-optional-catch-binding" "7.0.0-beta.40" - "@babel/plugin-proposal-unicode-property-regex" "7.0.0-beta.40" - "@babel/plugin-syntax-async-generators" "7.0.0-beta.40" - "@babel/plugin-syntax-object-rest-spread" "7.0.0-beta.40" - "@babel/plugin-syntax-optional-catch-binding" "7.0.0-beta.40" - "@babel/plugin-transform-arrow-functions" "7.0.0-beta.40" - "@babel/plugin-transform-async-to-generator" "7.0.0-beta.40" - "@babel/plugin-transform-block-scoped-functions" "7.0.0-beta.40" - "@babel/plugin-transform-block-scoping" "7.0.0-beta.40" - "@babel/plugin-transform-classes" "7.0.0-beta.40" - "@babel/plugin-transform-computed-properties" "7.0.0-beta.40" - "@babel/plugin-transform-destructuring" "7.0.0-beta.40" - "@babel/plugin-transform-dotall-regex" "7.0.0-beta.40" - "@babel/plugin-transform-duplicate-keys" "7.0.0-beta.40" - "@babel/plugin-transform-exponentiation-operator" "7.0.0-beta.40" - "@babel/plugin-transform-for-of" "7.0.0-beta.40" - "@babel/plugin-transform-function-name" "7.0.0-beta.40" - "@babel/plugin-transform-literals" "7.0.0-beta.40" - "@babel/plugin-transform-modules-amd" "7.0.0-beta.40" - "@babel/plugin-transform-modules-commonjs" "7.0.0-beta.40" - "@babel/plugin-transform-modules-systemjs" "7.0.0-beta.40" - "@babel/plugin-transform-modules-umd" "7.0.0-beta.40" - "@babel/plugin-transform-new-target" "7.0.0-beta.40" - "@babel/plugin-transform-object-super" "7.0.0-beta.40" - "@babel/plugin-transform-parameters" "7.0.0-beta.40" - "@babel/plugin-transform-regenerator" "7.0.0-beta.40" - "@babel/plugin-transform-shorthand-properties" "7.0.0-beta.40" - "@babel/plugin-transform-spread" "7.0.0-beta.40" - "@babel/plugin-transform-sticky-regex" "7.0.0-beta.40" - "@babel/plugin-transform-template-literals" "7.0.0-beta.40" - "@babel/plugin-transform-typeof-symbol" "7.0.0-beta.40" - "@babel/plugin-transform-unicode-regex" "7.0.0-beta.40" +"@babel/preset-env@^7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.0.0-beta.44.tgz#9d3df27d81b134cae8a52a36279402aadad6d5d2" + dependencies: + "@babel/helper-module-imports" "7.0.0-beta.44" + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/plugin-proposal-async-generator-functions" "7.0.0-beta.44" + "@babel/plugin-proposal-object-rest-spread" "7.0.0-beta.44" + "@babel/plugin-proposal-optional-catch-binding" "7.0.0-beta.44" + "@babel/plugin-proposal-unicode-property-regex" "7.0.0-beta.44" + "@babel/plugin-syntax-async-generators" "7.0.0-beta.44" + "@babel/plugin-syntax-object-rest-spread" "7.0.0-beta.44" + "@babel/plugin-syntax-optional-catch-binding" "7.0.0-beta.44" + "@babel/plugin-transform-arrow-functions" "7.0.0-beta.44" + "@babel/plugin-transform-async-to-generator" "7.0.0-beta.44" + "@babel/plugin-transform-block-scoped-functions" "7.0.0-beta.44" + "@babel/plugin-transform-block-scoping" "7.0.0-beta.44" + "@babel/plugin-transform-classes" "7.0.0-beta.44" + "@babel/plugin-transform-computed-properties" "7.0.0-beta.44" + "@babel/plugin-transform-destructuring" "7.0.0-beta.44" + "@babel/plugin-transform-dotall-regex" "7.0.0-beta.44" + "@babel/plugin-transform-duplicate-keys" "7.0.0-beta.44" + "@babel/plugin-transform-exponentiation-operator" "7.0.0-beta.44" + "@babel/plugin-transform-for-of" "7.0.0-beta.44" + "@babel/plugin-transform-function-name" "7.0.0-beta.44" + "@babel/plugin-transform-literals" "7.0.0-beta.44" + "@babel/plugin-transform-modules-amd" "7.0.0-beta.44" + "@babel/plugin-transform-modules-commonjs" "7.0.0-beta.44" + "@babel/plugin-transform-modules-systemjs" "7.0.0-beta.44" + "@babel/plugin-transform-modules-umd" "7.0.0-beta.44" + "@babel/plugin-transform-new-target" "7.0.0-beta.44" + "@babel/plugin-transform-object-super" "7.0.0-beta.44" + "@babel/plugin-transform-parameters" "7.0.0-beta.44" + "@babel/plugin-transform-regenerator" "7.0.0-beta.44" + "@babel/plugin-transform-shorthand-properties" "7.0.0-beta.44" + "@babel/plugin-transform-spread" "7.0.0-beta.44" + "@babel/plugin-transform-sticky-regex" "7.0.0-beta.44" + "@babel/plugin-transform-template-literals" "7.0.0-beta.44" + "@babel/plugin-transform-typeof-symbol" "7.0.0-beta.44" + "@babel/plugin-transform-unicode-regex" "7.0.0-beta.44" browserslist "^3.0.0" invariant "^2.2.2" semver "^5.3.0" -"@babel/register@^7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.0.0-beta.40.tgz#40df0bdbb2fe74a7c7b09af3d59b71c8cd53c4da" +"@babel/preset-typescript@^7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.0.0-beta.44.tgz#2b5890bba7b21df6af11c0fc23b1251bd48b2c63" + dependencies: + "@babel/helper-plugin-utils" "7.0.0-beta.44" + "@babel/plugin-transform-typescript" "7.0.0-beta.44" + +"@babel/register@^7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/register/-/register-7.0.0-beta.44.tgz#89cce279f1444aa560f10597073d0e448482d960" dependencies: core-js "^2.5.3" find-cache-dir "^1.0.0" @@ -442,32 +527,33 @@ pirates "^3.0.1" source-map-support "^0.4.2" -"@babel/template@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.40.tgz#034988c6424eb5c3268fe6a608626de1f4410fc8" +"@babel/template@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.44.tgz#f8832f4fdcee5d59bf515e595fc5106c529b394f" dependencies: - "@babel/code-frame" "7.0.0-beta.40" - "@babel/types" "7.0.0-beta.40" - babylon "7.0.0-beta.40" + "@babel/code-frame" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" lodash "^4.2.0" -"@babel/traverse@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.40.tgz#d140e449b2e093ef9fe1a2eecc28421ffb4e521e" +"@babel/traverse@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.44.tgz#a970a2c45477ad18017e2e465a0606feee0d2966" dependencies: - "@babel/code-frame" "7.0.0-beta.40" - "@babel/generator" "7.0.0-beta.40" - "@babel/helper-function-name" "7.0.0-beta.40" - "@babel/types" "7.0.0-beta.40" - babylon "7.0.0-beta.40" - debug "^3.0.1" + "@babel/code-frame" "7.0.0-beta.44" + "@babel/generator" "7.0.0-beta.44" + "@babel/helper-function-name" "7.0.0-beta.44" + "@babel/helper-split-export-declaration" "7.0.0-beta.44" + "@babel/types" "7.0.0-beta.44" + babylon "7.0.0-beta.44" + debug "^3.1.0" globals "^11.1.0" invariant "^2.2.0" lodash "^4.2.0" -"@babel/types@7.0.0-beta.40": - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.40.tgz#25c3d7aae14126abe05fcb098c65a66b6d6b8c14" +"@babel/types@7.0.0-beta.44": + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.44.tgz#6b1b164591f77dec0a0342aca995f2d046b3a757" dependencies: esutils "^2.0.2" lodash "^4.2.0" @@ -492,6 +578,237 @@ dependencies: samsam "1.3.0" +"@types/chai-as-promised@^7.1.0": + version "7.1.0" + resolved "https://registry.yarnpkg.com/@types/chai-as-promised/-/chai-as-promised-7.1.0.tgz#010b04cde78eacfb6e72bfddb3e58fe23c2e78b9" + dependencies: + "@types/chai" "*" + +"@types/chai@*", "@types/chai@^4.1.2": + version "4.1.2" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.2.tgz#f1af664769cfb50af805431c407425ed619daa21" + +"@types/cross-spawn@^6.0.0": + version "6.0.0" + resolved "https://registry.yarnpkg.com/@types/cross-spawn/-/cross-spawn-6.0.0.tgz#320aaf1d1a12979f1b84fe7a5590a7e860bf3a80" + dependencies: + "@types/node" "*" + +"@types/debug@^0.0.30": + version "0.0.30" + resolved "https://registry.yarnpkg.com/@types/debug/-/debug-0.0.30.tgz#dc1e40f7af3b9c815013a7860e6252f6352a84df" + +"@types/electron-packager@^10.1.0": + version "10.1.0" + resolved "https://registry.yarnpkg.com/@types/electron-packager/-/electron-packager-10.1.0.tgz#8d61ef76a2676936c59d14392a9c0c1853405953" + dependencies: + "@types/node" "*" + +"@types/electron-winstaller@^2.6.1": + version "2.6.1" + resolved "https://registry.yarnpkg.com/@types/electron-winstaller/-/electron-winstaller-2.6.1.tgz#7acd7956bfe1a9e89602a7bb130384dd55f15508" + +"@types/events@*": + version "1.2.0" + resolved "https://registry.yarnpkg.com/@types/events/-/events-1.2.0.tgz#81a6731ce4df43619e5c8c945383b3e62a89ea86" + +"@types/fetch-mock@^6.0.1": + version "6.0.1" + resolved "https://registry.yarnpkg.com/@types/fetch-mock/-/fetch-mock-6.0.1.tgz#df4e9f3a12fc81fae173f018ea17ad79441c10ba" + +"@types/form-data@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@types/form-data/-/form-data-2.2.1.tgz#ee2b3b8eaa11c0938289953606b745b738c54b1e" + dependencies: + "@types/node" "*" + +"@types/fs-extra@^5.0.2": + version "5.0.2" + resolved "https://registry.yarnpkg.com/@types/fs-extra/-/fs-extra-5.0.2.tgz#235a7e2b56452cc0a6a4809b53e1d1eaffff9c96" + dependencies: + "@types/node" "*" + +"@types/glob@^5.0.35": + version "5.0.35" + resolved "https://registry.yarnpkg.com/@types/glob/-/glob-5.0.35.tgz#1ae151c802cece940443b5ac246925c85189f32a" + dependencies: + "@types/events" "*" + "@types/minimatch" "*" + "@types/node" "*" + +"@types/inquirer@^0.0.41": + version "0.0.41" + resolved "https://registry.yarnpkg.com/@types/inquirer/-/inquirer-0.0.41.tgz#0c33027dcd0b0dde234e22afa454f2c75d8b30d2" + dependencies: + "@types/rx" "*" + "@types/through" "*" + +"@types/lodash.merge@^4.6.3": + version "4.6.3" + resolved "https://registry.yarnpkg.com/@types/lodash.merge/-/lodash.merge-4.6.3.tgz#a41c49fe404c4bfb653ae6dda76abeedeace14ff" + dependencies: + "@types/lodash" "*" + +"@types/lodash.template@^4.4.3": + version "4.4.3" + resolved "https://registry.yarnpkg.com/@types/lodash.template/-/lodash.template-4.4.3.tgz#3c6df2eb7e964cd56b12ce55ac0e6669fef6216f" + dependencies: + "@types/lodash" "*" + +"@types/lodash@*": + version "4.14.107" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.107.tgz#b2d2ae3958bfb8ff828495cbe12214af9e4d035e" + +"@types/log-symbols@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@types/log-symbols/-/log-symbols-2.0.0.tgz#7919e2ec3c8d13879bfdcab310dd7a3f7fc9466d" + +"@types/mime-types@^2.1.0": + version "2.1.0" + resolved "https://registry.yarnpkg.com/@types/mime-types/-/mime-types-2.1.0.tgz#9ca52cda363f699c69466c2a6ccdaad913ea7a73" + +"@types/minimatch@*": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" + +"@types/mocha@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-5.1.0.tgz#591f158012ec30de978b00065239a84fb1ce4380" + dependencies: + "@types/node" "*" + +"@types/node-fetch@^1.6.8": + version "1.6.8" + resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-1.6.8.tgz#a59d8c75b300ddc3ca3eef23d449d677f9486c3d" + dependencies: + "@types/node" "*" + +"@types/node@*", "@types/node@^9.6.5": + version "9.6.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-9.6.5.tgz#ee700810fdf49ac1c399fc5980b7559b3e5a381d" + +"@types/opn@^5.1.0": + version "5.1.0" + resolved "https://registry.yarnpkg.com/@types/opn/-/opn-5.1.0.tgz#bff7bc371677f4bdbb37884400e03fd81f743927" + dependencies: + "@types/node" "*" + +"@types/ora@^1.3.4": + version "1.3.4" + resolved "https://registry.yarnpkg.com/@types/ora/-/ora-1.3.4.tgz#b7fbbea8dac9851eb1918a761e2f4fae4cec03f5" + dependencies: + "@types/node" "*" + +"@types/pify@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@types/pify/-/pify-3.0.1.tgz#6c45127d0279a9518b0ef48971ec95b91dcb5f47" + +"@types/proxyquire@^1.3.28": + version "1.3.28" + resolved "https://registry.yarnpkg.com/@types/proxyquire/-/proxyquire-1.3.28.tgz#05a647bb0d8fe48fc8edcc193e43cc79310faa7d" + +"@types/rx-core-binding@*": + version "4.0.4" + resolved "https://registry.yarnpkg.com/@types/rx-core-binding/-/rx-core-binding-4.0.4.tgz#d969d32f15a62b89e2862c17b3ee78fe329818d3" + dependencies: + "@types/rx-core" "*" + +"@types/rx-core@*": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/rx-core/-/rx-core-4.0.3.tgz#0b3354b1238cedbe2b74f6326f139dbc7a591d60" + +"@types/rx-lite-aggregates@*": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/rx-lite-aggregates/-/rx-lite-aggregates-4.0.3.tgz#6efb2b7f3d5f07183a1cb2bd4b1371d7073384c2" + dependencies: + "@types/rx-lite" "*" + +"@types/rx-lite-async@*": + version "4.0.2" + resolved "https://registry.yarnpkg.com/@types/rx-lite-async/-/rx-lite-async-4.0.2.tgz#27fbf0caeff029f41e2d2aae638b05e91ceb600c" + dependencies: + "@types/rx-lite" "*" + +"@types/rx-lite-backpressure@*": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/rx-lite-backpressure/-/rx-lite-backpressure-4.0.3.tgz#05abb19bdf87cc740196c355e5d0b37bb50b5d56" + dependencies: + "@types/rx-lite" "*" + +"@types/rx-lite-coincidence@*": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/rx-lite-coincidence/-/rx-lite-coincidence-4.0.3.tgz#80bd69acc4054a15cdc1638e2dc8843498cd85c0" + dependencies: + "@types/rx-lite" "*" + +"@types/rx-lite-experimental@*": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/rx-lite-experimental/-/rx-lite-experimental-4.0.1.tgz#c532f5cbdf3f2c15da16ded8930d1b2984023cbd" + dependencies: + "@types/rx-lite" "*" + +"@types/rx-lite-joinpatterns@*": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/rx-lite-joinpatterns/-/rx-lite-joinpatterns-4.0.1.tgz#f70fe370518a8432f29158cc92ffb56b4e4afc3e" + dependencies: + "@types/rx-lite" "*" + +"@types/rx-lite-testing@*": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/rx-lite-testing/-/rx-lite-testing-4.0.1.tgz#21b19d11f4dfd6ffef5a9d1648e9c8879bfe21e9" + dependencies: + "@types/rx-lite-virtualtime" "*" + +"@types/rx-lite-time@*": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/rx-lite-time/-/rx-lite-time-4.0.3.tgz#0eda65474570237598f3448b845d2696f2dbb1c4" + dependencies: + "@types/rx-lite" "*" + +"@types/rx-lite-virtualtime@*": + version "4.0.3" + resolved "https://registry.yarnpkg.com/@types/rx-lite-virtualtime/-/rx-lite-virtualtime-4.0.3.tgz#4b30cacd0fe2e53af29f04f7438584c7d3959537" + dependencies: + "@types/rx-lite" "*" + +"@types/rx-lite@*": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@types/rx-lite/-/rx-lite-4.0.5.tgz#b3581525dff69423798daa9a0d33c1e66a5e8c4c" + dependencies: + "@types/rx-core" "*" + "@types/rx-core-binding" "*" + +"@types/rx@*": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@types/rx/-/rx-4.1.1.tgz#598fc94a56baed975f194574e0f572fd8e627a48" + dependencies: + "@types/rx-core" "*" + "@types/rx-core-binding" "*" + "@types/rx-lite" "*" + "@types/rx-lite-aggregates" "*" + "@types/rx-lite-async" "*" + "@types/rx-lite-backpressure" "*" + "@types/rx-lite-coincidence" "*" + "@types/rx-lite-experimental" "*" + "@types/rx-lite-joinpatterns" "*" + "@types/rx-lite-testing" "*" + "@types/rx-lite-time" "*" + "@types/rx-lite-virtualtime" "*" + +"@types/semver@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-5.5.0.tgz#146c2a29ee7d3bae4bf2fcb274636e264c813c45" + +"@types/sinon@^4.3.1": + version "4.3.1" + resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-4.3.1.tgz#32458f9b166cd44c23844eee4937814276f35199" + +"@types/through@*": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/through/-/through-0.0.29.tgz#72943aac922e179339c651fa34a4428a4d722f93" + dependencies: + "@types/node" "*" + JSONStream@~1.3.1: version "1.3.2" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.2.tgz#c102371b6ec3a7cf3b847ca00c20bb0fce4c6dea" @@ -1019,9 +1336,9 @@ babylon@6.18.0, babylon@^6.17.0, babylon@^6.18.0: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" -babylon@7.0.0-beta.40: - version "7.0.0-beta.40" - resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.40.tgz#91fc8cd56d5eb98b28e6fde41045f2957779940a" +babylon@7.0.0-beta.44: + version "7.0.0-beta.44" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.44.tgz#89159e15e6e30c5096e22d738d8c0af8a0e8ca1d" balanced-match@^1.0.0: version "1.0.0" @@ -1425,9 +1742,17 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.1.0: escape-string-regexp "^1.0.5" supports-color "^5.2.0" +chalk@^2.3.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.0.tgz#a060a297a6b57e15b61ca63ce84995daa0fe6e52" + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + chalk@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.2.tgz#250dc96b07491bfd601e648d66ddf5f60c7a5c65" + version "2.4.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" dependencies: ansi-styles "^3.2.1" escape-string-regexp "^1.0.5" @@ -1651,6 +1976,10 @@ colors@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" +colors@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.2.1.tgz#f4a3d302976aaf042356ba1ade3b1a2c62d9d794" + colors@~0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/colors/-/colors-0.6.2.tgz#2423fe6678ac0c5dae8852e5d0e5be08c997abcc" @@ -4950,6 +5279,10 @@ make-dir@^1.0.0: dependencies: pify "^3.0.0" +make-error@^1.1.1: + version "1.3.4" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.4.tgz#19978ed575f9e9545d2ff8c13e33b5d18a67d535" + make-fetch-happen@^2.4.13: version "2.6.0" resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-2.6.0.tgz#8474aa52198f6b1ae4f3094c04e8370d35ea8a38" @@ -7248,6 +7581,12 @@ source-map-support@^0.4.2: dependencies: source-map "^0.5.6" +source-map-support@^0.5.3: + version "0.5.4" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.4.tgz#54456efa89caa9270af7cd624cc2f123e51fbae8" + dependencies: + source-map "^0.6.0" + source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" @@ -7262,7 +7601,7 @@ source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@^0.5.7, sour version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" -source-map@^0.6.1: +source-map@^0.6.0, source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" @@ -7521,8 +7860,8 @@ supports-color@^5.1.0, supports-color@^5.2.0: has-flag "^3.0.0" supports-color@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.3.0.tgz#5b24ac15db80fa927cf5227a4a33fd3c4c7676c0" + version "5.4.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.4.0.tgz#1c6b337402c2137605efe19f10fec390f6faab54" dependencies: has-flag "^3.0.0" @@ -7868,6 +8207,19 @@ truncate-utf8-bytes@^1.0.0: dependencies: utf8-byte-length "^1.0.1" +ts-node@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-6.0.0.tgz#46c25f8498593a9248eeea16906f1598fa098140" + dependencies: + arrify "^1.0.0" + chalk "^2.3.0" + diff "^3.1.0" + make-error "^1.1.1" + minimist "^1.2.0" + mkdirp "^0.5.1" + source-map-support "^0.5.3" + yn "^2.0.0" + tunnel-agent@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" @@ -7896,6 +8248,10 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" +typescript@^2.8.1: + version "2.8.1" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.8.1.tgz#6160e4f8f195d5ba81d4876f9c0cc1fbc0820624" + uglify-js@^2.6: version "2.8.29" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.29.tgz#29c5733148057bb4e1f75df35b7a9cb72e6a59dd" @@ -8486,6 +8842,10 @@ yauzl@2.4.1: dependencies: fd-slicer "~1.0.1" +yn@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" + zip-folder@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/zip-folder/-/zip-folder-1.0.0.tgz#70a7744fd1789a2feb41ad3419b32e9fd87957b2"