diff --git a/.eslintrc.typescript.js b/.eslintrc.typescript.js new file mode 100644 index 0000000..1ce059e --- /dev/null +++ b/.eslintrc.typescript.js @@ -0,0 +1,14 @@ +const { eslintConfig } = require('./package.json') +eslintConfig.parser = '@typescript-eslint/parser' +eslintConfig.parserOptions.sourceType = 'module' +eslintConfig.extends.push( + 'plugin:@typescript-eslint/eslint-recommended', + 'plugin:@typescript-eslint/recommended' +) + +eslintConfig.rules['node/no-unsupported-features/es-syntax'] = 'off' +eslintConfig.rules['comma-dangle'] = ['error', 'only-multiline'] +eslintConfig.rules.semi = ['error', 'always'] +eslintConfig.rules['space-before-function-paren'] = ['error', 'never'] + +module.exports = eslintConfig diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..180ae56 --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,28 @@ +name: Publish documentation + +on: + push: + branches: + - master + tags: + - v[0-9]+.[0-9]+.[0-9]+* + +jobs: + docs: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: Fetch all git branches + run: git fetch --no-tags --prune --depth=1 origin +refs/heads/*:refs/remotes/origin/* + - uses: actions/setup-node@v1 + with: + node-version: 12.x + - run: yarn + - run: yarn docs:build + - uses: docker://malept/gha-gh-pages:1.0.2 + with: + docsPath: typedoc + showUnderscoreFiles: true + versionDocs: true + env: + GH_PAGES_SSH_DEPLOY_KEY: ${{ secrets.GH_PAGES_SSH_DEPLOY_KEY }} diff --git a/.gitignore b/.gitignore index 79945d6..11d1887 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ .nyc_output node_modules package-lock.json +typedoc yarn.lock diff --git a/README.md b/README.md index 6807a52..f1a14e9 100644 --- a/README.md +++ b/README.md @@ -42,8 +42,7 @@ It is recommended to ignore the generated `snap` directory in your version contr Available command-line options are displayed when you run `electron-installer-snap --help`. -For the JavaScript API, please see the [API -docs](/~https://github.com/electron-userland/electron-installer-snap/blob/master/docs/api.md). +For the JavaScript API, please see the [API docs](https://electron-userland.github.io/electron-installer-snap/). ## Thanks diff --git a/ci/build_docs.js b/ci/build_docs.js new file mode 100755 index 0000000..c89db23 --- /dev/null +++ b/ci/build_docs.js @@ -0,0 +1,41 @@ +'use strict' + +const { Application } = require('typedoc') + +const config = { + excludeExternals: true, + excludePrivate: true, + excludeProtected: true, + includeDeclarations: true, + mode: 'file' +} + +const replaceRef = /^refs\/(head|tag)s\// + +function gitRevisionFromGitHubRef () { + const githubRef = process.env.GITHUB_REF + if (githubRef) { + return githubRef.replace(replaceRef, '') + } +} + +const gitRevision = process.argv[2] || gitRevisionFromGitHubRef() +if (gitRevision) { + if (/^[0-9a-f]+$/i.test(gitRevision)) { + config.gitRevision = gitRevision + } else if (gitRevision.startsWith('v')) { + config.includeVersion = true + } +} + +const app = new Application() +app.bootstrap(config) + +const project = app.convert(['src/index.d.ts']) +if (project) { + app.generateDocs(project, 'typedoc') +} else { + console.error('Could not generate API documentation from TypeScript definition!') + // eslint-disable-next-line no-process-exit + process.exit(1) +} diff --git a/docs/api.md b/docs/api.md index d0d8183..6f7e5fb 100644 --- a/docs/api.md +++ b/docs/api.md @@ -1,213 +1 @@ -# `electron-installer-snap` API Documentation - -## Usage - -The `electron-installer-snap` API uses the Promise pattern to perform asynchronous operations. - -Minimal example: - -```javascript -const snap = require('electron-installer-snap') - -const snapPath = await snap(options) -console.log(`Created snap at ${snapPath}!`) -``` - -Full example with [Electron Packager](https://npm.im/electron-packager): - -```javascript -const packager = require('electron-packager') -const snap = require('electron-installer-snap') - -const arch = 'x64' - -const paths = await packager({dir: '/path/to/app', platform: 'linux', arch: arch}) -const snapPath = await snap({src: paths[0], arch: arch}) -console.log(`Created snap at ${snapPath}!`) -``` - -If you need to use the callback pattern instead of the `async`/`await` pattern, look into the -[`util.callbackify` function](https://nodejs.org/api/util.html#util_util_callbackify_original). - -## `options` - -Any options that aren't specified here are passed through to the `snapcraft.yaml` file. - -### Required - -#### `src` - -*String* - -The directory where the customized Electron application has been created, e.g., via Electron -Packager. - -### Optional - -#### `appConfig` - -*Object* (Default: `{}`) - -[Additional Snapcraft configuration](https://docs.snapcraft.io/build-snaps/syntax#app-name) for the -Electron app. - -#### `appPlugs` - -*Array* of *String*s - -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`](#features) option. To set any attributes for the plugs, set them in the -`plugs` option. - -For example, if the app uses a DBus interface: - -```javascript -{ - appPlugs: ['my-dbus-interface'], - plugs: { - 'my-dbus-interface': { - interface: 'dbus', - name: 'com.example.my-interface', - bus: 'session' - } - } -} -``` - -`plugs` will be passed through directly to the generated `snapcraft.yaml`. - -#### `appSlots` - -*Array* of *String*s - -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`](#features) option. To set any attributes for the plugs, set them in the -`slots` option. - -For example, if the app creates a DBus interface: - -```javascript -{ - appSlots: ['my-dbus-interface'], - slots: { - 'my-dbus-interface': { - interface: 'dbus', - name: 'com.example.my-interface', - bus: 'session' - } - } -} -``` - -`slots` will be passed through directly to the generated `snapcraft.yaml`. - -#### `arch` - -*String* (Default: host arch, via `process.arch`) - -Either the Node.js-formatted arch or Snap-formatted arch, used to specify the Snap's target arch. - -#### `confinement` - -*String* (default: `devmode`) - -See the [Snapcraft documentation](https://snapcraft.io/docs/reference/confinement). - -#### `description` - -*String* - -The longer description for the snap. Can contain newlines. - -#### `desktopTemplate` - -*String* - -The absolute path to a custom Freedesktop.org desktop file template. - -#### `dest` - -*String* (Default: current working directory) - -The directory where the `.snap` file is created. Defaults to the current working directory. - -#### `executableName` - -*String* (Default: either `productName` or `name` in `package.json`) - -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. - -#### `features` - -*Object* - -Describes what functionality the Electron app needs, in order to work inside the Snap sandbox. -Available features: - -* `audio` - PulseAudio support -* `alsa` - ALSA support *(replaces `audio` support if both are specified)* -* `browserSandbox` - [web browser functionality](/~https://github.com/snapcore/snapd/wiki/Interfaces#browser-support). - This is enabled by default when using Electron ≥ 5.0.0, due to the - [setuid sandbox support](/~https://github.com/electron/electron/pull/17269). -* `mpris` - [MPRIS](https://specifications.freedesktop.org/mpris-spec/latest/) support. If enabled, - the interface name must be specified as the feature value. -* `passwords` - Access the secret service (e.g., GNOME Keyring) -* `webgl` - WebGL support (requires Mesa, etc.) - -Example: - -```javascript -{ - features: { - audio: true, - mpris: 'com.example.mpris', - webgl: true - } -} -``` - -Setting a feature to a `false`-y value does not disable the feature, only omitting the feature from the -`Object` does that. - -#### `grade` - -*String* (Default: `devel`) - -The quality grade of the Snap. See the [Snapcraft documentation](https://docs.snapcraft.io/build-snaps/syntax#grade) -for valid values. - -#### `hookScripts` - -*Object* - -One or more [hook scripts](https://docs.snapcraft.io/build-snaps/hooks) to be installed with the -Snap. The format of the `Object` is `{ hookName: pathToHookScript, [...] }`. Hook names can be found -in the Snapcraft documentation. - -#### `name` - -*String* (Default: `name` in `package.json`) - -The name of the Snap package. - -#### `snapcraft` - -*String* (Default: searches paths in the `PATH` environment variable) - -The absolute path to the `snapcraft` executable. - -#### `summary` - -*String* (Default: `description` in `package.json`) - -A 78 character long summary for the Snap. - -#### `version` - -*String* (Default: `version` in `package.json`) - -The version of the Snap package. +[API Documentation](https://electron-userland.github.io/electron-installer-snap) has moved. diff --git a/package.json b/package.json index fab6132..864deca 100644 --- a/package.json +++ b/package.json @@ -5,21 +5,27 @@ "author": "Mark Lee", "license": "Apache-2.0", "main": "src/index.js", + "types": "src/index.d.ts", "bin": { "electron-installer-snap": "src/cli.js" }, "files": [ "NEWS.md", "resources", - "src" + "src", + "src/index.d.ts" ], "scripts": { "ava": "ava", "codecov": "nyc report --reporter=text-lcov | codecov --disable=gcov --pipe", "coverage": "nyc ava", - "lint": "eslint .", + "docs:build": "node ci/build_docs.js", + "eslint:js": "eslint .", + "eslint:ts": "eslint --ext .ts --config .eslintrc.typescript.js .", + "lint": "npm run eslint:js && npm run eslint:ts && npm run tsd", "test": "npm run lint && ava", - "test:fast": "cross-env FAST_TESTS_ONLY=1 npm test" + "test:fast": "cross-env FAST_TESTS_ONLY=1 npm test", + "tsd": "tsd" }, "repository": "electron-userland/electron-installer-snap", "keywords": [ @@ -30,6 +36,8 @@ "linux" ], "devDependencies": { + "@typescript-eslint/eslint-plugin": "^2.26.0", + "@typescript-eslint/parser": "^2.26.0", "ava": "^3.0.0", "codecov": "^3.1.0", "cross-env": "^7.0.0", @@ -43,7 +51,10 @@ "husky": "^4.2.3", "lint-staged": "^10.1.2", "nyc": "^15.0.0", - "sinon": "^9.0.0" + "sinon": "^9.0.0", + "tsd": "^0.11.0", + "typedoc": "^0.17.3", + "typescript": "^3.8.3" }, "dependencies": { "@malept/cross-spawn-promise": "^1.0.0", @@ -92,6 +103,9 @@ "strict": "error" } }, + "eslintIgnore": [ + "typedoc" + ], "funding": { "url": "/~https://github.com/electron-userland/electron-installer-snap?sponsor=1" }, @@ -103,6 +117,12 @@ "lint-staged": { "*.js": [ "eslint . --fix" + ], + "*.ts": [ + "npm run eslint:ts -- --fix" ] + }, + "tsd": { + "directory": "test" } } diff --git a/src/index.d.ts b/src/index.d.ts new file mode 100644 index 0000000..7525b69 --- /dev/null +++ b/src/index.d.ts @@ -0,0 +1,223 @@ +/** + * The `electron-installer-snap` API uses the Promise pattern to perform asynchronous operations. + * + * Minimal example: + * + * ```javascript + * const snap = require('electron-installer-snap') + * + * const snapPath = await snap(options) + * console.log(`Created snap at ${snapPath}!`) + * ``` + * + * Full example with [Electron Packager](https://npm.im/electron-packager): + * + * ```javascript + * const packager = require('electron-packager') + * const snap = require('electron-installer-snap') + * + * const arch = 'x64' + * + * const paths = await packager({dir: '/path/to/app', platform: 'linux', arch: arch}) + * const snapPath = await snap({src: paths[0], arch: arch}) + * console.log(`Created snap at ${snapPath}!`) + * ``` + * + * If you need to use the callback pattern instead of the `async`/`await` pattern, look into the + * [`util.callbackify` function](https://nodejs.org/api/util.html#util_util_callbackify_original). + */ +declare function createSnap(userSupplied: createSnap.Options & createSnap.SnapcraftConfig): Promise; + +declare namespace createSnap { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + type SnapcraftConfig = Record; + /** + * Any options that aren't specified here are passed through to the `snapcraft.yaml` file. + */ + interface Options { + src: string; + + /** + * [Additional Snapcraft configuration](https://docs.snapcraft.io/build-snaps/syntax#app-name) + * for the Electron app. + */ + appConfig?: object; + /** + * 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. + * + * For example, if the app uses a DBus interface: + * + * ```javascript + * { + * appPlugs: ['my-dbus-interface'], + * plugs: { + * 'my-dbus-interface': { + * interface: 'dbus', + * name: 'com.example.my-interface', + * bus: 'session' + * } + * } + * } + * ``` + * + * `plugs` will be passed through directly to the generated `snapcraft.yaml`. + */ + 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. + * + * For example, if the app creates a DBus interface: + * + * ```javascript + * { + * appSlots: ['my-dbus-interface'], + * slots: { + * 'my-dbus-interface': { + * interface: 'dbus', + * name: 'com.example.my-interface', + * bus: 'session' + * } + * } + * } + * ``` + * + * [[`slots`]] will be passed through directly to the generated `snapcraft.yaml`. + */ + appSlots?: string[]; + /** + * Either the Node.js-formatted arch or Snap-formatted arch, used to specify the Snap's target arch. + * + * Default: the host arch, via [`process.arch`](https://nodejs.org/dist/latest-v12.x/docs/api/process.html#process_process_arch). + */ + arch?: 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 directory where the `.snap` file is created. + * + * Default: the current working directory. + */ + dest?: string; + /** + * The executable name of the Electron app, sans file extension. Corresponds + * to the [`executableName` option](https://electron.github.io/electron-packager/master/interfaces/electronpackager.options.html#executablename) + * in Electron Packager. + * + * Default: either `productName` or `name` in `package.json` + */ + executableName?: string; + /** + * Describes what functionality the Electron app needs, in order to work inside the Snap sandbox. + * + * Example: + * + * ```javascript + * { + * features: { + * audio: true, + * mpris: 'com.example.mpris', + * webgl: true + * } + * } + * ``` + * + * Setting a feature to a `false`-y value does not disable the feature, only omitting the + * feature from the `Object` does that. + */ + features?: { + /** + * Audio support via PulseAudio. + */ + audio?: true; + /** + * Audio support via ALSA (replaces `audio` support if both are specified) + */ + alsa?: true; + /** + * [Web browser functionality](/~https://github.com/snapcore/snapd/wiki/Interfaces#browser-support). + * This is enabled by default when using Electron ≥ 5.0.0, due to the + * [setuid sandbox support](/~https://github.com/electron/electron/pull/17269). + */ + 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. + * + * Default: `devel` + */ + grade?: 'devel' | 'stable'; + /** + * One or more [hook scripts](https://docs.snapcraft.io/build-snaps/hooks) to be installed with + * the Snap. The format of the `Object` is `{ hookName: pathToHookScript, […] }`. Hook names + * can be found in the Snapcraft documentation. + */ + hookScripts?: Record; + /** + * The name of the Snap package. + * + * Default: `name` in `package.json` + */ + name?: string; + /** + * See [[`appPlugs`]] for details. + */ + plugs?: object; + /** + * See [[`appSlots`]] for details. + */ + slots?: object; + /** + * The absolute path to the snapcraft executable. + * + * By default, it searches paths in the `PATH` environment variable. + */ + snapcraft?: string; + /** + * A 78 character long summary for the Snap. + * + * Default: `description` in `package.json` + */ + summary?: string; + /** + * The version of the Snap package. + * + * Default: `version` in `package.json` + */ + version?: string; + } +} + +export = createSnap; diff --git a/test/index.test-d.ts b/test/index.test-d.ts new file mode 100644 index 0000000..bb3898a --- /dev/null +++ b/test/index.test-d.ts @@ -0,0 +1,33 @@ +import * as createSnap from '..'; +import { expectError } from 'tsd'; + +expectError(createSnap()); +expectError(createSnap({})); + +await createSnap({ + src: 'test' +}); + +expectError(createSnap({ + src: 'test', + features: { + nonexistent: true + } +})); + +expectError(createSnap({ + src: 'test', + features: { + mpris: true + } +})); + +expectError(createSnap({ + src: 'test', + grade: 'nonexistent' +})); + +await createSnap({ + src: 'test', + passthruToSnapcraftYaml: 'test' +});